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; }
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; }
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"; } } }
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"; } } }
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; }
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; } }
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); }
// 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); }
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; }
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; }
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"; } }
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); }
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); }
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; }
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; } } }
/** * 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); } } } }
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; }
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; }
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); }
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; }
// 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); }
/** * @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; }
/** * @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; }
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; }
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; }
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 ¶ms = 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"; }
// 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; }
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; } } } }
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 } }