虛擬機(jī)的方法調(diào)用和字節(jié)碼執(zhí)行

目錄

一、運(yùn)行時(shí)棧幀結(jié)構(gòu)
二、方法調(diào)用
三永部、方法執(zhí)行

一字管、運(yùn)行時(shí)棧幀結(jié)構(gòu)

棧幀是用于支持虛擬機(jī)進(jìn)行 方法調(diào)用 和 方法執(zhí)行 的數(shù)據(jù)結(jié)構(gòu)啰挪,它是虛擬機(jī)運(yùn)行時(shí)數(shù)據(jù)區(qū)中的虛擬機(jī)棧的棧元素。棧幀存儲(chǔ)了方法的局部變量表嘲叔、操作數(shù)棧亡呵、動(dòng)態(tài)鏈接和方法返回地址等信息。每一個(gè)方法從調(diào)用開始至執(zhí)行完成的過程硫戈,都對(duì)應(yīng)著一個(gè)棧幀在虛擬機(jī)棧里面從入棧到出棧的過程锰什。

每一個(gè)棧幀都包括了局部變量表、操作數(shù)棧丁逝、動(dòng)態(tài)鏈接汁胆、方法返回地址和一些額外的附加信息。在編譯程序代碼的時(shí)候霜幼,棧幀中需要 多大的局部變量表嫩码,多深的操作數(shù)棧 都已經(jīng)完全確定了,并且寫入到了方法表的 Code 屬性中罪既,因此一個(gè)棧幀需要分配多少 內(nèi)存铸题,不會(huì)受到程序運(yùn)行期變量數(shù)據(jù)的影響,而僅僅取決于具體的虛擬機(jī)實(shí)現(xiàn)琢感。

一個(gè)線程中的方法調(diào)用鏈可能很長(zhǎng)(如一個(gè)方法內(nèi)調(diào)用了許多其他方法)丢间,很多方法都同時(shí)處于執(zhí)行狀態(tài)。對(duì)于執(zhí)行引擎來(lái)說(shuō)猩谊,在活動(dòng)線程 中千劈,只有位于棧頂?shù)臈攀怯行У模Q為 當(dāng)前棧幀 牌捷,與這個(gè)棧幀相關(guān)聯(lián)的方法稱為當(dāng)前方法墙牌。執(zhí)行引擎運(yùn)行的所有字節(jié)碼指令都只針對(duì)當(dāng)前棧幀進(jìn)行操作,在概念模型上暗甥,典型的棧幀結(jié)構(gòu)如下所示喜滨。

