Browse Source

Proxy property descriptor trap work

Very minimal implementations:

* getOwnPropertyDescriptor trap: works enough to support virtualization
  of enumeration, but doesn't provide 'value', 'get', or 'set'.

* defineProperty: just pass-through so far, no actual trap implementation.
pull/1567/head
Sami Vaarala 8 years ago
parent
commit
c115f75b03
  1. 2
      src-input/duk_bi_object.c
  2. 2
      src-input/duk_bi_protos.h
  3. 16
      src-input/duk_bi_proxy.c
  4. 4
      src-input/duk_hobject.h
  5. 3
      src-input/duk_hobject_enum.c
  6. 83
      src-input/duk_hobject_props.c

2
src-input/duk_bi_object.c

@ -690,7 +690,7 @@ DUK_INTERNAL duk_ret_t duk_bi_object_constructor_keys_shared(duk_hthread *thr) {
DUK_ASSERT(magic >= 0 && magic < (duk_int_t) (sizeof(duk__object_keys_enum_flags) / sizeof(duk_small_uint_t)));
enum_flags = duk__object_keys_enum_flags[magic];
duk_proxy_ownkeys_postprocess(thr, h_proxy_target, enum_flags);
duk_proxy_ownkeys_postprocess(thr, (duk_hproxy *) obj, enum_flags);
return 1;
skip_proxy:

2
src-input/duk_bi_protos.h

@ -75,7 +75,7 @@ void duk_bi_json_stringify_helper(duk_hthread *thr,
DUK_INTERNAL_DECL duk_ret_t duk_textdecoder_decode_utf8_nodejs(duk_hthread *thr);
#if defined(DUK_USE_ES6_PROXY)
DUK_INTERNAL_DECL void duk_proxy_ownkeys_postprocess(duk_hthread *thr, duk_hobject *h_proxy_target, duk_uint_t flags);
DUK_INTERNAL_DECL void duk_proxy_ownkeys_postprocess(duk_hthread *thr, duk_hproxy *h_proxy, duk_uint_t flags);
#endif
#endif /* DUK_BUILTIN_PROTOS_H_INCLUDED */

16
src-input/duk_bi_proxy.c

@ -9,12 +9,12 @@
* array of valid result keys (strings or symbols). TypeError for invalid
* values. Flags are shared with duk_enum().
*/
DUK_INTERNAL void duk_proxy_ownkeys_postprocess(duk_hthread *thr, duk_hobject *h_proxy_target, duk_uint_t flags) {
DUK_INTERNAL void duk_proxy_ownkeys_postprocess(duk_hthread *thr, duk_hproxy *h_proxy, duk_uint_t flags) {
duk_uarridx_t i, len, idx;
duk_propdesc desc;
DUK_ASSERT_CTX_VALID(thr);
DUK_ASSERT(h_proxy_target != NULL);
DUK_ASSERT_CTX_VALID(ctx);
DUK_ASSERT(h_proxy != NULL);
len = (duk_uarridx_t) duk_get_length(thr, -1);
idx = 0;
@ -32,11 +32,13 @@ DUK_INTERNAL void duk_proxy_ownkeys_postprocess(duk_hthread *thr, duk_hobject *h
}
if (!(flags & DUK_ENUM_INCLUDE_NONENUMERABLE)) {
/* No support for 'getOwnPropertyDescriptor' trap yet,
* so check enumerability always from target object
* descriptor.
/* Check enumerability from Proxy so that a possible
* getOwnPropertyDescriptor trap can be invoked. It
* would be tempting to cache the trap function but
* it may be removed as a side effect of a previous
* call so we must look it up every time.
*/
if (duk_hobject_get_own_propdesc(thr, h_proxy_target, duk_known_hstring(thr, -1), &desc, 0 /*flags*/)) {
if (duk_hobject_get_own_propdesc(thr, (duk_hobject *) h_proxy, duk_known_hstring(thr, -1), &desc, 0 /*flags*/)) {
if ((desc.flags & DUK_PROPDESC_FLAG_ENUMERABLE) == 0) {
DUK_DDD(DUK_DDDPRINT("ignore non-enumerable property: %!T", duk_get_tval(thr, -1)));
goto skip_key;

4
src-input/duk_hobject.h

@ -748,8 +748,8 @@ union duk_propvalue {
struct duk_propdesc {
/* read-only values 'lifted' for ease of use */
duk_small_uint_t flags;
duk_hobject *get;
duk_hobject *set;
duk_hobject *get; /* borrowed */
duk_hobject *set; /* borrowed */
/* for updating (all are set to < 0 for virtual properties) */
duk_int_t e_idx; /* prop index in 'entry part', < 0 if not there */

3
src-input/duk_hobject_enum.c

@ -268,7 +268,8 @@ DUK_INTERNAL void duk_hobject_enumerator_create(duk_hthread *thr, duk_small_uint
h_trap_result = duk_require_hobject(thr, -1);
DUK_UNREF(h_trap_result);
duk_proxy_ownkeys_postprocess(thr, h_proxy_target, enum_flags);
/* FIXME: enum_target vs. h_proxy_target? */
duk_proxy_ownkeys_postprocess(thr, (duk_hproxy *) enum_target, enum_flags);
/* -> [ ... enum_target res trap_result keys_array ] */
/* Copy cleaned up trap result keys into the enumerator object. */

83
src-input/duk_hobject_props.c

@ -1595,6 +1595,8 @@ DUK_LOCAL void duk__check_arguments_map_for_delete(duk_hthread *thr, duk_hobject
DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
/* FIXME: find_existing_entry, removes propdesc usage */
if (!duk_hobject_get_own_propdesc(thr, obj, DUK_HTHREAD_STRING_INT_MAP(thr), temp_desc, DUK_GETDESC_FLAG_PUSH_VALUE)) {
DUK_DDD(DUK_DDDPRINT("arguments: key not mapped, no exotic delete behavior"));
return;
@ -1686,6 +1688,66 @@ DUK_LOCAL duk_bool_t duk__get_own_propdesc_raw(duk_hthread *thr, duk_hobject *ob
out_desc->a_idx = -1;
#endif
/* FIXME: property descriptor helpers would need to be reworked
* so that both object and duk_propdesc outputs are supported.
*/
#if defined(DUK_USE_ES6_PROXY)
if (DUK_UNLIKELY(DUK_HOBJECT_IS_PROXY(obj))) {
duk_hproxy *h_proxy;
duk_hobject *h_target;
duk_tval tv_key;
DUK_TVAL_SET_STRING(&tv_key, key);
if (duk__proxy_check_prop(thr, obj, DUK_STRIDX_GET_OWN_PROPERTY_DESCRIPTOR, &tv_key, &h_target)) {
duk_push_hobject(thr, h_target); /* target */
duk_push_hstring(thr, key); /* P */
duk_call_method(thr, 2 /*nargs*/);
/* XXX: At present out_desc->{get,set} are borrowed so they're
* provided as NULL even when the descriptor has them.
*/
/* FIXME: validate descriptor, convert it to internal form.
* At present out_desc->get etc are borrowed so value, get,
* set must be scrubbed, leaving only attributes behind which
* is fine for now.
*/
/* FIXME: arguments special */
out_desc->get = NULL;
out_desc->set = NULL;
out_desc->e_idx = -1;
out_desc->h_idx = -1;
out_desc->a_idx = -1;
out_desc->flags = 0;
if (duk_get_prop_stridx_boolean(thr, -1, DUK_STRIDX_WRITABLE, NULL)) {
out_desc->flags |= DUK_PROPDESC_FLAG_WRITABLE;
}
if (duk_get_prop_stridx_boolean(thr, -1, DUK_STRIDX_ENUMERABLE, NULL)) {
out_desc->flags |= DUK_PROPDESC_FLAG_ENUMERABLE;
}
if (duk_get_prop_stridx_boolean(thr, -1, DUK_STRIDX_CONFIGURABLE, NULL)) {
out_desc->flags |= DUK_PROPDESC_FLAG_CONFIGURABLE;
}
out_desc->flags |= DUK_PROPDESC_FLAG_VIRTUAL;
if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
duk_get_prop_stridx(thr, -1, DUK_STRIDX_VALUE);
duk_remove_m2(thr);
} else {
duk_pop(thr);
}
return 1;
}
DUK_D(DUK_DPRINT("getting own property descriptor for Proxy"));
h_proxy = (duk_hproxy *) obj;
DUK_ASSERT(h_proxy->target != NULL);
obj = h_proxy->target;
}
#endif /* DUK_USE_ES6_PROXY */
/*
* Try entries part first because it's the common case.
*
@ -3870,6 +3932,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
goto fail_not_writable;
}
#endif
/* FIXME: add explicit virtual property safety check */
/* Although there are writable virtual properties (e.g. plain buffer
* and buffer object number indices), they are handled before we come
@ -4974,6 +5037,7 @@ void duk_hobject_prepare_property_descriptor(duk_hthread *thr,
idx_value = duk_get_top_index(thr);
}
/* FIXME: some overlap here */
if (duk_get_prop_stridx(thr, idx_in, DUK_STRIDX_WRITABLE)) {
is_data_desc = 1;
if (duk_to_boolean(thr, -1)) {
@ -5116,6 +5180,10 @@ duk_bool_t duk_hobject_define_property_helper(duk_hthread *thr,
DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
/* FIXME: maybe add defineProperty trap at the same time, so that only
* non-Proxy objects come here?
*/
/* All the flags fit in 16 bits, so will fit into duk_bool_t. */
has_writable = (defprop_flags & DUK_DEFPROP_HAVE_WRITABLE);
@ -5151,6 +5219,21 @@ duk_bool_t duk_hobject_define_property_helper(duk_hthread *thr,
(long) has_set, (void *) set, (duk_heaphdr *) set,
(long) arr_idx, (long) throw_flag));
/*
* Proxy objects.
*/
#if defined(DUK_USE_ES6_PROXY)
if (DUK_UNLIKELY(DUK_HOBJECT_IS_PROXY(obj))) {
duk_hproxy *h_proxy;
h_proxy = (duk_hproxy *) obj;
obj = h_proxy->target;
DUK_ASSERT(obj != NULL);
DUK_ASSERT(!DUK_HOBJECT_IS_PROXY(obj));
}
#endif /* DUK_USE_ES6_PROXY */
/*
* Array exotic behaviors can be implemented at this point. The local variables
* are essentially a 'value copy' of the input descriptor (Desc), which is modified

Loading…
Cancel
Save