fix(runtime,codegen): new / instanceof / typeof on a class-object value (#1789) - #1795
Merged
Conversation
…ue (#1789) Make the instance-side operations work when the class is a class-expression VALUE (a heap class object from #1786) rather than `INT32(class_id)`. Adds a per-object discriminator `OBJECT_TYPE_CLASS` so a class object is told apart from its instances (which share the template's class_id): - ClassExprFresh codegen stamps the allocation via `js_object_mark_class` (object_type = OBJECT_TYPE_CLASS). Own-field get/set are gated on `gc_type`/`class_id`, not on this tag, so #1786/#1787/#1788 reads are unaffected; the tag also keeps class objects out of the instance-shaped PIC (which is keyed by the shared class_id). - `typeof aClassObject` → "function" (classes are callable), matching the existing INT32-ClassRef case. - `new (classObjectValue)(args)` → `js_new_function_construct` reads the object's class_id and allocates an instance of it, so instance methods dispatch and `instanceof` matches. (Constructor-body/field-init via dynamic new is a tracked refinement; static `new ClassName()` is unchanged.) - `x instanceof classObjectValue` → `js_instanceof_dynamic` resolves the class_id from the POINTER (not just the INT32 tag) and walks the chain. Shared helpers `is_class_object_ptr` / `is_class_object_value` validate the GcHeader before reading `object_type`. Gap test test_gap_class_expr_new_instanceof.ts byte-identical to node (typeof/own-static/new+instanceof/method dispatch). Zero regressions (class suite + #1786/#1787/#1788 gap tests unchanged, 17/17 spot-check). Note: per-evaluation class objects share the template's class_id, so cross-evaluation `instanceof` (one make() result vs a different make() result) isn't distinguished — inherent to the shared-class_id model. Refs #1789, #1785, #1772.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
#1789 —
new/instanceof/typeofon a class-object valuePart of epic #1785 (design #1772). Builds on the merged #1786 foundation + #1787/#1788 (#1792, #1793). Validated byte-for-byte against node, zero regressions.
What
Make the instance-side operations work when the class is a class-expression value (a heap class object) rather than
INT32(class_id). Introduces the per-object discriminatorOBJECT_TYPE_CLASSso a class object is distinguished from its instances (which share the template'sclass_id):ClassExprFreshcodegen marks the allocation viajs_object_mark_class→object_type = OBJECT_TYPE_CLASS.typeof aClassObject→"function"(classes are callable), matching the existing INT32-ClassRef case.new (classObjectValue)(args):js_new_function_constructreads the object'sclass_idand allocates an instance of it → instance methods dispatch,instanceofmatches.x instanceof classObjectValue:js_instanceof_dynamicnow resolves theclass_idfrom a POINTER class object (previously INT32-tag only) and walks the chain.is_class_object_ptr/is_class_object_valuevalidate the GcHeader before readingobject_type.Why it's safe
Own-field get/set are gated on
gc_type/class_id, not onobject_type, so the foundation's own-field reads (#1786/#1787/#1788) are unaffected — confirmed by the unchanged gap tests + 17/17 class spot-check. The new tag also keeps class objects out of the instance-shaped PIC (which is keyed by the sharedclass_id), which is correct.Coordination with #1790
The
OBJECT_TYPE_CLASSdiscriminator is exactly the marker #1790's #1096 layout descriptor needs to scan a class object precisely (pointer-bearing static-field slots + the prototype link). It now exists — #1790 should reuse it rather than add its own.Notes / scope
class { m(){} }remains an INT32 ClassRef (unchanged path).class_id, so cross-evaluationinstanceof(onemake()result vs a differentmake()result) isn't distinguished — inherent to the shared-class_id model.newon a class-object value is a tracked refinement (staticnew ClassName()is unchanged).Gap test
test_gap_class_expr_new_instanceof.tsbyte-identical to node.Refs #1789, #1785, #1772.