Пример #1
0
    uint64_t VTable::bytesUsed() const
    {
        uint64_t bytesUsed = sizeof(VTable);

        if(ivtable != NULL)
            bytesUsed += ivtable->bytesUsed();

        const TraitsBindingsp td = traits->getTraitsBindings();
        const uint32_t n = td->methodCount;
        const uint32_t baseMethodCount = base ? td->base->methodCount : 0;
        bytesUsed += td->methodCount*sizeof(MethodInfo*);

        for (uint32_t i=0; i < n; i++)
        {
            MethodInfo* method = td->getMethod(i);

            if (i < baseMethodCount && td->base && method == td->base->getMethod(i))
            {
                continue;
            }
            else if(method != NULL)
            {
                bytesUsed += method->bytesUsed();
            }
        }
        return bytesUsed;
    }
Пример #2
0
 bool DebugStackFrame::setLocal(int which, Atom& val)
 {
     bool worked = false;
     if (trace->framep() && trace->info())
     {
         int firstLocal, pastLastLocal;
         localBounds(&firstLocal, &pastLastLocal);
         int count = pastLastLocal - firstLocal;
         if (count > 0 && which < count)
         {
             MethodInfo* info = trace->info();
             if (which == 0 && info->needRestOrArguments())
             {
                 // They are trying to modify the first local, but that is actually the special
                 // array for "...rest" or for "arguments".  That is too complicated to allow
                 // right now.  We're just going to fail the request.
             }
             else
             {
                 // copy the single arg over
                 info->unboxLocals(&val, 0, trace->types(), trace->framep(), firstLocal+which, 1);
                 worked = true;
             }
         }
     }
     return worked;
 }
Пример #3
0
	void DebugCLI::locals()
	{
		Atom* ptr;
		int count, line; 
		SourceInfo* src;
		DebugFrame* frame = core->debugger->frameAt(0);

		// source information
		frame->sourceLocation(src, line);

		// method
		MethodInfo* info = functionFor(src, line);
		if (info)
		{
			frame->arguments(ptr, count);
			for(int i=0; i<count; i++)
			{
				// write out the name
				if (info && (info->getLocalName(i) != core->kundefined) )
					core->console << info->getLocalName(i) << " = ";

				core->console << core->format(*ptr++);
				//if (i<count-1)
					core->console << "\n";
			}
		}
	}
Пример #4
0
	void DebugCLI::locals()
	{
		Atom* ptr;
		int count, line; 
		SourceInfo* src;
		DebugFrame* frame = core->debugger()->frameAt(0);

		// source information
		frame->sourceLocation(src, line);

		// method
		MethodInfo* info = functionFor(src, line);
		if (info)
		{
			frame->locals(ptr, count);
			for(int i=0; i<count; i++)
			{
				// write out the name
                Stringp nm = info->getLocalName(i);
                if (nm != core->kundefined) 
					core->console << nm;
                else
                    core->console << "<local_" << i << ">";
				core->console << " = " << core->format(*ptr++) << "\n";
			}
		}
	}
