Browse Source

Merge pull request #1123 from svaarala/api-set-length

Add duk_set_length() to correspond with duk_get_length()
pull/980/head
Sami Vaarala 8 years ago
committed by GitHub
parent
commit
8c4f7a46c6
  1. 3
      RELEASES.rst
  2. 3
      doc/release-notes-v2-0.rst
  3. 3
      src-input/duk_api_internal.h
  4. 1
      src-input/duk_api_public.h.in
  5. 41
      src-input/duk_api_stack.c
  6. 2
      src-input/duk_bi_json.c
  7. 4
      src-input/duk_hobject.h
  8. 29
      src-input/duk_hobject_props.c
  9. 14
      src-input/duk_js_compiler.c
  10. 2
      src-input/duk_js_executor.c
  11. 8
      tests/api/test-get-length.c
  12. 50
      tests/api/test-set-length.c
  13. 5
      website/api/duk_get_length.yaml
  14. 23
      website/api/duk_set_length.yaml

3
RELEASES.rst

@ -1976,6 +1976,9 @@ Planned
* Add duk_inspect_callstack_entry() to provide internal information about a
callstack entry; the output matches Duktape.act() (GH-1128)
* Add duk_set_length() API call and change duk_get_length() limits from
uint32 to size_t supported range (GH-1123)
* Add ability to perform an indirect debugger Eval with non-empty callstack by
sending null for the callstack level (GH-747)

3
doc/release-notes-v2-0.rst

@ -1044,6 +1044,9 @@ Other incompatible changes
previously an error was thrown. This situation never occurs for standard
Ecmascript strings or valid UTF-8 strings.
* ``duk_get_length()`` now allows the ``size_t`` rather than the unsigned 32-bit
integer range for the target value's ``.length``.
* Legacy octal literal handling has been improved to match more closely with
ES6 Annex B. Octal look-alike decimal literals like "0778" and "0778.123"
are now allowed.

3
src-input/duk_api_internal.h

