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; }
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]); } }
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"); }
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; }
struct MethodDefinition* method_is_on_arity(struct object_heap* oh, struct Object* method, struct Symbol* selector, struct Object* args[], word_t n) { word_t positions, i; struct MethodDefinition* def; positions = 0; def = NULL; for (i = 0; i < n; i++) { if (!object_is_smallint(args[i])) { struct MethodDefinition* roleDef = object_has_role_named_at(args[i], selector, 1<<i, method); if (roleDef != NULL) { positions |= 1<<i; def = roleDef; } } } return ((def != NULL && positions == def->dispatchPositions)? def : NULL); }
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"); }
/* * 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; }