棧幀的概念結(jié)構(gòu).png
接下來(lái)詳細(xì)說(shuō)明一下棧幀中的局部變量、操作數(shù)棧撤防、動(dòng)態(tài)鏈接虽风、方法返回地址等各個(gè)部分的作用和數(shù)據(jù)結(jié)構(gòu)。

  1. 局部變量表
  • 局部變量表是一組變量值存儲(chǔ)空間,用于存放 方法參數(shù)方法內(nèi)部定義的局部變量辜膝。在 Java 程序編譯為 Class 文件時(shí)无牵,就在方法的 Code 屬性的 max_locals 數(shù)據(jù)項(xiàng)中確定了該方法所需要分配的局部變量表的最大容量。
  • 局部變量表是以 變量槽(Variable Slot厂抖,下稱Slot)為最小單位茎毁,每個(gè) Slot 都應(yīng)該能存放 一個(gè)boolean、short忱辅、byte七蜘、char、int墙懂、float橡卤、reference 和 returnAddress 類型的數(shù)據(jù), 這 8 種數(shù)據(jù)類型损搬,都可以使用 32 位或更小的物理內(nèi)存來(lái)存放碧库。
  • 一個(gè) Slot 可以存放一個(gè) 32 位以內(nèi)的數(shù)據(jù)類型,Java 中占用 32 位以內(nèi)的數(shù)據(jù)類型有 boolean场躯、short谈为、 byte、char踢关、int、float粘茄、reference 和 returnAddress 8 種類型签舞。前面 6 種不需要解釋,而第 7 種 reference 類型表示一個(gè)對(duì)象實(shí)例的引用柒瓣,虛擬機(jī)規(guī)范并對(duì)其特別說(shuō)明儒搭, 但虛擬機(jī)實(shí)現(xiàn)至少都應(yīng)當(dāng)能通過這個(gè)引用做到這兩點(diǎn):第一是從引用中直接或間接地查找到對(duì)象在 Java 堆中 數(shù)據(jù)存放的起始地址索引;第二是此引用中直接或間接地查找到對(duì)象所屬數(shù)據(jù)類型在方法區(qū)中的存儲(chǔ)的類型 信息芙贫,否則無(wú)法實(shí)現(xiàn) Java 語(yǔ)言規(guī)范中定義的語(yǔ)法約束搂鲫。第 8 種已經(jīng)很少見了,它是為字節(jié)碼指令 jsr磺平、jsr_w 和 ret 服務(wù)的魂仍,指向了一條字節(jié)碼指令的地址。
  • 對(duì)于 64 位的數(shù)據(jù)類型拣挪,虛擬機(jī)會(huì)以高位對(duì)齊的方式為其分配兩個(gè)連續(xù)的 Slot 空間擦酌,Java 語(yǔ)言中明確的 64 位數(shù)據(jù)類型只有 long 和double 兩種。由于局部變量表建立在線程的堆棧上菠劝,是線程私有的數(shù)據(jù)赊舶, 無(wú)論讀寫兩個(gè)連續(xù)的 Slot 是否為原子操作,都不會(huì)引起數(shù)據(jù)安全問題。
  • 在方法執(zhí)行時(shí)笼平,虛擬機(jī)是使用局部變量表完成參數(shù)值到參數(shù)變量列表的傳遞過程的园骆,如果執(zhí)行的是實(shí)例方法(即非靜態(tài)方法),那局部變量表的第 0 個(gè)索引的 Slot 默認(rèn)是用于傳遞方法所屬對(duì)象實(shí)例的引用寓调, 在方法中可以通過關(guān)鍵字 “this” 來(lái)訪問到這個(gè)隱含的參數(shù)锌唾。其余參數(shù)則按照參數(shù)表順序排列,占用從 1 開始 的局部變量 Slot捶牢,參數(shù)表分配完畢后鸠珠,再根據(jù)方法體內(nèi)部定義的變量順序和作用域分配其余的 Slot。
  1. 操作數(shù)棧
  • 操作數(shù)棧也常稱為操作棧秋麸,它是一個(gè)先進(jìn)后出的棧渐排。
  • 同局部變量表一樣,操作數(shù)棧的最大深度也在編譯的時(shí)候?qū)懭氲?Code 屬性的 max_stacks 數(shù)據(jù)項(xiàng)中灸蟆。棧的最小深度為0驯耻,最大深度直到報(bào)棧溢出異常。
  • 32 位數(shù)據(jù)類型所占的棧容量為 1炒考,64 位數(shù)據(jù)類型所占的棧容量為 2可缚。即 32 位的數(shù)據(jù)類型(boolean、short斋枢、 byte帘靡、char、int瓤帚、float描姚、reference 和 returnAddress)在棧中占 1 個(gè)空間,64 位數(shù)據(jù)類型(long戈次、double)在棧中占 2 個(gè)空間轩勘。
  • 當(dāng)一個(gè)方法剛剛開始執(zhí)行的時(shí)候,這個(gè)方法的操作數(shù)棧是空的怯邪,在方法的執(zhí)行過程中绊寻,會(huì)有各種字節(jié)碼指令往操作數(shù)棧中寫入和提取內(nèi)容,也就是進(jìn)棧和出棧操作悬秉。
  • 操作數(shù)棧中元素的數(shù)據(jù)類型必須與字節(jié)碼指令的序列嚴(yán)格匹配澄步,在編譯程序代碼的時(shí)候,編譯期要嚴(yán)格保證 這一點(diǎn)搂捧,在類校驗(yàn)階段的數(shù)據(jù)流分析中還要再次驗(yàn)證這一點(diǎn)驮俗。
  1. 動(dòng)態(tài)連接
  • 每個(gè)棧幀都包含一個(gè)指向運(yùn)行時(shí)常量池中該棧幀所屬方法的引用, 持有這個(gè)引用是為支持方法調(diào)用過程中的動(dòng)態(tài)連接允跑。Class 文件的常量池存在 大量的符號(hào)引用王凑,字節(jié)碼中的方法調(diào)用指令就以常量池中指向方法的符號(hào)引用 作為參數(shù)搪柑。
  • 符號(hào)引用轉(zhuǎn)換為直接引用可以分為 靜態(tài)解析動(dòng)態(tài)連接
    靜態(tài)解析:存在 Class 文件的常量池中的符號(hào)引用索烹,這些符號(hào)引用一部分會(huì)在類加載或者第一次使用的時(shí)候 就轉(zhuǎn)化為直接引用工碾,這種轉(zhuǎn)化稱為靜態(tài)解析。如靜態(tài)方法和私有方法百姓,前者與類型直接關(guān)聯(lián)渊额,后者在外部不可 被訪問,這兩種方法各自的特定決定了他們都不可能通過繼承或別的方法重寫其他版本垒拢,因此它們都適合在類 加載階段進(jìn)行解析旬迹。
    動(dòng)態(tài)連接:另外一部分符號(hào)引用將在每一次運(yùn)行期間轉(zhuǎn)換為直接引用,這部分成功為動(dòng)態(tài)連接求类。
  1. 方法返回地址
    當(dāng)一個(gè)方法開始執(zhí)行后奔垦, 只有兩種方式可以退出這個(gè)方法。
  • 正常完成出口:這種方式是執(zhí)行引擎遇到任意一個(gè)方法返回的字節(jié)碼指令尸疆, 這時(shí)候可能會(huì)有返回值傳遞給上層的方法調(diào)用者椿猎,是否有返回值和返回值的類 型將根據(jù)遇到何種方法返回指令來(lái)決定。
  • 異常完成出口:這種退出方式是寿弱,在方法執(zhí)行過程中遇到了異常犯眠, 并且這個(gè)異常沒有在方法體內(nèi)得到處理,無(wú)論是 Java 虛擬機(jī)內(nèi)部產(chǎn)生的異常症革, 還是代碼中使用 athrow 字節(jié)碼指令產(chǎn)生的異常筐咧,只要在本方法的異常表中沒有搜索到匹配的異常處理器,就會(huì)導(dǎo)致方法按退出噪矛。

