Exemplo n.º 1
0
DUK_INTERNAL duk_ret_t duk_bi_proxy_constructor(duk_context *ctx) {
	duk_hobject *h_target;
	duk_hobject *h_handler;

	if (!duk_is_constructor_call(ctx)) {
		return DUK_RET_TYPE_ERROR;
	}

	/* Reject a proxy object as the target because it would need
	 * special handler in property lookups.  (ES6 has no such restriction)
	 */
	h_target = duk_require_hobject_or_lfunc_coerce(ctx, 0);
	DUK_ASSERT(h_target != NULL);
	if (DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(h_target)) {
		return DUK_RET_TYPE_ERROR;
	}

	/* Reject a proxy object as the handler because it would cause
	 * potentially unbounded recursion.  (ES6 has no such restriction)
	 */
	h_handler = duk_require_hobject_or_lfunc_coerce(ctx, 1);
	DUK_ASSERT(h_handler != NULL);
	if (DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(h_handler)) {
		return DUK_RET_TYPE_ERROR;
	}

	/* XXX: the returned value is exotic in ES6, but we use a
	 * simple object here with no prototype.  Without a prototype,
	 * [[DefaultValue]] coercion fails which is abit confusing.
	 * No callable check/handling in the current Proxy subset.
	 */
	(void) duk_push_object_helper_proto(ctx,
	                                    DUK_HOBJECT_FLAG_EXTENSIBLE |
	                                    DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ |
	                                    DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
	                                    NULL);
	DUK_ASSERT_TOP(ctx, 3);

	/* Make _Target and _Handler non-configurable and non-writable.
	 * They can still be forcibly changed by C code (both user and
	 * Duktape internal), but not by Ecmascript code.
	 */

	/* Proxy target */
	duk_dup(ctx, 0);
	duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE);

	/* Proxy handler */
	duk_dup(ctx, 1);
	duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_HANDLER, DUK_PROPDESC_FLAGS_NONE);

	return 1;  /* replacement handler */
}
Exemplo n.º 2
0
DUK_EXTERNAL void duk_enum(duk_context *ctx, duk_idx_t obj_index, duk_uint_t enum_flags) {
	DUK_ASSERT_CTX_VALID(ctx);

	duk_dup(ctx, obj_index);
	duk_require_hobject_or_lfunc_coerce(ctx, -1);
	duk_hobject_enumerator_create(ctx, enum_flags);   /* [target] -> [enum] */
}
Exemplo n.º 3
0
DUK_INTERNAL duk_ret_t duk_bi_error_prototype_to_string(duk_context *ctx) {
	/* XXX: optimize with more direct internal access */

	duk_push_this(ctx);
	(void) duk_require_hobject_or_lfunc_coerce(ctx, -1);

	/* [ ... this ] */

	duk_get_prop_stridx(ctx, -1, DUK_STRIDX_NAME);
	if (duk_is_undefined(ctx, -1)) {
		duk_pop(ctx);
		duk_push_string(ctx, "Error");
	} else {
		duk_to_string(ctx, -1);
	}

	/* [ ... this name ] */

	/* XXX: Are steps 6 and 7 in E5 Section 15.11.4.4 duplicated by
	 * accident or are they actually needed?  The first ToString()
	 * could conceivably return 'undefined'.
	 */
	duk_get_prop_stridx(ctx, -2, DUK_STRIDX_MESSAGE);
	if (duk_is_undefined(ctx, -1)) {
		duk_pop(ctx);
		duk_push_string(ctx, "");
	} else {
		duk_to_string(ctx, -1);
	}

	/* [ ... this name message ] */

	if (duk_get_length(ctx, -2) == 0) {
		/* name is empty -> return message */
		return 1;
	}
	if (duk_get_length(ctx, -1) == 0) {
		/* message is empty -> return name */
		duk_pop(ctx);
		return 1;
	}
	duk_push_string(ctx, ": ");
	duk_insert(ctx, -2);  /* ... name ': ' message */
	duk_concat(ctx, 3);

	return 1;
}
Exemplo n.º 4
0
/* Shared helper for Object.getOwnPropertyNames() and Object.keys().
 * Magic: 0=getOwnPropertyNames, 1=Object.keys.
 */
