jiahuimbzuai/CoQuIR huggingface dataset:
//  [c]
static inline struct f2fs_sb_info *F2FS_P_SB(struct page *page)
{
	return F2FS_M_SB(page->mapping);
}
//  [c]
}

static inline bool f2fs_force_buffered_io(struct inode *inode,
				struct kiocb *iocb, struct iov_iter *iter)
{
	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
	int rw = iov_iter_rw(iter);

	if (f2fs_post_read_required(inode))
		return true;
	if (f2fs_is_multi_device(sbi))
		return true;
	/*
	 * for blkzoned device, fallback direct IO to buffered IO, so
	 * all IOs can be serialized by log-structured write.
	 */
	if (f2fs_sb_has_blkzoned(sbi))
		return true;
	if (test_opt(sbi, LFS) && (rw == WRITE) &&
				block_unaligned_IO(inode, iocb, iter))
		return true;
	if (is_sbi_flag_set(F2FS_I_SB(inode), SBI_CP_DISABLED) &&
					!(inode->i_flags & S_SWAPFILE))
		return true;
//  [c]
}

static inline bool f2fs_force_buffered_io(struct inode *inode,
				struct kiocb *iocb, struct iov_iter *iter)
{
	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
	int rw = iov_iter_rw(iter);

	if (f2fs_post_read_required(inode))
		return true;
	if (f2fs_is_multi_device(sbi))
		return true;
	/*
	 * for blkzoned device, fallback direct IO to buffered IO, so
	 * all IOs can be serialized by log-structured write.
	 */
	if (f2fs_sb_has_blkzoned(sbi))
		return true;
	if (test_opt(sbi, LFS) && (rw == WRITE) &&
				block_unaligned_IO(inode, iocb, iter))
		return true;
	if (is_sbi_flag_set(F2FS_I_SB(inode), SBI_CP_DISABLED))
		return true;
//  [c]
void migrate_page_copy(struct page *newpage, struct page *page)
{
	int cpupid;

	if (PageHuge(page) || PageTransHuge(page))
		copy_huge_page(newpage, page);
	else
		copy_highpage(newpage, page);

	if (PageError(page))
		SetPageError(newpage);
	if (PageReferenced(page))
		SetPageReferenced(newpage);
	if (PageUptodate(page))
		SetPageUptodate(newpage);
	if (TestClearPageActive(page)) {
		VM_BUG_ON_PAGE(PageUnevictable(page), page);
		SetPageActive(newpage);
	} else if (TestClearPageUnevictable(page))
		SetPageUnevictable(newpage);
	if (PageChecked(page))
		SetPageChecked(newpage);
	if (PageMappedToDisk(page))
		SetPageMappedToDisk(newpage);

	/* Move dirty on pages not done by migrate_page_move_mapping() */
	if (PageDirty(page))
		SetPageDirty(newpage);

	if (page_is_young(page))
		set_page_young(newpage);
	if (page_is_idle(page))
		set_page_idle(newpage);

	/*
	 * Copy NUMA information to the new page, to prevent over-eager
	 * future migrations of this same page.
	 */
	cpupid = page_cpupid_xchg_last(page, -1);
	page_cpupid_xchg_last(newpage, cpupid);

	ksm_migrate_page(newpage, page);
	/*
	 * Please do not reorder this without considering how mm/ksm.c's
	 * get_ksm_page() depends upon ksm_migrate_page() and PageSwapCache().
	 */
	if (PageSwapCache(page))
		ClearPageSwapCache(page);
	ClearPagePrivate(page);
	set_page_private(page, 0);

	/*
	 * If any waiters have accumulated on the new page then
	 * wake them up.
	 */
	if (PageWriteback(newpage))
		end_page_writeback(newpage);
}
//  [c]
void migrate_page_copy(struct page *newpage, struct page *page)
{
	int cpupid;

	if (PageHuge(page) || PageTransHuge(page))
		copy_huge_page(newpage, page);
	else
		copy_highpage(newpage, page);

	if (PageError(page))
		SetPageError(newpage);
	if (PageReferenced(page))
		SetPageReferenced(newpage);
	if (PageUptodate(page))
		SetPageUptodate(newpage);
	if (TestClearPageActive(page)) {
		VM_BUG_ON_PAGE(PageUnevictable(page), page);
		SetPageActive(newpage);
	} else if (TestClearPageUnevictable(page))
		SetPageUnevictable(newpage);
	if (PageChecked(page))
		SetPageChecked(newpage);
	if (PageMappedToDisk(page))
		SetPageMappedToDisk(newpage);

	if (PageDirty(page)) {
		clear_page_dirty_for_io(page);
		/*
		 * Want to mark the page and the radix tree as dirty, and
		 * redo the accounting that clear_page_dirty_for_io undid,
		 * but we can't use set_page_dirty because that function
		 * is actually a signal that all of the page has become dirty.
		 * Whereas only part of our page may be dirty.
		 */
		if (PageSwapBacked(page))
			SetPageDirty(newpage);
		else
			__set_page_dirty_nobuffers(newpage);
 	}

	if (page_is_young(page))
		set_page_young(newpage);
	if (page_is_idle(page))
		set_page_idle(newpage);

	/*
	 * Copy NUMA information to the new page, to prevent over-eager
	 * future migrations of this same page.
	 */
	cpupid = page_cpupid_xchg_last(page, -1);
	page_cpupid_xchg_last(newpage, cpupid);

	ksm_migrate_page(newpage, page);
	/*
	 * Please do not reorder this without considering how mm/ksm.c's
	 * get_ksm_page() depends upon ksm_migrate_page() and PageSwapCache().
	 */
	if (PageSwapCache(page))
		ClearPageSwapCache(page);
	ClearPagePrivate(page);
	set_page_private(page, 0);

	/*
	 * If any waiters have accumulated on the new page then
	 * wake them up.
	 */
	if (PageWriteback(newpage))
		end_page_writeback(newpage);
}
//  [c]
int migrate_page_move_mapping(struct address_space *mapping,
		struct page *newpage, struct page *page,
		struct buffer_head *head, enum migrate_mode mode,
		int extra_count)
{
	int expected_count = 1 + extra_count;
	void **pslot;

	if (!mapping) {
		/* Anonymous page without mapping */
		if (page_count(page) != expected_count)
			return -EAGAIN;

		/* No turning back from here */
		set_page_memcg(newpage, page_memcg(page));
		newpage->index = page->index;
		newpage->mapping = page->mapping;
		if (PageSwapBacked(page))
			SetPageSwapBacked(newpage);

		return MIGRATEPAGE_SUCCESS;
	}

	spin_lock_irq(&mapping->tree_lock);

	pslot = radix_tree_lookup_slot(&mapping->page_tree,
 					page_index(page));

	expected_count += 1 + page_has_private(page);
	if (page_count(page) != expected_count ||
		radix_tree_deref_slot_protected(pslot, &mapping->tree_lock) != page) {
		spin_unlock_irq(&mapping->tree_lock);
		return -EAGAIN;
	}

	if (!page_freeze_refs(page, expected_count)) {
		spin_unlock_irq(&mapping->tree_lock);
		return -EAGAIN;
	}

	/*
	 * In the async migration case of moving a page with buffers, lock the
	 * buffers using trylock before the mapping is moved. If the mapping
	 * was moved, we later failed to lock the buffers and could not move
	 * the mapping back due to an elevated page count, we would have to
	 * block waiting on other references to be dropped.
	 */
	if (mode == MIGRATE_ASYNC && head &&
			!buffer_migrate_lock_buffers(head, mode)) {
		page_unfreeze_refs(page, expected_count);
		spin_unlock_irq(&mapping->tree_lock);
		return -EAGAIN;
	}

	/*
	 * Now we know that no one else is looking at the page:
	 * no turning back from here.
	 */
	set_page_memcg(newpage, page_memcg(page));
	newpage->index = page->index;
	newpage->mapping = page->mapping;
	if (PageSwapBacked(page))
		SetPageSwapBacked(newpage);

	get_page(newpage);	/* add cache reference */
	if (PageSwapCache(page)) {
		SetPageSwapCache(newpage);
		set_page_private(newpage, page_private(page));
	}

	radix_tree_replace_slot(pslot, newpage);

	/*
	 * Drop cache reference from old page by unfreezing
	 * to one less reference.
	 * We know this isn't the last reference.
	 */
	page_unfreeze_refs(page, expected_count - 1);

	/*
	 * If moved to a different zone then also account
	 * the page for that zone. Other VM counters will be
	 * taken care of when we establish references to the
	 * new page and drop references to the old page.
	 *
	 * Note that anonymous pages are accounted for
	 * via NR_FILE_PAGES and NR_ANON_PAGES if they
	 * are mapped to swap space.
	 */
	__dec_zone_page_state(page, NR_FILE_PAGES);
	__inc_zone_page_state(newpage, NR_FILE_PAGES);
	if (!PageSwapCache(page) && PageSwapBacked(page)) {
		__dec_zone_page_state(page, NR_SHMEM);
		__inc_zone_page_state(newpage, NR_SHMEM);
	}
	spin_unlock_irq(&mapping->tree_lock);

	return MIGRATEPAGE_SUCCESS;
}
//  [c]
void Jsi_ValueArrayShift(Jsi_Interp *interp, Jsi_Value *v)
{
    if (v->vt != JSI_VT_OBJECT) {
        Jsi_LogBug("Jsi_ValueArrayShift, target is not object");
        return;
    }
    Jsi_Obj *o = v->d.obj;
    if (o->isarrlist) {
        uint i;
        if (!o->arrCnt)
            return;
        if (o->arr[0])
            Jsi_DecrRefCount(interp, o->arr[0]);
        for (i=1; i<o->arrCnt; i++) {
            o->arr[i-1] = o->arr[i];
        }
        o->arr[o->arrCnt--] = NULL;
        return;
    }
    
    int len = jsi_SizeOfArray(interp, v->d.obj);
    if (len <= 0) return;
    
    Jsi_Value *v0 = Jsi_ValueArrayIndex(interp, v, 0);
    if (!v0) return;
    
    Jsi_ValueReset(interp, &v0);
    
    int i;
    Jsi_Value *last = v0;
    for (i = 1; i < len; ++i) {
        Jsi_Value *t = Jsi_ValueArrayIndex(interp, v, i);
        if (!t) return;
        Jsi_ValueCopy(interp, last, t);
        Jsi_ValueReset(interp, &t);
        last = t;
    }
    Jsi_ObjSetLength(interp, v->d.obj, len - 1);
}
//  [c]
void Jsi_ValueArrayShift(Jsi_Interp *interp, Jsi_Value *v)
{
    if (v->vt != JSI_VT_OBJECT) {
        Jsi_LogBug("Jsi_ValueArrayShift, target is not object");
        return;
    }
    Jsi_Obj *o = v->d.obj;
    if (o->isarrlist) {
        uint i;
        if (!o->arrCnt)
            return;
        if (o->arr[0])
            Jsi_DecrRefCount(interp, o->arr[0]);
        for (i=1; i<o->arrCnt; i++) {
            o->arr[i-1] = o->arr[i];
        }
        o->arr[o->arrCnt--] = NULL;
        return;
    }
    
    int len = Jsi_ObjGetLength(interp, v->d.obj);
    if (len <= 0) return;
    
    Jsi_Value *v0 = Jsi_ValueArrayIndex(interp, v, 0);
    if (!v0) return;
    
    Jsi_ValueReset(interp, &v0);
    
    int i;
    Jsi_Value *last = v0;
    for (i = 1; i < len; ++i) {
        Jsi_Value *t = Jsi_ValueArrayIndex(interp, v, i);
        if (!t) return;
        Jsi_ValueCopy(interp, last, t);
        Jsi_ValueReset(interp, &t);
        last = t;
    }
    Jsi_ObjSetLength(interp, v->d.obj, len - 1);
}
//  [c]
usage (int status)
{
  if (status != EXIT_SUCCESS)
    fprintf (stderr, _("Try `%s --help' for more information.\n"),
	     program_name);
  else
    {
      printf (_("\
Usage: %s [OPTION]... [STRINGS]...\n\
"), program_name);
      fputs (_("\
Internationalized Domain Name (IDNA2008) convert STRINGS, or standard input.\n\
\n\
"), stdout);
      fputs (_("\
Command line interface to the Libidn2 implementation of IDNA2008.\n\
\n\
All strings are expected to be encoded in the locale charset.\n\
\n\
To process a string that starts with `-', for example `-foo', use `--'\n\
to signal the end of parameters, as in `idn2 --quiet -- -foo'.\n\
\n\
Mandatory arguments to long options are mandatory for short options too.\n\
"), stdout);
      fputs (_("\
  -h, --help                Print help and exit\n\
  -V, --version             Print version and exit\n\
"), stdout);
      fputs (_("\
  -d, --decode              Decode (punycode) domain name\n\
  -l, --lookup              Lookup domain name (default)\n\
  -r, --register            Register label\n\
"), stdout);
      fputs (_("\
  -T, --tr46t               Enable TR46 transitional processing\n\
  -N, --tr46nt              Enable TR46 non-transitional processing\n\
      --no-tr46             Disable TR46 processing\n\
"), stdout);
      fputs (_("\
      --usestd3asciirules   Enable STD3 ASCII rules\n\
      --no-alabelroundtrip  Disable ALabel rountrip for lookups\n\
      --debug               Print debugging information\n\
      --quiet               Silent operation\n\
"), stdout);
      emit_bug_reporting_address ();
    }
  exit (status);
}
//  [c]
usage (int status)
{
  if (status != EXIT_SUCCESS)
    fprintf (stderr, _("Try `%s --help' for more information.\n"),
	     program_name);
  else
    {
      printf (_("\
Usage: %s [OPTION]... [STRINGS]...\n\
"), program_name);
      fputs (_("\
Internationalized Domain Name (IDNA2008) convert STRINGS, or standard input.\n\
\n\
"), stdout);
      fputs (_("\
Command line interface to the Libidn2 implementation of IDNA2008.\n\
\n\
All strings are expected to be encoded in the locale charset.\n\
\n\
To process a string that starts with `-', for example `-foo', use `--'\n\
to signal the end of parameters, as in `idn2 --quiet -- -foo'.\n\
\n\
Mandatory arguments to long options are mandatory for short options too.\n\
"), stdout);
      fputs (_("\
  -h, --help               Print help and exit\n\
  -V, --version            Print version and exit\n\
"), stdout);
      fputs (_("\
  -d, --decode             Decode (punycode) domain name\n\
  -l, --lookup             Lookup domain name (default)\n\
  -r, --register           Register label\n\
"), stdout);
      fputs (_("\
  -T, --tr46t              Enable TR46 transitional processing\n\
  -N, --tr46nt             Enable TR46 non-transitional processing\n\
      --no-tr46            Disable TR46 processing\n\
"), stdout);
      fputs (_("\
      --usestd3asciirules  Enable STD3 ASCII rules\n\
      --debug              Print debugging information\n\
      --quiet              Silent operation\n\
"), stdout);
      emit_bug_reporting_address ();
    }
  exit (status);
}
//  [c]
static Jsi_RC jsi_ArrayFilterCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,Jsi_Value **ret, Jsi_Func *funcPtr) {
    if (_this->vt != JSI_VT_OBJECT || !Jsi_ObjIsArray(interp, _this->d.obj))
        return Jsi_LogError("expected array object");
    Jsi_RC rc = JSI_OK;
    int curlen, nsiz, i, fval, n = 0, maa = 0;
    Jsi_Obj *obj, *nobj;
    Jsi_Value *func, *vpargs, *nthis = NULL, *sthis, *nrPtr = NULL;
    Jsi_Func *fptr = NULL;

    func = Jsi_ValueArrayIndex(interp, args, 0);
    if (!Jsi_ValueIsFunction(interp, func)) 
        return Jsi_LogError("expected function");
    sthis = Jsi_ValueArrayIndex(interp, args, 1);
    if (!sthis)
        sthis = nthis = Jsi_ValueNew1(interp);
    obj = _this->d.obj;
    curlen = jsi_SizeOfArray(interp, obj);    
    Jsi_ObjListifyArray(interp, obj);
    nobj = Jsi_ObjNewType(interp, JSI_OT_ARRAY);
    nsiz = obj->arrCnt;
    if (nsiz<=0) nsiz = 1;
    if (Jsi_ObjArraySizer(interp, nobj, nsiz) <= 0) {
        Jsi_LogError("index too large: %d", nsiz);
        rc = JSI_ERROR;
        goto bail;
    }
    Jsi_ValueMakeArrayObject(interp, ret, nobj);
    nrPtr = Jsi_ValueNew1(interp);
    Jsi_Value *vobjs[4];

    fptr = func->d.obj->d.fobj->func;
    maa = (fptr->argnames?fptr->argnames->argCnt:0);
    if (maa>3)
        maa = 3;
    for (i = 0; i < curlen; i++) {
        if (!obj->arr[i]) continue;
        vobjs[0] = obj->arr[i];
        vobjs[1] = (maa>1?Jsi_ValueNewNumber(interp, i):NULL);
        vobjs[2] = _this;
        vpargs = Jsi_ValueMakeObject(interp, NULL, Jsi_ObjNewArray(interp, vobjs, maa, 0));
        Jsi_IncrRefCount(interp, vpargs);
        rc = Jsi_FunctionInvoke(interp, func, vpargs, &nrPtr, sthis);
        Jsi_DecrRefCount(interp, vpargs);
        fval = Jsi_ValueIsTrue(interp, nrPtr);
        Jsi_ValueMakeUndef(interp, &nrPtr);
        if( JSI_OK!=rc ) {
            goto bail;
        }
        if (fval) {
            nobj->arr[n++] = obj->arr[i];
            Jsi_IncrRefCount(interp, obj->arr[i]);
        }
    }
    if (nthis)
        Jsi_DecrRefCount(interp, nthis);
    Jsi_DecrRefCount(interp, nrPtr);
    Jsi_ObjSetLength(interp, nobj, n);
    return JSI_OK;
        
bail:
    if (nthis)
        Jsi_DecrRefCount(interp, nthis);
    if (nrPtr)
        Jsi_DecrRefCount(interp, nrPtr);
    Jsi_ValueMakeNull(interp, ret);
    return rc;
}
//  [c]
static Jsi_RC jsi_ArrayFilterCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,Jsi_Value **ret, Jsi_Func *funcPtr) {
    if (_this->vt != JSI_VT_OBJECT || !Jsi_ObjIsArray(interp, _this->d.obj))
        return Jsi_LogError("expected array object");
    Jsi_RC rc = JSI_OK;
    int curlen, nsiz, i, fval, n = 0, maa = 0;
    Jsi_Obj *obj, *nobj;
    Jsi_Value *func, *vpargs, *nthis = NULL, *sthis, *nrPtr = NULL;
    Jsi_Func *fptr = NULL;

    func = Jsi_ValueArrayIndex(interp, args, 0);
    if (!Jsi_ValueIsFunction(interp, func)) 
        return Jsi_LogError("expected function");
    sthis = Jsi_ValueArrayIndex(interp, args, 1);
    if (!sthis)
        sthis = nthis = Jsi_ValueNew1(interp);
    obj = _this->d.obj;
    curlen = Jsi_ObjGetLength(interp, obj);    
    if (curlen < 0) {
        Jsi_ObjSetLength(interp, obj, 0);
    }
    Jsi_ObjListifyArray(interp, obj);
    nobj = Jsi_ObjNewType(interp, JSI_OT_ARRAY);
    nsiz = obj->arrCnt;
    if (nsiz<=0) nsiz = 1;
    if (Jsi_ObjArraySizer(interp, nobj, nsiz) <= 0) {
        Jsi_LogError("index too large: %d", nsiz);
        rc = JSI_ERROR;
        goto bail;
    }
    Jsi_ValueMakeArrayObject(interp, ret, nobj);
    nrPtr = Jsi_ValueNew1(interp);
    Jsi_Value *vobjs[4];

    fptr = func->d.obj->d.fobj->func;
    maa = (fptr->argnames?fptr->argnames->argCnt:0);
    if (maa>3)
        maa = 3;
    for (i = 0; i < curlen; i++) {
        if (!obj->arr[i]) continue;
        vobjs[0] = obj->arr[i];
        vobjs[1] = (maa>1?Jsi_ValueNewNumber(interp, i):NULL);
        vobjs[2] = _this;
        vpargs = Jsi_ValueMakeObject(interp, NULL, Jsi_ObjNewArray(interp, vobjs, maa, 0));
        Jsi_IncrRefCount(interp, vpargs);
        rc = Jsi_FunctionInvoke(interp, func, vpargs, &nrPtr, sthis);
        Jsi_DecrRefCount(interp, vpargs);
        fval = Jsi_ValueIsTrue(interp, nrPtr);
        Jsi_ValueMakeUndef(interp, &nrPtr);
        if( JSI_OK!=rc ) {
            goto bail;
        }
        if (fval) {
            nobj->arr[n++] = obj->arr[i];
            Jsi_IncrRefCount(interp, obj->arr[i]);
        }
    }
    if (nthis)
        Jsi_DecrRefCount(interp, nthis);
    Jsi_DecrRefCount(interp, nrPtr);
    Jsi_ObjSetLength(interp, nobj, n);
    return JSI_OK;
        
bail:
    if (nthis)
        Jsi_DecrRefCount(interp, nthis);
    if (nrPtr)
        Jsi_DecrRefCount(interp, nrPtr);
    Jsi_ValueMakeNull(interp, ret);
    return rc;
}
//  [c]
static Jsi_RC jsi_ArrayConcatCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,Jsi_Value **ret, Jsi_Func *funcPtr) {
    if (_this->vt != JSI_VT_OBJECT || !Jsi_ObjIsArray(interp, _this->d.obj))
        return Jsi_LogError("expected array object");
    Jsi_RC rc = JSI_OK;
    int curlen, argc, nsiz;
    Jsi_Obj *obj, *nobj;
    Jsi_Value *va;

    obj = _this->d.obj;
    
    argc = Jsi_ValueGetLength(interp, args);
    curlen = jsi_SizeOfArray(interp, obj);
    Jsi_ObjListifyArray(interp, obj);
   
    nobj = Jsi_ObjNewType(interp, JSI_OT_ARRAY);
    nsiz = obj->arrMaxSize;
    if (nsiz<=0) nsiz = 100;
    if (Jsi_ObjArraySizer(interp, nobj, nsiz+1) <= 0) {
        rc = JSI_ERROR;
        Jsi_LogError("index too large: %d", nsiz+1);
        goto bail;
    }

    int i, j, m;
    for (i = 0; i<curlen; i++)
    {
        if (!obj->arr[i]) continue;
        nobj->arr[i] = NULL;
        Jsi_ValueDup2(interp, nobj->arr+i, obj->arr[i]);
    }
    m = i;
    for (i = 0; i < argc; i++) {
         va = Jsi_ValueArrayIndex(interp, args, i);
         if (va->vt == JSI_VT_OBJECT && Jsi_ObjIsArray(interp, va->d.obj)) {
            int margc = Jsi_ValueGetLength(interp, va);
            Jsi_Obj *mobj = va->d.obj;
            Jsi_ObjListifyArray(interp, mobj);
            if (Jsi_ObjArraySizer(interp, nobj, curlen += margc) <= 0) {
                rc = JSI_ERROR;
                Jsi_LogError("index too large: %d", curlen);
                goto bail;
            }
            for (j = 0; j<margc; j++, m++)
            {
                if (!mobj->arr[j]) continue;
                nobj->arr[m] = NULL;
                Jsi_ValueDup2(interp, nobj->arr+m, mobj->arr[j]);
            }
        } else {
            if (Jsi_ObjArraySizer(interp, nobj, ++curlen) <= 0) {
                rc = JSI_ERROR;
                Jsi_LogError("index too large: %d", curlen);
                goto bail;
            }
            nobj->arr[m] = NULL;
            Jsi_ValueDup2(interp, nobj->arr+m++, va);
       }
    }
    Jsi_ObjSetLength(interp, nobj, curlen);
    Jsi_ValueMakeArrayObject(interp, ret, nobj);
    return JSI_OK;
        
bail:
    Jsi_ValueMakeNull(interp, ret);
    return rc;
}
//  [c]
static Jsi_RC jsi_ArrayConcatCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,Jsi_Value **ret, Jsi_Func *funcPtr) {
    if (_this->vt != JSI_VT_OBJECT || !Jsi_ObjIsArray(interp, _this->d.obj))
        return Jsi_LogError("expected array object");
    Jsi_RC rc = JSI_OK;
    int curlen, argc, nsiz;
    Jsi_Obj *obj, *nobj;
    Jsi_Value *va;

    obj = _this->d.obj;
    
    argc = Jsi_ValueGetLength(interp, args);
    curlen = Jsi_ObjGetLength(interp, obj);
    if (curlen < 0) {
        Jsi_ObjSetLength(interp, obj, 0);
    }
    Jsi_ObjListifyArray(interp, obj);
   
    nobj = Jsi_ObjNewType(interp, JSI_OT_ARRAY);
    nsiz = obj->arrMaxSize;
    if (nsiz<=0) nsiz = 100;
    if (Jsi_ObjArraySizer(interp, nobj, nsiz+1) <= 0) {
        rc = JSI_ERROR;
        Jsi_LogError("index too large: %d", nsiz+1);
        goto bail;
    }

    int i, j, m;
    for (i = 0; i<curlen; i++)
    {
        if (!obj->arr[i]) continue;
        nobj->arr[i] = NULL;
        Jsi_ValueDup2(interp, nobj->arr+i, obj->arr[i]);
    }
    m = i;
    for (i = 0; i < argc; i++) {
         va = Jsi_ValueArrayIndex(interp, args, i);
         if (va->vt == JSI_VT_OBJECT && Jsi_ObjIsArray(interp, va->d.obj)) {
            int margc = Jsi_ValueGetLength(interp, va);
            Jsi_Obj *mobj = va->d.obj;
            Jsi_ObjListifyArray(interp, mobj);
            if (Jsi_ObjArraySizer(interp, nobj, curlen += margc) <= 0) {
                rc = JSI_ERROR;
                Jsi_LogError("index too large: %d", curlen);
                goto bail;
            }
            for (j = 0; j<margc; j++, m++)
            {
                if (!mobj->arr[j]) continue;
                nobj->arr[m] = NULL;
                Jsi_ValueDup2(interp, nobj->arr+m, mobj->arr[j]);
            }
        } else {
            if (Jsi_ObjArraySizer(interp, nobj, ++curlen) <= 0) {
                rc = JSI_ERROR;
                Jsi_LogError("index too large: %d", curlen);
                goto bail;
            }
            nobj->arr[m] = NULL;
            Jsi_ValueDup2(interp, nobj->arr+m++, va);
       }
    }
    Jsi_ObjSetLength(interp, nobj, curlen);
    Jsi_ValueMakeArrayObject(interp, ret, nobj);
    return JSI_OK;
        
bail:
    Jsi_ValueMakeNull(interp, ret);
    return rc;
}
//  [c]
static Jsi_RC jsi_ArrayFlatSub(Jsi_Interp *interp, Jsi_Obj* nobj, Jsi_Value *arr, int depth) {
    
    int i, n = 0, len = jsi_SizeOfArray(interp, arr->d.obj);
    if (len <= 0) return JSI_OK;
    Jsi_RC rc = JSI_OK;
    int clen = jsi_SizeOfArray(interp, nobj);
    for (i = 0; i < len && rc == JSI_OK; i++) {
        Jsi_Value *t = Jsi_ValueArrayIndex(interp, arr, i);
        if (t && depth>0 && Jsi_ValueIsArray(interp, t))
            rc = jsi_ArrayFlatSub(interp, nobj, t , depth-1);
        else if (!Jsi_ValueIsUndef(interp, t))
            Jsi_ObjArrayAdd(interp, nobj, t);
        if ((++n + clen)>interp->maxArrayList)
            return Jsi_LogError("array size exceeded");
    }
    return rc;
}
//  [c]
static Jsi_RC jsi_ArrayFlatSub(Jsi_Interp *interp, Jsi_Obj* nobj, Jsi_Value *arr, int depth) {
    
    int i, n = 0, len = Jsi_ObjGetLength(interp, arr->d.obj);
    if (len <= 0) return JSI_OK;
    Jsi_RC rc = JSI_OK;
    int clen = Jsi_ObjGetLength(interp, nobj);
    for (i = 0; i < len && rc == JSI_OK; i++) {
        Jsi_Value *t = Jsi_ValueArrayIndex(interp, arr, i);
        if (t && depth>0 && Jsi_ValueIsArray(interp, t))
            rc = jsi_ArrayFlatSub(interp, nobj, t , depth-1);
        else if (!Jsi_ValueIsUndef(interp, t))
            Jsi_ObjArrayAdd(interp, nobj, t);
        if ((++n + clen)>interp->maxArrayList)
            return Jsi_LogError("array size exceeded");
    }
    return rc;
}
//  [c]
static Jsi_RC jsi_ArrayFillCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,Jsi_Value **ret, Jsi_Func *funcPtr) {
    if (_this->vt != JSI_VT_OBJECT || !Jsi_ObjIsArray(interp, _this->d.obj)) 
        return Jsi_LogError("expected array object");
    Jsi_RC rc = JSI_OK;
    int istart = 0, iend, n, nsiz;
    Jsi_Number nstart = 0, nend = 0; // TODO: merge with code in ArraySliceCmd.
    Jsi_Value *value = Jsi_ValueArrayIndex(interp, args, 0),
        *start = Jsi_ValueArrayIndex(interp, args, 1),
        *end = Jsi_ValueArrayIndex(interp, args, 2);
    Jsi_Obj *obj = _this->d.obj;
    n = jsi_SizeOfArray(interp, obj);

    if (start && Jsi_GetNumberFromValue(interp, start, &nstart) == JSI_OK) {
        istart = (int)nstart;
        if (istart > n)
            goto bail;
        if (istart < 0)
            istart = (n+istart);
        if (istart<0)
            goto bail;
    }
      
    if (n == 0) {
        goto bail;
    }
    iend = n-1;
    if (end && Jsi_GetNumberFromValue(interp,end, &nend) == JSI_OK) {
        iend = (int) nend;
        if (iend >= n)
            iend = n;
        if (iend < 0)
            iend = (n+iend);
        if (iend<0)
            goto bail;
    }
    nsiz = iend-istart+1;
    if (nsiz<=0)
        goto bail;

    int i;
    for (i = istart; i <= iend; i++)
    {
        if (obj->arr[i])
            Jsi_ValueCopy(interp, obj->arr[i], value);
        else
            obj->arr[i] = Jsi_ValueDup(interp, value);
    }
bail:
    if (_this != *ret) {
        Jsi_ValueMove(interp, *ret, _this);
        /*if (*ret)
            Jsi_DecrRefCount(interp, *ret);
        *ret = _this;
        Jsi_IncrRefCount(interp, *ret);*/
    }
    return rc;
}
//  [c]
static Jsi_RC jsi_ArrayFillCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,Jsi_Value **ret, Jsi_Func *funcPtr) {
    if (_this->vt != JSI_VT_OBJECT || !Jsi_ObjIsArray(interp, _this->d.obj)) 
        return Jsi_LogError("expected array object");
    Jsi_RC rc = JSI_OK;
    int istart = 0, iend, n, nsiz;
    Jsi_Number nstart = 0, nend = 0; // TODO: merge with code in ArraySliceCmd.
    Jsi_Value *value = Jsi_ValueArrayIndex(interp, args, 0),
        *start = Jsi_ValueArrayIndex(interp, args, 1),
        *end = Jsi_ValueArrayIndex(interp, args, 2);
    Jsi_Obj *obj = _this->d.obj;
    n = Jsi_ObjGetLength(interp, obj);

    if (start && Jsi_GetNumberFromValue(interp, start, &nstart) == JSI_OK) {
        istart = (int)nstart;
        if (istart > n)
            goto bail;
        if (istart < 0)
            istart = (n+istart);
        if (istart<0)
            goto bail;
    }
      
    if (n == 0) {
        goto bail;
    }
    iend = n-1;
    if (end && Jsi_GetNumberFromValue(interp,end, &nend) == JSI_OK) {
        iend = (int) nend;
        if (iend >= n)
            iend = n;
        if (iend < 0)
            iend = (n+iend);
        if (iend<0)
            goto bail;
    }
    nsiz = iend-istart+1;
    if (nsiz<=0)
        goto bail;

    int i;
    for (i = istart; i <= iend; i++)
    {
        if (obj->arr[i])
            Jsi_ValueCopy(interp, obj->arr[i], value);
        else
            obj->arr[i] = Jsi_ValueDup(interp, value);
    }
bail:
    if (_this != *ret) {
        Jsi_ValueMove(interp, *ret, _this);
        /*if (*ret)
            Jsi_DecrRefCount(interp, *ret);
        *ret = _this;
        Jsi_IncrRefCount(interp, *ret);*/
    }
    return rc;
}
//  [c]
static Jsi_RC jsi_ArrayIndexSubCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,Jsi_Value **ret, Jsi_Func *funcPtr, int op) {
    int istart = 0, n, i = 0, dir=1, idx=-1;
    Jsi_Value *seq = Jsi_ValueArrayIndex(interp, args, 0),
        *start = Jsi_ValueArrayIndex(interp, args, 1);
    Jsi_Obj *obj = _this->d.obj;
    if (_this->vt != JSI_VT_OBJECT || !Jsi_ObjIsArray(interp, _this->d.obj))
        return Jsi_LogError("expected array object");

    if (!seq) {
        goto bail;
    }
    
    n = jsi_SizeOfArray(interp, obj);    
    if (n == 0) {
        goto bail;
    }
    Jsi_Number nstart;
    if (op == 2) {
        istart = n-1;
    }
    if (start && Jsi_GetNumberFromValue(interp,start, &nstart)==JSI_OK) {
        istart = (int)nstart;
        if (istart > n)
            goto bail;
        if (istart < 0)
            istart = (n+istart);
        if (istart<0)
            goto bail;
    }
    if (op == 2) {
        istart = n-1;
        dir = -1;
    }
    Jsi_ObjListifyArray(interp, obj);
    for (i = istart; ; i+=dir)
    {
        if ((dir>0 && i>=n) || (dir<0 && i<0) || i>=(int)obj->arrCnt)
            break;
        if (obj->arr[i] && Jsi_ValueCmp(interp, obj->arr[i], seq, JSI_CMP_EXACT)==0) {
            idx = i;
            break;
        }
    }
bail:
    if (op == 3)
        Jsi_ValueMakeBool(interp, ret, (idx!=-1));
    else
        Jsi_ValueMakeNumber(interp, ret, idx);
    return JSI_OK;
}
//  [c]
static Jsi_RC jsi_ArrayIndexSubCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,Jsi_Value **ret, Jsi_Func *funcPtr, int op) {
    int istart = 0, n, i = 0, dir=1, idx=-1;
    Jsi_Value *seq = Jsi_ValueArrayIndex(interp, args, 0),
        *start = Jsi_ValueArrayIndex(interp, args, 1);
    Jsi_Obj *obj = _this->d.obj;
    if (_this->vt != JSI_VT_OBJECT || !Jsi_ObjIsArray(interp, _this->d.obj))
        return Jsi_LogError("expected array object");

    if (!seq) {
        goto bail;
    }
    
    n = Jsi_ObjGetLength(interp, obj);    
    if (n == 0) {
        goto bail;
    }
    Jsi_Number nstart;
    if (op == 2) {
        istart = n-1;
    }
    if (start && Jsi_GetNumberFromValue(interp,start, &nstart)==JSI_OK) {
        istart = (int)nstart;
        if (istart > n)
            goto bail;
        if (istart < 0)
            istart = (n+istart);
        if (istart<0)
            goto bail;
    }
    if (op == 2) {
        istart = n-1;
        dir = -1;
    }
    Jsi_ObjListifyArray(interp, obj);
    for (i = istart; ; i+=dir)
    {
        if ((dir>0 && i>=n) || (dir<0 && i<0) || i>=(int)obj->arrCnt)
            break;
        if (obj->arr[i] && Jsi_ValueCmp(interp, obj->arr[i], seq, JSI_CMP_EXACT)==0) {
            idx = i;
            break;
        }
    }
bail:
    if (op == 3)
        Jsi_ValueMakeBool(interp, ret, (idx!=-1));
    else
        Jsi_ValueMakeNumber(interp, ret, idx);
    return JSI_OK;
}
//  [c]
static Jsi_RC jsi_ArrayPushCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Func *funcPtr)
{
    Jsi_Obj *obj;
    
    if (_this->vt != JSI_VT_OBJECT || !Jsi_ObjIsArray(interp, _this->d.obj)) {
        Jsi_ValueMakeNumber(interp, ret, 0);
        return JSI_OK;
    }
    obj = _this->d.obj;
    
    int argc = Jsi_ValueGetLength(interp, args);
    int curlen = jsi_SizeOfArray(interp, obj);    
    int i;
    for (i = 0; i < argc; ++i) {
        Jsi_Value *ov = Jsi_ValueArrayIndex(interp, args, i);
        if (!ov) { Jsi_LogBug("Arguments Error"); ov = Jsi_ValueNew(interp); }
        Jsi_ValueInsertArray(interp, _this, curlen + i, ov, 0);
    }
    
    Jsi_ValueMakeNumber(interp, ret, jsi_SizeOfArray(interp, obj));
    return JSI_OK;
}
//  [c]
static Jsi_RC jsi_ArrayPushCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Func *funcPtr)
{
    Jsi_Obj *obj;
    
    if (_this->vt != JSI_VT_OBJECT || !Jsi_ObjIsArray(interp, _this->d.obj)) {
        Jsi_ValueMakeNumber(interp, ret, 0);
        return JSI_OK;
    }
    obj = _this->d.obj;
    
    int argc = Jsi_ValueGetLength(interp, args);
    int curlen = Jsi_ObjGetLength(interp, obj);
    if (curlen < 0) {
        Jsi_ObjSetLength(interp, obj, 0);
    }
    
    int i;
    for (i = 0; i < argc; ++i) {
        Jsi_Value *ov = Jsi_ValueArrayIndex(interp, args, i);
        if (!ov) { Jsi_LogBug("Arguments Error"); ov = Jsi_ValueNew(interp); }
        Jsi_ValueInsertArray(interp, _this, curlen + i, ov, 0);
    }
    
    Jsi_ValueMakeNumber(interp, ret, Jsi_ObjGetLength(interp, obj));
    return JSI_OK;
}
//  [c]
static Jsi_RC jsi_ArrayMapCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,Jsi_Value **ret, Jsi_Func *funcPtr) {
    if (_this->vt != JSI_VT_OBJECT || !Jsi_ObjIsArray(interp, _this->d.obj))
        return Jsi_LogError("expected array object");
    Jsi_RC rc = JSI_OK;
    int curlen, nsiz, i, maa = 0;
    Jsi_Obj *obj, *nobj;
    Jsi_Value *func, *vpargs, *nthis = NULL, *sthis;
    Jsi_Func *fptr = NULL;

    func = Jsi_ValueArrayIndex(interp, args, 0);
    if (!Jsi_ValueIsFunction(interp, func)) 
        return Jsi_LogError("expected function");
    sthis = Jsi_ValueArrayIndex(interp, args, 1);
    if (!sthis)
        sthis = nthis = Jsi_ValueNew1(interp);
    obj = _this->d.obj;
    curlen = jsi_SizeOfArray(interp, obj);    
    Jsi_ObjListifyArray(interp, obj);
    nobj = Jsi_ObjNewType(interp, JSI_OT_ARRAY);
    nsiz = obj->arrCnt;
    if (nsiz<=0) nsiz = 1;
    if (Jsi_ObjArraySizer(interp, nobj, nsiz) <= 0) {
        Jsi_LogError("index too large: %d", nsiz);
        rc = JSI_ERROR;
        goto bail;
    }
    Jsi_ValueMakeArrayObject(interp, ret, nobj);
    Jsi_Value *vobjs[3];

    fptr = func->d.obj->d.fobj->func;
    maa = (fptr->argnames?fptr->argnames->argCnt:0);
    if (maa>3)
        maa = 3;
    for (i = 0; i < curlen; i++) {
        if (!obj->arr[i]) continue;
        vobjs[0] = obj->arr[i];
        vobjs[1] = (maa>1?Jsi_ValueNewNumber(interp, i):NULL);
        vobjs[2] = _this;
        vpargs = Jsi_ValueMakeObject(interp, NULL, Jsi_ObjNewArray(interp, vobjs, maa, 0));
        Jsi_IncrRefCount(interp, vpargs);
        nobj->arr[i] = Jsi_ValueNew1(interp);
        rc = Jsi_FunctionInvoke(interp, func, vpargs, nobj->arr+i, sthis);
        Jsi_DecrRefCount(interp, vpargs);
        if( JSI_OK!=rc ) {
            goto bail;
        }
    }
    Jsi_ObjSetLength(interp, nobj, curlen);
    if (nthis)
        Jsi_DecrRefCount(interp, nthis);
    return JSI_OK;
        
bail:
    Jsi_ValueMakeNull(interp, ret);
    if (nthis)
        Jsi_DecrRefCount(interp, nthis);
    return rc;
}
//  [c]
static Jsi_RC jsi_ArrayMapCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,Jsi_Value **ret, Jsi_Func *funcPtr) {
    if (_this->vt != JSI_VT_OBJECT || !Jsi_ObjIsArray(interp, _this->d.obj))
        return Jsi_LogError("expected array object");
    Jsi_RC rc = JSI_OK;
    int curlen, nsiz, i, maa = 0;
    Jsi_Obj *obj, *nobj;
    Jsi_Value *func, *vpargs, *nthis = NULL, *sthis;
    Jsi_Func *fptr = NULL;

    func = Jsi_ValueArrayIndex(interp, args, 0);
    if (!Jsi_ValueIsFunction(interp, func)) 
        return Jsi_LogError("expected function");
    sthis = Jsi_ValueArrayIndex(interp, args, 1);
    if (!sthis)
        sthis = nthis = Jsi_ValueNew1(interp);
    obj = _this->d.obj;
    curlen = Jsi_ObjGetLength(interp, obj);    
    if (curlen < 0) {
        Jsi_ObjSetLength(interp, obj, 0);
    }
    Jsi_ObjListifyArray(interp, obj);
    nobj = Jsi_ObjNewType(interp, JSI_OT_ARRAY);
    nsiz = obj->arrCnt;
    if (nsiz<=0) nsiz = 1;
    if (Jsi_ObjArraySizer(interp, nobj, nsiz) <= 0) {
        Jsi_LogError("index too large: %d", nsiz);
        rc = JSI_ERROR;
        goto bail;
    }
    Jsi_ValueMakeArrayObject(interp, ret, nobj);
    Jsi_Value *vobjs[3];

    fptr = func->d.obj->d.fobj->func;
    maa = (fptr->argnames?fptr->argnames->argCnt:0);
    if (maa>3)
        maa = 3;
    for (i = 0; i < curlen; i++) {
        if (!obj->arr[i]) continue;
        vobjs[0] = obj->arr[i];
        vobjs[1] = (maa>1?Jsi_ValueNewNumber(interp, i):NULL);
        vobjs[2] = _this;
        vpargs = Jsi_ValueMakeObject(interp, NULL, Jsi_ObjNewArray(interp, vobjs, maa, 0));
        Jsi_IncrRefCount(interp, vpargs);
        nobj->arr[i] = Jsi_ValueNew1(interp);
        rc = Jsi_FunctionInvoke(interp, func, vpargs, nobj->arr+i, sthis);
        Jsi_DecrRefCount(interp, vpargs);
        if( JSI_OK!=rc ) {
            goto bail;
        }
    }
    Jsi_ObjSetLength(interp, nobj, curlen);
    if (nthis)
        Jsi_DecrRefCount(interp, nthis);
    return JSI_OK;
        
bail:
    Jsi_ValueMakeNull(interp, ret);
    if (nthis)
        Jsi_DecrRefCount(interp, nthis);
    return rc;
}
//  [c]
static Jsi_RC jsi_ArrayPopCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Func *funcPtr)
{
    if (_this->vt != JSI_VT_OBJECT || !Jsi_ObjIsArray(interp, _this->d.obj)) {
        Jsi_ValueMakeNumber(interp, ret, 0);
        return JSI_OK;
    }
    Jsi_Value *v;
    Jsi_Obj *obj;
    obj = _this->d.obj;
    int i = jsi_SizeOfArray(interp, obj) - 1;

    if (i < 0) {
        Jsi_ValueMakeUndef(interp, ret);
        return JSI_OK;
    }
    
    if (obj->arr) {
        if ((v = obj->arr[i])) {
            obj->arr[i] = NULL;
            obj->arrCnt--;
        }
    } else {
        v = Jsi_ValueArrayIndex(interp, _this, i);
    }
    if (v) {
        Jsi_DecrRefCount(interp, *ret);
        *ret = v;
    }
    Jsi_ObjSetLength(interp, obj, i);
    return JSI_OK;
}
//  [c]
static Jsi_RC jsi_ArrayPopCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Func *funcPtr)
{
    if (_this->vt != JSI_VT_OBJECT || !Jsi_ObjIsArray(interp, _this->d.obj)) {
        Jsi_ValueMakeNumber(interp, ret, 0);
        return JSI_OK;
    }
    Jsi_Value *v;
    Jsi_Obj *obj;
    obj = _this->d.obj;
    int i = Jsi_ObjGetLength(interp, obj) - 1;

    if (i < 0) {
        Jsi_ValueMakeUndef(interp, ret);
        return JSI_OK;
    }
    
    if (obj->arr) {
        if ((v = obj->arr[i])) {
            obj->arr[i] = NULL;
            obj->arrCnt--;
        }
    } else {
        v = Jsi_ValueArrayIndex(interp, _this, i);
    }
    if (v) {
        Jsi_DecrRefCount(interp, *ret);
        *ret = v;
    }
    Jsi_ObjSetLength(interp, obj, i);
    return JSI_OK;
}
//  [c]
static Jsi_RC jsi_ArrayShiftCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,Jsi_Value **ret, Jsi_Func *funcPtr) {
    if (_this->vt != JSI_VT_OBJECT || !Jsi_ObjIsArray(interp, _this->d.obj))
        return Jsi_LogError("expected array object");
    Jsi_Value *v;
    Jsi_Obj *obj = _this->d.obj;
    Jsi_ObjListifyArray(interp, obj);
    uint n = jsi_SizeOfArray(interp, obj);
    if (n<=0) {
        Jsi_ValueMakeUndef(interp, ret);
    } else {
        n--;
        v = obj->arr[0];
        memmove(obj->arr, obj->arr+1, n*sizeof(Jsi_Value*));
        obj->arr[n] = NULL;
        Jsi_ValueDup2(interp, ret, v);
        Jsi_DecrRefCount(interp, v);
        Jsi_ObjSetLength(interp, obj, n);
    }
    return JSI_OK;
}
//  [c]
static Jsi_RC jsi_ArrayShiftCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,Jsi_Value **ret, Jsi_Func *funcPtr) {
    if (_this->vt != JSI_VT_OBJECT || !Jsi_ObjIsArray(interp, _this->d.obj))
        return Jsi_LogError("expected array object");
    Jsi_Value *v;
    Jsi_Obj *obj = _this->d.obj;
    Jsi_ObjListifyArray(interp, obj);
    uint n = Jsi_ObjGetLength(interp, obj);
    assert(n <= obj->arrCnt);
    if (n<=0) {
        Jsi_ValueMakeUndef(interp, ret);
    } else {
        n--;
        v = obj->arr[0];
        memmove(obj->arr, obj->arr+1, n*sizeof(Jsi_Value*));
        obj->arr[n] = NULL;
        Jsi_ValueDup2(interp, ret, v);
        Jsi_DecrRefCount(interp, v);
        Jsi_ObjSetLength(interp, obj, n);
    }
    return JSI_OK;
}
//  [c]
static Jsi_RC jsi_ArraySliceCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,Jsi_Value **ret, Jsi_Func *funcPtr) {
   if (_this->vt != JSI_VT_OBJECT || !Jsi_ObjIsArray(interp, _this->d.obj))
        return Jsi_LogError("expected array object");

    Jsi_RC rc = JSI_OK;
    int istart = 0, iend, n, nsiz;
    Jsi_Number nstart;
    Jsi_Obj *nobj, *obj;
    Jsi_Value *start = Jsi_ValueArrayIndex(interp, args, 0),
        *end = Jsi_ValueArrayIndex(interp, args, 1);
    if (!start) {
        goto bail;
    }
    obj = _this->d.obj;
    n = jsi_SizeOfArray(interp, obj);
    if (Jsi_GetNumberFromValue(interp,start, &nstart) == JSI_OK) {
        istart = (int)nstart;
        if (istart > n)
            goto done;
        if (istart < 0)
            istart = (n+istart);
        if (istart<0)
            goto bail;
    }
      
    if (n == 0) {
done:
        Jsi_ValueMakeArrayObject(interp, ret, Jsi_ObjNewType(interp, JSI_OT_ARRAY));
        return JSI_OK;
    }
    Jsi_Number nend;
    iend = n-1;
    if (end && Jsi_GetNumberFromValue(interp,end, &nend) == JSI_OK) {
        iend = (int) nend;
        if (iend >= n)
            iend = n;
        if (iend < 0)
            iend = (n+iend);
        if (iend<0)
            goto bail;
    }
    nsiz = iend-istart+1;
    if (nsiz<=0)
        goto done;
    Jsi_ObjListifyArray(interp, obj);
    
    nobj = Jsi_ObjNewType(interp, JSI_OT_ARRAY);

    if (Jsi_ObjArraySizer(interp, nobj, nsiz) <= 0) {
        rc = Jsi_LogError("index too large: %d", nsiz);
        goto bail;
    }

    int i, m;
    for (m = 0, i = istart; i <= iend; i++, m++)
    {
        if (!obj->arr[i]) continue;
        nobj->arr[m] = NULL;
        Jsi_ValueDup2(interp, nobj->arr+m, obj->arr[i]);
    }
    Jsi_ObjSetLength(interp, nobj, nsiz);
    Jsi_ValueMakeArrayObject(interp, ret, nobj);
    return JSI_OK;
    
bail:
    Jsi_ValueMakeNull(interp, ret);
    return rc;
}
//  [c]
static Jsi_RC jsi_ArraySliceCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,Jsi_Value **ret, Jsi_Func *funcPtr) {
   if (_this->vt != JSI_VT_OBJECT || !Jsi_ObjIsArray(interp, _this->d.obj))
        return Jsi_LogError("expected array object");

    Jsi_RC rc = JSI_OK;
    int istart = 0, iend, n, nsiz;
    Jsi_Number nstart;
    Jsi_Obj *nobj, *obj;
    Jsi_Value *start = Jsi_ValueArrayIndex(interp, args, 0),
        *end = Jsi_ValueArrayIndex(interp, args, 1);
    if (!start) {
        goto bail;
    }
    obj = _this->d.obj;
    n = Jsi_ObjGetLength(interp, obj);
    if (Jsi_GetNumberFromValue(interp,start, &nstart) == JSI_OK) {
        istart = (int)nstart;
        if (istart > n)
            goto done;
        if (istart < 0)
            istart = (n+istart);
        if (istart<0)
            goto bail;
    }
      
    if (n == 0) {
done:
        Jsi_ValueMakeArrayObject(interp, ret, Jsi_ObjNewType(interp, JSI_OT_ARRAY));
        return JSI_OK;
    }
    Jsi_Number nend;
    iend = n-1;
    if (end && Jsi_GetNumberFromValue(interp,end, &nend) == JSI_OK) {
        iend = (int) nend;
        if (iend >= n)
            iend = n;
        if (iend < 0)
            iend = (n+iend);
        if (iend<0)
            goto bail;
    }
    nsiz = iend-istart+1;
    if (nsiz<=0)
        goto done;
    Jsi_ObjListifyArray(interp, obj);
    
    nobj = Jsi_ObjNewType(interp, JSI_OT_ARRAY);

    if (Jsi_ObjArraySizer(interp, nobj, nsiz) <= 0) {
        rc = Jsi_LogError("index too large: %d", nsiz);
        goto bail;
    }

    int i, m;
    for (m = 0, i = istart; i <= iend; i++, m++)
    {
        if (!obj->arr[i]) continue;
        nobj->arr[m] = NULL;
        Jsi_ValueDup2(interp, nobj->arr+m, obj->arr[i]);
    }
    Jsi_ObjSetLength(interp, nobj, nsiz);
    Jsi_ValueMakeArrayObject(interp, ret, nobj);
    return JSI_OK;
    
bail:
    Jsi_ValueMakeNull(interp, ret);
    return rc;
}
//  [c]
static Jsi_RC jsi_ArraySizeOfCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,Jsi_Value **ret, Jsi_Func *funcPtr) {
    if (_this->vt != JSI_VT_OBJECT || !Jsi_ObjIsArray(interp, _this->d.obj))
        return Jsi_LogError("expected array object");
    int i = jsi_SizeOfArray(interp, _this->d.obj);
    Jsi_ValueMakeNumber(interp, ret, i);
    return JSI_OK;
}
//  [c]
static Jsi_RC jsi_ArraySizeOfCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,Jsi_Value **ret, Jsi_Func *funcPtr) {
    if (_this->vt != JSI_VT_OBJECT || !Jsi_ObjIsArray(interp, _this->d.obj))
        return Jsi_LogError("expected array object");
    int i = Jsi_ObjGetLength(interp, _this->d.obj);
    Jsi_ValueMakeNumber(interp, ret, i);
    return JSI_OK;
}
//  [c]
static Jsi_RC jsi_ArrayJoinCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Func *funcPtr)
{
    if (_this->vt != JSI_VT_OBJECT || !Jsi_ObjIsArray(interp, _this->d.obj))
        return Jsi_LogError("expected array object");
    const char *jstr = "";
    int argc, curlen;
    Jsi_DString dStr = {};

    curlen = jsi_SizeOfArray(interp, _this->d.obj);
    if (curlen == 0) {
        goto bail;
    }

    if (Jsi_ValueGetLength(interp, args) >= 1) {
        Jsi_Value *sc = Jsi_ValueArrayIndex(interp, args, 0);
        if (sc != NULL)
            jstr = Jsi_ValueToString(interp, sc, NULL);
    }
    
    if (0 == (argc=jsi_SizeOfArray(interp, _this->d.obj))) {
        goto bail;
    }
    int i;
    for (i = 0; i < argc; ++i) {
        const char *cp;
        Jsi_Value *ov = Jsi_ValueArrayIndex(interp, _this, i);
        if (!ov) {
            /* TODO: are NULL args ok? */ 
            continue;
            cp = "";
        } else
            cp = Jsi_ValueToString(interp, ov, NULL);
        if (i && jstr[0])
            Jsi_DSAppend(&dStr, jstr, NULL);
        Jsi_DSAppend(&dStr, cp, NULL);
    }
    
    Jsi_ValueMakeStringDup(interp, ret, Jsi_DSValue(&dStr));
    Jsi_DSFree(&dStr);
    return JSI_OK;
bail:
    Jsi_ValueMakeStringDup(interp, ret, "");
    return JSI_OK;        
}
//  [c]
static Jsi_RC jsi_ArrayJoinCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Func *funcPtr)
{
    if (_this->vt != JSI_VT_OBJECT || !Jsi_ObjIsArray(interp, _this->d.obj))
        return Jsi_LogError("expected array object");
    const char *jstr = "";
    int argc, curlen;
    Jsi_DString dStr = {};

    curlen = Jsi_ObjGetLength(interp, _this->d.obj);
    if (curlen == 0) {
        goto bail;
    }

    if (Jsi_ValueGetLength(interp, args) >= 1) {
        Jsi_Value *sc = Jsi_ValueArrayIndex(interp, args, 0);
        if (sc != NULL)
            jstr = Jsi_ValueToString(interp, sc, NULL);
    }
    
    if (0 == (argc=Jsi_ObjGetLength(interp, _this->d.obj))) {
        goto bail;
    }
    int i;
    for (i = 0; i < argc; ++i) {
        const char *cp;
        Jsi_Value *ov = Jsi_ValueArrayIndex(interp, _this, i);
        if (!ov) {
            /* TODO: are NULL args ok? */ 
            continue;
            cp = "";
        } else
            cp = Jsi_ValueToString(interp, ov, NULL);
        if (i && jstr[0])
            Jsi_DSAppend(&dStr, jstr, NULL);
        Jsi_DSAppend(&dStr, cp, NULL);
    }
    
    Jsi_ValueMakeStringDup(interp, ret, Jsi_DSValue(&dStr));
    Jsi_DSFree(&dStr);
    return JSI_OK;
bail:
    Jsi_ValueMakeStringDup(interp, ret, "");
    return JSI_OK;        
}
//  [c]
static Jsi_RC jsi_ArrayUnshiftCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,Jsi_Value **ret, Jsi_Func *funcPtr) {
    if (_this->vt != JSI_VT_OBJECT || !Jsi_ObjIsArray(interp, _this->d.obj))
        return Jsi_LogError("expected array object");

    Jsi_Obj *obj = _this->d.obj;
    int argc = Jsi_ValueGetLength(interp, args);
    int curlen = jsi_SizeOfArray(interp, obj);
    if (argc <= 0) {
        Jsi_ValueMakeNumber(interp, ret, 0);
        return JSI_OK;
    }
    Jsi_ObjListifyArray(interp, obj);
    if (Jsi_ObjArraySizer(interp, obj, curlen+argc)<=0) 
        return Jsi_LogError("too long");
    memmove(obj->arr+argc, obj->arr, (curlen)*sizeof(Jsi_Value*));
    obj->arrCnt += argc;
    int i;
    for (i = 0; i < argc; ++i) {
        Jsi_Value *ov = Jsi_ValueArrayIndex(interp, args, i);
        obj->arr[i] = NULL;
        if (!ov) { Jsi_LogBug("Arguments Error"); continue; }
        obj->arr[i] = ov;
        Jsi_IncrRefCount(interp, ov);
    }
    Jsi_ObjSetLength(interp, obj, curlen+argc);
    
    Jsi_ValueMakeNumber(interp, ret, jsi_SizeOfArray(interp, obj));
    return JSI_OK;
}
//  [c]
static Jsi_RC jsi_ArrayUnshiftCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,Jsi_Value **ret, Jsi_Func *funcPtr) {
    if (_this->vt != JSI_VT_OBJECT || !Jsi_ObjIsArray(interp, _this->d.obj))
        return Jsi_LogError("expected array object");

    Jsi_Obj *obj = _this->d.obj;
    int argc = Jsi_ValueGetLength(interp, args);
    int curlen = Jsi_ObjGetLength(interp, obj);
    if (curlen < 0) {
        Jsi_ObjSetLength(interp, obj, 0);
    }
    if (argc <= 0) {
        Jsi_ValueMakeNumber(interp, ret, 0);
        return JSI_OK;
    }
    Jsi_ObjListifyArray(interp, obj);
    if (Jsi_ObjArraySizer(interp, obj, curlen+argc)<=0) 
        return Jsi_LogError("too long");
    memmove(obj->arr+argc, obj->arr, (curlen)*sizeof(Jsi_Value*));
    obj->arrCnt += argc;
    int i;
    for (i = 0; i < argc; ++i) {
        Jsi_Value *ov = Jsi_ValueArrayIndex(interp, args, i);
        obj->arr[i] = NULL;
        if (!ov) { Jsi_LogBug("Arguments Error"); continue; }
        obj->arr[i] = ov;
        Jsi_IncrRefCount(interp, ov);
    }
    Jsi_ObjSetLength(interp, obj, curlen+argc);
    
    Jsi_ValueMakeNumber(interp, ret, Jsi_ObjGetLength(interp, obj));
    return JSI_OK;
}