/*---------------------------------------------------------------------*//**
	ブロックオブジェクトを積む ⇒ js_PutBlockObject
**//*---------------------------------------------------------------------*/
bool EsStackFrame::putBlockObject(EsContext* ctx, bool isNormalUnwind)
{
	EsObject* obj = _objScopeChain;

	ASSERT(obj->getClass()->getClassType() == EsSysClasses::CLASSTYPE_BLOCK);
	ASSERT(obj->getSlots()->getPrivateData() == this);
	ASSERT(obj->getObjType() == OBJT_BLOCK);
	ASSERT(((EsBlock*)obj)->isCloned());		// ⇒ JS_ASSERT(OBJ_IS_CLONED_BLOCK(obj));

	s32 depth = obj->getSlots()->getBlockDepth();
	s32 count = obj->getScope()->getScopePropertyNum();	// ⇒ count = OBJ_BLOCK_COUNT(cx, obj);
	ASSERT(depth <= (_regs->sp() - getStackTop()));
	ASSERT(count <= (_regs->sp() - getStackTop() - depth));
	ASSERT(count >= 1);

	depth += _il->getFixedSlotNum();
	obj->slots()->setValue(obj->getSlots()->getBlockDepthIndex() + 1, obj->getSlots()->getValue(depth));	// ⇒ obj->fslots[JSSLOT_BLOCK_DEPTH + 1] = fp->slots[depth];
	if(isNormalUnwind && (count > 1))
	{
		count--;
		if(obj->slots()->recreate(NUM_INITIAL_SLOT + count))	// ⇒ js_ReallocSlots(cx, obj, JS_INITIAL_NSLOTS + count, JS_TRUE)
		{
			TFW_COPY_MEMORY(obj->slots()->dvalue(0), &_varrSlots[depth + 1], sizeof(EsValue) * count);	// ⇒ memcpy(obj->dslots, fp->slots + depth + 1, count * sizeof(jsval));
		}
		else
		{
			isNormalUnwind = false;
		}
	}

	obj->slots()->setPrivateData(0L);
	_objScopeChain = obj->slots()->parentObject();

	return isNormalUnwind;
}
Exemple #2
0
/* GCのマークフェーズ */
static void gc_mark(void)
{
  int i;
  /* スタックトップと, スタックを指すポインタを取得 */
  int stack_top        = getStackTop();  
  LL1LL_Value *stack_p = getStackPointer(); 
  LL1LL_Object *pos;

  /* 全マークをリセット */
  for (pos = heap_head; pos != NULL; pos = pos->next)
    pos->marked = LL1LL_FALSE;

  /* スタック(参照できるオブジェクト)を走査 */
  for (i = 0; i < stack_top; i++) {
    if (stack_p[i].type != LL1LL_OBJECT_TYPE) { 
      /* オブジェクトでないなら次へ */
      continue;
    } else {
      /* マークを付ける */
      if (is_string(stack_p[i])) {
        stack_p[i].u.object->marked = LL1LL_TRUE;
      } else {
        /* should be ARRAY_OBJECT here */
        array_mark(stack_p[i].u.object);  /* 配列マークのルーチンへ */
      }
    }
  }

}
Exemple #3
0
/**
 * DCI handler init
 */
