『壹』 Hermes源碼分析(二)——解析位元組碼
前面一節 講到位元組碼序列化為二進制是有固定的格式的,這里我們分析一下源碼裡面是怎麼處理的
這里可以看到首先寫入的是魔數,他的值為
對應的二進制見下圖,注意是小端位元組序
第二項是位元組碼的版本,筆者的版本是74,也即 上圖中的4a00 0000
第三項是源碼的hash,這里採用的是SHA1演算法,生成的哈希值是160位,因此佔用了20個位元組
第四項是文件長度,這個欄位是32位的,也就是下圖中的為0aa030,轉換成十進制就是696368,實際文件大小也是這么多
後面的欄位類似,就不一一分析了,頭部所有欄位的類型都可以在 BytecodeFileHeader.h 中看到,Hermes按照既定的內存布局把欄位寫入後再序列化,就得到了我們看到的位元組碼文件。
這里寫入的數據很多,以函數頭的寫入為例,我們調用了visitFunctionHeader方法,並通過byteCodeMole拿到函數的簽名,將其寫入函數表(存疑,在實際的文件中並沒有看到這一部分)。注意這些數據必須按順序寫入,因為讀出的時候也是按對應順序來的。
我們知道react-native 在載入位元組碼的時候需要調用hermes的prepareJavaScript方法, 那這個方法做了些什麼事呢?
這里做了兩件事情:
1. 判斷是否是位元組碼,如果是則調用createBCProviderFromBuffer,否則調用createBCProviderFromSrc,我們這里只關注createBCProviderFromBuffer
2.通過BCProviderFromBuffer的構造方法得到文件頭和函數頭的信息(populateFromBuffer方法),下面是這個方法的實現。
BytecodeFileFields的populateFromBuffer方法也是一個模版方法,注意這里調用populateFromBuffer方法的是一個 ConstBytecodeFileFields對象,他代表的是不可變的位元組碼欄位。
細心的讀者會發現這里也有visitFunctionHeaders方法, 這里主要為了復用visitBytecodeSegmentsInOrder的邏輯,把populator當作一個visitor來按順序讀取buffer的內容,並提前載入到BytecodeFileFields裡面,以減少後面執行位元組碼時解析的時間。
Hermes引擎在讀取了位元組碼之後會通過解析BytecodeFileHeader這個結構體中的欄位來獲取一些關鍵信息,例如bundle是否是位元組碼格式,是否包含了函數,位元組碼的版本是否匹配等。注意這里我們只是解析了頭部,沒有解析整個位元組碼,後面執行位元組碼時才會解析剩餘的部分。
evaluatePreparedJavaScript這個方法,主要是調用了HermesRuntime的 runBytecode方法,這里hermesPrep時上一步解析頭部時獲取的BCProviderFromBuffer實例。
runBytecode這個方法比較長,主要做了幾件事情:
這里說明一下,Domain是用於垃圾回收的運行時模塊的代理, Domain被創建時是空的,並跟隨著運行時模塊進行傳播, 在運行時模塊的整個生命周期內都一直存在。在某個Domain下創建的所有函數都會保持著對這個Domain的強引用。當Domain被回收的時候,這個Domain下的所有函數都不能使用。
未完待續。。。
『貳』 哈希函數構造方法講解哈希函數簡介
HELLO,哈希函數構造方法講解,哈希函數簡介很多人還不知道,現在讓我們一起來看看吧!
1、中文名:哈希函數外文名:Hash Function別名:散列函數表達式:Addr = H(key)作用1:加密作用2:語音識別作用3:散列表領域:計算機演算法哈希函數指將哈希表中元素的關鍵鍵值映射為元素存儲位置的函數。
2、一般的線性表,樹中,記錄在結構中的相對位置是隨機的,即和記錄的關鍵字之間不存在確定的關系,因此,在結構中查找記錄時需進行一系列和關鍵字的比較。
3、這一類查找方法建立在「比較「的基礎上,查找的效率依賴於查找過程中所進行的比較次數。
4、 理想的情況是能直接找到需要的記錄,因此必須在記錄的存儲位置和它的關鍵字之間建立一個確定的對應關系f,使每個關鍵字和結構中一個唯一的存儲位置相對應。
本文到此講解完畢了,希望對大家有幫助。
『叄』 深入理解 HashSet 及底層源碼分析
HashSet是基於HashMap實現的,主要用於存儲不重復的對象。以下是對其底層源碼及特性的深入理解:
1. 底層結構: 核心實現:HashSet的底層實際上是基於HashMap的。HashMap的key用於存儲HashSet中的元素,而value則使用一個統一的佔位對象。 唯一性保證:由於HashMap的key具有唯一性,因此HashSet中的元素也是唯一的。
2. 特性: 不允許重復元素:HashSet不允許存儲重復的元素。如果嘗試添加已存在的元素,添加操作將失敗。 無序性:HashSet中的元素沒有特定的順序。它們的存儲順序取決於HashMap的內部實現,通常是基於哈希碼的分布。
3. 重要方法: 構造方法:HashSet的構造方法實際上調用了HashMap的構造方法,從而建立了一個基於HashMap的存儲結構。 添加方法:添加元素到HashSet時,實際上是將該元素作為HashMap的key進行存儲。如果添加成功,則返回true;否則返回false。 刪除方法:從HashSet中刪除元素時,實際上是在HashMap中刪除對應的key。如果刪除成功,則返回true;否則返回false。 iterator方法:HashSet的迭代器是通過獲取HashMap的keySet的迭代器來實現的。這樣,可以遍歷HashSet中的所有元素。 size方法:HashSet的size方法直接調用了HashMap的size方法,以獲取當前存儲的元素數量。
總結:HashSet的底層源碼主要依賴於HashMap的實現。它通過利用HashMap的特性來確保元素的唯一性和無序性。了解這些底層實現細節對於正確使用和理解HashSet至關重要。
『肆』 什麼是hash
hash(散列、雜湊)函數,其核心功能是將任意長度的數據映射到有限長度的域上。具體來說,它將輸入的數據m經過一系列雜糅操作後,生成一個固定長度的數據h,作為數據m的特徵(指紋)。不考慮數據塊m的大小,輸出的值h始終為固定長度。實現hash值的生成,可以將數據塊m分成固定長度(如128位),然後依次進行hash運算,通過不同的迭代方法(如前一塊的hash值與後一塊的hash值進行異或)來實現。如果數據塊m不足128位,可以通過補零或補一的方式調整其長度,具體調整方法則由演算法指定。
除了基本的hash值生成原理,我們還可以深入探討hash演算法在不同場景下的應用及其特性。首先,hash演算法的抗碰撞能力至關重要。它意味著,對於任意兩個不同的數據塊,它們的hash值相同的可能性非常小;對於一個特定的數據塊,找到與之hash值相同的另一個數據塊也極其困難。其次,hash演算法還具有抗篡改能力,即對於一個數據塊,即便是改動其一個比特位,其hash值的變化也會非常顯著。
在數據結構中,如哈希表(hashmap)等應用中,hash值(key)的主要作用是加速鍵值對的查找。這里的key設計要求在於均勻地分配數據,以減少碰撞的發生,確保value能夠被有效地分布到不同的桶中。然而,為了提高整體演算法的set性能,hash值的生成速度變得尤為重要。例如,Java中的String類就採用了一個簡潔的乘加迭代運算來生成hashCode值。
在密碼學領域,hash演算法的應用主要集中在消息摘要和簽名上。通過使用hash演算法生成消息摘要,可以確保消息的完整性和驗證發送者的真實身份。以知乎為例,用戶在登錄時輸入的密碼經過hash演算法處理後,網站只保存該hash值,而非原始密碼。這樣即使黑客獲取了hash值,也無法直接推斷出原始密碼。當用戶嘗試登錄時,網站會重新計算hash值並與存儲的原hash值進行比對,確保登錄信息的安全性。
考慮到抗碰撞和抗篡改能力的高要求,hash演算法在密碼學中的設計與應用通常更加重視這些安全特性,而非速度。MD5是一個經典的例子,其輸出長度為128位,設計預期碰撞概率極低。即便是被破解後,MD5的碰撞概率上限也達到了一個極小的數值,這意味著找到一個與目標文件相同的hash值需要巨大的計算量。通過觀察MD5加密結果,我們可以直觀地看到,即使僅改變輸入字元串中的少數比特位,其生成的MD5值也會產生顯著差異。
雖然構造一個演算法,使其在輸出長度為128位的情況下具有極高的抗碰撞能力和分布均勻性,同時保持良好的抗篡改能力,看似理想,但至今密碼學家尚未找到實現這一目標的演算法。然而,根據隨機預言機(Random Oracle)的假設,這一目標是可能存在的,盡管尚未被嚴格構造出來。在密碼學中,hash演算法的設計和應用不斷進步,以適應不同的安全需求,如變色龍哈希(ChameleonHash)等演算法的出現,展示了在保持抗碰撞能力的同時,可以提供額外的安全特性,如抗篡改性和可偽造性,以應對復雜的安全挑戰。