@ -258,9 +258,6 @@ DUK_INTERNAL_DECL void duk_xdef_prop_stridx_builtin(duk_context *ctx, duk_idx_t
DUK_INTERNAL_DECL void duk_xdef_prop_stridx_thrower(duk_context *ctx, duk_idx_t obj_idx, duk_small_uint_t stridx); /* [] -> [] */
/* Set object 'length'. */
DUK_INTERNAL_DECL void duk_set_length(duk_context *ctx, duk_idx_t idx, duk_size_t length);
DUK_INTERNAL_DECL void duk_pack(duk_context *ctx, duk_idx_t count);
#if 0
DUK_INTERNAL_DECL void duk_unpack(duk_context *ctx);

1
src-input/duk_api_public.h.in

@ -642,6 +642,7 @@ DUK_EXTERNAL_DECL duk_c_function duk_get_c_function(duk_context *ctx, duk_idx_t
DUK_EXTERNAL_DECL duk_context *duk_get_context(duk_context *ctx, duk_idx_t idx);
DUK_EXTERNAL_DECL void *duk_get_heapptr(duk_context *ctx, duk_idx_t idx);
DUK_EXTERNAL_DECL duk_size_t duk_get_length(duk_context *ctx, duk_idx_t idx);
DUK_EXTERNAL_DECL void duk_set_length(duk_context *ctx, duk_idx_t idx, duk_size_t len);
/*
* Require operations: no coercion, throw error if index or type

41
src-input/duk_api_stack.c

@ -1827,16 +1827,26 @@ DUK_EXTERNAL duk_size_t duk_get_length(duk_context *ctx, duk_idx_t idx) {
case DUK_TAG_BOOLEAN:
case DUK_TAG_POINTER:
return 0;
#if defined(DUK_USE_PREFER_SIZE)
/* All of these types (besides object) have a virtual, non-configurable
* .length property which is within size_t range so we can just look it
* up without specific type checks.
*/
case DUK_TAG_STRING:
case DUK_TAG_BUFFER:
case DUK_TAG_LIGHTFUNC: {
duk_size_t ret;
duk_get_prop_stridx(ctx, idx, DUK_STRIDX_LENGTH);
ret = (duk_size_t) duk_to_number_m1(ctx);
duk_pop(ctx);
return ret;
}
#else /* DUK_USE_PREFER_SIZE */
case DUK_TAG_STRING: {
duk_hstring *h = DUK_TVAL_GET_STRING(tv);
DUK_ASSERT(h != NULL);
return (duk_size_t) DUK_HSTRING_GET_CHARLEN(h);
}
case DUK_TAG_OBJECT: {
duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
DUK_ASSERT(h != NULL);
return (duk_size_t) duk_hobject_get_length((duk_hthread *) ctx, h);
}
case DUK_TAG_BUFFER: {
duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
DUK_ASSERT(h != NULL);
@ -1847,6 +1857,12 @@ DUK_EXTERNAL duk_size_t duk_get_length(duk_context *ctx, duk_idx_t idx) {
lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv);
return (duk_size_t) DUK_LFUNC_FLAGS_GET_LENGTH(lf_flags);
}
#endif /* DUK_USE_PREFER_SIZE */
case DUK_TAG_OBJECT: {
duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
DUK_ASSERT(h != NULL);
return (duk_size_t) duk_hobject_get_length((duk_hthread *) ctx, h);
}
#if defined(DUK_USE_FASTINT)
case DUK_TAG_FASTINT:
#endif
@ -1859,7 +1875,6 @@ DUK_EXTERNAL duk_size_t duk_get_length(duk_context *ctx, duk_idx_t idx) {
DUK_UNREACHABLE();
}
/*
* duk_known_xxx() helpers
*
@ -1913,18 +1928,12 @@ DUK_INTERNAL duk_hnatfunc *duk_known_hnatfunc(duk_context *ctx, duk_idx_t idx) {
return (duk_hnatfunc *) duk__known_heaphdr(ctx, idx);
}
DUK_INTERNAL void duk_set_length(duk_context *ctx, duk_idx_t idx, duk_size_t length) {
duk_hthread *thr = (duk_hthread *) ctx;
duk_hobject *h;
DUK_EXTERNAL void duk_set_length(duk_context *ctx, duk_idx_t idx, duk_size_t len) {
DUK_ASSERT_CTX_VALID(ctx);
h = duk_get_hobject(ctx, idx);
if (!h) {
return;
}
duk_hobject_set_length(thr, h, (duk_uint32_t) length); /* XXX: typing */
idx = duk_normalize_index(ctx, idx);
duk_push_uint(ctx, (duk_uint_t) len);
duk_put_prop_stridx(ctx, idx, DUK_STRIDX_LENGTH);
}
/*

2
src-input/duk_bi_json.c

@ -2472,7 +2472,7 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du
goto abort_fastpath;
}
arr_len = (duk_uint_fast32_t) duk_hobject_get_length(js_ctx->thr, obj);
arr_len = (duk_uint_fast32_t) ((duk_harray *) obj)->length;
asize = (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(obj);
/* Array part may be larger than 'length'; if so, iterate
* only up to array 'length'. Array part may also be smaller

4
src-input/duk_hobject.h

@ -887,9 +887,7 @@ DUK_INTERNAL_DECL duk_bool_t duk_hobject_delprop_raw(duk_hthread *thr, duk_hobje
DUK_INTERNAL_DECL duk_bool_t duk_hobject_hasprop_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key);
DUK_INTERNAL_DECL void duk_hobject_define_property_internal(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_small_uint_t flags);
DUK_INTERNAL_DECL void duk_hobject_define_property_internal_arridx(duk_hthread *thr, duk_hobject *obj, duk_uarridx_t arr_idx, duk_small_uint_t flags);
DUK_INTERNAL_DECL void duk_hobject_set_length(duk_hthread *thr, duk_hobject *obj, duk_uint32_t length); /* XXX: duk_uarridx_t? */
DUK_INTERNAL_DECL void duk_hobject_set_length_zero(duk_hthread *thr, duk_hobject *obj);
DUK_INTERNAL_DECL duk_uint32_t duk_hobject_get_length(duk_hthread *thr, duk_hobject *obj); /* XXX: duk_uarridx_t? */
DUK_INTERNAL_DECL duk_size_t duk_hobject_get_length(duk_hthread *thr, duk_hobject *obj);
/* helpers for defineProperty() and defineProperties() */
DUK_INTERNAL_DECL

29
src-input/duk_hobject_props.c

@ -4745,26 +4745,7 @@ DUK_INTERNAL void duk_hobject_define_property_internal_arridx(duk_hthread *thr,
* Internal helpers for managing object 'length'
*/
/* XXX: awkward helpers */
DUK_INTERNAL void duk_hobject_set_length(duk_hthread *thr, duk_hobject *obj, duk_uint32_t length) {
duk_context *ctx = (duk_context *) thr;
duk_push_hobject(ctx, obj);
duk_push_hstring_stridx(ctx, DUK_STRIDX_LENGTH);
duk_push_u32(ctx, length);
(void) duk_hobject_putprop(thr,
DUK_GET_TVAL_NEGIDX(ctx, -3),
DUK_GET_TVAL_NEGIDX(ctx, -2),
DUK_GET_TVAL_NEGIDX(ctx, -1),
0);
duk_pop_3(ctx);
}
DUK_INTERNAL void duk_hobject_set_length_zero(duk_hthread *thr, duk_hobject *obj) {
duk_hobject_set_length(thr, obj, 0);
}
DUK_INTERNAL duk_uint32_t duk_hobject_get_length(duk_hthread *thr, duk_hobject *obj) {
DUK_INTERNAL duk_size_t duk_hobject_get_length(duk_hthread *thr, duk_hobject *obj) {
duk_context *ctx = (duk_context *) thr;
duk_double_t val;
@ -4785,9 +4766,11 @@ DUK_INTERNAL duk_uint32_t duk_hobject_get_length(duk_hthread *thr, duk_hobject *
val = duk_to_number_m1(ctx);
duk_pop_3(ctx);
/* XXX: better check */
if (val >= 0.0 && val < DUK_DOUBLE_2TO32) {
return (duk_uint32_t) val;
/* This isn't part of Ecmascript semantics; return a value within
* duk_size_t range, or 0 otherwise.
*/
if (val >= 0.0 && val <= (duk_double_t) DUK_SIZE_MAX) {
return (duk_size_t) val;
}
return 0;
}

14
src-input/duk_js_compiler.c

@ -585,11 +585,11 @@ DUK_LOCAL void duk__reset_func_for_pass2(duk_compiler_ctx *comp_ctx) {
*/
DUK_BW_RESET_SIZE(thr, &func->bw_code);
duk_hobject_set_length_zero(thr, func->h_consts);
duk_set_length(ctx, func->consts_idx, 0);
/* keep func->h_funcs; inner functions are not reparsed to avoid O(depth^2) parsing */
func->fnum_next = 0;
/* duk_hobject_set_length_zero(thr, func->h_funcs); */
duk_hobject_set_length_zero(thr, func->h_labelnames);
/* duk_set_length(ctx, func->funcs_idx, 0); */
duk_set_length(ctx, func->labelnames_idx, 0);
duk_hbuffer_reset(thr, func->h_labelinfos);
/* keep func->h_argnames; it is fixed for all passes */
@ -2760,13 +2760,9 @@ DUK_LOCAL void duk__lookup_active_label(duk_compiler_ctx *comp_ctx, duk_hstring
DUK_LOCAL void duk__reset_labels_to_length(duk_compiler_ctx *comp_ctx, duk_int_t len) {
duk_hthread *thr = comp_ctx->thr;
duk_context *ctx = (duk_context *) thr;
duk_size_t new_size;
/* XXX: duk_set_length */
new_size = sizeof(duk_labelinfo) * (duk_size_t) len;
duk_push_int(ctx, len);
duk_put_prop_stridx(ctx, comp_ctx->curr_func.labelnames_idx, DUK_STRIDX_LENGTH);
duk_hbuffer_resize(thr, comp_ctx->curr_func.h_labelinfos, new_size);
duk_set_length(ctx, comp_ctx->curr_func.labelnames_idx, (duk_size_t) len);
duk_hbuffer_resize(thr, comp_ctx->curr_func.h_labelinfos, sizeof(duk_labelinfo) * (duk_size_t) len);
}
/*

2
src-input/duk_js_executor.c

@ -4787,7 +4787,7 @@ DUK_LOCAL DUK_NOINLINE void duk__js_execute_bytecode_inner(duk_hthread *entry_th
* ToUint32() which is odd but happens now as a side effect of
* 'arr_idx' type.
*/
duk_hobject_set_length(thr, duk_known_hobject(ctx, obj_idx), (duk_uint32_t) arr_idx);
duk_set_length(thr, obj_idx, (duk_size_t) (duk_uarridx_t) arr_idx);
break;
}

8
tests/api/test-get-length.c

@ -59,13 +59,13 @@ void test(duk_context *ctx) {
duk_put_prop_string(ctx, -2, "length");
/* 8 */
duk_push_object(ctx); /* length: outside 32-bit range but within range after ToInteger() */
duk_push_number(ctx, 4294967295.9);
duk_push_object(ctx); /* length: just within 32-bit range */
duk_push_number(ctx, (duk_double_t) 0xffffffffUL);
duk_put_prop_string(ctx, -2, "length");
/* 9 */
duk_push_object(ctx); /* length: outside 32-bit range */
duk_push_number(ctx, 4294967296);
duk_push_object(ctx); /* length: outside size_t range */
duk_push_number(ctx, (duk_double_t) DUK_SIZE_MAX + 1.0);
duk_put_prop_string(ctx, -2, "length");
/* 10 */

50
tests/api/test-set-length.c

@ -0,0 +1,50 @@
/*===
*** test_basic (duk_safe_call)
["foo","bar","quux","bax"]
["foo"]
["foo",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null]
{"foo":123}
{"foo":123,"length":123}
final top: 0
==> rc=0, result='undefined'
===*/
static duk_ret_t test_basic(duk_context *ctx, void *udata) {
(void) udata;
duk_eval_string(ctx, "[ 'foo', 'bar', 'quux', 'bax' ]");
duk_dup(ctx, -1);
printf("%s\n", duk_json_encode(ctx, -1));
duk_pop(ctx);
duk_set_length(ctx, -1, 1);
duk_dup(ctx, -1);
printf("%s\n", duk_json_encode(ctx, -1));
duk_pop(ctx);
duk_set_length(ctx, -1, 100);
duk_dup(ctx, -1);
printf("%s\n", duk_json_encode(ctx, -1));
duk_pop(ctx);
duk_pop(ctx);
duk_eval_string(ctx, "({ foo: 123 })");
duk_dup(ctx, -1);
printf("%s\n", duk_json_encode(ctx, -1));
duk_pop(ctx);
duk_set_length(ctx, -1, 123);
duk_dup(ctx, -1);
printf("%s\n", duk_json_encode(ctx, -1));
duk_pop(ctx);
duk_pop(ctx);
printf("final top: %ld\n", (long) duk_get_top(ctx));
return 0;
}
void test(duk_context *ctx) {
TEST_SAFE_CALL(test_basic);
}

5
website/api/duk_get_length.yaml

@ -11,7 +11,7 @@ summary: |
<ul>
<li>String: character length of string (<i>not</i> byte length)</li>
<li>Object: <code>Math.floor(ToNumber(obj.length))</code> if result within
32-bit unsigned range; otherwise 0</li>
<code>duk_size_t</code> unsigned range; otherwise 0</li>
<li>Buffer: byte length of buffer</li>
<li>Other type or invalid stack index: 0</li>
</ul>
@ -28,4 +28,7 @@ example: |
tags:
- stack
seealso:
- duk_set_length
introduced: 1.0.0

23
website/api/duk_set_length.yaml

@ -0,0 +1,23 @@
name: duk_set_length
proto: |
void duk_set_length(duk_context *ctx, duk_idx_t idx, duk_size_t len);
stack: |
[ ... val! ... ]
summary: |
<p>Set "length" for value at <code>idx</code>. Equivalent to the Ecmascript
statement <code>obj.length = len;</code>.</p>
example: |
/* Set array length to zero, deleting elements as a side effect. */
duk_set_length(ctx, -3, 0);
tags:
- stack
seealso:
- duk_get_length
introduced: 2.0.0
Loading…
Cancel
Save