This commit is contained in:
2026-01-31 06:51:19 -06:00
parent 6712755940
commit 03feb370fd
3 changed files with 397 additions and 365 deletions

117
plan.md
View File

@@ -132,42 +132,78 @@ Categories remaining:
--- ---
## Phase 6: Update Bytecode Serialization ## Phase 6: Update Bytecode Serialization
### 6.1 JS_WriteObjectTag Changes ### 6.1 JS_WriteObjectTag Changes
- [ ] Write cpool values as JSValue (text serialization) - [x] Changed JS_WriteObjectTag to use bc_put_key() directly for property keys
- [ ] Variable opcodes reference cpool indices (already u32) - [x] Removed JS_ValueToAtom/bc_put_atom path (was broken anyway)
- [x] cpool values serialized via JS_WriteObjectRec()
### 6.2 JS_ReadObject Changes ### 6.2 JS_ReadObject Changes
- [ ] Read cpool values as JSValue - [x] Changed JS_ReadObjectTag to use bc_get_key() for property keys
- [ ] Variable opcode operands are cpool indices - [x] Uses JS_SetPropertyInternal with JSValue keys
### 6.3 Version Bump ### 6.3 Opcode Format Updates ✓
- [ ] Increment bytecode version to indicate new format - [x] Added OP_FMT_key_u8, OP_FMT_key_u16, OP_FMT_key_label_u16 formats
- [x] Updated variable opcodes to use key formats instead of atom formats
- [x] Updated bc_byte_swap() to handle new key formats
- [x] Updated JS_WriteFunctionBytecode() to skip key format opcodes
- [x] Updated JS_ReadFunctionBytecode() to skip key format opcodes
### 6.4 Version Bump ✓
- [x] Incremented BC_VERSION from 5 to 6
--- ---
## Phase 7: Final Cleanup ## Phase 7: Final Cleanup
### 7.1 Remove JSAtom Type and Functions ### 7.1 Additional Parser/Compiler Fixes ✓
- [ ] Remove `typedef uint32_t JSAtom` - [x] Fixed TOK_IDENT case to use JSValue name, JS_DupValue, emit_key
- [ ] Remove JS_NewAtom, JS_NewAtomString - [x] Fixed TOK_TRY catch clause to use JSValue name
- [ ] Remove JS_FreeAtom, JS_DupAtom (currently stubs) - [x] Fixed js_parse_statement_or_decl label_name to use JSValue
- [ ] Remove JS_AtomToValue, JS_ValueToAtom - [x] Fixed OP_scope_get_var "eval" check to use js_key_equal_str
- [ ] Remove JS_AtomToCString, JS_AtomGetStr - [x] Fixed js_parse_delete to use JSValue for name comparison
- [ ] Remove all JS_ATOM_* constants - [x] Fixed JSON parsing to use js_key_from_string for property names
- [ ] Remove JSAtomStruct and related - [x] Added js_key_from_string() helper function
- [x] Added JS_KEY__ret_, JS_KEY__eval_, JS_KEY__var_ for internal names
- [x] Updated add_closure_var, get_closure_var2, get_closure_var to use JSValue var_name
- [x] Updated set_closure_from_var to use JS_DupValue
- [x] Updated add_closure_variables to use JS_DupValue
- [x] Updated instantiate_hoisted_definitions to use fd_cpool_add for keys
- [x] Updated resolve_variables to use js_key_equal and fd_cpool_add
### 7.2 Remove quickjs-atom.h ### 7.1.1 Property Access and Runtime Fixes ✓
- [ ] Delete or convert to JSValue text initialization - [x] Fixed JS_GetPropertyValue to use js_key_from_string instead of JS_ValueToAtom
- [x] Fixed JS_GetPropertyKey to use js_key_from_string for string keys
- [x] Fixed JS_SetPropertyKey to use js_key_from_string for string keys
- [x] Fixed JS_HasPropertyKey to use js_key_from_string for string keys
- [x] Fixed JS_DeletePropertyKey to use js_key_from_string for string keys
- [x] Updated JS_HasProperty signature to take JSValue prop
- [x] Fixed OP_get_ref_value handler to use JSValue key
- [x] Fixed OP_put_ref_value handler to use JSValue key
- [x] Updated free_func_def to use JS_FreeValue for JSValue fields
### 7.3 Remove Legacy JSObject Type ### 7.2 Remove JSAtom Type and Functions ✓
- [ ] Remove JS_GC_OBJ_TYPE_JS_OBJECT if unused - [x] Removed most JS_ATOM_* constants (kept JS_ATOM_NULL, JS_ATOM_END for BC compat)
- [ ] Remove JSObject struct (replaced by JSRecord) - [x] JS_NewAtomString now returns JSValue using js_key_new
- [x] JS_FreeAtom, JS_DupAtom are stubs (no-op for backward compat)
- [x] JS_AtomToValue, JS_ValueToAtom are stubs (minimal BC compat)
- [x] Replaced JS_ATOM_* usages with JS_KEY_* or JS_GetPropertyStr
### 7.4 Update quickjs.h Public API ### 7.3 Additional Runtime Fixes ✓
- [ ] Remove JSAtom references from public API - [x] Fixed free_function_bytecode to use JS_FreeValueRT for JSValue fields
- [ ] Ensure all property functions use JSValue keys or const char* - [x] Fixed JS_SetPropertyFunctionList to use JSValue keys via find_key()
- [x] Fixed JS_InstantiateFunctionListItem to use JSValue keys
- [x] Fixed internalize_json_property to use JSValue names
- [x] Fixed emit_break and push_break_entry to use JSValue label_name
- [x] Implemented JS_Invoke to use JSValue method key
### 7.4 Remaining Stubs (kept for bytecode backward compatibility)
- JSAtom typedef (uint32_t) - used in BC serialization
- JS_ATOM_NULL, JS_ATOM_END - bytecode format markers
- JS_FreeAtom, JS_DupAtom - no-op stubs
- JS_FreeAtomRT, JS_DupAtomRT - no-op stubs
- Legacy BC reader (idx_to_atom array) - for reading old bytecode
--- ---
@@ -176,22 +212,26 @@ Categories remaining:
**Build: SUCCEEDS** with warnings (unused variables, labels) **Build: SUCCEEDS** with warnings (unused variables, labels)
**Statistics:** **Statistics:**
- JS_ATOM_* usages: ~40 remaining (down from 171+) - JS_ATOM_* usages: Minimal (only BC serialization compat)
- Most remaining are stub functions and debug code - Property access uses JS_KEY_* macros or JS_GetPropertyStr
- BC_VERSION: 6 (updated for new key-based format)
**What Works:** **What Works:**
- All property access via JSValue keys
- Keyword detection via string comparison - Keyword detection via string comparison
- Function declaration parsing with JSValue names - Function declaration parsing with JSValue names
- Variable definition with JSValue names - Variable definition with JSValue names
- Property access with JSValue keys
- Closure variable tracking with JSValue names - Closure variable tracking with JSValue names
- VM opcode handlers read cpool indices and look up JSValue - VM opcode handlers read cpool indices and look up JSValue
- resolve_scope_var() uses JSValue throughout - resolve_scope_var() uses JSValue throughout
- js_parse_property_name() returns JSValue - js_parse_property_name() returns JSValue
- Bytecode serialization uses bc_put_key/bc_get_key for property keys
**Next Priority:** - Variable opcodes use key format (cpool indices)
1. Update bytecode serialization (Phase 6) - JSON parsing uses JSValue keys
2. Final cleanup - remove JSAtom type completely (Phase 7) - Internal variable names use JS_KEY__ret_, JS_KEY__eval_, JS_KEY__var_
- JS_SetPropertyFunctionList uses JSValue keys
- JS_Invoke uses JSValue method keys
- break/continue labels use JSValue
--- ---
@@ -206,14 +246,3 @@ Categories remaining:
- JSRecord with open addressing is fully implemented - JSRecord with open addressing is fully implemented
- js_key_hash and js_key_equal work with both immediate and heap text - js_key_hash and js_key_equal work with both immediate and heap text
- js_key_equal_str enables comparison with C string literals for internal names - js_key_equal_str enables comparison with C string literals for internal names
---
## Testing Strategy
After each sub-phase:
1. `make` - verify compilation
2. Run basic eval: `./cell -e "1+1"`
3. Run property test: `./cell -e "var o = {a:1}; o.a"`
4. Run function test: `./cell -e "(function f(x){return x*2})(3)"`
5. Run closure test: `./cell -e "var f = (function(){var x=1;return function(){return x++}})(); f(); f()"`

