Skip to content

Commit 33d9322

Browse files
mmoskalabchatra
andauthored
fix GC-related crash in codegen (microsoft#10944)
* set refMask when building object/array literals * limit size of ldlit sections --------- Co-authored-by: Abhijith Chatra <abchatra@microsoft.com>
1 parent 02d811c commit 33d9322

2 files changed

Lines changed: 24 additions & 4 deletions

File tree

‎pxtcompiler/emitter/emitter.ts‎

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1839,9 +1839,12 @@ ${lbl}: .short 0xffff
18391839
let eltT = arrayElementType(typeOf(node))
18401840
let coll = ir.shared(ir.rtcall("Array_::mk", []))
18411841
for (let elt of node.elements) {
1842-
let mask = isRefCountedExpr(elt) ? 2 : 0
1842+
let mask = isRefCountedExpr(elt) ? (1 << 1) : 0
18431843
proc.emitExpr(ir.rtcall("Array_::push", [coll, emitExpr(elt)], mask))
18441844
}
1845+
if (node.elements.length > 0)
1846+
// Make sure there is at least one use of the array, so it doesn't get GC-ed away in the last push.
1847+
proc.emitExpr(ir.rtcall("langsupp::ignore", [coll], 1))
18451848
return coll
18461849
}
18471850
function emitObjectLiteral(node: ObjectLiteralExpression) {
@@ -1851,6 +1854,7 @@ ${lbl}: .short 0xffff
18511854

18521855
let keyName: string
18531856
let init: ir.Expr
1857+
let mask = 0
18541858
if (p.kind == SK.ShorthandPropertyAssignment) {
18551859
const sp = p as ShorthandPropertyAssignment
18561860
assert(!sp.equalsToken && !sp.objectAssignmentInitializer) // disallowed by TS grammar checker
@@ -1874,6 +1878,8 @@ ${lbl}: .short 0xffff
18741878
keyName = p.name.kind == SK.StringLiteral ?
18751879
(p.name as StringLiteral).text : p.name.getText();
18761880
init = emitExpr(p.initializer)
1881+
if (isRefCountedExpr(p.initializer))
1882+
mask |= 1 << 2
18771883
}
18781884
const fieldId = target.isNative
18791885
? ir.numlit(getIfaceMemberId(keyName))
@@ -1883,8 +1889,11 @@ ${lbl}: .short 0xffff
18831889
fieldId,
18841890
init
18851891
];
1886-
proc.emitExpr(ir.rtcall(target.isNative ? "pxtrt::mapSet" : "pxtrt::mapSetByString", args))
1892+
proc.emitExpr(ir.rtcall(target.isNative ? "pxtrt::mapSet" : "pxtrt::mapSetByString", args, mask))
18871893
})
1894+
// Make sure there is at least one use of the map, so it doesn't get GC-ed away in the last mapSet.
1895+
if (node.properties.length > 0)
1896+
proc.emitExpr(ir.rtcall("langsupp::ignore", [expr], 1))
18881897
return expr
18891898
}
18901899
function emitPropertyAssignment(node: PropertyDeclaration) {
@@ -3359,7 +3368,7 @@ ${lbl}: .short 0xffff
33593368
} else if (decl && (decl.kind == SK.PropertySignature || decl.kind == SK.PropertyAssignment || isSlowField(decl))) {
33603369
proc.emitExpr(emitCallCore(trg, trg, [src], null, decl as FunctionLikeDeclaration))
33613370
} else {
3362-
for (;;) {
3371+
for (; ;) {
33633372
if (trg.kind === SK.PropertyAccessExpression) {
33643373
const idx = fieldIndex(trg as PropertyAccessExpression)
33653374
const fld = getFieldInfo(idx.classInfo, idx.name)

‎pxtcompiler/emitter/thumb.ts‎

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,16 +261,27 @@ namespace ts.pxtc.thumb {
261261
let values: pxt.Map<string> = {}
262262
let seq = 1
263263

264+
const isLdLit = (line: assembler.Line) =>
265+
line.type == "instruction" && line.instruction && line.instruction.name == "ldlit";
266+
264267
for (let i = 0; i < f.lines.length; ++i) {
265268
let line = f.lines[i]
266269
outlines.push(line)
267-
if (line.type == "instruction" && line.instruction && line.instruction.name == "ldlit") {
270+
if (isLdLit(line)) {
268271
if (!nextGoodSpot) {
269272
let limit = line.location + 900 // leave some space - real limit is 1020
270273
let j = i + 1
274+
let numLdLits = 0;
271275
for (; j < f.lines.length; ++j) {
272276
if (f.lines[j].location > limit)
273277
break
278+
if (isLdLit(f.lines[j])) {
279+
numLdLits++;
280+
// Short branches have 256 bytes range. We don't want to move code by anywhere
281+
// close to that. Each ldlit is 4 bytes.
282+
if (numLdLits >= 160 / 4)
283+
break;
284+
}
274285
let op = f.lines[j].getOp()
275286
if (op == "b" || op == "bb" || (op == "pop" && f.lines[j].words[2] == "pc"))
276287
nextGoodSpot = f.lines[j]

0 commit comments

Comments
 (0)