@@ -24,6 +24,7 @@ private struct Word {
2424 WordType type;
2525 bool inline;
2626 Node[] inlineNodes;
27+ bool error;
2728
2829 // for C words
2930 Type[] params;
@@ -135,6 +136,8 @@ class BackendARM64 : CompilerBackend {
135136 NewConst(" Exception.msg" , 8 );
136137 NewConst(" Exception.sizeof" , 24 + 8 );
137138
139+ globals[" _cal_exception" ] = Global(GetType(" Exception" ), false , 0 );
140+
138141 foreach (ref type ; types) {
139142 NewConst(format(" %s.sizeof" , type.name), cast (long ) type.size);
140143 }
@@ -466,6 +469,32 @@ class BackendARM64 : CompilerBackend {
466469 output ~= format(" bl __func__%s\n " , node.name.Sanitise());
467470 }
468471 }
472+
473+ if (word.error) {
474+ if (" __arm64_exception" in words) {
475+ bool crash;
476+
477+ if (inScope) {
478+ crash = ! words[thisFunc].error;
479+ }
480+ else {
481+ crash = true ;
482+ }
483+
484+ if (crash) {
485+ output ~= format(" ldr x9, =__global_%s\n " , Sanitise(" _cal_exception" ));
486+ output ~= " ldr x9, [x9]\n " ;
487+ output ~= " cmp x9, #0\n " ;
488+ output ~= format(" bne __func__%s\n " , Sanitise(" __arm64_exception" ));
489+ }
490+ else {
491+ CompileReturn(node);
492+ }
493+ }
494+ else {
495+ Warn(node.error, " No exception handler" );
496+ }
497+ }
469498 }
470499 else if (VariableExists(node.name)) {
471500 auto var = GetVariable(node.name);
@@ -531,13 +560,23 @@ class BackendARM64 : CompilerBackend {
531560 thisFunc = node.name;
532561
533562 if (node.inline) {
534- words[node.name] = Word(WordType.Callisto, true , node.nodes);
563+ if (node.errors) {
564+ output ~= format(" ldr x9, =__global_%s\n " , Sanitise(" _cal_exception" ));
565+ output ~= " ldr x10, #0\n " ;
566+ output ~= " str x10, [x9]\n " ;
567+ }
568+
569+ words[node.name] = Word(
570+ WordType.Callisto, true , node.nodes
571+ );
535572 }
536573 else {
537574 assert (! inScope);
538575 inScope = true ;
539576
540- words[node.name] = Word(node.raw? WordType.Raw : WordType.Callisto , false , []);
577+ words[node.name] = Word(
578+ node.raw? WordType.Raw : WordType.Callisto , false , [], node.errors
579+ );
541580
542581 string symbol =
543582 node.raw? node.name : format(" __func__%s" , node.name.Sanitise());
@@ -549,6 +588,12 @@ class BackendARM64 : CompilerBackend {
549588 output ~= format(" %s:\n " , symbol);
550589 output ~= " str lr, [x20, #-8]!\n " ;
551590
591+ if (node.errors) {
592+ output ~= format(" ldr x9, =__global_%s\n " , Sanitise(" _cal_exception" ));
593+ output ~= " ldr x10, #0\n " ;
594+ output ~= " str x10, [x9]\n " ;
595+ }
596+
552597 // allocate parameters
553598 size_t paramSize = node.params.length * 8 ;
554599 foreach (ref type ; node.paramTypes) {
@@ -1215,6 +1260,88 @@ class BackendARM64 : CompilerBackend {
12151260 }
12161261
12171262
1218- override void CompileTryCatch (TryCatchNode node) {}
1219- override void CompileThrow (WordNode node) {}
1263+ override void CompileTryCatch (TryCatchNode node) {
1264+ if (node.func ! in words) {
1265+ Error(node.error, " Function '%s' doesn't exist" , node.func);
1266+ }
1267+
1268+ auto word = words[node.func];
1269+
1270+ if (! word.error) {
1271+ Error(node.error, " Function '%s' doesn't throw" , node.func);
1272+ }
1273+ if (word.type != WordType.Callisto) {
1274+ Error(node.error, " Non-callisto functions can't throw" );
1275+ }
1276+
1277+ if (word.inline) {
1278+ foreach (inode ; word.inlineNodes) {
1279+ compiler.CompileNode(inode);
1280+ }
1281+ }
1282+ else {
1283+ output ~= format(" bl __func__%s\n " , node.func.Sanitise());
1284+ }
1285+
1286+ ++ blockCounter;
1287+
1288+ output ~= format(" ldr x9, =__global_%s\n " , Sanitise(" _cal_exception" ));
1289+ output ~= " ldr x9, [x9]\n " ;
1290+ output ~= " cmp x9, #0\n " ;
1291+ output ~= format(" beq __catch_%d_end\n " , blockCounter);
1292+
1293+ // create scope
1294+ auto oldVars = variables.dup ;
1295+ auto oldSize = GetStackSize();
1296+
1297+ foreach (inode ; node.catchBlock) {
1298+ compiler.CompileNode(inode);
1299+ }
1300+
1301+ // remove scope
1302+ foreach (ref var ; variables) {
1303+ if (oldVars.canFind(var)) continue ;
1304+ if (! var.type.hasDeinit) continue ;
1305+
1306+ output ~= format(" add x9, x20, #%d\n " , var.offset);
1307+ output ~= " str x9, [x19], #8\n " ;
1308+ output ~= format(" bl __type_deinit_%s\n " , var.type.name.Sanitise());
1309+ }
1310+ if (GetStackSize() - oldSize > 0 ) {
1311+ OffsetLocalsStack(GetStackSize() - oldSize, false );
1312+ }
1313+ variables = oldVars;
1314+
1315+ output ~= format(" __catch_%d_end:\n " , blockCounter);
1316+ }
1317+
1318+ override void CompileThrow (WordNode node) {
1319+ if (! inScope || (! words[thisFunc].error)) {
1320+ Error(node.error, " Not in a function that can throw" );
1321+ }
1322+ if (words[thisFunc].inline) {
1323+ Error(node.error, " Can't use throw in an inline function" );
1324+ }
1325+
1326+ // set exception error
1327+ output ~= format(" ldr x9, =__global_%s\n " , Sanitise(" _cal_exception" ));
1328+ output ~= " mov x10, 0xFFFFFFFFFFFFFFFF\n " ;
1329+ output ~= " str x10, [x9]\n " ;
1330+
1331+ // copy exception message
1332+ output ~= " sub x19, x19, #8\n " ;
1333+ output ~= " mov x10, x19\n " ;
1334+ output ~= " add x11, x9, #8\n " ;
1335+ output ~= " mov x12, #3\n " ;
1336+ // copy x10 to x11, x12 times
1337+ output ~= " 1:\n " ;
1338+ output ~= " ldr x13, [x10]\n " ;
1339+ output ~= " str x13, [x11]\n " ;
1340+ output ~= " add x10, x10, #8\n " ;
1341+ output ~= " add x11, x11, #8\n " ;
1342+ output ~= " sub x12, x12, #1\n " ;
1343+ output ~= " bne 1b\n " ;
1344+
1345+ CompileReturn(node);
1346+ }
12201347}
0 commit comments