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 Unified Diffs Ignore Whitespace Patch

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

78
79
80
81
82
83
84






85
86
87
88
89
90
91
...
134
135
136
137
138
139
140




141
142
143
144
145
146
147
....
1087
1088
1089
1090
1091
1092
1093
1094











1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
....
1779
1780
1781
1782
1783
1784
1785





1786
1787
1788
1789
1790
1791
1792
....
1802
1803
1804
1805
1806
1807
1808















1809
1810














1811
1812
1813
1814
1815
1816
1817
....
1824
1825
1826
1827
1828
1829
1830














1831
1832
1833
1834
1835














1836
1837
1838
1839
1840
1841
1842
	
	/** Is this method synchronized? */
	protected final boolean issynchronized;
	
	/** Is this an instance method? */
	protected final boolean isinstance;
	






	/** Monitor target register used. */
	protected final int monitortarget;
	
	/** Volatile registers to use. */
	protected final VolatileRegisterStack volatiles;
	
	/** Standard exception handler table. */
................................................................................
		this.isinstance = __bc.isInstance();
		
		// Determine monitor target register and the volatile base
		int volbase = NativeCode.ARGUMENT_REGISTER_BASE + 2 +
			__bc.maxLocals() + __bc.maxStack();
		this.monitortarget = volbase;
		this.volatiles = new VolatileRegisterStack(volbase + 1);




	}
	
	/**
	 * {@inheritDoc}
	 * @since 2019/04/12
	 */
	@Override
