reg_t reg_t::operator+(const reg_t right) const { if (isPointer() && right.isNumber()) { // Pointer arithmetics. Only some pointer types make sense here SegmentObj *mobj = g_sci->getEngineState()->_segMan->getSegmentObj(getSegment()); if (!mobj) error("[VM]: Attempt to add %d to invalid pointer %04x:%04x", right.getOffset(), PRINT_REG(*this)); switch (mobj->getType()) { case SEG_TYPE_LOCALS: case SEG_TYPE_SCRIPT: case SEG_TYPE_STACK: case SEG_TYPE_DYNMEM: return make_reg(getSegment(), getOffset() + right.toSint16()); default: return lookForWorkaround(right, "addition"); } } else if (isNumber() && right.isPointer()) { // Adding a pointer to a number, flip the order return right + *this; } else if (isNumber() && right.isNumber()) { // Normal arithmetics return make_reg(0, toSint16() + right.toSint16()); } else { return lookForWorkaround(right, "addition"); } }
void run_gc(EngineState *s) { SegManager *segMan = s->_segMan; // Some debug stuff debugC(kDebugLevelGC, "[GC] Running..."); #ifdef GC_DEBUG_CODE const char *segnames[SEG_TYPE_MAX + 1]; int segcount[SEG_TYPE_MAX + 1]; memset(segnames, 0, sizeof(segnames)); memset(segcount, 0, sizeof(segcount)); #endif // Compute the set of all segments references currently in use. AddrSet *activeRefs = findAllActiveReferences(s); // Iterate over all segments, and check for each whether it // contains stuff that can be collected. const Common::Array<SegmentObj *> &heap = segMan->getSegments(); for (uint seg = 1; seg < heap.size(); seg++) { SegmentObj *mobj = heap[seg]; if (mobj != NULL) { #ifdef GC_DEBUG_CODE const SegmentType type = mobj->getType(); segnames[type] = segmentTypeNames[type]; #endif // Get a list of all deallocatable objects in this segment, // then free any which are not referenced from somewhere. const Common::Array<reg_t> tmp = mobj->listAllDeallocatable(seg); for (Common::Array<reg_t>::const_iterator it = tmp.begin(); it != tmp.end(); ++it) { const reg_t addr = *it; if (!activeRefs->contains(addr)) { // Not found -> we can free it mobj->freeAtAddress(segMan, addr); debugC(kDebugLevelGC, "[GC] Deallocating %04x:%04x", PRINT_REG(addr)); #ifdef GC_DEBUG_CODE segcount[type]++; #endif } } } } delete activeRefs; #ifdef GC_DEBUG_CODE // Output debug summary of garbage collection debugC(kDebugLevelGC, "[GC] Summary:"); for (int i = 0; i <= SEG_TYPE_MAX; i++) if (segcount[i]) debugC(kDebugLevelGC, "\t%d\t* %s", segcount[i], segnames[i]); #endif }
uint16 Kernel::findRegType(reg_t reg) { // No segment? Must be integer if (!reg.getSegment()) return SIG_TYPE_INTEGER | (reg.getOffset() ? 0 : SIG_TYPE_NULL); if (reg.getSegment() == 0xFFFF) return SIG_TYPE_UNINITIALIZED; // Otherwise it's an object SegmentObj *mobj = _segMan->getSegmentObj(reg.getSegment()); if (!mobj) return SIG_TYPE_ERROR; uint16 result = 0; if (!mobj->isValidOffset(reg.getOffset())) result |= SIG_IS_INVALID; switch (mobj->getType()) { case SEG_TYPE_SCRIPT: if (reg.getOffset() <= (*(Script *)mobj).getBufSize() && reg.getOffset() >= (uint)-SCRIPT_OBJECT_MAGIC_OFFSET && (*(Script *)mobj).offsetIsObject(reg.getOffset())) { result |= ((Script *)mobj)->getObject(reg.getOffset()) ? SIG_TYPE_OBJECT : SIG_TYPE_REFERENCE; } else result |= SIG_TYPE_REFERENCE; break; case SEG_TYPE_CLONES: result |= SIG_TYPE_OBJECT; break; case SEG_TYPE_LOCALS: case SEG_TYPE_STACK: case SEG_TYPE_DYNMEM: case SEG_TYPE_HUNK: #ifdef ENABLE_SCI32 case SEG_TYPE_ARRAY: case SEG_TYPE_STRING: #endif result |= SIG_TYPE_REFERENCE; break; case SEG_TYPE_LISTS: result |= SIG_TYPE_LIST; break; case SEG_TYPE_NODES: result |= SIG_TYPE_NODE; break; default: return SIG_TYPE_ERROR; } return result; }
static AddrSet *normalizeAddresses(SegManager *segMan, const AddrSet &nonnormal_map) { AddrSet *normal_map = new AddrSet(); for (AddrSet::const_iterator i = nonnormal_map.begin(); i != nonnormal_map.end(); ++i) { reg_t reg = i->_key; SegmentObj *mobj = segMan->getSegmentObj(reg.getSegment()); if (mobj) { reg = mobj->findCanonicAddress(segMan, reg); normal_map->setVal(reg, true); } } return normal_map; }
reg_t kArray(EngineState *s, int argc, reg_t *argv) { uint16 op = argv[0].toUint16(); // Use kString when accessing strings // This is possible, as strings inherit from arrays // and in this case (type 3) arrays are of type char *. // kString is almost exactly the same as kArray, so // this call is possible // TODO: we need to either merge SCI2 strings and // arrays together, and in the future merge them with // the SCI1 strings and arrays in the segment manager if (op == 0) { // New, check if the target type is 3 (string) if (argv[2].toUint16() == 3) return kString(s, argc, argv); } else { if (s->_segMan->getSegmentType(argv[1].getSegment()) == SEG_TYPE_STRING || s->_segMan->getSegmentType(argv[1].getSegment()) == SEG_TYPE_SCRIPT) { return kString(s, argc, argv); } #if 0 if (op == 6) { if (s->_segMan->getSegmentType(argv[3].getSegment()) == SEG_TYPE_STRING || s->_segMan->getSegmentType(argv[3].getSegment()) == SEG_TYPE_SCRIPT) { return kString(s, argc, argv); } } #endif } switch (op) { case 0: { // New reg_t arrayHandle; SciArray<reg_t> *array = s->_segMan->allocateArray(&arrayHandle); array->setType(argv[2].toUint16()); array->setSize(argv[1].toUint16()); return arrayHandle; } case 1: { // Size SciArray<reg_t> *array = s->_segMan->lookupArray(argv[1]); return make_reg(0, array->getSize()); } case 2: { // At (return value at an index) SciArray<reg_t> *array = s->_segMan->lookupArray(argv[1]); if (g_sci->getGameId() == GID_PHANTASMAGORIA2) { // HACK: Phantasmagoria 2 keeps trying to access past the end of an // array when it starts. I'm assuming it's trying to see where the // array ends, or tries to resize it. Adjust the array size // accordingly, and return NULL for now. if (array->getSize() == argv[2].toUint16()) { array->setSize(argv[2].toUint16()); return NULL_REG; } } return array->getValue(argv[2].toUint16()); } case 3: { // Atput (put value at an index) SciArray<reg_t> *array = s->_segMan->lookupArray(argv[1]); uint32 index = argv[2].toUint16(); uint32 count = argc - 3; if (index + count > 65535) break; if (array->getSize() < index + count) array->setSize(index + count); for (uint16 i = 0; i < count; i++) array->setValue(i + index, argv[i + 3]); return argv[1]; // We also have to return the handle } case 4: // Free // Freeing of arrays is handled by the garbage collector return s->r_acc; case 5: { // Fill SciArray<reg_t> *array = s->_segMan->lookupArray(argv[1]); uint16 index = argv[2].toUint16(); // A count of -1 means fill the rest of the array uint16 count = argv[3].toSint16() == -1 ? array->getSize() - index : argv[3].toUint16(); uint16 arraySize = array->getSize(); if (arraySize < index + count) array->setSize(index + count); for (uint16 i = 0; i < count; i++) array->setValue(i + index, argv[4]); return argv[1]; } case 6: { // Cpy if (argv[1].isNull() || argv[3].isNull()) { if (getSciVersion() == SCI_VERSION_3) { // FIXME: Happens in SCI3, probably because of a missing kernel function. warning("kArray(Cpy): Request to copy from or to a null pointer"); return NULL_REG; } else { // SCI2-2.1: error out error("kArray(Cpy): Request to copy from or to a null pointer"); } } reg_t arrayHandle = argv[1]; SciArray<reg_t> *array1 = s->_segMan->lookupArray(argv[1]); SciArray<reg_t> *array2 = s->_segMan->lookupArray(argv[3]); uint32 index1 = argv[2].toUint16(); uint32 index2 = argv[4].toUint16(); // The original engine ignores bad copies too if (index2 > array2->getSize()) break; // A count of -1 means fill the rest of the array uint32 count = argv[5].toSint16() == -1 ? array2->getSize() - index2 : argv[5].toUint16(); if (array1->getSize() < index1 + count) array1->setSize(index1 + count); for (uint16 i = 0; i < count; i++) array1->setValue(i + index1, array2->getValue(i + index2)); return arrayHandle; } case 7: // Cmp // Not implemented in SSCI warning("kArray(Cmp) called"); return s->r_acc; case 8: { // Dup if (argv[1].isNull()) { warning("kArray(Dup): Request to duplicate a null pointer"); #if 0 // Allocate an array anyway reg_t arrayHandle; SciArray<reg_t> *dupArray = s->_segMan->allocateArray(&arrayHandle); dupArray->setType(3); dupArray->setSize(0); return arrayHandle; #endif return NULL_REG; } SegmentObj *sobj = s->_segMan->getSegmentObj(argv[1].getSegment()); if (!sobj || sobj->getType() != SEG_TYPE_ARRAY) error("kArray(Dup): Request to duplicate a segment which isn't an array"); reg_t arrayHandle; SciArray<reg_t> *dupArray = s->_segMan->allocateArray(&arrayHandle); // This must occur after allocateArray, as inserting a new object // in the heap object list might invalidate this pointer. Also refer // to the same issue in kClone() SciArray<reg_t> *array = s->_segMan->lookupArray(argv[1]); dupArray->setType(array->getType()); dupArray->setSize(array->getSize()); for (uint32 i = 0; i < array->getSize(); i++) dupArray->setValue(i, array->getValue(i)); return arrayHandle; } case 9: // Getdata if (!s->_segMan->isHeapObject(argv[1])) return argv[1]; return readSelector(s->_segMan, argv[1], SELECTOR(data)); default: error("Unknown kArray subop %d", op); } return NULL_REG; }