Пример #5
0
MethodInfo *Assembly::getStaticMethodInfo(const char *name)
{
    utArray<Type *> types;

    for (UTsize i = 0; i < modules.size(); i++)
    {
        modules.at(i)->getTypes(types);

        for (UTsize j = 0; j < types.size(); j++)
        {
            Type *type = types.at(j);

            MemberTypes types;
            types.method = true;
            utArray<MemberInfo *> members;
            type->findMembers(types, members);
            for (UTsize k = 0; k < members.size(); k++)
            {
                //TODO: this get's the first static main method, at compiler time
                // we need to verify only one entry per assembly

                MethodInfo *methodInfo = (MethodInfo *)members.at(k);
                if (methodInfo->isStatic() && !strcmp(methodInfo->getName(), name))
                {
                    return methodInfo;
                }
            }
        }

        types.clear();
    }

    return NULL;
}
Пример #6
0
void nsToolkit::RunPump(void* arg)
{
  int32		code;
  char		portname[64];
  ThreadInterfaceData id;
#ifdef DEBUG
  printf("TK-RunPump\n");
#endif
  ThreadInitInfo *info = (ThreadInitInfo*)arg;
  PR_EnterMonitor(info->monitor);

  gThreadState = PR_TRUE;

  PR_Notify(info->monitor);
  PR_ExitMonitor(info->monitor);

  delete info;

  // system wide unique names
  PR_snprintf(portname, sizeof(portname), "event%lx", 
              (long unsigned) PR_GetCurrentThread());

  port_id event = create_port(200, portname);

  while(read_port_etc(event, &code, &id, sizeof(id), B_TIMEOUT, 1000) >= 0)
  {
          MethodInfo *mInfo = (MethodInfo *)id.data;
          mInfo->Invoke();
          if(id.waitingThread != 0)
            resume_thread(id.waitingThread);
          delete mInfo;
  }
}
Пример #7
0
void Assembly::connectToDebugger(const char *host, int port)
{
    if (!vm)
    {
        LSError("Assembly::connectToDebugger called on uninitialized assembly");
    }

    Type *debuggerClient = vm->getType("system.debugger.DebuggerClient");

    if (!debuggerClient)
    {
        LSError("Unable to get system.debugger.DebuggerClient");
    }

    MethodInfo *method = debuggerClient->findMethodInfoByName("connect");

    if (!method)
    {
        LSError("Unable to get system.debugger.DebuggerClient.connect method");
    }

    lua_pushstring(vm->VM(), host);
    lua_pushnumber(vm->VM(), port);

    method->invoke(NULL, 2);
}
Пример #8
0
// After loading an ABC and inserting scripts into the verify queue,
// process the work queues until they are empty.
void BaseExecMgr::verifyEarly(Toplevel* toplevel, AbcEnv* abc_env)
{
    GCList<MethodInfo> verifyQueue2(core->GetGC(), kListInitialCapacity);
    int verified;
    do {
        verified = 0;
        while (!verifyTraitsQueue.isEmpty()) {
            Traits* t = verifyTraitsQueue.removeFirst();
            t->resolveSignatures(toplevel);
            TraitsBindingsp td = t->getTraitsBindings();
            enqFunction(t->init);
            for (int i=0, n=td->methodCount; i < n; i++)
                enqFunction(td->getMethod(i));
        }
        while (!verifyFunctionQueue.isEmpty()) {
            MethodInfo* f = verifyFunctionQueue.removeLast();
            if (!isVerified(f)) {
                if (f->declaringTraits()->init != f && f->declaringScope() == NULL) {
                    verifyQueue2.add(f);
                    continue;
                }
                verified++;
                //console << "pre verify " << f << "\n";
                verifyMethod(f, toplevel, abc_env);
                setVerified(f);
                if (config.verifyonly)
                    f->_invoker = verifyOnlyInvoker;
            }
        }
        while (!verifyQueue2.isEmpty())
            verifyFunctionQueue.add(verifyQueue2.removeLast());
    } while (verified > 0);
}
Пример #9
0
void Assembly::bootstrap()
{
    utArray<Type *> types;
    getTypes(types);

    Type *btype = vm->getType("system.Bootstrap");

    for (UTsize i = 0; i < types.size(); i++)
    {
        Type *type = types[i];

        if (type->getFullName() == "system.Null")
        {
            continue;
        }

        if (type->castToType(btype))
        {
            MemberInfo *mi = type->findMember("initialize");
            assert(mi);
            assert(mi->isMethod());

            MethodInfo *method = (MethodInfo *)mi;

            method->invoke(NULL, 0);
        }
    }
}
bool DataBus::GetClientMethodInfoResponsePacket::create(const quint8 source,
                                                        const quint8 destination,
                                                        const quint8 packetId,
                                                        const MethodInfo &methodInfo,
                                                        Packet *packet)
{
    // Check parameters
    if ((source == 0) ||
        (methodInfo.isValid() == false) ||
        (packet == 0))
    {
        // Error, invalid parameters
        return false;
    }

    // Create Header
    packet->setSource(source);
    packet->setDestination(destination);
    packet->setPacketType(PacketType_GetClientMethodInfoResponse);
    packet->setPacketId(packetId);

    // Create Payload
    QByteArray data;

    data.append(static_cast<char>(methodInfo.getId()));
    data.append(methodInfo.getName());
    data.append(static_cast<char>(methodInfo.getNoOfParameters()));
    data.append(static_cast<char>(methodInfo.getNoOfReturnValues()));

    packet->setData(data);

    // Success
    return true;
}
Пример #11
0
 Stringp Debugger::methodNameAt(DebugStackFrame* frame) {
     if (frame == NULL) return NULL;
     int line;
     SourceInfo* src = NULL;
     // source information
     frame->sourceLocation(src, line);
     MethodInfo* info = functionFor(src, line, frame);
     return  info ? info->getMethodName() : NULL;
 }