二嗜浮、方法調(diào)用

方法調(diào)用并不等同于方法執(zhí)行,方法調(diào)用階段唯一的任務(wù)就是確定 被調(diào)用方法的版本(即調(diào)用哪一個(gè)方法)摩疑, 暫時(shí)還不涉及到方法內(nèi)部的具體運(yùn)行過程。 在程序運(yùn)行時(shí)畏铆,進(jìn)行方法調(diào)用是最普遍雷袋、最 頻繁的操作,但是 Class 文件的編譯過程中不 包含傳統(tǒng)編譯中的連接步驟辞居,一切方法調(diào)用在 Class 文件里面存儲(chǔ)的都只是符號(hào)引用楷怒,而不是 方法在實(shí)際運(yùn)行時(shí)內(nèi)存布局中的入口地址(直接引用)。 這個(gè)特性給 Java 帶來(lái)了更強(qiáng)大的動(dòng)態(tài)擴(kuò)展能力瓦灶,但也使得 Java 方法調(diào)用過程變得相對(duì)復(fù)雜起來(lái)鸠删,需要在類加載期間, 甚至到運(yùn)行期間才能確定目標(biāo)方法的直接引用贼陶。

  1. 解析調(diào)用
  • 所有方法調(diào)用的目標(biāo)方法在 Class 文件里面都是常量池中的符號(hào)引用刃泡, 在類加載的解析階段巧娱,會(huì)將其中一部分符號(hào)引用轉(zhuǎn)化為直接引用,這種解析能成立的前提是:方法在程序真正運(yùn)行之前就能有一個(gè) 可確定的版本烘贴,并且這個(gè)方法的調(diào)用版本 在運(yùn)行期是不可改變的禁添。換句話說(shuō),調(diào)用目標(biāo)在程序代碼寫好桨踪、編譯期進(jìn)行編譯 時(shí)就必須確定下來(lái)老翘。這類方法的調(diào)用稱為解析(Resolution)。
  • 符合“解析”的方法:在Java語(yǔ)言中符號(hào)“編譯期可知锻离,運(yùn)行期不可變”這個(gè)要求的方法铺峭,主要包括 靜態(tài)方法私有方法 兩大類,前者與類型直接關(guān)聯(lián)汽纠,后者在外部不可被訪問卫键,這兩種方法各自的特定決定了他們都不可能通過繼承或別的方法重寫其他版本,因此它們都適合在類加載階段進(jìn)行解析疏虫。
  1. 分派調(diào)用
    眾所周知永罚,Java 是一門面向?qū)ο蟮某绦蛘Z(yǔ)言,因?yàn)?Java 具備面向?qū)ο蟮?3 個(gè)基本特征:繼承卧秘、封裝和多態(tài)呢袱。分派調(diào)用過程將會(huì)揭示多態(tài)性特征的一些最基本的體現(xiàn),如“重載”和“重寫” 在Java虛擬機(jī)之中是如何實(shí)現(xiàn)的翅敌。分派調(diào)用可以分為 “靜態(tài)分派” 和 “動(dòng)態(tài)分派”羞福。
  • 靜態(tài)分派:所有依賴靜態(tài)類型(方法的參數(shù)類型)來(lái)定位方法執(zhí)行版本的分派動(dòng)作稱為靜態(tài)分派。靜態(tài)分派的典型應(yīng)用是方法的 重載蚯涮。靜態(tài)分派發(fā)生在編譯階段治专,因此確定靜態(tài)分派的動(dòng)作實(shí)際上不是由虛擬機(jī)來(lái)執(zhí)行的。
  • 動(dòng)態(tài)分派
    在運(yùn)行期根據(jù)實(shí)際類型確定方法執(zhí)行版本的分派過程稱為動(dòng)態(tài)動(dòng)態(tài)遭顶。動(dòng)態(tài)分派的典型應(yīng)用是方法的 重寫张峰。動(dòng)態(tài)分派是通過字節(jié)碼 invokevirtual 指令進(jìn)行多態(tài)查找的過程的,而 invokevirtual 字節(jié)碼指令的作用是調(diào)用實(shí)例方法(這里指的是可被重寫的實(shí)例方法)棒旗,invokevirtual 指令的運(yùn)行時(shí)解析過程大致分為以下幾個(gè)步驟:
    1)喘批、找到操作數(shù)棧頂?shù)牡谝粋€(gè)元素所指向的對(duì)象的實(shí)際類型,記作 C铣揉。
    2)饶深、如果在類型 C 中找到與常量中的描述符和簡(jiǎn)單名稱都相符的方法,則進(jìn)行訪問權(quán)限校驗(yàn)逛拱,如果通過則返回這個(gè)方法的直接引用敌厘,查找結(jié)束;如果不通過朽合,則返回 java.lang.IllegalAccessError 異常俱两。
    3)饱狂、否則,按照繼承關(guān)系 從下往上依次對(duì) C 的各個(gè)父類進(jìn)行第 2 步的搜索和驗(yàn)證過程锋华。
    4)嗡官、如果始終沒有找到合適的方法,則拋出 Java.lang.AbstractMethodError 異常毯焕。

