void WordcodeEmitter::undoRelativeOffsetInJump()
	{
		AvmAssert(isJumpInstruction(O[nextI - 1]));
		AvmAssert(I[nextI - 1] + 2 == dest);
		
		uintptr_t offset = I[nextI - 1][1];
		if (offset == 0x80000000U) {
			// Forward branch, must find and nuke the backpatch
			backpatch_info *b = backpatches;
			backpatch_info *b2 = NULL;
			while (b != NULL && b->patch_loc != &I[nextI - 1][1])
				b2 = b, b = b->next;
			AvmAssert(b != NULL);
			if (b2 == NULL)
				backpatches = b->next;
			else
				b2->next = b->next;
			// b is unlinked
			// Install the ABC byte offset from the backpatch structure (will be positive)
			I[nextI - 1][1] = uint32_t(b->target_pc - code_start);
			delete b;
		}
		else {
			// Backward branch
			AvmAssert((int32_t)I[nextI - 1][1] < 0);
			// Install the negative of the absolute word offset of the target
			I[nextI - 1][1] = -int32_t(buffer_offset + (dest - buffers->data) + (int32_t)I[nextI - 1][1]);
		}
	}
Ejemplo n.º 2
0
/* test if the current instruction `instr' is a BT or a BF */
int isUnconditionalJump(t_axe_instruction *instr)
{
   if (isJumpInstruction(instr))
   {
      if ((instr->opcode == BT) || (instr->opcode == BF))
         return 1;
   }

   return 0;
}
	bool WordcodeEmitter::replace(uint32_t old_instr, uint32_t new_words, bool jump_has_been_translated) 
	{
		// Undo any relative offsets in the last instruction, if that wasn't done by
		// the commit code.

		if (isJumpInstruction(O[nextI - 1]) && !jump_has_been_translated)
			undoRelativeOffsetInJump();
		
		// Catenate unconsumed instructions onto R (it's easier than struggling with
		// moving instructions across buffer boundaries)

		uint32_t k = new_words;
		for ( uint32_t n=old_instr ; n < nextI ; n++ ) {
			uint32_t len = calculateInstructionWidth(O[n]);
			S[k] = O[n];
			for ( uint32_t j=0 ; j < len ; j++ )
				R[k++] = I[n][j];
		}
		
		// Unlink the last buffer segment if we took everything from it, push it onto
		// a reserve (there can only ever be one free).  We know I[nextI-1] points into the
		// current buffer, so check if I[0] is between the start of the buffer and
		// the last instruction.
		
		if (!(buffers->data <= I[0] && I[0] <= I[nextI-1])) {
			spare_buffer = buffers;
			buffers = buffers->next;
			spare_buffer->next = NULL;
			dest_limit = buffers->data + sizeof(buffers->data)/sizeof(buffers->data[0]);
			buffer_offset -= buffers->entries_used;
		}
		dest = I[0];
		
		// Emit the various instructions from new_data, handling branches specially.
		//
		// At this point the instance variables state, I, O, nextI, backtrack_stack,
		// and backtrack_idx are dead, and all the data we need for emitting the
		// instructions are in S and R.  In addition, dest has been rolled back and
		// points to the address of the first instruction in the peephole window, and
		// nothing is live in the code buffer beyond that point.  It's as if we are
		// in a context where we're just emitting instructions.
		//
		// Consequently, we set state to 0 and start emitting instructions from S/R
		// normally, calling peep() after each instruction that was not replaced by
		// the current action.  This works without having local copies of S and R
		// because peephole optimization cannot insert a replacement sequence that is 
		// longer than the matched sequence; so the segments of S and R used by any
		// recursive match will not affect what we're doing here.  Furthermore, 'dest'
		// is shared between this match and recursive matches, so if a recursive match
		// shortens the instruction sequence the correct value of dest will be used
		// when we get back to the present invocation of replace().

		// Reset the machine.
		
		state = 0;
		
		uint32_t i=0;
		while (i < k) {
			uintptr_t op = S[i];
			uintptr_t width = calculateInstructionWidth(op);
			CHECK(width);
			if (isJumpInstruction(op)) {
				*dest++ = R[i++];
				int32_t offset = int32_t(R[i++]);
				if (offset >= 0) {
					// Forward jump
					// Install a new backpatch structure
					makeAndInsertBackpatch(code_start + offset, uint32_t(buffer_offset + (dest + (width - 1) - buffers->data)));
				}
				else {
					// Backward jump
					// Compute new jump offset
					*dest = -int32_t(buffer_offset + (dest + (width - 1) - buffers->data) + offset);
					dest++;
				}
				if (width >= 3)
					*dest++ = R[i++];
				if (width >= 4)
					*dest++ = R[i++];
				AvmAssert(width <= 4);
			}
			else {
				switch (width) {
					default:
						AvmAssert(!"Can't happen");
					case 1:
						*dest++ = R[i++];
						break;
					case 2:
						*dest++ = R[i++];
						*dest++ = R[i++];
						break;
					case 3:
						*dest++ = R[i++];
						*dest++ = R[i++];
						*dest++ = R[i++];
						break;
					case 5:  // OP_debug
						*dest++ = R[i++];
						*dest++ = R[i++];
						*dest++ = R[i++];
						*dest++ = R[i++];
						*dest++ = R[i++];
						break;
				}
			}
			if (i-width >= new_words)
				peep((uint32_t)op, dest-width);
		}
		
		return true;  // always
	}