Пример #12
0
	void DebugCLI::bt()
	{
		//core->stackTrace->dump(core->console);
		//core->console << '\n';

		// obtain information about each frame 
		int frameCount = core->debugger()->frameCount();
		for(int k=0; k<frameCount; k++)
		{
			Atom* ptr;
			int count, line; 
			SourceInfo* src;
			DebugFrame* frame = core->debugger()->frameAt(k);

			// source information
			frame->sourceLocation(src, line);

			core->console << "#" << k << "   ";

			// this 
			Atom a = nullObjectAtom;
			frame->dhis(a);
			core->console << core->format(a) << ".";

			// method
			MethodInfo* info = functionFor(src, line);
			if (info)
				core->console << info->getMethodName();
			else
				core->console << "<unknown>";

			core->console << "(";

			// dump args
			frame->arguments(ptr, count);
			for(int i=0; i<count; i++)
			{
				// write out the name
                Stringp nm = info->getArgName(i);
				if (info && (nm != core->kundefined))
					core->console << nm << "=";

				core->console << core->format(*ptr++);
				if (i<count-1)
					core->console << ",";
			}
			core->console << ") at ";
			if (src)
				core->console << src->name();
			else
				core->console << "???";

			core->console << ":" << (line) << "\n";
		}
	}
Пример #13
0
void Assembly::execute()
{
    MethodInfo *method = getStaticMethodInfo("main");

    if (!method)
    {
        LSError("Unable to find main method in Assembly %s", getName().c_str());
    }

    method->invoke(NULL, 0);
}
Пример #14
0
void VerifyallWriter::writeOp1(const FrameState* state, const uint8_t *pc, AbcOpcode opcode, uint32_t opd1, Traits *type)
{
    if (opcode == OP_newfunction) {
        MethodInfo *f = pool->getMethodInfo(opd1);
        AvmAssert(f->declaringTraits() == type);
        exec->enqFunction(f);
        exec->enqTraits(type);
    }
    else if (opcode == OP_newclass) {
        exec->enqTraits(type);
        exec->enqTraits(type->itraits);
    }
    coder->writeOp1(state, pc, opcode, opd1, type);
}
Пример #15
0
Expression *TypeCompiler::visit(CallExpression *call)
{
    MethodBase *methodBase = call->methodBase;

    call->function->visitExpression(this);

    // check whether we're calling a methodbase
    if (methodBase)
    {
        lmAssert(methodBase->isMethod(), "Non-method called");

        MethodInfo *method = (MethodInfo *)methodBase;
        generateCall(&call->function->e, call->arguments, method);

        call->e = call->function->e;
    }
    else
    {
        lmAssert(call->function->type, "Untyped call");

        // if we're calling a delegate we need to load up the call method
        if (call->function->type->isDelegate())
        {
            MethodInfo *method = (MethodInfo *)call->function->type->findMember("call");
            lmAssert(method, "delegate with no call method");

            ExpDesc right;
            BC::initExpDesc(&right, VKNUM, 0);
            right.u.nval = method->getOrdinal();

            BC::expToNextReg(cs->fs, &call->function->e);
            BC::expToNextReg(cs->fs, &right);
            BC::expToVal(cs->fs, &right);
            BC::indexed(cs->fs, &call->function->e, &right);

            generateCall(&call->function->e, call->arguments, NULL);
            call->e = call->function->e;
        }
        else
        {
            // we're directly calling a local, instance (bound), or static method of type Function
            generateCall(&call->function->e, call->arguments, NULL);
            call->e = call->function->e;
        }
    }

    return call;
}
Пример #16
0
void nsToolkit::RunPump(void* arg)
{
  int32		code;
  char		portname[64];
  ThreadInterfaceData id;

  ThreadInitInfo *info = (ThreadInitInfo*)arg;
  PR_EnterMonitor(info->monitor);

  gThreadState = PR_TRUE;

  PR_Notify(info->monitor);
  PR_ExitMonitor(info->monitor);

  delete info;

  // system wide unique names
  PR_snprintf(portname, sizeof(portname), "event%lx", 
              (long unsigned) PR_GetCurrentThread());

  port_id event = create_port(100, portname);

  while(read_port(event, &code, &id, sizeof(id)) >= 0)
  {
    switch(code)
    {
      case WM_CALLMETHOD :
        {
          MethodInfo *mInfo = (MethodInfo *)id.data;
          mInfo->Invoke();
          if(id.waitingThread != 0)
            resume_thread(id.waitingThread);
          delete mInfo;
        }
        break;
      case 'natv' :	// native queue PLEvent
        {
          PREventQueue *queue = (PREventQueue *)id.data;
          PR_ProcessPendingEvents(queue);
        }
        break;

      default :
        printf("nsToolkit::RunPump - UNKNOWN EVENT\n");
        break;
    }
  }
}
Пример #17
0
 /**
  * Scans the pool object and pulls out information about the abc file
  * placing it in the AbcFile
  */
 void Debugger::scanResources(AbcFile* file, PoolObject* pool)
 {
     // walk all methods
     for(uint32_t i=0, n = pool->methodCount(); i<n; i++)
     {
         MethodInfo* f = pool->getMethodInfo(i);
         if (f->hasMethodBody())
         {
             // yes there is code for this method
             if (f->abc_body_pos())
             {
                 // if body_pos is null we havent got the body yet or
                 // this is an interface method
                 scanCode(file, pool, f);
             }
         }
     }
 }
