Example #1
0
	void VirtualMachine::execute(const InstructionList& script)
	{
	ScriptValue emptyVar;
	emptyVar.Flags   = ScriptValue::VariableRef;
	emptyVar.Type    = -2;
	emptyVar.Pointer = 0x0;
	std::map<std::string, ScriptValue>::iterator it;

	for(int i = 0; i < script.size(); ++i)
	{
		const Instruction& cmd = script[i];
		bool jump = true;
		switch(cmd.Type)
		{
			case PUSH:
				push(cmd.Value);
				break;
			case GETVAR:
				it = Variables.find(cmd.Name);
				if(it == Variables.end())
					it = Variables.emplace(cmd.Name, emptyVar).first;

				pushRef(&((*it).second));
				break;
			case EOL:
				//clearStack();
				break;
			case FUNCALL:
			{
				std::vector<int> arguments;
				arguments.reserve(cmd.NumArguments);
				for(int i = 0; i < cmd.NumArguments; ++i)
					arguments.push_back(peek(i).Type);
				
				FunctionDeclaration* fn = Environment->resolveFunctionCall(cmd.Name, arguments);
				
				if(fn)
					(*(fn->FnPtr))(this);
				else
				{
					std::cout << "RUNTIME ERROR: No function matching " <<  cmd.Name << "(";
					for(int i = 0; i < cmd.NumArguments; ++i)
					{
						if(i != 0) std::cout << ", ";
						std::cout << Config->NativeTypes[peek(i).Type].Name;
					}
					std::cout << ")" << std::endl;
				}
				break;
			}
			case OBJCALL:
			{
				std::vector<int> arguments;
				arguments.reserve(cmd.NumArguments);
				for(int i = 0; i < cmd.NumArguments; ++i)
					arguments.push_back(peek(i+1).Type);
				
				FunctionDeclaration* fn = Environment->resolveMethodCall(peek(0).Type, cmd.Name, arguments);
				
				if(fn)
					(*(fn->FnPtr))(this);
				else
				{
					std::cout << "RUNTIME ERROR: No function matching " <<  cmd.Name << "(";
					for(int i = 0; i < cmd.NumArguments; ++i)
					{
						if(i != 0) std::cout << ", ";
						std::cout << Config->NativeTypes[peek(1+i).Type].Name;
					}
					std::cout << ") in " << Config->NativeTypes[peek(0).Type].Name << std::endl;
				}
				break;
			}
			case SUBCALL:
			{
				int targetPos = -1;
				for(int j = 0; j < script.size(); ++j)
				{
					if(script[j].Type    == LABEL)
					if(script[j].LabelID == cmd.LabelID)
					{
						targetPos = j;
						break;
					}
				}
				if(targetPos != -1)
				{
					CallStack[CallStackPosition].ReturnAddress = i;
					CallStack[CallStackPosition].StackPosition = StackPosition;
					CallStackPosition++;
					i = targetPos;
				}
				break;
			}
			case SUBENTER:
			{
				int targetPos = -1;
				for(int j = i; j < script.size(); ++j)
				{
					if(script[j].Type    == LABEL)
					if(script[j].LabelID == cmd.LabelID)
					{
						targetPos = j;
						break;
					}
				}
				if(targetPos != -1)
				{
					CallStack[CallStackPosition].ReturnAddress = targetPos;
					CallStack[CallStackPosition].StackPosition = StackPosition;
					CallStackPosition++;
				}
				break;
			}
			case RETURN:
				if(CallStackPosition > 0)
				{
					ScriptValue retValue = pop();
					CallStackPosition--;
					i = CallStack[CallStackPosition].ReturnAddress;
					StackPosition = CallStack[CallStackPosition].StackPosition;
					push(retValue);
				}
				break;
			case JUMPTO:
			case JUMPIF:
			case JUMPIFN:
				     if(cmd.Type == JUMPTO ) jump =  true;
				else if(cmd.Type == JUMPIF ) jump =  pop().as<int>();
				else if(cmd.Type == JUMPIFN) jump = !pop().as<int>();
				if(jump)
				{
					int targetPos = -1;
					for(int j = 0; j < script.size(); ++j)
					{
						if(script[j].Type    == LABEL)
						if(script[j].LabelID == cmd.LabelID)
						{
							targetPos = j;
							break;
						}
					}
					if(targetPos != -1)
						i = targetPos;
				}
				break;
			case LABEL:
				// Ignore.
				break;
			default:
				std::cout << "Unimplemented Instruction " << cmd.Type << std::endl;
				break;
		}
	}
	}
