]> git.kaiwu.me - njs.git/commitdiff
__proto__ property fixes.
authorIgor Sysoev <igor@sysoev.ru>
Mon, 23 Nov 2015 19:34:24 +0000 (22:34 +0300)
committerIgor Sysoev <igor@sysoev.ru>
Mon, 23 Nov 2015 19:34:24 +0000 (22:34 +0300)
njs/njs_number.c
njs/njs_object.c
njs/njs_object.h
njs/njs_string.c
njs/njs_vm.c
njs/njs_vm.h
njs/test/njs_unit_test.c

index a12264e6694ab8272eae5f4e9e377125dd863dab..2a97fd4a6200c8f4eef391261e6cd4d56269fe2f 100644 (file)
@@ -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, },
index c217de30d5d807c0cb5993d1e5bb5e5a744d0c23..5f36fdd4a7b648fbeb576e8847f3ad493733ac59 100644 (file)
@@ -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"
index 3483cd0a8f901baa7275774fabca312d568cbff0..bdb7968444b47c97500da25f899e805d21806c8c 100644 (file)
@@ -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);
index 22567b42e085a4f2dddd616e3de964a27344421d..e5f3fe246398989948571255027606b4530cd4a9 100644 (file)
@@ -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, },
 
index f1b23ae2ed60d5abcae9a68e5ee74ebb080a3d47..562180fe6fa654da347aa5bd0c84fa5c935af84a 100644 (file)
@@ -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;
index c378bf5888ef017ac7f7c626f08bdae7fc1f323c..d3f7c78db3291f73871fee030050f3fbef6c1e92 100644 (file)
@@ -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,
index 397ba19b2cc537de2bf40eaa76757ff34a483ea1..9868a37b37de826dd70a2bd1551a7edab800971a 100644 (file)
@@ -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") },