Skip to content
Merged
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
32 changes: 32 additions & 0 deletions tslang/include/TypeScript/MLIRLogic/MLIRGenStore.h
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,38 @@ struct InterfaceInfo
return offset + methods.size() + fields.size();
}

// vtable slot numbers must be a pure function of the interface's own declaration
// (extends, then own methods in order, then own fields in order) - NOT of whichever
// object happens to be cast to it first. getVirtualTable() re-derives the same
// methods-then-fields order per-cast (needed to mark per-object optional members
// missing), but a module that only reads an already-typed interface value - without
// ever casting an object to it itself (e.g. importing an already-boxed global from
// another compilation unit) - never runs getVirtualTable() at all. Without this
// eagerly-computed, cast-independent pass, such a module falls back on the
// interleaved declaration-order index assigned at member-registration time
// (mlirGenInterfaceAddFieldMember / addInterfaceMethod), which disagrees with the
// methods-first layout whenever a field is declared before a method in source order -
// reading through the wrong vtable slot (e.g. a method's function pointer
// reinterpreted as a field offset) and crashing.
void assignCanonicalVirtualIndexes()
{
auto offset = 0;
for (auto &extent : extends)
{
offset += std::get<1>(extent)->getVTableSize();
}

for (auto &method : methods)
{
method.virtualIndex = offset++;
}

for (auto &field : fields)
{
field.virtualIndex = offset++;
}
}

void recalcOffsets()
{
auto offset = 0;
Expand Down
5 changes: 5 additions & 0 deletions tslang/lib/TypeScript/MLIRGenInterfaces.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,11 @@ namespace mlirgen

} while (notResolved > 0);

// fix up vtable slot numbers to the canonical methods-then-fields order now that
// all members are known - see assignCanonicalVirtualIndexes() for why this can't
// be left to getVirtualTable()'s per-cast assignment alone.
newInterfacePtr->assignCanonicalVirtualIndexes();

// add to export if any
if (auto hasExport = getExportModifier(interfaceDeclarationAST))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,11 @@ namespace A {

// invalid Point3d is not exported
export var Origin3d: Point3d = { x: 0, y: 0, z: 0 };

export interface Counter {
count: number;
inc(): void;
}

export var counter: Counter = { count: 0, inc() { this.count = this.count + 1; } };
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,6 @@ if (A.Origin3d.x == 0)
print("ok");
}

print(A.counter.count);

print("done.");
Loading