Пример #18
0
 bool DebugStackFrame::setArgument(int which, Atom& val)
 {
     bool worked = false;
     if (trace->framep() && trace->info())
     {
         int firstArgument, pastLastArgument;
         argumentBounds(&firstArgument, &pastLastArgument);
         int count = pastLastArgument - firstArgument;
         if (count > 0 && which < count)
         {
             // copy the single arg over
             MethodInfo* info = trace->info();
             info->unboxLocals(&val, 0, trace->types(), trace->framep(), firstArgument+which, 1);
             worked = true;
         }
     }
     return worked;
 }
Пример #19
0
	MethodInfo* DebugCLI::functionFor(SourceInfo* src, int line)
	{
		MethodInfo* info = NULL;
		if (src)
		{
			// find the function at this location
			int size = src->functionCount();
			for(int i=0; i<size; i++)
			{
				MethodInfo* m = src->functionAt(i);
				if (line >= m->firstSourceLine() && line <= m->lastSourceLine())
				{
					info = m;
					break;
				}
			}
		}
		return info;
	}
Пример #20
0
void LSLuaState::invokeStaticMethod(const utString& typePath,
                                    const char *methodName, int numParameters)
{
    Type *type = getType(typePath.c_str());

    lmAssert(type, "LSLuaState::invokeStaticMethod unknown type: %s", typePath.c_str());

    MemberInfo *member = type->findMember(methodName);
    lmAssert(member, "LSLuaState::invokeStaticMethod unknown member: %s:%s", typePath.c_str(), methodName);
    if (!member->isMethod())
    {
        lmAssert(0, "LSLuaState::invokeStaticMethod member: %s:%s is not a method", typePath.c_str(), methodName);
    }

    MethodInfo *method = (MethodInfo *)member;

    lmAssert(method->isStatic(), "LSLuaState::invokeStaticMethod member: %s:%s is not a static method", typePath.c_str(), methodName);

    method->invoke(NULL, numParameters);
}
Пример #21
0
 Stringp Debugger::autoVarName(DebugStackFrame* frame, int index, AutoVarKind kind) {
     if (frame == NULL) return NULL;
     int line;
     SourceInfo* src = NULL;
     // source information
     frame->sourceLocation(src, line);
     MethodInfo* info = functionFor(src, line, frame);
     if (!info) return NULL;
     switch (kind) {
     case AUTO_LOCAL:
         return info->getLocalName(index);
     case AUTO_ARGUMENT:
         return info->getArgName(index);
     case AUTO_THIS:
         return NULL;
     default:
         AvmAssert(false);
     }
     return NULL;
 }