Ejemplo n.º 4
0
/* set the def-use values for the current node */
void setDefUses(t_cflow_Graph *graph, t_cflow_Node *node)
{
   t_axe_instruction *instr;
   t_cflow_var *varDest;
   t_cflow_var *varSource1;
   t_cflow_var *varSource2;

   /* preconditions */
   if (graph == NULL) {
      cflow_errorcode = CFLOW_GRAPH_UNDEFINED;
      return;
   }
   
   if (node == NULL) {
      cflow_errorcode = CFLOW_INVALID_NODE;
      return;
   }

   if (node->instr == NULL) {
      cflow_errorcode = CFLOW_INVALID_INSTRUCTION;
      return;
   }

   if ((node->instr)->opcode == INVALID_OPCODE) {
      cflow_errorcode = CFLOW_INVALID_INSTRUCTION;
      return;
   }
   
   /* update the value of `instr' */
   instr = node->instr;

   /* if the instruction is a Jump instruction then does nothing */
   if ( isJumpInstruction(instr))
      return;

   /* initialize the values of varDest, varSource1 and varSource2 */
   varDest = NULL;
   varSource1 = NULL;
   varSource2 = NULL;

   /* update the values of the variables */
   if (instr->reg_1 != NULL)
      varDest = allocVariable(graph, (instr->reg_1)->ID);
   if (instr->reg_2 != NULL)
      varSource1 = allocVariable(graph, (instr->reg_2)->ID);
   if (instr->reg_3 != NULL)
      varSource2 = allocVariable(graph, (instr->reg_3)->ID);
   
   switch(instr->opcode)
   {
      case LOAD : case AXE_READ : node->def = varDest; break;
      case STORE : case AXE_WRITE : (node->uses)[0] = varDest; break;
      case SGE : case SGT: case SLE : case SLT : case SNE :
      case SEQ : node->def = varDest; break;
      case HALT : case RET : case JSR : case NOP : break;
      case MOVA : node->def = varDest; break;
      case NOTB : case NOTL : case ROTRI : case ROTLI :
      case SHRI : case SHLI : case DIVI : case MULI :
      case EORBI : case ORBI : case ANDBI : case EORLI :
      case ORLI : case ANDLI : case SUBI : case ADDI :
                node->def = varDest;
                (node->uses)[0] = varSource1; break;
      default :
                if ((instr->reg_1)->indirect)
                     (node->uses)[2] = varDest;
                else
                     node->def = varDest;
                (node->uses)[0] = varSource1;
                (node->uses)[1] = varSource2;
   }
}
Ejemplo n.º 5
0
void updateFlowGraph(t_cflow_Graph *graph)
{
   t_list *current_element;
   t_basic_block *current_block;
   t_basic_block *successor;
   
   /* preconditions: graph should not be a NULL pointer */
   if (graph == NULL){
      cflow_errorcode = CFLOW_GRAPH_UNDEFINED;
      return;
   }

   successor = NULL;
   current_element = graph->blocks;
   while(current_element != NULL)
   {
      t_list *last_element;
      t_cflow_Node *last_node;
      t_axe_instruction *last_instruction;
      t_basic_block *jumpBlock;
      
      /* retrieve the current block */
      current_block = (t_basic_block *) LDATA(current_element);
      assert(current_block != NULL);
      assert(current_block->nodes != NULL);

      /* get the last node of the basic block */
      last_element = getLastElement(current_block->nodes);
      assert(last_element != NULL);
      
      last_node = (t_cflow_Node *) LDATA(last_element);
      assert(last_node != NULL);

      last_instruction = last_node->instr;
      assert(last_instruction != NULL);

      if (isHaltInstruction(last_instruction))
      {
         setSucc(current_block, graph->endingBlock);
         setPred(graph->endingBlock, current_block);
      }
      else
      {
         if (isJumpInstruction(last_instruction))
         {
            if (  (last_instruction->address == NULL)
                  || ((last_instruction->address)->labelID == NULL) )
            {
               cflow_errorcode = CFLOW_INVALID_LABEL_FOUND;
               return;
            }
         
            jumpBlock = searchLabel(graph
                  , (last_instruction->address)->labelID);
            if (jumpBlock == NULL) {
               cflow_errorcode = CFLOW_INVALID_LABEL_FOUND;
               return;
            }

            /* add the jumpBlock to the list of successors of current_block */
            /* add also current_block to the list of predecessors of jumpBlock */
            setPred(jumpBlock, current_block);
            if (cflow_errorcode != CFLOW_OK)
               return;
            setSucc(current_block, jumpBlock);
            if (cflow_errorcode != CFLOW_OK)
               return;
         }

         if (!isUnconditionalJump(last_instruction))
         {
            t_basic_block *nextBlock;
            t_list *next_element;
            
            next_element = LNEXT(current_element);
            if (next_element != NULL)
            {
               nextBlock = LDATA(next_element);
               assert(nextBlock != NULL);
               
               setSucc(current_block, nextBlock);
               setPred(nextBlock, current_block);
            }
            else
            {
               setSucc(current_block, graph->endingBlock);
               setPred(graph->endingBlock, current_block);
            }
         
            if (cflow_errorcode != CFLOW_OK)
               return;
         }
      }

      /* update the value of `current_element' */
      current_element = LNEXT(current_element);
   }
}