Skip to content

Commit

Permalink
Proxy property descriptor trap work
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
svaarala committed Jun 15, 2017
1 parent 3f3a93c commit ce40e69
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 9 deletions.
2 changes: 1 addition & 1 deletion src-input/duk_bi_object.c
Original file line number Diff line number Diff line change
Expand Up @@ -743,7 +743,7 @@ DUK_INTERNAL duk_ret_t duk_bi_object_constructor_keys_shared(duk_context *ctx) {
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(ctx, h_proxy_target, enum_flags);
duk_proxy_ownkeys_postprocess(ctx, (duk_hproxy *) obj, enum_flags);
return 1;

skip_proxy:
Expand Down
2 changes: 1 addition & 1 deletion src-input/duk_bi_protos.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ void duk_bi_json_stringify_helper(duk_context *ctx,
DUK_INTERNAL_DECL duk_ret_t duk_textdecoder_decode_utf8_nodejs(duk_context *ctx);

#if defined(DUK_USE_ES6_PROXY)
DUK_INTERNAL_DECL void duk_proxy_ownkeys_postprocess(duk_context *ctx, duk_hobject *h_proxy_target, duk_uint_t flags);
DUK_INTERNAL_DECL void duk_proxy_ownkeys_postprocess(duk_context *ctx, duk_hproxy *h_proxy, duk_uint_t flags);
#endif

#endif /* DUK_BUILTIN_PROTOS_H_INCLUDED */
14 changes: 8 additions & 6 deletions src-input/duk_bi_proxy.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@
* 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_context *ctx, duk_hobject *h_proxy_target, duk_uint_t flags) {
DUK_INTERNAL void duk_proxy_ownkeys_postprocess(duk_context *ctx, duk_hproxy *h_proxy, duk_uint_t flags) {
duk_hthread *thr = (duk_hthread *) ctx;
duk_uarridx_t i, len, idx;
duk_propdesc desc;

DUK_ASSERT_CTX_VALID(ctx);
DUK_ASSERT(h_proxy_target != NULL);
DUK_ASSERT(h_proxy != NULL);

len = (duk_uarridx_t) duk_get_length(ctx, -1);
idx = 0;
Expand All @@ -32,11 +32,13 @@ DUK_INTERNAL void duk_proxy_ownkeys_postprocess(duk_context *ctx, 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(ctx, -1), &desc, 0 /*flags*/)) {
if (duk_hobject_get_own_propdesc(thr, (duk_hobject *) h_proxy, duk_known_hstring(ctx, -1), &desc, 0 /*flags*/)) {
if ((desc.flags & DUK_PROPDESC_FLAG_ENUMERABLE) == 0) {
DUK_DDD(DUK_DDDPRINT("ignore non-enumerable property: %!T", duk_get_tval(ctx, -1)));
goto skip_key;
Expand Down
2 changes: 1 addition & 1 deletion src-input/duk_hobject_enum.c
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ DUK_INTERNAL void duk_hobject_enumerator_create(duk_context *ctx, duk_small_uint
h_trap_result = duk_require_hobject(ctx, -1);
DUK_UNREF(h_trap_result);

duk_proxy_ownkeys_postprocess(ctx, h_proxy_target, enum_flags);
duk_proxy_ownkeys_postprocess(ctx, (duk_hproxy *) enum_target, enum_flags);
/* -> [ ... enum_target res trap_result keys_array ] */

/* Copy cleaned up trap result keys into the enumerator object. */
Expand Down
71 changes: 71 additions & 0 deletions src-input/duk_hobject_props.c
Original file line number Diff line number Diff line change
Expand Up @@ -1633,6 +1633,56 @@ DUK_LOCAL duk_bool_t duk__get_own_propdesc_raw(duk_hthread *thr, duk_hobject *ob
out_desc->h_idx = -1;
out_desc->a_idx = -1;

/* 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(ctx, h_target); /* target */
duk_push_hstring(ctx, key); /* P */
duk_call_method(ctx, 2 /*nargs*/);

/* 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 */

if (duk_get_prop_stridx_boolean(ctx, -1, DUK_STRIDX_WRITABLE, NULL)) {
out_desc->flags |= DUK_PROPDESC_FLAG_WRITABLE;
}
if (duk_get_prop_stridx_boolean(ctx, -1, DUK_STRIDX_ENUMERABLE, NULL)) {
out_desc->flags |= DUK_PROPDESC_FLAG_ENUMERABLE;
}
if (duk_get_prop_stridx_boolean(ctx, -1, DUK_STRIDX_CONFIGURABLE, NULL)) {
out_desc->flags |= DUK_PROPDESC_FLAG_ENUMERABLE;
}
out_desc->flags |= DUK_PROPDESC_FLAG_VIRTUAL;

if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
duk_get_prop_stridx(ctx, -1, DUK_STRIDX_VALUE);
duk_remove_m2(ctx);
} else {
duk_pop(ctx);
}

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 */

/*
* Array part
*/
Expand Down Expand Up @@ -3768,6 +3818,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
Expand Down Expand Up @@ -4871,6 +4922,7 @@ void duk_hobject_prepare_property_descriptor(duk_context *ctx,
idx_value = duk_get_top_index(ctx);
}

/* FIXME: some overlap here */
if (duk_get_prop_stridx(ctx, idx_in, DUK_STRIDX_WRITABLE)) {
is_data_desc = 1;
if (duk_to_boolean(ctx, -1)) {
Expand Down Expand Up @@ -5014,6 +5066,10 @@ duk_bool_t duk_hobject_define_property_helper(duk_context *ctx,

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);
Expand Down Expand Up @@ -5049,6 +5105,21 @@ duk_bool_t duk_hobject_define_property_helper(duk_context *ctx,
(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
Expand Down

0 comments on commit ce40e69

Please sign in to comment.