................................................................................
	 * @since 2019/04/11
	 */
	@Override
	public final void doReturn(JavaStackResult.Input __in)
	{
		NativeCodeBuilder codebuilder = this.codebuilder;
		
		// Returning a value? Copy it to the return register











		if (__in != null)
		{
			int a = __in.register,
				b = NativeCode.RETURN_REGISTER;
			
			// Copy value to return register
			if (__in.type.isWide())
			{
				codebuilder.addCopy(a, b);
				codebuilder.addCopy(a + 1, b + 1);
			}
			else
				codebuilder.addCopy(a, b);
			
			// If we are returning an object, we need to reference count it
			if (__in.isObject())
				this.__refCount(NativeCode.RETURN_REGISTER);
		}
		
		// Uncount anything which was enqueued
		for (int q : this.state.result.enqueue())
			this.__refUncount(q);
		
		// Do the return
		this.__generateReturn();
	}
	
	/**
	 * {@inheritDoc}
	 * @since 2019/04/11
................................................................................
	 * @return
	 */
	private final NativeCodeLabel __generateReturn(JavaStackEnqueueList __eq)
		throws NullPointerException
	{
		if (__eq == null)
			throw new NullPointerException("NARG");





		
		// Find unique return point
		boolean freshdx;
		List<JavaStackEnqueueList> returns = this._returns;
		int dx = returns.indexOf(__eq);
		if ((freshdx = (dx < 0)))
			returns.add((dx = returns.size()), __eq);
................................................................................
		// is generate a return instruction
		NativeCodeBuilder codebuilder = this.codebuilder;
		if (__eq.isEmpty())
		{
			// If this is synchronized, we need to exit the monitor
			if (this.issynchronized)
			{















				this.__monitor(false, this.monitortarget);
				this.__refUncount(this.monitortarget);














			}
			
			// Debug exit
			codebuilder.add(NativeInstructionType.DEBUG_EXIT);
			
			// Since there is nothing to uncount, just return
			codebuilder.add(NativeInstructionType.RETURN);
................................................................................
		if (!freshdx && __eq.size() > 1)
		{
			// Jump to label
			codebuilder.addGoto(lb);
			
			return lb;
		}














		
		// Since the enqueue list is not empty, we can just trim a register
		// from the top and recursively go down
		// So uncount the top
		this.__refUncount(__eq.top());














		
		// Recursively go down since the enqueues may possibly be shared, if
		// any of these enqueues were previously made then the recursive
		// call will just make a goto
		this.__generateReturn(__eq.trimTop());
		
		// Note that we do not return the recursive result because that







>
>
>
>
>
>







 







>
>
>
>







 







|
>
>
>
>
>
>
>
>
>
>
>













|
<
<
<
|
<
<
<
<
<







 







>
>
>
>
>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>


>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>





>
>
>
>
>
>
>
>
>
>
>
>
>
>







78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
...
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
....
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129



1130





1131
1132
1133
1134
1135
1136
1137
....
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
....
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
....
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
	
	/** Is this method synchronized? */
	protected final boolean issynchronized;
	
	/** Is this an instance method? */
	protected final boolean isinstance;
	
	/** Returning value? */
	protected final boolean isreturn;
	
	/** Returning wide value? */
	protected final boolean isreturnwide;
	
	/** Monitor target register used. */
	protected final int monitortarget;
	
	/** Volatile registers to use. */
	protected final VolatileRegisterStack volatiles;
	
	/** Standard exception handler table. */
................................................................................
		this.isinstance = __bc.isInstance();
		
		// Determine monitor target register and the volatile base
		int volbase = NativeCode.ARGUMENT_REGISTER_BASE + 2 +
			__bc.maxLocals() + __bc.maxStack();
		this.monitortarget = volbase;
		this.volatiles = new VolatileRegisterStack(volbase + 1);
		
		// Returning values?
		this.isreturn = (__bc.type().returnValue() != null);
		this.isreturnwide = (isreturn && __bc.type().returnValue().isWide());
	}
	
	/**
	 * {@inheritDoc}
	 * @since 2019/04/12
	 */
	@Override
................................................................................
	 * @since 2019/04/11
	 */
	@Override
	public final void doReturn(JavaStackResult.Input __in)
	{
		NativeCodeBuilder codebuilder = this.codebuilder;
		
		// If we are returning an object, we need to reference count it up
		// so it does not get garbage collected as a return is happening
		if (__in != null && __in.isObject())
			this.__refCount(__in.register);
		
		// Uncount all references that need to be cleared out as we return
		for (int q : this.state.result.enqueue())
			this.__refUncount(q);
		
		// Copy the returning value at the end to increase it's lifetime
		// as much as possible. Otherwise if we copy too early to the return
		// register then future uncounts can completely trash the value
		if (__in != null)
		{
			int a = __in.register,
				b = NativeCode.RETURN_REGISTER;
			
			// Copy value to return register
			if (__in.type.isWide())
			{
				codebuilder.addCopy(a, b);
				codebuilder.addCopy(a + 1, b + 1);
			}
			else
				codebuilder.addCopy(a, b);
		}



		





		// Do the return
		this.__generateReturn();
	}
	
	/**
	 * {@inheritDoc}
	 * @since 2019/04/11
................................................................................
	 * @return
	 */
	private final NativeCodeLabel __generateReturn(JavaStackEnqueueList __eq)
		throws NullPointerException
	{
		if (__eq == null)
			throw new NullPointerException("NARG");
		
		// Will be used to generate safe spots
		VolatileRegisterStack volatiles = this.volatiles;
		int ssh = -1,
			ssl = -1;
		
		// Find unique return point
		boolean freshdx;
		List<JavaStackEnqueueList> returns = this._returns;
		int dx = returns.indexOf(__eq);
		if ((freshdx = (dx < 0)))
			returns.add((dx = returns.size()), __eq);
................................................................................
		// is generate a return instruction
		NativeCodeBuilder codebuilder = this.codebuilder;
		if (__eq.isEmpty())
		{
			// If this is synchronized, we need to exit the monitor
			if (this.issynchronized)
			{
				// Protect return value, if there is one
				if (isreturn)
				{
					ssh = volatiles.get();
					codebuilder.addCopy(NativeCode.RETURN_REGISTER, ssh);
				}
				
				// And wide value, if any
				if (isreturnwide)
				{
					ssl = volatiles.get();
					codebuilder.addCopy(NativeCode.RETURN_REGISTER + 1, ssl);
				}
				
				// Uncount and clear out
				this.__monitor(false, this.monitortarget);
				this.__refUncount(this.monitortarget);
				
				// Recover value, if any
				if (isreturn)
				{
					codebuilder.addCopy(ssh, NativeCode.RETURN_REGISTER);
					volatiles.remove(ssh);
				}
				
				// Recover wide, if any
				if (isreturnwide)
				{
					codebuilder.addCopy(ssl, NativeCode.RETURN_REGISTER + 1);
					volatiles.remove(ssl);
				}
			}
			
			// Debug exit
			codebuilder.add(NativeInstructionType.DEBUG_EXIT);
			
			// Since there is nothing to uncount, just return
			codebuilder.add(NativeInstructionType.RETURN);
................................................................................
		if (!freshdx && __eq.size() > 1)
		{
			// Jump to label
			codebuilder.addGoto(lb);
			
			return lb;
		}
		
		// Protect return value, if there is one
		if (isreturn)
		{
			ssh = volatiles.get();
			codebuilder.addCopy(NativeCode.RETURN_REGISTER, ssh);
		}
		
		// And wide value, if any
		if (isreturnwide)
		{
			ssl = volatiles.get();
			codebuilder.addCopy(NativeCode.RETURN_REGISTER + 1, ssl);
		}
		
		// Since the enqueue list is not empty, we can just trim a register
		// from the top and recursively go down
		// So uncount the top
		this.__refUncount(__eq.top());
		
		// Recover value, if any
		if (isreturn)
		{
			codebuilder.addCopy(ssh, NativeCode.RETURN_REGISTER);
			volatiles.remove(ssh);
		}
		
		// Recover wide, if any
		if (isreturnwide)
		{
			codebuilder.addCopy(ssl, NativeCode.RETURN_REGISTER + 1);
			volatiles.remove(ssl);
		}
		
		// Recursively go down since the enqueues may possibly be shared, if
		// any of these enqueues were previously made then the recursive
		// call will just make a goto
		this.__generateReturn(__eq.trimTop());
		
		// Note that we do not return the recursive result because that