#include "master.hpp" namespace factor { // Size of the object pointed to by a tagged pointer cell object_size(cell tagged) { if (immediate_p(tagged)) return 0; return untag(tagged)->size(); } void factor_vm::primitive_special_object() { fixnum n = untag_fixnum(ctx->peek()); ctx->replace(special_objects[n]); } void factor_vm::primitive_set_special_object() { fixnum n = untag_fixnum(ctx->pop()); cell value = ctx->pop(); special_objects[n] = value; } void factor_vm::primitive_identity_hashcode() { cell tagged = ctx->peek(); object* obj = untag(tagged); ctx->replace(tag_fixnum(obj->hashcode())); } void factor_vm::primitive_compute_identity_hashcode() { object* obj = untag(ctx->pop()); object_counter++; if (object_counter == 0) object_counter++; obj->set_hashcode((cell)obj ^ object_counter); } void factor_vm::primitive_set_slot() { fixnum slot = untag_fixnum(ctx->pop()); object* obj = untag(ctx->pop()); cell value = ctx->pop(); cell* slot_ptr = &obj->slots()[slot]; *slot_ptr = value; write_barrier(slot_ptr); } // Allocates memory void factor_vm::primitive_clone() { data_root obj(ctx->peek(), this); if (immediate_p(obj.value())) return; cell size = object_size(obj.value()); object* new_obj = allot_object(obj.type(), size); memcpy(new_obj, obj.untagged(), size); new_obj->set_hashcode(0); ctx->replace(tag_dynamic(new_obj)); } // Allocates memory void factor_vm::primitive_size() { ctx->replace(from_unsigned_cell(object_size(ctx->peek()))); } struct slot_become_fixup : no_fixup { std::map* become_map; slot_become_fixup(std::map* become_map) : become_map(become_map) {} object* fixup_data(object* old) { std::map::const_iterator iter = become_map->find(old); if (iter != become_map->end()) return iter->second; return old; } }; // classes.tuple uses this to reshape tuples; tools.deploy.shaker uses this // to coalesce equal but distinct quotations and wrappers. // Calls gc void factor_vm::primitive_become() { primitive_minor_gc(); array* new_objects = untag_check(ctx->pop()); array* old_objects = untag_check(ctx->pop()); cell capacity = array_capacity(new_objects); if (capacity != array_capacity(old_objects)) critical_error("bad parameters to become", 0); // Build the forwarding map std::map become_map; for (cell i = 0; i < capacity; i++) { cell old_ptr = array_nth(old_objects, i); cell new_ptr = array_nth(new_objects, i); if (old_ptr != new_ptr) become_map[untag(old_ptr)] = untag(new_ptr); } // Update all references to old objects to point to new objects { slot_visitor visitor(this, slot_become_fixup(&become_map)); visitor.visit_all_roots(); auto object_become_func = [&](object* obj) { visitor.visit_slots(obj); }; each_object(object_become_func); auto code_block_become_func = [&](code_block* compiled, cell size) { visitor.visit_code_block_objects(compiled); visitor.visit_embedded_literals(compiled); code->write_barrier(compiled); }; each_code_block(code_block_become_func); } // Since we may have introduced old->new references, need to revisit // all objects and code blocks on a minor GC. data->mark_all_cards(); } }