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.

add support for __proto__ accessor and setter

+185 -48
+1 -1
meson.build
··· 79 79 build_date = run_command('date', '+%Y-%m-%d', check: true).stdout().strip() 80 80 81 81 version_conf = configuration_data() 82 - version_conf.set('ANT_VERSION', '0.2.3.10') 82 + version_conf.set('ANT_VERSION', '0.2.3.11') 83 83 version_conf.set('ANT_GIT_HASH', git_hash) 84 84 version_conf.set('ANT_BUILD_DATE', build_date) 85 85
+96 -37
src/ant.c
··· 1869 1869 static bool is_internal_prop(const char *key, jsoff_t klen) { 1870 1870 if (klen < 2) return false; 1871 1871 if (key[0] != '_' || key[1] != '_') return false; 1872 + if (klen == STR_PROTO_LEN && memcmp(key, STR_PROTO, STR_PROTO_LEN) == 0) return false; 1872 1873 if (klen >= 9 && key[2] == 's' && key[3] == 'y' && key[4] == 'm' && key[5] == '_' && key[klen-1] == '_' && key[klen-2] == '_') return true; 1873 1874 return true; 1874 1875 } ··· 3041 3042 jsoff_t koff = (jsoff_t) vdata(k); 3042 3043 jsoff_t klen = offtolen(loadoff(js, koff)); 3043 3044 const char *key = (char *) &js->mem[koff + sizeof(jsoff_t)]; 3044 - if (streq(key, klen, STR_PROTO, STR_PROTO_LEN)) { 3045 - return js_mkerr(js, "cannot assign to " STR_PROTO); 3046 - } 3047 3045 3048 3046 if (vtype(obj) == T_ARR && streq(key, klen, "length", 6)) { 3049 3047 jsval_t err = validate_array_length(js, v); ··· 4005 4003 } 4006 4004 4007 4005 static jsval_t call_proto_accessor(struct js *js, jsval_t prim, jsval_t accessor, bool has_accessor, jsval_t *arg, int arg_count, bool is_setter) { 4008 - if (!has_accessor || (vtype(accessor) != T_FUNC && vtype(accessor) != T_CFUNC)) { 4009 - return is_setter ? js_mkundef() : js_mkundef(); 4010 - } 4006 + if (!has_accessor || (vtype(accessor) != T_FUNC && vtype(accessor) != T_CFUNC)) return js_mkundef(); 4011 4007 4012 4008 js_parse_state_t saved; 4013 4009 JS_SAVE_STATE(js, saved); ··· 4015 4011 jsoff_t saved_toff = js->toff; 4016 4012 jsoff_t saved_tlen = js->tlen; 4017 4013 4014 + jsval_t saved_this = js->this_val; 4015 + js->this_val = prim; 4018 4016 push_this(prim); 4019 4017 jsval_t result = call_js_with_args(js, accessor, arg, arg_count); 4020 4018 pop_this(); 4019 + js->this_val = saved_this; 4021 4020 4022 4021 JS_RESTORE_STATE(js, saved); 4023 4022 js->flags = saved_flags; ··· 4344 4343 static bool try_accessor_setter(struct js *js, jsval_t obj, const char *key, size_t key_len, jsval_t val, jsval_t *out) { 4345 4344 jsval_t setter = js_mkundef(); 4346 4345 bool has_setter = false; 4346 + 4347 4347 lkp_with_setter(js, obj, key, key_len, &setter, &has_setter); 4348 + if (!has_setter) return false; 4348 4349 4349 4350 jsval_t result = call_proto_accessor(js, obj, setter, has_setter, &val, 1, true); 4350 - if (vtype(result) != T_UNDEF) { 4351 + if (is_err(result)) { 4351 4352 *out = result; 4352 4353 return true; 4353 4354 } 4354 - return false; 4355 + 4356 + *out = val; 4357 + return true; 4355 4358 } 4356 4359 4357 4360 static jsval_t assign(struct js *js, jsval_t lhs, jsval_t val) { ··· 4393 4396 4394 4397 jsoff_t key_len; 4395 4398 const char *key_str = (const char *)&js->mem[vstr(js, key, &key_len)]; 4396 - 4397 - if (key_len == STR_PROTO_LEN && memcmp(key_str, STR_PROTO, STR_PROTO_LEN) == 0) { 4398 - uint8_t vt = vtype(val); 4399 - if (vt == T_OBJ || vt == T_NULL) { 4400 - set_slot(js, obj, SLOT_PROTO, val); 4401 - return val; 4402 - } 4403 - return val; 4404 - } 4405 4399 4406 4400 jsval_t setter_result; 4407 4401 if (try_accessor_setter(js, obj, key_str, key_len, val, &setter_result)) { ··· 6740 6734 return regexp_obj; 6741 6735 } 6742 6736 6737 + static jsval_t set_obj_property(struct js *js, jsval_t obj, jsval_t key, jsval_t val, bool is_computed, bool *proto_set) { 6738 + bool is_proto = false; 6739 + if (!is_computed && vtype(key) == T_STR) { 6740 + jsoff_t klen; 6741 + const char *kstr = (char *)&js->mem[vstr(js, key, &klen)]; 6742 + is_proto = (klen == STR_PROTO_LEN && memcmp(kstr, STR_PROTO, STR_PROTO_LEN) == 0); 6743 + } 6744 + 6745 + if (is_proto) { 6746 + if (*proto_set) return js_mkerr_typed(js, JS_ERR_SYNTAX, "Duplicate __proto__ fields are not allowed in object literals"); 6747 + *proto_set = true; 6748 + uint8_t pt = vtype(val); 6749 + if (pt == T_OBJ || pt == T_ARR || pt == T_FUNC || pt == T_NULL) { 6750 + set_proto(js, obj, pt == T_NULL ? js_mknull() : val); 6751 + } 6752 + return js_mkundef(); 6753 + } 6754 + 6755 + if (vtype(val) == T_FUNC) { 6756 + jsval_t func_obj = mkval(T_OBJ, vdata(val)); 6757 + if (lkp(js, func_obj, "name", 4) == 0) { 6758 + jsval_t name_key = js_mkstr(js, "name", 4); 6759 + if (!is_err(name_key)) setprop(js, func_obj, name_key, key); 6760 + } 6761 + } 6762 + 6763 + return setprop(js, obj, key, val); 6764 + } 6765 + 6743 6766 static jsval_t js_obj_literal(struct js *js) { 6744 6767 uint8_t exe = !(js->flags & F_NOEXEC); 6745 6768 jsval_t obj = exe ? mkobj(js, 0) : js_mkundef(); ··· 6749 6772 if (vtype(object_proto) == T_OBJ) set_proto(js, obj, object_proto); 6750 6773 } 6751 6774 js->consumed = 1; 6775 + bool proto_set_in_literal = false; 6752 6776 6753 6777 while (next(js) != TOK_RBRACE) { 6754 6778 jsval_t key = 0; ··· 6975 6999 if (exe) { 6976 7000 if (is_err(val)) return val; 6977 7001 if (is_err(key)) return key; 6978 - jsval_t resolved_val = resolveprop(js, val); 6979 - 6980 - if (vtype(resolved_val) == T_FUNC) { 6981 - jsval_t func_obj = mkval(T_OBJ, vdata(resolved_val)); 6982 - jsoff_t name_prop = lkp(js, func_obj, "name", 4); 6983 - if (name_prop == 0) { 6984 - jsval_t name_key = js_mkstr(js, "name", 4); 6985 - if (!is_err(name_key)) setprop(js, func_obj, name_key, key); 6986 - } 6987 - } 6988 - 6989 - jsval_t res = setprop(js, obj, key, resolved_val); 7002 + jsval_t res = set_obj_property( 7003 + js, obj, key, resolveprop(js, val), 7004 + is_computed, &proto_set_in_literal 7005 + ); 6990 7006 if (is_err(res)) return res; 6991 7007 } 6992 7008 } ··· 13057 13073 return js_mkerr(js, "Object.setPrototypeOf: prototype must be an object or null"); 13058 13074 } 13059 13075 13060 - if (pt != T_NULL) { 13061 - jsval_t cur = proto; 13062 - int depth = 0; 13063 - while (vtype(cur) != T_NULL && depth < 32) { 13064 - if (vdata(cur) == vdata(obj)) return js_mkerr(js, "Cyclic __proto__ value"); 13065 - cur = get_proto(js, cur); 13066 - depth++; 13067 - } 13076 + for (jsval_t cur = proto; pt != T_NULL && vtype(cur) != T_NULL; cur = get_proto(js, cur)) { 13077 + if (vdata(cur) == vdata(obj)) return js_mkerr(js, "Cyclic __proto__ value"); 13068 13078 } 13069 13079 13070 13080 set_proto(js, obj, proto); 13071 13081 return obj; 13082 + } 13083 + 13084 + static jsval_t builtin_proto_getter(struct js *js, jsval_t *args, int nargs) { 13085 + jsval_t this_val = js->this_val; 13086 + uint8_t t = vtype(this_val); 13087 + 13088 + if (t == T_UNDEF || t == T_NULL) { 13089 + return js_mkerr_typed(js, JS_ERR_TYPE, "Cannot read property '__proto__' of %s", typestr(t)); 13090 + } 13091 + 13092 + if (t == T_OBJ || t == T_ARR || t == T_FUNC) { 13093 + return get_proto(js, this_val); 13094 + } 13095 + 13096 + return get_prototype_for_type(js, t); 13097 + } 13098 + 13099 + static jsval_t builtin_proto_setter(struct js *js, jsval_t *args, int nargs) { 13100 + jsval_t this_val = js->this_val; 13101 + uint8_t t = vtype(this_val); 13102 + 13103 + if (t == T_UNDEF || t == T_NULL) { 13104 + return js_mkerr_typed(js, JS_ERR_TYPE, "Cannot set property '__proto__' of %s", typestr(t)); 13105 + } 13106 + 13107 + if (t != T_OBJ && t != T_ARR && t != T_FUNC) { 13108 + return js_mkundef(); 13109 + } 13110 + 13111 + if (nargs == 0) return js_mkundef(); 13112 + 13113 + jsval_t proto = args[0]; 13114 + uint8_t pt = vtype(proto); 13115 + 13116 + if (pt != T_OBJ && pt != T_ARR && pt != T_FUNC && pt != T_NULL) { 13117 + return js_mkundef(); 13118 + } 13119 + 13120 + for (jsval_t cur = proto; pt != T_NULL && vtype(cur) == T_OBJ; cur = get_proto(js, cur)) { 13121 + if (vdata(cur) == vdata(this_val)) return js_mkundef(); 13122 + } 13123 + 13124 + set_proto(js, this_val, proto); 13125 + return js_mkundef(); 13072 13126 } 13073 13127 13074 13128 static jsval_t builtin_object_create(struct js *js, jsval_t *args, int nargs) { ··· 19877 19931 setprop(js, object_proto, js_mkstr(js, "hasOwnProperty", 14), js_mkfun(builtin_object_hasOwnProperty)); 19878 19932 setprop(js, object_proto, js_mkstr(js, "isPrototypeOf", 13), js_mkfun(builtin_object_isPrototypeOf)); 19879 19933 setprop(js, object_proto, js_mkstr(js, "propertyIsEnumerable", 20), js_mkfun(builtin_object_propertyIsEnumerable)); 19934 + 19935 + jsval_t proto_getter = js_mkfun(builtin_proto_getter); 19936 + jsval_t proto_setter = js_mkfun(builtin_proto_setter); 19937 + setprop(js, object_proto, js_mkstr(js, STR_PROTO, STR_PROTO_LEN), js_mkundef()); 19938 + js_set_accessor_desc(js, object_proto, STR_PROTO, STR_PROTO_LEN, proto_getter, proto_setter, JS_DESC_C); 19880 19939 19881 19940 jsval_t function_proto = js_mkobj(js); 19882 19941 set_proto(js, function_proto, object_proto);
+75 -10
tests/__proto__.js
··· 1 - function ShapeA() {} 2 - const ShapeB = { 3 - a() { 4 - console.log('aaa'); 1 + function testCode() { 2 + // __proto__ in object literals - basic support 3 + if (!({ __proto__: [] } instanceof Array) || { __proto__: null } instanceof Object) { 4 + return false; 5 + } 6 + 7 + // __proto__ in object literals - multiple __proto__ is an error 8 + try { 9 + eval('({ __proto__ : [], __proto__: {} })'); 10 + return false; 11 + } catch (e) {} 12 + 13 + // __proto__ in object literals - not a computed property 14 + var a = '__proto__'; 15 + if ({ [a]: [] } instanceof Array) { 16 + return false; 17 + } 18 + 19 + // __proto__ in object literals - not a shorthand method 20 + if ({ __proto__() {} } instanceof Function) { 21 + return false; 22 + } 23 + 24 + // __proto__ in object literals - not a shorthand property 25 + var __proto__ = []; 26 + if ({ __proto__ } instanceof Array) { 27 + return false; 28 + } 29 + 30 + // Object.prototype.__proto__ - get prototype 31 + var A = function () {}; 32 + if (new A().__proto__ !== A.prototype) { 33 + return false; 34 + } 35 + 36 + // Object.prototype.__proto__ - set prototype 37 + var o = {}; 38 + o.__proto__ = Array.prototype; 39 + if (!(o instanceof Array)) { 40 + return false; 41 + } 42 + 43 + // Object.prototype.__proto__ - absent from Object.create(null) 44 + var o2 = Object.create(null), 45 + p = {}; 46 + o2.__proto__ = p; 47 + if (Object.getPrototypeOf(o2) === p) { 48 + return false; 5 49 } 6 - }; 7 50 8 - ShapeA.prototype.__proto__ = ShapeB; 9 - console.log(ShapeA.prototype.__proto__); // { a: [Function: a] } 51 + // Object.prototype.__proto__ - correct property descriptor 52 + var desc = Object.getOwnPropertyDescriptor(Object.prototype, '__proto__'); 53 + if (!(desc && 'get' in desc && 'set' in desc && desc.configurable && !desc.enumerable)) { 54 + return false; 55 + } 10 56 11 - const shapeA = new ShapeA(); 12 - shapeA.a(); // aaa 13 - console.log(ShapeA.prototype === shapeA.__proto__); // true 57 + // Object.prototype.__proto__ - present in hasOwnProperty() 58 + if (!Object.prototype.hasOwnProperty('__proto__')) { 59 + return false; 60 + } 61 + 62 + // Object.prototype.__proto__ - present in Object.getOwnPropertyNames() 63 + if (Object.getOwnPropertyNames(Object.prototype).indexOf('__proto__') === -1) { 64 + return false; 65 + } 66 + 67 + return true; 68 + } 69 + 70 + try { 71 + if (testCode()) { 72 + console.log('kangax-es6/annex-b.__proto__.js: OK'); 73 + } else { 74 + console.log('kangax-es6/annex-b.__proto__.js: failed'); 75 + } 76 + } catch (e) { 77 + console.log('kangax-es6/annex-b.__proto__.js: exception: ' + e); 78 + }
+13
tests/shape.js
··· 1 + function ShapeA() {} 2 + const ShapeB = { 3 + a() { 4 + console.log('aaa'); 5 + } 6 + }; 7 + 8 + ShapeA.prototype.__proto__ = ShapeB; 9 + console.log(ShapeA.prototype.__proto__); // { a: [Function: a] } 10 + 11 + const shapeA = new ShapeA(); 12 + shapeA.a(); // aaa 13 + console.log(ShapeA.prototype === shapeA.__proto__); // true