static inline void addToCoreMap(std::map<std::pair<unsigned, unsigned>,Core*> &coreMap, SystemState &system) { for (SystemState::node_iterator it = system.node_begin(), e = system.node_end(); it != e; ++it) { addToCoreMap(coreMap, **it); } }
static void connectWaveformTracer(SystemState &system, WaveformTracer &waveformTracer) { for (SystemState::node_iterator outerIt = system.node_begin(), outerE = system.node_end(); outerIt != outerE; ++outerIt) { Node &node = **outerIt; for (Node::core_iterator innerIt = node.core_begin(), innerE = node.core_end(); innerIt != innerE; ++innerIt) { Core &core = **innerIt; connectWaveformTracer(core, waveformTracer); } } }
static inline void addToCoreMap(std::map<std::pair<unsigned, unsigned>,Core*> &coreMap, SystemState &system) { for (Node *node : system.getNodes()) { if (!node->isProcessorNode()) continue; addToCoreMap(coreMap, static_cast<ProcessorNode&>(*node)); } }
void LoggingTracer::dumpThreadSummary(const SystemState &system) { for (Node *node : system.getNodes()) { if (!node->isProcessorNode()) continue; for (Core *core : static_cast<ProcessorNode*>(node)->getCores()) { dumpThreadSummary(*core); } } }
static void connectWaveformTracer(SystemState &system, WaveformTracer &waveformTracer) { for (Node *node : system.getNodes()) { if (!node->isProcessorNode()) continue; for (Core *core : static_cast<ProcessorNode*>(node)->getCores()) { connectWaveformTracer(*core, waveformTracer); } } waveformTracer.finalizePorts(); }
void RootMovieClip::commitFrame(bool another) { setFramesLoaded(frames.size()); if(another) frames.push_back(Frame()); if(getFramesLoaded()==1 && frameRate!=0) { SystemState* sys = getSys(); if(this==sys) { /* now the frameRate is available and all SymbolClass tags have created their classes */ sys->addTick(1000/frameRate,sys); } else { this->incRef(); sys->currentVm->addEvent(NullRef, _MR(new InitFrameEvent(_MNR(this)))); } } }
static int runCores(SystemState &sys, const std::set<Core*> &cores, const std::map<Core*,uint32_t> &entryPoints) { for (std::set<Core*>::iterator it = cores.begin(), e = cores.end(); it != e; ++it) { Core *core = *it; sys.schedule(core->getThread(0)); std::map<Core*,uint32_t>::const_iterator match; if ((match = entryPoints.find(core)) != entryPoints.end()) { uint32_t entryPc = core->physicalAddress(match->second) >> 1; if (core->isValidPc(entryPc)) { core->getThread(0).pc = entryPc; } else { std::cout << "Warning: invalid ELF entry point 0x"; std::cout << std::hex << match->second << std::dec << "\n"; } } }
void LoggingTracer::attach(const SystemState &systemState) { symInfo = &systemState.getSymbolInfo(); }
void ABCVm::optimizeFunction(SyntheticFunction* function) { method_info* mi=function->mi; SystemState* sys = function->getSystemState(); ActivationType activationType(mi); istringstream code(mi->body->code); const int code_len=mi->body->code.size(); ostringstream out; u8 opcode; std::map<uint32_t, BasicBlock> basicBlocks; std::set<uint32_t> pendingBlocks; uint32_t curStart=0; BasicBlock* curBlock=NULL; basicBlocks.insert(make_pair(0,BasicBlock(NULL))); pendingBlocks.insert(0); //Create a map of addresses to fixups to rewrite the exception data: from, to and target for(uint32_t i=0;i<mi->body->exceptions.size();i++) { exception_info& ei=mi->body->exceptions[i]; //Also create a new basic block at the exception target address, //otherwise that code might be considered unreachable and lost if(basicBlocks.find(ei.target)==basicBlocks.end()) { BasicBlock* expBlock=&(basicBlocks.insert(make_pair(ei.target,BasicBlock(NULL))).first->second); //Those blocks starts with the exception on the stack expBlock->pushStack(Type::anyType); expBlock->initialStackTypes = expBlock->stackTypes; pendingBlocks.insert(ei.target); } } //Instructions map, useful to translate exceptions and validate just addresses std::map<uint32_t, uint32_t> instructionsMap; //Rewrite optimized code for faster execution, the new format is //uint8 opcode, [uint32 operand]* | [ASObject* pre resolved object] //Analize validity of basic blocks //Understand types of the values on the local scope stack //Optimize away getLex while(1) { uint32_t here=code.tellg(); uint32_t there=out.tellp(); if(curBlock && curStart!=here) { //Try to find the block for this instruction auto it=basicBlocks.find(here); if(it!=basicBlocks.end()) { if(it->second.realStart!=0xffffffff) { //Fall into an already translated block //Create a jump to it out << (uint8_t)0x10; writeInt32(out, 0xffffffff); there = out.tellp(); it->second.fixups.push_back(there-4); //End the current block, so that a pending one can be selected curBlock->realEnd=there; curBlock->originalEnd=here; curBlock=NULL; } else { BasicBlock* predBlock=curBlock; predBlock->realEnd=there; predBlock->originalEnd=here; curBlock=&(it->second); curBlock->realStart=there; curBlock->predBlocks.push_back(predBlock); curStart=it->first; } } } while(curBlock==NULL) { //If there is no currently active block search for the next pending one if(pendingBlocks.empty()) break; //It's possible that a pending block gets done while translating //the previous one, so check if the block has been already done auto it=pendingBlocks.begin(); uint32_t pendingStart=*it; pendingBlocks.erase(it); auto blockIt=basicBlocks.find(pendingStart); assert(blockIt!=basicBlocks.end()); if(blockIt->second.realStart==(0xffffffff)) { //The block has not been traslated yet curStart=pendingStart; curBlock=&blockIt->second; curBlock->realStart=there; code.seekg(curStart); here=curStart; } } if(curBlock==NULL) break; bool success=instructionsMap.insert(make_pair(here,there)).second; if(success==false) { //This instruction has been already added //it means that we discovered that a block starts here after the previous //block has been already translated by fallthrough //Solve the problem by invalidating the old block and adding it to the pending blocks auto it=basicBlocks.lower_bound(here); assert(it!=basicBlocks.begin()); it--; uint32_t nextBlockStart=it->second.originalEnd; uint32_t oldStart=it->first; it->second.resetCode(); pendingBlocks.insert(oldStart); //Delete all instructions in the deleted block from the instructionsMap auto instructionsMapStart=instructionsMap.lower_bound(oldStart); auto instructionsMapEnd=instructionsMap.lower_bound(nextBlockStart); instructionsMap.erase(instructionsMapStart,instructionsMapEnd); } code >> opcode; if(code.eof()) { //As the code has ended we must be in no block if(curBlock==NULL) break; else throw ParseException("End of code in optimizer"); } assert(curBlock); switch(opcode) { case 0x02: { //nop break; } case 0x03: { //throw curBlock->popStack(1); out << (uint8_t)opcode; curBlock->realEnd=out.tellp(); curBlock->originalEnd=code.tellg(); curBlock=NULL; break; } case 0x04: { //getsuper u30 t; code >> t; int numRT=mi->context->getMultinameRTData(t); curBlock->popStack(numRT+1); curBlock->pushStack(Type::anyType); out << (uint8_t)opcode; writeInt32(out, t); break; } case 0x05: { //setsuper u30 t; code >> t; int numRT=mi->context->getMultinameRTData(t); curBlock->popStack(numRT+2); out << (uint8_t)opcode; writeInt32(out, t); break; } case 0x06: { //dxns u30 t; code >> t; out << (uint8_t)opcode; writeInt32(out, t); break; } case 0x07: { //dxnslate curBlock->popStack(1); out << (uint8_t)opcode; break; } case 0x08: { //kill u30 t; code >> t; out << (uint8_t)opcode; writeInt32(out, t); break; } case 0x09: { //label //Create a new basic block BasicBlock* predBlock=curBlock; predBlock->realEnd=there; int here=code.tellg(); predBlock->originalEnd=here; curStart=here-1; curBlock=&(basicBlocks.insert(make_pair(curStart,BasicBlock(predBlock))).first->second); curBlock->realStart=there; curBlock->predBlocks.push_back(predBlock); break; } case 0x0c: case 0x0d: case 0x0e: case 0x0f: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: case 0x18: case 0x19: case 0x1a: { //ifnlt //ifnle //ifngt //ifnge //ifeq //ifne //iflt //ifle //ifgt //ifge //ifstricteq //ifstrictne s24 t; code >> t; curBlock->popStack(2); BasicBlock* const predBlock=curBlock; uint32_t oldStart=curStart; //The new block starts after this function int here=code.tellg(); verifyBranch(pendingBlocks,basicBlocks,oldStart,here,t,code_len); out << (uint8_t)opcode; writeBranchAddress(basicBlocks, here, t, out); predBlock->realEnd=out.tellp(); predBlock->originalEnd=here; auto it=basicBlocks.find(curStart); if(it==basicBlocks.end()) { curStart=here; curBlock=&(basicBlocks.insert(make_pair(curStart,BasicBlock(predBlock))).first->second); curBlock->predBlocks.push_back(predBlock); curBlock->realStart=out.tellp(); } //If the fall through block alredy exists, just go on //A jump will be added when the fallthrough is detected break; } case 0x10: { //jump s24 t; code >> t; //The new block starts after this function int here=code.tellg(); verifyBranch(pendingBlocks,basicBlocks,curStart,here,t,code_len); out << (uint8_t)opcode; writeBranchAddress(basicBlocks, here, t, out); //Reset the block to NULL curBlock->realEnd=out.tellp(); curBlock->originalEnd=here; curBlock=NULL; break; } case 0x11: case 0x12: { //iftrue //iffalse s24 t; code >> t; curBlock->popStack(1); BasicBlock* const predBlock=curBlock; predBlock->realEnd=there; uint32_t oldStart=curStart; //The new block starts after this function int here=code.tellg(); verifyBranch(pendingBlocks,basicBlocks,oldStart,here,t,code_len); out << (uint8_t)opcode; writeBranchAddress(basicBlocks, here, t, out); predBlock->realEnd=out.tellp(); predBlock->originalEnd=here; auto it=basicBlocks.find(curStart); if(it==basicBlocks.end()) { curStart=here; curBlock=&(basicBlocks.insert(make_pair(curStart,BasicBlock(predBlock))).first->second); curBlock->predBlocks.push_back(predBlock); curBlock->realStart=out.tellp(); } //If the fall through block alredy exists, just go on //A jump will be added when the fallthrough is detected break; } case 0x1b: { //lookupswitch int here=int(code.tellg())-1; //Base for the jumps is the instruction itself for the switch s24 t; code >> t; u30 count; code >> count; s24* offsets=g_newa(s24, count+1); for(unsigned int i=0;i<count+1;i++) code >> offsets[i]; curBlock->popStack(1); //Verify default branch and output it's translation verifyBranch(pendingBlocks,basicBlocks,curStart,here,t,code_len); out << (uint8_t)opcode; writeBranchAddress(basicBlocks, here, t, out); //Verify other branches and output their translations for(unsigned i=0;i<(count+1);i++) verifyBranch(pendingBlocks,basicBlocks,curStart,here,offsets[i],code_len); writeInt32(out, count); for(unsigned i=0;i<(count+1);i++) writeBranchAddress(basicBlocks,here, (int)offsets[i], out); curBlock->realEnd=out.tellp(); curBlock->originalEnd=code.tellg(); curBlock=NULL; break; } case 0x1c: { //pushwith curBlock->popStack(1); curBlock->pushScopeStack(Type::anyType); out << (uint8_t)opcode; break; } case 0x1d: { //popscope curBlock->popScopeStack(); out << (uint8_t)opcode; break; } case 0x1e: { //nextname curBlock->popStack(2); curBlock->pushStack(Type::anyType); out << (uint8_t)opcode; break; } case 0x20: { //pushnull ASObject* ret=sys->getNullRef(); //We don't really need a reference to it ret->decRef(); curBlock->pushStack(InferenceData(ret)); out << (uint8_t)opcode; break; } case 0x21: { //pushundefined curBlock->pushStack(Type::anyType); out << (uint8_t)opcode; break; } case 0x23: { //nextvalue curBlock->popStack(2); curBlock->pushStack(Type::anyType); out << (uint8_t)opcode; break; } case 0x24: { //pushbyte int8_t t; code.read((char*)&t,1); out << (uint8_t)opcode; out << t; curBlock->pushStack(Class<Integer>::getClass(sys)); break; } case 0x25: { //pushshort // specs say pushshort is a u30, but it's really a u32 // see https://bugs.adobe.com/jira/browse/ASC-4181 u32 t; code >> t; out << (uint8_t)opcode; writeInt32(out, t); curBlock->pushStack(Class<Integer>::getClass(sys)); break; } case 0x26: { //pushtrue out << (uint8_t)opcode; curBlock->pushStack(Class<Boolean>::getClass(sys)); break; } case 0x27: { //pushfalse out << (uint8_t)opcode; curBlock->pushStack(Class<Boolean>::getClass(sys)); break; } case 0x28: { //pushnan out << (uint8_t)opcode; curBlock->pushStack(Type::anyType); break; } case 0x29: { //pop out << (uint8_t)opcode; curBlock->popStack(1); break; } case 0x2a: { //dup out << (uint8_t)opcode; InferenceData data=curBlock->peekStack(); curBlock->popStack(1); curBlock->pushStack(data); curBlock->pushStack(data); break; } case 0x2b: { //swap out << (uint8_t)opcode; curBlock->popStack(2); curBlock->pushStack(Type::anyType); curBlock->pushStack(Type::anyType); break; } case 0x2c: { //pushstring u30 t; code >> t; out << (uint8_t)opcode; writeInt32(out, t); curBlock->pushStack(Type::anyType); break; } case 0x2d: { //pushint u30 t; code >> t; //TODO: collabpse on pushshort s32 val=mi->context->constant_pool.integer[t]; out << (uint8_t)opcode; writeInt32(out, val); curBlock->pushStack(Class<Integer>::getClass(sys)); break; } case 0x2e: { //pushuint u30 t; code >> t; u32 val=mi->context->constant_pool.uinteger[t]; out << (uint8_t)opcode; writeInt32(out, val); curBlock->pushStack(Class<Integer>::getClass(sys)); break; } case 0x2f: { //pushdouble u30 t; code >> t; double val=mi->context->constant_pool.doubles[t]; out << (uint8_t)opcode; writeDouble(out, val); curBlock->pushStack(Class<Number>::getClass(sys)); break; } case 0x30: { //pushscope InferenceData t=curBlock->peekStack(); curBlock->popStack(1); curBlock->pushScopeStack(t); out << (uint8_t)opcode; break; } case 0x31: { //pushnamespace u30 t; code >> t; out << (uint8_t)opcode; writeInt32(out,t); curBlock->pushStack(Type::anyType); break; } case 0x32: { //hasnext2 u30 t,t2; code >> t; code >> t2; out << (uint8_t)opcode; writeInt32(out,t); writeInt32(out,t2); curBlock->pushStack(Class<Boolean>::getClass(sys)); break; } //Alchemy opcodes case 0x35: case 0x36: case 0x37: { //li8 //li16 //li32 out << (uint8_t)opcode; curBlock->popStack(1); curBlock->pushStack(Class<Integer>::getClass(sys)); break; } case 0x3a: case 0x3b: case 0x3c: { //si8 //si16 //si32 out << (uint8_t)opcode; curBlock->popStack(2); break; } case 0x40: { //newfunction u30 t; code >> t; out << (uint8_t)opcode; writeInt32(out,t); curBlock->pushStack(Type::anyType); break; } case 0x41: { //call u30 t; code >> t; out << (uint8_t)opcode; writeInt32(out,t); curBlock->popStack(t+2); curBlock->pushStack(Type::anyType); break; } case 0x42: { //construct u30 t; code >> t; out << (uint8_t)opcode; writeInt32(out,t); curBlock->popStack(t+1); curBlock->pushStack(Type::anyType); break; } case 0x4a: { //constructprop u30 t,t2; code >> t; code >> t2; out << (uint8_t)opcode; writeInt32(out,t); writeInt32(out,t2); int numRT=mi->context->getMultinameRTData(t); curBlock->popStack(numRT+t2+1); curBlock->pushStack(Type::anyType); break; } case 0x45: case 0x46: case 0x4c: //callproplex seems to be exactly like callproperty { //callsuper //callproperty u30 t,t2; code >> t; code >> t2; out << (uint8_t)opcode; writeInt32(out,t); writeInt32(out,t2); int numRT=mi->context->getMultinameRTData(t); curBlock->popStack(numRT+t2); InferenceData baseData=curBlock->peekStack(); //Try to infer the return type InferenceData inferredData; if(baseData.isValid() && numRT==0) { const multiname* name=mi->context->getMultiname(t,NULL); if(baseData.type) { const Class_base* objType=dynamic_cast<const Class_base*>(baseData.type); if(objType) { const variable* var=objType->findBorrowedGettable(*name); if(var && var->var && var->var->getObjectType()==T_FUNCTION) { SyntheticFunction* calledFunc=dynamic_cast<SyntheticFunction*>(var->var); if(calledFunc) inferredData.type=calledFunc->mi->returnType; } } } } //The object is the last thing in the stack curBlock->popStack(1); curBlock->pushStack(inferredData); break; } case 0x47: { //returnvoid out << (uint8_t)opcode; curBlock->realEnd=out.tellp(); curBlock->originalEnd=code.tellg(); curBlock=NULL; break; } case 0x48: { //returnvalue out << (uint8_t)opcode; curBlock->popStack(1); curBlock->realEnd=out.tellp(); curBlock->originalEnd=code.tellg(); curBlock=NULL; break; } case 0x49: { //constructsuper u30 t; code >> t; out << (uint8_t)opcode; writeInt32(out,t); curBlock->popStack(t+1); break; } case 0x4e: case 0x4f: { //callsupervoid //callpropvoid u30 t,t2; code >> t; code >> t2; out << (uint8_t)opcode; writeInt32(out,t); writeInt32(out,t2); int numRT=mi->context->getMultinameRTData(t); curBlock->popStack(numRT+1+t2); break; } case 0x53: { //constructgenerictype u30 t; code >> t; out << (uint8_t)opcode; writeInt32(out,t); curBlock->popStack(t+1); curBlock->pushStack(Type::anyType); break; } case 0x55: { //newobject u30 t; code >> t; out << (uint8_t)opcode; writeInt32(out,t); curBlock->popStack(t*2); curBlock->pushStack(Type::anyType); break; } case 0x56: { //newarray u30 t; code >> t; out << (uint8_t)opcode; writeInt32(out,t); curBlock->popStack(t); curBlock->pushStack(Type::anyType); break; } case 0x57: { //newactivation out << (uint8_t)opcode; curBlock->pushStack(&activationType); break; } case 0x58: { //newclass u30 t; code >> t; out << (uint8_t)opcode; writeInt32(out,t); curBlock->popStack(1); curBlock->pushStack(Type::anyType); break; } case 0x59: { //getdescendants u30 t; code >> t; out << (uint8_t)opcode; writeInt32(out,t); int numRT=mi->context->getMultinameRTData(t); curBlock->popStack(numRT+1); curBlock->pushStack(Type::anyType); break; } case 0x5a: { //newcatch u30 t; code >> t; out << (uint8_t)opcode; writeInt32(out,t); curBlock->pushStack(Type::anyType); break; } case 0x5d: { //findpropstrict u30 t; code >> t; int numRT=mi->context->getMultinameRTData(t); //No runtime multinames are accepted InferenceData inferredData; if(numRT==0 && function->isMethod()) { //Attempt early binding const multiname* name=mi->context->getMultiname(t,NULL); inferredData=earlyBindFindPropStrict(out, function, curBlock->scopeStackTypes, name); } curBlock->popStack(numRT); if(!inferredData.isValid()) { out << (uint8_t)opcode; writeInt32(out,t); } curBlock->pushStack(inferredData); break; } case 0x5e: { //findproperty u30 t; code >> t; out << (uint8_t)opcode; writeInt32(out,t); int numRT=mi->context->getMultinameRTData(t); curBlock->popStack(numRT); curBlock->pushStack(Type::anyType); break; } case 0x60: { //getlex u30 t; code >> t; int numRT=mi->context->getMultinameRTData(t); //No runtime multinames are accepted if(numRT) throw ParseException("Bad code in optimizer"); const multiname* name=mi->context->getMultiname(t,NULL); InferenceData inferredData; //Only methods can be early binded, anonymous functions do //not have a fixed function scope stack if(function->isMethod()) inferredData=earlyBindGetLex(out, function, curBlock->scopeStackTypes, name, t); if(!inferredData.isValid()) { //Early binding failed, use normal translation out << (uint8_t)opcode; writeInt32(out,t); } curBlock->pushStack(inferredData); break; } case 0x61: { //setproperty u30 t; code >> t; out << (uint8_t)opcode; writeInt32(out,t); int numRT=mi->context->getMultinameRTData(t); curBlock->popStack(numRT+2); break; } case 0x62: { //getlocal u30 i; code >> i; out << (uint8_t)opcode; writeInt32(out,i); const Type* t=getLocalType(function, i); curBlock->pushStack(t); break; } case 0x63: { //setlocal u30 i; code >> i; out << (uint8_t)opcode; writeInt32(out,i); curBlock->popStack(1); break; } case 0x64: { //getglobalscope out << (uint8_t)opcode; curBlock->pushStack(Type::anyType); break; } case 0x65: { //getscopeobject u30 t; code >> t; out << (uint8_t)opcode; writeInt32(out,t); //NOTE: getscopeobject only resolves the local part of the scope stack //not the one inherited curBlock->pushStack(curBlock->scopeStackTypes[t]); break; } case 0x66: { //getproperty u30 t; code >> t; out << (uint8_t)opcode; writeInt32(out,t); int numRT=mi->context->getMultinameRTData(t); curBlock->popStack(numRT+1); curBlock->pushStack(Type::anyType); break; } case 0x68: { //initproperty u30 t; code >> t; out << (uint8_t)opcode; writeInt32(out,t); int numRT=mi->context->getMultinameRTData(t); curBlock->popStack(numRT+2); break; } case 0x6a: { //deleteproperty u30 t; code >> t; out << (uint8_t)opcode; writeInt32(out,t); int numRT=mi->context->getMultinameRTData(t); curBlock->popStack(numRT+1); curBlock->pushStack(Class<Boolean>::getClass(sys)); break; } case 0x6c: { //getslot u30 t; code >> t; out << (uint8_t)opcode; writeInt32(out,t); curBlock->popStack(1); curBlock->pushStack(Type::anyType); break; } case 0x6d: { //setslot u30 t; code >> t; InferenceData valueData = curBlock->peekStack(); curBlock->popStack(1); InferenceData objData = curBlock->peekStack(); curBlock->popStack(1); if(objData.type) { const multiname* slotType = objData.type->resolveSlotTypeName(t); if(slotType) { ASObject* ret=mi->context->root->applicationDomain->getVariableByMultinameOpportunistic(*slotType); if(ret && ret->getObjectType()==T_CLASS) { Class_base* c=static_cast<Class_base*>(ret); if(valueData.isOfType(c)) { //We know the value is already of the right type //Let's skip coercion out << (uint8_t)SET_SLOT_NO_COERCE; writeInt32(out,t); break; } } } } //If we did not manage to optimize the call, translate it directly out << (uint8_t)opcode; writeInt32(out,t); break; } case 0x70: case 0x71: case 0x72: case 0x85: case 0x95: { //convert_s //esc_xelem //esc_xattr //coerce_s //typeof out << (uint8_t)opcode; curBlock->popStack(1); curBlock->pushStack(Class<ASString>::getClass(sys)); break; } case 0x73: { //convert_i out << (uint8_t)opcode; curBlock->popStack(1); curBlock->pushStack(Class<Integer>::getClass(sys)); break; } case 0x74: { //convert_u out << (uint8_t)opcode; curBlock->popStack(1); curBlock->pushStack(Class<UInteger>::getClass(sys)); break; } case 0x75: { //convert_d out << (uint8_t)opcode; curBlock->popStack(1); curBlock->pushStack(Class<Number>::getClass(sys)); break; } case 0x76: { //convert_b out << (uint8_t)opcode; curBlock->popStack(1); curBlock->pushStack(Class<Boolean>::getClass(sys)); break; } case 0x78: { //checkfilter //TODO: it may be optimized here out << (uint8_t)opcode; curBlock->popStack(1); curBlock->pushStack(Type::anyType); break; } case 0x80: { //coerce u30 t; code >> t; int numRT=mi->context->getMultinameRTData(t); //No runtime multinames are accepted if(numRT) throw ParseException("Bad code in optimizer"); InferenceData baseData=curBlock->peekStack(); const multiname* name=mi->context->getMultiname(t,NULL); Class_base* coerceToClass = NULL; InferenceData inferredData; //Try to resolve the type is it is already defined ASObject* ret=mi->context->root->applicationDomain->getVariableByMultinameOpportunistic(*name); if(ret && ret->getObjectType()==T_CLASS) { coerceToClass=static_cast<Class_base*>(ret); //Also extract the type information for later use if the type has been //already resolved inferredData.type = coerceToClass; } if(baseData.isOfType(coerceToClass)) { //We can skip the coercion break; } out << (uint8_t)opcode; //Translate coerce to a rewriting opcode //The pointer to the multiname will become the pointer to //the type after the first execution writePtr(out,name); curBlock->popStack(1); curBlock->pushStack(inferredData); break; } case 0x82: { //coerce_a out << (uint8_t)opcode; curBlock->popStack(1); curBlock->pushStack(Type::anyType); break; } case 0x86: { //astype u30 t; code >> t; out << (uint8_t)opcode; writeInt32(out,t); int numRT=mi->context->getMultinameRTData(t); //No runtime multinames are accepted if(numRT) throw ParseException("Bad code in optimizer"); //TODO: write the right type curBlock->popStack(1); curBlock->pushStack(Type::anyType); break; } case 0x87: { //astypelate out << (uint8_t)opcode; curBlock->popStack(2); curBlock->pushStack(Type::anyType); break; } case 0x90: case 0x91: case 0x93: { //negate //increment //decrement out << (uint8_t)opcode; curBlock->popStack(1); curBlock->pushStack(Class<Number>::getClass(sys)); break; } case 0x92: case 0x94: { //inclocal //declocal u30 t; code >> t; out << (uint8_t)opcode; writeInt32(out,t); break; } case 0x96: { //not out << (uint8_t)opcode; curBlock->popStack(1); curBlock->pushStack(Class<Boolean>::getClass(sys)); break; } case 0x97: case 0xc0: case 0xc1: case 0xc4: { //bitnot //increment_i //decrement_i //negate_i out << (uint8_t)opcode; curBlock->popStack(1); curBlock->pushStack(Class<Integer>::getClass(sys)); break; } case 0xa0: { //add out << (uint8_t)opcode; //TODO: some type inference may be done here curBlock->popStack(2); curBlock->pushStack(Type::anyType); break; } case 0xa1: case 0xa2: case 0xa3: case 0xa4: { //subtract //multiply //divide //modulo out << (uint8_t)opcode; curBlock->popStack(2); curBlock->pushStack(Class<Number>::getClass(sys)); break; } case 0xa5: case 0xa6: case 0xa7: case 0xa8: case 0xa9: case 0xaa: case 0xc5: case 0xc6: case 0xc7: { //lshift //rshift //urshift //bitand //bitor //bitxor //add_i //subtract_i //multiply_i out << (uint8_t)opcode; curBlock->popStack(2); curBlock->pushStack(Class<Integer>::getClass(sys)); break; } case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf: case 0xb0: case 0xb1: case 0xb3: case 0xb4: { //equals //strictequals //lessthan //lessequals //greaterthan //greaterequals //instanceof //istypelate //in out << (uint8_t)opcode; curBlock->popStack(2); curBlock->pushStack(Class<Boolean>::getClass(sys)); break; } case 0xb2: { //istype u30 t; code >> t; out << (uint8_t)opcode; writeInt32(out,t); int numRT=mi->context->getMultinameRTData(t); //No runtime multinames are accepted if(numRT) throw ParseException("Bad code in optimizer"); curBlock->popStack(1); curBlock->pushStack(Class<Boolean>::getClass(sys)); break; } case 0xc2: { //inclocal_i u30 t; code >> t; out << (uint8_t)opcode; writeInt32(out,t); break; } case 0xc3: { //declocal_i u30 t; code >> t; out << (uint8_t)opcode; writeInt32(out,t); break; } case 0xd0: case 0xd1: case 0xd2: case 0xd3: { //getlocal_n //TODO: collapse on getlocal out << (uint8_t)opcode; //Infer the type of the object when possible const Type* t=getLocalType(function, opcode-0xd0); curBlock->pushStack(t); break; } case 0xd4: case 0xd5: case 0xd6: case 0xd7: { //setlocal_n //TODO: collapse on setlocal out << (uint8_t)opcode; curBlock->popStack(1); break; } case 0xef: { //debug, ignore uint8_t debug_type; u30 index; uint8_t reg; u30 extra; code.read((char*)&debug_type,1); code >> index; code.read((char*)®,1); code >> extra; break; } case 0xf0: case 0xf1: { //debugline, ignore //debugfile, ignore u30 t; code >> t; break; } default: LOG(LOG_ERROR,_("Not optimizable instruction @") << code.tellg()); LOG(LOG_ERROR,_("dump ") << hex << (unsigned int)opcode << dec); throw ParseException("Not implemented instruction in optimizer"); } } assert(!basicBlocks.empty()); //The original exception ranges must be translated to one //or more exception ranges as the blocks have been reordered uint32_t originalExceptionSize=mi->body->exceptions.size(); for(uint32_t i=0;i<originalExceptionSize;i++) { exception_info* ei=&mi->body->exceptions[i]; //Find out where the exception begins uint32_t excStart = ei->from; assert(instructionsMap.find(ei->target)!=instructionsMap.end()); assert(instructionsMap.find(ei->from)!=instructionsMap.end()); ei->target=instructionsMap.find(ei->target)->second; ei->from=instructionsMap.find(ei->from)->second; //Find out what block it starts into auto it=(--basicBlocks.upper_bound(excStart)); uint32_t lastRealEnd = it->second.realEnd; it++; //Find out if the reordered blocks are linear, //if not duplicate exception entry uint32_t originalEnd = ei->to; while(it!=basicBlocks.end() && it->first <= originalEnd) { if(it->second.realStart != lastRealEnd) { //Duplicate the exception ei->to = lastRealEnd; mi->body->exceptions.push_back(*ei); //Careful! ei is invalidated by now! ei=&mi->body->exceptions.back(); ei->from = it->second.realStart; } lastRealEnd = it->second.realEnd; ++it; } auto instructionIterator=instructionsMap.lower_bound(originalEnd); if(instructionIterator==instructionsMap.end() || instructionIterator->first!=originalEnd) { //If the to instruction has not been traslated, limit the range to the previous one --instructionIterator; } ei->to = instructionIterator->second; assert(ei->to >= ei->from); } //Loop over the basic blocks to do //1) branch fixups //3) consistency checks for(auto it=basicBlocks.begin();it!=basicBlocks.end();++it) { //Fixups const BasicBlock& bb=it->second; assert(bb.realStart!=0xffffffff); assert(bb.realEnd!=0xffffffff); assert(bb.originalEnd!=0xffffffff); for(uint32_t i=0;i<bb.fixups.size();i++) { uint32_t strOffset=bb.fixups[i]; out.seekp(strOffset); writeInt32(out, bb.realStart); } if(bb.predBlocks.size()==0) { //It may be the starting block or an exception handling block continue; } const vector<InferenceData>& predStackTypes=bb.predBlocks[0]->stackTypes; const vector<InferenceData>& predScopeStackTypes=bb.predBlocks[0]->scopeStackTypes; for(uint32_t i=0;i<bb.predBlocks.size();i++) { //TODO: should check //until then, silence warning about unused variables: (void) predStackTypes; (void) predScopeStackTypes; } } //Overwrite the old code mi->body->code=out.str(); mi->body->codeStatus = method_body_info::OPTIMIZED; }
int main(int argc, char* argv[]) { char* fileName=NULL; char* url=NULL; char* paramsFileName=NULL; #ifdef PROFILING_SUPPORT char* profilingFileName=NULL; #endif char *HTTPcookie=NULL; SecurityManager::SANDBOXTYPE sandboxType=SecurityManager::LOCAL_WITH_FILE; bool useInterpreter=true; bool useJit=false; bool exitOnError=false; LOG_LEVEL log_level=LOG_INFO; setlocale(LC_ALL, ""); #ifdef _WIN32 const char* localedir = getExectuablePath(); #else const char* localedir = "/usr/share/locale"; #endif bindtextdomain("lightspark", localedir); textdomain("lightspark"); LOG(LOG_INFO,"Lightspark version " << VERSION << " Copyright 2009-2012 Alessandro Pignotti and others"); //Make GTK thread enabled g_thread_init(NULL); gdk_threads_init(); //Give GTK a chance to parse its own options gtk_init (&argc, &argv); for(int i=1;i<argc;i++) { if(strcmp(argv[i],"-u")==0 || strcmp(argv[i],"--url")==0) { i++; if(i==argc) { fileName=NULL; break; } url=argv[i]; } else if(strcmp(argv[i],"-ni")==0 || strcmp(argv[i],"--disable-interpreter")==0) useInterpreter=false; else if(strcmp(argv[i],"-j")==0 || strcmp(argv[i],"--enable-jit")==0) useJit=true; else if(strcmp(argv[i],"-l")==0 || strcmp(argv[i],"--log-level")==0) { i++; if(i==argc) { fileName=NULL; break; } log_level=(LOG_LEVEL) min(4, max(0, atoi(argv[i]))); } else if(strcmp(argv[i],"-p")==0 || strcmp(argv[i],"--parameters-file")==0) { i++; if(i==argc) { fileName=NULL; break; } paramsFileName=argv[i]; } #ifdef PROFILING_SUPPORT else if(strcmp(argv[i],"-o")==0 || strcmp(argv[i],"--profiling-output")==0) { i++; if(i==argc) { fileName=NULL; break; } profilingFileName=argv[i]; } #endif else if(strcmp(argv[i],"-s")==0 || strcmp(argv[i],"--security-sandbox")==0) { i++; if(i==argc) { fileName=NULL; break; } if(strncmp(argv[i], "remote", 6) == 0) sandboxType = SecurityManager::REMOTE; else if(strncmp(argv[i], "local-with-filesystem", 21) == 0) sandboxType = SecurityManager::LOCAL_WITH_FILE; else if(strncmp(argv[i], "local-with-networking", 21) == 0) sandboxType = SecurityManager::LOCAL_WITH_NETWORK; else if(strncmp(argv[i], "local-trusted", 13) == 0) sandboxType = SecurityManager::LOCAL_TRUSTED; } else if(strcmp(argv[i],"-v")==0 || strcmp(argv[i],"--version")==0) { exit(0); } else if(strcmp(argv[i],"--exit-on-error")==0) { exitOnError = true; } else if(strcmp(argv[i],"--HTTP-cookies")==0) { i++; if(i==argc) { fileName=NULL; break; } HTTPcookie=argv[i]; } else { //No options flag, so set the swf file name if(fileName) //If already set, exit in error status { fileName=NULL; break; } fileName=argv[i]; } } if(fileName==NULL) { LOG(LOG_ERROR, "Usage: " << argv[0] << " [--url|-u http://loader.url/file.swf]" << " [--disable-interpreter|-ni] [--enable-jit|-j] [--log-level|-l 0-4]" << " [--parameters-file|-p params-file] [--security-sandbox|-s sandbox]" << " [--exit-on-error] [--HTTP-cookies cookie]" << #ifdef PROFILING_SUPPORT " [--profiling-output|-o profiling-file]" << #endif " <file.swf>"); exit(1); } #ifndef _WIN32 struct rlimit rl; getrlimit(RLIMIT_AS,&rl); rl.rlim_cur=400000000; rl.rlim_max=rl.rlim_cur; //setrlimit(RLIMIT_AS,&rl); #endif Log::setLogLevel(log_level); ifstream f(fileName, ios::in|ios::binary); f.seekg(0, ios::end); uint32_t fileSize=f.tellg(); f.seekg(0, ios::beg); if(!f) { LOG(LOG_ERROR, argv[0] << ": " << fileName << ": No such file or directory"); exit(2); } f.exceptions ( istream::eofbit | istream::failbit | istream::badbit ); cout.exceptions( ios::failbit | ios::badbit); cerr.exceptions( ios::failbit | ios::badbit); ParseThread* pt = new ParseThread(f); SystemState::staticInit(); EngineData::startGTKMain(); //NOTE: see SystemState declaration SystemState* sys =new SystemState(pt, fileSize); setTLSSys(sys); sys->setDownloadedPath(fileName); //This setting allows qualifying filename-only paths to fully qualified paths //When the URL parameter is set, set the root URL to the given parameter if(url) { sys->setOrigin(url, fileName); sandboxType = SecurityManager::REMOTE; } #ifndef _WIN32 //When running in a local sandbox, set the root URL to the current working dir else if(sandboxType != SecurityManager::REMOTE) { char * cwd = get_current_dir_name(); string cwdStr = string("file://") + string(cwd); free(cwd); cwdStr += "/"; sys->setOrigin(cwdStr, fileName); } #endif else { sys->setOrigin(string("file://") + fileName); LOG(LOG_INFO, _("Warning: running with no origin URL set.")); } //One of useInterpreter or useJit must be enabled if(!(useInterpreter || useJit)) { LOG(LOG_ERROR,_("No execution model enabled")); exit(1); } sys->useInterpreter=useInterpreter; sys->useJit=useJit; sys->exitOnError=exitOnError; if(paramsFileName) sys->parseParametersFromFile(paramsFileName); #ifdef PROFILING_SUPPORT if(profilingFileName) sys->setProfilingOutput(profilingFileName); #endif if(HTTPcookie) sys->setCookies(HTTPcookie); sys->setParamsAndEngine(new StandaloneEngineData(), true); sys->securityManager->setSandboxType(sandboxType); if(sandboxType == SecurityManager::REMOTE) LOG(LOG_INFO, _("Running in remote sandbox")); else if(sandboxType == SecurityManager::LOCAL_WITH_NETWORK) LOG(LOG_INFO, _("Running in local-with-networking sandbox")); else if(sandboxType == SecurityManager::LOCAL_WITH_FILE) LOG(LOG_INFO, _("Running in local-with-filesystem sandbox")); else if(sandboxType == SecurityManager::LOCAL_TRUSTED) LOG(LOG_INFO, _("Running in local-trusted sandbox")); sys->downloadManager=new StandaloneDownloadManager(); //Start the parser sys->addJob(pt); /* Destroy blocks until the 'terminated' flag is set by * SystemState::setShutdownFlag. */ sys->destroy(); delete pt; SystemState::staticDeinit(); EngineData::quitGTKMain(); return 0; }