Пример #22
0
	// entry point when the first call to the method is late bound.
	/*static*/ Atom MethodInfo::verifyCoerceEnter(MethodEnv* env, int argc, Atom* args)
	{
		MethodInfo* f = env->method;

		#ifdef AVMPLUS_VERIFYALL
		// never verify late in verifyall mode
		AvmAssert(!f->pool()->core->config.verifyall);
		#endif

		f->verify(env->toplevel(), env->abcEnv());

#if VMCFG_METHODENV_IMPL32
		// we got here by calling env->_implGPR, which now is pointing to verifyEnter(),
		// but next time we want to call the real code, not verifyEnter again.
		// All other MethodEnv's in their default state will call the target method
		// directly and never go through verifyEnter().
		env->_implGPR = f->implGPR();
#endif

        AvmAssert(f->_invoker != MethodInfo::verifyCoerceEnter);
		return f->invoke(env, argc, args);
	}
Пример #23
0
    /**
     * @return a pointer to an object Atom whose members are
     * the active locals for this frame.
     */
    bool DebugStackFrame::locals(Atom*& ar, int& count)
    {
        bool worked = true;
        if (trace->framep() && trace->info())
        {
            int firstLocal, pastLastLocal;
            localBounds(&firstLocal, &pastLastLocal);
            count = pastLastLocal - firstLocal;
            AvmAssert(count >= 0);
            if ((count > 0) && debugger)
            {
                // frame looks like [this][param0...paramN][local0...localN]
                ar = (Atom*) debugger->core->GetGC()->Calloc(count, sizeof(Atom), GC::kContainsPointers|GC::kZero);
                MethodInfo* info = trace->info();
                info->boxLocals(trace->framep(), firstLocal, trace->types(), ar, 0, count);

                // If NEED_REST or NEED_ARGUMENTS is set, and the jit is being used, then the first
                // local is actually not an atom at all -- it is an ArrayObject*.  So, we need to
                // convert it to an atom.  (If the interpreter is being used instead of the jit, then
                // it is stored as an atom.)
                if (info->needRestOrArguments())
                {
                    int atomType = atomKind(ar[0]);
                    if (atomType == 0) // 0 is not a legal atom type, so ar[0] is not an atom
                    {
                        ScriptObject* obj = (ScriptObject*)ar[0];
                        ar[0] = obj->atom();
                    }
                }
            }
        }
        else
        {
            worked = false;
            count = 0;
        }
        return worked;
    }
Пример #24
0
 /**
  * @return a pointer to an object Atom whose members are
  * the arguments passed into a function for this frame
  */
 bool DebugStackFrame::arguments(Atom*& ar, int& count)
 {
     bool worked = true;
     if (trace->framep() && trace->info())
     {
         int firstArgument, pastLastArgument;
         argumentBounds(&firstArgument, &pastLastArgument);
         count = pastLastArgument - firstArgument;
         if ((count > 0) && debugger)
         {
             // pull the args into an array -- skip [0] which is [this]
             ar = (Atom*) debugger->core->GetGC()->Calloc(count, sizeof(Atom), GC::kContainsPointers|GC::kZero);
             MethodInfo* info = trace->info();
             info->boxLocals(trace->framep(), firstArgument, trace->types(), ar, 0, count);
         }
     }
     else
     {
         worked = false;
         count = 0;
     }
     return worked;
 }