View File

@@ -54,6 +54,9 @@ FMT(atom_label_u8)
FMT(atom_label_u16) FMT(atom_label_u16)
FMT(label_u16) FMT(label_u16)
FMT(key) FMT(key)
FMT(key_u8)
FMT(key_u16)
FMT(key_label_u16)
#undef FMT #undef FMT
#endif /* FMT */ #endif /* FMT */
@@ -104,24 +107,24 @@ DEF( array_from, 3, 0, 1, npop) /* arguments are not counted in n_pop */
DEF( return, 1, 1, 0, none) DEF( return, 1, 1, 0, none)
DEF( return_undef, 1, 0, 0, none) DEF( return_undef, 1, 0, 0, none)
DEF( throw, 1, 1, 0, none) DEF( throw, 1, 1, 0, none)
DEF( throw_error, 6, 0, 0, atom_u8) DEF( throw_error, 6, 0, 0, key_u8)
DEF( eval, 5, 1, 1, npop_u16) /* func args... -> ret_val */ DEF( eval, 5, 1, 1, npop_u16) /* func args... -> ret_val */
DEF( regexp, 1, 2, 1, none) /* create a RegExp object from the pattern and a DEF( regexp, 1, 2, 1, none) /* create a RegExp object from the pattern and a
bytecode string */ bytecode string */
DEF( check_var, 5, 0, 1, atom) /* check if a variable exists */ DEF( check_var, 5, 0, 1, key) /* check if a variable exists */
DEF( get_var_undef, 5, 0, 1, atom) /* push undefined if the variable does not exist */ DEF( get_var_undef, 5, 0, 1, key) /* push undefined if the variable does not exist */
DEF( get_var, 5, 0, 1, atom) /* throw an exception if the variable does not exist */ DEF( get_var, 5, 0, 1, key) /* throw an exception if the variable does not exist */
DEF( put_var, 5, 1, 0, atom) /* must come after get_var */ DEF( put_var, 5, 1, 0, key) /* must come after get_var */
DEF( put_var_init, 5, 1, 0, atom) /* must come after put_var. Used to initialize a global lexical variable */ DEF( put_var_init, 5, 1, 0, key) /* must come after put_var. Used to initialize a global lexical variable */
DEF( put_var_strict, 5, 2, 0, atom) /* for strict mode variable write */ DEF( put_var_strict, 5, 2, 0, key) /* for strict mode variable write */
DEF( get_ref_value, 1, 2, 3, none) DEF( get_ref_value, 1, 2, 3, none)
DEF( put_ref_value, 1, 3, 0, none) DEF( put_ref_value, 1, 3, 0, none)
DEF( define_var, 6, 0, 0, atom_u8) DEF( define_var, 6, 0, 0, key_u8)
DEF(check_define_var, 6, 0, 0, atom_u8) DEF(check_define_var, 6, 0, 0, key_u8)
DEF( define_func, 6, 1, 0, atom_u8) DEF( define_func, 6, 1, 0, key_u8)
DEF( get_field, 5, 1, 1, key) DEF( get_field, 5, 1, 1, key)
DEF( get_field2, 5, 1, 2, key) DEF( get_field2, 5, 1, 2, key)
DEF( put_field, 5, 2, 0, key) DEF( put_field, 5, 2, 0, key)
@@ -130,14 +133,14 @@ DEF( get_array_el2, 1, 2, 2, none) /* obj prop -> obj value */
DEF( get_array_el3, 1, 2, 3, none) /* obj prop -> obj prop1 value */ DEF( get_array_el3, 1, 2, 3, none) /* obj prop -> obj prop1 value */
DEF( put_array_el, 1, 3, 0, none) DEF( put_array_el, 1, 3, 0, none)
DEF( define_field, 5, 2, 1, key) DEF( define_field, 5, 2, 1, key)
DEF( set_name, 5, 1, 1, atom) DEF( set_name, 5, 1, 1, key)
DEF(set_name_computed, 1, 2, 2, none) DEF(set_name_computed, 1, 2, 2, none)
DEF(define_array_el, 1, 3, 2, none) DEF(define_array_el, 1, 3, 2, none)
DEF(copy_data_properties, 2, 3, 3, u8) DEF(copy_data_properties, 2, 3, 3, u8)
DEF( define_method, 6, 2, 1, atom_u8) DEF( define_method, 6, 2, 1, key_u8)
DEF(define_method_computed, 2, 3, 1, u8) /* must come after define_method */ DEF(define_method_computed, 2, 3, 1, u8) /* must come after define_method */
DEF( define_class, 6, 2, 2, atom_u8) /* parent ctor -> ctor proto */ DEF( define_class, 6, 2, 2, key_u8) /* parent ctor -> ctor proto */
DEF( define_class_computed, 6, 3, 3, atom_u8) /* field_name parent ctor -> field_name ctor proto (class with computed name) */ DEF( define_class_computed, 6, 3, 3, key_u8) /* field_name parent ctor -> field_name ctor proto (class with computed name) */
DEF( get_loc, 3, 0, 1, loc) DEF( get_loc, 3, 0, 1, loc)
DEF( put_loc, 3, 1, 0, loc) /* must come after get_loc */ DEF( put_loc, 3, 1, 0, loc) /* must come after get_loc */
@@ -169,10 +172,10 @@ DEF( to_object, 1, 1, 1, none)
//DEF( to_string, 1, 1, 1, none) //DEF( to_string, 1, 1, 1, none)
DEF( to_propkey, 1, 1, 1, none) DEF( to_propkey, 1, 1, 1, none)
DEF( make_loc_ref, 7, 0, 2, atom_u16) DEF( make_loc_ref, 7, 0, 2, key_u16)
DEF( make_arg_ref, 7, 0, 2, atom_u16) DEF( make_arg_ref, 7, 0, 2, key_u16)
DEF(make_var_ref_ref, 7, 0, 2, atom_u16) DEF(make_var_ref_ref, 7, 0, 2, key_u16)
DEF( make_var_ref, 5, 0, 2, atom) DEF( make_var_ref, 5, 0, 2, key)
/* arithmetic/logic operations */ /* arithmetic/logic operations */
DEF( neg, 1, 1, 1, none) DEF( neg, 1, 1, 1, none)
@@ -187,7 +190,7 @@ DEF( add_loc, 2, 1, 0, loc8)
DEF( not, 1, 1, 1, none) DEF( not, 1, 1, 1, none)
DEF( lnot, 1, 1, 1, none) DEF( lnot, 1, 1, 1, none)
DEF( delete, 1, 2, 1, none) DEF( delete, 1, 2, 1, none)
DEF( delete_var, 5, 0, 1, atom) DEF( delete_var, 5, 0, 1, key)
DEF( mul, 1, 2, 1, none) DEF( mul, 1, 2, 1, none)
DEF( mul_float, 1, 2, 1, none) DEF( mul_float, 1, 2, 1, none)
@@ -227,15 +230,15 @@ def( label, 5, 0, 0, label) /* emitted in phase 1, removed in phase 3 *
/* the following opcodes must be in the same order as the 'with_x' and /* the following opcodes must be in the same order as the 'with_x' and
get_var_undef, get_var and put_var opcodes */ get_var_undef, get_var and put_var opcodes */
def(scope_get_var_undef, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2 */ def(scope_get_var_undef, 7, 0, 1, key_u16) /* emitted in phase 1, removed in phase 2 */
def( scope_get_var, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2 */ def( scope_get_var, 7, 0, 1, key_u16) /* emitted in phase 1, removed in phase 2 */
def( scope_put_var, 7, 1, 0, atom_u16) /* emitted in phase 1, removed in phase 2 */ def( scope_put_var, 7, 1, 0, key_u16) /* emitted in phase 1, removed in phase 2 */
def(scope_delete_var, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2 */ def(scope_delete_var, 7, 0, 1, key_u16) /* emitted in phase 1, removed in phase 2 */
def( scope_make_ref, 11, 0, 2, atom_label_u16) /* emitted in phase 1, removed in phase 2 */ def( scope_make_ref, 11, 0, 2, key_label_u16) /* emitted in phase 1, removed in phase 2 */
def( scope_get_ref, 7, 0, 2, atom_u16) /* emitted in phase 1, removed in phase 2 */ def( scope_get_ref, 7, 0, 2, key_u16) /* emitted in phase 1, removed in phase 2 */
def(scope_put_var_init, 7, 0, 2, atom_u16) /* emitted in phase 1, removed in phase 2 */ def(scope_put_var_init, 7, 0, 2, key_u16) /* emitted in phase 1, removed in phase 2 */
def(scope_get_var_checkthis, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2, only used to return 'this' in derived class constructors */ def(scope_get_var_checkthis, 7, 0, 1, key_u16) /* emitted in phase 1, removed in phase 2, only used to return 'this' in derived class constructors */
def(get_field_opt_chain, 5, 1, 1, atom) /* emitted in phase 1, removed in phase 2 */ def(get_field_opt_chain, 5, 1, 1, key) /* emitted in phase 1, removed in phase 2 */
def(get_array_el_opt_chain, 1, 2, 1, none) /* emitted in phase 1, removed in phase 2 */ def(get_array_el_opt_chain, 1, 2, 1, none) /* emitted in phase 1, removed in phase 2 */
def( set_class_name, 5, 1, 1, u32) /* emitted in phase 1, removed in phase 2 */ def( set_class_name, 5, 1, 1, u32) /* emitted in phase 1, removed in phase 2 */

File diff suppressed because it is too large Load Diff