Check-in [1e543c9951]

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Protect return values with temporary registers so they are not destroyed during uncounts.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:1e543c9951db340e6debc84a380b106af86f820f
User & Date: stephanie.gawroriski 2019-06-13 23:59:23
Context
2019-06-14
00:15
Stop of an out of range register is decoded; Add debug note. check-in: 2dabb55ba2 user: stephanie.gawroriski tags: trunk
2019-06-13
23:59
Protect return values with temporary registers so they are not destroyed during uncounts. check-in: 1e543c9951 user: stephanie.gawroriski tags: trunk
23:42
Debugging. check-in: 08ccb21a57 user: stephanie.gawroriski tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to runt/libs/tool-classfile/dev/shadowtail/classfile/nncc/NearNativeByteCodeHandler.java.

    78     78   	
    79     79   	/** Is this method synchronized? */
    80     80   	protected final boolean issynchronized;
    81     81   	
    82     82   	/** Is this an instance method? */
    83     83   	protected final boolean isinstance;
    84     84   	
           85  +	/** Returning value? */
           86  +	protected final boolean isreturn;
           87  +	
           88  +	/** Returning wide value? */
           89  +	protected final boolean isreturnwide;
           90  +	
    85     91   	/** Monitor target register used. */
    86     92   	protected final int monitortarget;
    87     93   	
    88     94   	/** Volatile registers to use. */
    89     95   	protected final VolatileRegisterStack volatiles;
    90     96   	
    91     97   	/** Standard exception handler table. */
................................................................................
   134    140   		this.isinstance = __bc.isInstance();
   135    141   		
   136    142   		// Determine monitor target register and the volatile base
   137    143   		int volbase = NativeCode.ARGUMENT_REGISTER_BASE + 2 +
   138    144   			__bc.maxLocals() + __bc.maxStack();
   139    145   		this.monitortarget = volbase;
   140    146   		this.volatiles = new VolatileRegisterStack(volbase + 1);
          147  +		
          148  +		// Returning values?
          149  +		this.isreturn = (__bc.type().returnValue() != null);
          150  +		this.isreturnwide = (isreturn && __bc.type().returnValue().isWide());
   141    151   	}
   142    152   	
   143    153   	/**
   144    154   	 * {@inheritDoc}
   145    155   	 * @since 2019/04/12
   146    156   	 */
   147    157   	@Override
