From cae3b115918b8f6eb2e581d64fbafb456e420524 Mon Sep 17 00:00:00 2001 From: Igor Sysoev Date: Mon, 23 Nov 2015 22:34:24 +0300 Subject: [PATCH] __proto__ property fixes. --- njs/njs_number.c | 4 +++ njs/njs_object.c | 27 +++++++++++++++++++ njs/njs_object.h | 1 + njs/njs_string.c | 13 +-------- njs/njs_vm.c | 8 ++++++ njs/njs_vm.h | 5 ++++ njs/test/njs_unit_test.c | 57 ++++++++++++++++++++++++++++++++++++++++ 7 files changed, 103 insertions(+), 12 deletions(-) diff --git a/njs/njs_number.c b/njs/njs_number.c index a12264e6..2a97fd4a 100644 --- a/njs/njs_number.c +++ b/njs/njs_number.c @@ -319,6 +319,10 @@ njs_number_prototype_to_string(njs_vm_t *vm, njs_param_t *param) static const njs_object_prop_t njs_number_prototype_properties[] = { + { njs_getter(njs_primitive_prototype_get_proto), + njs_string("__proto__"), + NJS_NATIVE_GETTER, 0, 0, 0, }, + { njs_native_function(njs_number_prototype_value_of, 0), njs_string("valueOf"), NJS_METHOD, 0, 0, 0, }, diff --git a/njs/njs_object.c b/njs/njs_object.c index c217de30..5f36fdd4 100644 --- a/njs/njs_object.c +++ b/njs/njs_object.c @@ -325,6 +325,33 @@ njs_object_null_hash(njs_vm_t *vm, nxt_lvlhsh_t *hash) } +/* + * The __proto__ property of booleans, numbers and strings primitives + * and Boolean.prototype, Number.prototype, and String.prototype objects. + */ + +njs_ret_t +njs_primitive_prototype_get_proto(njs_vm_t *vm, njs_value_t *value) +{ + vm->retval.type = NJS_OBJECT; + vm->retval.data.truth = 1; + + /* + * The __proto__ getters reside in object prototypes of primitive + * types. "AND 0x7" maps type of value to prototype offset: + * NJS_BOOLEAN > NJS_PROTOTYPE_BOOLEAN, + * NJS_NUMBER > NJS_PROTOTYPE_NUMBER, + * NJS_STRING > NJS_PROTOTYPE_STRING, + * NJS_OBJECT > NJS_PROTOTYPE_OBJECT. + * So "".__proto__ points to String.prototype while + * String.prototype.__proto__ points to Object.prototype. + */ + vm->retval.data.u.object = &vm->prototypes[value->type & 7]; + + return NXT_OK; +} + + /* * The "prototype" property of Object(), Array() and other functions is * created on demand in the functions' private hash by the "prototype" diff --git a/njs/njs_object.h b/njs/njs_object.h index 3483cd0a..bdb79684 100644 --- a/njs/njs_object.h +++ b/njs/njs_object.h @@ -60,6 +60,7 @@ nxt_int_t njs_object_hash_create(njs_vm_t *vm, nxt_lvlhsh_t *hash, const njs_object_prop_t *prop, nxt_uint_t n); njs_ret_t njs_object_function(njs_vm_t *vm, njs_param_t *param); njs_object_prop_t *njs_object_prop_alloc(njs_vm_t *vm, const njs_value_t *name); +njs_ret_t njs_primitive_prototype_get_proto(njs_vm_t *vm, njs_value_t *value); njs_ret_t njs_object_prototype_create_prototype(njs_vm_t *vm, njs_value_t *value); nxt_int_t njs_object_function_hash(njs_vm_t *vm, nxt_lvlhsh_t *hash); diff --git a/njs/njs_string.c b/njs/njs_string.c index 22567b42..e5f3fe24 100644 --- a/njs/njs_string.c +++ b/njs/njs_string.c @@ -310,17 +310,6 @@ njs_string_function_hash(njs_vm_t *vm, nxt_lvlhsh_t *hash) } -static njs_ret_t -njs_string_prototype_get_prototype(njs_vm_t *vm, njs_value_t *value) -{ - vm->retval.type = NJS_OBJECT; - vm->retval.data.truth = 1; - vm->retval.data.u.object = &vm->prototypes[NJS_PROTOTYPE_STRING]; - - return NXT_OK; -} - - static njs_ret_t njs_string_prototype_length(njs_vm_t *vm, njs_value_t *value) { @@ -1587,7 +1576,7 @@ njs_string_to_number(njs_value_t *value) static const njs_object_prop_t njs_string_prototype_properties[] = { - { njs_getter(njs_string_prototype_get_prototype), + { njs_getter(njs_primitive_prototype_get_proto), njs_string("__proto__"), NJS_NATIVE_GETTER, 0, 0, 0, }, diff --git a/njs/njs_vm.c b/njs/njs_vm.c index f1b23ae2..562180fe 100644 --- a/njs/njs_vm.c +++ b/njs/njs_vm.c @@ -873,6 +873,14 @@ njs_property_query(njs_vm_t *vm, njs_property_query_t *pq, njs_value_t *object, vm->exception = &njs_exception_type_error; return NXT_ERROR; + case NJS_NUMBER: + if (pq->query != NJS_PROPERTY_QUERY_GET) { + return NJS_PRIMITIVE_VALUE; + } + + obj = &vm->prototypes[NJS_PROTOTYPE_NUMBER]; + break; + case NJS_STRING: if (pq->query == NJS_PROPERTY_QUERY_DELETE) { return NXT_DECLINED; diff --git a/njs/njs_vm.h b/njs/njs_vm.h index c378bf58..d3f7c78d 100644 --- a/njs/njs_vm.h +++ b/njs/njs_vm.h @@ -57,6 +57,11 @@ typedef enum { /* * The object types have the third bit set. It is used in njs_is_object(). + * NJS_OBJECT_BOOLEAN, NJS_OBJECT_NUMBER, and NJS_OBJECT_STRING must be + * equal to NJS_BOOLEAN, NJS_NUMBER, and NJS_STRING respectively with + * the third bit set. It is used in njs_primitive_prototype_get_proto(). + * The order of object types is used in vm->prototypes and vm->functions + * arrays. */ NJS_OBJECT = 0x08, NJS_ARRAY = 0x09, diff --git a/njs/test/njs_unit_test.c b/njs/test/njs_unit_test.c index 397ba19b..9868a37b 100644 --- a/njs/test/njs_unit_test.c +++ b/njs/test/njs_unit_test.c @@ -2565,6 +2565,9 @@ static njs_unit_test_t njs_test[] = { nxt_string("var o = { valueOf: function() { return 'OK' } } o.valueOf()"), nxt_string("OK") }, + { nxt_string("0..__proto__ === 1..__proto__"), + nxt_string("true") }, + { nxt_string("[].__proto__ === [1,2].__proto__"), nxt_string("true") }, @@ -2610,12 +2613,30 @@ static njs_unit_test_t njs_test[] = { nxt_string("Object.name"), nxt_string("Object") }, + { nxt_string("Object.length"), + nxt_string("1") }, + + { nxt_string("Object.__proto__ === Function.prototype"), + nxt_string("true") }, + { nxt_string("Object.prototype.constructor === Object"), nxt_string("true") }, + { nxt_string("Object.prototype.__proto__ === null"), + nxt_string("true") }, + { nxt_string("Object.constructor === Function"), nxt_string("true") }, + { nxt_string("({}).__proto__ === Object.prototype"), + nxt_string("true") }, + + { nxt_string("({}).__proto__.constructor === Object"), + nxt_string("true") }, + + { nxt_string("({}).constructor === Object"), + nxt_string("true") }, + { nxt_string("var a = Array(3); a +''"), nxt_string(",,") }, @@ -2652,9 +2673,15 @@ static njs_unit_test_t njs_test[] = { nxt_string("Array.length"), nxt_string("1") }, + { nxt_string("Array.__proto__ === Function.prototype"), + nxt_string("true") }, + { nxt_string("Array.prototype.constructor === Array"), nxt_string("true") }, + { nxt_string("Array.prototype.__proto__ === Object.prototype"), + nxt_string("true") }, + { nxt_string("Array.constructor === Function"), nxt_string("true") }, @@ -2687,12 +2714,21 @@ static njs_unit_test_t njs_test[] = { nxt_string("Number.length"), nxt_string("1") }, + { nxt_string("Number.__proto__ === Function.prototype"), + nxt_string("true") }, + { nxt_string("Number.prototype.constructor === Number"), nxt_string("true") }, + { nxt_string("Number.prototype.__proto__ === Object.prototype"), + nxt_string("true") }, + { nxt_string("Number.constructor === Function"), nxt_string("true") }, + { nxt_string("0..__proto__ === Number.prototype"), + nxt_string("true") }, + { nxt_string("String()"), nxt_string("") }, @@ -2708,12 +2744,21 @@ static njs_unit_test_t njs_test[] = { nxt_string("String.length"), nxt_string("1") }, + { nxt_string("String.__proto__ === Function.prototype"), + nxt_string("true") }, + { nxt_string("String.prototype.length"), nxt_string("0") }, { nxt_string("String.prototype.constructor === String"), nxt_string("true") }, + { nxt_string("String.prototype.__proto__ === Object.prototype"), + nxt_string("true") }, + + { nxt_string("''.__proto__ === String.prototype"), + nxt_string("true") }, + { nxt_string("String.constructor === Function"), nxt_string("true") }, @@ -2732,9 +2777,15 @@ static njs_unit_test_t njs_test[] = { nxt_string("Function.length"), nxt_string("1") }, + { nxt_string("Function.__proto__ === Function.prototype"), + nxt_string("true") }, + { nxt_string("Function.prototype.constructor === Function"), nxt_string("true") }, + { nxt_string("Function.prototype.__proto__ === Object.prototype"), + nxt_string("true") }, + { nxt_string("Function.constructor === Function"), nxt_string("true") }, @@ -2744,9 +2795,15 @@ static njs_unit_test_t njs_test[] = { nxt_string("RegExp.length"), nxt_string("2") }, + { nxt_string("RegExp.__proto__ === Function.prototype"), + nxt_string("true") }, + { nxt_string("RegExp.prototype.constructor === RegExp"), nxt_string("true") }, + { nxt_string("RegExp.prototype.__proto__ === Object.prototype"), + nxt_string("true") }, + { nxt_string("RegExp.constructor === Function"), nxt_string("true") }, -- 2.47.3