예제 #1
0
void duk_hbuffer_remove_slice(duk_hthread *thr, duk_hbuffer_dynamic *buf, size_t offset, size_t length) {
	char *p;
	size_t end_offset;

	DUK_ASSERT(thr != NULL);
	DUK_ASSERT(buf != NULL);
	DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(buf));
	DUK_ASSERT(offset >= 0);                                       /* always true */
	DUK_ASSERT(offset <= DUK_HBUFFER_GET_SIZE(buf));               /* allow equality */
	DUK_ASSERT(length >= 0);                                       /* always true */
	DUK_ASSERT(offset + length <= DUK_HBUFFER_GET_SIZE(buf));      /* allow equality */

	if (length == 0) {
		return;
	}

	p = (char *) DUK_HBUFFER_DYNAMIC_GET_CURR_DATA_PTR(buf);

	end_offset = offset + length;

	if (end_offset < DUK_HBUFFER_GET_SIZE(buf)) {
		/* not strictly from end of buffer; need to shuffle data */
		DUK_MEMMOVE(p + offset,
		            p + end_offset,
	                    DUK_HBUFFER_GET_SIZE(buf) - end_offset);  /* always > 0 */
	}

	DUK_MEMSET(p + DUK_HBUFFER_GET_SIZE(buf) - length,
	           0,
	           length);  /* always > 0 */

	buf->size -= length;

	/* Note: no shrink check, intentional */
}
예제 #2
0
void duk_hbuffer_insert_bytes(duk_hthread *thr, duk_hbuffer_dynamic *buf, size_t offset, duk_uint8_t *data, size_t length) {
	char *p;

	/* XXX: allow inserts with offset > curr_size? i.e., insert zeroes automatically? */

	DUK_ASSERT(thr != NULL);
	DUK_ASSERT(buf != NULL);
	DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(buf));
	DUK_ASSERT_DISABLE(offset >= 0);  /* unsigned, so always true */
	DUK_ASSERT(offset <= DUK_HBUFFER_GET_SIZE(buf));  /* equality is OK (= append) */
	DUK_ASSERT(data != NULL);
	DUK_ASSERT_DISABLE(length >= 0);  /* unsigned, so always true */

	if (length == 0) {
		return;
	}

	if (DUK_HBUFFER_DYNAMIC_GET_SPARE_SIZE(buf) < length) {
		duk_hbuffer_resize(thr,
		                   buf,
		                   DUK_HBUFFER_GET_SIZE(buf),
		                   duk__add_spare(DUK_HBUFFER_GET_SIZE(buf) + length));
	}
	DUK_ASSERT(DUK_HBUFFER_DYNAMIC_GET_SPARE_SIZE(buf) >= length);

	p = (char *) DUK_HBUFFER_DYNAMIC_GET_CURR_DATA_PTR(buf);
	if (offset < DUK_HBUFFER_GET_SIZE(buf)) {
		/* not an append */

		DUK_ASSERT(DUK_HBUFFER_GET_SIZE(buf) - offset > 0);  /* not a zero byte memmove */
		DUK_MEMMOVE((void *) (p + offset + length),
		            (void *) (p + offset),
		            DUK_HBUFFER_GET_SIZE(buf) - offset);
	}

	DUK_MEMCPY((void *) (p + offset),
	           data,
	           length);

	buf->size += length;
}
예제 #3
0
void duk_hbuffer_remove_slice(duk_hthread *thr, duk_hbuffer_dynamic *buf, size_t offset, size_t length) {
	char *p;
	size_t end_offset;

	DUK_UNREF(thr);

	DUK_ASSERT(thr != NULL);
	DUK_ASSERT(buf != NULL);
	DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(buf));
	DUK_ASSERT_DISABLE(offset >= 0);                               /* always true */
	DUK_ASSERT(offset <= DUK_HBUFFER_GET_SIZE(buf));               /* allow equality */
	DUK_ASSERT_DISABLE(length >= 0);                               /* always true */
	DUK_ASSERT(offset + length <= DUK_HBUFFER_GET_SIZE(buf));      /* allow equality */

	if (length == 0) {
		return;
	}

	p = (char *) DUK_HBUFFER_DYNAMIC_GET_CURR_DATA_PTR(buf);

	end_offset = offset + length;

	if (end_offset < DUK_HBUFFER_GET_SIZE(buf)) {
		/* not strictly from end of buffer; need to shuffle data */
		DUK_MEMMOVE(p + offset,
		            p + end_offset,
	                    DUK_HBUFFER_GET_SIZE(buf) - end_offset);  /* always > 0 */
	}

	/* Here we want to zero data even with automatic buffer zeroing
	 * disabled as we depend on this internally too.
	 */
	DUK_MEMZERO(p + DUK_HBUFFER_GET_SIZE(buf) - length,
	            length);  /* always > 0 */

	buf->size -= length;

	/* Note: no shrink check, intentional */
}
예제 #4
0
static void duk__sort_array_indices(duk_hobject *h_obj) {
	duk_hstring **keys;
	duk_hstring **p_curr, **p_insert, **p_end;
	duk_hstring *h_curr;
	duk_uarridx_t val_highest, val_curr, val_insert;

	DUK_ASSERT(h_obj != NULL);
	DUK_ASSERT(h_obj->e_next >= 2);  /* control props */

	if (h_obj->e_next <= 1 + DUK__ENUM_START_INDEX) {
		return;
	}

	keys = DUK_HOBJECT_E_GET_KEY_BASE(h_obj);
	p_end = keys + h_obj->e_next;
	keys += DUK__ENUM_START_INDEX;

	DUK_DDD(DUK_DDDPRINT("keys=%p, p_end=%p (after skipping enum props)",
	                     (void *) keys, (void *) p_end));

#ifdef DUK_USE_DDDPRINT
	{
		duk_uint_fast32_t i;
		for (i = 0; i < (duk_uint_fast32_t) h_obj->e_next; i++) {
			DUK_DDD(DUK_DDDPRINT("initial: %ld %p -> %!O",
			                     (long) i,
			                     (void *) DUK_HOBJECT_E_GET_KEY_PTR(h_obj, i),
			                     (duk_heaphdr *) DUK_HOBJECT_E_GET_KEY(h_obj, i)));
		}
	}
#endif

	val_highest = DUK_HSTRING_GET_ARRIDX_SLOW(keys[0]);
	for (p_curr = keys + 1; p_curr < p_end; p_curr++) {
		DUK_ASSERT(*p_curr != NULL);
		val_curr = DUK_HSTRING_GET_ARRIDX_SLOW(*p_curr);

		if (val_curr >= val_highest) {
			DUK_DDD(DUK_DDDPRINT("p_curr=%p, p_end=%p, val_highest=%ld, val_curr=%ld -> "
			                     "already in correct order, next",
			                     (void *) p_curr, (void *) p_end, (long) val_highest, (long) val_curr));
			val_highest = val_curr;
			continue;
		}

		DUK_DDD(DUK_DDDPRINT("p_curr=%p, p_end=%p, val_highest=%ld, val_curr=%ld -> "
		                     "needs to be inserted",
		                     (void *) p_curr, (void *) p_end, (long) val_highest, (long) val_curr));
	
		/* Needs to be inserted; scan backwards, since we optimize
		 * for the case where elements are nearly in order.
		 */

		p_insert = p_curr - 1;
		for (;;) {
			val_insert = DUK_HSTRING_GET_ARRIDX_SLOW(*p_insert);
			if (val_insert < val_curr) {
				DUK_DDD(DUK_DDDPRINT("p_insert=%p, val_insert=%ld, val_curr=%ld -> insert after this",
				                     (void *) p_insert, (long) val_insert, (long) val_curr));
				p_insert++;
				break;
			}
			if (p_insert == keys) {
				DUK_DDD(DUK_DDDPRINT("p_insert=%p -> out of keys, insert to beginning", (void *) p_insert));
				break;
			}
			DUK_DDD(DUK_DDDPRINT("p_insert=%p, val_insert=%ld, val_curr=%ld -> search backwards",
			                     (void *) p_insert, (long) val_insert, (long) val_curr));
			p_insert--;
		}

		DUK_DDD(DUK_DDDPRINT("final p_insert=%p", (void *) p_insert));

		/*        .-- p_insert   .-- p_curr
		 *        v              v
		 *  | ... | insert | ... | curr
		 */

		h_curr = *p_curr;
		DUK_DDD(DUK_DDDPRINT("memmove: dest=%p, src=%p, size=%ld, h_curr=%p",
		                     (void *) (p_insert + 1), (void *) p_insert,
		                     (long) (p_curr - p_insert), (void *) h_curr));

		DUK_MEMMOVE((void *) (p_insert + 1),
		            (void *) p_insert,
		            (size_t) ((p_curr - p_insert) * sizeof(duk_hstring *)));
		*p_insert = h_curr;
		/* keep val_highest */
	}

#ifdef DUK_USE_DDDPRINT
	{
		duk_uint_fast32_t i;
		for (i = 0; i < (duk_uint_fast32_t) h_obj->e_next; i++) {
			DUK_DDD(DUK_DDDPRINT("final: %ld %p -> %!O",
			                     (long) i,
			                     (void *) DUK_HOBJECT_E_GET_KEY_PTR(h_obj, i),
			                     (duk_heaphdr *) DUK_HOBJECT_E_GET_KEY(h_obj, i)));
		}
	}
#endif
}
예제 #5
0
DUK_INTERNAL duk_uint_fast32_t duk_heap_strcache_offset_char2byte(duk_hthread *thr, duk_hstring *h, duk_uint_fast32_t char_offset) {
    duk_heap *heap;
    duk_strcache *sce;
    duk_uint_fast32_t byte_offset;
    duk_small_int_t i;
    duk_bool_t use_cache;
    duk_uint_fast32_t dist_start, dist_end, dist_sce;
    duk_uint8_t *p_start;
    duk_uint8_t *p_end;
    duk_uint8_t *p_found;

    if (char_offset > DUK_HSTRING_GET_CHARLEN(h)) {
        goto error;
    }

    /*
     *  For ASCII strings, the answer is simple.
     */

    if (DUK_HSTRING_IS_ASCII(h)) {
        /* clen == blen -> pure ascii */
        return char_offset;
    }

    /*
     *  For non-ASCII strings, we need to scan forwards or backwards
     *  from some starting point.  The starting point may be the start
     *  or end of the string, or some cached midpoint in the string
     *  cache.
     *
     *  For "short" strings we simply scan without checking or updating
     *  the cache.  For longer strings we check and update the cache as
     *  necessary, inserting a new cache entry if none exists.
     */

    DUK_DDD(DUK_DDDPRINT("non-ascii string %p, char_offset=%ld, clen=%ld, blen=%ld",
                         (void *) h, (long) char_offset,
                         (long) DUK_HSTRING_GET_CHARLEN(h),
                         (long) DUK_HSTRING_GET_BYTELEN(h)));

    heap = thr->heap;
    sce = NULL;
    use_cache = (DUK_HSTRING_GET_CHARLEN(h) > DUK_HEAP_STRINGCACHE_NOCACHE_LIMIT);

    if (use_cache) {
#ifdef DUK_USE_DDDPRINT
        DUK_DDD(DUK_DDDPRINT("stringcache before char2byte (using cache):"));
        for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) {
            duk_strcache *c = heap->strcache + i;
            DUK_DDD(DUK_DDDPRINT("  [%ld] -> h=%p, cidx=%ld, bidx=%ld",
                                 (long) i, (void *) c->h, (long) c->cidx, (long) c->bidx));
        }
#endif

        for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) {
            duk_strcache *c = heap->strcache + i;

            if (c->h == h) {
                sce = c;
                break;
            }
        }
    }

    /*
     *  Scan from shortest distance:
     *    - start of string
     *    - end of string
     *    - cache entry (if exists)
     */

    DUK_ASSERT(DUK_HSTRING_GET_CHARLEN(h) >= char_offset);
    dist_start = char_offset;
    dist_end = DUK_HSTRING_GET_CHARLEN(h) - char_offset;
    dist_sce = 0;
    DUK_UNREF(dist_sce);  /* initialize for debug prints, needed if sce==NULL */

    p_start = (duk_uint8_t *) DUK_HSTRING_GET_DATA(h);
    p_end = (duk_uint8_t *) (p_start + DUK_HSTRING_GET_BYTELEN(h));
    p_found = NULL;

    if (sce) {
        if (char_offset >= sce->cidx) {
            dist_sce = char_offset - sce->cidx;
            if ((dist_sce <= dist_start) && (dist_sce <= dist_end)) {
                DUK_DDD(DUK_DDDPRINT("non-ascii string, use_cache=%ld, sce=%p:%ld:%ld, "
                                     "dist_start=%ld, dist_end=%ld, dist_sce=%ld => "
                                     "scan forwards from sce",
                                     (long) use_cache, (void *) (sce ? sce->h : NULL),
                                     (sce ? (long) sce->cidx : (long) -1),
                                     (sce ? (long) sce->bidx : (long) -1),
                                     (long) dist_start, (long) dist_end, (long) dist_sce));

                p_found = duk__scan_forwards(p_start + sce->bidx,
                                             p_end,
                                             dist_sce);
                goto scan_done;
            }
        } else {
            dist_sce = sce->cidx - char_offset;
            if ((dist_sce <= dist_start) && (dist_sce <= dist_end)) {
                DUK_DDD(DUK_DDDPRINT("non-ascii string, use_cache=%ld, sce=%p:%ld:%ld, "
                                     "dist_start=%ld, dist_end=%ld, dist_sce=%ld => "
                                     "scan backwards from sce",
                                     (long) use_cache, (void *) (sce ? sce->h : NULL),
                                     (sce ? (long) sce->cidx : (long) -1),
                                     (sce ? (long) sce->bidx : (long) -1),
                                     (long) dist_start, (long) dist_end, (long) dist_sce));

                p_found = duk__scan_backwards(p_start + sce->bidx,
                                              p_start,
                                              dist_sce);
                goto scan_done;
            }
        }
    }

    /* no sce, or sce scan not best */

    if (dist_start <= dist_end) {
        DUK_DDD(DUK_DDDPRINT("non-ascii string, use_cache=%ld, sce=%p:%ld:%ld, "
                             "dist_start=%ld, dist_end=%ld, dist_sce=%ld => "
                             "scan forwards from string start",
                             (long) use_cache, (void *) (sce ? sce->h : NULL),
                             (sce ? (long) sce->cidx : (long) -1),
                             (sce ? (long) sce->bidx : (long) -1),
                             (long) dist_start, (long) dist_end, (long) dist_sce));

        p_found = duk__scan_forwards(p_start,
                                     p_end,
                                     dist_start);
    } else {
        DUK_DDD(DUK_DDDPRINT("non-ascii string, use_cache=%ld, sce=%p:%ld:%ld, "
                             "dist_start=%ld, dist_end=%ld, dist_sce=%ld => "
                             "scan backwards from string end",
                             (long) use_cache, (void *) (sce ? sce->h : NULL),
                             (sce ? (long) sce->cidx : (long) -1),
                             (sce ? (long) sce->bidx : (long) -1),
                             (long) dist_start, (long) dist_end, (long) dist_sce));

        p_found = duk__scan_backwards(p_end,
                                      p_start,
                                      dist_end);
    }

