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
20 changes: 20 additions & 0 deletions tslang/lib/TypeScript/MLIRGenImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -2123,6 +2123,26 @@ class MLIRGenImpl
// save value
auto address = builder.create<mlir_ts::AddressOfOp>(
location, mlir_ts::RefType::get(variableDeclarationInfo.type), variableDeclarationInfo.fullName, mlir::IntegerAttr());

// A global is a root and owns what it holds, so its declaration hands the count over
// as an assignment to it does (isOwnedGlobalSlot): `const t = new C()` in top-level
// code stored the instance, and §9.30 then gave its reference back at the end of the
// block, leaving the global pointing at a freed block. A `var` met again in a loop
// gives up what it held before.
if (isOwningSlot(location, address))
{
if (producesOwnedReference(variableDeclarationInfo.initial))
{
consumeOwnedReference(variableDeclarationInfo.initial);
}
else
{
builder.create<mlir_ts::RetainOp>(location, variableDeclarationInfo.initial);
}

builder.create<mlir_ts::ReleaseSlotOp>(location, address);
}

auto storeOp = builder.create<mlir_ts::StoreOp>(location, variableDeclarationInfo.initial, address);
if (variableDeclarationInfo.varClass.atomic)
{
Expand Down
8 changes: 7 additions & 1 deletion tslang/test/tester/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2564,7 +2564,7 @@ foreach(own_test own_fresh_string own_fresh_array own_return_new own_try_local o
own_call_no_drops own_getter_borrow own_param_kept own_any_box
own_string_length_borrow
own_closure_borrow own_closure_escape own_generator own_interface_view
own_async own_record_return own_generator_borrow)
own_async own_record_return own_generator_borrow own_global_script)
tslang_add_test(NAME test-jit-own-${own_test} COMMAND test-runner -jit -mm=own "${PROJECT_SOURCE_DIR}/test/tester/own/${own_test}.ts")
tslang_add_test(NAME test-compile-own-${own_test} COMMAND test-runner -mm=own "${PROJECT_SOURCE_DIR}/test/tester/own/${own_test}.ts")
# The promise: no counting at all in what own emits.
Expand All @@ -2576,6 +2576,12 @@ foreach(own_test own_fresh_string own_fresh_array own_return_new own_try_local o
FAIL_REGULAR_EXPRESSION "__tslang_inc_ref|__tslang_dec_ref|error:|Stack dump")
endforeach()

# A global declared in top-level code owns what it is given, under every model that counts.
foreach(global_mm rc none gc)
tslang_add_test(NAME test-jit-${global_mm}-own-global-script COMMAND test-runner -jit -mm=${global_mm} "${PROJECT_SOURCE_DIR}/test/tester/own/own_global_script.ts")
tslang_add_test(NAME test-compile-${global_mm}-own-global-script COMMAND test-runner -mm=${global_mm} "${PROJECT_SOURCE_DIR}/test/tester/own/own_global_script.ts")
endforeach()

# Across a library boundary: the library exports its functions' `__own_no_drops`, and a borrow held
# across a call to one survives. Run as a -shared pair (the library loaded at run time) and, on
# Windows, checked against a library that lists nothing (own-shared-no-drops.cmake).
Expand Down
45 changes: 45 additions & 0 deletions tslang/test/tester/own/own_global_script.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// A global declared in top-level code owns what it is given: `const t = new C()` there stored the
// instance with no reference of its own, and the reference was then given back at the end of the
// block that made it, leaving the global pointing at a freed block. A `var` in a nested block is
// still a global, and the rest of the top-level code reads it after that block has ended.
class Holder {
v: number;
s: string;

constructor(v: number) {
this.v = v;
this.s = "holder-" + v;
}
}

function churn() {
let keep: Holder[] = [];
for (let i = 0; i < 1000; i++) keep.push(new Holder(i));
return keep.length;
}

function readAll() {
return held.v + later.v + text.length;
}

const held = new Holder(7);
let later = new Holder(8);
var text = "x" + held.v;

{
var inBlock = new Holder(9);
}

assert(churn() == 1000);
assert(held.v == 7 && held.s == "holder-7");
assert(later.v == 8 && later.s == "holder-8");
assert(text == "x7");
assert(inBlock.v == 9 && inBlock.s == "holder-9");
assert(readAll() == 17);

// overwritten: the old value is given up
later = new Holder(10);
assert(churn() == 1000);
assert(later.s == "holder-10");

print("done.");
Loading