/*---------------------------------------------------------------------*//** ブロックオブジェクトを積む ⇒ 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; }
/* 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); /* 配列マークのルーチンへ */ } } } }
/** * 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; }
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; }
// 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(); } }
/* 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) {