scan_done:

    if (!p_found) {
        /* Scan error: this shouldn't normally happen; it could happen if
         * string is not valid UTF-8 data, and clen/blen are not consistent
         * with the scanning algorithm.
         */
        goto error;
    }

    DUK_ASSERT(p_found >= p_start);
    DUK_ASSERT(p_found <= p_end);  /* may be equal */
    byte_offset = (duk_uint32_t) (p_found - p_start);

    DUK_DDD(DUK_DDDPRINT("-> string %p, cidx %ld -> bidx %ld",
                         (void *) h, (long) char_offset, (long) byte_offset));

    /*
     *  Update cache entry (allocating if necessary), and move the
     *  cache entry to the first place (in an "LRU" policy).
     */

    if (use_cache) {
        /* update entry, allocating if necessary */
        if (!sce) {
            sce = heap->strcache + DUK_HEAP_STRCACHE_SIZE - 1;  /* take last entry */
            sce->h = h;
        }
        DUK_ASSERT(sce != NULL);
        sce->bidx = (duk_uint32_t) (p_found - p_start);
        sce->cidx = (duk_uint32_t) char_offset;

        /* LRU: move our entry to first */
        if (sce > &heap->strcache[0]) {
            /*
             *   A                  C
             *   B                  A
             *   C <- sce    ==>    B
             *   D                  D
             */
            duk_strcache tmp;

            tmp = *sce;
            DUK_MEMMOVE((void *) (&heap->strcache[1]),
                        (void *) (&heap->strcache[0]),
                        (size_t) (((char *) sce) - ((char *) &heap->strcache[0])));
            heap->strcache[0] = tmp;

            /* 'sce' points to the wrong entry here, but is no longer used */
        }
#ifdef DUK_USE_DDDPRINT
        DUK_DDD(DUK_DDDPRINT("stringcache after char2byte (using cache):"));
        for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) {
            duk_strcache *c = heap->strcache + i;
            DUK_DDD(DUK_DDDPRINT("  [%ld] -> h=%p, cidx=%ld, bidx=%ld",
                                 (long) i, (void *) c->h, (long) c->cidx, (long) c->bidx));
        }