三衍腥、方法的執(zhí)行

上面我們了解了虛擬機(jī)是如何調(diào)用方法的,這里我們來(lái)探討一下虛擬機(jī)是如何執(zhí)行方法中的字節(jié)碼指令的纳猫。許多 Java 虛擬機(jī)的執(zhí)行引擎在執(zhí)行 Java 代碼的時(shí)候都有解析執(zhí)行(通過解析器執(zhí)行)和編譯執(zhí)行(通過即時(shí)編譯器產(chǎn)生本地代碼執(zhí)行)兩種選擇(即許多主流的商用虛擬機(jī)都同時(shí)包含解析器與編譯器)婆咸,這里主要說(shuō)明一下解析執(zhí)行。

1芜辕、基于棧的指令集和基于寄存器的指令集
Java 編譯器輸出的指令流尚骄,基本上是一種 基于棧的指令集架構(gòu),指令流中的指令大部分都是零地址指令侵续,它們依賴操作數(shù)棧進(jìn)行工作倔丈,與之相對(duì)的另一套常用的指令集架構(gòu)是 基于寄存器的指令集,最典型的就是 x86 的二地址指令集状蜗,換句話說(shuō)需五,就是現(xiàn)在我們主流 PC 機(jī)中直接支持的指令集架構(gòu),這些指令依賴寄存器進(jìn)行工作轧坎。那么棧的指令集與基于寄存器的指令集這兩者之間有什么不同呢宏邮?
舉個(gè)例子,分別使用兩種指令集計(jì)算 “1 + 1” 的結(jié)果缸血,基于棧的指令集回事這樣的:

iconst_1
iconst_1
iadd
istore_0

兩條 iconst_1 指令連續(xù)把兩個(gè)常量 1 壓入操作數(shù)棧中蜜氨,iadd 指令把棧頂?shù)膬蓚€(gè)值出棧、相加捎泻,然后把結(jié)果放回棧頂飒炎,最后 istore_0 把棧頂?shù)闹捣诺骄植孔兞勘淼牡?0 個(gè) Slot(變量槽) 中。
如果基于寄存器笆豁,那程序可能會(huì)是這個(gè)樣子:

mov eax, 1
add eax, 1