void drDcihInit(
    const addr_t    dciBuffer,
    const uint32_t  dciBufferLen
){
    /* Ensure thread stack is clean */
    clearStack( drDcihStack );

    /* DCI message buffer */
    message = (dciMessage_t*) dciBuffer;

    /**
     * Update DCI handler thread so that notifications will be delivered
     * to DCI handler thread
     */
    if (DRAPI_OK != drUtilsUpdateNotificationThread( DRIVER_THREAD_NO_DCIH ))
    {
        drDbgPrintLnf("[Driver DrTemplate] drDcihInit(): Updating notification thread failed");
    }

    /**
     * Start DCI handler thread. EXH thread becomes local
     * exception handler of DCIH thread
     */
    if (DRAPI_OK != drApiStartThread(
                    DRIVER_THREAD_NO_DCIH,
                    FUNC_PTR(drDcih),
                    getStackTop(drDcihStack),
                    DCIH_PRIORITY,
                    DRIVER_THREAD_NO_EXCH))

    {
            drDbgPrintLnf("[Driver DrTemplate] drDcihInit(): drApiStartThread failed");
    }
}
/*---------------------------------------------------------------------*//**
	スコープを遡る ⇒ js_UnwindScope
**//*---------------------------------------------------------------------*/
bool EsStackFrame::unwindScope(EsContext* ctx, s32 depthStack, bool isNormalUnwind)
{
	ASSERT(depthStack >= 0);
	ASSERT((getStackTop() + depthStack) <= _regs->sp(0));

	EsObject* obj = _objBlockChain;
	while(obj != 0L)
	{
		ASSERT(obj->getClass()->getClassType() == EsSysClasses::CLASSTYPE_BLOCK);
		if(obj->getSlots()->getBlockDepth() < depthStack)
		{
			break;
		}
		obj = obj->slots()->parentObject();
	}
	_objBlockChain = obj;

	while(true)
	{
		obj = _objScopeChain;
		const EsClass* cls = getActiveBlockClass(ctx, obj, depthStack);
		if(cls == 0L)	{	break;	}
		if(cls->getClassType() == EsSysClasses::CLASSTYPE_BLOCK)
		{
			if(!putBlockObject(ctx, isNormalUnwind))	{	isNormalUnwind = false;	}
		}
		else
		{
			leaveWithBlock(ctx);
		}
	}

	_regs->setCurSpIndex(depthStack);	// ⇒ fp->regs->sp = StackBase(fp) + stackDepth;
	return isNormalUnwind;
}
/*---------------------------------------------------------------------*//**
	準備 ⇒ js_Execute の冒頭部分
**//*---------------------------------------------------------------------*/
bool EsStackFrame::prepareForRun(EsContext* ctx, EsInterlang* il, EsObject* objScope, EsStackFrame* sfrmDown, u16 flags)
{
	EsStackFrame* sfrmOld = ctx->getTopStackFrame();
	_il = il;
	if(sfrmDown != 0L)
	{
		_objCall = sfrmDown->_objCall;
		_objArgs = sfrmDown->_objArgs;
		_objVar = sfrmDown->_objVar;
		_objCallee = sfrmDown->_objCallee;
		_func = sfrmDown->_func;
		_objThis = sfrmDown->_objThis;
		if(TFW_IS_FLAG(sfrmDown->_flags, F_COMPUTED_THIS))
		{
			flags |= F_COMPUTED_THIS;
		}
		_numArg = sfrmDown->_numArg;
		_valarrStack = sfrmDown->_valarrStack;
	}
	else
	{
		_objCall = 0L;
		_objArgs = 0L;
		_objVar = objScope;
		_objCallee = 0L;
		_func = 0L;
		_objThis = objScope;
		_numArg = 0;
		_valarrStack = 0L;
	}
	_flags = flags;
	_sfrmDown = sfrmDown;
	_objScopeChain = objScope;
	_objBlockChain = 0L;

	// スロットの作成
	_numSlot = il->getSlotNum();		// ⇒ script->nslots
	if(_numSlot > 0)
	{
		_varrSlots = _varrSlotsAlloc = new EsValue[_numSlot];	// ⇒ frame.slots = js_AllocRawStack(cx, script->nslots, &mark);
		if(_varrSlots == 0L)	{	return false;	}
	}
	else
	{
		_varrSlots = _varrSlotsAlloc = 0L;
	}

	// レジスタの作成
	_pc = new EsProgramCounter(il->getBytecode());				// ⇒ regs.pc = script->code;
	_regs = new EsStackRegister(ctx, _pc, getStackTop(), _numSlot - il->getFixedSlotNum(), 0);

	// 関数返答値の作成
	_valFuncRes = new EsValue();

	return true;
}
Exemple #6
0
void setGCStateCurrentThreadAndStack (GC_state s) {
  GC_thread thread;
  GC_stack stack;

  thread = getThreadCurrent (s);
  s->exnStack = thread->exnStack;
  stack = getStackCurrent (s);
  s->stackBottom = getStackBottom (s, stack);
  s->stackTop = getStackTop (s, stack);
  s->stackLimit = getStackLimit (s, stack);
  markCard (s, (pointer)stack);
}
/*---------------------------------------------------------------------*//**
	with ブロックに入る ⇒ js_EnterWith
**//*---------------------------------------------------------------------*/
bool EsStackFrame::enterWithBlock(EsContext* ctx, s32 indexStack)
{
	EsValue* sp = _regs->sp(0);
	ASSERT(indexStack < 0);
	ASSERT(getStackTop() <= (sp + indexStack));

	EsObject* obj;
	if(!sp[-1].isPrimitive())
	{
		ASSERT(sp[-1].isObject());
		obj = sp[-1].getObject();
	}
	else
	{
		if(!ctx->convValueToObject(&obj, &sp[-1]))
		{
			return false;
		}
		sp[-1].setValue(obj);
	}

	EsObject* objParent = makeScopeChainObject(ctx);
	if(objParent == 0L)
	{
		return false;
	}

	// ※※※ 実装不要 ※※※ ⇒ OBJ_TO_INNER_OBJECT, JSExtendedClass, JSExtendedClass

	// with オブジェクトを作成する ⇒ js_NewWithObject(cx, obj, parent, sp + stackIndex - StackBase(fp));
	EsObject* objWith = ctx->newObject(EsWith::EsWithClass::getInstance(), obj, objParent);
	if(objWith == 0L)	{	return false;	}
	objWith->slots()->setPrivateData(this);
	s32 depth = (s32)(sp + indexStack - getStackTop());
	objWith->slots()->setBlockDepth(depth);	// ⇒ OBJ_SET_BLOCK_DEPTH(cx, obj, depth);

	setScopeChainObject(objWith);

	return true;
}
Exemple #8
0
// Go through BBs in dominance order, create new values for each definition,
// and replace all sources with their current new values.
//
// NOTE: The values generated for function inputs/outputs have no connection
// to their corresponding outputs/inputs in other functions. Only allocation
// of physical registers will establish this connection.
//
void RenamePass::search(BasicBlock *bb)
{
   LValue *lval, *ssa;
   int d, s;
   const Target *targ = prog->getTarget();

   // Put current definitions for function inputs values on the stack.
   // They can be used before any redefinitions are pushed.
   if (bb == BasicBlock::get(func->cfg.getRoot())) {
      for (std::deque<ValueDef>::iterator it = func->ins.begin();
           it != func->ins.end(); ++it) {
         lval = it->get()->asLValue();
         assert(lval);

         ssa = new_LValue(func, targ->nativeFile(lval->reg.file));
         ssa->reg.size = lval->reg.size;
         ssa->reg.data.id = lval->reg.data.id;

         it->setSSA(ssa);
         stack[lval->id].push(ssa);
      }
   }

   for (Instruction *stmt = bb->getFirst(); stmt; stmt = stmt->next) {
      // PHI sources get definitions from the passes through the incident BBs,
      // so skip them here.
      if (stmt->op != OP_PHI) {
         for (s = 0; stmt->srcExists(s); ++s) {
            lval = stmt->getSrc(s)->asLValue();
            if (!lval)
               continue;
            // Values on the stack created in previously visited blocks, and
            // function inputs, will be valid because they dominate this one.
            lval = getStackTop(lval);
            if (!lval)
               lval = mkUndefined(stmt->getSrc(s));
            stmt->setSrc(s, lval);
         }
      }
      for (d = 0; stmt->defExists(d); ++d) {
         lval = stmt->def(d).get()->asLValue();
         assert(lval);
         stmt->def(d).setSSA(
            new_LValue(func, targ->nativeFile(lval->reg.file)));
         stmt->def(d).get()->reg.size = lval->reg.size;
         stmt->def(d).get()->reg.data.id = lval->reg.data.id;
         stack[lval->id].push(stmt->def(d).get());
      }
   }

   // Update sources of PHI ops corresponding to this BB in outgoing BBs.
   for (Graph::EdgeIterator ei = bb->cfg.outgoing(); !ei.end(); ei.next()) {
      Instruction *phi;
      int p = 0;
      BasicBlock *sb = BasicBlock::get(ei.getNode());

      // which predecessor of sb is bb ?
      for (Graph::EdgeIterator ei = sb->cfg.incident(); !ei.end(); ei.next()) {
         if (ei.getNode() == &bb->cfg)
            break;
         ++p;
      }
      assert(p < sb->cfg.incidentCount());

      for (phi = sb->getPhi(); phi && phi->op == OP_PHI; phi = phi->next) {
         lval = getStackTop(phi->getSrc(p));
         if (!lval)
            lval = mkUndefined(phi->getSrc(p));
         phi->setSrc(p, lval);
      }
   }

   // Visit the BBs we dominate.
   for (Graph::EdgeIterator ei = bb->dom.outgoing(); !ei.end(); ei.next())
      search(BasicBlock::get(ei.getNode()));

   // Update function outputs to the last definitions of their pre-SSA values.
   // I hope they're unique, i.e. that we get PHIs for all of them ...
   if (bb == BasicBlock::get(func->cfgExit)) {
      for (std::deque<ValueRef>::iterator it = func->outs.begin();
           it != func->outs.end(); ++it) {
         lval = it->get()->asLValue();
         if (!lval)
            continue;
         lval = getStackTop(lval);
         if (!lval)
            lval = mkUndefined(it->get());
         it->set(lval);
      }
   }

   // Pop the values we created in this block from the stack because we will
   // return to blocks that we do not dominate.
   for (Instruction *stmt = bb->getFirst(); stmt; stmt = stmt->next) {
      if (stmt->op == OP_NOP)
         continue;
      for (d = 0; stmt->defExists(d); ++d)
         stack[stmt->def(d).preSSA()->id].pop();
   }
}
Exemple #9
0
/* dfsMarkByMode (s, r, m, shc, slw)
 *
 * Sets all the mark bits in the object graph pointed to by r.
 *
 * If m is MARK_MODE, it sets the bits to 1.
 * If m is UNMARK_MODE, it sets the bits to 0.
 *
 * If shc, it hash-conses the objects marked.
 *
 * If slw, it links the weak objects marked.
 *
 * It returns the total size in bytes of the objects marked.
 */
