Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
394c8b8
-mm=own: spec section 23, Shared<T> (design)
ASDAlexander77 Oct 3, 2026
6cf1ed1
-mm=own: the Shared<T> implementation plan (spec section 23)
ASDAlexander77 Oct 3, 2026
22d3f3c
-mm=own Shared<T>: the type, its ops and MLIRGen (spec 23.1)
ASDAlexander77 Oct 3, 2026
4132348
-mm=own Shared<T>: a handle is counted, under rc first (spec 23.2)
ASDAlexander77 Oct 3, 2026
4a81676
-mm=own Shared<T>: own leaves handles to the count; reads through a h…
ASDAlexander77 Oct 3, 2026
7681df0
-mm=own Shared<T>: a constructor filling a handle field is not a drop…
ASDAlexander77 Oct 3, 2026
eda4257
-mm=own Shared<T>: any write through any handle ends a borrow; handle…
ASDAlexander77 Oct 3, 2026
8b5b893
-mm=own Shared<T>: handles in containers, any and closures; cycles (s…
ASDAlexander77 Oct 3, 2026
85f99e2
-mm=own Shared<T>: a union of a handle and members that own nothing i…
ASDAlexander77 Oct 3, 2026
bbac9ba
-mm=own Shared<T>: measure, corpus and results (spec 23.7)
ASDAlexander77 Oct 3, 2026
28f3fe3
-mm=own Shared<T>: the Linux run (spec 23.7)
ASDAlexander77 Oct 3, 2026
105d121
-mm=own Shared<T>: annotate the plan's results step; name the teeth (…
ASDAlexander77 Oct 3, 2026
2402454
-mm=own Shared<T>: the final review's fixes - global handles, const h…
ASDAlexander77 Oct 3, 2026
fad98c5
-mm=own Shared<T>: handles copied inside a generator, in own_shared_c…
ASDAlexander77 Oct 3, 2026
476c4d8
-mm=own Shared<T>: the final review and its fix round in the results …
ASDAlexander77 Oct 3, 2026
81c348e
-mm=own Shared<T>: the second fix round - handle globals from any ini…
ASDAlexander77 Oct 3, 2026
866520d
-mm=own Shared<T>: the third fix round - a store counts only when rc …
ASDAlexander77 Oct 3, 2026
3a86e20
-mm=own Shared<T>: a handle global from an element read takes its own…
ASDAlexander77 Oct 3, 2026
ceedafa
-mm=own Shared<T>: the third fix round in the results (spec 23.7)
ASDAlexander77 Oct 3, 2026
4486dee
-mm=own Shared<T>: the fourth fix round - a handle read's uses are de…
ASDAlexander77 Oct 3, 2026
d636eb8
-mm=own Shared<T>: a using disposal before return p.child is a conser…
ASDAlexander77 Oct 3, 2026
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
1,266 changes: 1,266 additions & 0 deletions tslang/docs/superpowers/plans/2026-10-03-own-shared.md

Large diffs are not rendered by default.

685 changes: 683 additions & 2 deletions tslang/docs/superpowers/specs/2026-09-24-own-memory-model-design.md

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions tslang/include/TypeScript/LowerToLLVM/CastLogicHelper.h
Original file line number Diff line number Diff line change
Expand Up @@ -1175,6 +1175,12 @@ class CastLogicHelper
LLVM_DEBUG(llvm::dbgs() << "\n!! union storage type: " << storageType << "\n";);
valueForBoxing = rewriter.create<mlir_ts::GetValueFromUnionOp>(loc, storageType, in);
}
else if (MLIRTypeHelper::isSharedHandleType(unionType))
{
// `Shared<T> | null` (own spec 23.1) is one pointer, boxed under the handle's own
// descriptor: the union has no `typeof` name, so it had no tag at all
typeOfValue = toh.typeOfLogic(loc, baseType);
}
else
{
typeOfValue = toh.typeOfLogic(loc, inType);
Expand Down
26 changes: 20 additions & 6 deletions tslang/include/TypeScript/LowerToLLVM/OwnershipRoutineLogic.h
Original file line number Diff line number Diff line change
Expand Up @@ -627,8 +627,9 @@ class OwnershipRoutineLogic
// Runs `thenBody` -- the destroy half: release what the value owns, then free it -- only
// when `payloadPtr` is non-null and the reference being dropped was the last one. Under
// own there is no count: the one owner is giving the block up, so it goes unless it is
// immortal (a literal, a `typeof` tag).
void emitIfLastReference(mlir::Value payloadPtr, llvm::function_ref<void()> thenBody)
// immortal (a literal, a `typeof` tag). A `counted` block - a Shared<T> handle's (own spec
// 23.2) - is counted under own too.
void emitIfLastReference(mlir::Value payloadPtr, llvm::function_ref<void()> thenBody, bool counted = false)
{
TypeHelper th(rewriter);
auto loc = op->getLoc();
Expand All @@ -643,7 +644,8 @@ class OwnershipRoutineLogic
rewriter.create<LLVM::BrOp>(loc, ValueRange{}, continuationBlock);

rewriter.setInsertionPointToEnd(decBlock);
auto wasLast = compileOptions.memoryModel == MemoryModelOwn ? emitIsMortal(payloadPtr) : emitDecRef(payloadPtr);
auto wasLast = compileOptions.memoryModel == MemoryModelOwn && !counted ? emitIsMortal(payloadPtr)
: emitDecRef(payloadPtr);
rewriter.create<LLVM::CondBrOp>(loc, wasLast, thenBlock, continuationBlock);

rewriter.setInsertionPointToEnd(currentBlock);
Expand Down Expand Up @@ -976,6 +978,18 @@ class OwnershipRoutineLogic
return;
}

// a handle (own spec 23.2) is counted in every model that tracks ownership: the last one
// releases the payload and frees the block
if (auto sharedType = dyn_cast<mlir_ts::SharedType>(type))
{
auto handle = rewriter.create<LLVM::LoadOp>(loc, ptrTy, slotPtr);
emitIfLastReference(handle, [&]() {
releaseSlot(sharedType.getElementType(), handle);
emitFreeBlock(handle);
}, /*counted=*/true);
return;
}

// an "any" box owns its own block, and its payload's type is only known through the
// tag
if (isa<mlir_ts::AnyType>(type))
Expand Down Expand Up @@ -1135,9 +1149,9 @@ class OwnershipRoutineLogic
auto ptrTy = th.getPtrType();

// each of these is a reference to a block of its own: string, class and object
// instances, and an "any" box
if (isa<mlir_ts::StringType>(type) || isa<mlir_ts::ClassType>(type) || isa<mlir_ts::ObjectType>(type) ||
isa<mlir_ts::AnyType>(type))
// instances, a Shared<T> handle, and an "any" box
if (isa<mlir_ts::StringType>(type) || isa<mlir_ts::ClassType>(type) || isa<mlir_ts::SharedType>(type) ||
isa<mlir_ts::ObjectType>(type) || isa<mlir_ts::AnyType>(type))
{
emitIncRef(rewriter.create<LLVM::LoadOp>(loc, ptrTy, slotPtr));
return;
Expand Down
5 changes: 5 additions & 0 deletions tslang/include/TypeScript/MLIRLogic/MLIRPrinter.h
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,11 @@ class MLIRPrinter
printType(out, t.getElementType());
out << ">";
})
.template Case<mlir_ts::SharedType>([&](auto t) {
out << "Shared<";
printType(out, t.getElementType());
out << ">";
})
.template Case<mlir_ts::TupleType>([&](auto t) {
printTupleOrObjectType(out, t);
})
Expand Down
2 changes: 2 additions & 0 deletions tslang/include/TypeScript/MLIRLogic/MLIRTypeCore.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class MLIRTypeCore
|| isa<mlir_ts::ObjectType>(typeIn)
|| isa<mlir_ts::AnyType>(typeIn)
|| isa<mlir_ts::ClassType>(typeIn)
|| isa<mlir_ts::SharedType>(typeIn)
|| isa<mlir_ts::UnknownType>(typeIn)
|| isa<mlir_ts::RefType>(typeIn)
|| isa<mlir_ts::ValueRefType>(typeIn)
Expand Down Expand Up @@ -72,6 +73,7 @@ class MLIRTypeCore
|| isa<mlir_ts::StringType>(typeIn)
|| isa<mlir_ts::ObjectType>(typeIn)
|| isa<mlir_ts::ClassType>(typeIn)
|| isa<mlir_ts::SharedType>(typeIn)
|| isa<mlir_ts::OptionalType>(typeIn)
|| isa<mlir_ts::AnyType>(typeIn)
|| isa<mlir_ts::UnknownType>(typeIn)
Expand Down
70 changes: 68 additions & 2 deletions tslang/include/TypeScript/MLIRLogic/MLIRTypeHelper.h
Original file line number Diff line number Diff line change
Expand Up @@ -2118,6 +2118,71 @@ class MLIRTypeHelper
return ownsHeapMemory(location, type, visiting);
}

