diff --git a/src/compiler.ts b/src/compiler.ts index e93e6e6848..a36d0a5bf9 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -1181,7 +1181,7 @@ export class Compiler extends DiagnosticEmitter { ); } module.addGlobal(internalName, nativeType, true, this.makeZero(type)); - if (type.isManaged && !this.skippedAutoreleases.has(initExpr)) initExpr = this.makeRetain(initExpr); + if (type.isManaged && !this.skippedAutoreleases.has(initExpr)) initExpr = this.makeRetain(initExpr, type); this.currentBody.push( module.global_set(internalName, initExpr) ); @@ -1274,7 +1274,7 @@ export class Compiler extends DiagnosticEmitter { if (initInStart) { module.addGlobal(enumValue.internalName, NativeType.I32, true, module.i32(0)); this.currentBody.push( - this.makeGlobalAssignment(enumValue, initExpr, false) + this.makeGlobalAssignment(enumValue, initExpr, Type.i32, false) ); previousValueIsMut = true; } else { @@ -1373,7 +1373,8 @@ export class Compiler extends DiagnosticEmitter { stmts.push( module.local_set(index, this.makeRetain( - module.local_get(index, type.toNativeType()) + module.local_get(index, type.toNativeType()), + type ) ) ); @@ -1511,7 +1512,8 @@ export class Compiler extends DiagnosticEmitter { ), module.local_set(thisLocal.index, this.makeRetain( - this.makeAllocation(classInstance) + this.makeAllocation(classInstance), + classInstance.type ) ) ) @@ -1674,7 +1676,7 @@ export class Compiler extends DiagnosticEmitter { module.local_get(0, nativeThisType), nativeValueType, instance.memoryOffset ); - if (type.isManaged) valueExpr = this.makeRetain(valueExpr); + if (type.isManaged) valueExpr = this.makeRetain(valueExpr, type); instance.getterRef = module.addFunction(instance.internalGetterName, nativeThisType, nativeValueType, null, valueExpr); if (instance.setterRef) { instance.set(CommonFlags.COMPILED); @@ -1711,9 +1713,9 @@ export class Compiler extends DiagnosticEmitter { ), module.block(null, [ module.drop( - this.makeRetain(module.local_get(1, nativeValueType)) + this.makeRetain(module.local_get(1, nativeValueType), type) ), - this.makeRelease(module.local_get(2, nativeValueType)) + this.makeRelease(module.local_get(2, nativeValueType), type) ]) ), module.local_get(1, nativeValueType) @@ -3099,7 +3101,7 @@ export class Compiler extends DiagnosticEmitter { module.local_set(local.index, initAutoreleaseSkipped ? initExpr - : this.makeRetain(initExpr) + : this.makeRetain(initExpr, type) ) ); } else { @@ -3497,7 +3499,7 @@ export class Compiler extends DiagnosticEmitter { // check if that worked, and if it didn't, keep the reference alive if (!this.skippedAutoreleases.has(expr)) { let index = this.tryUndoAutorelease(expr, flow); - if (index == -1) expr = this.makeRetain(expr); + if (index == -1) expr = this.makeRetain(expr, returnType); this.skippedAutoreleases.add(expr); } } @@ -5638,7 +5640,7 @@ export class Compiler extends DiagnosticEmitter { if (!leftAutoreleaseSkipped) { retainLeftInElse = true; } else { - rightExpr = this.makeRetain(rightExpr); + rightExpr = this.makeRetain(rightExpr, rightType); rightAutoreleaseSkipped = true; } } else if (!(constraints & Constraints.WILL_RETAIN)) { // otherwise keep right alive a little longer @@ -5649,7 +5651,8 @@ export class Compiler extends DiagnosticEmitter { if (leftAutoreleaseSkipped) { // left turned out to be true'ish and is dropped rightStmts.unshift( this.makeRelease( - module.local_get(temp.index, leftType.toNativeType()) + module.local_get(temp.index, leftType.toNativeType()), + leftType ) ); } @@ -5662,7 +5665,8 @@ export class Compiler extends DiagnosticEmitter { rightExpr, retainLeftInElse ? this.makeRetain( - module.local_get(temp.index, leftType.toNativeType()) + module.local_get(temp.index, leftType.toNativeType()), + leftType ) : module.local_get(temp.index, leftType.toNativeType()) ); @@ -5742,7 +5746,7 @@ export class Compiler extends DiagnosticEmitter { if (!leftAutoreleaseSkipped) { retainLeftInThen = true; } else { - rightExpr = this.makeRetain(rightExpr); + rightExpr = this.makeRetain(rightExpr, rightType); rightAutoreleaseSkipped = true; } } else if (!(constraints & Constraints.WILL_RETAIN)) { // otherwise keep right alive a little longer @@ -5755,7 +5759,8 @@ export class Compiler extends DiagnosticEmitter { // once implicit conversion with strings is performed and left is "", so: rightStmts.unshift( this.makeRelease( - module.local_get(temp.index, leftType.toNativeType()) + module.local_get(temp.index, leftType.toNativeType()), + leftType ) ); } @@ -5767,7 +5772,8 @@ export class Compiler extends DiagnosticEmitter { this.makeIsTrueish(leftExpr, leftType), retainLeftInThen ? this.makeRetain( - module.local_get(temp.index, leftType.toNativeType()) + module.local_get(temp.index, leftType.toNativeType()), + leftType ) : module.local_get(temp.index, leftType.toNativeType()), rightExpr @@ -6021,7 +6027,7 @@ export class Compiler extends DiagnosticEmitter { this.currentType = tee ? global.type : Type.void; return module.unreachable(); } - return this.makeGlobalAssignment(global, valueExpr, tee); + return this.makeGlobalAssignment(global, valueExpr, valueType, tee); } case ElementKind.FIELD: { let fieldInstance = target; @@ -6043,6 +6049,7 @@ export class Compiler extends DiagnosticEmitter { assert(fieldParent.kind == ElementKind.CLASS); return this.makeFieldAssignment(fieldInstance, valueExpr, + valueType, this.compileExpression( assert(thisExpression), (fieldParent).type, @@ -6189,7 +6196,9 @@ export class Compiler extends DiagnosticEmitter { if (flow.isAnyLocalFlag(localIndex, LocalFlags.ANY_RETAINED)) { valueExpr = this.makeReplace( valueExpr, + valueType, module.local_get(localIndex, type.toNativeType()), + type, alreadyRetained ); if (tee) { // local = REPLACE(local, value) @@ -6202,7 +6211,7 @@ export class Compiler extends DiagnosticEmitter { } else { flow.unsetLocalFlag(localIndex, LocalFlags.CONDITIONALLY_RETAINED); flow.setLocalFlag(localIndex, LocalFlags.RETAINED); - if (!alreadyRetained) valueExpr = this.makeRetain(valueExpr); + if (!alreadyRetained) valueExpr = this.makeRetain(valueExpr, valueType); if (tee) { // local = __retain(value, local) this.currentType = type; return module.local_tee(localIndex, valueExpr); @@ -6232,6 +6241,8 @@ export class Compiler extends DiagnosticEmitter { global: VariableLikeElement, /** The value to assign. */ valueExpr: ExpressionRef, + /** The type of the value to assign. */ + valueType: Type, /** Whether to tee the value. */ tee: bool ): ExpressionRef { @@ -6245,7 +6256,9 @@ export class Compiler extends DiagnosticEmitter { valueExpr = module.global_set(global.internalName, this.makeReplace( valueExpr, + valueType, module.global_get(global.internalName, nativeType), + type, alreadyRetained ) ); @@ -6282,6 +6295,8 @@ export class Compiler extends DiagnosticEmitter { field: Field, /** The value to assign. */ valueExpr: ExpressionRef, + /** The type of the value to assign. */ + valueType: Type, /** The value of `this`. */ thisExpr: ExpressionRef, /** Whether to tee the value. */ @@ -6315,10 +6330,12 @@ export class Compiler extends DiagnosticEmitter { module.local_tee(tempThis.index, thisExpr), this.makeReplace( module.local_tee(tempValue.index, valueExpr), + valueType, module.load(fieldType.byteSize, fieldType.is(TypeFlags.SIGNED), module.local_get(tempThis.index, nativeThisType), nativeFieldType, field.memoryOffset ), + fieldType, alreadyRetained ), nativeFieldType, field.memoryOffset @@ -6332,10 +6349,12 @@ export class Compiler extends DiagnosticEmitter { module.local_tee(tempThis.index, thisExpr), this.makeReplace( valueExpr, + valueType, module.load(fieldType.byteSize, fieldType.is(TypeFlags.SIGNED), module.local_get(tempThis.index, nativeThisType), nativeFieldType, field.memoryOffset ), + fieldType, alreadyRetained ), nativeFieldType, field.memoryOffset @@ -6833,7 +6852,7 @@ export class Compiler extends DiagnosticEmitter { if (flow.isNonnull(paramExpr, paramType)) flow.setLocalFlag(argumentLocal.index, LocalFlags.NONNULL); // inlining is aware of skipped autoreleases: if (paramType.isManaged) { - if (!this.skippedAutoreleases.has(paramExpr)) paramExpr = this.makeRetain(paramExpr); + if (!this.skippedAutoreleases.has(paramExpr)) paramExpr = this.makeRetain(paramExpr, paramType); flow.setLocalFlag(argumentLocal.index, LocalFlags.RETAINED); } body.unshift( @@ -6877,7 +6896,7 @@ export class Compiler extends DiagnosticEmitter { if (flow.isNonnull(initExpr, initType)) flow.setLocalFlag(argumentLocal.index, LocalFlags.NONNULL); if (initType.isManaged) { flow.setLocalFlag(argumentLocal.index, LocalFlags.RETAINED); - if (!this.skippedAutoreleases.has(initExpr)) initExpr = this.makeRetain(initExpr); + if (!this.skippedAutoreleases.has(initExpr)) initExpr = this.makeRetain(initExpr, initType); } body.push( module.local_set(argumentLocal.index, initExpr) @@ -6901,7 +6920,7 @@ export class Compiler extends DiagnosticEmitter { this.currentType = returnType; if (returnType.isManaged) { if (immediatelyDropped) { - expr = this.makeRelease(expr); + expr = this.makeRelease(expr, returnType); this.currentType = Type.void; } } @@ -7238,14 +7257,14 @@ export class Compiler extends DiagnosticEmitter { // /** Makes a retain call, retaining the expression's value. */ - makeRetain(expr: ExpressionRef): ExpressionRef { + makeRetain(expr: ExpressionRef, type: Type): ExpressionRef { var retainInstance = this.program.retainInstance; this.compileFunction(retainInstance); return this.module.call(retainInstance.internalName, [ expr ], this.options.nativeSizeType); } /** Makes a release call, releasing the expression's value. Changes the current type to void.*/ - makeRelease(expr: ExpressionRef): ExpressionRef { + makeRelease(expr: ExpressionRef, type: Type): ExpressionRef { var releaseInstance = this.program.releaseInstance; this.compileFunction(releaseInstance); return this.module.call(releaseInstance.internalName, [ expr ], NativeType.None); @@ -7255,8 +7274,12 @@ export class Compiler extends DiagnosticEmitter { makeReplace( /** New value being assigned. */ newExpr: ExpressionRef, + /** The type of the new expression. */ + newType: Type, /** Old value being replaced. */ oldExpr: ExpressionRef, + /** The type of the old expression. */ + oldType: Type, /** Whether the new value is already retained. */ alreadyRetained: bool = false, ): ExpressionRef { @@ -7269,7 +7292,7 @@ export class Compiler extends DiagnosticEmitter { let temp = flow.getTempLocal(this.options.usizeType, findUsedLocals(oldExpr)); let ret = module.block(null, [ module.local_set(temp.index, newExpr), - this.makeRelease(oldExpr), + this.makeRelease(oldExpr, oldType), module.local_get(temp.index, nativeSizeType) ], nativeSizeType); flow.freeTempLocal(temp); @@ -7290,9 +7313,9 @@ export class Compiler extends DiagnosticEmitter { ), module.block(null, [ module.local_set(temp1.index, - this.makeRetain(module.local_get(temp1.index, nativeSizeType)) + this.makeRetain(module.local_get(temp1.index, nativeSizeType), newType) ), - this.makeRelease(module.local_get(temp2.index, nativeSizeType)) + this.makeRelease(module.local_get(temp2.index, nativeSizeType), oldType) ]) ), module.local_get(temp1.index, nativeSizeType) @@ -7399,7 +7422,7 @@ export class Compiler extends DiagnosticEmitter { // If it worked, autorelease in `outerFlow` instead ? this.makeAutorelease(expr, type, outerFlow) // If it didn't work, extend the lifetime into `outerFlow` - : this.makeAutorelease(this.makeRetain(expr), type, outerFlow); + : this.makeAutorelease(this.makeRetain(expr, type), type, outerFlow); } /** Performs any queued autoreleases in the specified flow. */ @@ -7429,7 +7452,8 @@ export class Compiler extends DiagnosticEmitter { if (finalize) flow.unsetLocalFlag(localIndex, LocalFlags.ANY_RETAINED); stmts.push( this.makeRelease( - module.local_get(localIndex, local.type.toNativeType()) + module.local_get(localIndex, local.type.toNativeType()), + local.type ) ); } @@ -7524,7 +7548,8 @@ export class Compiler extends DiagnosticEmitter { flow.unsetLocalFlag(localIndex, LocalFlags.ANY_RETAINED); stmts.push( this.makeRelease( - module.local_get(localIndex, local.type.toNativeType()) + module.local_get(localIndex, local.type.toNativeType()), + local.type ) ); } @@ -7661,7 +7686,7 @@ export class Compiler extends DiagnosticEmitter { this.currentType = returnType; if (returnType.isManaged) { if (immediatelyDropped) { - expr = this.makeRelease(expr); + expr = this.makeRelease(expr, returnType); this.currentType = Type.void; } else if (!skipAutorelease) { expr = this.makeAutorelease(expr, returnType); @@ -7687,7 +7712,7 @@ export class Compiler extends DiagnosticEmitter { this.currentType = returnType; if (returnType.isManaged) { if (immediatelyDropped) { - expr = this.makeRelease(expr); + expr = this.makeRelease(expr, returnType); this.currentType = Type.void; } else if (!skipAutorelease) { expr = this.makeAutorelease(expr, returnType); @@ -7800,7 +7825,7 @@ export class Compiler extends DiagnosticEmitter { this.currentType = returnType; if (returnType.isManaged) { if (immediatelyDropped) { - expr = this.makeRelease(expr); + expr = this.makeRelease(expr, returnType); this.currentType = Type.void; } else { expr = this.makeAutorelease(expr, returnType); @@ -8576,7 +8601,7 @@ export class Compiler extends DiagnosticEmitter { : module.i32(i64_low(bufferAddress)) ], expression); this.currentType = arrayType; - expr = this.makeRetain(expr); + expr = this.makeRetain(expr, arrayType); if (arrayType.isManaged) { if (!(constraints & Constraints.WILL_RETAIN)) { expr = this.makeAutorelease(expr, arrayType); @@ -8616,7 +8641,8 @@ export class Compiler extends DiagnosticEmitter { program.options.isWasm64 ? module.i64(0) : module.i32(0) - ], expression) + ], expression), + arrayType ) ) ); @@ -8638,7 +8664,7 @@ export class Compiler extends DiagnosticEmitter { if (isManaged) { // value = __retain(value) if (!this.skippedAutoreleases.has(valueExpr)) { - valueExpr = this.makeRetain(valueExpr); + valueExpr = this.makeRetain(valueExpr, elementType); } } // store(tempData, value, immOffset) @@ -8748,7 +8774,8 @@ export class Compiler extends DiagnosticEmitter { isWasm64 ? module.i64(i64_low(bufferAddress), i64_high(bufferAddress)) : module.i32(i64_low(bufferAddress)) - ], expression) + ], expression), + program.arrayBufferInstance.type ); if (arrayType.isManaged) { if (constraints & Constraints.WILL_RETAIN) { @@ -8785,7 +8812,8 @@ export class Compiler extends DiagnosticEmitter { ? module.i64(bufferSize) : module.i32(bufferSize), module.i32(arrayInstance.id) - ], expression) + ], expression), + program.arrayBufferInstance.type ) ) ); @@ -8795,7 +8823,7 @@ export class Compiler extends DiagnosticEmitter { if (isManaged) { // value = __retain(value) if (!this.skippedAutoreleases.has(valueExpr)) { - valueExpr = this.makeRetain(valueExpr); + valueExpr = this.makeRetain(valueExpr, elementType); } } // store(tempThis, value, immOffset) @@ -8921,7 +8949,7 @@ export class Compiler extends DiagnosticEmitter { let expr = this.compileExpression(values[i], fieldType, Constraints.CONV_IMPLICIT | Constraints.WILL_RETAIN); if (fieldType.isManaged && !this.skippedAutoreleases.has(expr)) { - expr = this.makeRetain(expr); + expr = this.makeRetain(expr, fieldType); } exprs.push( module.store( // TODO: handle setters as well @@ -9136,7 +9164,8 @@ export class Compiler extends DiagnosticEmitter { // return this // } var allocExpr = this.makeAllocation(classInstance); - if (classInstance.type.isManaged) allocExpr = this.makeRetain(allocExpr); + var classType = classInstance.type; + if (classType.isManaged) allocExpr = this.makeRetain(allocExpr, classType); stmts.push( module.if( module.unary(nativeSizeType == NativeType.I64 ? UnaryOp.EqzI64 : UnaryOp.EqzI32, @@ -9390,18 +9419,18 @@ export class Compiler extends DiagnosticEmitter { if (ifThenAutoreleaseSkipped != ifElseAutoreleaseSkipped) { // unify to both skipped if (!ifThenAutoreleaseSkipped) { - ifThenExpr = this.makeRetain(ifThenExpr); + ifThenExpr = this.makeRetain(ifThenExpr, ifThenType); ifThenAutoreleaseSkipped = true; } else { - ifElseExpr = this.makeRetain(ifElseExpr); + ifElseExpr = this.makeRetain(ifElseExpr, ifElseType); ifElseAutoreleaseSkipped = true; } } else if (!ifThenAutoreleaseSkipped && commonType.isManaged) { // keep alive a little longer if (constraints & Constraints.WILL_RETAIN) { // try to undo both let ifThenIndex = this.tryUndoAutorelease(ifThenExpr, ifThenFlow); - if (ifThenIndex == -1) ifThenExpr = this.makeRetain(ifThenExpr); + if (ifThenIndex == -1) ifThenExpr = this.makeRetain(ifThenExpr, ifThenType); let ifElseIndex = this.tryUndoAutorelease(ifElseExpr, ifElseFlow); - if (ifElseIndex == -1) ifElseExpr = this.makeRetain(ifElseExpr); + if (ifElseIndex == -1) ifElseExpr = this.makeRetain(ifElseExpr, ifElseType); ifThenAutoreleaseSkipped = true; ifElseAutoreleaseSkipped = true; } else { @@ -10472,7 +10501,7 @@ export class Compiler extends DiagnosticEmitter { : 1 + parameterIndex, // this is local 0 nativeFieldType ); - if (fieldType.isManaged) initExpr = this.makeRetain(initExpr); + if (fieldType.isManaged) initExpr = this.makeRetain(initExpr, fieldType); // fall back to use initializer if present } else if (initializerNode) { @@ -10480,7 +10509,7 @@ export class Compiler extends DiagnosticEmitter { Constraints.CONV_IMPLICIT | Constraints.WILL_RETAIN ); if (fieldType.isManaged && !this.skippedAutoreleases.has(initExpr)) { - initExpr = this.makeRetain(initExpr); + initExpr = this.makeRetain(initExpr, fieldType); } // otherwise initialize with zero