size_t dfsMarkByMode (GC_state s, pointer root,
                      GC_markMode mode,
                      bool shouldHashCons,
                      bool shouldLinkWeaks) {
  GC_header mark; /* Used to set or clear the mark bit. */
  size_t size; /* Total number of bytes marked. */
  pointer cur; /* The current object being marked. */
  pointer prev; /* The previous object on the mark stack. */
  pointer next; /* The next object to mark. */
  pointer todo; /* A pointer to the pointer in cur to next. */
  GC_header header;
  GC_header* headerp;
  uint16_t bytesNonObjptrs;
  uint16_t numObjptrs;
  GC_objectTypeTag tag;
  uint32_t objptrIndex; /* The i'th pointer in the object (element) being marked. */
  GC_header nextHeader;
  GC_header* nextHeaderp;
  GC_arrayCounter arrayIndex;
  pointer top; /* The top of the next stack frame to mark. */
  GC_returnAddress returnAddress;
  GC_frameLayout frameLayout;
  GC_frameOffsets frameOffsets;

  if (isPointerMarkedByMode (root, mode))
    /* Object has already been marked. */
    return 0;
  mark = (MARK_MODE == mode) ? MARK_MASK : 0;
  size = 0;
  cur = root;
  prev = NULL;
  headerp = getHeaderp (cur);
  header = *headerp;
  goto mark;
markNext:
  /* cur is the object that was being marked.
   * prev is the mark stack.
   * next is the unmarked object to be marked.
   * nextHeaderp points to the header of next.
   * nextHeader is the header of next.
   * todo is a pointer to the pointer inside cur that points to next.
   */
  if (DEBUG_DFS_MARK)
    fprintf (stderr,
             "markNext"
             "  cur = "FMTPTR"  next = "FMTPTR
             "  prev = "FMTPTR"  todo = "FMTPTR"\n",
             (uintptr_t)cur, (uintptr_t)next,
             (uintptr_t)prev, (uintptr_t)todo);
  assert (not isPointerMarkedByMode (next, mode));
  assert (nextHeaderp == getHeaderp (next));
  assert (nextHeader == getHeader (next));
  // assert (*(pointer*) todo == next);
  assert (fetchObjptrToPointer (todo, s->heap.start) == next);
  headerp = nextHeaderp;
  header = nextHeader;
  // *(pointer*)todo = prev;
  storeObjptrFromPointer (todo, prev, s->heap.start);
  prev = cur;
  cur = next;
mark:
  if (DEBUG_DFS_MARK)
    fprintf (stderr, "mark  cur = "FMTPTR"  prev = "FMTPTR"  mode = %s\n",
             (uintptr_t)cur, (uintptr_t)prev,
             (mode == MARK_MODE) ? "mark" : "unmark");
  /* cur is the object to mark.
   * prev is the mark stack.
   * headerp points to the header of cur.
   * header is the header of cur.
   */
  assert (not isPointerMarkedByMode (cur, mode));
  assert (header == getHeader (cur));
  assert (headerp == getHeaderp (cur));
  header ^= MARK_MASK;
  /* Store the mark.  In the case of an object that contains a pointer to
   * itself, it is essential that we store the marked header before marking
   * the internal pointers (markInNormal below).  If we didn't, then we
   * would see the object as unmarked and traverse it again.
   */
  *headerp = header;
  splitHeader (s, header, &tag, NULL, &bytesNonObjptrs, &numObjptrs);
  if (NORMAL_TAG == tag) {
    size +=
      GC_NORMAL_HEADER_SIZE
      + bytesNonObjptrs
      + (numObjptrs * OBJPTR_SIZE);
    if (0 == numObjptrs) {
      /* There is nothing to mark. */
normalDone:
      if (shouldHashCons)
        cur = hashConsPointer (s, cur, TRUE);
      goto ret;
    }
    todo = cur + bytesNonObjptrs;
    objptrIndex = 0;
markInNormal:
    if (DEBUG_DFS_MARK)
      fprintf (stderr, "markInNormal  objptrIndex = %"PRIu32"\n", objptrIndex);
    assert (objptrIndex < numObjptrs);
    // next = *(pointer*)todo;
    next = fetchObjptrToPointer (todo, s->heap.start);
    if (not isPointer (next)) {
markNextInNormal:
      assert (objptrIndex < numObjptrs);
      objptrIndex++;
      if (objptrIndex == numObjptrs) {
        /* Done.  Clear out the counters and return. */
        *headerp = header & ~COUNTER_MASK;
        goto normalDone;
      }
      todo += OBJPTR_SIZE;
      goto markInNormal;
    }
    nextHeaderp = getHeaderp (next);
    nextHeader = *nextHeaderp;
    if (mark == (nextHeader & MARK_MASK)) {
      if (shouldHashCons)
        shareObjptr (s, (objptr*)todo);
      goto markNextInNormal;
    }
    *headerp = (header & ~COUNTER_MASK) | (objptrIndex << COUNTER_SHIFT);
    goto markNext;
  } else if (WEAK_TAG == tag) {
    /* Store the marked header and don't follow any pointers. */
    if (shouldLinkWeaks) {
      GC_weak w;

      w = (GC_weak)(cur + offsetofWeak (s));
      if (DEBUG_WEAK)
        fprintf (stderr, "marking weak "FMTPTR" ",
                 (uintptr_t)w);
      if (isObjptr (w->objptr)) {
        if (DEBUG_WEAK)
          fprintf (stderr, "linking\n");
        w->link = s->weaks;
        s->weaks = w;
      } else {
        if (DEBUG_WEAK)
          fprintf (stderr, "not linking\n");
      }
    }
    goto ret;
  } else if (ARRAY_TAG == tag) {
    /* When marking arrays:
     *   arrayIndex is the index of the element to mark.
     *   cur is the pointer to the array.
     *   objptrIndex is the index of the pointer within the element
     *     (i.e. the i'th pointer is at index i).
     *   todo is the start of the element.
     */
    size +=
      GC_ARRAY_HEADER_SIZE
      + sizeofArrayNoHeader (s, getArrayLength (cur), bytesNonObjptrs, numObjptrs);
    if (0 == numObjptrs or 0 == getArrayLength (cur)) {
      /* There is nothing to mark. */
arrayDone:
      if (shouldHashCons)
        cur = hashConsPointer (s, cur, TRUE);
      goto ret;
    }
    /* Begin marking first element. */
    arrayIndex = 0;
    todo = cur;
markArrayElt:
    assert (arrayIndex < getArrayLength (cur));
    objptrIndex = 0;
    /* Skip to the first pointer. */
    todo += bytesNonObjptrs;
markInArray:
    if (DEBUG_DFS_MARK)
      fprintf (stderr, "markInArray arrayIndex = %"PRIxARRCTR" objptrIndex = %"PRIu32"\n",
               arrayIndex, objptrIndex);
    assert (arrayIndex < getArrayLength (cur));
    assert (objptrIndex < numObjptrs);
    assert (todo == indexArrayAtObjptrIndex (s, cur, arrayIndex, objptrIndex));
    // next = *(pointer*)todo;
    next = fetchObjptrToPointer (todo, s->heap.start);
    if (not (isPointer(next))) {
markNextInArray:
      assert (arrayIndex < getArrayLength (cur));
      assert (objptrIndex < numObjptrs);
      assert (todo == indexArrayAtObjptrIndex (s, cur, arrayIndex, objptrIndex));
      todo += OBJPTR_SIZE;
      objptrIndex++;
      if (objptrIndex < numObjptrs)
        goto markInArray;
      arrayIndex++;
      if (arrayIndex < getArrayLength (cur))
        goto markArrayElt;
      /* Done.  Clear out the counters and return. */
      *getArrayCounterp (cur) = 0;
      *headerp = header & ~COUNTER_MASK;
      goto arrayDone;
    }
    nextHeaderp = getHeaderp (next);
    nextHeader = *nextHeaderp;
    if (mark == (nextHeader & MARK_MASK)) {
      if (shouldHashCons)
        shareObjptr (s, (objptr*)todo);
      goto markNextInArray;
    }
    /* Recur and mark next. */
    *getArrayCounterp (cur) = arrayIndex;
    *headerp = (header & ~COUNTER_MASK) | (objptrIndex << COUNTER_SHIFT);
    goto markNext;
  } else {
    assert (STACK_TAG == tag);
    size +=
      GC_STACK_HEADER_SIZE
      + sizeof (struct GC_stack) + ((GC_stack)cur)->reserved;
    top = getStackTop (s, (GC_stack)cur);
    assert (((GC_stack)cur)->used <= ((GC_stack)cur)->reserved);
markInStack:
    /* Invariant: top points just past the return address of the frame
     * to be marked.
     */
    assert (getStackBottom (s, (GC_stack)cur) <= top);
    if (DEBUG_DFS_MARK)
      fprintf (stderr, "markInStack  top = %"PRIuMAX"\n",
               (uintmax_t)(top - getStackBottom (s, (GC_stack)cur)));
    if (top == getStackBottom (s, (GC_stack)(cur)))
      goto ret;
    objptrIndex = 0;
    returnAddress = *(GC_returnAddress*) (top - GC_RETURNADDRESS_SIZE);
    frameLayout = getFrameLayoutFromReturnAddress (s, returnAddress);
    frameOffsets = frameLayout->offsets;
    ((GC_stack)cur)->markTop = top;
markInFrame:
    if (objptrIndex == frameOffsets [0]) {
      top -= frameLayout->size;
      goto markInStack;
    }
    todo = top - frameLayout->size + frameOffsets [objptrIndex + 1];
    // next = *(pointer*)todo;
    next = fetchObjptrToPointer (todo, s->heap.start);
    if (DEBUG_DFS_MARK)
      fprintf (stderr,
               "    offset %u  todo "FMTPTR"  next = "FMTPTR"\n",
               frameOffsets [objptrIndex + 1],
               (uintptr_t)todo, (uintptr_t)next);
    if (not isPointer (next)) {
      objptrIndex++;
      goto markInFrame;
    }
    nextHeaderp = getHeaderp (next);
    nextHeader = *nextHeaderp;
    if (mark == (nextHeader & MARK_MASK)) {
      objptrIndex++;
      if (shouldHashCons)
        shareObjptr (s, (objptr*)todo);
      goto markInFrame;
    }
    ((GC_stack)cur)->markIndex = objptrIndex;
    goto markNext;
  }
  assert (FALSE);
ret:
  /* Done marking cur, continue with prev.
   * Need to set the pointer in the prev object that pointed to cur
   * to point back to prev, and restore prev.
   */
  if (DEBUG_DFS_MARK)
    fprintf (stderr, "return  cur = "FMTPTR"  prev = "FMTPTR"\n",
             (uintptr_t)cur, (uintptr_t)prev);
  assert (isPointerMarkedByMode (cur, mode));
  if (NULL == prev)
    return size;
  next = cur;
  cur = prev;
  headerp = getHeaderp (cur);
  header = *headerp;
  splitHeader (s, header, &tag, NULL, &bytesNonObjptrs, &numObjptrs);
  /* It's impossible to get a WEAK_TAG here, since we would never
   * follow the weak object pointer.
   */
  assert (WEAK_TAG != tag);
  if (NORMAL_TAG == tag) {
    todo = cur + bytesNonObjptrs;
    objptrIndex = (header & COUNTER_MASK) >> COUNTER_SHIFT;
    todo += objptrIndex * OBJPTR_SIZE;
    // prev = *(pointer*)todo;
    prev = fetchObjptrToPointer (todo, s->heap.start);
    // *(pointer*)todo = next;
    storeObjptrFromPointer (todo, next, s->heap.start);
    if (shouldHashCons)
      markIntergenerationalPointer (s, (pointer*)todo);
    goto markNextInNormal;
  } else if (ARRAY_TAG == tag) {