2016-01-23 49 views
4

編寫一個類似Java的語言編譯器,我在編譯synchronized blocks時遇到問題。我想出了以下的想法給他們簡化爲try-finally塊:可以將一個同步塊簡化爲字節碼級上的Try-Finally塊嗎?

synchonized (obj) { 
    statements... 
} 

可與

Object _lock = obj 
_monitorEnter(lock) 
try { 
    statements... 
} 
finally { 
    _monitorExit(lock) 
} 

_monitorEnter_monitorExit更換代表MONITORENTERMONITOREXIT說明。

我是否正確編譯了​​這個假設,還是我錯過了一些東西?

編輯

我以前執行過一些特殊的處理在體內returnthrow語句。基本上,它會在每個*RETURNTHROW指令之前手動加載所有lock變量和MONITOREXIT。這是由finally塊處理,還是我仍然需要這些檢查?

+1

是的,這是正確的。實際上,這是['java.util.concurrent.locks.Lock']的_exact_語法(https://docs.oracle.com/javase/tutorial/essential/concurrency/newlocks.html)。 –

+0

我不確定我是否理解你的想法。如果你是實現編譯器的人,用'try ... finally'替換'synchronized'並不能簡化任何事情,因爲你仍然是必須實現'try ... finally'的人,那麼,不是嗎?所以你仍然需要關心你自己的任何'return'語句。 – Holger

+0

@Holger當然可以,但我必須兩次實施同樣的事情,所以犯錯誤的方法有兩倍。目前,同步字節碼的生成只是try/finally語句的一個特例。 – Clashsoft

回答

5

你的假設是正確的。 Java語言中的​​塊通過monitorentermonitorexit指令實現。您可以查看JVM規範詳細信息here

同步在Java虛擬機被監控 進入和退出,明確地(通過使用monitorenter和 monitorexit指令)或隱式(通過方法調用和 返回指令)來實現。

編譯器生成的字節碼將處理​​體內拋出的所有異常,所以你試試,最後的辦法將工作在這裏很好。

Specificationfinally聲明不會告訴任何有關釋放監視器的內容。第一個鏈接中提供的示例顯示了在​​區塊中封裝的簡單方法的字節碼。正如你所看到的,任何可能的異常都會被處理以確保monitorexit指令的執行。你應該在你的編譯器中實現相同的行爲(編寫將在finally語句中釋放monitor的代碼)。

void onlyMe(Foo f) { 
    synchronized(f) { 
     doSomething(); 
    } 
} 

Method void onlyMe(Foo) 
0 aload_1    // Push f 
1 dup     // Duplicate it on the stack 
2 astore_2   // Store duplicate in local variable 2 
3 monitorenter  // Enter the monitor associated with f 
4 aload_0    // Holding the monitor, pass this and... 
5 invokevirtual #5 // ...call Example.doSomething()V 
8 aload_2    // Push local variable 2 (f) 
9 monitorexit   // Exit the monitor associated with f 
10 goto 18    // Complete the method normally 
13 astore_3   // In case of any throw, end up here 
14 aload_2    // Push local variable 2 (f) 
15 monitorexit   // Be sure to exit the monitor! 
16 aload_3    // Push thrown value... 
17 athrow    // ...and rethrow value to the invoker 
18 return    // Return in the normal case 
Exception table: 
From To  Target  Type 
4  10  13   any 
13  16  13   any 
+0

謝謝+1。但你是否也可以解決我的編輯問題? – Clashsoft

0

Java編譯器將同步塊編譯爲非常像try-finally的東西,正如您猜測的那樣。但是,有一個細微差別 - 異常處理捕獲monitorexit拋出的異常並無限循環釋放鎖。在Java中沒有辦法像這樣指定控制流。

+0

是的,儘管我不確定這是否是強制性的,只是因爲它出現在規範的一個示例代碼中,可能無限循環是一個很好的特性。 – Holger