]> gitweb.factorcode.org Git - factor.git/blob - vm/objects.cpp
New identity-hashcode primitive
[factor.git] / vm / objects.cpp
1 #include "master.hpp"
2
3 namespace factor
4 {
5
6 void factor_vm::primitive_special_object()
7 {
8         fixnum e = untag_fixnum(dpeek());
9         drepl(special_objects[e]);
10 }
11
12 void factor_vm::primitive_set_special_object()
13 {
14         fixnum e = untag_fixnum(dpop());
15         cell value = dpop();
16         special_objects[e] = value;
17 }
18
19 void factor_vm::primitive_identity_hashcode()
20 {
21         cell tagged = dpeek();
22         if(immediate_p(tagged))
23                 drepl(tagged & ~TAG_MASK);
24         else
25         {
26                 object *obj = untag<object>(tagged);
27                 if(obj->hashcode() == 0)
28                 {
29                         /* Use megamorphic_cache_misses as a random source of randomness */
30                         obj->set_hashcode(((cell)obj / block_granularity) ^ dispatch_stats.megamorphic_cache_hits);
31                 }
32                 drepl(tag_fixnum(obj->hashcode()));
33         }
34 }
35
36 void factor_vm::primitive_set_slot()
37 {
38         fixnum slot = untag_fixnum(dpop());
39         object *obj = untag<object>(dpop());
40         cell value = dpop();
41
42         cell *slot_ptr = &obj->slots()[slot];
43         *slot_ptr = value;
44         write_barrier(slot_ptr);
45 }
46
47 cell factor_vm::clone_object(cell obj_)
48 {
49         data_root<object> obj(obj_,this);
50
51         if(immediate_p(obj.value()))
52                 return obj.value();
53         else
54         {
55                 cell size = object_size(obj.value());
56                 object *new_obj = allot_object(obj.type(),size);
57                 memcpy(new_obj,obj.untagged(),size);
58                 new_obj->set_hashcode(0);
59                 return tag_dynamic(new_obj);
60         }
61 }
62
63 void factor_vm::primitive_clone()
64 {
65         drepl(clone_object(dpeek()));
66 }
67
68 /* Size of the object pointed to by a tagged pointer */
69 cell factor_vm::object_size(cell tagged)
70 {
71         if(immediate_p(tagged))
72                 return 0;
73         else
74                 return untag<object>(tagged)->size();
75 }
76
77 void factor_vm::primitive_size()
78 {
79         box_unsigned_cell(object_size(dpop()));
80 }
81
82 struct slot_become_visitor {
83         std::map<object *,object *> *become_map;
84
85         explicit slot_become_visitor(std::map<object *,object *> *become_map_) :
86                 become_map(become_map_) {}
87
88         object *operator()(object *old)
89         {
90                 std::map<object *,object *>::const_iterator iter = become_map->find(old);
91                 if(iter != become_map->end())
92                         return iter->second;
93                 else
94                         return old;
95         }
96 };
97
98 struct object_become_visitor {
99         slot_visitor<slot_become_visitor> *workhorse;
100
101         explicit object_become_visitor(slot_visitor<slot_become_visitor> *workhorse_) :
102                 workhorse(workhorse_) {}
103
104         void operator()(object *obj)
105         {
106                 workhorse->visit_slots(obj);
107         }
108 };
109
110 /* classes.tuple uses this to reshape tuples; tools.deploy.shaker uses this
111    to coalesce equal but distinct quotations and wrappers. */
112 void factor_vm::primitive_become()
113 {
114         array *new_objects = untag_check<array>(dpop());
115         array *old_objects = untag_check<array>(dpop());
116
117         cell capacity = array_capacity(new_objects);
118         if(capacity != array_capacity(old_objects))
119                 critical_error("bad parameters to become",0);
120
121         /* Build the forwarding map */
122         std::map<object *,object *> become_map;
123
124         for(cell i = 0; i < capacity; i++)
125         {
126                 tagged<object> old_obj(array_nth(old_objects,i));
127                 tagged<object> new_obj(array_nth(new_objects,i));
128
129                 if(old_obj != new_obj)
130                         become_map[old_obj.untagged()] = new_obj.untagged();
131         }
132
133         /* Update all references to old objects to point to new objects */
134         slot_visitor<slot_become_visitor> workhorse(this,slot_become_visitor(&become_map));
135         workhorse.visit_roots();
136         workhorse.visit_contexts();
137
138         object_become_visitor object_visitor(&workhorse);
139         each_object(object_visitor);
140
141         /* Since we may have introduced old->new references, need to revisit
142         all objects on a minor GC. */
143         data->mark_all_cards();
144         primitive_minor_gc();
145
146         /* If a word's definition quotation was in old_objects and the
147            quotation in new_objects is not compiled, we might leak memory
148            by referencing the old quotation unless we recompile all
149            unoptimized words. */
150         compile_all_words();
151
152         /* Update references to old objects in the code heap */
153         update_code_heap_words_and_literals();
154 }
155
156 }