Skip to content

Commit cc0357b

Browse files
committed
feat(compiler): Support operand-less instructions and fix parser crash
1 parent 9df732f commit cc0357b

File tree

6 files changed

+186
-3
lines changed

6 files changed

+186
-3
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# AsmX G3 Compiler
22

3+
[ChangeLog](./changelog)
4+
35
## Command Line Interface (CLI) Usage
46

57
### Installation

changelog

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
### **Changelog: rev 2.0**
2+
3+
This release introduces a critical stability fix for the compiler and expands the supported `amd64` instruction set. The revision is updated from `1.0` to `2.0` to reflect these significant improvements.
4+
5+
---
6+
7+
### **Bug Fixes**
8+
9+
* **Compiler: Resolved a critical null reference error during instruction parsing.**
10+
11+
A recurring internal system error that caused an `Unhandled Rejection` has been fixed. This error occurred when the compiler's parser attempted to process instructions that have no operands.
12+
13+
**Symptom:** The compiler would crash with the following error message, preventing the assembly of valid code that included operand-less instructions.
14+
```
15+
✘ Unhandled Rejection, Reason: Cannot read properties of undefined (reading 'type')
16+
```
17+
18+
**Root Cause:** The `zcc_build_generic_instruction` method directly accessed `ast[0].type` without first verifying that the `ast[0]` element existed. For instructions without operands, this `ast[0]` was `undefined`, leading to a `TypeError` and a compiler crash.
19+
20+
**Solution:** The code has been patched to use optional chaining (`?.`). The condition is now `ast[0]?.type`, which safely checks for the existence of `ast[0]` and its `type` property before attempting to access it. This ensures that operand-less instructions are handled gracefully by the parser.
21+
22+
**Before:**
23+
```javascript
24+
static zcc_build_generic_instruction(ast) {
25+
if (ast[0].type == TypeOfAtomicExpression.ARGUMENTS) { // Crashes if ast[0] is undefined
26+
return ast[0].body.values;
27+
}
28+
return ast;
29+
}
30+
```
31+
32+
**After (Fix Implemented):**
33+
```javascript
34+
static zcc_build_generic_instruction(ast) {
35+
if (ast[0]?.type && ast[0].type == TypeOfAtomicExpression.ARGUMENTS) { // Safely checks for existence
36+
return ast[0].body.values;
37+
}
38+
return ast;
39+
}
40+
```
41+
42+
### **New Features**
43+
44+
* **Instruction Set: Added support for common `amd64` instructions without operands.**
45+
46+
To enhance low-level programming capabilities, the instruction set has been updated to include several fundamental `amd64` instructions that do not take any operands.
47+
48+
The following instructions are now fully supported:
49+
* `nop`: No Operation
50+
* `fwait`: Check pending unmasked floating-point exceptions
51+
* `pushf`: Push rFLAGS Register onto the Stack
52+
* `popf`: Pop Stack into rFLAGS Register
53+
* `sahf`: Store AH into Flags
54+
* `lahf`: Load Status Flags into AH Register
55+
56+
**Implementation:** These instructions have been mapped within the compiler's `instructionSet`, allowing the assembler to correctly recognize and encode them.
57+
58+
### **Developer Impact**
59+
60+
Developers can now write code utilizing these common, operand-less instructions without encountering a compiler crash. This fix removes a significant blocker and enables more flexible and direct low-level code generation.
61+

src/ast/builder.instruction.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ class BuilderExpression {
149149
}
150150

