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