#endif
    }

    return byte_offset;

error:
    DUK_ERROR(thr, DUK_ERR_INTERNAL_ERROR, "string scan error");
    return 0;
}
예제 #6
0
void duk_hbuffer_insert_slice(duk_hthread *thr, duk_hbuffer_dynamic *buf, size_t dst_offset, size_t src_offset, size_t length) {
	char *p;
	size_t src_end_offset;  /* source end (exclusive) in initial buffer */
	size_t len;

	DUK_ASSERT(thr != NULL);
	DUK_ASSERT(buf != NULL);
	DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(buf));
	DUK_ASSERT_DISABLE(dst_offset >= 0);                           /* always true */
	DUK_ASSERT(dst_offset <= DUK_HBUFFER_GET_SIZE(buf));           /* allow equality */
	DUK_ASSERT_DISABLE(src_offset >= 0);                           /* always true */
	DUK_ASSERT(src_offset <= DUK_HBUFFER_GET_SIZE(buf));           /* allow equality */
	DUK_ASSERT_DISABLE(length >= 0);                               /* always true */
	DUK_ASSERT(src_offset + length <= DUK_HBUFFER_GET_SIZE(buf));  /* allow equality */

	if (length == 0) {
		return;
	}

	if (DUK_HBUFFER_DYNAMIC_GET_SPARE_SIZE(buf) < length) {
		duk_hbuffer_resize(thr,
		                   buf,
		                   DUK_HBUFFER_GET_SIZE(buf),
		                   duk__add_spare(DUK_HBUFFER_GET_SIZE(buf) + length));
	}
	DUK_ASSERT(DUK_HBUFFER_DYNAMIC_GET_SPARE_SIZE(buf) >= length);

	p = (char *) DUK_HBUFFER_DYNAMIC_GET_CURR_DATA_PTR(buf);

	/*
	 *  src_offset and dst_offset refer to the state of the buffer
	 *  before any changes are made.  This must be taken into account
	 *  when moving data around; in particular, the source data may
	 *  "straddle" the dst_offset, so the insert may need to be handled
	 *  in two pieces.
	 */

	src_end_offset = src_offset + length;

	/* create a hole for the insert */
	len = DUK_HBUFFER_GET_SIZE(buf) - dst_offset;
	if (len > 0) {
		DUK_MEMMOVE(p + dst_offset + length,
		            p + dst_offset,
		            len);
	}

	if (src_offset < dst_offset) {
		if (src_end_offset <= dst_offset) {
			/* entire source is before 'dst_offset' */
			DUK_MEMCPY(p + dst_offset,
			           p + src_offset,
			           length);
		} else {
			/* part of the source is before 'dst_offset'; straddles */
			len = dst_offset - src_offset;
			DUK_ASSERT(len >= 1 && len < length);
			DUK_ASSERT(length - len >= 1);
			DUK_MEMCPY(p + dst_offset,
			           p + src_offset,
			           len);
			DUK_MEMCPY(p + dst_offset + len,
			           p + src_offset + length + len,  /* take above memmove() into account */
			           length - len);
		}
	} else {
		/* entire source is after 'dst_offset' */
		DUK_MEMCPY(p + dst_offset,
		           p + src_offset + length,  /* take above memmove() into account */
		           length);
	}

	buf->size += length;
}