151151
static zcc_build_generic_instruction(ast) {
152-
if (ast[0].type == TypeOfAtomicExpression.ARGUMENTS) {
152+
if (ast[0]?.type && ast[0].type == TypeOfAtomicExpression.ARGUMENTS) {
153153
return ast[0].body.values;
154154
}
155155
return ast;

src/backend/targets/x86_64/hwm/tbl.cjs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,65 @@ class AssemblyInstructionDescriptorTable {
361361
};
362362
this.instructionSet.set('lea', leaDef);
363363
});
364+
const instructions_without_operands_map = [
365+
{
366+
mnemonic: 'nop',
367+
variants: [
368+
{
369+
opcode: [0x90],
370+
operands: []
371+
}
372+
]
373+
},
374+
{
375+
mnemonic: 'fwait',
376+
variants: [
377+
{
378+
opcode: [0x9B],
379+
operands: []
380+
}
381+
]
382+
},
383+
{
384+
mnemonic: 'pushf',
385+
variants: [
386+
{
387+
opcode: [0x9C],
388+
operands: []
389+
}
390+
]
391+
},
392+
{
393+
mnemonic: 'popf',
394+
variants: [
395+
{
396+
opcode: [0x9D],
397+
operands: []
398+
}
399+
]
400+
},
401+
{
402+
mnemonic: 'sahf',
403+
variants: [
404+
{
405+
opcode: [0x9E],
406+
operands: []
407+
}
408+
]
409+
},
410+
{
411+
mnemonic: 'lahf',
412+
variants: [
413+
{
414+
opcode: [0x9F],
415+
operands: []
416+
}
417+
]
418+
}
419+
];
420+
for (const instruction_define of instructions_without_operands_map) {
421+
this.instructionSet.set(instruction_define.mnemonic, instruction_define);
422+
}
364423
}
365424
static getInstructionSet() {
366425
return this.instructionSet;

src/backend/targets/x86_64/hwm/tbl.cts

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,67 @@ export class AssemblyInstructionDescriptorTable {
378378
};
379379
this.instructionSet.set('lea', leaDef);
380380
});
381+
382+
const instructions_without_operands_map: InstructionDefinition[] = [
383+
{
384+
mnemonic: 'nop',
385+
variants: [
386+
{
387+
opcode: [0x90],
388+
operands: []
389+
}
390+
]
391+
},
392+
{
393+
mnemonic: 'fwait',
394+
variants: [
395+
{
396+
opcode: [0x9B],
397+
operands: []
398+
}
399+
]
400+
},
401+
{
402+
mnemonic: 'pushf',
403+
variants: [
404+
{
405+
opcode: [0x9C],
406+
operands: []
407+
}
408+
]
409+
},
410+
{
411+
mnemonic: 'popf',
412+
variants: [
413+
{
414+
opcode: [0x9D],
415+
operands: []
416+
}
417+
]
418+
},
419+
{
420+
mnemonic: 'sahf',
421+
variants: [
422+
{
423+
opcode: [0x9E],
424+
operands: []
425+
}
426+
]
427+
},
428+
{
429+
mnemonic: 'lahf',
430+
variants: [
431+
{
432+
opcode: [0x9F],
433+
operands: []
434+
}
435+
]
436+
}
437+
];
438+
439+
for (const instruction_define of instructions_without_operands_map) {
440+
this.instructionSet.set(instruction_define.mnemonic as string, instruction_define);
441+
}
381442
}
382443

383444
public static getInstructionSet(): Map<string, InstructionDefinition> {

src/kernel.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ function helper() {
7070
journal_composer_TL3('Compilation Options:');
7171
journal_composer_TL3(" -r, --release Create a executable file");
7272
journal_composer_TL3(" -o, --objname Set the output file name");
73-
journal_composer_TL3(" -m, --march Specify the target CPU architecture (x86_64, riscv, or arm64) for compilation");
73+
journal_composer_TL3(" -m, --march Specify the target CPU architecture (x86_64, x64, amd64) for compilation");
7474
journal_composer_TL3('Commands:');
7575
journal_composer_TL3(' --update Update AsmX compilation platform');
7676
}
@@ -81,7 +81,7 @@ function version() {
8181
}
8282

8383
function dumpversion() {
84-
Server.journal.log('Version: v28 (rev 1.0)');
84+
Server.journal.log('Version: v28 (rev 2.0)');
8585
}
8686

8787
function dumpmachine() {

0 commit comments

Comments
 (0)