/// <summary>Handle <c>ICorProfilerCallback::JITCompilationStarted</c></summary>
/// <remarks>The 'workhorse' </remarks>
HRESULT STDMETHODCALLTYPE CCodeInjection::JITCompilationStarted( 
        /* [in] */ FunctionID functionId, /* [in] */ BOOL fIsSafeToBlock) 
{
    ModuleID moduleId; mdToken funcToken;
    std::wstring methodName = GetMethodName(functionId, 
        moduleId, funcToken);
    ATLTRACE(_T("::JITCompilationStarted(%X -> %s)"), 
        functionId, W2CT(methodName.c_str()));

    if (L"ProfilerTarget.Program.OnMethodToInstrument" == methodName && 
        m_targetMethodRef !=0 ) {
        // get method body
        LPCBYTE pMethodHeader = NULL;
        ULONG iMethodSize = 0;
        COM_FAIL_RETURN(m_profilerInfo3->GetILFunctionBody(
            moduleId, funcToken, &pMethodHeader, &iMethodSize), 
            S_OK);

        CComPtr<IMetaDataEmit> metaDataEmit;
        COM_FAIL_RETURN(m_profilerInfo3->GetModuleMetaData(moduleId, 
            ofRead | ofWrite, IID_IMetaDataEmit, (IUnknown**)&metaDataEmit), S_OK);

        // parse IL
        Method instMethod((IMAGE_COR_ILMETHOD*)pMethodHeader); // <--
        instMethod.SetMinimumStackSize(3); // should be correct for this sample
        
        // NOTE: build signature (in the knowledge that the method we are instrumenting currently has no local vars)
        static COR_SIGNATURE localSignature[] = 
        {
            IMAGE_CEE_CS_CALLCONV_LOCAL_SIG,   
            0x02,                                   
            ELEMENT_TYPE_ARRAY, ELEMENT_TYPE_OBJECT, 01, 00, 00,  
            ELEMENT_TYPE_ARRAY, ELEMENT_TYPE_OBJECT, 01, 00, 00
        };
        
        mdSignature signature;
        COM_FAIL_RETURN(metaDataEmit->GetTokenFromSig(localSignature, sizeof(localSignature), &signature), S_OK);
        instMethod.m_header.LocalVarSigTok = signature;

        // insert new IL block
        InstructionList instructions; // NOTE: this IL will be different for an instance method or if the local vars signature is different
        instructions.push_back(new Instruction(CEE_NOP));
        instructions.push_back(new Instruction(CEE_LDC_I4_2));
        instructions.push_back(new Instruction(CEE_NEWARR, m_objectTypeRef));
        instructions.push_back(new Instruction(CEE_STLOC_1));
        instructions.push_back(new Instruction(CEE_LDLOC_1));
        instructions.push_back(new Instruction(CEE_LDC_I4_0));
        instructions.push_back(new Instruction(CEE_LDARG_0));
        instructions.push_back(new Instruction(CEE_STELEM_REF));
        instructions.push_back(new Instruction(CEE_LDLOC_1));
        instructions.push_back(new Instruction(CEE_LDC_I4_1));
        instructions.push_back(new Instruction(CEE_LDARG_1));
        instructions.push_back(new Instruction(CEE_STELEM_REF));
        instructions.push_back(new Instruction(CEE_LDLOC_1));
        instructions.push_back(new Instruction(CEE_STLOC_0));
        instructions.push_back(new Instruction(CEE_LDLOC_0));
        instructions.push_back(new Instruction(CEE_CALL, m_targetMethodRef));

        instMethod.InsertSequenceInstructionsAtOriginalOffset(
            0, instructions);

        instMethod.DumpIL();

        // allocate memory
        CComPtr<IMethodMalloc> methodMalloc;
        COM_FAIL_RETURN(m_profilerInfo3->GetILFunctionBodyAllocator(
            moduleId, &methodMalloc), S_OK);
        void* pNewMethod = methodMalloc->Alloc(instMethod.GetMethodSize());

        // write new method
        instMethod.WriteMethod((IMAGE_COR_ILMETHOD*)pNewMethod);
        COM_FAIL_RETURN(m_profilerInfo3->SetILFunctionBody(moduleId, 
            funcToken, (LPCBYTE) pNewMethod), S_OK);

        // update IL maps
        ULONG mapSize = instMethod.GetILMapSize();
        void* pMap = CoTaskMemAlloc(mapSize * sizeof(COR_IL_MAP));
        instMethod.PopulateILMap(mapSize, (COR_IL_MAP*)pMap);

        COM_FAIL_RETURN(m_profilerInfo3->SetILInstrumentedCodeMap(
            functionId, TRUE, mapSize, (COR_IL_MAP*)pMap), S_OK);
        CoTaskMemFree(pMap);
    }

    return S_OK;
}
Example #3
0
bool ThreadPlanStepRange::SetNextBranchBreakpoint() {
  if (m_next_branch_bp_sp)
    return true;

  Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
  // Stepping through ranges using breakpoints doesn't work yet, but with this
  // off we fall back to instruction
  // single stepping.
  if (!m_use_fast_step)
    return false;

  lldb::addr_t cur_addr = GetThread().GetRegisterContext()->GetPC();
  // Find the current address in our address ranges, and fetch the disassembly
  // if we haven't already:
  size_t pc_index;
  size_t range_index;
  InstructionList *instructions =
      GetInstructionsForAddress(cur_addr, range_index, pc_index);
  if (instructions == nullptr)
    return false;
  else {
    Target &target = GetThread().GetProcess()->GetTarget();
    uint32_t branch_index;
    branch_index =
        instructions->GetIndexOfNextBranchInstruction(pc_index, target);

    Address run_to_address;

    // If we didn't find a branch, run to the end of the range.
    if (branch_index == UINT32_MAX) {
      uint32_t last_index = instructions->GetSize() - 1;
      if (last_index - pc_index > 1) {
        InstructionSP last_inst =
            instructions->GetInstructionAtIndex(last_index);
        size_t last_inst_size = last_inst->GetOpcode().GetByteSize();
        run_to_address = last_inst->GetAddress();
        run_to_address.Slide(last_inst_size);
      }
    } else if (branch_index - pc_index > 1) {
      run_to_address =
          instructions->GetInstructionAtIndex(branch_index)->GetAddress();
    }

    if (run_to_address.IsValid()) {
      const bool is_internal = true;
      m_next_branch_bp_sp =
          GetTarget().CreateBreakpoint(run_to_address, is_internal, false);
      if (m_next_branch_bp_sp) {
        if (log) {
          lldb::break_id_t bp_site_id = LLDB_INVALID_BREAK_ID;
          BreakpointLocationSP bp_loc =
              m_next_branch_bp_sp->GetLocationAtIndex(0);
          if (bp_loc) {
            BreakpointSiteSP bp_site = bp_loc->GetBreakpointSite();
            if (bp_site) {
              bp_site_id = bp_site->GetID();
            }
          }
          log->Printf("ThreadPlanStepRange::SetNextBranchBreakpoint - Setting "
                      "breakpoint %d (site %d) to run to address 0x%" PRIx64,
                      m_next_branch_bp_sp->GetID(), bp_site_id,
                      run_to_address.GetLoadAddress(
                          &m_thread.GetProcess()->GetTarget()));
        }
        m_next_branch_bp_sp->SetThreadID(m_thread.GetID());
        m_next_branch_bp_sp->SetBreakpointKind("next-branch-location");
        return true;
      } else
        return false;
    }
  }
  return false;
}
Example #4
0
Value Interpreter::exec(const InstructionList &instructions, Bindings &bindings)
{
	Stack stack;
	ClosureValues closureValues;

	for(InstructionList::const_iterator it = instructions.begin() ; it != instructions.end() ; ++it)
	{
		Instruction::Type type = it->type();
		const Value &value = it->value();
		switch(type)
		{
		case Instruction::PUSH:
			if(settings_.trace)
			{				
				std::cout << "DEBUG: " << it->sourceLocation() << " push " << value << '\n';
			}
			stack.push_back(value);
			break;
		case Instruction::CALL:
			{
				if(settings_.trace)
				{
					std::cout << "DEBUG: " << it->sourceLocation() << " call " << value << '\n';
				}
				Value result = handleFunction(it->sourceLocation(), value, stack, bindings);
				stack.push_back(result);
				if(settings_.trace)
				{
					std::cout << "DEBUG: " << it->sourceLocation() << " return value " << result << '\n';
				}
			}
			break;
		case Instruction::JUMP:
			{
				int instructionsToSkip = getInstructionsToSkip(type, value);
				int remaining = instructions.end() - it;
				if(remaining < instructionsToSkip)
				{
					throw CompilerBug("insufficient instructions available to skip! (remaining: " + str(remaining) + " < instructionsToSkip: " + str(instructionsToSkip) + ")");
				}

				if(settings_.trace)
				{
					std::cout << "DEBUG: " << it->sourceLocation() << " jumping back " << instructionsToSkip << '\n';
				}
				it += instructionsToSkip;
			}
			break;
		case Instruction::LOOP:
			{
				int instructionsToSkip = getInstructionsToSkip(type, value);
				int instructionsAvailable = instructions.size(); // Note: signed type is important!
				if(instructionsAvailable < instructionsToSkip)
				{
					throw CompilerBug("insufficient instructions available to loop! (instructionsToSkip: " + str(instructionsToSkip) + " > instructions.size(): " + str(instructions.size()) + ")");
				}

				if(settings_.trace)
				{				
					std::cout << "DEBUG: " << it->sourceLocation() << " looping back " << instructionsToSkip << " instructions\n";
				}
				it -= instructionsToSkip;
			}
			break;
		case Instruction::CLOSE:
			{
				if(settings_.trace)
				{
					std::cout << "DEBUG: " << it->sourceLocation() << " close " << value << '\n';
				}
				Value result = handleClose(value, stack, closureValues, bindings);
				stack.push_back(result);
			}
			break;
		case Instruction::COND_JUMP:
			{
				if(stack.empty())
				{
					throw CompilerBug("empty stack when testing conditional jump");
				}
				int instructionsToSkip = getInstructionsToSkip(type, value);
				int remaining = instructions.end() - it;
				if(remaining < instructionsToSkip)
				{
					throw CompilerBug("insufficient instructions available to skip! (remaining: " + str(remaining) + " < instructionsToSkip: " + str(instructionsToSkip) + ")");
				}

				Value top = pop(stack);
				if(settings_.trace)
				{				
					std::cout << "DEBUG: " << it->sourceLocation() << " jumping back " << instructionsToSkip << " if " << top << '\n';
				}

				if(top.isFalsey())
				{
					it += instructionsToSkip;
				}
			}
			break;
		case Instruction::REF_LOCAL:
			handleRef(Bindings::Local, value, stack, bindings);
			if(settings_.trace)
			{
				std::cout << "DEBUG: " << it->sourceLocation() << " local ref '" << value.string() << "' is " << stack.back() << '\n';
			}
			break;
		case Instruction::INIT_LOCAL:
			{
				const Value &intialisedValue = handleInit(Bindings::Local, value, stack, bindings);
				if(settings_.trace)
				{
					std::cout << "DEBUG: " << it->sourceLocation() << " local init '" << value.string() << "' to " << intialisedValue << '\n';
				}
			}
			break;
		case Instruction::ASSIGN_LOCAL:
			{
				const Value &assignedValue = handleAssign(Bindings::Local, value, stack, bindings);
				if(settings_.trace)
				{
					std::cout << "DEBUG: " << it->sourceLocation() << " local assign '" << value.string() << "' to " << assignedValue << '\n';
				}
			}
			break;
		case Instruction::REF_GLOBAL:
			handleRef(Bindings::Global, value, stack, bindings);
			if(settings_.trace)
			{
				std::cout << "DEBUG: " << it->sourceLocation() << " global ref '" << value.string() << "' is " << stack.back() << '\n';
			}
			break;
		case Instruction::INIT_GLOBAL:
			{
				const Value &intialisedValue = handleInit(Bindings::Global, value, stack, bindings);
				if(settings_.trace)
				{
					std::cout << "DEBUG: " << it->sourceLocation() << " global init '" << value.string() << "' to " << intialisedValue << '\n';
				}
			}
			break;
		case Instruction::ASSIGN_GLOBAL:
			{
				const Value &assignedValue = handleAssign(Bindings::Global, value, stack, bindings);
				if(settings_.trace)
				{
					std::cout << "DEBUG: " << it->sourceLocation() << " global assign '" << value.string() << "' to " << assignedValue << '\n';
				}
			}
			break;
		case Instruction::REF_CLOSURE:
			handleRef(Bindings::Closure, value, stack, bindings);
			if(settings_.trace)
			{
				std::cout << "DEBUG: " << it->sourceLocation() << " closure ref '" << value.string() << "' is " << stack.back() << '\n';
			}
			break;
		case Instruction::INIT_CLOSURE:
			{
				Identifier identifier = Identifier(value.string());
				Bindings::ValuePtr &binding = bindings.getPointer(identifier);
				closureValues.push_back(ClosedNameAndValue(identifier, binding));
				if(settings_.trace)
				{
					std::cout << "DEBUG: " << it->sourceLocation() << " closure init '" << value.string() << "' is " << *binding << '\n';
				}
			}
			break;
		case Instruction::ASSIGN_CLOSURE:
			{
				const Value &assignedValue = handleAssign(Bindings::Closure, value, stack, bindings);
				if(settings_.trace)
				{
					std::cout << "DEBUG: " << it->sourceLocation() << " closure assign '" << value.string() << "' to " << assignedValue << '\n';
				}
			}
			break;
		case Instruction::MEMBER_ACCESS:
			{
				if(settings_.trace)
				{
					std::cout << "DEBUG: " << it->sourceLocation() << " member access " << value << '\n';
				}
				assert(value.isString());
				const std::string &memberName = value.string();

				Value top = pop(stack);
				if(!top.isObject())
				{
					throw ExecutionError(it->sourceLocation(), "Member access instruction requires an object but got " + str(top));
				}
				const Value::Object &object = top.object();
				Value::Object::const_iterator memberIterator = object.find(memberName);
				if (memberIterator == object.end())
				{
					throw ExecutionError(it->sourceLocation(), "Unknown member name " + memberName + " for " + str(top));
				}
				if(settings_.trace)
				{
					std::cout << "DEBUG: " << it->sourceLocation() << " member access " << value.string() << "." << memberName << " was " << memberIterator->second << '\n';
				}
				stack.push_back(memberIterator->second);
			}
			break;
		default:
			throw CompilerBug("unhandled instruction type: " + str(type));
		}

		if (settings_.trace)
		{
			if (stack.empty())
			{
				std::cout << "Stack is empty\n";
			}
			else
			{
				std::cout << "Stack contains " << stack.size() << " entries:\n";
				int index = 0;
				for(Stack::const_iterator it = stack.begin() ; it != stack.end() ; ++it)
				{
					++index;
					std::cout << index << ":  " << *it << '\n';
				}
			}

			if (closureValues.empty())
			{
				std::cout << "closureValues is empty\n";
			}
			else
			{
				std::cout << "closureValues contains " << closureValues.size() << " entries:\n";
				int index = 0;
				for(const ClosedNameAndValue &closedValue: closureValues)
				{
					++index;
					std::cout << index << ":  " << closedValue.first << " -> " << *closedValue.second << " @ " << closedValue.second << '\n';
				}
			}
		}
	}
	
	return stack.empty() ? Value::nil() : pop(stack);
}