// A handle (own spec 23.2): a value counted in every model that tracks ownership. That is a
// Shared<T>, an optional of a handle, or a union of at least one Shared<T> whose other members
// own no heap memory: null, undefined, a number, a boolean, a literal, another Shared<U>.
// `Shared<T> | null` is one pointer; `Shared<T> | number` is tagged, and its routines dispatch
// on the tag through descriptors, each Shared member's counting and the others' doing nothing.
static bool isSharedHandleType(mlir::Type type)
{
if (isa<mlir_ts::SharedType>(type))
{
return true;
}

if (auto optionalType = dyn_cast<mlir_ts::OptionalType>(type))
{
return isSharedHandleType(optionalType.getElementType());
}

if (auto unionType = dyn_cast<mlir_ts::UnionType>(type))
{
auto shared = false;
for (auto member : unionType.getTypes())
{
if (isa<mlir_ts::SharedType>(member))
{
shared = true;
continue;
}

if (ownsHeapMemoryOfUnionMember(member))
{
return false;
}
}

return shared;
}

return false;
}

// A union with a Shared<T> member that is not a handle: another member owns a block of its own
// (`Shared<T> | string`, `Shared<T> | Node`), which -mm=own does not count (spec 23.2).
static bool isSharedInOwningUnionType(mlir::Type type)
{
if (auto optionalType = dyn_cast<mlir_ts::OptionalType>(type))
{
return isSharedInOwningUnionType(optionalType.getElementType());
}

auto unionType = dyn_cast<mlir_ts::UnionType>(type);
return unionType && llvm::any_of(unionType.getTypes(), [](mlir::Type member) { return isa<mlir_ts::SharedType>(member); }) &&
!isSharedHandleType(unionType);
}

