Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make memory and string behave like the hack versions would. #557

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 40 additions & 21 deletions simulator/src/vm/os/memory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,48 +3,67 @@ import { ERRNO } from "./errors.js";
import { OS } from "./os.js";

const HEAP_BASE = 2048;
const HEAP_SIZE = 14336;

interface Segment {
address: number;
length: number;
}
const HEAP_SIZE = 14334;

export class MemoryLib {
private memory: VmMemory;
private os: OS;

private freeSegments: Segment[] = [{ address: HEAP_BASE, length: HEAP_SIZE }];
private freeListPtr: number;

public constructor(memory: VmMemory, os: OS) {
this.memory = memory;
this.os = os;
this.freeListPtr = HEAP_BASE;
this.memory.set(HEAP_BASE, 0);
this.memory.set(HEAP_BASE + 1, HEAP_SIZE);
}

alloc(size: number): number {
if (size <= 0) {
this.os.sys.error(ERRNO.ARRAY_SIZE_NOT_POSITIVE);
return 0;
}
for (let i = 0; i < this.freeSegments.length; i++) {
const seg = this.freeSegments[i];
if (seg.length >= size) {
const address = seg.address;
seg.address += size + 1;
seg.length -= size + 1;
if (seg.length === 0) {
this.freeSegments.splice(i, 1);

let blockPtr = this.freeListPtr;
do {
const nextFreeList = this.memory.get(blockPtr);
const blockSize = this.memory.get(blockPtr + 1);
if (blockSize >= size + 2) {
// We can fit this required size and overhead in this block.
this.memory.set(blockPtr + 1, size);

const newBlockPtr = blockPtr + 2 + size;
const newBlockSize = blockSize - size - 2;
this.memory.set(newBlockPtr, nextFreeList);
this.memory.set(newBlockPtr + 1, newBlockSize);
if (this.freeListPtr === blockPtr) {
// Move freelist pointer to the new block.
this.freeListPtr = newBlockPtr;
}
this.memory.set(address, size); // save the segment size for deallocation
return address + 1;
return blockPtr + 2;
} else {
// We can't fit this required size and overhead in this block.
blockPtr = nextFreeList;
}
}
} while (blockPtr !== 0);

this.os.sys.error(ERRNO.HEAP_OVERFLOW);
return 0;
}

deAlloc(address: number) {
const size = this.memory.get(address - 1);
this.freeSegments.push({ address: address - 1, length: size + 1 });
const deallocBlockPtr = address - 2;
// This will be the last block in the free list.
this.memory.set(deallocBlockPtr, 0);

let blockPtr = this.freeListPtr;
do {
const nextBlockPtr = this.memory.get(blockPtr);
if (nextBlockPtr === 0) {
this.memory.set(blockPtr, deallocBlockPtr);
return;
}
blockPtr = nextBlockPtr;
} while (blockPtr !== 0);
}
}
11 changes: 8 additions & 3 deletions simulator/src/vm/os/string.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,15 @@ export class StringLib {
if (size < 0) {
this.os.sys.error(ERRNO.STRING_LENGTH_NEG);
}
const pointer = this.os.memory.alloc(size + 2); // +2 to save length, maxLength fields
const pointer = this.os.memory.alloc(size + 3); // +3 to save length, maxLength, charArray Ptr
if (this.os.sys.halted) {
// alloc returned with an error
return 0;
}

this.memory.set(pointer, size); // set maxLength = size
this.memory.set(pointer + 1, 0); // set length = 0
this.memory.set(pointer + 2, this.os.memory.alloc(size)); // set charArrayPtr.
return pointer;
}

Expand All @@ -61,20 +62,24 @@ export class StringLib {
this.memory.set(pointer + 1, length);
}

private charArrayPointer(pointer: number) {
return this.memory.get(pointer + 2);
}

charAt(pointer: number, index: number) {
if (index < 0 || index >= this.length(pointer)) {
this.os.sys.error(ERRNO.GET_CHAR_INDEX_OUT_OF_BOUNDS);
return 0;
}
return this.memory.get(pointer + index + 2); // +2 to skip the length fields
return this.memory.get(this.charArrayPointer(pointer) + index);
}

setCharAt(pointer: number, index: number, value: number) {
if (index < 0 || index >= this.length(pointer)) {
this.os.sys.error(ERRNO.SET_CHAR_INDEX_OUT_OF_BOUNDS);
return;
}
this.memory.set(pointer + index + 2, value);
this.memory.set(this.charArrayPointer(pointer) + index, value);
}

// This returns the string pointer to allow compilation of string literals as described in the book,
Expand Down