159 lines
No EOL
4.9 KiB
Markdown
159 lines
No EOL
4.9 KiB
Markdown
# Remorse C++ Compatibility Header Draft
|
|
|
|
## Purpose
|
|
|
|
This note defines the minimum compatibility/support layer that future hand-maintained Remorse C++ skeletons should target.
|
|
|
|
It is not a final header and it is not a compiler lock-in decision. It is a draft contract so early class-emission work does not silently drift into host-only modern C++ assumptions.
|
|
|
|
This note should stay paired with [docs/remorse-rebuild-abi-notes.md](docs/remorse-rebuild-abi-notes.md).
|
|
|
|
## Why This Layer Is Needed
|
|
|
|
Current rebuild notes already make three constraints clear:
|
|
|
|
- Track A original-style executable reconstruction remains in scope
|
|
- the executable is shaped by segmented pointers and far-call conventions
|
|
- host compilation success is not enough if layout, slot order, or call shape drift
|
|
|
|
That means the first C++ skeletons should compile against a compatibility layer that makes these constraints explicit even before the exact compiler/toolchain decision is closed.
|
|
|
|
## Minimum Header Categories
|
|
|
|
### 1. Exact-width integer aliases
|
|
|
|
Needed because:
|
|
|
|
- field maps are being recovered by offset
|
|
- slot/value and save/load structures use exact-width arithmetic
|
|
- sign extension versus zero extension matters repeatedly in the current notes
|
|
|
|
Current draft surface:
|
|
|
|
```cpp
|
|
using u8 = std::uint8_t;
|
|
using s8 = std::int8_t;
|
|
using u16 = std::uint16_t;
|
|
using s16 = std::int16_t;
|
|
using u32 = std::uint32_t;
|
|
using s32 = std::int32_t;
|
|
```
|
|
|
|
### 2. Packing controls
|
|
|
|
Needed because:
|
|
|
|
- object and save-state layouts are currently tracked by exact offsets
|
|
- future vtable-bearing structs must not silently pick host-default padding
|
|
|
|
Current draft surface:
|
|
|
|
```cpp
|
|
#define CR_PACK_PUSH_1
|
|
#define CR_PACK_POP
|
|
#define CR_PACKED
|
|
```
|
|
|
|
The final spelling can change per compiler. The important part is that early source slices already depend on named packing controls rather than ad hoc pragmas in every file.
|
|
|
|
### 3. Calling-convention markers
|
|
|
|
Needed because:
|
|
|
|
- later method and helper promotion will need to distinguish ordinary helpers from call-shape-sensitive surfaces
|
|
- Track A may need explicit far/near or compiler-family-specific conventions
|
|
|
|
Current draft surface:
|
|
|
|
```cpp
|
|
#define CR_CDECL
|
|
#define CR_STDCALL
|
|
#define CR_THISCALL
|
|
#define CR_FARCALL
|
|
```
|
|
|
|
`CR_FARCALL` is intentionally placeholder-level today. The current value is in making far-call-sensitive surfaces visible in source, not in pretending the final compiler spelling is already known.
|
|
|
|
### 4. Segmented pointer helper types
|
|
|
|
Needed because:
|
|
|
|
- several notes still preserve segment:offset provenance directly
|
|
- owner-loaded VM source pairs and some callback/resource lanes should not be flattened too early
|
|
|
|
Current draft surface:
|
|
|
|
```cpp
|
|
struct FarPtr16 {
|
|
u16 offset;
|
|
u16 segment;
|
|
};
|
|
|
|
template <typename T>
|
|
struct FarPtr {
|
|
u16 offset;
|
|
u16 segment;
|
|
};
|
|
```
|
|
|
|
Current rule:
|
|
|
|
- use these first as evidence-preserving placeholders, not as proof that final emitted code must literally use this exact host representation everywhere.
|
|
|
|
### 5. Vtable and slot-order helpers
|
|
|
|
Needed because:
|
|
|
|
- current family notes still treat slot order as evidence, not cosmetics
|
|
- later MCP or hand-authored promotion should preserve raw order even when names are provisional
|
|
|
|
Current draft surface:
|
|
|
|
```cpp
|
|
#define CR_VSLOT(index)
|
|
```
|
|
|
|
This can stay documentation-only at first if needed. The point is to keep raw slot numbering visible in provisional class headers.
|
|
|
|
## First Skeleton Rules
|
|
|
|
When the first class family is emitted to source, the compatibility header should enforce these rules:
|
|
|
|
1. every field uses exact-width aliases
|
|
2. every packed layout is explicit
|
|
3. every unresolved far/segment-sensitive pointer uses a named placeholder type
|
|
4. every provisional virtual surface keeps raw slot order visible
|
|
5. Track A-only assumptions are marked instead of being silently baked into Track B-style cleanup
|
|
|
|
## Families Most Likely To Need This Immediately
|
|
|
|
1. `EntityDispatchEntry`
|
|
2. `SpriteNode`
|
|
3. `EntityVmRuntime`
|
|
4. `EntityVmOwnerResource`
|
|
5. `EntityVmContext`
|
|
|
|
`Entity` will also need it, but its family split is large enough that it should probably not be the first source-emission pilot.
|
|
|
|
## What This Draft Deliberately Avoids
|
|
|
|
- picking one final compiler family now
|
|
- pretending near/far semantics are already solved
|
|
- turning unresolved imported-runtime calls into polished modern interfaces
|
|
- flattening segment:offset provenance into generic host pointers too early
|
|
|
|
## Proposed Next Step
|
|
|
|
Once the first pilot family is chosen, convert this note into a real minimal header with:
|
|
|
|
- exact-width aliases
|
|
- packing markers
|
|
- calling-convention placeholders
|
|
- one segmented-pointer placeholder type
|
|
- one comment block explaining Track A versus Track B expectations
|
|
|
|
## Bottom Line
|
|
|
|
The compatibility header should exist before the first C++ skeleton is emitted, not after.
|
|
|
|
That keeps early source work honest and preserves the option of an original-style rebuild instead of quietly drifting into a pure host-port codebase. |