1
2 /*
3 * Copyright (C) Igor Sysoev
4 * Copyright (C) NGINX, Inc.
5 */
6
7 #ifndef _NJS_OBJECT_H_INCLUDED_
8 #define _NJS_OBJECT_H_INCLUDED_
9
10
11 typedef enum {
12 NJS_OBJECT_PROP_DESCRIPTOR,
13 NJS_OBJECT_PROP_GETTER,
14 NJS_OBJECT_PROP_SETTER,
15 } njs_object_prop_define_t;
16
17
18 struct njs_object_init_s {
19 const njs_object_prop_t *properties;
20 njs_uint_t items;
21 };
22
23
24 typedef struct njs_traverse_s njs_traverse_t;
25
26 struct njs_traverse_s {
27 struct njs_traverse_s *parent;
28 njs_object_prop_t *prop;
29
30 njs_value_t value;
31 njs_array_t *keys;
32 int64_t index;
33
34 #define NJS_TRAVERSE_MAX_DEPTH 32
35 };
36
37
38 typedef njs_int_t (*njs_object_traverse_cb_t)(njs_vm_t *vm,
39 njs_traverse_t *traverse, void *ctx);
40
41
42 njs_object_t *njs_object_alloc(njs_vm_t *vm);
43 njs_object_t *njs_object_value_copy(njs_vm_t *vm, njs_value_t *value);
44 njs_object_value_t *njs_object_value_alloc(njs_vm_t *vm, njs_uint_t index,
45 size_t extra,const njs_value_t *value);
46 njs_array_t *njs_object_enumerate(njs_vm_t *vm, const njs_object_t *object,
47 njs_object_enum_t kind, njs_object_enum_type_t type, njs_bool_t all);
48 njs_array_t *njs_object_own_enumerate(njs_vm_t *vm, const njs_object_t *object,
49 njs_object_enum_t kind, njs_object_enum_type_t type, njs_bool_t all);
50 njs_int_t njs_object_traverse(njs_vm_t *vm, njs_object_t *object, void *ctx,
51 njs_object_traverse_cb_t cb);
52 njs_int_t njs_object_hash_create(njs_vm_t *vm, njs_lvlhsh_t *hash,
53 const njs_object_prop_t *prop, njs_uint_t n);
54 njs_int_t njs_primitive_prototype_get_proto(njs_vm_t *vm,
55 njs_object_prop_t *prop, njs_value_t *value, njs_value_t *setval,
56 njs_value_t *retval);
57 njs_int_t njs_object_prototype_create(njs_vm_t *vm, njs_object_prop_t *prop,
58 njs_value_t *value, njs_value_t *setval, njs_value_t *retval);
59 njs_value_t *njs_property_prototype_create(njs_vm_t *vm, njs_lvlhsh_t *hash,
60 njs_object_t *prototype);
61 njs_int_t njs_object_prototype_proto(njs_vm_t *vm, njs_object_prop_t *prop,
62 njs_value_t *value, njs_value_t *setval, njs_value_t *retval);
63 njs_int_t njs_object_prototype_create_constructor(njs_vm_t *vm,
64 njs_object_prop_t *prop, njs_value_t *value, njs_value_t *setval,
65 njs_value_t *retval);
66 njs_value_t *njs_property_constructor_set(njs_vm_t *vm, njs_lvlhsh_t *hash,
67 njs_value_t *constructor);
68 njs_int_t njs_object_prototype_to_string(njs_vm_t *vm, njs_value_t *args,
69 njs_uint_t nargs, njs_index_t unused);
70 njs_int_t njs_object_length(njs_vm_t *vm, njs_value_t *value, int64_t *dst);
71
72 njs_int_t njs_prop_private_copy(njs_vm_t *vm, njs_property_query_t *pq);
73 njs_object_prop_t *njs_object_prop_alloc(njs_vm_t *vm, const njs_value_t *name,
74 const njs_value_t *value, uint8_t attributes);
75 njs_int_t njs_object_property(njs_vm_t *vm, const njs_value_t *value,
76 njs_lvlhsh_query_t *lhq, njs_value_t *retval);
77 njs_object_prop_t *njs_object_property_add(njs_vm_t *vm, njs_value_t *object,
78 njs_value_t *key, njs_bool_t replace);
79 njs_int_t njs_object_prop_define(njs_vm_t *vm, njs_value_t *object,
80 njs_value_t *name, njs_value_t *value, njs_object_prop_define_t type);
81 njs_int_t njs_object_prop_descriptor(njs_vm_t *vm, njs_value_t *dest,
82 njs_value_t *value, njs_value_t *setval);
83 const char *njs_prop_type_string(njs_object_prop_type_t type);
84 njs_int_t njs_object_prop_init(njs_vm_t *vm, const njs_object_init_t* init,
85 const njs_object_prop_t *base, njs_value_t *value, njs_value_t *retval);
86
87
88 njs_inline njs_bool_t
njs_is_data_descriptor(njs_object_prop_t * prop)89 njs_is_data_descriptor(njs_object_prop_t *prop)
90 {
91 return prop->writable != NJS_ATTRIBUTE_UNSET || njs_is_valid(&prop->value);
92 }
93
94
95 njs_inline njs_bool_t
njs_is_accessor_descriptor(njs_object_prop_t * prop)96 njs_is_accessor_descriptor(njs_object_prop_t *prop)
97 {
98 return njs_is_function_or_undefined(&prop->getter)
99 || njs_is_function_or_undefined(&prop->setter);
100 }
101
102
103 njs_inline njs_bool_t
njs_is_generic_descriptor(njs_object_prop_t * prop)104 njs_is_generic_descriptor(njs_object_prop_t *prop)
105 {
106 return !njs_is_data_descriptor(prop) && !njs_is_accessor_descriptor(prop);
107 }
108
109
110 njs_inline void
njs_object_property_key_set(njs_lvlhsh_query_t * lhq,const njs_value_t * key,uint32_t hash)111 njs_object_property_key_set(njs_lvlhsh_query_t *lhq, const njs_value_t *key,
112 uint32_t hash)
113 {
114 if (njs_is_symbol(key)) {
115
116 lhq->key.length = 0;
117 lhq->key.start = NULL;
118 lhq->key_hash = njs_symbol_key(key);
119
120 } else {
121
122 /* string. */
123
124 njs_string_get(key, &lhq->key);
125
126 if (hash == 0) {
127 lhq->key_hash = njs_djb_hash(lhq->key.start, lhq->key.length);
128
129 } else {
130 lhq->key_hash = hash;
131 }
132 }
133 }
134
135
136 njs_inline void
njs_object_property_init(njs_lvlhsh_query_t * lhq,const njs_value_t * key,uint32_t hash)137 njs_object_property_init(njs_lvlhsh_query_t *lhq, const njs_value_t *key,
138 uint32_t hash)
139 {
140 lhq->proto = &njs_object_hash_proto;
141
142 njs_object_property_key_set(lhq, key, hash);
143 }
144
145
146 njs_inline njs_int_t
njs_primitive_value_to_key(njs_vm_t * vm,njs_value_t * dst,const njs_value_t * src)147 njs_primitive_value_to_key(njs_vm_t *vm, njs_value_t *dst,
148 const njs_value_t *src)
149 {
150 const njs_value_t *value;
151
152 switch (src->type) {
153
154 case NJS_NULL:
155 value = &njs_string_null;
156 break;
157
158 case NJS_UNDEFINED:
159 value = &njs_string_undefined;
160 break;
161
162 case NJS_BOOLEAN:
163 value = njs_is_true(src) ? &njs_string_true : &njs_string_false;
164 break;
165
166 case NJS_NUMBER:
167 return njs_number_to_string(vm, dst, src);
168
169 case NJS_SYMBOL:
170 case NJS_STRING:
171 /* GC: njs_retain(src); */
172 value = src;
173 break;
174
175 default:
176 return NJS_ERROR;
177 }
178
179 *dst = *value;
180
181 return NJS_OK;
182 }
183
184
185 njs_inline njs_int_t
njs_value_to_key(njs_vm_t * vm,njs_value_t * dst,njs_value_t * value)186 njs_value_to_key(njs_vm_t *vm, njs_value_t *dst, njs_value_t *value)
187 {
188 njs_int_t ret;
189 njs_value_t primitive;
190
191 if (njs_slow_path(!njs_is_primitive(value))) {
192 if (njs_slow_path(njs_is_object_symbol(value))) {
193 /* should fail */
194 value = njs_object_value(value);
195
196 } else {
197 ret = njs_value_to_primitive(vm, &primitive, value, 1);
198 if (njs_slow_path(ret != NJS_OK)) {
199 return ret;
200 }
201
202 value = &primitive;
203 }
204 }
205
206 return njs_primitive_value_to_key(vm, dst, value);
207 }
208
209
210 njs_inline njs_int_t
njs_key_string_get(njs_vm_t * vm,njs_value_t * key,njs_str_t * str)211 njs_key_string_get(njs_vm_t *vm, njs_value_t *key, njs_str_t *str)
212 {
213 njs_int_t ret;
214
215 if (njs_slow_path(njs_is_symbol(key))) {
216 ret = njs_symbol_descriptive_string(vm, key, key);
217 if (njs_slow_path(ret != NJS_OK)) {
218 return ret;
219 }
220 }
221
222 njs_string_get(key, str);
223
224 return NJS_OK;
225 }
226
227
228 njs_inline njs_int_t
njs_object_length_set(njs_vm_t * vm,njs_value_t * value,int64_t length)229 njs_object_length_set(njs_vm_t *vm, njs_value_t *value, int64_t length)
230 {
231 njs_value_t index;
232
233 static const njs_value_t string_length = njs_string("length");
234
235 njs_value_number_set(&index, length);
236
237 return njs_value_property_set(vm, value, njs_value_arg(&string_length),
238 &index);
239 }
240
241
242 njs_inline njs_int_t
njs_object_string_tag(njs_vm_t * vm,njs_value_t * value,njs_value_t * tag)243 njs_object_string_tag(njs_vm_t *vm, njs_value_t *value, njs_value_t *tag)
244 {
245 njs_int_t ret;
246
247 static const njs_value_t to_string_tag =
248 njs_wellknown_symbol(NJS_SYMBOL_TO_STRING_TAG);
249
250 ret = njs_value_property(vm, value, njs_value_arg(&to_string_tag), tag);
251 if (njs_slow_path(ret != NJS_OK)) {
252 return ret;
253 }
254
255 if (!njs_is_string(tag)) {
256 return NJS_DECLINED;
257 }
258
259 return NJS_OK;
260 }
261
262
263 njs_inline njs_object_t *
_njs_object_proto_lookup(njs_object_t * proto,njs_value_type_t type)264 _njs_object_proto_lookup(njs_object_t *proto, njs_value_type_t type)
265 {
266 do {
267 if (njs_fast_path(proto->type == type)) {
268 break;
269 }
270
271 proto = proto->__proto__;
272 } while (proto != NULL);
273
274 return proto;
275 }
276
277
278 #define njs_object_proto_lookup(proto, vtype, ctype) \
279 (ctype *) _njs_object_proto_lookup(proto, vtype)
280
281
282 extern const njs_object_type_init_t njs_obj_type_init;
283
284
285 #endif /* _NJS_OBJECT_H_INCLUDED_ */
286