................................................................................
  1087   1097   	 * @since 2019/04/11
  1088   1098   	 */
  1089   1099   	@Override
  1090   1100   	public final void doReturn(JavaStackResult.Input __in)
  1091   1101   	{
  1092   1102   		NativeCodeBuilder codebuilder = this.codebuilder;
  1093   1103   		
  1094         -		// Returning a value? Copy it to the return register
         1104  +		// If we are returning an object, we need to reference count it up
         1105  +		// so it does not get garbage collected as a return is happening
         1106  +		if (__in != null && __in.isObject())
         1107  +			this.__refCount(__in.register);
         1108  +		
         1109  +		// Uncount all references that need to be cleared out as we return
         1110  +		for (int q : this.state.result.enqueue())
         1111  +			this.__refUncount(q);
         1112  +		
         1113  +		// Copy the returning value at the end to increase it's lifetime
         1114  +		// as much as possible. Otherwise if we copy too early to the return
         1115  +		// register then future uncounts can completely trash the value
  1095   1116   		if (__in != null)
  1096   1117   		{
  1097   1118   			int a = __in.register,
  1098   1119   				b = NativeCode.RETURN_REGISTER;
  1099   1120   			
  1100   1121   			// Copy value to return register
  1101   1122   			if (__in.type.isWide())
  1102   1123   			{
  1103   1124   				codebuilder.addCopy(a, b);
  1104   1125   				codebuilder.addCopy(a + 1, b + 1);
  1105   1126   			}
  1106   1127   			else
  1107   1128   				codebuilder.addCopy(a, b);
  1108         -			
  1109         -			// If we are returning an object, we need to reference count it
  1110         -			if (__in.isObject())
  1111         -				this.__refCount(NativeCode.RETURN_REGISTER);
  1112   1129   		}
  1113   1130   		
  1114         -		// Uncount anything which was enqueued
  1115         -		for (int q : this.state.result.enqueue())
  1116         -			this.__refUncount(q);
  1117         -		
  1118   1131   		// Do the return
  1119   1132   		this.__generateReturn();
  1120   1133   	}
  1121   1134   	
  1122   1135   	/**
  1123   1136   	 * {@inheritDoc}
  1124   1137   	 * @since 2019/04/11
................................................................................
  1779   1792   	 * @return
  1780   1793   	 */
  1781   1794   	private final NativeCodeLabel __generateReturn(JavaStackEnqueueList __eq)
  1782   1795   		throws NullPointerException
  1783   1796   	{
  1784   1797   		if (__eq == null)
  1785   1798   			throw new NullPointerException("NARG");
         1799  +		
         1800  +		// Will be used to generate safe spots
         1801  +		VolatileRegisterStack volatiles = this.volatiles;
         1802  +		int ssh = -1,
         1803  +			ssl = -1;
  1786   1804   		
  1787   1805   		// Find unique return point
  1788   1806   		boolean freshdx;
  1789   1807   		List<JavaStackEnqueueList> returns = this._returns;
  1790   1808   		int dx = returns.indexOf(__eq);
  1791   1809   		if ((freshdx = (dx < 0)))
  1792   1810   			returns.add((dx = returns.size()), __eq);
................................................................................
  1802   1820   		// is generate a return instruction
  1803   1821   		NativeCodeBuilder codebuilder = this.codebuilder;
  1804   1822   		if (__eq.isEmpty())
  1805   1823   		{
  1806   1824   			// If this is synchronized, we need to exit the monitor
  1807   1825   			if (this.issynchronized)
  1808   1826   			{
         1827  +				// Protect return value, if there is one
         1828  +				if (isreturn)
         1829  +				{
         1830  +					ssh = volatiles.get();
         1831  +					codebuilder.addCopy(NativeCode.RETURN_REGISTER, ssh);
         1832  +				}
         1833  +				
         1834  +				// And wide value, if any
         1835  +				if (isreturnwide)
         1836  +				{
         1837  +					ssl = volatiles.get();
         1838  +					codebuilder.addCopy(NativeCode.RETURN_REGISTER + 1, ssl);
         1839  +				}
         1840  +				
         1841  +				// Uncount and clear out
  1809   1842   				this.__monitor(false, this.monitortarget);
  1810   1843   				this.__refUncount(this.monitortarget);
         1844  +				
         1845  +				// Recover value, if any
         1846  +				if (isreturn)
         1847  +				{
         1848  +					codebuilder.addCopy(ssh, NativeCode.RETURN_REGISTER);
         1849  +					volatiles.remove(ssh);
         1850  +				}
         1851  +				
         1852  +				// Recover wide, if any
         1853  +				if (isreturnwide)
         1854  +				{
         1855  +					codebuilder.addCopy(ssl, NativeCode.RETURN_REGISTER + 1);
         1856  +					volatiles.remove(ssl);
         1857  +				}
  1811   1858   			}
  1812   1859   			
  1813   1860   			// Debug exit
  1814   1861   			codebuilder.add(NativeInstructionType.DEBUG_EXIT);
  1815   1862   			
  1816   1863   			// Since there is nothing to uncount, just return
  1817   1864   			codebuilder.add(NativeInstructionType.RETURN);
................................................................................
  1824   1871   		if (!freshdx && __eq.size() > 1)
  1825   1872   		{
  1826   1873   			// Jump to label
  1827   1874   			codebuilder.addGoto(lb);
  1828   1875   			
  1829   1876   			return lb;
  1830   1877   		}
         1878  +		
         1879  +		// Protect return value, if there is one
         1880  +		if (isreturn)
         1881  +		{
         1882  +			ssh = volatiles.get();
         1883  +			codebuilder.addCopy(NativeCode.RETURN_REGISTER, ssh);
         1884  +		}
         1885  +		
         1886  +		// And wide value, if any
         1887  +		if (isreturnwide)
         1888  +		{
         1889  +			ssl = volatiles.get();
         1890  +			codebuilder.addCopy(NativeCode.RETURN_REGISTER + 1, ssl);
         1891  +		}
  1831   1892   		
  1832   1893   		// Since the enqueue list is not empty, we can just trim a register
  1833   1894   		// from the top and recursively go down
  1834   1895   		// So uncount the top
  1835   1896   		this.__refUncount(__eq.top());
         1897  +		
         1898  +		// Recover value, if any
         1899  +		if (isreturn)
         1900  +		{
         1901  +			codebuilder.addCopy(ssh, NativeCode.RETURN_REGISTER);
         1902  +			volatiles.remove(ssh);
         1903  +		}
         1904  +		
         1905  +		// Recover wide, if any
         1906  +		if (isreturnwide)
         1907  +		{
         1908  +			codebuilder.addCopy(ssl, NativeCode.RETURN_REGISTER + 1);
         1909  +			volatiles.remove(ssl);
         1910  +		}
  1836   1911   		
  1837   1912   		// Recursively go down since the enqueues may possibly be shared, if
  1838   1913   		// any of these enqueues were previously made then the recursive
  1839   1914   		// call will just make a goto
  1840   1915   		this.__generateReturn(__eq.trimTop());
  1841   1916   		
  1842   1917   		// Note that we do not return the recursive result because that