4 word_t
method_pic_hash(struct object_heap
* oh
, struct CompiledMethod
* callerMethod
, word_t arity
, struct Object
* args
[]) {
5 word_t arraySize
= array_size(callerMethod
->calleeCount
);
6 word_t entryStart
= (hash_selector(oh
, NULL
, args
, arity
) % (arraySize
/CALLER_PIC_ENTRY_SIZE
)) * CALLER_PIC_ENTRY_SIZE
;
12 void method_save_cache(struct object_heap
* oh
, struct MethodDefinition
* md
, struct Symbol
* name
, struct Object
* arguments
[], word_t n
) {
13 struct MethodCacheEntry
* cacheEntry
;
15 word_t hash
= hash_selector(oh
, name
, arguments
, n
);
16 assert(n
<= METHOD_CACHE_ARITY
);
17 cacheEntry
= &oh
->methodCache
[hash
& (METHOD_CACHE_SIZE
-1)];
18 cacheEntry
->method
= md
;
19 cacheEntry
->selector
= name
;
20 for (i
= 0; i
< n
; i
++) {
21 cacheEntry
->maps
[i
] = object_get_map(oh
, arguments
[i
]);
26 struct MethodDefinition
* method_check_cache(struct object_heap
* oh
, struct Symbol
* selector
, struct Object
* arguments
[], word_t n
) {
27 struct MethodCacheEntry
* cacheEntry
;
28 word_t hash
= hash_selector(oh
, selector
, arguments
, n
);
29 assert(n
<= METHOD_CACHE_ARITY
);
30 oh
->method_cache_access
++;
31 cacheEntry
= &oh
->methodCache
[hash
& (METHOD_CACHE_SIZE
-1)];
32 if (cacheEntry
->selector
!= selector
) return NULL
;
34 /*fix findOn: might not call us with enough elements*/
35 if (object_to_smallint(selector
->cacheMask
) > (1 << n
)) return NULL
;
37 switch (object_to_smallint(selector
->cacheMask
)) { /*the found positions for the function*/
38 case 1: if (object_get_map(oh
, arguments
[0]) != cacheEntry
->maps
[0]) return NULL
; break;
39 case 2: if (object_get_map(oh
, arguments
[1]) != cacheEntry
->maps
[1]) return NULL
; break;
40 case 4: if (object_get_map(oh
, arguments
[2]) != cacheEntry
->maps
[2]) return NULL
; break;
42 case 3: if (object_get_map(oh
, arguments
[0]) != cacheEntry
->maps
[0] ||
43 object_get_map(oh
, arguments
[1]) != cacheEntry
->maps
[1]) return NULL
; break;
44 case 5: if (object_get_map(oh
, arguments
[0]) != cacheEntry
->maps
[0] ||
45 object_get_map(oh
, arguments
[2]) != cacheEntry
->maps
[2]) return NULL
; break;
46 case 6: if (object_get_map(oh
, arguments
[1]) != cacheEntry
->maps
[1] ||
47 object_get_map(oh
, arguments
[2]) != cacheEntry
->maps
[2]) return NULL
; break;
49 case 7: if (object_get_map(oh
, arguments
[0]) != cacheEntry
->maps
[0] ||
50 object_get_map(oh
, arguments
[1]) != cacheEntry
->maps
[1] ||
51 object_get_map(oh
, arguments
[2]) != cacheEntry
->maps
[2]) return NULL
; break;
53 oh
->method_cache_hit
++;
54 return cacheEntry
->method
;
61 * This is the main dispatch function
64 struct MethodDefinition
* method_dispatch_on(struct object_heap
* oh
, struct Symbol
* name
,
65 struct Object
* arguments
[], word_t arity
, struct Object
* resendMethod
) {
67 struct MethodDefinition
*dispatch
, *bestDef
;
68 struct Object
* slotLocation
;
69 word_t bestRank
, depth
, delegationCount
, resendRank
, restricted
, i
;
72 #ifdef PRINT_DEBUG_DISPATCH
73 printf("dispatch to: '");
75 printf("' (arity: %" PRIdPTR
")\n", arity
);
76 for (i
= 0; i
< arity
; i
++) {
77 printf("arguments[%" PRIdPTR
"] (%p) = ", i
, (void*)arguments
[i
]); print_type(oh
, arguments
[i
]);
79 /* printf("resend: "); print_object(resendMethod);*/
85 #ifndef SLATE_DISABLE_METHOD_CACHE
86 if (resendMethod
== NULL
&& arity
<= METHOD_CACHE_ARITY
) {
87 dispatch
= method_check_cache(oh
, name
, arguments
, arity
);
88 if (dispatch
!= NULL
) return dispatch
;
92 oh
->current_dispatch_id
++;
95 resendRank
= ((resendMethod
== NULL
) ? WORDT_MAX
: 0);
97 for (i
= 0; i
< arity
; i
++) {
100 struct Object
* arg
= arguments
[i
];
103 restricted
= WORDT_MAX
; /*pointer in delegate_stack (with sp of delegateCount) to where we don't trace further*/
106 /* Set up obj to be a pointer to the object, or SmallInteger if it's
107 a direct SmallInt. */
108 if (object_is_smallint(arg
)) {
109 obj
= get_special(oh
, SPECIAL_OOP_SMALL_INT_PROTO
);
113 /* Identify the map, and update its dispatchID and reset the visited mask
114 if it hasn't been visited during this call already. */
117 if (map
->dispatchID
!= oh
->current_dispatch_id
) {
118 map
->dispatchID
= oh
->current_dispatch_id
;
119 map
->visitedPositions
= 0;
122 /* we haven't been here before */
123 if ((map
->visitedPositions
& (1 << i
)) == 0) {
125 struct RoleEntry
* role
;
127 /* If the map marks an obj-meta transition and the top of the stack
128 is not the original argument, then mark the restriction point at
129 the top of the delegation stack. */
131 if (((word_t
)map
->flags
& MAP_FLAG_RESTRICT_DELEGATION
) && (arg
!= arguments
[i
])) {
132 restricted
= delegationCount
;
134 map
->visitedPositions
|= (1 << i
);
135 role
= role_table_entry_for_name(oh
, map
->roleTable
, name
);
136 while (role
!= NULL
) {
137 if ((object_to_smallint(role
->rolePositions
) & (1 << i
)) != 0) {
138 struct MethodDefinition
* def
= role
->methodDefinition
;
139 /* If the method hasn't been visited this time, mark it
140 so and clear the other dispatch marks.*/
141 if (def
->dispatchID
!= oh
->current_dispatch_id
) {
142 def
->dispatchID
= oh
->current_dispatch_id
;
143 def
->foundPositions
= 0;
144 def
->dispatchRank
= 0;
146 /*If the method hasn't been found at this position...*/
147 if ((def
->foundPositions
& (1 << i
)) == 0) {
150 def
->dispatchRank
|= ((31 - depth
) << ((5 - i
) * 5));
151 def
->foundPositions
|= (1 << i
);
153 #ifdef PRINT_DEBUG_FOUND_ROLE
154 printf("found role index %" PRIdPTR
" <%p> for '%s' foundPos: %" PRIuPTR
"x dispatchPos: %" PRIuPTR
"x\n",
157 ((struct Symbol
*)(role
->name
))->elements
, def
->foundPositions
, def
->dispatchPositions
);
160 if (def
->method
== resendMethod
) {
161 struct RoleEntry
* rescan
= role_table_entry_for_name(oh
, map
->roleTable
, name
);
162 resendRank
= def
->dispatchRank
;
163 while (rescan
!= role
) {
164 struct MethodDefinition
* redef
= rescan
->methodDefinition
;
165 if (redef
->foundPositions
== redef
->dispatchPositions
&&
166 (dispatch
== NULL
|| redef
->dispatchRank
<= resendRank
)) {
169 if (redef
->dispatchRank
> bestRank
) {
170 bestRank
= redef
->dispatchRank
;
174 if (rescan
->nextRole
== oh
->cached
.nil
) {
177 rescan
= &map
->roleTable
->roles
[object_to_smallint(rescan
->nextRole
)];
182 } else /*not a resend*/ {
183 if (def
->foundPositions
== def
->dispatchPositions
&&
184 (dispatch
== NULL
|| def
->dispatchRank
> dispatch
->dispatchRank
) &&
185 def
->dispatchRank
<= resendRank
) {
188 if (def
->dispatchRank
> bestRank
) {
189 bestRank
= def
->dispatchRank
;
194 if (def
->dispatchRank
>= bestRank
&& def
!= bestDef
) {
195 bestRank
= def
->dispatchRank
;
201 role
= ((role
->nextRole
== oh
->cached
.nil
) ? NULL
: &map
->roleTable
->roles
[object_to_smallint(role
->nextRole
)]);
202 } /*while role != NULL*/
204 if (depth
> 31) { /*fix wordsize*/
207 if (dispatch
!= NULL
&& bestDef
== dispatch
) {
208 if (dispatch
->slotAccessor
!= oh
->cached
.nil
) {
209 arguments
[0] = slotLocation
;
210 /*do we need to try to do a heap_store_into?*/
211 #ifdef PRINT_DEBUG_DISPATCH_SLOT_CHANGES
212 printf("arguments[0] changed to slot location: \n");
213 print_detail(oh
, arguments
[0]);
216 if (resendMethod
== 0 && arity
<= METHOD_CACHE_ARITY
) method_save_cache(oh
, dispatch
, name
, arguments
, arity
);
223 /* We add the delegates to the list when we didn't just finish checking a restricted object*/
224 if (delegationCount
<= restricted
&& array_size(map
->delegates
) > 0) {
225 struct OopArray
* delegates
= map
->delegates
;
226 word_t offset
= object_array_offset((struct Object
*)delegates
);
227 word_t limit
= object_total_size((struct Object
*)delegates
);
228 for (; offset
!= limit
; offset
+= sizeof(word_t
)) {
229 struct Object
* delegate
= object_slot_value_at_offset((struct Object
*)delegates
, offset
);
230 if (delegate
!= oh
->cached
.nil
) {
231 oh
->delegation_stack
[delegationCount
++] = delegate
;
236 } /*end haven't been here before*/
241 if (delegationCount
< restricted
) restricted
= WORDT_MAX
; /*everything is unrestricted now*/
243 if (delegationCount
< 0 || delegationCount
>= DELEGATION_STACK_SIZE
) break;
245 arg
= oh
->delegation_stack
[delegationCount
];
253 if (dispatch
!= NULL
&& dispatch
->slotAccessor
!= oh
->cached
.nil
) {
254 /*check heap store into?*/
255 arguments
[0] = slotLocation
;
256 #ifdef PRINT_DEBUG_DISPATCH_SLOT_CHANGES
257 printf("arguments[0] changed to slot location: \n");
258 print_detail(oh
, arguments
[0]);
263 #ifndef SLATE_DISABLE_METHOD_CACHE
264 if (dispatch
!= NULL
&& resendMethod
== 0 && arity
< METHOD_CACHE_ARITY
) {
265 method_save_cache(oh
, dispatch
, name
, arguments
, arity
);
273 bool method_on_call_stack(struct object_heap
* oh
, struct CompiledMethod
* method
) {
275 struct Interpreter
* i
= oh
->cached
.interpreter
;
276 word_t fp
= i
->framePointer
;
277 struct Closure
* closure
= (struct Closure
*)i
->method
;
279 if (closure
->method
== method
) return true;
280 fp
= object_to_smallint(i
->stack
->elements
[fp
- FRAME_OFFSET_PREVIOUS_FRAME_POINTER
]);
281 if (fp
< FUNCTION_FRAME_SIZE
) break;
282 closure
= (struct Closure
*)i
->stack
->elements
[fp
- FRAME_OFFSET_METHOD
];
283 } while (fp
>= FUNCTION_FRAME_SIZE
);
285 if (closure
->method
== method
) return true;
290 void method_unoptimize(struct object_heap
* oh
, struct CompiledMethod
* method
) {
291 #ifdef PRINT_DEBUG_UNOPTIMIZER
292 printf("Unoptimizing '"); print_symbol(method
->selector
); printf("'\n");
294 if (method_on_call_stack(oh
, method
)) {
295 printf("Fixme cannot unoptimizing because on call stack: '"); print_symbol(method
->selector
); printf("'\n");
299 method
->code
= method
->oldCode
;
300 heap_store_into(oh
, (struct Object
*) method
->code
, (struct Object
*) method
->oldCode
);
301 method
->isInlined
= oh
->cached
.false_object
;
302 method
->calleeCount
= (struct OopArray
*)oh
->cached
.nil
;
303 method
->callCount
= smallint_to_object(0);
304 oh
->optimizedMethods
.erase(method
);
309 void method_remove_optimized_sending(struct object_heap
* oh
, struct Symbol
* symbol
) {
310 if (oh
->optimizedMethods
.empty()) return;
311 for (std::multiset
<struct CompiledMethod
*>::iterator i
= oh
->optimizedMethods
.begin(); i
!= oh
->optimizedMethods
.end(); i
++) {
312 struct CompiledMethod
* method
= *i
;
314 if (method
->selector
== symbol
) {
315 method_unoptimize(oh
, method
);
318 for (int j
= 0; j
< array_size(method
->selectors
); j
++) {
319 if (array_elements(method
->selectors
)[j
] == (struct Object
*)symbol
) {
320 method_unoptimize(oh
, method
);
330 void method_optimize(struct object_heap
* oh
, struct CompiledMethod
* method
) {
332 /* only optimize old objects because they don't move in memory and
333 * we don't want to have to update our method cache every gc */
334 if (object_is_young(oh
, (struct Object
*)method
)) return;
337 // make sure we don't optimize something already on the stack
338 // since a return will put us possibly at a different op code
339 if (method_on_call_stack(oh
, method
)) {
343 if (!optimizer_method_can_be_optimized(oh
, method
)) {
344 //don't bother trying anymore
345 method
->isInlined
= oh
->cached
.true_object
;
346 method
->oldCode
= method
->code
;
347 method
->nextInlineAtCallCount
= oh
->cached
.nil
;
351 #ifdef PRINT_DEBUG_OPTIMIZER
352 printf("Optimizing '"); print_symbol(method
->selector
); printf("'\n");
356 #ifdef PRINT_DEBUG_OPTIMIZER2
357 method_print_debug_info(oh
, method
);
358 printf("This method is called by:\n");
359 method_print_debug_info(oh
, oh
->cached
.interpreter
->method
);
362 if ((struct Object
*)method
->oldCode
== oh
->cached
.nil
) {
363 method
->oldCode
= method
->code
;
364 heap_store_into(oh
, (struct Object
*) method
->oldCode
, (struct Object
*) method
->code
);
367 //whether to start with a fresh slate
368 //not starting may give us another degree of inlining
369 heap_store_into(oh
, (struct Object
*) method
->oldCode
, (struct Object
*) method
->code
);
371 method
->isInlined
= oh
->cached
.true_object
;
372 oh
->optimizedMethods
.insert(method
);
373 #ifdef SLATE_SHOW_INLINER_CODE
375 print_type(oh
, (struct Object
*)method
->selector
);
376 print_code_disassembled(oh
, method
->code
);
378 optimizer_inline_callees(oh
, method
);
379 #ifdef SLATE_SHOW_INLINER_CODE
381 print_code_disassembled(oh
, method
->code
);
386 void method_pic_setup(struct object_heap
* oh
, struct CompiledMethod
* caller
) {
388 caller
->calleeCount
= heap_clone_oop_array_sized(oh
, get_special(oh
, SPECIAL_OOP_ARRAY_PROTO
), CALLER_PIC_SIZE
*CALLER_PIC_ENTRY_SIZE
);
389 heap_store_into(oh
, (struct Object
*) caller
, (struct Object
*) caller
->calleeCount
);
393 struct MethodDefinition
* method_pic_match_selector(struct object_heap
* oh
, struct Object
* picEntry
[],
394 struct Symbol
* selector
,
395 word_t arity
, struct Object
* args
[], word_t incrementWhenFound
) {
396 struct Closure
* closure
= (struct Closure
*) ((struct MethodDefinition
*)picEntry
[PIC_CALLEE
])->method
;
397 struct Symbol
* methodSelector
;
398 /*primitive methods store their selector in a different place*/
399 if (closure
->base
.map
->delegates
->elements
[0] == oh
->cached
.primitive_method_window
) {
400 methodSelector
= (struct Symbol
*)((struct PrimitiveMethod
*)closure
)->selector
;
402 methodSelector
= closure
->method
->selector
;
405 if (methodSelector
== selector
406 && object_to_smallint(picEntry
[PIC_CALLEE_ARITY
]) == arity
) {
407 /*callee method and arity work out, check the maps*/
408 word_t j
, success
= 1;
409 for (j
= 0; j
< arity
; j
++) {
410 if ((struct Map
*)((struct OopArray
*)picEntry
[PIC_CALLEE_MAPS
])->elements
[j
] != object_get_map(oh
, args
[j
])) {
416 if (incrementWhenFound
) {
417 picEntry
[PIC_CALLEE_COUNT
] = smallint_to_object(object_to_smallint(picEntry
[PIC_CALLEE_COUNT
]) + 1);
419 return (struct MethodDefinition
*)picEntry
[PIC_CALLEE
];
426 void method_pic_insert(struct object_heap
* oh
, struct OopArray
* calleeCount
,
427 struct Object
* picEntry
[], struct MethodDefinition
* def
,
428 word_t arity
, struct Object
* args
[]) {
431 picEntry
[PIC_CALLEE
] = (struct Object
*)def
;
432 picEntry
[PIC_CALLEE_ARITY
] = smallint_to_object(arity
);
433 picEntry
[PIC_CALLEE_COUNT
] = smallint_to_object(1);
434 picEntry
[PIC_CALLEE_MAPS
] =
435 (struct Object
*)heap_clone_oop_array_sized(oh
, get_special(oh
, SPECIAL_OOP_ARRAY_PROTO
), arity
);
437 heap_store_into(oh
, (struct Object
*) calleeCount
, picEntry
[PIC_CALLEE
]);
438 heap_store_into(oh
, (struct Object
*) calleeCount
, picEntry
[PIC_CALLEE_MAPS
]);
440 for (j
= 0; j
< arity
; j
++) {
441 ((struct OopArray
*)picEntry
[PIC_CALLEE_MAPS
])->elements
[j
] = (struct Object
*)object_get_map(oh
, args
[j
]);
442 heap_store_into(oh
, picEntry
[PIC_CALLEE_MAPS
], ((struct OopArray
*)picEntry
[PIC_CALLEE_MAPS
])->elements
[j
]);
447 void method_pic_flush_caller_pics(struct object_heap
* oh
, struct CompiledMethod
* callee
) {
450 if (callee
->base
.map
->delegates
->elements
[0] == oh
->cached
.closure_method_window
) callee
= callee
->method
;
451 assert (callee
->base
.map
->delegates
->elements
[0] == oh
->cached
.compiled_method_window
);
452 if (!object_is_smallint(callee
->cachedInCallersCount
)) return;
453 for (i
= 0; i
< object_to_smallint(callee
->cachedInCallersCount
); i
++) {
454 /*this should reset the pic*/
455 method_pic_setup(oh
, (struct CompiledMethod
*)callee
->cachedInCallers
->elements
[i
]);
461 /*when a function is redefined, we need to know what PICs to flush. Here each method will
462 keep a list of all the pics that it is in */
463 void method_pic_add_callee_backreference(struct object_heap
* oh
,
464 struct CompiledMethod
* caller
, struct CompiledMethod
* callee
) {
466 if (callee
->base
.map
->delegates
->elements
[0] == oh
->cached
.closure_method_window
) callee
= callee
->method
;
467 if (callee
->base
.map
->delegates
->elements
[0] == oh
->cached
.primitive_method_window
) return;
469 assert (callee
->base
.map
->delegates
->elements
[0] == oh
->cached
.compiled_method_window
);
471 if ((struct Object
*)callee
->cachedInCallers
== oh
->cached
.nil
) {
472 callee
->cachedInCallers
= heap_clone_oop_array_sized(oh
, get_special(oh
, SPECIAL_OOP_ARRAY_PROTO
), 32);
473 heap_store_into(oh
, (struct Object
*)callee
, (struct Object
*)callee
->cachedInCallers
);
474 callee
->cachedInCallersCount
= smallint_to_object(0);
477 if (object_to_smallint(callee
->cachedInCallersCount
) >= array_size(callee
->cachedInCallers
)) {
478 struct OopArray
* newArray
= heap_clone_oop_array_sized(oh
, get_special(oh
, SPECIAL_OOP_ARRAY_PROTO
), array_size(callee
->cachedInCallers
) * 2);
479 copy_words_into(callee
->cachedInCallers
->elements
, array_size(callee
->cachedInCallers
), newArray
->elements
);
480 callee
->cachedInCallers
= newArray
;
481 heap_store_into(oh
, (struct Object
*)callee
, (struct Object
*)callee
->cachedInCallers
);
484 callee
->cachedInCallers
->elements
[object_to_smallint(callee
->cachedInCallersCount
)] = (struct Object
*)caller
;
485 heap_store_into(oh
, (struct Object
*)callee
->cachedInCallers
, (struct Object
*)caller
);
486 callee
->cachedInCallersCount
= smallint_to_object(object_to_smallint(callee
->cachedInCallersCount
) + 1);
490 void method_pic_add_callee(struct object_heap
* oh
, struct CompiledMethod
* callerMethod
, struct MethodDefinition
* def
,
491 word_t arity
, struct Object
* args
[]) {
493 word_t arraySize
= array_size(callerMethod
->calleeCount
);
494 word_t entryStart
= method_pic_hash(oh
, callerMethod
, arity
, args
);
497 if (callerMethod
->calleeCount
->elements
[i
+PIC_CALLEE
] == oh
->cached
.nil
) {
498 Pinned
<struct OopArray
> pinArray(oh
);
499 pinArray
= callerMethod
->calleeCount
;
500 method_pic_insert(oh
, callerMethod
->calleeCount
, &callerMethod
->calleeCount
->elements
[i
], def
, arity
, args
);
501 Pinned
<struct CompiledMethod
> defMethod(oh
);
502 defMethod
= (struct CompiledMethod
*) def
->method
;
503 method_pic_add_callee_backreference(oh
, callerMethod
, (struct CompiledMethod
*) defMethod
);
507 /*this old slow code will fill up the hash table instead of only looking at the entry where the hash lands us*/
509 for (i
= entryStart
; i
< arraySize
; i
+= CALLER_PIC_ENTRY_SIZE
) {
510 /* if it's nil, we need to insert it*/
511 if (callerMethod
->calleeCount
->elements
[i
+PIC_CALLEE
] == oh
->cached
.nil
) {
512 Pinned
<struct OopArray
> pinArray(oh
);
513 pinArray
= callerMethod
->calleeCount
;
514 method_pic_insert(oh
, callerMethod
->calleeCount
, &callerMethod
->calleeCount
->elements
[i
], def
, arity
, args
);
515 Pinned
<struct CompiledMethod
> defMethod(oh
);
516 defMethod
= (struct CompiledMethod
*) def
->method
;
517 method_pic_add_callee_backreference(oh
, callerMethod
, (struct CompiledMethod
*) defMethod
);
521 for (i
= 0; i
< entryStart
; i
+= CALLER_PIC_ENTRY_SIZE
) {
522 /*MUST be same as first loop*/
523 if (callerMethod
->calleeCount
->elements
[i
+PIC_CALLEE
] == oh
->cached
.nil
) {
524 method_pic_insert(oh
, callerMethod
->calleeCount
, &callerMethod
->calleeCount
->elements
[i
], def
, arity
, args
);
525 Pinned
<struct CompiledMethod
> defMethod(oh
);
526 defMethod
= (struct CompiledMethod
*) def
->method
;
527 method_pic_add_callee_backreference(oh
, callerMethod
, (struct CompiledMethod
*)defMethod
);
536 struct MethodDefinition
* method_pic_find_callee(struct object_heap
* oh
, struct CompiledMethod
* callerMethod
,
537 struct Symbol
* selector
, word_t arity
, struct Object
* args
[]) {
539 #ifdef SLATE_DISABLE_PIC_LOOKUP
543 Pinned
<struct MethodDefinition
> retval(oh
);
545 word_t arraySize
= array_size(callerMethod
->calleeCount
);
546 word_t entryStart
= method_pic_hash(oh
, callerMethod
, arity
, args
);
550 if (callerMethod
->calleeCount
->elements
[i
+PIC_CALLEE
] == oh
->cached
.nil
) return NULL
;
551 retval
= method_pic_match_selector(oh
, &callerMethod
->calleeCount
->elements
[i
], selector
, arity
, args
, TRUE
);
552 if ((struct MethodDefinition
*)retval
!= NULL
) return retval
;
553 return NULL
; /*only look at first match*/
555 #else /*this old code goes through the whole hash table which will take a while in a bad case*/
556 for (i
= entryStart
; i
< arraySize
; i
+= CALLER_PIC_ENTRY_SIZE
) {
557 if (callerMethod
->calleeCount
->elements
[i
+PIC_CALLEE
] == oh
->cached
.nil
) return NULL
;
558 retval
= method_pic_match_selector(oh
, &callerMethod
->calleeCount
->elements
[i
], selector
, arity
, args
, TRUE
);
559 if ((struct MethodDefinition
*)retval
!= NULL
) return retval
;
561 for (i
= 0; i
< entryStart
; i
+= CALLER_PIC_ENTRY_SIZE
) {
562 /*MUST be same as first loop*/
563 if (callerMethod
->calleeCount
->elements
[i
+PIC_CALLEE
] == oh
->cached
.nil
) return NULL
;
564 retval
= method_pic_match_selector(oh
, &callerMethod
->calleeCount
->elements
[i
], selector
, arity
, args
, TRUE
);
565 if ((struct MethodDefinition
*)retval
!= NULL
) return retval
;
571 struct MethodDefinition
* method_is_on_arity(struct object_heap
* oh
, struct Object
* method
, struct Symbol
* selector
, struct Object
* args
[], word_t n
) {
574 struct MethodDefinition
* def
;
579 for (i
= 0; i
< n
; i
++) {
580 if (!object_is_smallint(args
[i
])) {
582 struct MethodDefinition
* roleDef
= object_has_role_named_at(args
[i
], selector
, 1<<i
, method
);
583 if (roleDef
!= NULL
) {
591 return ((def
!= NULL
&& positions
== def
->dispatchPositions
)? def
: NULL
);
596 struct MethodDefinition
* method_define(struct object_heap
* oh
, struct Object
* method
, struct Symbol
* selector
, struct Object
* args
[], word_t n
) {
599 struct Object
* argBuffer
[MAX_ARITY
];
600 Pinned
<struct MethodDefinition
> def(oh
);
601 Pinned
<struct MethodDefinition
> oldDef(oh
);
603 def
= (struct MethodDefinition
*)heap_clone_special(oh
, SPECIAL_OOP_METHOD_DEF_PROTO
);
605 for (i
= 0; i
< n
; i
++) {
606 if (!object_is_smallint(args
[i
]) && args
[i
] != get_special(oh
, SPECIAL_OOP_NO_ROLE
)) {
607 positions
|= (1 << i
);
611 /* any methods that call the same symbol must be decompiled because they might call an old version */
612 method_remove_optimized_sending(oh
, selector
);
613 selector
->cacheMask
= smallint_to_object(object_to_smallint(selector
->cacheMask
) | positions
);
614 assert(n
<= MAX_ARITY
);
616 copy_words_into(args
, n
, argBuffer
); /* method_dispatch_on modifies its arguments (first argument)*/
617 oldDef
= method_dispatch_on(oh
, selector
, argBuffer
, n
, NULL
);
618 if (oldDef
== (struct Object
*)NULL
|| oldDef
->dispatchPositions
!= positions
|| oldDef
!= method_is_on_arity(oh
, oldDef
->method
, selector
, args
, n
)) {
621 if (oldDef
!= (struct Object
*)NULL
) {
622 Pinned
<struct CompiledMethod
> oldDefMethod(oh
);
623 oldDefMethod
= (struct CompiledMethod
*)oldDef
->method
;
624 method_pic_flush_caller_pics(oh
, (struct CompiledMethod
*)oldDefMethod
);
626 def
->method
= method
;
627 heap_store_into(oh
, (struct Object
*) def
, (struct Object
*) method
);
628 def
->dispatchPositions
= positions
;
631 for (i
= 0; i
< n
; i
++) {
632 if (!object_is_smallint(args
[i
]) && (struct Object
*)args
[i
] != get_special(oh
, SPECIAL_OOP_NO_ROLE
)) {
633 if (oldDef
!= (struct Object
*)NULL
) {
634 object_remove_role(oh
, args
[i
], selector
, oldDef
);
636 object_add_role_at(oh
, args
[i
], selector
, 1<<i
, def
);