Browse Source

first draft of buffer virtual length/index property implementation, not as trivial as seems because buffer bytes are the first writable virtual properties

pull/2/head
Sami Vaarala 11 years ago
parent
commit
2fec305179
  1. 18
      src/duk_api.c
  2. 1
      src/duk_bi_buffer.c
  3. 12
      src/duk_hobject.h
  4. 32
      src/duk_hobject_enum.c
  5. 223
      src/duk_hobject_props.c

18
src/duk_api.c

@ -1837,12 +1837,8 @@ void *duk_to_pointer(duk_context *ctx, int index) {
void duk_to_object(duk_context *ctx, int index) {
duk_hthread *thr = (duk_hthread *) ctx;
duk_tval *tv;
duk_hobject *res;
int shared_flags = 0; /* shared flags for a subset of types */
int shared_proto = 0;
int shared_string = 0;
/* FIXME: rework shared_XXX to fit into one reg? */
DUK_ASSERT(ctx != NULL);
@ -1865,9 +1861,9 @@ void duk_to_object(duk_context *ctx, int index) {
}
case DUK_TAG_STRING: {
shared_flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
DUK_HOBJECT_FLAG_SPECIAL_STRINGOBJ |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_STRING);
shared_proto = DUK_BIDX_STRING_PROTOTYPE;
shared_string = 1;
goto create_object;
}
case DUK_TAG_OBJECT: {
@ -1876,6 +1872,7 @@ void duk_to_object(duk_context *ctx, int index) {
}
case DUK_TAG_BUFFER: {
shared_flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
DUK_HOBJECT_FLAG_SPECIAL_BUFFEROBJ |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_BUFFER);
shared_proto = DUK_BIDX_BUFFER_PROTOTYPE;
goto create_object;
@ -1897,22 +1894,17 @@ void duk_to_object(duk_context *ctx, int index) {
create_object:
(void) duk_push_object_helper(ctx, shared_flags, shared_proto);
res = duk_require_hobject(ctx, -1);
DUK_ASSERT(res != NULL);
/* Note: Boolean prototype's internal value property is not writable,
* but duk_def_prop_stridx() disregards the write protection. Boolean
* instances are immutable.
*
* String and buffer special behaviors are already enabled which is not
* ideal, but a write to the internal value is not affected by them.
*/
duk_dup(ctx, index);
duk_def_prop_stridx(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE);
/* FIXME: fix this check to lookup class from shared_flags to minimize size */
if (shared_string) {
/* Enable special string behavior only after internal value has been set */
DUK_HOBJECT_SET_SPECIAL_STRINGOBJ(res);
}
duk_replace(ctx, index);
}

1
src/duk_bi_buffer.c

@ -20,6 +20,7 @@ int duk_bi_buffer_constructor(duk_context *ctx) {
if (duk_is_constructor_call(ctx)) {
duk_push_object_helper(ctx,
DUK_HOBJECT_FLAG_EXTENSIBLE |
DUK_HOBJECT_FLAG_SPECIAL_BUFFEROBJ |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_BUFFER),
DUK_BIDX_BUFFER_PROTOTYPE);

12
src/duk_hobject.h

@ -49,7 +49,7 @@
#define DUK_HOBJECT_FLAG_SPECIAL_STRINGOBJ DUK_HEAPHDR_USER_FLAG(14) /* 'String' object, array index special behavior */
#define DUK_HOBJECT_FLAG_SPECIAL_ARGUMENTS DUK_HEAPHDR_USER_FLAG(15) /* 'Arguments' object and has arguments special behavior (non-strict callee) */
#define DUK_HOBJECT_FLAG_SPECIAL_DUKFUNC DUK_HEAPHDR_USER_FLAG(16) /* Duktape/C (nativefunction) object, special 'length' */
/* bit 17 unused */
#define DUK_HOBJECT_FLAG_SPECIAL_BUFFEROBJ DUK_HEAPHDR_USER_FLAG(17) /* 'Buffer' object, array index special behavior, virtual 'length' */
/* bit 18 unused */
/* bit 19 unused */
/* bit 20 unused */
@ -112,7 +112,8 @@
#define DUK_HOBJECT_SPECIAL_BEHAVIOR_FLAGS (DUK_HOBJECT_FLAG_SPECIAL_ARRAY | \
DUK_HOBJECT_FLAG_SPECIAL_ARGUMENTS | \
DUK_HOBJECT_FLAG_SPECIAL_STRINGOBJ | \
DUK_HOBJECT_FLAG_SPECIAL_DUKFUNC)
DUK_HOBJECT_FLAG_SPECIAL_DUKFUNC | \
DUK_HOBJECT_FLAG_SPECIAL_BUFFEROBJ)
#define DUK_HOBJECT_HAS_SPECIAL_BEHAVIOR(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_SPECIAL_BEHAVIOR_FLAGS)
@ -132,6 +133,7 @@
#define DUK_HOBJECT_HAS_SPECIAL_STRINGOBJ(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_SPECIAL_STRINGOBJ)
#define DUK_HOBJECT_HAS_SPECIAL_ARGUMENTS(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_SPECIAL_ARGUMENTS)
#define DUK_HOBJECT_HAS_SPECIAL_DUKFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_SPECIAL_DUKFUNC)
#define DUK_HOBJECT_HAS_SPECIAL_BUFFEROBJ(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_SPECIAL_BUFFEROBJ)
#define DUK_HOBJECT_SET_EXTENSIBLE(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXTENSIBLE)
#define DUK_HOBJECT_SET_CONSTRUCTABLE(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CONSTRUCTABLE)
@ -149,6 +151,7 @@
#define DUK_HOBJECT_SET_SPECIAL_STRINGOBJ(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_SPECIAL_STRINGOBJ)
#define DUK_HOBJECT_SET_SPECIAL_ARGUMENTS(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_SPECIAL_ARGUMENTS)
#define DUK_HOBJECT_SET_SPECIAL_DUKFUNC(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_SPECIAL_DUKFUNC)
#define DUK_HOBJECT_SET_SPECIAL_BUFFEROBJ(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_SPECIAL_BUFFEROBJ)
#define DUK_HOBJECT_CLEAR_EXTENSIBLE(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXTENSIBLE)
#define DUK_HOBJECT_CLEAR_CONSTRUCTABLE(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CONSTRUCTABLE)
@ -166,12 +169,16 @@
#define DUK_HOBJECT_CLEAR_SPECIAL_STRINGOBJ(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_SPECIAL_STRINGOBJ)
#define DUK_HOBJECT_CLEAR_SPECIAL_ARGUMENTS(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_SPECIAL_ARGUMENTS)
#define DUK_HOBJECT_CLEAR_SPECIAL_DUKFUNC(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_SPECIAL_DUKFUNC)
#define DUK_HOBJECT_CLEAR_SPECIAL_BUFFEROBJ(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_SPECIAL_BUFFEROBJ)
/* flags used for property attributes in duk_propdesc and packed flags */
#define DUK_PROPDESC_FLAG_WRITABLE (1 << 0) /* E5 Section 8.6.1 */
#define DUK_PROPDESC_FLAG_ENUMERABLE (1 << 1) /* E5 Section 8.6.1 */
#define DUK_PROPDESC_FLAG_CONFIGURABLE (1 << 2) /* E5 Section 8.6.1 */
#define DUK_PROPDESC_FLAG_ACCESSOR (1 << 3) /* accessor */
#define DUK_PROPDESC_FLAG_VIRTUAL (1 << 4) /* property is virtual: used in duk_propdesc, never stored
* (used by e.g. buffer virtual properties)
*/
#define DUK_PROPDESC_FLAGS_MASK (DUK_PROPDESC_FLAG_WRITABLE | \
DUK_PROPDESC_FLAG_ENUMERABLE | \
DUK_PROPDESC_FLAG_CONFIGURABLE | \
@ -663,6 +670,7 @@ int duk_hobject_object_ownprop_helper(duk_context *ctx, int required_desc_flags)
/* internal properties */
int duk_hobject_get_internal_value(duk_heap *heap, duk_hobject *obj, duk_tval *tv);
duk_hstring *duk_hobject_get_internal_value_string(duk_heap *heap, duk_hobject *obj);
duk_hbuffer *duk_hobject_get_internal_value_buffer(duk_heap *heap, duk_hobject *obj);
/* hobject management functions */
void duk_hobject_compact_props(duk_hthread *thr, duk_hobject *obj);

32
src/duk_hobject_enum.c

@ -189,24 +189,36 @@ void duk_hobject_enumerator_create(duk_context *ctx, int enum_flags) {
curr = target;
while (curr) {
duk_uint32_t i;
duk_uint32_t i, len;
/*
* Virtual properties.
*
* String indices are virtual and always enumerable. String 'length'
* is virtual and non-enumerable. Array and arguments object props
* have special behavior but are concrete.
* String and buffer indices are virtual and always enumerable,
* 'length' is virtual and non-enumerable. Array and arguments
* object props have special behavior but are concrete.
*/
if (DUK_HOBJECT_HAS_SPECIAL_STRINGOBJ(curr)) {
duk_hstring *h_val;
h_val = duk_hobject_get_internal_value_string(thr->heap, curr);
DUK_ASSERT(h_val != NULL); /* string objects must not created without internal value */
if (DUK_HOBJECT_HAS_SPECIAL_STRINGOBJ(curr) ||
DUK_HOBJECT_HAS_SPECIAL_BUFFEROBJ(curr)) {
/* String and buffer enumeration behavior is identical now,
* so use shared handler.
*/
if (DUK_HOBJECT_HAS_SPECIAL_STRINGOBJ(curr)) {
duk_hstring *h_val;
h_val = duk_hobject_get_internal_value_string(thr->heap, curr);
DUK_ASSERT(h_val != NULL); /* string objects must not created without internal value */
len = DUK_HSTRING_GET_CHARLEN(h_val);
} else {
duk_hbuffer *h_val;
DUK_ASSERT(DUK_HOBJECT_HAS_SPECIAL_BUFFEROBJ(curr));
h_val = duk_hobject_get_internal_value_buffer(thr->heap, curr);
DUK_ASSERT(h_val != NULL); /* buffer objects must not created without internal value */
len = DUK_HBUFFER_GET_SIZE(h_val);
}
/* FIXME: type for 'i' to match string max len (duk_uint32_t) */
for (i = 0; i < DUK_HSTRING_GET_CHARLEN(h_val); i++) {
for (i = 0; i < len; i++) {
duk_hstring *k;
k = duk_heap_string_intern_u32_checked(thr, i);

223
src/duk_hobject_props.c

@ -1076,6 +1076,22 @@ duk_hstring *duk_hobject_get_internal_value_string(duk_heap *heap, duk_hobject *
return NULL;
}
duk_hbuffer *duk_hobject_get_internal_value_buffer(duk_heap *heap, duk_hobject *obj) {
duk_tval tv;
DUK_ASSERT(heap != NULL);
DUK_ASSERT(obj != NULL);
if (duk_hobject_get_internal_value(heap, obj, &tv)) {
duk_hbuffer *h;
DUK_ASSERT(DUK_TVAL_IS_BUFFER(&tv));
h = DUK_TVAL_GET_BUFFER(&tv);
return h;
}
return NULL;
}
/*
* Arguments handling helpers (argument map mainly).
*
@ -1393,7 +1409,8 @@ static int duk__get_own_property_desc_raw(duk_hthread *thr, duk_hobject *obj, du
duk_push_hstring(ctx, h_val);
duk_substring(ctx, -1, arr_idx, arr_idx + 1); /* [str] -> [substr] */
}
out_desc->flags = DUK_PROPDESC_FLAG_ENUMERABLE; /* E5 Section 15.5.5.2 */
out_desc->flags = DUK_PROPDESC_FLAG_ENUMERABLE | /* E5 Section 15.5.5.2 */
DUK_PROPDESC_FLAG_VIRTUAL;
DUK_ASSERT(!DUK_HOBJECT_HAS_SPECIAL_ARGUMENTS(obj));
return 1; /* cannot be e.g. arguments special, since special 'traits' are mutually exclusive */
@ -1411,7 +1428,52 @@ static int duk__get_own_property_desc_raw(duk_hthread *thr, duk_hobject *obj, du
if (push_value) {
duk_push_number(ctx, (double) DUK_HSTRING_GET_CHARLEN(h_val));
}
out_desc->flags = 0; /* E5 Section 15.5.5.1 */
out_desc->flags = DUK_PROPDESC_FLAG_VIRTUAL; /* E5 Section 15.5.5.1 */
DUK_ASSERT(!DUK_HOBJECT_HAS_SPECIAL_ARGUMENTS(obj));
return 1; /* cannot be arguments special */
}
} else if (DUK_HOBJECT_HAS_SPECIAL_BUFFEROBJ(obj)) {
DUK_DDDPRINT("buffer object special property get for key: %!O, arr_idx: %d", key, arr_idx);
if (arr_idx != DUK__NO_ARRAY_INDEX) {
duk_hbuffer *h_val;
DUK_DDDPRINT("array index exists");
h_val = duk_hobject_get_internal_value_buffer(thr->heap, obj);
DUK_ASSERT(h_val);
if (arr_idx < DUK_HBUFFER_GET_SIZE(h_val)) {
DUK_DDDPRINT("-> found, array index inside buffer");
if (push_value) {
duk_push_int(ctx, ((duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(h_val))[arr_idx]);
}
out_desc->flags = DUK_PROPDESC_FLAG_WRITABLE |
DUK_PROPDESC_FLAG_ENUMERABLE |
DUK_PROPDESC_FLAG_VIRTUAL;
DUK_ASSERT(!DUK_HOBJECT_HAS_SPECIAL_ARGUMENTS(obj));
return 1; /* cannot be e.g. arguments special, since special 'traits' are mutually exclusive */
} else {
/* index is above internal buffer length -> property is fully normal */
DUK_DDDPRINT("array index outside buffer -> normal property");
}
} else if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
duk_hbuffer *h_val;
DUK_DDDPRINT("-> found, key is 'length', length special behavior");
/* FIXME: buffer length should be writable and have special behavior
* like arrays. For now, make it read-only and use explicit methods
* to operate on buffer length.
*/
h_val = duk_hobject_get_internal_value_buffer(thr->heap, obj);
DUK_ASSERT(h_val != NULL);
if (push_value) {
duk_push_number(ctx, (double) DUK_HBUFFER_GET_SIZE(h_val));
}
out_desc->flags = DUK_PROPDESC_FLAG_VIRTUAL;
DUK_ASSERT(!DUK_HOBJECT_HAS_SPECIAL_ARGUMENTS(obj));
return 1; /* cannot be arguments special */
@ -1426,7 +1488,7 @@ static int duk__get_own_property_desc_raw(duk_hthread *thr, duk_hobject *obj, du
duk_int16_t func_nargs = ((duk_hnativefunction *) obj)->nargs;
duk_push_int(ctx, func_nargs == DUK_HNATIVEFUNCTION_NARGS_VARARGS ? 0 : func_nargs);
}
out_desc->flags = 0; /* not enumerable */
out_desc->flags = DUK_PROPDESC_FLAG_VIRTUAL; /* not enumerable */
DUK_ASSERT(!DUK_HOBJECT_HAS_SPECIAL_ARGUMENTS(obj));
return 1; /* cannot be arguments special */
@ -1586,13 +1648,14 @@ static duk_tval *duk__shallow_fast_path_array_check_u32(duk_hobject *obj, duk_ui
if ((!DUK_HOBJECT_HAS_SPECIAL_ARGUMENTS(obj)) &&
(!DUK_HOBJECT_HAS_SPECIAL_STRINGOBJ(obj)) &&
(!DUK_HOBJECT_HAS_SPECIAL_BUFFEROBJ(obj)) &&
(DUK_HOBJECT_HAS_ARRAY_PART(obj)) &&
(key_idx < obj->a_size)) {
/* technically required to check, but obj->a_size check covers this */
DUK_ASSERT(key_idx != 0xffffffffU);
DUK_DDDPRINT("fast path attempt (key is an array index, no special "
"string/arguments behavior, object has array part, key "
"string/arguments/buffer behavior, object has array part, key "
"inside array size)");
DUK_ASSERT(obj->a_size > 0); /* true even for key_idx == 0 */
@ -1623,11 +1686,12 @@ static duk_tval *duk__shallow_fast_path_array_check_tval(duk_hobject *obj, duk_t
if (DUK_TVAL_IS_NUMBER(key_tv) &&
(!DUK_HOBJECT_HAS_SPECIAL_ARGUMENTS(obj)) &&
(!DUK_HOBJECT_HAS_SPECIAL_STRINGOBJ(obj)) &&
(!DUK_HOBJECT_HAS_SPECIAL_BUFFEROBJ(obj)) &&
(DUK_HOBJECT_HAS_ARRAY_PART(obj))) {
double d;
duk_uint32_t idx;
DUK_DDDPRINT("fast path attempt (key is a number, no special string/arguments "
DUK_DDDPRINT("fast path attempt (key is a number, no special string/arguments/buffer "
"behavior, object has array part)");
/* FIXME: faster way to do this index coercion and validation? */
@ -1727,6 +1791,7 @@ int duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key) {
case DUK_TAG_STRING: {
duk_hstring *h = DUK_TVAL_GET_STRING(tv_obj);
/* FIXME: arr_idx / number handling duplication */
if (DUK_TVAL_IS_NUMBER(tv_key)) {
double t = DUK_TVAL_GET_NUMBER(tv_key);
duk_uint32_t idx = (duk_uint32_t) t;
@ -1820,11 +1885,62 @@ int duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key) {
break;
}
/* Buffer doesn't have virtual properties at the moment (indices or length). */
/* Buffer has virtual properties similar to string, but indexed values
* are numbers, not 1-byte buffers/strings which would perform badly.
*/
case DUK_TAG_BUFFER: {
duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv_obj);
/* FIXME: arr_idx / number handling duplication */
if (DUK_TVAL_IS_NUMBER(tv_key)) {
double t = DUK_TVAL_GET_NUMBER(tv_key);
duk_uint32_t idx = (duk_uint32_t) t;
DUK_DDDPRINT("base object is buffer, key is number %!T, int value %d", tv_key, (int) idx);
if ((double) idx == t && /* is whole and >= 0 */
idx < DUK_HBUFFER_GET_SIZE(h)) { /* and inside buffer */
duk_push_int(ctx, ((duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(h))[idx]);
DUK_DDDPRINT("-> %!T (base is a buffer, key is a whole number "
"inside buffer length -> return byte as number",
duk_get_tval(ctx, -1));
return 1;
}
}
duk_push_tval(ctx, tv_key);
duk_to_string(ctx, -1);
key = duk_get_hstring(ctx, -1);
arr_idx = DUK_HSTRING_GET_ARRIDX_FAST(key);
DUK_ASSERT(key != NULL);
DUK_DDDPRINT("base object buffer, key is a non-fast-path number; after coercion key is %!T, arr_idx %d", duk_get_tval(ctx, -1), arr_idx);
if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
duk_pop(ctx); /* [key] -> [] */
duk_push_number(ctx, (double) DUK_HBUFFER_GET_SIZE(h)); /* [] -> [res] */
DUK_DDDPRINT("-> %!T (base is buffer, key is 'length' after coercion -> "
"return buffer length)",
duk_get_tval(ctx, -1));
return 1;
}
if (arr_idx != DUK__NO_ARRAY_INDEX &&
arr_idx < DUK_HBUFFER_GET_SIZE(h)) {
duk_pop(ctx); /* [key] -> [] */
duk_push_int(ctx, ((duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(h))[arr_idx]);
DUK_DDDPRINT("-> %!T (base is buffer, key is an index inside buffer length "
"after coercion -> return byte as number)",
duk_get_tval(ctx, -1));
return 1;
}
DUK_DDDPRINT("base object is a buffer, start lookup from buffer prototype");
curr = thr->builtins[DUK_BIDX_BUFFER_PROTOTYPE];
break;
goto lookup; /* avoid double coercion */
}
case DUK_TAG_POINTER: {
@ -2424,13 +2540,9 @@ int duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key, du
switch (DUK_TVAL_GET_TAG(tv_obj)) {
case DUK_TAG_UNDEFINED:
case DUK_TAG_NULL:
case DUK_TAG_BUFFER:
case DUK_TAG_POINTER: {
/* FIXME: prototype objects for buffer and perhaps pointer? */
case DUK_TAG_NULL: {
/* Note: unconditional throw */
DUK_DDDPRINT("base object is undefined, null, buffer, or pointer -> reject (object=%!iT)", tv_obj);
DUK_DDDPRINT("base object is undefined or null -> reject (object=%!iT)", tv_obj);
DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "invalid base reference for property write");
return 0;
}
@ -2466,8 +2578,7 @@ int duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key, du
DUK_DDDPRINT("base object is a string, start lookup from string prototype");
curr = thr->builtins[DUK_BIDX_STRING_PROTOTYPE];
goto lookup; /* avoid double coercion */
goto lookup; /* avoid double coercion */
}
case DUK_TAG_OBJECT: {
@ -2478,6 +2589,47 @@ int duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key, du
break;
}
case DUK_TAG_BUFFER: {
duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv_obj);
/*
* Note: currently no fast path for array writes.
*/
DUK_ASSERT(key == NULL);
duk_push_tval(ctx, tv_key);
duk_to_string(ctx, -1);
key = duk_get_hstring(ctx, -1);
arr_idx = DUK_HSTRING_GET_ARRIDX_FAST(key);
DUK_ASSERT(key != NULL);
if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
goto fail_not_writable;
}
if (arr_idx != DUK__NO_ARRAY_INDEX &&
arr_idx < DUK_HBUFFER_GET_SIZE(h)) {
duk_uint8_t *data;
DUK_DDDPRINT("writing to buffer data at index %d", (int) arr_idx);
data = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(h);
duk_push_tval(ctx, tv_val);
data[arr_idx] = (duk_uint8_t) duk_to_number(ctx, -1);
duk_pop_2(ctx);
DUK_DDDPRINT("result: success (buffer data write)");
return 1;
}
DUK_DDDPRINT("base object is a buffer, start lookup from buffer prototype");
curr = thr->builtins[DUK_BIDX_BUFFER_PROTOTYPE];
goto lookup; /* avoid double coercion */
}
case DUK_TAG_POINTER: {
DUK_DDDPRINT("base object is a pointer, start lookup from pointer prototype");
curr = thr->builtins[DUK_BIDX_POINTER_PROTOTYPE];
break;
}
default: {
/* number */
DUK_DDDPRINT("base object is a number, start lookup from number prototype");
@ -2567,10 +2719,36 @@ int duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key, du
* Found existing own (non-inherited) plain property.
* Do an access control check and update in place.
*/
if (!(desc.flags & DUK_PROPDESC_FLAG_WRITABLE)) {
DUK_DDPRINT("found existing own (non-inherited) plain property, but property is not writable");
goto fail_not_writable;
}
if (desc.flags & DUK_PROPDESC_FLAG_VIRTUAL) {
DUK_DDPRINT("found existing own (non-inherited) virtual property, property is writable");
if (DUK_HOBJECT_HAS_SPECIAL_BUFFEROBJ(curr)) {
duk_hbuffer *h;
/* FIXME: lots of duplication here too */
DUK_DDPRINT("writable virtual property is in buffer object");
h = duk_hobject_get_internal_value_buffer(thr->heap, curr);
DUK_ASSERT(h != NULL);
if (arr_idx != DUK__NO_ARRAY_INDEX &&
arr_idx < DUK_HBUFFER_GET_SIZE(h)) {
duk_uint8_t *data;
DUK_DDDPRINT("writing to buffer data at index %d", (int) arr_idx);
data = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(h);
duk_push_tval(ctx, tv_val);
data[arr_idx] = (duk_uint8_t) duk_to_number(ctx, -1);
duk_pop(ctx);
goto success_no_arguments_special;
}
}
goto fail_internal; /* should not happen */
}
DUK_DDPRINT("put to existing own plain property, property is writable");
goto update_old;
}
@ -2613,10 +2791,11 @@ int duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key, du
DUK_ASSERT(orig != NULL);
/* Currently there are no writable virtual properties,
* so the property must be concretely stored in either
* the array or the entry part.
/* Although there are writable virtual properties (e.g. plain buffer
* and buffer object number indices), they are handled before we come
* here.
*/
DUK_ASSERT((desc.flags & DUK_PROPDESC_FLAG_VIRTUAL) == 0);
DUK_ASSERT(desc.a_idx >= 0 || desc.e_idx >= 0);
if (DUK_HOBJECT_HAS_SPECIAL_ARRAY(orig) &&
@ -2979,6 +3158,14 @@ int duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key, du
}
duk_pop(ctx); /* remove key */
return 0;
fail_internal:
DUK_DDDPRINT("result: error, internal");
if (throw_flag) {
DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "internal error");
}
duk_pop(ctx); /* remove key */
return 0;
}
/*

Loading…
Cancel
Save