static bool ownsHeapMemoryOfUnionMember(mlir::Type member)
{
if (isa<mlir_ts::NullType, mlir_ts::UndefinedType>(member))
{
return false;
}

MLIRTypeHelper mth(member.getContext(), CompileOptions{});
return mth.ownsHeapMemory(mlir::UnknownLoc::get(member.getContext()), member);
}

// Field types of a record-shaped type, empty for anything else.
llvm::SmallVector<mlir::Type> getOwnershipFieldTypes(mlir::Type type)
{
Expand Down Expand Up @@ -3785,9 +3850,10 @@ class MLIRTypeHelper
return false;
}

// owns its own block
// owns its own block. A Shared<T> handle (own spec 23) does too, and its block's payload
// is released by the handle's routine, so it is not a record here
if (isa<mlir_ts::StringType>(type) || isa<mlir_ts::ArrayType>(type) || isa<mlir_ts::ClassType>(type) ||
isa<mlir_ts::ObjectType>(type) || isa<mlir_ts::AnyType>(type))
isa<mlir_ts::SharedType>(type) || isa<mlir_ts::ObjectType>(type) || isa<mlir_ts::AnyType>(type))
{
return true;
}
Expand Down
5 changes: 5 additions & 0 deletions tslang/include/TypeScript/MLIRLogic/MLIRTypeIterator.h
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,11 @@ class MLIRTypeIterator
return false;
return true;
})
.Case<mlir_ts::SharedType>([&](auto t) {
if (!iterate(t.getElementType()))
return false;
return true;
})
.Case<mlir_ts::TupleType>([&](auto t) {
for (auto subType : t.getFields())
{
Expand Down
7 changes: 7 additions & 0 deletions tslang/include/TypeScript/MLIRLogic/TypeOfOpHelper.h
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,13 @@ class TypeOfOpHelper
return "object";
}

// A Shared<T> handle (own spec 23.2) is what JavaScript's `typeof` calls a wrapper object.
// Its descriptor is keyed by the type, so Shared<A> and Shared<B> still get distinct ones.
if (isa<mlir_ts::SharedType>(type))
{
return "object";
}

if (isa<mlir_ts::SymbolType>(type))
{
return "symbol";
Expand Down
19 changes: 19 additions & 0 deletions tslang/include/TypeScript/TypeScriptOps.td
Original file line number Diff line number Diff line change
Expand Up @@ -2382,6 +2382,25 @@ def TypeScript_StringCopyOp : TypeScript_Op<"StringCopy", [AllTypesMatch<["in",
let results = (outs Res<AnyType, "", [MemAlloc]>:$result);
}

// Shared<T> (own spec 23). `new Shared(x)`: a block of one T, which `value` moves into.
def TypeScript_SharedNewOp : TypeScript_Op<"SharedNew"> {
let arguments = (ins AnyType:$value);
let results = (outs Res<TypeScript_Shared, "", [MemAlloc]>:$result);
}

// The place `s.value`: a reference to the handle's payload. It is read with ts.Load and written
// with ts.Store, as a field is.
def TypeScript_SharedValueRefOp : TypeScript_Op<"SharedValueRef"> {
let arguments = (ins TypeScript_Shared:$shared);
let results = (outs TypeScript_Ref:$result);
}

// `Shared.count(s)`: the number of handles under rc and own, -1 under gc and none.
def TypeScript_SharedCountOp : TypeScript_Op<"SharedCount"> {
let arguments = (ins TypeScript_Shared:$shared);
let results = (outs TypeScript_Number:$result);
}

def TypeScript_StringCompareOp : TypeScript_Op<"StringCompare"> {
let arguments = (ins TypeScript_String:$op1, TypeScript_String:$op2, I32Attr:$code);
let results = (outs TypeScript_Boolean:$result);
Expand Down
28 changes: 28 additions & 0 deletions tslang/include/TypeScript/TypeScriptTypes.td
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,34 @@ def TypeScript_Ref : TypeScript_Type<"Ref"> {
];
}

// Shared<T> (own spec 23): a counted handle to a block whose payload is one T.
def TypeScript_Shared : TypeScript_Type<"Shared"> {
let mnemonic = "shared";

let description = [{
Syntax:

```
shared-type ::= `shared` `<` type `>`
```

Examples:

```mlir
shared<!ts.class<Node>>
```
}];
let parameters = (ins "Type":$elementType);

let assemblyFormat = "`<` params `>`";

let builders = [
TypeBuilderWithInferredContext<(ins "Type":$elementType), [{
return Base::get(elementType.getContext(), elementType);
}]>
];
}

def TypeScript_ValueRef : TypeScript_Type<"ValueRef"> {
let mnemonic = "value_ref";

Expand Down
2 changes: 1 addition & 1 deletion tslang/lib/TypeScript/LowerToAffineLoops.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2657,7 +2657,7 @@ void AddTsAffineLegalOps(ConversionTarget &target)
mlir_ts::ElementRefOp, mlir_ts::PointerOffsetRefOp, mlir_ts::FuncOp, mlir_ts::GlobalOp, mlir_ts::GlobalResultOp, mlir_ts::DefaultOp,
mlir_ts::HasValueOp, mlir_ts::ValueOp, mlir_ts::ValueOrDefaultOp, mlir_ts::NullOp, mlir_ts::ParseFloatOp, mlir_ts::ParseIntOp, mlir_ts::IsNaNOp,
mlir_ts::PrintOp, mlir_ts::ConvertFOp, mlir_ts::SizeOfOp, mlir_ts::TypeDescriptorOp, mlir_ts::RetainOp, mlir_ts::ReleaseOp, mlir_ts::RetainSlotOp, mlir_ts::ReleaseSlotOp, mlir_ts::RetainCellOp, mlir_ts::ReleaseCellOp, mlir_ts::StoreOp, mlir_ts::SymbolRefOp, mlir_ts::LengthOfOp, mlir_ts::SetLengthOfOp,
mlir_ts::StringLengthOp, mlir_ts::StringResizeOp, mlir_ts::StringConcatOp, mlir_ts::StringCopyOp, mlir_ts::StringCompareOp, mlir_ts::AnyCompareOp,
mlir_ts::StringLengthOp, mlir_ts::StringResizeOp, mlir_ts::StringConcatOp, mlir_ts::StringCopyOp, mlir_ts::SharedNewOp, mlir_ts::SharedValueRefOp, mlir_ts::SharedCountOp, mlir_ts::StringCompareOp, mlir_ts::AnyCompareOp,
mlir_ts::LoadOp, mlir_ts::LoadSaveOp, mlir_ts::NewOp, mlir_ts::CreateTupleOp, mlir_ts::DeconstructTupleOp, mlir_ts::CreateArrayOp,
mlir_ts::NewEmptyArrayOp, mlir_ts::NewArrayOp, mlir_ts::DeleteOp, mlir_ts::PropertyRefOp, mlir_ts::InsertPropertyOp,
mlir_ts::ExtractPropertyOp, mlir_ts::LogicalBinaryOp, mlir_ts::UndefOp, mlir_ts::VariableOp, mlir_ts::DebugVariableOp, mlir_ts::AllocaOp,
Expand Down
Loading
Loading