]> gitweb.factorcode.org Git - factor.git/blob - vm/dispatch.cpp
Merge branch 'master' of git://factorcode.org/git/factor
[factor.git] / vm / dispatch.cpp
1 #include "master.hpp"
2
3 namespace factor
4 {
5
6 cell factor_vm::search_lookup_alist(cell table, cell klass)
7 {
8         array *elements = untag<array>(table);
9         fixnum index = array_capacity(elements) - 2;
10         while(index >= 0)
11         {
12                 if(array_nth(elements,index) == klass)
13                         return array_nth(elements,index + 1);
14                 else
15                         index -= 2;
16         }
17
18         return F;
19 }
20
21 cell factor_vm::search_lookup_hash(cell table, cell klass, cell hashcode)
22 {
23         array *buckets = untag<array>(table);
24         cell bucket = array_nth(buckets,hashcode & (array_capacity(buckets) - 1));
25         if(tagged<object>(bucket).type_p(WORD_TYPE) || bucket == F)
26                 return bucket;
27         else
28                 return search_lookup_alist(bucket,klass);
29 }
30
31 cell factor_vm::nth_superclass(tuple_layout *layout, fixnum echelon)
32 {
33         cell *ptr = (cell *)(layout + 1);
34         return ptr[echelon * 2];
35 }
36
37 cell factor_vm::nth_hashcode(tuple_layout *layout, fixnum echelon)
38 {
39         cell *ptr = (cell *)(layout + 1);
40         return ptr[echelon * 2 + 1];
41 }
42
43 cell factor_vm::lookup_tuple_method(cell obj, cell methods)
44 {
45         tuple_layout *layout = untag<tuple_layout>(untag<tuple>(obj)->layout);
46
47         array *echelons = untag<array>(methods);
48
49         fixnum echelon = untag_fixnum(layout->echelon);
50         fixnum max_echelon = array_capacity(echelons) - 1;
51         if(echelon > max_echelon) echelon = max_echelon;
52        
53         while(echelon >= 0)
54         {
55                 cell echelon_methods = array_nth(echelons,echelon);
56
57                 if(tagged<object>(echelon_methods).type_p(WORD_TYPE))
58                         return echelon_methods;
59                 else if(echelon_methods != F)
60                 {
61                         cell klass = nth_superclass(layout,echelon);
62                         cell hashcode = untag_fixnum(nth_hashcode(layout,echelon));
63                         cell result = search_lookup_hash(echelon_methods,klass,hashcode);
64                         if(result != F)
65                                 return result;
66                 }
67
68                 echelon--;
69         }
70
71         critical_error("Cannot find tuple method",methods);
72         return F;
73 }
74
75 cell factor_vm::lookup_hi_tag_method(cell obj, cell methods)
76 {
77         array *hi_tag_methods = untag<array>(methods);
78         cell tag = untag<object>(obj)->h.hi_tag() - HEADER_TYPE;
79 #ifdef FACTOR_DEBUG
80         assert(tag < TYPE_COUNT - HEADER_TYPE);
81 #endif
82         return array_nth(hi_tag_methods,tag);
83 }
84
85 cell factor_vm::lookup_hairy_method(cell obj, cell methods)
86 {
87         cell method = array_nth(untag<array>(methods),TAG(obj));
88         if(tagged<object>(method).type_p(WORD_TYPE))
89                 return method;
90         else
91         {
92                 switch(TAG(obj))
93                 {
94                 case TUPLE_TYPE:
95                         return lookup_tuple_method(obj,method);
96                         break;
97                 case OBJECT_TYPE:
98                         return lookup_hi_tag_method(obj,method);
99                         break;
100                 default:
101                         critical_error("Bad methods array",methods);
102                         return 0;
103                 }
104         }
105 }
106
107 cell factor_vm::lookup_method(cell obj, cell methods)
108 {
109         cell tag = TAG(obj);
110         if(tag == TUPLE_TYPE || tag == OBJECT_TYPE)
111                 return lookup_hairy_method(obj,methods);
112         else
113                 return array_nth(untag<array>(methods),TAG(obj));
114 }
115
116 inline void factor_vm::primitive_lookup_method()
117 {
118         cell methods = dpop();
119         cell obj = dpop();
120         dpush(lookup_method(obj,methods));
121 }
122
123 PRIMITIVE(lookup_method)
124 {
125         PRIMITIVE_GETVM()->primitive_lookup_method();
126 }
127
128 cell factor_vm::object_class(cell obj)
129 {
130         switch(TAG(obj))
131         {
132         case TUPLE_TYPE:
133                 return untag<tuple>(obj)->layout;
134         case OBJECT_TYPE:
135                 return untag<object>(obj)->h.value;
136         default:
137                 return tag_fixnum(TAG(obj));
138         }
139 }
140
141 cell factor_vm::method_cache_hashcode(cell klass, array *array)
142 {
143         cell capacity = (array_capacity(array) >> 1) - 1;
144         return ((klass >> TAG_BITS) & capacity) << 1;
145 }
146
147 void factor_vm::update_method_cache(cell cache, cell klass, cell method)
148 {
149         array *cache_elements = untag<array>(cache);
150         cell hashcode = method_cache_hashcode(klass,cache_elements);
151         set_array_nth(cache_elements,hashcode,klass);
152         set_array_nth(cache_elements,hashcode + 1,method);
153 }
154
155 inline void factor_vm::primitive_mega_cache_miss()
156 {
157         megamorphic_cache_misses++;
158
159         cell cache = dpop();
160         fixnum index = untag_fixnum(dpop());
161         cell methods = dpop();
162
163         cell object = ((cell *)ds)[-index];
164         cell klass = object_class(object);
165         cell method = lookup_method(object,methods);
166
167         update_method_cache(cache,klass,method);
168
169         dpush(method);
170 }
171
172 PRIMITIVE(mega_cache_miss)
173 {
174         PRIMITIVE_GETVM()->primitive_mega_cache_miss();
175 }
176
177 inline void factor_vm::primitive_reset_dispatch_stats()
178 {
179         megamorphic_cache_hits = megamorphic_cache_misses = 0;
180 }
181
182 PRIMITIVE(reset_dispatch_stats)
183 {
184         PRIMITIVE_GETVM()->primitive_reset_dispatch_stats();
185 }
186
187 inline void factor_vm::primitive_dispatch_stats()
188 {
189         growable_array stats(this);
190         stats.add(allot_cell(megamorphic_cache_hits));
191         stats.add(allot_cell(megamorphic_cache_misses));
192         stats.trim();
193         dpush(stats.elements.value());
194 }
195
196 PRIMITIVE(dispatch_stats)
197 {
198         PRIMITIVE_GETVM()->primitive_dispatch_stats();
199 }
200
201 void quotation_jit::emit_mega_cache_lookup(cell methods_, fixnum index, cell cache_)
202 {
203         gc_root<array> methods(methods_,parent_vm);
204         gc_root<array> cache(cache_,parent_vm);
205
206         /* Generate machine code to determine the object's class. */
207         emit_class_lookup(index,PIC_HI_TAG_TUPLE);
208
209         /* Do a cache lookup. */
210         emit_with(parent_vm->userenv[MEGA_LOOKUP],cache.value());
211         
212         /* If we end up here, the cache missed. */
213         emit(parent_vm->userenv[JIT_PROLOG]);
214
215         /* Push index, method table and cache on the stack. */
216         push(methods.value());
217         push(tag_fixnum(index));
218         push(cache.value());
219         word_call(parent_vm->userenv[MEGA_MISS_WORD]);
220
221         /* Now the new method has been stored into the cache, and its on
222            the stack. */
223         emit(parent_vm->userenv[JIT_EPILOG]);
224         emit(parent_vm->userenv[JIT_EXECUTE_JUMP]);
225 }
226
227 }