00001 #include "slate.hpp"
00002
00003
00004 word_t method_pic_hash(struct object_heap* oh, struct CompiledMethod* callerMethod, word_t arity, struct Object* args[]) {
00005 word_t arraySize = array_size(callerMethod->calleeCount);
00006 word_t entryStart = (hash_selector(oh, NULL, args, arity) % (arraySize/CALLER_PIC_ENTRY_SIZE)) * CALLER_PIC_ENTRY_SIZE;
00007 return entryStart;
00008 }
00009
00010
00011
00012 void method_save_cache(struct object_heap* oh, struct MethodDefinition* md, struct Symbol* name, struct Object* arguments[], word_t n) {
00013 struct MethodCacheEntry* cacheEntry;
00014 word_t i;
00015 word_t hash = hash_selector(oh, name, arguments, n);
00016 assert(n <= METHOD_CACHE_ARITY);
00017 cacheEntry = &oh->methodCache[hash & (METHOD_CACHE_SIZE-1)];
00018 cacheEntry->method = md;
00019 cacheEntry->selector = name;
00020 for (i = 0; i < n; i++) {
00021 cacheEntry->maps[i] = object_get_map(oh, arguments[i]);
00022 }
00023 }
00024
00025
00026 struct MethodDefinition* method_check_cache(struct object_heap* oh, struct Symbol* selector, struct Object* arguments[], word_t n) {
00027 struct MethodCacheEntry* cacheEntry;
00028 word_t hash = hash_selector(oh, selector, arguments, n);
00029 assert(n <= METHOD_CACHE_ARITY);
00030 oh->method_cache_access++;
00031 cacheEntry = &oh->methodCache[hash & (METHOD_CACHE_SIZE-1)];
00032 if (cacheEntry->selector != selector) return NULL;
00033
00034
00035 if (object_to_smallint(selector->cacheMask) > (1 << n)) return NULL;
00036
00037 switch (object_to_smallint(selector->cacheMask)) {
00038 case 1: if (object_get_map(oh, arguments[0]) != cacheEntry->maps[0]) return NULL; break;
00039 case 2: if (object_get_map(oh, arguments[1]) != cacheEntry->maps[1]) return NULL; break;
00040 case 4: if (object_get_map(oh, arguments[2]) != cacheEntry->maps[2]) return NULL; break;
00041
00042 case 3: if (object_get_map(oh, arguments[0]) != cacheEntry->maps[0] ||
00043 object_get_map(oh, arguments[1]) != cacheEntry->maps[1]) return NULL; break;
00044 case 5: if (object_get_map(oh, arguments[0]) != cacheEntry->maps[0] ||
00045 object_get_map(oh, arguments[2]) != cacheEntry->maps[2]) return NULL; break;
00046 case 6: if (object_get_map(oh, arguments[1]) != cacheEntry->maps[1] ||
00047 object_get_map(oh, arguments[2]) != cacheEntry->maps[2]) return NULL; break;
00048
00049 case 7: if (object_get_map(oh, arguments[0]) != cacheEntry->maps[0] ||
00050 object_get_map(oh, arguments[1]) != cacheEntry->maps[1] ||
00051 object_get_map(oh, arguments[2]) != cacheEntry->maps[2]) return NULL; break;
00052 }
00053 oh->method_cache_hit++;
00054 return cacheEntry->method;
00055
00056 }
00057
00058
00059
00060
00061
00062
00063
00064 struct MethodDefinition* method_dispatch_on(struct object_heap* oh, struct Symbol* name,
00065 struct Object* arguments[], word_t arity, struct Object* resendMethod) {
00066
00067 struct MethodDefinition *dispatch, *bestDef;
00068 struct Object* slotLocation;
00069 word_t bestRank, depth, delegationCount, resendRank, restricted, i;
00070
00071
00072 #ifdef PRINT_DEBUG_DISPATCH
00073 printf("dispatch to: '");
00074 print_symbol(name);
00075 printf("' (arity: %" PRIdPTR ")\n", arity);
00076 for (i = 0; i < arity; i++) {
00077 printf("arguments[%" PRIdPTR "] (%p) = ", i, (void*)arguments[i]); print_type(oh, arguments[i]);
00078 }
00079
00080 #endif
00081
00082 dispatch = NULL;
00083 slotLocation = NULL;
00084
00085 #ifndef SLATE_DISABLE_METHOD_CACHE
00086 if (resendMethod == NULL && arity <= METHOD_CACHE_ARITY) {
00087 dispatch = method_check_cache(oh, name, arguments, arity);
00088 if (dispatch != NULL) return dispatch;
00089 }
00090 #endif
00091
00092 oh->current_dispatch_id++;
00093 bestRank = 0;
00094 bestDef = NULL;
00095 resendRank = ((resendMethod == NULL) ? WORDT_MAX : 0);
00096
00097 for (i = 0; i < arity; i++) {
00098 struct Object *obj;
00099 struct Map* map;
00100 struct Object* arg = arguments[i];
00101 delegationCount = 0;
00102 depth = 0;
00103 restricted = WORDT_MAX;
00104
00105 do {
00106
00107
00108 if (object_is_smallint(arg)) {
00109 obj = get_special(oh, SPECIAL_OOP_SMALL_INT_PROTO);
00110 } else {
00111 obj = arg;
00112 }
00113
00114
00115 map = obj->map;
00116
00117 if (map->dispatchID != oh->current_dispatch_id) {
00118 map->dispatchID = oh->current_dispatch_id;
00119 map->visitedPositions = 0;
00120 }
00121
00122
00123 if ((map->visitedPositions & (1 << i)) == 0) {
00124
00125 struct RoleEntry* role;
00126
00127
00128
00129
00130
00131 if (((word_t)map->flags & MAP_FLAG_RESTRICT_DELEGATION) && (arg != arguments[i])) {
00132 restricted = delegationCount;
00133 }
00134 map->visitedPositions |= (1 << i);
00135 role = role_table_entry_for_name(oh, map->roleTable, name);
00136 while (role != NULL) {
00137 if ((object_to_smallint(role->rolePositions) & (1 << i)) != 0) {
00138 struct MethodDefinition* def = role->methodDefinition;
00139
00140
00141 if (def->dispatchID != oh->current_dispatch_id) {
00142 def->dispatchID = oh->current_dispatch_id;
00143 def->foundPositions = 0;
00144 def->dispatchRank = 0;
00145 }
00146
00147 if ((def->foundPositions & (1 << i)) == 0) {
00148
00149
00150 def->dispatchRank |= ((31 - depth) << ((5 - i) * 5));
00151 def->foundPositions |= (1 << i);
00152
00153 #ifdef PRINT_DEBUG_FOUND_ROLE
00154 printf("found role index %" PRIdPTR " <%p> for '%s' foundPos: %" PRIuPTR "x dispatchPos: %" PRIuPTR "x\n",
00155 i,
00156 (void*) role,
00157 ((struct Symbol*)(role->name))->elements, def->foundPositions, def->dispatchPositions);
00158 #endif
00159
00160 if (def->method == resendMethod) {
00161 struct RoleEntry* rescan = role_table_entry_for_name(oh, map->roleTable, name);
00162 resendRank = def->dispatchRank;
00163 while (rescan != role) {
00164 struct MethodDefinition* redef = rescan->methodDefinition;
00165 if (redef->foundPositions == redef->dispatchPositions &&
00166 (dispatch == NULL || redef->dispatchRank <= resendRank)) {
00167 dispatch = redef;
00168 slotLocation = obj;
00169 if (redef->dispatchRank > bestRank) {
00170 bestRank = redef->dispatchRank;
00171 bestDef = redef;
00172 }
00173 }
00174 if (rescan->nextRole == oh->cached.nil) {
00175 rescan = NULL;
00176 } else {
00177 rescan = &map->roleTable->roles[object_to_smallint(rescan->nextRole)];
00178 }
00179
00180 }
00181
00182 } else {
00183 if (def->foundPositions == def->dispatchPositions &&
00184 (dispatch == NULL || def->dispatchRank > dispatch->dispatchRank) &&
00185 def->dispatchRank <= resendRank) {
00186 dispatch = def;
00187 slotLocation = obj;
00188 if (def->dispatchRank > bestRank) {
00189 bestRank = def->dispatchRank;
00190 bestDef = def;
00191 }
00192 }
00193 }
00194 if (def->dispatchRank >= bestRank && def != bestDef) {
00195 bestRank = def->dispatchRank;
00196 bestDef = NULL;
00197 }
00198 }
00199
00200 }
00201 role = ((role->nextRole == oh->cached.nil) ? NULL : &map->roleTable->roles[object_to_smallint(role->nextRole)]);
00202 }
00203
00204 if (depth > 31) {
00205 assert(0);
00206 }
00207 if (dispatch != NULL && bestDef == dispatch) {
00208 if (dispatch->slotAccessor != oh->cached.nil) {
00209 arguments[0] = slotLocation;
00210
00211 #ifdef PRINT_DEBUG_DISPATCH_SLOT_CHANGES
00212 printf("arguments[0] changed to slot location: \n");
00213 print_detail(oh, arguments[0]);
00214 #endif
00215 }
00216 if (resendMethod == 0 && arity <= METHOD_CACHE_ARITY) method_save_cache(oh, dispatch, name, arguments, arity);
00217 return dispatch;
00218 }
00219
00220 depth++;
00221
00222
00223
00224 if (delegationCount <= restricted && array_size(map->delegates) > 0) {
00225 struct OopArray* delegates = map->delegates;
00226 word_t offset = object_array_offset((struct Object*)delegates);
00227 word_t limit = object_total_size((struct Object*)delegates);
00228 for (; offset != limit; offset += sizeof(word_t)) {
00229 struct Object* delegate = object_slot_value_at_offset((struct Object*)delegates, offset);
00230 if (delegate != oh->cached.nil) {
00231 oh->delegation_stack[delegationCount++] = delegate;
00232 }
00233 }
00234 }
00235
00236 }
00237
00238
00239
00240 delegationCount--;
00241 if (delegationCount < restricted) restricted = WORDT_MAX;
00242
00243 if (delegationCount < 0 || delegationCount >= DELEGATION_STACK_SIZE) break;
00244
00245 arg = oh->delegation_stack[delegationCount];
00246
00247
00248 } while (1);
00249
00250 }
00251
00252
00253 if (dispatch != NULL && dispatch->slotAccessor != oh->cached.nil) {
00254
00255 arguments[0] = slotLocation;
00256 #ifdef PRINT_DEBUG_DISPATCH_SLOT_CHANGES
00257 printf("arguments[0] changed to slot location: \n");
00258 print_detail(oh, arguments[0]);
00259 #endif
00260
00261 }
00262
00263 #ifndef SLATE_DISABLE_METHOD_CACHE
00264 if (dispatch != NULL && resendMethod == 0 && arity < METHOD_CACHE_ARITY) {
00265 method_save_cache(oh, dispatch, name, arguments, arity);
00266 }
00267 #endif
00268
00269 return dispatch;
00270 }
00271
00272
00273
00274
00275 void method_unoptimize(struct object_heap* oh, struct CompiledMethod* method) {
00276 #ifdef PRINT_DEBUG_UNOPTIMIZER
00277 printf("Unoptimizing '"); print_symbol(method->selector); printf("'\n");
00278 #endif
00279 method->code = method->oldCode;
00280 heap_store_into(oh, (struct Object*) method->code, (struct Object*) method->oldCode);
00281 method->isInlined = oh->cached.false_object;
00282 method->calleeCount = (struct OopArray*)oh->cached.nil;
00283 method->callCount = smallint_to_object(0);
00284 oh->optimizedMethods.erase(method);
00285
00286 }
00287
00288
00289 void method_remove_optimized_sending(struct object_heap* oh, struct Symbol* symbol) {
00290 if (oh->optimizedMethods.empty()) return;
00291 for (std::multiset<struct CompiledMethod*>::iterator i = oh->optimizedMethods.begin(); i != oh->optimizedMethods.end(); i++) {
00292 struct CompiledMethod* method = *i;
00293
00294 if (method->selector == symbol) {
00295 method_unoptimize(oh, method);
00296 continue;
00297 }
00298 for (int j = 0; j < array_size(method->selectors); j++) {
00299 if (array_elements(method->selectors)[j] == (struct Object*)symbol) {
00300 method_unoptimize(oh, method);
00301 break;
00302 }
00303 }
00304 }
00305
00306 }
00307
00308 bool method_on_call_stack(struct object_heap* oh, struct CompiledMethod* method) {
00309
00310 struct Interpreter* i = oh->cached.interpreter;
00311 word_t fp = i->framePointer;
00312 struct Closure* closure = (struct Closure*)i->method;
00313 do {
00314 if (closure->method == method) return true;
00315 fp = object_to_smallint(i->stack->elements[fp - FRAME_OFFSET_PREVIOUS_FRAME_POINTER]);
00316 if (fp < FUNCTION_FRAME_SIZE) break;
00317 closure = (struct Closure*)i->stack->elements[fp - FRAME_OFFSET_METHOD];
00318 } while (fp >= FUNCTION_FRAME_SIZE);
00319
00320 if (closure->method == method) return true;
00321 return false;
00322 }
00323
00324
00325 void method_optimize(struct object_heap* oh, struct CompiledMethod* method) {
00326
00327
00328
00329 if (object_is_young(oh, (struct Object*)method)) return;
00330
00331
00332
00333
00334 if (method_on_call_stack(oh, method)) {
00335 return;
00336 }
00337
00338 if (!optimizer_method_can_be_optimized(oh, method)) {
00339
00340 method->isInlined = oh->cached.true_object;
00341 method->oldCode = method->code;
00342 method->nextInlineAtCallCount = oh->cached.nil;
00343 return;
00344 }
00345
00346 #ifdef PRINT_DEBUG_OPTIMIZER
00347 printf("Optimizing '"); print_symbol(method->selector); printf("'\n");
00348 #endif
00349
00350
00351 #ifdef PRINT_DEBUG_OPTIMIZER2
00352 method_print_debug_info(oh, method);
00353 printf("This method is called by:\n");
00354 method_print_debug_info(oh, oh->cached.interpreter->method);
00355 #endif
00356
00357 if ((struct Object*)method->oldCode == oh->cached.nil) {
00358 method->oldCode = method->code;
00359 heap_store_into(oh, (struct Object*) method->oldCode, (struct Object*) method->code);
00360
00361 }
00362
00363
00364
00365 heap_store_into(oh, (struct Object*) method->oldCode, (struct Object*) method->code);
00366
00367 method->isInlined = oh->cached.true_object;
00368 oh->optimizedMethods.insert(method);
00369 #ifdef SLATE_SHOW_INLINER_CODE
00370 printf("before:\n");
00371 print_type(oh, (struct Object*)method->selector);
00372 print_code_disassembled(oh, method->code);
00373 #endif
00374 optimizer_inline_callees(oh, method);
00375 #ifdef SLATE_SHOW_INLINER_CODE
00376 printf("after:\n");
00377 print_code_disassembled(oh, method->code);
00378 #endif
00379
00380 }
00381
00382 void method_pic_setup(struct object_heap* oh, struct CompiledMethod* caller) {
00383
00384 caller->calleeCount = heap_clone_oop_array_sized(oh, get_special(oh, SPECIAL_OOP_ARRAY_PROTO), CALLER_PIC_SIZE*CALLER_PIC_ENTRY_SIZE);
00385 heap_store_into(oh, (struct Object*) caller, (struct Object*) caller->calleeCount);
00386
00387 }
00388
00389 struct MethodDefinition* method_pic_match_selector(struct object_heap* oh, struct Object* picEntry[],
00390 struct Symbol* selector,
00391 word_t arity, struct Object* args[], word_t incrementWhenFound) {
00392 struct Closure* closure = (struct Closure*) ((struct MethodDefinition*)picEntry[PIC_CALLEE])->method;
00393 struct Symbol* methodSelector;
00394
00395 if (closure->base.map->delegates->elements[0] == oh->cached.primitive_method_window) {
00396 methodSelector = (struct Symbol*)((struct PrimitiveMethod*)closure)->selector;
00397 } else {
00398 methodSelector = closure->method->selector;
00399 }
00400
00401 if (methodSelector == selector
00402 && object_to_smallint(picEntry[PIC_CALLEE_ARITY]) == arity) {
00403
00404 word_t j, success = 1;
00405 for (j = 0; j < arity; j++) {
00406 if ((struct Map*)((struct OopArray*)picEntry[PIC_CALLEE_MAPS])->elements[j] != object_get_map(oh, args[j])) {
00407 success = 0;
00408 break;
00409 }
00410 }
00411 if (success) {
00412 if (incrementWhenFound) {
00413 picEntry[PIC_CALLEE_COUNT] = smallint_to_object(object_to_smallint(picEntry[PIC_CALLEE_COUNT]) + 1);
00414 }
00415 return (struct MethodDefinition*)picEntry[PIC_CALLEE];
00416 }
00417 }
00418 return NULL;
00419 }
00420
00421
00422 void method_pic_insert(struct object_heap* oh, struct OopArray* calleeCount,
00423 struct Object* picEntry[], struct MethodDefinition* def,
00424 word_t arity, struct Object* args[]) {
00425
00426 word_t j;
00427 picEntry[PIC_CALLEE] = (struct Object*)def;
00428 picEntry[PIC_CALLEE_ARITY] = smallint_to_object(arity);
00429 picEntry[PIC_CALLEE_COUNT] = smallint_to_object(1);
00430 picEntry[PIC_CALLEE_MAPS] =
00431 (struct Object*)heap_clone_oop_array_sized(oh, get_special(oh, SPECIAL_OOP_ARRAY_PROTO), arity);
00432
00433 heap_store_into(oh, (struct Object*) calleeCount, picEntry[PIC_CALLEE]);
00434 heap_store_into(oh, (struct Object*) calleeCount, picEntry[PIC_CALLEE_MAPS]);
00435
00436 for (j = 0; j < arity; j++) {
00437 ((struct OopArray*)picEntry[PIC_CALLEE_MAPS])->elements[j] = (struct Object*)object_get_map(oh, args[j]);
00438 heap_store_into(oh, picEntry[PIC_CALLEE_MAPS], ((struct OopArray*)picEntry[PIC_CALLEE_MAPS])->elements[j]);
00439 }
00440
00441 }
00442
00443 void method_pic_flush_caller_pics(struct object_heap* oh, struct CompiledMethod* callee) {
00444
00445 int i;
00446 if (callee->base.map->delegates->elements[0] == oh->cached.closure_method_window) callee = callee->method;
00447 assert (callee->base.map->delegates->elements[0] == oh->cached.compiled_method_window);
00448 if (!object_is_smallint(callee->cachedInCallersCount)) return;
00449 for (i = 0; i < object_to_smallint(callee->cachedInCallersCount); i++) {
00450
00451 method_pic_setup(oh, (struct CompiledMethod*)callee->cachedInCallers->elements[i]);
00452 }
00453
00454
00455 }
00456
00457
00458
00459 void method_pic_add_callee_backreference(struct object_heap* oh,
00460 struct CompiledMethod* caller, struct CompiledMethod* callee) {
00461
00462 if (callee->base.map->delegates->elements[0] == oh->cached.closure_method_window) callee = callee->method;
00463 if (callee->base.map->delegates->elements[0] == oh->cached.primitive_method_window) return;
00464
00465 assert (callee->base.map->delegates->elements[0] == oh->cached.compiled_method_window);
00466
00467 if ((struct Object*)callee->cachedInCallers == oh->cached.nil) {
00468 callee->cachedInCallers = heap_clone_oop_array_sized(oh, get_special(oh, SPECIAL_OOP_ARRAY_PROTO), 32);
00469 heap_store_into(oh, (struct Object*)callee, (struct Object*)callee->cachedInCallers);
00470 callee->cachedInCallersCount = smallint_to_object(0);
00471 }
00472
00473 if (object_to_smallint(callee->cachedInCallersCount) >= array_size(callee->cachedInCallers)) {
00474 struct OopArray* newArray = heap_clone_oop_array_sized(oh, get_special(oh, SPECIAL_OOP_ARRAY_PROTO), array_size(callee->cachedInCallers) * 2);
00475 copy_words_into(callee->cachedInCallers->elements, array_size(callee->cachedInCallers), newArray->elements);
00476 callee->cachedInCallers = newArray;
00477 heap_store_into(oh, (struct Object*)callee, (struct Object*)callee->cachedInCallers);
00478 }
00479
00480 callee->cachedInCallers->elements[object_to_smallint(callee->cachedInCallersCount)] = (struct Object*)caller;
00481 heap_store_into(oh, (struct Object*)callee->cachedInCallers, (struct Object*)caller);
00482 callee->cachedInCallersCount = smallint_to_object(object_to_smallint(callee->cachedInCallersCount) + 1);
00483
00484 }
00485
00486 void method_pic_add_callee(struct object_heap* oh, struct CompiledMethod* callerMethod, struct MethodDefinition* def,
00487 word_t arity, struct Object* args[]) {
00488 word_t i;
00489 word_t arraySize = array_size(callerMethod->calleeCount);
00490 word_t entryStart = method_pic_hash(oh, callerMethod, arity, args);
00491
00492 #if 0
00493 if (callerMethod->calleeCount->elements[i+PIC_CALLEE] == oh->cached.nil) {
00494 Pinned<struct OopArray> pinArray(oh);
00495 pinArray = callerMethod->calleeCount;
00496 method_pic_insert(oh, callerMethod->calleeCount, &callerMethod->calleeCount->elements[i], def, arity, args);
00497 Pinned<struct CompiledMethod> defMethod(oh);
00498 defMethod = (struct CompiledMethod*) def->method;
00499 method_pic_add_callee_backreference(oh, callerMethod, (struct CompiledMethod*) defMethod);
00500 return;
00501 }
00502
00503
00504 #else
00505 for (i = entryStart; i < arraySize; i+= CALLER_PIC_ENTRY_SIZE) {
00506
00507 if (callerMethod->calleeCount->elements[i+PIC_CALLEE] == oh->cached.nil) {
00508 Pinned<struct OopArray> pinArray(oh);
00509 pinArray = callerMethod->calleeCount;
00510 method_pic_insert(oh, callerMethod->calleeCount, &callerMethod->calleeCount->elements[i], def, arity, args);
00511 Pinned<struct CompiledMethod> defMethod(oh);
00512 defMethod = (struct CompiledMethod*) def->method;
00513 method_pic_add_callee_backreference(oh, callerMethod, (struct CompiledMethod*) defMethod);
00514 return;
00515 }
00516 }
00517 for (i = 0; i < entryStart; i+= CALLER_PIC_ENTRY_SIZE) {
00518
00519 if (callerMethod->calleeCount->elements[i+PIC_CALLEE] == oh->cached.nil) {
00520 method_pic_insert(oh, callerMethod->calleeCount, &callerMethod->calleeCount->elements[i], def, arity, args);
00521 Pinned<struct CompiledMethod> defMethod(oh);
00522 defMethod = (struct CompiledMethod*) def->method;
00523 method_pic_add_callee_backreference(oh, callerMethod, (struct CompiledMethod*)defMethod);
00524 return;
00525 }
00526 }
00527 #endif
00528 }
00529
00530
00531
00532 struct MethodDefinition* method_pic_find_callee(struct object_heap* oh, struct CompiledMethod* callerMethod,
00533 struct Symbol* selector, word_t arity, struct Object* args[]) {
00534
00535 #ifdef SLATE_DISABLE_PIC_LOOKUP
00536 return NULL;
00537 #endif
00538
00539 Pinned<struct MethodDefinition> retval(oh);
00540 word_t i;
00541 word_t arraySize = array_size(callerMethod->calleeCount);
00542 word_t entryStart = method_pic_hash(oh, callerMethod, arity, args);
00543
00544
00545 #if 0
00546 if (callerMethod->calleeCount->elements[i+PIC_CALLEE] == oh->cached.nil) return NULL;
00547 retval = method_pic_match_selector(oh, &callerMethod->calleeCount->elements[i], selector, arity, args, TRUE);
00548 if ((struct MethodDefinition*)retval != NULL) return retval;
00549 return NULL;
00550
00551 #else
00552 for (i = entryStart; i < arraySize; i+= CALLER_PIC_ENTRY_SIZE) {
00553 if (callerMethod->calleeCount->elements[i+PIC_CALLEE] == oh->cached.nil) return NULL;
00554 retval = method_pic_match_selector(oh, &callerMethod->calleeCount->elements[i], selector, arity, args, TRUE);
00555 if ((struct MethodDefinition*)retval != NULL) return retval;
00556 }
00557 for (i = 0; i < entryStart; i+= CALLER_PIC_ENTRY_SIZE) {
00558
00559 if (callerMethod->calleeCount->elements[i+PIC_CALLEE] == oh->cached.nil) return NULL;
00560 retval = method_pic_match_selector(oh, &callerMethod->calleeCount->elements[i], selector, arity, args, TRUE);
00561 if ((struct MethodDefinition*)retval != NULL) return retval;
00562 }
00563 #endif
00564 return NULL;
00565 }
00566
00567 struct MethodDefinition* method_is_on_arity(struct object_heap* oh, struct Object* method, struct Symbol* selector, struct Object* args[], word_t n) {
00568
00569 word_t positions, i;
00570 struct MethodDefinition* def;
00571
00572 positions = 0;
00573 def = NULL;
00574
00575 for (i = 0; i < n; i++) {
00576 if (!object_is_smallint(args[i])) {
00577
00578 struct MethodDefinition* roleDef = object_has_role_named_at(args[i], selector, 1<<i, method);
00579 if (roleDef != NULL) {
00580 positions |= 1<<i;
00581 def = roleDef;
00582 }
00583
00584 }
00585 }
00586
00587 return ((def != NULL && positions == def->dispatchPositions)? def : NULL);
00588
00589 }
00590
00591
00592 struct MethodDefinition* method_define(struct object_heap* oh, struct Object* method, struct Symbol* selector, struct Object* args[], word_t n) {
00593
00594 word_t positions, i;
00595 struct Object* argBuffer[16];
00596 Pinned<struct MethodDefinition> def(oh);
00597 Pinned<struct MethodDefinition> oldDef(oh);
00598
00599 def = (struct MethodDefinition*)heap_clone_special(oh, SPECIAL_OOP_METHOD_DEF_PROTO);
00600 positions = 0;
00601 for (i = 0; i < n; i++) {
00602 if (!object_is_smallint(args[i]) && args[i] != get_special(oh, SPECIAL_OOP_NO_ROLE)) {
00603 positions |= (1 << i);
00604 }
00605 }
00606
00607
00608 method_remove_optimized_sending(oh, selector);
00609 selector->cacheMask = smallint_to_object(object_to_smallint(selector->cacheMask) | positions);
00610 assert(n<=16);
00611
00612 copy_words_into(args, n, argBuffer);
00613 oldDef = method_dispatch_on(oh, selector, argBuffer, n, NULL);
00614 if (oldDef == (struct Object*)NULL || oldDef->dispatchPositions != positions || oldDef != method_is_on_arity(oh, oldDef->method, selector, args, n)) {
00615 oldDef = NULL;
00616 }
00617 if (oldDef != (struct Object*)NULL) {
00618 Pinned<struct CompiledMethod> oldDefMethod(oh);
00619 oldDefMethod = (struct CompiledMethod*)oldDef->method;
00620 method_pic_flush_caller_pics(oh, (struct CompiledMethod*)oldDefMethod);
00621 }
00622 def->method = method;
00623 heap_store_into(oh, (struct Object*) def, (struct Object*) method);
00624 def->dispatchPositions = positions;
00625
00626
00627 for (i = 0; i < n; i++) {
00628 if (!object_is_smallint(args[i]) && (struct Object*)args[i] != get_special(oh, SPECIAL_OOP_NO_ROLE)) {
00629 if (oldDef != (struct Object*)NULL) {
00630 object_remove_role(oh, args[i], selector, oldDef);
00631 }
00632 object_add_role_at(oh, args[i], selector, 1<<i, def);
00633 }
00634 }
00635 return def;
00636
00637 }
00638