MIRROR: javascript for ๐Ÿœ's, a tiny runtime with big ambitions
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Pin object and array literals to primordial prototypes

+160 -22
+6 -2
include/internal.h
··· 152 152 #ifdef ANT_JIT 153 153 void *jit_ctx; 154 154 #endif 155 - 156 - ant_value_t global; 155 + 156 + // TODO: should be under sym struct 157 + // rename object to object_proto 157 158 ant_value_t object; 159 + ant_value_t array_proto; 160 + 161 + ant_value_t global; 158 162 ant_value_t this_val; 159 163 ant_value_t new_target; 160 164 ant_value_t current_func;
+8 -7
src/ant.c
··· 1412 1412 if (pt != T_OBJ && pt != T_FUNC) break; 1413 1413 1414 1414 ant_value_t proto_proto = js_get_proto(js, proto_val); 1415 - ant_value_t object_proto = get_ctor_proto(js, "Object", 6); 1415 + ant_value_t object_proto = js->object; 1416 1416 proto_is_null_proto = (vtype(proto_proto) == T_NULL) && 1417 1417 (vdata(proto_val) != vdata(object_proto)); 1418 1418 ··· 2353 2353 ant_object_t *obj = obj_alloc(js, T_ARR, (uint8_t)ANT_INOBJ_MAX_SLOTS); 2354 2354 if (!obj) return js_mkerr(js, "oom"); 2355 2355 ant_value_t arr = mkval(T_ARR, (uintptr_t)obj); 2356 - ant_value_t array_proto = get_ctor_proto(js, "Array", 5); 2356 + ant_value_t array_proto = js->array_proto; 2357 2357 if (vtype(array_proto) == T_OBJ) js_set_proto_init(arr, array_proto); 2358 2358 2359 2359 obj->u.array.cap = MAX_DENSE_INITIAL_CAP; ··· 2377 2377 2378 2378 ant_value_t js_newobj(ant_t *js) { 2379 2379 ant_value_t obj = mkobj(js, 0); 2380 - ant_value_t proto = get_ctor_proto(js, "Object", 6); 2380 + ant_value_t proto = js->object; 2381 2381 if (vtype(proto) == T_OBJ) js_set_proto_init(obj, proto); 2382 2382 return obj; 2383 2383 } ··· 2666 2666 ant_value_t proto_obj = mkobj(js, 0); 2667 2667 if (is_err(proto_obj)) return proto_obj; 2668 2668 2669 - ant_value_t object_proto = get_ctor_proto(js, "Object", 6); 2669 + ant_value_t object_proto = js->object; 2670 2670 if (vtype(object_proto) == T_OBJ) { 2671 2671 js_set_proto_init(proto_obj, object_proto); 2672 2672 } ··· 3839 3839 3840 3840 static ant_value_t get_prototype_for_type(ant_t *js, uint8_t type) { 3841 3841 switch (type) { 3842 + case T_OBJ: return js->object; 3843 + case T_ARR: return js->array_proto; 3842 3844 case T_STR: return get_ctor_proto(js, "String", 6); 3843 3845 case T_NUM: return get_ctor_proto(js, "Number", 6); 3844 3846 case T_BOOL: return get_ctor_proto(js, "Boolean", 7); 3845 - case T_ARR: return get_ctor_proto(js, "Array", 5); 3846 3847 case T_FUNC: return get_ctor_proto(js, "Function", 8); 3847 3848 case T_PROMISE: return get_ctor_proto(js, "Promise", 7); 3848 - case T_OBJ: return get_ctor_proto(js, "Object", 6); 3849 3849 case T_BIGINT: return get_ctor_proto(js, "BigInt", 6); 3850 3850 case T_SYMBOL: return get_ctor_proto(js, "Symbol", 6); 3851 3851 default: return js_mknull(); ··· 4597 4597 4598 4598 static ant_value_t builtin_Object(ant_t *js, ant_value_t *args, int nargs) { 4599 4599 if (nargs == 0 || vtype(args[0]) == T_NULL || vtype(args[0]) == T_UNDEF) { 4600 - ant_value_t obj_proto = js_get_ctor_proto(js, "Object", 6); 4600 + ant_value_t obj_proto = js->object; 4601 4601 if (is_unboxed_obj(js, js->this_val, obj_proto)) return js->this_val; 4602 4602 return js_mkobj(js); 4603 4603 } ··· 12818 12818 set_proto(js, glob, object_proto); 12819 12819 12820 12820 js->object = object_proto; 12821 + js->array_proto = array_proto; 12821 12822 js->owns_mem = false; 12822 12823 js->max_size = 0; 12823 12824
+1
src/gc/objects.c
··· 453 453 454 454 gc_mark_value(js, js->global); 455 455 gc_mark_value(js, js->object); 456 + gc_mark_value(js, js->array_proto); 456 457 gc_mark_value(js, js->this_val); 457 458 gc_mark_value(js, js->new_target); 458 459 gc_mark_value(js, js->current_func);
+6 -3
src/modules/date.c
··· 1278 1278 1279 1279 void init_date_module(void) { 1280 1280 ant_t *js = rt->js; 1281 - ant_value_t glob = js_glob(js); 1282 - ant_value_t object_proto = js_get_ctor_proto(js, "Object", 6); 1281 + ant_value_t glob = js->global; 1282 + ant_value_t object_proto = js->object; 1283 + 1283 1284 ant_value_t function_proto = js_get_ctor_proto(js, "Function", 8); 1284 - 1285 1285 ant_value_t date_proto = js_mkobj(js); 1286 + 1286 1287 js_set_proto_init(date_proto, object_proto); 1287 1288 1288 1289 static const date_method_entry_t kDateProtoMethods[] = { ··· 1343 1344 ant_value_t date_ctor_obj = js_mkobj(js); 1344 1345 js_set_proto_init(date_ctor_obj, function_proto); 1345 1346 js_set_slot(date_ctor_obj, SLOT_CFUNC, js_mkfun(builtin_Date)); 1347 + 1346 1348 static const date_method_entry_t kDateCtorMethods[] = { 1347 1349 DATE_METHOD_ENTRY("now", builtin_Date_now), 1348 1350 DATE_METHOD_ENTRY("parse", builtin_Date_parse), 1349 1351 DATE_METHOD_ENTRY("UTC", builtin_Date_UTC), 1350 1352 }; 1353 + 1351 1354 date_define_methods(js, date_ctor_obj, kDateCtorMethods, DATE_COUNT_OF(kDateCtorMethods)); 1352 1355 js_setprop_nonconfigurable(js, date_ctor_obj, "prototype", 9, date_proto); 1353 1356 js_setprop(js, date_ctor_obj, ANT_STRING("name"), ANT_STRING("Date"));
+7 -7
src/modules/wasm.c
··· 1239 1239 g_wasm_linkerror_proto = js_mkobj(js); 1240 1240 g_wasm_runtimeerror_proto = js_mkobj(js); 1241 1241 1242 - js_set_proto_init(g_wasm_module_proto, js_get_ctor_proto(js, "Object", 6)); 1243 - js_set_proto_init(g_wasm_instance_proto, js_get_ctor_proto(js, "Object", 6)); 1244 - js_set_proto_init(g_wasm_global_proto, js_get_ctor_proto(js, "Object", 6)); 1245 - js_set_proto_init(g_wasm_memory_proto, js_get_ctor_proto(js, "Object", 6)); 1246 - js_set_proto_init(g_wasm_table_proto, js_get_ctor_proto(js, "Object", 6)); 1247 - js_set_proto_init(g_wasm_tag_proto, js_get_ctor_proto(js, "Object", 6)); 1248 - js_set_proto_init(g_wasm_exception_proto, js_get_ctor_proto(js, "Object", 6)); 1242 + js_set_proto_init(g_wasm_module_proto, js->object); 1243 + js_set_proto_init(g_wasm_instance_proto, js->object); 1244 + js_set_proto_init(g_wasm_global_proto, js->object); 1245 + js_set_proto_init(g_wasm_memory_proto, js->object); 1246 + js_set_proto_init(g_wasm_table_proto, js->object); 1247 + js_set_proto_init(g_wasm_tag_proto, js->object); 1248 + js_set_proto_init(g_wasm_exception_proto, js->object); 1249 1249 1250 1250 js_set_proto_init(g_wasm_compileerror_proto, error_proto); 1251 1251 js_set_proto_init(g_wasm_linkerror_proto, error_proto);
+1 -1
src/silver/glue.c
··· 393 393 394 394 ant_value_t jit_helper_object(sv_vm_t *vm, ant_t *js) { 395 395 ant_value_t obj = mkobj(js, 0); 396 - ant_value_t proto = js_get_ctor_proto(js, "Object", 6); 396 + ant_value_t proto = js->object; 397 397 if (vtype(proto) == T_OBJ) js_set_proto_init(obj, proto); 398 398 return obj; 399 399 }
+1 -1
src/silver/ops/literals.h
··· 70 70 ant_shape_retain(site->shared_shape); 71 71 } 72 72 } 73 - ant_value_t proto = js_get_ctor_proto(js, "Object", 6); 73 + ant_value_t proto = js->object; 74 74 if (vtype(proto) == T_OBJ) js_set_proto_init(obj, proto); 75 75 vm->stack[vm->sp++] = obj; 76 76 }
+1 -1
src/silver/ops/upvalues.h
··· 11 11 ant_value_t proto_obj = mkobj(js, 0); 12 12 if (is_err(proto_obj)) return proto_obj; 13 13 14 - ant_value_t object_proto = js_get_ctor_proto(js, "Object", 6); 14 + ant_value_t object_proto = js->object; 15 15 if (vtype(object_proto) == T_OBJ) js_set_proto_init(proto_obj, object_proto); 16 16 17 17 ant_value_t ctor_key = js_mkstr(js, "constructor", 11);
+129
tests/test_literal_primordials.cjs
··· 1 + function assert(cond, msg) { 2 + if (!cond) throw new Error(msg); 3 + } 4 + 5 + function assertEq(actual, expected, msg) { 6 + if (actual !== expected) { 7 + throw new Error(msg + ' (expected ' + expected + ', got ' + actual + ')'); 8 + } 9 + } 10 + 11 + const BuiltinObject = Object; 12 + const BuiltinArray = Array; 13 + const primordialObjectProto = BuiltinObject.getPrototypeOf({}); 14 + const primordialArrayProto = BuiltinObject.getPrototypeOf([]); 15 + const originalObjectCtorProto = BuiltinObject.prototype; 16 + const originalArrayCtorProto = BuiltinArray.prototype; 17 + 18 + function restore() { 19 + globalThis.Object = BuiltinObject; 20 + globalThis.Array = BuiltinArray; 21 + BuiltinObject.prototype = originalObjectCtorProto; 22 + BuiltinArray.prototype = originalArrayCtorProto; 23 + } 24 + 25 + function tryRedefineCtorPrototype(ctor, proto) { 26 + try { 27 + BuiltinObject.defineProperty(ctor, 'prototype', { 28 + value: proto, 29 + writable: true 30 + }); 31 + return true; 32 + } catch (_) { 33 + return false; 34 + } 35 + } 36 + 37 + console.log('literal primordial prototype regression'); 38 + 39 + try { 40 + console.log('\nTest 1: object literal ignores Object.prototype assignment'); 41 + { 42 + const altProto = { mark: 'object-assign' }; 43 + BuiltinObject.prototype = altProto; 44 + const obj = {}; 45 + assert(BuiltinObject.getPrototypeOf(obj) === primordialObjectProto, 'object literal should keep primordial Object prototype'); 46 + assertEq(obj.mark, undefined, 'object literal should ignore assigned ctor prototype'); 47 + } 48 + restore(); 49 + console.log('PASS'); 50 + 51 + console.log('\nTest 2: object literal ignores global Object rebinding'); 52 + { 53 + function AltObject() {} 54 + AltObject.prototype = { mark: 'object-global' }; 55 + globalThis.Object = AltObject; 56 + assertEq(globalThis.Object.prototype.mark, 'object-global', 'global Object rebinding should be visible from JS'); 57 + const obj = {}; 58 + assert( 59 + BuiltinObject.getPrototypeOf(obj) === primordialObjectProto, 60 + 'object literal should keep primordial Object prototype after global rebinding' 61 + ); 62 + assertEq(obj.mark, undefined, 'object literal should ignore rebound global Object'); 63 + } 64 + restore(); 65 + console.log('PASS'); 66 + 67 + console.log('\nTest 3: object literal ignores Object.defineProperty on ctor prototype'); 68 + { 69 + const altProto = { mark: 'object-define' }; 70 + if (!tryRedefineCtorPrototype(BuiltinObject, altProto)) { 71 + console.log('SKIP'); 72 + } else { 73 + assertEq(BuiltinObject.prototype.mark, 'object-define', 'defineProperty should update Object.prototype property'); 74 + const obj = {}; 75 + assert( 76 + BuiltinObject.getPrototypeOf(obj) === primordialObjectProto, 77 + 'object literal should keep primordial Object prototype after defineProperty' 78 + ); 79 + assertEq(obj.mark, undefined, 'object literal should ignore defineProperty-updated ctor prototype'); 80 + } 81 + } 82 + restore(); 83 + console.log('PASS'); 84 + 85 + console.log('\nTest 4: array literal ignores Array.prototype assignment'); 86 + { 87 + const altProto = []; 88 + altProto.mark = 'array-assign'; 89 + BuiltinArray.prototype = altProto; 90 + const arr = []; 91 + assert(BuiltinObject.getPrototypeOf(arr) === primordialArrayProto, 'array literal should keep primordial Array prototype'); 92 + assertEq(arr.mark, undefined, 'array literal should ignore assigned ctor prototype'); 93 + } 94 + restore(); 95 + console.log('PASS'); 96 + 97 + console.log('\nTest 5: array literal ignores global Array rebinding'); 98 + { 99 + function AltArray() {} 100 + AltArray.prototype = { mark: 'array-global' }; 101 + globalThis.Array = AltArray; 102 + assertEq(globalThis.Array.prototype.mark, 'array-global', 'global Array rebinding should be visible from JS'); 103 + const arr = []; 104 + assert(BuiltinObject.getPrototypeOf(arr) === primordialArrayProto, 'array literal should keep primordial Array prototype after global rebinding'); 105 + assertEq(arr.mark, undefined, 'array literal should ignore rebound global Array'); 106 + } 107 + restore(); 108 + console.log('PASS'); 109 + 110 + console.log('\nTest 6: array literal ignores Object.defineProperty on ctor prototype'); 111 + { 112 + const altProto = []; 113 + altProto.mark = 'array-define'; 114 + if (!tryRedefineCtorPrototype(BuiltinArray, altProto)) { 115 + console.log('SKIP'); 116 + } else { 117 + assertEq(BuiltinArray.prototype.mark, 'array-define', 'defineProperty should update Array.prototype property'); 118 + const arr = []; 119 + assert(BuiltinObject.getPrototypeOf(arr) === primordialArrayProto, 'array literal should keep primordial Array prototype after defineProperty'); 120 + assertEq(arr.mark, undefined, 'array literal should ignore defineProperty-updated ctor prototype'); 121 + } 122 + } 123 + restore(); 124 + console.log('PASS'); 125 + 126 + console.log('\nAll literal primordial prototype tests passed'); 127 + } finally { 128 + restore(); 129 + }