DUK_INTERNAL duk_ret_t duk_bi_object_constructor_keys_shared(duk_context *ctx) {
	duk_hthread *thr = (duk_hthread *) ctx;
	duk_hobject *obj;
#if defined(DUK_USE_ES6_PROXY)
	duk_hobject *h_proxy_target;
	duk_hobject *h_proxy_handler;
	duk_hobject *h_trap_result;
	duk_uarridx_t i, len, idx;
#endif
	duk_small_uint_t enum_flags;

	DUK_ASSERT_TOP(ctx, 1);

	obj = duk_require_hobject_or_lfunc_coerce(ctx, 0);
	DUK_ASSERT(obj != NULL);
	DUK_UNREF(obj);

#if defined(DUK_USE_ES6_PROXY)
	if (DUK_LIKELY(!duk_hobject_proxy_check(thr,
	                                        obj,
	                                        &h_proxy_target,
	                                        &h_proxy_handler))) {
		goto skip_proxy;
	}

	duk_push_hobject(ctx, h_proxy_handler);
	if (!duk_get_prop_stridx(ctx, -1, DUK_STRIDX_OWN_KEYS)) {
		/* Careful with reachability here: don't pop 'obj' before pushing
		 * proxy target.
		 */
		DUK_DDD(DUK_DDDPRINT("no ownKeys trap, get keys of target instead"));
		duk_pop_2(ctx);
		duk_push_hobject(ctx, h_proxy_target);
		duk_replace(ctx, 0);
		DUK_ASSERT_TOP(ctx, 1);
		goto skip_proxy;
	}

	/* [ obj handler trap ] */
	duk_insert(ctx, -2);
	duk_push_hobject(ctx, h_proxy_target);  /* -> [ obj trap handler target ] */
	duk_call_method(ctx, 1 /*nargs*/);      /* -> [ obj trap_result ] */
	h_trap_result = duk_require_hobject(ctx, -1);
	DUK_UNREF(h_trap_result);

	len = (duk_uarridx_t) duk_get_length(ctx, -1);
	idx = 0;
	duk_push_array(ctx);
	for (i = 0; i < len; i++) {
		/* [ obj trap_result res_arr ] */
		if (duk_get_prop_index(ctx, -2, i) && duk_is_string(ctx, -1)) {
			/* XXX: for Object.keys() we should check enumerability of key */
			/* [ obj trap_result res_arr propname ] */
			duk_put_prop_index(ctx, -2, idx);
			idx++;
		} else {
			duk_pop(ctx);
		}
	}

	/* XXX: for Object.keys() the [[OwnPropertyKeys]] result (trap result)
	 * should be filtered so that only enumerable keys remain.  Enumerability
	 * should be checked with [[GetOwnProperty]] on the original object
	 * (i.e., the proxy in this case).  If the proxy has a getOwnPropertyDescriptor
	 * trap, it should be triggered for every property.  If the proxy doesn't have
	 * the trap, enumerability should be checked against the target object instead.
	 * We don't do any of this now, so Object.keys() and Object.getOwnPropertyNames()
	 * return the same result now for proxy traps.  We still do clean up the trap
	 * result, so that Object.keys() and Object.getOwnPropertyNames() will return a
	 * clean array of strings without gaps.
	 */
	return 1;

 skip_proxy:
#endif  /* DUK_USE_ES6_PROXY */

	DUK_ASSERT_TOP(ctx, 1);

	if (duk_get_current_magic(ctx)) {
		/* Object.keys */
		enum_flags = DUK_ENUM_OWN_PROPERTIES_ONLY |
		             DUK_ENUM_NO_PROXY_BEHAVIOR;
	} else {
		/* Object.getOwnPropertyNames */
		enum_flags = DUK_ENUM_INCLUDE_NONENUMERABLE |
		             DUK_ENUM_OWN_PROPERTIES_ONLY |
		             DUK_ENUM_NO_PROXY_BEHAVIOR;
	}

	return duk_hobject_get_enumerated_keys(ctx, enum_flags);
}
Exemplo n.º 5
0
DUK_INTERNAL duk_ret_t duk_bi_object_constructor_define_properties(duk_context *ctx) {
	duk_small_uint_t pass;
	duk_uint_t defprop_flags;
	duk_hobject *obj;
	duk_idx_t idx_value;
	duk_hobject *get;
	duk_hobject *set;

	/* Lightfunc handling by ToObject() coercion. */
	obj = duk_require_hobject_or_lfunc_coerce(ctx, 0);  /* target */
	DUK_ASSERT(obj != NULL);

	duk_to_object(ctx, 1);        /* properties object */

	DUK_DDD(DUK_DDDPRINT("target=%!iT, properties=%!iT",
	                     (duk_tval *) duk_get_tval(ctx, 0),
	                     (duk_tval *) duk_get_tval(ctx, 1)));

	/*
	 *  Two pass approach to processing the property descriptors.
	 *  On first pass validate and normalize all descriptors before
	 *  any changes are made to the target object.  On second pass
	 *  make the actual modifications to the target object.
	 *
	 *  Right now we'll just use the same normalize/validate helper
	 *  on both passes, ignoring its outputs on the first pass.
	 */

	for (pass = 0; pass < 2; pass++) {
		duk_set_top(ctx, 2);  /* -> [ hobject props ] */
		duk_enum(ctx, 1, DUK_ENUM_OWN_PROPERTIES_ONLY /*enum_flags*/);

		for (;;) {
			duk_hstring *key;

			/* [ hobject props enum(props) ] */

			duk_set_top(ctx, 3);

			if (!duk_next(ctx, 2, 1 /*get_value*/)) {
				break;
			}

			DUK_DDD(DUK_DDDPRINT("-> key=%!iT, desc=%!iT",
			                     (duk_tval *) duk_get_tval(ctx, -2),
			                     (duk_tval *) duk_get_tval(ctx, -1)));

			/* [ hobject props enum(props) key desc ] */

			duk_hobject_prepare_property_descriptor(ctx,
			                                        4 /*idx_desc*/,
			                                        &defprop_flags,
			                                        &idx_value,
			                                        &get,
			                                        &set);

			/* [ hobject props enum(props) key desc value? getter? setter? ] */

			if (pass == 0) {
				continue;
			}

			key = duk_get_hstring(ctx, 3);
			DUK_ASSERT(key != NULL);

			duk_hobject_define_property_helper(ctx,
			                                   defprop_flags,
			                                   obj,
			                                   key,
			                                   idx_value,
			                                   get,
			                                   set);
		}
	}

	/*
	 *  Return target object
	 */

	duk_dup(ctx, 0);
	return 1;
}
Exemplo n.º 6
0
DUK_INTERNAL duk_ret_t duk_bi_object_constructor_define_property(duk_context *ctx) {
	duk_hobject *obj;
	duk_hstring *key;
	duk_hobject *get;
	duk_hobject *set;
	duk_idx_t idx_value;
	duk_uint_t defprop_flags;

	DUK_ASSERT(ctx != NULL);

	DUK_DDD(DUK_DDDPRINT("Object.defineProperty(): ctx=%p obj=%!T key=%!T desc=%!T",
	                     (void *) ctx,
	                     (duk_tval *) duk_get_tval(ctx, 0),
	                     (duk_tval *) duk_get_tval(ctx, 1),
	                     (duk_tval *) duk_get_tval(ctx, 2)));

	/* [ obj key desc ] */

	/* Lightfuncs are currently supported by coercing to a temporary
	 * Function object; changes will be allowed (the coerced value is
	 * extensible) but will be lost.
	 */
	obj = duk_require_hobject_or_lfunc_coerce(ctx, 0);
	(void) duk_to_string(ctx, 1);
	key = duk_require_hstring(ctx, 1);
	(void) duk_require_hobject(ctx, 2);

	DUK_ASSERT(obj != NULL);
	DUK_ASSERT(key != NULL);
	DUK_ASSERT(duk_get_hobject(ctx, 2) != NULL);

	/*
	 *  Validate and convert argument property descriptor (an Ecmascript
	 *  object) into a set of defprop_flags and possibly property value,
	 *  getter, and/or setter values on the value stack.
	 *
	 *  Lightfunc set/get values are coerced to full Functions.
	 */

	duk_hobject_prepare_property_descriptor(ctx,
	                                        2 /*idx_desc*/,
	                                        &defprop_flags,
	                                        &idx_value,
	                                        &get,
	                                        &set);

	/*
	 *  Use Object.defineProperty() helper for the actual operation.
	 */

	duk_hobject_define_property_helper(ctx,
	                                   defprop_flags,
	                                   obj,
	                                   key,
	                                   idx_value,
	                                   get,
	                                   set);

	/* Ignore the normalize/validate helper outputs on the value stack,
	 * they're popped automatically.
	 */

	/*
	 *  Return target object.
	 */

	duk_push_hobject(ctx, obj);
	return 1;
}