diff --git a/pkg/native_compiler/lib/back_end/arm64/assembler.dart b/pkg/native_compiler/lib/back_end/arm64/assembler.dart index 0ae9e4ab66a..b83be2d2cae 100644 --- a/pkg/native_compiler/lib/back_end/arm64/assembler.dart +++ b/pkg/native_compiler/lib/back_end/arm64/assembler.dart @@ -818,6 +818,11 @@ final class Arm64Assembler extends Assembler with Uint32OutputBuffer { callRuntime(RuntimeEntry.FatalError, 1); } + @override + void breakpoint() { + brk(0); + } + /// Generate code for inline object allocation. void inlineAllocation( Register resultReg, @@ -1898,6 +1903,11 @@ final class Arm64Assembler extends Assembler with Uint32OutputBuffer { ); } + void brk(int imm) { + assert(_isUint(16, imm)); + emit(B31 | B30 | B28 | B26 | B21 | (imm << 5)); + } + void scvtf( FPRegister rd, Register rn, [ diff --git a/pkg/native_compiler/lib/back_end/arm64/code_generator.dart b/pkg/native_compiler/lib/back_end/arm64/code_generator.dart index 03ea583d09a..bc47351b8e5 100644 --- a/pkg/native_compiler/lib/back_end/arm64/code_generator.dart +++ b/pkg/native_compiler/lib/back_end/arm64/code_generator.dart @@ -901,7 +901,17 @@ final class Arm64CodeGenerator extends CodeGenerator { @override void visitNullCheck(NullCheck instr) { - _asm.unimplemented('Unimplemented: code generation for NullCheck'); + final operandReg = inputReg(instr, 0); + final resultReg = outputReg(instr); + if (operandReg != resultReg) { + _asm.mov(resultReg, operandReg); + } + final Label slowPath = addSlowPath(() { + _asm.callRuntime(RuntimeEntry.NullCastError, 0); + _asm.breakpoint(); + }); + _asm.cmp(resultReg, nullReg); + _asm.b(slowPath, .equal); } int _getNumberOfInputsForSubtypeTestCache( diff --git a/pkg/native_compiler/lib/back_end/assembler.dart b/pkg/native_compiler/lib/back_end/assembler.dart index 65726a43b0d..ba0e21135f8 100644 --- a/pkg/native_compiler/lib/back_end/assembler.dart +++ b/pkg/native_compiler/lib/back_end/assembler.dart @@ -202,6 +202,7 @@ abstract base class Assembler { void callStub(Code stub); void unimplemented(String message); + void breakpoint(); } /// Assembler output buffer holding 32-bit instructions. diff --git a/pkg/native_compiler/test/back_end/arm64/assembler_test.dart b/pkg/native_compiler/test/back_end/arm64/assembler_test.dart index b54f29df6ba..86745da314b 100644 --- a/pkg/native_compiler/test/back_end/arm64/assembler_test.dart +++ b/pkg/native_compiler/test/back_end/arm64/assembler_test.dart @@ -398,6 +398,10 @@ void main() { 'blr lr\n', ); }); + test('breakpoint', () { + asm.breakpoint(); + expectDisassembly('brk #0x0\n'); + }); test('inlineAllocation - object size 16', () { final slowPath = Label(); asm.inlineAllocation( @@ -1637,7 +1641,16 @@ void main() { 'ret r1\n', ); }); - + test('brk', () { + asm.brk(0x1234); + expectDisassembly('brk #0x1234\n'); + expectThrows(() { + asm.brk(-1); + }); + expectThrows(() { + asm.brk(0x10000); + }); + }); test('scvtf', () { asm.scvtf(V0, R0); asm.scvtf(V1, R2, .s32);