Пример #25
0
 MethodInfo* Debugger::functionFor(SourceInfo* src, int line, DebugStackFrame* frame)
 {
     MethodInfo* info = NULL;
     if (src)
     {
         // find the function at this location
         int size = src->functionCount();
         for(int i=0; i<size; i++)
         {
             MethodInfo* m = src->functionAt(i);
             if (line >= m->firstSourceLine() && line <= m->lastSourceLine())
             {
                  info = m;
                  break;
             }
         }
     }
     if (!info && frame) {
          // fallback on frame info
          return frame->trace->info();
     }
     return info;
 }
Пример #26
0
MethodInfo *BinReader::readMethodInfo(Type *type)
{
    MethodInfo *methodInfo = lmNew(NULL) MethodInfo();

    methodInfo->declaringType = type;

    readMethodBase(methodInfo);

    Type *retType = NULL;
    if (bytes->readBoolean())
    {
        retType = getType(readPoolString());
    }

    methodInfo->memberType.method = true;
    methodInfo->type = getType("system.Function");

    if (retType)
    {
        methodInfo->setReturnType(retType);
    }

    return methodInfo;
}
Пример #27
0
void print_method(const MethodInfo &mi)
{
    std::cout << "\t    ";

    // display if the method is virtual
    if (mi.isVirtual())
        std::cout << "virtual ";

    // display the method's return type if defined
    if (mi.getReturnType().isDefined())
        std::cout << mi.getReturnType().getQualifiedName() << " ";
    else
        std::cout << "[UNDEFINED TYPE] ";

    // display the method's name
    std::cout << mi.getName() << "(";

    // display method's parameters
    const ParameterInfoList &params = mi.getParameters();
    for (ParameterInfoList::const_iterator k=params.begin(); k!=params.end(); ++k)
    {
        // get the ParameterInfo object that describes the 
        // current parameter
        const ParameterInfo &pi = **k;

        // display the parameter's modifier
        if (pi.isIn())
            std::cout << "IN";
        if (pi.isOut())
            std::cout << "OUT";
        if (pi.isIn() || pi.isOut())
            std::cout << " ";

        // display the parameter's type name
        if (pi.getParameterType().isDefined())
            std::cout << pi.getParameterType().getQualifiedName();

        // display the parameter's name if defined
        if (!pi.getName().empty())
            std::cout << " " << pi.getName();

        if ((k+1)!=params.end())
            std::cout << ", ";
    }
    std::cout << ")";
    if (mi.isConst())
        std::cout << " const";
    if (mi.isPureVirtual())
        std::cout << " = 0";
    std::cout << "\n";
}
Пример #28
0
    // increment the invocation counter, return true once method is compiled
    REALLY_INLINE bool OSR::countInvoke(MethodEnv* env)
    {
        MethodInfo* m = env->method;
        if (--m->_abc.countdown)
            return false;
        if (m->isInterpreted()) {
#ifdef AVMPLUS_VERBOSE
            if (m->pool()->isVerbose(VB_execpolicy))
                env->core()->console <<
                    "execpolicy jit hot-call " << env->method << "\n";
#endif
            AvmAssert(!m->hasFailedJit());
            BaseExecMgr* exec = BaseExecMgr::exec(env);
            exec->verifyJit(m, m->getMethodSignature(),
                            env->toplevel(), env->abcEnv(), NULL);
            if (m->hasFailedJit())
                return false;
        }
        // Method was already compiled; we got here because env->_implGPR
        // was not updated.  Update it now.
        env->_implGPR = env->method->_implGPR;
        return true;
    }