mov 指令把 EAX 寄存器的值設(shè)為 1厌丑,然后 add 指令再把這個(gè)值加 1,最后結(jié)果再保存到 EAX 寄存器中渔呵。
基于棧的指令集和基于寄存器的指令集比較:

  • 基于棧的指令集的主要優(yōu)點(diǎn)是可移植,而寄存器由硬件直接提供砍鸠,程序直接依賴這些硬件寄存器則不可避免的要收到硬件的約束扩氢。
  • 基于棧的指令集還有一些優(yōu)點(diǎn),如代碼更加緊湊爷辱、編譯器實(shí)現(xiàn)更加簡(jiǎn)單等录豺。
  • 棧結(jié)構(gòu)指令集的主要缺點(diǎn)是執(zhí)行速度相對(duì)來(lái)說(shuō)會(huì)稍慢一點(diǎn)朦肘,因?yàn)閷?shí)現(xiàn)相同的功能,需要的指令數(shù)量一般會(huì)比寄存器指令集多双饥,因出棧媒抠、入棧操作本身就產(chǎn)生了相當(dāng)多的指令數(shù)量。

2咏花、基于棧的解析器執(zhí)行過程
這里通過一個(gè)例子來(lái)說(shuō)明一下趴生,代碼如下所示。

這里主要說(shuō)明執(zhí)行 calc() 方法的字節(jié)碼指令昏翰,我們使用 javap -verbose MethodExecutor 命令查看它的 Class 文件的字節(jié)碼指令如下所示苍匆。
javap 提示這段代碼需要深度為 2 的操作數(shù)棧和 4 個(gè) Slot 的局部變量表,由于這是一個(gè)實(shí)例方法棚菊,所以局部變量表的第 0 個(gè)位置為 “this”浸踩,下面通過圖解的方式描述 calc() 方法的字節(jié)碼指令執(zhí)行過程,以及描述執(zhí)行過程中的代碼统求、操作數(shù)棧检碗、布局變量表的變化情況。
執(zhí)行偏移地址為 0 的指令的情況
執(zhí)行偏移地址為 2 的指令的情況
執(zhí)行偏移地址為 11 的指令的情況
執(zhí)行偏移地址為 12 的指令的情況
執(zhí)行偏移地址為 13 的指令的情況
執(zhí)行偏移地址為 14 的指令的情況
執(zhí)行偏移地址為 16 的指令的情況
我們從這段程序的執(zhí)行中可以看出棧結(jié)構(gòu)指令集的一般運(yùn)行過程码邻,整個(gè)運(yùn)算過程的中間變量都以操作數(shù)棧的出棧折剃、入棧為信息交換途徑。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末冒滩,一起剝皮案震驚了整個(gè)濱河市微驶,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌开睡,老刑警劉巖因苹,帶你破解...
    沈念sama閱讀 218,525評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異篇恒,居然都是意外死亡扶檐,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門胁艰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)款筑,“玉大人,你說(shuō)我怎么就攤上這事腾么∧问幔” “怎么了?”我有些...
    開封第一講書人閱讀 164,862評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵解虱,是天一觀的道長(zhǎng)攘须。 經(jīng)常有香客問我,道長(zhǎng)殴泰,這世上最難降的妖魔是什么于宙? 我笑而不...
    開封第一講書人閱讀 58,728評(píng)論 1 294
  • 正文 為了忘掉前任浮驳,我火速辦了婚禮,結(jié)果婚禮上捞魁,老公的妹妹穿的比我還像新娘至会。我一直安慰自己,他們只是感情好谱俭,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,743評(píng)論 6 392
  • 文/花漫 我一把揭開白布奉件。 她就那樣靜靜地躺著,像睡著了一般旺上。 火紅的嫁衣襯著肌膚如雪瓶蚂。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,590評(píng)論 1 305
  • 那天宣吱,我揣著相機(jī)與錄音窃这,去河邊找鬼。 笑死征候,一個(gè)胖子當(dāng)著我的面吹牛杭攻,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播疤坝,決...
    沈念sama閱讀 40,330評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼兆解,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了跑揉?” 一聲冷哼從身側(cè)響起锅睛,我...
    開封第一講書人閱讀 39,244評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎历谍,沒想到半個(gè)月后现拒,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,693評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡望侈,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,885評(píng)論 3 336
  • 正文 我和宋清朗相戀三年印蔬,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片脱衙。...
    茶點(diǎn)故事閱讀 40,001評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡侥猬,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出捐韩,到底是詐尸還是另有隱情退唠,我是刑警寧澤,帶...
    沈念sama閱讀 35,723評(píng)論 5 346
  • 正文 年R本政府宣布荤胁,位于F島的核電站铜邮,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜松蒜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,343評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望已旧。 院中可真熱鬧秸苗,春花似錦、人聲如沸运褪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)秸讹。三九已至檀咙,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間璃诀,已是汗流浹背弧可。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留劣欢,地道東北人棕诵。 一個(gè)月前我還...
    沈念sama閱讀 48,191評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像凿将,于是被迫代替她去往敵國(guó)和親校套。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,955評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容