Skip to content
Closed
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
42 changes: 0 additions & 42 deletions packages/compiler/src/backend/llvm/borrowed-receivers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,51 +2,9 @@ import { isStableReceiverOperand } from "../../ir/analysis.js";
import { isRefCounted, type IrExpr, type IrStmt } from "../../ir/ir.js";
import type { LlvmEmitterContext, LlValue } from "./expr-context.js";

/** The value of a sequence whose statements are only throwing guards over
* scalar conditions: `if (cond) throw` with no else, where the throw is the
* runtime's coded Node error (a derived constructor's `this` before super()
* lowers to exactly this). Such guards read no reference and replace no
* owner, so the sequence can be read wherever its result can: the guards
* still run in place, and only the result is borrowed. Null otherwise. */
export function guardedValue(e: IrExpr): IrExpr | null {
if (e.kind !== "seqExpr") return null;
for (const s of e.stmts) {
if (
s.kind !== "if" ||
s.else_ !== null ||
isRefCounted(s.cond.type) ||
!scalarGuardCondition(s.cond) ||
s.then.length !== 1
)
return null;
const only = s.then[0]!;
if (
only.kind !== "exprStmt" ||
only.expr.kind !== "libCall" ||
only.expr.fn !== "error.nodeThrow" ||
!only.expr.args.every((arg) => arg.kind === "numLit" || arg.kind === "strLit")
)
return null;
}
return e.result;
}

function scalarGuardCondition(e: IrExpr): boolean {
switch (e.kind) {
case "boolLit":
case "varRef":
return !isRefCounted(e.type);
case "unary":
return scalarGuardCondition(e.operand);
default:
return false;
}
}

function stableProjection(host: LlvmEmitterContext, e: IrExpr): boolean {
switch (e.kind) {
case "varRef":
case "seqExpr":
return host.canBorrowReceiver(e);
case "unionNarrow":
case "downcast":
Expand Down
14 changes: 6 additions & 8 deletions packages/compiler/src/backend/llvm/classes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ import type { Int32Slots } from "../../ir/int32-slots.js";
import {
cycleRootLines,
FN_ATTRS,
cycleDeadLines,
llFieldType,
releaseBody,
releaseFastPath,
Expand Down Expand Up @@ -231,7 +230,7 @@ export function emitClassMembershipHelper(
/** The root's slot list as seen by one class: the implementation the class
* dispatches to, or null outside the slot's declaring subtree / on a
* fully-abstract chain (vtEntriesFor, ported). */
export function vtEntriesFor(meta: LlClassMeta): { slot: LlVtSlot; impl: LlClassMeta | null }[] {
function vtEntriesFor(meta: LlClassMeta): { slot: LlVtSlot; impl: LlClassMeta | null }[] {
return meta.root.slots.map((slot): { slot: LlVtSlot; impl: LlClassMeta | null } => {
if (!(slot.declarer.pre <= meta.pre && meta.pre <= slot.declarer.post)) {
return { slot, impl: null };
Expand Down Expand Up @@ -300,10 +299,6 @@ export interface ClassHost extends ShapeHost {
readonly unionsById: Map<string, IrUnionDef>;
unitInstanceRef(unionId: string, tag: number): string;
cstr(text: string): string;
/** The symbol a vtable stores for a method implementation (its owned
* entry point unless the slot's calling convention borrows; see
* LlEmitter.virtualEntry). */
virtualEntry?(implFn: string): string;
}

/** The newFn initialization stores for fields whose type ADMITS undefined
Expand Down Expand Up @@ -418,7 +413,7 @@ export function emitClassShapes(
const entries = vtEntriesFor(meta).map(({ slot, impl }) =>
impl === null
? `ptr null` // outside the declaring subtree / fully-abstract chain
: `ptr @${host.virtualEntry?.(`%${impl.def.name}.${slot.method}`) ?? mangleFunction(`%${impl.def.name}.${slot.method}`)}`,
: `ptr @${mangleFunction(`%${impl.def.name}.${slot.method}`)}`,
);
const head = `%ScrVt { ${host.sizeType} ${meta.pre}, ${host.sizeType} ${meta.post}, ptr @${mangleClassReleaseDirect(cls.name)} }`;
defs.push(
Expand Down Expand Up @@ -550,7 +545,10 @@ export function emitClassShapes(
` br i1 %dead, label %free, label %${traced ? "root" : "done"}`,
`free:`,
];
if (traced) reld.push(...cycleDeadLines(host, "teardown"));
if (traced) {
host.declare(`declare void @scr_cyc_on_dead(ptr)`);
reld.push(` call void @scr_cyc_on_dead(ptr %o)`);
}
if (bounded) {
const destroy = `${mangleClassReleaseDirect(cls.name)}_destroy`;
const destroyBody: string[] = [
Expand Down
2 changes: 0 additions & 2 deletions packages/compiler/src/backend/llvm/dyn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,6 @@ export const DYN_KIND = {
* unit instances (undefined-armed dynCheck targets build them). */
export interface DynHost extends WalkerHost {
unitInstanceRef(unionId: string, tag: number): string;
/** See ClassHost.virtualEntry. */
virtualEntry?(implFn: string): string;
/** The immortal ABSENT field-slot state of an undefined-armed union. */
absentInstanceRef(unionId: string): string;
liveDynRefAdapter(t: IrType): { snapshot: string; commit: string };
Expand Down
Loading
Loading