Solidity語言學習筆記————41、記憶體佈局
記憶體佈局(Layout in Memory)
Solidity預留了4個32位元組大小的槽位:
0x00
-0x3f
: 雜湊方法的暫存空間(scratch space)0x40
-0x5f
: 前已分配記憶體大小,也稱空閒記憶體指標(free memory pointer)0x60
-0x7f
: 零槽(zero slot)
暫存空間可在語句之間使用(如在內聯編譯時使用)。零槽用作動態記憶體陣列的初始值,不應寫入資料(空閒記憶體初始指標指向0x80
)。
Solidity總是在空閒記憶體指標所在位置建立一個新物件,且對應的記憶體永遠不會被釋放(也許未來會改變這種做法)。
警告 |
---|
有一些在Solidity中的操作需要超過64位元組的臨時空間,這樣就會超過預留的暫存空間。他們就將會分配到空閒記憶體指標所在的地方,但由於他們自身的特點,生命週期相對較短,且指標本身不能更新,記憶體也許會,也許不會被清零(zerod out)。因此,大家不應該認為空閒的記憶體一定已經是清零(zeroed out)的。 |
呼叫資料的佈局(Layout of CallData)
當部署一個合約,並且當它從一個帳戶被呼叫時,輸入資料被假定為ABI規範中的格式。ABI規範要求將引數填充到32位元組的倍數。內部函式呼叫使用不同的約定。
內部機制 - 清理變數(Internals - Cleaning Up Variables)
當一個值佔用的位數小於32位元組時,那些沒有用到的位必須被清除掉。Solidity編譯器設計實現為,在任何可能受到潛在的殘存資料帶來的副作用之前,清理掉這些髒資料。比如,在向記憶體寫入一個值前,不需要的位元組位需要被清除掉,因為沒有用到的記憶體位可能被用來計算雜湊,或作為訊息呼叫的傳送的資料儲存。同樣的,在向storage中儲存時,未用到的位元組位需要被清理掉,否則這些髒資料會帶來意想不到的事情。
另一方面,如果接下來的後述操作不會產生副作用,我們不會主動清理這些位元組位。比如,由於任何非0的值被JUMP
指令認為是true
。在它作用JUMPI
指令的條件前,我們在不會清理這個布林值。
在上述設計準則之外,Solidity編譯器會在輸入資料載入到棧上後清理掉它們。
不同的型別,有不同的無效值的清理規則。
型別 | 有效值 | 無效值意味著 |
---|---|---|
有n的成員的列舉型別 | 0到(n - 1) | 異常(exception) |
布林 | 0或1 | 1 |
有符號整數 | sign-extended word | 當前靜默的包裝了結果,以後會以異常的形式丟擲來 |
無符號整數 | 高位節是0 | 當前靜默的包裝了結果,以後會以異常的形式丟擲來 |
內部機制 - 優化(Internals - The Optimizer)
Solidity是基於彙編優化的,所以它可以,同時也被其它程式語言所使用(譯者注:其它語言編譯為彙編)。編譯器會在JUMP
和JUMPDEST
處拆分基本的指令序列為一個個的基本塊。在這些程式碼塊內,所有的指令都被分析。所有的對棧,記憶體或儲存的操作被記錄成由指令及其引數組成的一個個表示式,這些表示式又會指向另一個表示式。核心目的是找到一些表示式在任何輸入的情況下都恆等,然後將它們組合成一個表示式類。優化器首先嚐試在一系列已知的表示式中,找出來一些全新的表示式。如果找不到,表示式通過一些簡單的原則進行簡化,比如 constant + constant = sum_of_constants
或X * 1 = X
。由於這一切是遞迴進行的,我們可以在第二項是一個更復雜的表達時,應用上述後續規則。對記憶體或儲存的修改,儲存的位置經常會被擦除,由此我們並不知道存的資料有什麼不同:如果我們首先寫入一個值x,再寫入另一個值y,這兩個都是輸入變數,第二個寫入時會覆蓋第一個,所以我們實際在寫入第二個值時,不知道第一個值是什麼了。所以,如果一個簡單的表示式x-y指向一個非0的常量,這樣我們就能在操作y時知道x記憶體儲的值。
在流程最後,我們知道哪一個表示式會在棧頂,並且有一系列的對記憶體或儲存的修改。這些資訊與基本的塊存在一起以方便的用來連線他們。此外,關於棧,儲存和記憶體配置的資訊會傳遞到下一個塊。如果我們知道所有JUMP
和JUMPI
指令的目標,我們可以構建程式的完整的控制流程圖。如果有任何一個我們不知道目標的跳轉(因為目標是通過輸入引數進行計算的,所以原則上可能發生),我們必須擦除塊知識的輸入,因為他有可能是某個JUMP
的目的地(譯者注:因為可能某個跳轉在執行時會指向他,修改他的狀態,所以他的推算狀態是錯誤的)。如果某個JUMPI
被發現他的條件是常量,它會被轉化為一個無狀態的跳轉。
在最後一步,每個塊中的程式碼都將重新生成。在某個塊結束時,將生成棧上表示式的依賴樹,不在這個樹上的操作就被丟棄了。在我們原始程式碼中想要應用的對記憶體、儲存想要的修改順序的程式碼就生成出來了(被丟棄的修改被認為是完全不需要的),最終,生成了所有的需要在棧上存在的值。
這些步驟應用於每個基本的塊,如果新生成的程式碼更小,將會替換現有的程式碼。如果一個塊在分析期間在JUMPI
處分裂,條件被證實為一個常量,JUMPI
將可以基於常量值被替換掉,比如下述程式碼:
var x = 7;
data[7] = 9;
if (data[x] != x + 2)
return 2;
else
return 1;
簡化的程式碼可以被編譯為:data[7] = 9;
return 1;
相關文章
- [譯]Go語言記憶體佈局Go記憶體
- Solidity語言學習筆記————1、初識Solidity語言Solid筆記
- Solidity語言學習筆記————40、儲存中狀態變數的佈局Solid筆記變數
- Solidity語言學習筆記————4、常量Solid筆記
- Solidity語言學習筆記————36、 庫Solid筆記
- Solidity語言學習筆記————15、結構體StructSolid筆記結構體Struct
- Solidity語言學習筆記————38、Solidity彙編Solid筆記
- Solidity語言學習筆記————12、陣列Solid筆記陣列
- Solidity語言學習筆記————33、事件(Events)Solid筆記事件
- Solidity語言學習筆記————37、Using forSolid筆記
- Solidity語言學習筆記————34、繼承Solid筆記繼承
- C 語言結構體記憶體佈局問題結構體記憶體
- C語言結構體記憶體佈局問題C語言結構體記憶體
- Solidity語言學習筆記————42、提示和技巧Solid筆記
- Solidity語言學習筆記————43、安全考量Solid筆記
- Solidity語言學習筆記————32、建立合約Solid筆記
- Solidity語言學習筆記————28、純函式Solid筆記函式
- Solidity語言學習筆記————26、回退函式Solid筆記函式
- 【記憶體管理】記憶體佈局記憶體
- Flex佈局學習筆記Flex筆記
- Solidity語言學習筆記————10、布林型、整型Solid筆記
- Solidity語言學習筆記————3、Remix的基本使用Solid筆記REM
- Solidity語言學習筆記————18、字串和函式Solid筆記字串函式
- Solidity語言學習筆記————14、左值運算子Solid筆記
- Solidity語言學習筆記————9、左值運算子Solid筆記
- Solidity語言學習筆記————17、原始檔對映Solid筆記
- Solidity語言學習筆記————5、全域性變數Solid筆記變數
- Solidity語言學習筆記————2、使用編譯器Solid筆記編譯
- Solidity語言學習筆記————39、獨立彙編Solid筆記
- Solidity語言學習筆記————25、作用域和宣告Solid筆記
- Solidity語言學習筆記————27、檢視函式Solid筆記函式
- Solidity語言學習筆記————30、函式過載Solid筆記函式
- Xamarin 學習筆記 - Layout(佈局)筆記
- CSS學習筆記:flex佈局CSS筆記Flex
- Solidity語言學習筆記————16、對映MappingSolid筆記APP
- Solidity語言學習筆記————35、抽象合約和介面Solid筆記抽象
- Solidity語言學習筆記————26、Assert, Require, Revert 和 ExceptionsSolid筆記UIException
- Solidity語言學習筆記————22、可見性和GettersSolid筆記