1 /*
2  *  Object built-ins
3  */
4 
5 #include "duk_internal.h"
6 
duk_bi_object_constructor(duk_context * ctx)7 DUK_INTERNAL duk_ret_t duk_bi_object_constructor(duk_context *ctx) {
8 	if (!duk_is_constructor_call(ctx) &&
9 	    !duk_is_null_or_undefined(ctx, 0)) {
10 		duk_to_object(ctx, 0);
11 		return 1;
12 	}
13 
14 	if (duk_is_object(ctx, 0)) {
15 		return 1;
16 	}
17 
18 	/* Pointer and buffer primitive values are treated like other
19 	 * primitives values which have a fully fledged object counterpart:
20 	 * promote to an object value.  Lightfuncs are coerced with
21 	 * ToObject() even they could also be returned as is.
22 	 */
23 	if (duk_check_type_mask(ctx, 0, DUK_TYPE_MASK_STRING |
24 	                                DUK_TYPE_MASK_BOOLEAN |
25 	                                DUK_TYPE_MASK_NUMBER |
26 	                                DUK_TYPE_MASK_POINTER |
27 	                                DUK_TYPE_MASK_BUFFER |
28 	                                DUK_TYPE_MASK_LIGHTFUNC)) {
29 		duk_to_object(ctx, 0);
30 		return 1;
31 	}
32 
33 	duk_push_object_helper(ctx,
34 	                       DUK_HOBJECT_FLAG_EXTENSIBLE |
35 	                       DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
36 	                       DUK_BIDX_OBJECT_PROTOTYPE);
37 	return 1;
38 }
39 
40 /* Shared helper to implement Object.getPrototypeOf and the ES6
41  * Object.prototype.__proto__ getter.
42  *
43  * http://www.ecma-international.org/ecma-262/6.0/index.html#sec-get-object.prototype.__proto__
44  */
duk_bi_object_getprototype_shared(duk_context * ctx)45 DUK_INTERNAL duk_ret_t duk_bi_object_getprototype_shared(duk_context *ctx) {
46 	duk_hthread *thr = (duk_hthread *) ctx;
47 	duk_hobject *h;
48 	duk_hobject *proto;
49 
50 	DUK_UNREF(thr);
51 
52 	/* magic: 0=getter call, 1=Object.getPrototypeOf */
53 	if (duk_get_current_magic(ctx) == 0) {
54 		duk_push_this_coercible_to_object(ctx);
55 		duk_insert(ctx, 0);
56 	}
57 
58 	h = duk_require_hobject_or_lfunc(ctx, 0);
59 	/* h is NULL for lightfunc */
60 
61 	/* XXX: should the API call handle this directly, i.e. attempt
62 	 * to duk_push_hobject(ctx, null) would push a null instead?
63 	 * (On the other hand 'undefined' would be just as logical, but
64 	 * not wanted here.)
65 	 */
66 
67 	if (h == NULL) {
68 		duk_push_hobject_bidx(ctx, DUK_BIDX_FUNCTION_PROTOTYPE);
69 	} else {
70 		proto = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h);
71 		if (proto) {
72 			duk_push_hobject(ctx, proto);
73 		} else {
74 			duk_push_null(ctx);
75 		}
76 	}
77 	return 1;
78 }
79 
80 /* Shared helper to implement ES6 Object.setPrototypeOf and
81  * Object.prototype.__proto__ setter.
82  *
83  * http://www.ecma-international.org/ecma-262/6.0/index.html#sec-get-object.prototype.__proto__
84  * http://www.ecma-international.org/ecma-262/6.0/index.html#sec-object.setprototypeof
85  */
duk_bi_object_setprototype_shared(duk_context * ctx)86 DUK_INTERNAL duk_ret_t duk_bi_object_setprototype_shared(duk_context *ctx) {
87 	duk_hthread *thr = (duk_hthread *) ctx;
88 	duk_hobject *h_obj;
89 	duk_hobject *h_new_proto;
90 	duk_hobject *h_curr;
91 	duk_ret_t ret_success = 1;  /* retval for success path */
92 
93 	/* Preliminaries for __proto__ and setPrototypeOf (E6 19.1.2.18 steps 1-4);
94 	 * magic: 0=setter call, 1=Object.setPrototypeOf
95 	 */
96 	if (duk_get_current_magic(ctx) == 0) {
97 		duk_push_this_check_object_coercible(ctx);
98 		duk_insert(ctx, 0);
99 		if (!duk_check_type_mask(ctx, 1, DUK_TYPE_MASK_NULL | DUK_TYPE_MASK_OBJECT)) {
100 			return 0;
101 		}
102 
103 		/* __proto__ setter returns 'undefined' on success unlike the
104 		 * setPrototypeOf() call which returns the target object.
105 		 */
106 		ret_success = 0;
107 	} else {
108 		duk_require_object_coercible(ctx, 0);
109 		duk_require_type_mask(ctx, 1, DUK_TYPE_MASK_NULL | DUK_TYPE_MASK_OBJECT);
110 	}
111 
112 	h_new_proto = duk_get_hobject(ctx, 1);
113 	/* h_new_proto may be NULL */
114 	if (duk_is_lightfunc(ctx, 0)) {
115 		if (h_new_proto == thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]) {
116 			goto skip;
117 		}
118 		goto fail_nonextensible;
119 	}
120 	h_obj = duk_get_hobject(ctx, 0);
121 	if (!h_obj) {
122 		goto skip;
123 	}
124 	DUK_ASSERT(h_obj != NULL);
125 
126 	/* [[SetPrototypeOf]] standard behavior, E6 9.1.2 */
127 	/* TODO: implement Proxy object support here */
128 
129 	if (h_new_proto == DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_obj)) {
130 		goto skip;
131 	}
132 	if (!DUK_HOBJECT_HAS_EXTENSIBLE(h_obj)) {
133 		goto fail_nonextensible;
134 	}
135 	for (h_curr = h_new_proto; h_curr != NULL; h_curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_curr)) {
136 		/* Loop prevention */
137 		if (h_curr == h_obj) {
138 			goto fail_loop;
139 		}
140 	}
141 	DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h_obj, h_new_proto);
142 	/* fall thru */
143 
144  skip:
145 	duk_set_top(ctx, 1);
146 	return ret_success;
147 
148  fail_nonextensible:
149  fail_loop:
150 	return DUK_RET_TYPE_ERROR;
151 }
152 
duk_bi_object_constructor_get_own_property_descriptor(duk_context * ctx)153 DUK_INTERNAL duk_ret_t duk_bi_object_constructor_get_own_property_descriptor(duk_context *ctx) {
154 	/* XXX: no need for indirect call */
155 	return duk_hobject_object_get_own_property_descriptor(ctx);
156 }
157 
duk_bi_object_constructor_create(duk_context * ctx)158 DUK_INTERNAL duk_ret_t duk_bi_object_constructor_create(duk_context *ctx) {
159 	duk_tval *tv;
160 	duk_hobject *proto = NULL;
161 
162 	DUK_ASSERT_TOP(ctx, 2);
163 
164 	tv = duk_get_tval(ctx, 0);
165 	DUK_ASSERT(tv != NULL);
166 	if (DUK_TVAL_IS_NULL(tv)) {
167 		;
168 	} else if (DUK_TVAL_IS_OBJECT(tv)) {
169 		proto = DUK_TVAL_GET_OBJECT(tv);
170 		DUK_ASSERT(proto != NULL);
171 	} else {
172 		return DUK_RET_TYPE_ERROR;
173 	}
174 
175 	(void) duk_push_object_helper_proto(ctx,
176 	                                    DUK_HOBJECT_FLAG_EXTENSIBLE |
177 	                                    DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
178 	                                    proto);
179 
180 	if (!duk_is_undefined(ctx, 1)) {
181 		/* [ O Properties obj ] */
182 
183 		duk_replace(ctx, 0);
184 
185 		/* [ obj Properties ] */
186 
187 		/* Just call the "original" Object.defineProperties() to
188 		 * finish up.
189 		 */
190 
191 		return duk_bi_object_constructor_define_properties(ctx);
192 	}
193 
194 	/* [ O Properties obj ] */
195 
196 	return 1;
197 }
198 
duk_bi_object_constructor_define_property(duk_context * ctx)199 DUK_INTERNAL duk_ret_t duk_bi_object_constructor_define_property(duk_context *ctx) {
200 	duk_hobject *obj;
201 	duk_hstring *key;
202 	duk_hobject *get;
203 	duk_hobject *set;
204 	duk_idx_t idx_value;
205 	duk_uint_t defprop_flags;
206 
207 	DUK_ASSERT(ctx != NULL);
208 
209 	DUK_DDD(DUK_DDDPRINT("Object.defineProperty(): ctx=%p obj=%!T key=%!T desc=%!T",
210 	                     (void *) ctx,
211 	                     (duk_tval *) duk_get_tval(ctx, 0),
212 	                     (duk_tval *) duk_get_tval(ctx, 1),
213 	                     (duk_tval *) duk_get_tval(ctx, 2)));
214 
215 	/* [ obj key desc ] */
216 
217 	/* Lightfuncs are currently supported by coercing to a temporary
218 	 * Function object; changes will be allowed (the coerced value is
219 	 * extensible) but will be lost.
220 	 */
221 	obj = duk_require_hobject_or_lfunc_coerce(ctx, 0);
222 	(void) duk_to_string(ctx, 1);
223 	key = duk_require_hstring(ctx, 1);
224 	(void) duk_require_hobject(ctx, 2);
225 
226 	DUK_ASSERT(obj != NULL);
227 	DUK_ASSERT(key != NULL);
228 	DUK_ASSERT(duk_get_hobject(ctx, 2) != NULL);
229 
230 	/*
231 	 *  Validate and convert argument property descriptor (an Ecmascript
232 	 *  object) into a set of defprop_flags and possibly property value,
233 	 *  getter, and/or setter values on the value stack.
234 	 *
235 	 *  Lightfunc set/get values are coerced to full Functions.
236 	 */
237 
238 	duk_hobject_prepare_property_descriptor(ctx,
239 	                                        2 /*idx_desc*/,
240 	                                        &defprop_flags,
241 	                                        &idx_value,
242 	                                        &get,
243 	                                        &set);
244 
245 	/*
246 	 *  Use Object.defineProperty() helper for the actual operation.
247 	 */
248 
249 	duk_hobject_define_property_helper(ctx,
250 	                                   defprop_flags,
251 	                                   obj,
252 	                                   key,
253 	                                   idx_value,
254 	                                   get,
255 	                                   set);
256 
257 	/* Ignore the normalize/validate helper outputs on the value stack,
258 	 * they're popped automatically.
259 	 */
260 
261 	/*
262 	 *  Return target object.
263 	 */
264 
265 	duk_push_hobject(ctx, obj);
266 	return 1;
267 }
268 
duk_bi_object_constructor_define_properties(duk_context * ctx)269 DUK_INTERNAL duk_ret_t duk_bi_object_constructor_define_properties(duk_context *ctx) {
270 	duk_small_uint_t pass;
271 	duk_uint_t defprop_flags;
272 	duk_hobject *obj;
273 	duk_idx_t idx_value;
274 	duk_hobject *get;
275 	duk_hobject *set;
276 
277 	/* Lightfunc handling by ToObject() coercion. */
278 	obj = duk_require_hobject_or_lfunc_coerce(ctx, 0);  /* target */
279 	DUK_ASSERT(obj != NULL);
280 
281 	duk_to_object(ctx, 1);        /* properties object */
282 
283 	DUK_DDD(DUK_DDDPRINT("target=%!iT, properties=%!iT",
284 	                     (duk_tval *) duk_get_tval(ctx, 0),
285 	                     (duk_tval *) duk_get_tval(ctx, 1)));
286 
287 	/*
288 	 *  Two pass approach to processing the property descriptors.
289 	 *  On first pass validate and normalize all descriptors before
290 	 *  any changes are made to the target object.  On second pass
291 	 *  make the actual modifications to the target object.
292 	 *
293 	 *  Right now we'll just use the same normalize/validate helper
294 	 *  on both passes, ignoring its outputs on the first pass.
295 	 */
296 
297 	for (pass = 0; pass < 2; pass++) {
298 		duk_set_top(ctx, 2);  /* -> [ hobject props ] */
299 		duk_enum(ctx, 1, DUK_ENUM_OWN_PROPERTIES_ONLY /*enum_flags*/);
300 
301 		for (;;) {
302 			duk_hstring *key;
303 
304 			/* [ hobject props enum(props) ] */
305 
306 			duk_set_top(ctx, 3);
307 
308 			if (!duk_next(ctx, 2, 1 /*get_value*/)) {
309 				break;
310 			}
311 
312 			DUK_DDD(DUK_DDDPRINT("-> key=%!iT, desc=%!iT",
313 			                     (duk_tval *) duk_get_tval(ctx, -2),
314 			                     (duk_tval *) duk_get_tval(ctx, -1)));
315 
316 			/* [ hobject props enum(props) key desc ] */
317 
318 			duk_hobject_prepare_property_descriptor(ctx,
319 			                                        4 /*idx_desc*/,
320 			                                        &defprop_flags,
321 			                                        &idx_value,
322 			                                        &get,
323 			                                        &set);
324 
325 			/* [ hobject props enum(props) key desc value? getter? setter? ] */
326 
327 			if (pass == 0) {
328 				continue;
329 			}
330 
331 			key = duk_get_hstring(ctx, 3);
332 			DUK_ASSERT(key != NULL);
333 
334 			duk_hobject_define_property_helper(ctx,
335 			                                   defprop_flags,
336 			                                   obj,
337 			                                   key,
338 			                                   idx_value,
339 			                                   get,
340 			                                   set);
341 		}
342 	}
343 
344 	/*
345 	 *  Return target object
346 	 */
347 
348 	duk_dup(ctx, 0);
349 	return 1;
350 }
351 
duk_bi_object_constructor_seal_freeze_shared(duk_context * ctx)352 DUK_INTERNAL duk_ret_t duk_bi_object_constructor_seal_freeze_shared(duk_context *ctx) {
353 	duk_hthread *thr = (duk_hthread *) ctx;
354 	duk_hobject *h;
355 	duk_bool_t is_freeze;
356 
357 	h = duk_require_hobject_or_lfunc(ctx, 0);
358 	if (!h) {
359 		/* Lightfunc, always success. */
360 		return 1;
361 	}
362 
363 	is_freeze = (duk_bool_t) duk_get_current_magic(ctx);
364 	duk_hobject_object_seal_freeze_helper(thr, h, is_freeze);
365 
366 	/* Sealed and frozen objects cannot gain any more properties,
367 	 * so this is a good time to compact them.
368 	 */
369 	duk_hobject_compact_props(thr, h);
370 
371 	return 1;
372 }
373 
duk_bi_object_constructor_prevent_extensions(duk_context * ctx)374 DUK_INTERNAL duk_ret_t duk_bi_object_constructor_prevent_extensions(duk_context *ctx) {
375 	duk_hthread *thr = (duk_hthread *) ctx;
376 	duk_hobject *h;
377 
378 	h = duk_require_hobject_or_lfunc(ctx, 0);
379 	if (!h) {
380 		/* Lightfunc, always success. */
381 		return 1;
382 	}
383 	DUK_ASSERT(h != NULL);
384 
385 	DUK_HOBJECT_CLEAR_EXTENSIBLE(h);
386 
387 	/* A non-extensible object cannot gain any more properties,
388 	 * so this is a good time to compact.
389 	 */
390 	duk_hobject_compact_props(thr, h);
391 
392 	return 1;
393 }
394 
duk_bi_object_constructor_is_sealed_frozen_shared(duk_context * ctx)395 DUK_INTERNAL duk_ret_t duk_bi_object_constructor_is_sealed_frozen_shared(duk_context *ctx) {
396 	duk_hobject *h;
397 	duk_bool_t is_frozen;
398 	duk_bool_t rc;
399 
400 	h = duk_require_hobject_or_lfunc(ctx, 0);
401 	if (!h) {
402 		duk_push_true(ctx);  /* frozen and sealed */
403 	} else {
404 		is_frozen = duk_get_current_magic(ctx);
405 		rc = duk_hobject_object_is_sealed_frozen_helper((duk_hthread *) ctx, h, is_frozen /*is_frozen*/);
406 		duk_push_boolean(ctx, rc);
407 	}
408 	return 1;
409 }
410 
duk_bi_object_constructor_is_extensible(duk_context * ctx)411 DUK_INTERNAL duk_ret_t duk_bi_object_constructor_is_extensible(duk_context *ctx) {
412 	duk_hobject *h;
413 
414 	h = duk_require_hobject_or_lfunc(ctx, 0);
415 	if (!h) {
416 		duk_push_false(ctx);
417 	} else {
418 		duk_push_boolean(ctx, DUK_HOBJECT_HAS_EXTENSIBLE(h));
419 	}
420 	return 1;
421 }
422 
423 /* Shared helper for Object.getOwnPropertyNames() and Object.keys().
424  * Magic: 0=getOwnPropertyNames, 1=Object.keys.
425  */
duk_bi_object_constructor_keys_shared(duk_context * ctx)426 DUK_INTERNAL duk_ret_t duk_bi_object_constructor_keys_shared(duk_context *ctx) {
427 	duk_hthread *thr = (duk_hthread *) ctx;
428 	duk_hobject *obj;
429 #if defined(DUK_USE_ES6_PROXY)
430 	duk_hobject *h_proxy_target;
431 	duk_hobject *h_proxy_handler;
432 	duk_hobject *h_trap_result;
433 	duk_uarridx_t i, len, idx;
434 #endif
435 	duk_small_uint_t enum_flags;
436 
437 	DUK_ASSERT_TOP(ctx, 1);
438 	DUK_UNREF(thr);
439 
440 	obj = duk_require_hobject_or_lfunc_coerce(ctx, 0);
441 	DUK_ASSERT(obj != NULL);
442 	DUK_UNREF(obj);
443 
444 #if defined(DUK_USE_ES6_PROXY)
445 	if (DUK_LIKELY(!duk_hobject_proxy_check(thr,
446 	                                        obj,
447 	                                        &h_proxy_target,
448 	                                        &h_proxy_handler))) {
449 		goto skip_proxy;
450 	}
451 
452 	duk_push_hobject(ctx, h_proxy_handler);
453 	if (!duk_get_prop_stridx(ctx, -1, DUK_STRIDX_OWN_KEYS)) {
454 		/* Careful with reachability here: don't pop 'obj' before pushing
455 		 * proxy target.
456 		 */
457 		DUK_DDD(DUK_DDDPRINT("no ownKeys trap, get keys of target instead"));
458 		duk_pop_2(ctx);
459 		duk_push_hobject(ctx, h_proxy_target);
460 		duk_replace(ctx, 0);
461 		DUK_ASSERT_TOP(ctx, 1);
462 		goto skip_proxy;
463 	}
464 
465 	/* [ obj handler trap ] */
466 	duk_insert(ctx, -2);
467 	duk_push_hobject(ctx, h_proxy_target);  /* -> [ obj trap handler target ] */
468 	duk_call_method(ctx, 1 /*nargs*/);      /* -> [ obj trap_result ] */
469 	h_trap_result = duk_require_hobject(ctx, -1);
470 	DUK_UNREF(h_trap_result);
471 
472 	len = (duk_uarridx_t) duk_get_length(ctx, -1);
473 	idx = 0;
474 	duk_push_array(ctx);
475 	for (i = 0; i < len; i++) {
476 		/* [ obj trap_result res_arr ] */
477 		if (duk_get_prop_index(ctx, -2, i) && duk_is_string(ctx, -1)) {
478 			/* XXX: for Object.keys() we should check enumerability of key */
479 			/* [ obj trap_result res_arr propname ] */
480 			duk_put_prop_index(ctx, -2, idx);
481 			idx++;
482 		} else {
483 			duk_pop(ctx);
484 		}
485 	}
486 
487 	/* XXX: missing trap result validation for non-configurable target keys
488 	 * (must be present), for non-extensible target all target keys must be
489 	 * present and no extra keys can be present.
490 	 * http://www.ecma-international.org/ecma-262/6.0/#sec-proxy-object-internal-methods-and-internal-slots-ownpropertykeys
491 	 */
492 
493 	/* XXX: for Object.keys() the [[OwnPropertyKeys]] result (trap result)
494 	 * should be filtered so that only enumerable keys remain.  Enumerability
495 	 * should be checked with [[GetOwnProperty]] on the original object
496 	 * (i.e., the proxy in this case).  If the proxy has a getOwnPropertyDescriptor
497 	 * trap, it should be triggered for every property.  If the proxy doesn't have
498 	 * the trap, enumerability should be checked against the target object instead.
499 	 * We don't do any of this now, so Object.keys() and Object.getOwnPropertyNames()
500 	 * return the same result now for proxy traps.  We still do clean up the trap
501 	 * result, so that Object.keys() and Object.getOwnPropertyNames() will return a
502 	 * clean array of strings without gaps.
503 	 */
504 	return 1;
505 
506  skip_proxy:
507 #endif  /* DUK_USE_ES6_PROXY */
508 
509 	DUK_ASSERT_TOP(ctx, 1);
510 
511 	if (duk_get_current_magic(ctx)) {
512 		/* Object.keys */
513 		enum_flags = DUK_ENUM_OWN_PROPERTIES_ONLY |
514 		             DUK_ENUM_NO_PROXY_BEHAVIOR;
515 	} else {
516 		/* Object.getOwnPropertyNames */
517 		enum_flags = DUK_ENUM_INCLUDE_NONENUMERABLE |
518 		             DUK_ENUM_OWN_PROPERTIES_ONLY |
519 		             DUK_ENUM_NO_PROXY_BEHAVIOR;
520 	}
521 
522 	return duk_hobject_get_enumerated_keys(ctx, enum_flags);
523 }
524 
duk_bi_object_prototype_to_string(duk_context * ctx)525 DUK_INTERNAL duk_ret_t duk_bi_object_prototype_to_string(duk_context *ctx) {
526 	duk_push_this(ctx);
527 	duk_to_object_class_string_top(ctx);
528 	return 1;
529 }
530 
duk_bi_object_prototype_to_locale_string(duk_context * ctx)531 DUK_INTERNAL duk_ret_t duk_bi_object_prototype_to_locale_string(duk_context *ctx) {
532 	DUK_ASSERT_TOP(ctx, 0);
533 	(void) duk_push_this_coercible_to_object(ctx);
534 	duk_get_prop_stridx(ctx, 0, DUK_STRIDX_TO_STRING);
535 	if (!duk_is_callable(ctx, 1)) {
536 		return DUK_RET_TYPE_ERROR;
537 	}
538 	duk_dup(ctx, 0);  /* -> [ O toString O ] */
539 	duk_call_method(ctx, 0);  /* XXX: call method tail call? */
540 	return 1;
541 }
542 
duk_bi_object_prototype_value_of(duk_context * ctx)543 DUK_INTERNAL duk_ret_t duk_bi_object_prototype_value_of(duk_context *ctx) {
544 	(void) duk_push_this_coercible_to_object(ctx);
545 	return 1;
546 }
547 
duk_bi_object_prototype_is_prototype_of(duk_context * ctx)548 DUK_INTERNAL duk_ret_t duk_bi_object_prototype_is_prototype_of(duk_context *ctx) {
549 	duk_hthread *thr = (duk_hthread *) ctx;
550 	duk_hobject *h_v;
551 	duk_hobject *h_obj;
552 
553 	DUK_ASSERT_TOP(ctx, 1);
554 
555 	h_v = duk_get_hobject(ctx, 0);
556 	if (!h_v) {
557 		duk_push_false(ctx);  /* XXX: tail call: return duk_push_false(ctx) */
558 		return 1;
559 	}
560 
561 	h_obj = duk_push_this_coercible_to_object(ctx);
562 	DUK_ASSERT(h_obj != NULL);
563 
564 	/* E5.1 Section 15.2.4.6, step 3.a, lookup proto once before compare.
565 	 * Prototype loops should cause an error to be thrown.
566 	 */
567 	duk_push_boolean(ctx, duk_hobject_prototype_chain_contains(thr, DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_v), h_obj, 0 /*ignore_loop*/));
568 	return 1;
569 }
570 
duk_bi_object_prototype_has_own_property(duk_context * ctx)571 DUK_INTERNAL duk_ret_t duk_bi_object_prototype_has_own_property(duk_context *ctx) {
572 	return duk_hobject_object_ownprop_helper(ctx, 0 /*required_desc_flags*/);
573 }
574 
duk_bi_object_prototype_property_is_enumerable(duk_context * ctx)575 DUK_INTERNAL duk_ret_t duk_bi_object_prototype_property_is_enumerable(duk_context *ctx) {
576 	return duk_hobject_object_ownprop_helper(ctx, DUK_PROPDESC_FLAG_ENUMERABLE /*required_desc_flags*/);
577 }
578