/*when a function is redefined, we need to know what PICs to flush. Here each method will keep a list of all the pics that it is in */ void method_pic_add_callee_backreference(struct object_heap* oh, struct CompiledMethod* caller, struct CompiledMethod* callee) { if (callee->base.map->delegates->elements[0] == oh->cached.closure_method_window) callee = callee->method; if (callee->base.map->delegates->elements[0] == oh->cached.primitive_method_window) return; assert (callee->base.map->delegates->elements[0] == oh->cached.compiled_method_window); if ((struct Object*)callee->cachedInCallers == oh->cached.nil) { callee->cachedInCallers = heap_clone_oop_array_sized(oh, get_special(oh, SPECIAL_OOP_ARRAY_PROTO), 32); heap_store_into(oh, (struct Object*)callee, (struct Object*)callee->cachedInCallers); callee->cachedInCallersCount = smallint_to_object(0); } if (object_to_smallint(callee->cachedInCallersCount) >= array_size(callee->cachedInCallers)) { struct OopArray* newArray = heap_clone_oop_array_sized(oh, get_special(oh, SPECIAL_OOP_ARRAY_PROTO), array_size(callee->cachedInCallers) * 2); copy_words_into(callee->cachedInCallers->elements, array_size(callee->cachedInCallers), newArray->elements); callee->cachedInCallers = newArray; heap_store_into(oh, (struct Object*)callee, (struct Object*)callee->cachedInCallers); } callee->cachedInCallers->elements[object_to_smallint(callee->cachedInCallersCount)] = (struct Object*)caller; heap_store_into(oh, (struct Object*)callee->cachedInCallers, (struct Object*)caller); callee->cachedInCallersCount = smallint_to_object(object_to_smallint(callee->cachedInCallersCount) + 1); }
struct MethodDefinition* method_pic_match_selector(struct object_heap* oh, struct Object* picEntry[], struct Symbol* selector, word_t arity, struct Object* args[], word_t incrementWhenFound) { struct Closure* closure = (struct Closure*) ((struct MethodDefinition*)picEntry[PIC_CALLEE])->method; struct Symbol* methodSelector; /*primitive methods store their selector in a different place*/ if (closure->base.map->delegates->elements[0] == oh->cached.primitive_method_window) { methodSelector = (struct Symbol*)((struct PrimitiveMethod*)closure)->selector; } else { methodSelector = closure->method->selector; } if (methodSelector == selector && object_to_smallint(picEntry[PIC_CALLEE_ARITY]) == arity) { /*callee method and arity work out, check the maps*/ word_t j, success = 1; for (j = 0; j < arity; j++) { if ((struct Map*)((struct OopArray*)picEntry[PIC_CALLEE_MAPS])->elements[j] != object_get_map(oh, args[j])) { success = 0; break; } } if (success) { if (incrementWhenFound) { picEntry[PIC_CALLEE_COUNT] = smallint_to_object(object_to_smallint(picEntry[PIC_CALLEE_COUNT]) + 1); } return (struct MethodDefinition*)picEntry[PIC_CALLEE]; } } return NULL; }
struct MethodDefinition* method_check_cache(struct object_heap* oh, struct Symbol* selector, struct Object* arguments[], word_t n) { struct MethodCacheEntry* cacheEntry; word_t hash = hash_selector(oh, selector, arguments, n); assert(n <= METHOD_CACHE_ARITY); oh->method_cache_access++; cacheEntry = &oh->methodCache[hash & (METHOD_CACHE_SIZE-1)]; if (cacheEntry->selector != selector) return NULL; /*fix findOn: might not call us with enough elements*/ if (object_to_smallint(selector->cacheMask) > (1 << n)) return NULL; switch (object_to_smallint(selector->cacheMask)) { /*the found positions for the function*/ case 1: if (object_get_map(oh, arguments[0]) != cacheEntry->maps[0]) return NULL; break; case 2: if (object_get_map(oh, arguments[1]) != cacheEntry->maps[1]) return NULL; break; case 4: if (object_get_map(oh, arguments[2]) != cacheEntry->maps[2]) return NULL; break; case 3: if (object_get_map(oh, arguments[0]) != cacheEntry->maps[0] || object_get_map(oh, arguments[1]) != cacheEntry->maps[1]) return NULL; break; case 5: if (object_get_map(oh, arguments[0]) != cacheEntry->maps[0] || object_get_map(oh, arguments[2]) != cacheEntry->maps[2]) return NULL; break; case 6: if (object_get_map(oh, arguments[1]) != cacheEntry->maps[1] || object_get_map(oh, arguments[2]) != cacheEntry->maps[2]) return NULL; break; case 7: if (object_get_map(oh, arguments[0]) != cacheEntry->maps[0] || object_get_map(oh, arguments[1]) != cacheEntry->maps[1] || object_get_map(oh, arguments[2]) != cacheEntry->maps[2]) return NULL; break; } oh->method_cache_hit++; return cacheEntry->method; }
void print_type(struct object_heap* oh, struct Object* o) { struct Object* traits; struct Object* traitsWindow; struct OopArray* x; if (object_is_smallint(o)) { fprintf(stderr, "%" PRIdPTR " (0x%" PRIuPTR ")\n", object_to_smallint(o), object_to_smallint(o)); return; } if (object_type(o) == TYPE_BYTE_ARRAY) { fprintf(stderr, "("); print_byte_array(o); fprintf(stderr, ") "); /*return;*/ } x = o->map->delegates; if (!x || array_size(x) < 1) goto fail; traitsWindow = x->elements[0]; { if (traitsWindow == oh->cached.compiled_method_window) { fprintf(stderr, "(method #"); print_byte_array((struct Object*)(((struct CompiledMethod*)o)->method->selector)); fprintf(stderr, ")"); } } x = traitsWindow->map->delegates; if (!x || array_size(x) < 1) goto fail; traits = x->elements[array_size(x)-1]; if (o == oh->cached.nil) { fprintf(stderr, "nil\n"); } else if (o == oh->cached.true_object) { fprintf(stderr, "true\n"); } else if (o == oh->cached.false_object) { fprintf(stderr, "false\n"); } else { print_printname(oh, o); fprintf(stderr, "("); print_printname(oh, traits); fprintf(stderr, ")\n"); } return; fail: fprintf(stderr, "<unknown type>\n"); }
void method_pic_flush_caller_pics(struct object_heap* oh, struct CompiledMethod* callee) { int i; if (callee->base.map->delegates->elements[0] == oh->cached.closure_method_window) callee = callee->method; assert (callee->base.map->delegates->elements[0] == oh->cached.compiled_method_window); if (!object_is_smallint(callee->cachedInCallersCount)) return; for (i = 0; i < object_to_smallint(callee->cachedInCallersCount); i++) { /*this should reset the pic*/ method_pic_setup(oh, (struct CompiledMethod*)callee->cachedInCallers->elements[i]); } }
word_t calculateMethodCallDepth(struct object_heap* oh) { struct Interpreter* i = oh->cached.interpreter; word_t fp = i->framePointer; word_t depth = 0; do { /*order matters here*/ fp = object_to_smallint(i->stack->elements[fp - FRAME_OFFSET_PREVIOUS_FRAME_POINTER]); if (fp < FUNCTION_FRAME_SIZE) break; depth++; } while (fp >= FUNCTION_FRAME_SIZE); return depth; }
bool method_on_call_stack(struct object_heap* oh, struct CompiledMethod* method) { struct Interpreter* i = oh->cached.interpreter; word_t fp = i->framePointer; struct Closure* closure = (struct Closure*)i->method; do { if (closure->method == method) return true; fp = object_to_smallint(i->stack->elements[fp - FRAME_OFFSET_PREVIOUS_FRAME_POINTER]); if (fp < FUNCTION_FRAME_SIZE) break; closure = (struct Closure*)i->stack->elements[fp - FRAME_OFFSET_METHOD]; } while (fp >= FUNCTION_FRAME_SIZE); if (closure->method == method) return true; return false; }
void print_object(struct Object* oop) { if (oop == NULL) { fprintf(stderr, "<object NULL>\n"); return; } if (oop_is_smallint((word_t)oop)) { fprintf(stderr, "<object int_value: %" PRIdPTR ">\n", object_to_smallint(oop)); } else { const char* typestr=0; switch (object_type(oop)) { case TYPE_OBJECT: typestr = "normal"; break; case TYPE_OOP_ARRAY: typestr = "oop array"; break; case TYPE_BYTE_ARRAY: typestr = "byte array"; break; } fprintf(stderr, "<object at %p, hash: 0x%" PRIxPTR ", size: %" PRIdPTR ", payload size: %" PRIdPTR ", type: %s>\n", (void*)oop, object_hash(oop), object_size(oop), payload_size(oop), typestr); } }
struct MethodDefinition* method_define(struct object_heap* oh, struct Object* method, struct Symbol* selector, struct Object* args[], word_t n) { word_t positions, i; struct Object* argBuffer[MAX_ARITY]; Pinned<struct MethodDefinition> def(oh); Pinned<struct MethodDefinition> oldDef(oh); def = (struct MethodDefinition*)heap_clone_special(oh, SPECIAL_OOP_METHOD_DEF_PROTO); positions = 0; for (i = 0; i < n; i++) { if (!object_is_smallint(args[i]) && args[i] != get_special(oh, SPECIAL_OOP_NO_ROLE)) { positions |= (1 << i); } } /* any methods that call the same symbol must be decompiled because they might call an old version */ method_remove_optimized_sending(oh, selector); selector->cacheMask = smallint_to_object(object_to_smallint(selector->cacheMask) | positions); assert(n <= MAX_ARITY); copy_words_into(args, n, argBuffer); /* method_dispatch_on modifies its arguments (first argument)*/ oldDef = method_dispatch_on(oh, selector, argBuffer, n, NULL); if (oldDef == (struct Object*)NULL || oldDef->dispatchPositions != positions || oldDef != method_is_on_arity(oh, oldDef->method, selector, args, n)) { oldDef = NULL; } if (oldDef != (struct Object*)NULL) { Pinned<struct CompiledMethod> oldDefMethod(oh); oldDefMethod = (struct CompiledMethod*)oldDef->method; method_pic_flush_caller_pics(oh, (struct CompiledMethod*)oldDefMethod); } def->method = method; heap_store_into(oh, (struct Object*) def, (struct Object*) method); def->dispatchPositions = positions; for (i = 0; i < n; i++) { if (!object_is_smallint(args[i]) && (struct Object*)args[i] != get_special(oh, SPECIAL_OOP_NO_ROLE)) { if (oldDef != (struct Object*)NULL) { object_remove_role(oh, args[i], selector, oldDef); } object_add_role_at(oh, args[i], selector, 1<<i, def); } } return def; }
bool_t print_printname(struct object_heap* oh, struct Object* o) { word_t i; struct Map* map = o->map; struct SlotTable* slotTable = map->slotTable; word_t limit = slot_table_capacity(slotTable); for (i=0; i < limit; i++) { if (slotTable->slots[i].name == (struct Symbol*)oh->cached.nil) continue; if (strncmp((char*)slotTable->slots[i].name->elements, "printName", 9) == 0) { struct Object* obj = object_slot_value_at_offset(o, object_to_smallint(slotTable->slots[i].offset)); if (object_is_smallint(obj) || object_type(obj) != TYPE_BYTE_ARRAY) { return FALSE; } else { print_byte_array(obj); return TRUE; } } } return FALSE; }
void print_object_with_depth(struct object_heap* oh, struct Object* o, word_t depth, word_t max_depth) { struct Map* map; word_t i; if (depth >= max_depth || object_is_smallint(o)) { fprintf(stderr, "(depth limit reached) "); print_object(o); return; } if (o == oh->cached.nil) { fprintf(stderr, "<object NilObject>\n"); return; } map = o->map; print_object(o); if (object_hash(o) >= ID_HASH_RESERVED) { indent(depth); fprintf(stderr, "<object is free/reserved>\n"); return; } indent(depth); fprintf(stderr, "{\n"); if (object_type(o) == TYPE_BYTE_ARRAY) { indent(depth); fprintf(stderr, "bytes: "); print_byte_array(o); fprintf(stderr, "\n"); } if (object_type(o) == TYPE_OOP_ARRAY) { struct OopArray* array = (struct OopArray*)o; indent(depth); fprintf(stderr, "size(array) = %" PRIdPTR "\n", object_array_size(o)); for (i=0; i < object_array_size(o); i++) { indent(depth); fprintf(stderr, "array[%" PRIdPTR "]: ", i); print_object_with_depth(oh, array->elements[i], depth+1, max_depth); if (object_array_size(o) - i > 10) { indent(depth); fprintf(stderr, "...\n"); i = object_array_size(o) - 2; } } } indent(depth); fprintf(stderr, "map flags: %" PRIdPTR " (%s)\n", object_to_smallint(map->flags), ((((word_t)map->flags & MAP_FLAG_RESTRICT_DELEGATION)==0)? "delegation not restricted":"delegation restricted")); { /*print if delegate*/ struct OopArray* delegates = map->delegates; word_t offset = object_array_offset((struct Object*)delegates); word_t limit = object_total_size((struct Object*)delegates); for (i = 0; offset != limit; offset += sizeof(word_t), i++) { struct Object* delegate = object_slot_value_at_offset((struct Object*)delegates, offset); indent(depth); fprintf(stderr, "delegate[%" PRIdPTR "] = ", i); print_object_with_depth(oh, delegate, (((word_t)map->flags & MAP_FLAG_RESTRICT_DELEGATION) == 0)? depth+1 : max(max_depth-1, depth+1), max_depth); } } {/*if?*/ struct SlotTable* slotTable = map->slotTable; word_t limit = slot_table_capacity(map->slotTable); indent(depth); fprintf(stderr, "slot count: %" PRIdPTR "\n", object_to_smallint(map->slotCount)); for (i=0; i < limit; i++) { if (slotTable->slots[i].name == (struct Symbol*)oh->cached.nil) continue; indent(depth); fprintf(stderr, "slot[%" PRIdPTR "]['", i); print_symbol(slotTable->slots[i].name); fprintf(stderr, "'] = "); { struct Object* obj = object_slot_value_at_offset(o, object_to_smallint(slotTable->slots[i].offset)); if (object_is_smallint(obj) || object_type(obj) != TYPE_BYTE_ARRAY) { print_object(obj); } else { print_byte_array(obj); fprintf(stderr, "\n"); } } } } /*indent(depth); fprintf(stderr, "map = "); print_object_with_depth(oh, (struct Object*)map, depth+1, max_depth);*/ /*roles */ { struct RoleTable* roleTable = map->roleTable; word_t limit = role_table_capacity(roleTable); indent(depth); fprintf(stderr, "role table capacity: %" PRIdPTR "\n", limit); for (i = 0; i < limit; i++) { if (roleTable->roles[i].name == (struct Symbol*)oh->cached.nil) {continue;} else { indent(depth); fprintf(stderr, "role[%" PRIdPTR "]['", i); print_symbol(roleTable->roles[i].name); fprintf(stderr, "'] @ 0x%04" PRIxPTR "\n", object_to_smallint(roleTable->roles[i].rolePositions)); #if 0 print_object_with_depth(oh, (struct Object*)roleTable->roles[i].methodDefinition, max_depth, max_depth); #endif if (limit - i > 50 && depth >= 2) { indent(depth); fprintf(stderr, "...\n"); i = limit - 3; } } } } indent(depth); fprintf(stderr, "}\n"); }
void print_backtrace(struct object_heap* oh) { word_t depth = 0, detail_depth = -1 /*raise this to print verbose args in stack longer*/; struct Interpreter* i = oh->cached.interpreter; struct Closure* closure = (struct Closure*)i->method; word_t codePointer = i->codePointer; word_t fp = i->framePointer; word_t sp = i->stackPointer; word_t codeSize = i->codeSize; word_t resultStackPointer = object_to_smallint(i->stack->elements[fp - FRAME_OFFSET_RESULT_STACK_POINTER]); struct LexicalContext* lc = (struct LexicalContext*)i->stack->elements[fp - FRAME_OFFSET_LEXICAL_CONTEXT];; fprintf(stderr, "printing backtrace from fp=%" PRIdPTR ", sp=%" PRIdPTR "\n", fp, i->stackPointer); do { word_t j; struct Object** vars; word_t input_count = object_to_smallint(closure->method->inputVariables); word_t local_count = object_to_smallint(closure->method->localVariables); vars = (closure->method->heapAllocate == oh->cached.true_object)? (&lc->variables[0]) : (&i->stack->elements[fp]); fprintf(stderr, "------------------------------\n"); fprintf(stderr, "FP: %" PRIdPTR "\n", fp); fprintf(stderr, "SP: %" PRIdPTR "\n", sp); fprintf(stderr, "IP: %" PRIdPTR "/%" PRIdPTR "\n", codePointer, codeSize); fprintf(stderr, "result: %" PRIdPTR "\n", resultStackPointer); fprintf(stderr, "code: %p\n", closure->method->code); fprintf(stderr, "selector #"); print_byte_array((struct Object*)(closure->method->selector)); fprintf(stderr, "\n"); fprintf(stderr, "regs: %" PRIdPTR "\n", object_to_smallint(closure->method->registerCount)); fprintf(stderr, "heap alloc: %s\n", (closure->method->heapAllocate == oh->cached.true_object)? "true" : "false"); for (j = 0; j < input_count; j++) { fprintf(stderr, "arg[%" PRIdPTR "] (%p) = ", j, (void*)vars[j]); if (depth > detail_depth) { print_type(oh, vars[j]); } else { print_detail(oh, vars[j]); } } if (closure->method->heapAllocate == oh->cached.true_object) { for (j = 0; j < local_count; j++) { fprintf(stderr, "var[%" PRIdPTR "] (%p)= ", j, (void*)lc->variables[j]); if (depth > detail_depth) { print_type(oh, lc->variables[j]); } else { print_detail(oh, lc->variables[j]); } } } else { for (j = input_count; j < input_count + local_count; j++) { fprintf(stderr, "var[%" PRIdPTR "] (%p) = ", j - input_count, (void*)vars[j]); if (depth > detail_depth) { print_type(oh, vars[j]); } else { print_detail(oh, vars[j]); } } } /*order matters here*/ codePointer = object_to_smallint(i->stack->elements[fp - FRAME_OFFSET_CODE_POINTER]); fp = object_to_smallint(i->stack->elements[fp - FRAME_OFFSET_PREVIOUS_FRAME_POINTER]); if (fp < FUNCTION_FRAME_SIZE) break; sp = object_to_smallint(i->stack->elements[fp - FRAME_OFFSET_BEFORE_CALL_STACK_POINTER]); resultStackPointer = object_to_smallint(i->stack->elements[fp - FRAME_OFFSET_RESULT_STACK_POINTER]); closure = (struct Closure*)i->stack->elements[fp - FRAME_OFFSET_METHOD]; lc = (struct LexicalContext*)i->stack->elements[fp - FRAME_OFFSET_LEXICAL_CONTEXT]; codeSize = array_size(closure->method->code); depth++; } while (fp >= FUNCTION_FRAME_SIZE); }
/* * This is the main dispatch function * */ struct MethodDefinition* method_dispatch_on(struct object_heap* oh, struct Symbol* name, struct Object* arguments[], word_t arity, struct Object* resendMethod) { struct MethodDefinition *dispatch, *bestDef; struct Object* slotLocation; word_t bestRank, depth, delegationCount, resendRank, restricted, i; #ifdef PRINT_DEBUG_DISPATCH fprintf(stderr, "dispatch to: '"); print_symbol(name); fprintf(stderr, "' (arity: %" PRIdPTR ")\n", arity); for (i = 0; i < arity; i++) { fprintf(stderr, "arguments[%" PRIdPTR "] (%p) = ", i, (void*)arguments[i]); print_type(oh, arguments[i]); } /* fprintf(stderr, "resend: "); print_object(resendMethod);*/ #endif dispatch = NULL; slotLocation = NULL; #ifndef SLATE_DISABLE_METHOD_CACHE if (resendMethod == NULL && arity <= METHOD_CACHE_ARITY) { dispatch = method_check_cache(oh, name, arguments, arity); if (dispatch != NULL) return dispatch; } #endif oh->current_dispatch_id++; bestRank = 0; bestDef = NULL; resendRank = ((resendMethod == NULL) ? WORDT_MAX : 0); for (i = 0; i < arity; i++) { struct Object *obj; struct Map* map; struct Object* arg = arguments[i]; delegationCount = 0; depth = 0; restricted = WORDT_MAX; /*pointer in delegate_stack (with sp of delegateCount) to where we don't trace further*/ do { /* Set up obj to be a pointer to the object, or SmallInteger if it's a direct SmallInt. */ if (object_is_smallint(arg)) { obj = get_special(oh, SPECIAL_OOP_SMALL_INT_PROTO); } else { obj = arg; } /* Identify the map, and update its dispatchID and reset the visited mask if it hasn't been visited during this call already. */ map = obj->map; if (map->dispatchID != oh->current_dispatch_id) { map->dispatchID = oh->current_dispatch_id; map->visitedPositions = 0; } /* we haven't been here before */ if ((map->visitedPositions & (1 << i)) == 0) { struct RoleEntry* role; /* If the map marks an obj-meta transition and the top of the stack is not the original argument, then mark the restriction point at the top of the delegation stack. */ if (((word_t)map->flags & MAP_FLAG_RESTRICT_DELEGATION) && (arg != arguments[i])) { restricted = delegationCount; } map->visitedPositions |= (1 << i); role = role_table_entry_for_name(oh, map->roleTable, name); while (role != NULL) { if ((object_to_smallint(role->rolePositions) & (1 << i)) != 0) { struct MethodDefinition* def = role->methodDefinition; /* If the method hasn't been visited this time, mark it so and clear the other dispatch marks.*/ if (def->dispatchID != oh->current_dispatch_id) { def->dispatchID = oh->current_dispatch_id; def->foundPositions = 0; def->dispatchRank = 0; } /*If the method hasn't been found at this position...*/ if ((def->foundPositions & (1 << i)) == 0) { /*fix*/ def->dispatchRank |= ((31 - depth) << ((5 - i) * 5)); def->foundPositions |= (1 << i); #ifdef PRINT_DEBUG_FOUND_ROLE fprintf(stderr, "found role index %" PRIdPTR " <%p> for '%s' foundPos: %" PRIuPTR "x dispatchPos: %" PRIuPTR "x\n", i, (void*) role, ((struct Symbol*)(role->name))->elements, def->foundPositions, def->dispatchPositions); #endif if (def->method == resendMethod) { struct RoleEntry* rescan = role_table_entry_for_name(oh, map->roleTable, name); resendRank = def->dispatchRank; while (rescan != role) { struct MethodDefinition* redef = rescan->methodDefinition; if (redef->foundPositions == redef->dispatchPositions && (dispatch == NULL || redef->dispatchRank <= resendRank)) { dispatch = redef; slotLocation = obj; if (redef->dispatchRank > bestRank) { bestRank = redef->dispatchRank; bestDef = redef; } } if (rescan->nextRole == oh->cached.nil) { rescan = NULL; } else { rescan = &map->roleTable->roles[object_to_smallint(rescan->nextRole)]; } } } else /*not a resend*/ { if (def->foundPositions == def->dispatchPositions && (dispatch == NULL || def->dispatchRank > dispatch->dispatchRank) && def->dispatchRank <= resendRank) { dispatch = def; slotLocation = obj; if (def->dispatchRank > bestRank) { bestRank = def->dispatchRank; bestDef = def; } } } if (def->dispatchRank >= bestRank && def != bestDef) { bestRank = def->dispatchRank; bestDef = NULL; } } } role = ((role->nextRole == oh->cached.nil) ? NULL : &map->roleTable->roles[object_to_smallint(role->nextRole)]); } /*while role != NULL*/ if (depth > 31) { /*fix wordsize*/ assert(0); } if (dispatch != NULL && bestDef == dispatch) { if (dispatch->slotAccessor != oh->cached.nil) { arguments[0] = slotLocation; /*do we need to try to do a heap_store_into?*/ #ifdef PRINT_DEBUG_DISPATCH_SLOT_CHANGES fprintf(stderr, "arguments[0] changed to slot location: \n"); print_detail(oh, arguments[0]); #endif } if (resendMethod == 0 && arity <= METHOD_CACHE_ARITY) method_save_cache(oh, dispatch, name, arguments, arity); return dispatch; } depth++; /* We add the delegates to the list when we didn't just finish checking a restricted object*/ if (delegationCount <= restricted && array_size(map->delegates) > 0) { struct OopArray* delegates = map->delegates; word_t offset = object_array_offset((struct Object*)delegates); word_t limit = object_total_size((struct Object*)delegates); for (; offset != limit; offset += sizeof(word_t)) { struct Object* delegate = object_slot_value_at_offset((struct Object*)delegates, offset); if (delegate != oh->cached.nil) { oh->delegation_stack[delegationCount++] = delegate; } } } } /*end haven't been here before*/ delegationCount--; if (delegationCount < restricted) restricted = WORDT_MAX; /*everything is unrestricted now*/ if (delegationCount < 0 || delegationCount >= DELEGATION_STACK_SIZE) break; arg = oh->delegation_stack[delegationCount]; } while (1); } if (dispatch != NULL && dispatch->slotAccessor != oh->cached.nil) { /*check heap store into?*/ arguments[0] = slotLocation; #ifdef PRINT_DEBUG_DISPATCH_SLOT_CHANGES fprintf(stderr, "arguments[0] changed to slot location: \n"); print_detail(oh, arguments[0]); #endif } #ifndef SLATE_DISABLE_METHOD_CACHE if (dispatch != NULL && resendMethod == 0 && arity < METHOD_CACHE_ARITY) { method_save_cache(oh, dispatch, name, arguments, arity); } #endif return dispatch; }