Skip to content

Commit

Permalink
Wire up some more
Browse files Browse the repository at this point in the history
  • Loading branch information
oleavr committed Sep 23, 2024
1 parent 6c16230 commit 5b41b93
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 18 deletions.
8 changes: 6 additions & 2 deletions apps/tracer/src/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,12 @@ export function useModel() {
const [addingTargets, setAddingTargets] = useState(false);
const [stagedItems, setStagedItems] = useState<StagedItem[]>([]);

const onR2ReadRequest = useCallback((address: string, size: number) => {
sendJsonMessage({ type: "memory:read", address, size });
const onR2ReadRequest = useCallback((address: bigint, size: number) => {
sendJsonMessage({
type: "memory:read",
address: "0x" + address.toString(16),
size
});
}, [sendJsonMessage]);

const { deliverR2ReadResponse } = useR2({
Expand Down
84 changes: 68 additions & 16 deletions apps/tracer/src/use-r2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,13 @@ export interface R2Source {
onReadRequest: ReadRequestHandler;
}

export type ReadRequestHandler = (address: string, size: number) => void;
export type ReadRequestHandler = (address: bigint, size: number) => void;

let state: "unloaded" | "loading" | "loaded" | "executing-command" = "unloaded";
let r2Module: MainModule | null = null;
const pendingCommands: CommandRequest[] = [];
const pendingReads: ((result: Uint8Array | null) => void)[] = [];
const cachedPages = new Map<bigint, Uint8Array | null>([[0n, null]]);

interface CommandRequest {
command: string;
Expand Down Expand Up @@ -65,26 +66,77 @@ export function useR2({ source }: R2Props = {}) {
async function loadR2(sourceRef: React.MutableRefObject<R2Source>) {
const r2 = await loadR2Module({
offset: "0",
onRead(offset: string, size: number): Promise<Uint8Array> {
return new Promise((resolve, reject) => {
const offsetAsNumber = parseInt(offset);
// TODO: Fix the SEEK_END offset check here:
if (offsetAsNumber < sourceRef.current.pageSize || offsetAsNumber === 0xffffffff) {
reject(new Error("read failed"));
return;
async onRead(offset: string, size: number): Promise<Uint8Array> {
const address = BigInt(offset);

const pageSize = BigInt(sourceRef.current.pageSize);
const firstPage = pageStart(address);
const lastPage = pageStart(address + BigInt(size) - 1n);
const pageAfterLastPage = lastPage + pageSize;
const numPages = (pageAfterLastPage - firstPage) / pageSize;

let allInCache = true;
for (let page = firstPage; page !== pageAfterLastPage; page += pageSize) {
const entry = cachedPages.get(page);
if (entry === null) {
throw new Error("read failed");
}
if (entry === undefined) {
allInCache = false;
break;
}
pendingReads.push(result => {
if (result !== null) {
resolve(result);
} else {
reject(new Error("read failed"));
}

if (!allInCache) {
try {
const block = await read(firstPage, Number(numPages * pageSize));
for (let page = firstPage; page !== pageAfterLastPage; page += pageSize) {
const offset = page - firstPage;
cachedPages.set(page, block.slice(Number(offset), Number(offset + pageSize)));
}
});
sourceRef.current.onReadRequest(offset.toString(), size);
});
} catch (e) {
for (let page = firstPage; page !== pageAfterLastPage; page += pageSize) {
cachedPages.set(page, null);
}
throw e;
}
}

const result = new Uint8Array(size);
let resultOffset = 0;
for (let page = firstPage; page !== pageAfterLastPage; page += pageSize) {
const remaining = size - resultOffset;
const chunkSize = (remaining > pageSize) ? Number(pageSize) : remaining;
const fromOffset = Number((page === firstPage) ? address % pageSize : 0n);
const toOffset = fromOffset + chunkSize;

const pageData = cachedPages.get(page)!;
result.set(pageData.slice(fromOffset, toOffset), resultOffset);

resultOffset += chunkSize;
}
return result;

function pageStart(address: bigint): bigint {
const pageOffset = address % pageSize;
return address - pageOffset;
}
},
});

function read(address: bigint, size: number): Promise<Uint8Array> {
return new Promise((resolve, reject) => {
pendingReads.push(result => {
if (result !== null) {
resolve(result);
} else {
reject(new Error("read failed"));
}
});
sourceRef.current.onReadRequest(address, size);
});
}

const { platform, arch, pointerSize } = sourceRef.current;

await r2.ccall("r2_open", "void", ["string", "string", "int"],
Expand Down

0 comments on commit 5b41b93

Please sign in to comment.