Пример #29
0
	void DebugCLI::set()
	{
		const char* what = nextToken();
		const char* equ = nextToken();
		const char* to = nextToken();
		if (!to || !equ || !what || *equ != '=')
		{
			core->console << " Bad format, should be:  'set {variable} = {value}' ";
		}
		else
		{
			// look for the varable in our locals or args.
			Atom* ptr;
			int count, line; 
			SourceInfo* src;
			DebugFrame* frame = core->debugger->frameAt(0);

			// source information
			frame->sourceLocation(src, line);
			if (!src)
			{
				core->console << "Unable to locate debug information for current source file, so no local or argument names known";
				return;
			}

			// method
			MethodInfo* info = functionFor(src, line);
			if (!info)
			{
				core->console << "Unable to find method debug information, so no local or argument names known";
				return;
			}

			frame->arguments(ptr, count);
			for(int i=0; i<count; i++)
			{
				Stringp arg = info->getArgName(i);
				if (arg->Equals(what)) 
				{
					// match!
					Atom a = ease2Atom(to, ptr[i]);
					if (a == undefinedAtom)
						core->console << " Type mismatch : current value is " << core->format(ptr[i]);
					else
						frame->setArgument(i, a);
					return;
				}
			}

			frame->locals(ptr, count);
			for(int i=0; i<count; i++)
			{
				Stringp local = info->getLocalName(i);
				if ( local->Equals(what)) 
				{
					// match!
					Atom a = ease2Atom(to, ptr[i]);
					if (a == undefinedAtom)
						core->console << " Type mismatch : current value is " << core->format(ptr[i]);
					else
						frame->setLocal(i, a);
					return;
				}
			}
		}
	}
Пример #30
0
    void Debugger::debugLine(int linenum)
    {
        AvmAssert( core->callStack !=0 );
        if (!core->callStack)
            return;

        AvmAssert(linenum > 0);

        int prev = core->callStack->linenum();
        core->callStack->set_linenum(linenum);

        int line = linenum;

        // line number has changed
        bool changed = (prev == line) ? false : true;
        bool exited =  (prev == -1) ? true : false; // are we being called as a result of function exit?
        if (!changed && !exited)
            return;  // still on the same line in the same function?

        Profiler* profiler = core->profiler();
        Sampler* s = core->get_sampler();
        if (profiler && profiler->profilingDataWanted && profiler->profileSwitch && !(s && s->sampling()))
        {
            profiler->sendLineTimestamp(line);
        }

        // tracing information
        if (!exited)
            traceLine(line);

        // check if we should stop due to breakpoint or step
        bool stop = false;
        if (stepState.flag)
        {
            if (stepState.startingDepth != -1 && core->callStack->depth() < stepState.startingDepth)
            {
                // We stepped out of whatever function was executing when the
                // stepInto/stepOver/stepOut command was executed.  We may be
                // in the middle of a line of code, but we still want to stop
                // immediately.  See bug 126633.
                stop = true;
            }
            else if (!exited && (stepState.depth == -1 || core->callStack->depth() <= stepState.depth) )
            {
                // We reached the beginning of a new line of code.
                stop = true;
            }
        }

        // we didn't decide to stop due to a step, but check if we hit a breakpoint
        if (!stop && !exited)
        {
            MethodInfo* f = core->callStack->info();
#ifdef VMCFG_AOT
            if (f && (f->hasMethodBody() || f->isCompiledMethod()))
#else
            if (f && f->hasMethodBody())
#endif
            {
                AbcFile* abc = f->file();
                if (abc)
                {
                    SourceFile* source = abc->sourceNamed( core->callStack->filename() );
                    if (source && source->hasBreakpoint(line))
                    {
                        stop = true;
                    }
                }
            }
        }

        // we still haven't decided to stop; check our watchpoints
        if (!stop && !exited)
        {
            if (hitWatchpoint())
                stop = true;
        }

        if (stop)
        {
            // Terminate whatever step operation may have been happening.  But first,
            // save the state of the step, so that if someone calls stepContinue(),
            // then we can restore it.
            StepState oldOldStepState = oldStepState; // save oldStepState in case of reentrancy
            oldStepState = stepState; // save stepState so that stepContinue() can find it
            stepState.clear(); // turn off stepping

            enterDebugger();

            oldStepState = oldOldStepState; // restore oldStepState
        }
    }