精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

深度解密 Python 虛擬機的執行環境:棧幀對象

開發 前端
因為很多動態信息無法靜態地存儲在 PyCodeObject 對象中,所以 PyCodeObject 對象在交給虛擬機之后,虛擬機會在其之上動態地構建出 PyFrameObject 對象,也就是棧幀。

楔子

從現在開始,我們將剖析虛擬機運行字節碼的原理。前面說了,Python 解釋器可以分為兩部分:Python 編譯器和 Python 虛擬機。

編譯器將源代碼編譯成 PyCodeObject 對象之后,就由虛擬機接手整個工作。虛擬機會從 PyCodeObject 中讀取字節碼,并在當前的上下文中執行,直到所有的字節碼都被執行完畢。

那么問題來了,既然源代碼在經過編譯之后,字節碼指令以及靜態信息都存儲在 PyCodeObject 當中,那么是不是意味著虛擬機就在 PyCodeObject 對象上進行所有的動作呢?

很明顯不是的,因為盡管 PyCodeObject 包含了關鍵的字節碼指令以及靜態信息,但有一個東西是沒有包含、也不可能包含的,就是程序在運行時的執行環境,這個執行環境在 Python 里面就是棧幀。

棧幀:虛擬機的執行環境

那什么是棧幀呢?我們舉個例子。

name = "古明地覺"

def some_func():
    name = "八意永琳"
    print(name)

some_func()
print(name)

上面的代碼當中出現了兩個 print(name),它們的字節碼指令相同,但執行的效果卻顯然是不同的,這樣的結果正是執行環境的不同所產生的。因為環境的不同,name 的值也不同。

因此同一個符號在不同環境中可能指向不同的類型、不同的值,必須在運行時進行動態捕捉和維護,這些信息不可能在 PyCodeObject 對象中被靜態存儲。

因此虛擬機并不是在 PyCodeObject 對象上執行操作的,而是在棧幀對象上。虛擬機在執行時,會根據 PyCodeObject 對象動態創建出棧幀對象,然后在棧幀里面執行字節碼。所以棧幀是虛擬機執行的上下文,執行時依賴的所有信息都存儲在棧幀中。

因此對于上面的代碼,我們可以大致描述一下流程:

  • 首先基于模塊的 PyCodeObject 創建一個棧幀,假設叫 A,所有的字節碼都會在棧幀中執行,虛擬機可以從棧幀里面獲取變量的值,也可以修改;
  • 當發生函數調用的時候,這里是 some_func,那么虛擬機會在棧幀 A 之上,為 some_func 創建一個新的棧幀,假設叫 B,然后在棧幀 B 里面執行函數 some_func 的字節碼指令;
  • 在棧幀 B 里面也有一個名字為 name 的變量,但由于執行環境、或者說棧幀的不同,name 指向的對象也不同;
  • 一旦函數 some_func 的字節碼指令全部執行完畢,那么會將當前的棧幀 B 銷毀(也可以保留),再回到調用者的棧幀中來。就像是遞歸一樣,每當調用函數時,就會在當前棧幀之上創建一個新的棧幀,一層一層創建,一層一層返回;

虛擬機和操作系統

不難發現,Python 虛擬機執行字節碼這個過程,就是在模擬操作系統運行可執行文件。比如:

程序加載

  • 操作系統:加載可執行文件到內存,設置程序計數器。
  • Python 虛擬機:加載 .pyc 文件中的 PyCodeObject 對象,初始化字節碼指令指針。

內存管理

  • 操作系統:為進程分配內存空間,管理堆和棧。
  • Python 虛擬機:創建和管理 Python 對象,處理內存分配和垃圾回收。

指令執行

  • 操作系統:CPU 逐條執行機器指令。
  • Python 虛擬機:虛擬機逐條執行字節碼指令。

資源管理

  • 操作系統:管理文件句柄、網絡連接等系統資源。
  • Python 虛擬機:管理文件對象、套接字等 Python 級別的資源。

異常處理

  • 操作系統:處理硬件中斷和軟件異常。
  • Python 虛擬機:捕獲和處理 Python 異常。

我們簡單地畫一張示意圖,來看看在一臺普通的 x64 機器上,可執行文件是以什么方式運行的,在這里主要關注棧幀的變化。假設有三個函數,函數 f 調用了函數 g,函數 g 又調用了函數 h。

圖片圖片

首先 CPU 有兩個關鍵的寄存器,它們在函數調用和棧幀管理中扮演關鍵角色。

RSP(Stack Pointer):棧指針,指向當前棧幀的頂部,或者說最后一個入棧的元素。因此隨著元素的入棧和出棧,RSP 會動態變化。由于地址從棧底到棧頂是逐漸減小的,所以 RSP 會隨著數據入棧而減小,隨著數據出棧而增大。當然不管 RSP 怎么變,它始終指向當前棧的頂部。

RBP(Base Pointer):基指針,指向當前棧幀的基址,它的作用是提供一個固定的參考點,用于訪問當前函數的局部變量和參數。當新的幀被創建時,它的基址會保存上一個幀的基址,并由 RBP 指向。

我們用一段 C 代碼來解釋一下。

#include <stdio.h>

int add(int a, int b) {
    int c = a + b;
    return c;
}

int main() {
    int a = 11;
    int b = 22;
    int result = add(a, b);
    printf("a + b = %d\n", result);
}

當執行函數 add 時,那么當前幀顯然就是函數 add 的棧幀,而調用者的幀(上一級棧幀)顯然就是函數 main 的棧幀。

棧是先入后出的數據結構,地址從棧底到棧頂是減小的。對于一個函數而言,所有對局部變量的操作都在自己的棧幀中完成,而調用函數的時候則會為其創建新的棧幀。

當執行函數 main 的時候,RSP 指向 main 棧幀的頂部,RBP 指向 main 棧幀的基址。然后在 main 里面又調用了函數 add,那么毫無疑問,系統會在地址空間中,在 main 的棧幀之上為 add 創建棧幀。然后讓 RSP 指向 add 棧幀的頂部,RBP 指向 add 棧幀的基址,而 add 棧幀的基址保存了上一級棧幀(main 棧幀)的基址。

當函數 add 執行結束時,會銷毀對應棧幀,再將 RSP 和 RBP 恢復為創建 add 棧幀之前的值,這樣程序的執行流程就又回到了函數 main 里面,當然程序的運行空間也回到了函數 main 的棧幀中。

不難發現,通過兩個 CPU 寄存器 RSP、RBP,以及棧幀中保存的上一級棧幀的基址,完美地維護了函數之間的調用鏈,這就是可執行文件在 x64 機器上的運行原理。

那么 Python 里面的棧幀是怎樣的呢?

棧幀的底層結構

相較于 x64 機器上看到的那個簡簡單單的棧幀,Python 的棧幀實際上包含了更多的信息。注:棧幀也是一個對象。

// Include/pytypedefs.h
typedef struct _frame PyFrameObject;

// Include/internal/pycore_frame.h
struct _frame {
    PyObject_HEAD
    PyFrameObject *f_back;     
    struct _PyInterpreterFrame *f_frame; 
    PyObject *f_trace;          
    int f_lineno;               
    char f_trace_lines;         
    char f_trace_opcodes;       
    char f_fast_as_locals;      
};

typedef struct _PyInterpreterFrame {
    PyCodeObject *f_code; 
    struct _PyInterpreterFrame *previous;
    PyObject *f_funcobj; 
    PyObject *f_globals; 
    PyObject *f_builtins; 
    PyObject *f_locals;
    PyFrameObject *frame_obj;
    _Py_CODEUNIT *prev_instr;
    int stacktop;
    uint16_t return_offset;
    char owner;
    PyObject *localsplus[1];
} _PyInterpreterFrame;

棧幀在底層由 PyFrameObject 表示,在 3.11 之前,所有字段都保存在該結構體中。但里面有一部分字段,在大部分情況下都用不到,比如一些用于 Debug 的字段。而這些不常用的字段,顯然會導致內存浪費,因為創建棧幀時要為所有字段都申請內存空間。

于是從 3.11 開始,虛擬機將 PyFrameObject 里面的核心字段提取出來,形成了更加輕量級的 _PyInterpreterFrame,從而減少內存使用并提高性能。

  • _PyInterpreterFrame:棧幀的核心結構,這是一個輕量級的 C 結構,只包含執行所需的基本信息,虛擬機會在內部使用它。
  • PyFrameObject:完整的棧幀對象,在需要更全面的幀信息時使用。比如從 Python 級別獲取棧幀時,拿到的對象在底層對應的就是 PyFrameObject 結構體。

通過這種拆分,虛擬機在大多數情況下只需使用輕量級的 _PyInterpreterFrame 即可,只有在需要完整的幀信息時,才會創建 PyFrameObject。

但要強調的是,由于 _PyInterpreterFrame 里面沒有 PyObject,所以它不是 Python 對象,它只是包含了棧幀的核心結構,真正的棧幀對象仍是 PyFrameObject。只不過對于虛擬機而言,很多時候只需實例化 _PyInterpreterFrame 結構體,即可完成任務。

另外 _PyInterpreterFrame 除了更輕量、結構更緊湊、創建速度快之外,它對 CPU 緩存也非常友好。

我們知道 Python 對象都是申請在堆上的,棧幀也不例外,當調用嵌套函數時,這些棧幀對象會零散在堆區的不同位置,對緩存不友好。但 _PyInterpreterFrame 則不是這樣,虛擬機為它專門引入了一個 Stack,這是一段預分配的內存區域,專門用于存儲 _PyInterpreterFrame 實例。

當需要創建 _PyInterpreterFrame 實例時,只需要改動一下棧指針,內存便創建好了。當需要銷毀時,直接將它從棧的頂端彈出即可,不需要顯式地釋放內存。并且由于 _PyInterpreterFrame 都是緊密排列在一起,所以對緩存也更加友好。

字段含義解析與代碼演示

下面來看一下這兩個結構體里面的字段都表示啥含義,不過在解釋字段含義之前,我們需要先知道如何在 Python 中獲取棧幀對象。

import inspect

def foo():
    # 返回當前所在的棧幀
    # 這個函數實際上是調用了 sys._getframe(1)
    return inspect.currentframe()

frame = foo()
print(frame) 
"""
<frame at 0x100de0fc0, file '.../main.py', line 6, code foo>
"""
print(type(frame)) 
"""
<class 'frame'>
"""

我們看到棧幀的類型是 <class 'frame'>,正如 PyCodeObject 對象的類型是 <class 'code'> 一樣,這兩個類沒有暴露給我們,所以不可以直接使用。

同理,還有 Python 的函數,類型是 <class 'function'>,模塊的類型是 <class 'module'>。這些解釋器都沒有給我們提供,如果直接使用的話,那么 frame、code、function、module 只是幾個沒有定義的變量罷了,這些類我們只能通過這種間接的方式獲取。

下面我們來看一下 PyFrameObject 里面每個字段的含義。

PyObject_HEAD

對象的頭部信息,所以棧幀也是一個對象。

PyFrameObject *f_back

當前棧幀的上一級棧幀,也就是調用者的棧幀。所以 x64 機器是通過 RSP、RBP 兩個指針維護函數的調用關系,而 Python 虛擬機則是通過棧幀的 f_back 字段。

import inspect

def foo():
    return inspect.currentframe()

frame = foo()
print(frame)
"""
<frame at 0x100de0fc0, file '.../main.py', line 6, code foo>
"""
# foo 的上一級棧幀,顯然對應的是模塊的棧幀
print(frame.f_back)
"""
<frame at 0x100adde40, file '.../main.py', line 12, code <module>>
"""
# 相當于模塊的上一級棧幀,顯然是 None
print(frame.f_back.f_back)
"""
None
"""

所以通過棧幀,你可以輕松地獲取完整的函數調用鏈路,我們一會兒演示。

struct _PyInterpreterFrame *f_frame

指向 struct _PyInterpreterFrame 實例,它包含了棧幀的核心結構。

PyObject *f_trace

追蹤函數,用于調試。

int f_lineno

獲取該棧幀時的源代碼行號。

import inspect

def foo():
    return inspect.currentframe()

frame = foo()
print(frame.f_lineno)  # 4

我們是在第 4 行獲取的棧幀,所以打印結果是 4。

char f_trace_lines

是否為每一行代碼調用追蹤函數,當設置為真(非零值)時,每當虛擬機執行到一個新的代碼行時,都會調用追蹤函數。這允許調試器在每行代碼執行時進行干預,比如設置斷點、檢查變量等。

char f_trace_opcodes

是否為每個字節碼指令調用追蹤函數,當設置為真時,虛擬機會在執行每個字節碼指令之前調用追蹤函數。這提供了更細粒度的控制,允許進行指令級別的調試。

所以不難發現,f_trace_lines 是行級追蹤,對應源代碼的每一行,通常用于普通的調試,如設置斷點、單步執行等,并且開銷相對較小。f_trace_opcodes 是指令級追蹤,對應每個字節碼指令,通常用于更深層次的調試,比如分析具體的字節碼執行過程,并且開銷較大。

import sys

def trace_lines(frame, event, arg):
    print(f"行號:{frame.f_lineno},文件名:{frame.f_code.co_filename}")
    return trace_lines

sys.settrace(trace_lines)

設置追蹤函數一般需要通過 sys.settrace,不過不常用,了解一下即可。

char f_fast_as_locals

要解釋這個字段,需要用到后續的知識,所以這里先簡單了解一下即可。Python 函數的局部變量是采用數組存儲的,以便快速訪問,這就是所謂的 fast locals。

但有時候我們就是需要一個字典,里面包含所有的局部變量,這時候可以調用 locals 函數,將局部變量的名稱和值以 key、value 的形式拷貝到字典中。而 f_fast_as_locals 字段則負責標記這個拷貝過程是否發生過。

然后再來看看 _PyInterpreterFrame 結構體里面的字段,我們說棧幀的核心字段都在該結構體中。

PyCodeObject *f_code

棧幀對象是在 PyCodeObject 之上構建的,所以它內部一定有一個字段指向 PyCodeObject。

import inspect

def e():
    f()

def f():
    g()

def g():
    h()

def h():
    frame = inspect.currentframe()  # 獲取棧幀
    func_names = []
    # 只要 frame 不為空,就一直循環,并將函數名添加到列表中
    while frame is not None:
        func_names.append(frame.f_code.co_name)
        frame = frame.f_back
    print(f"函數調用鏈路:{' -> '.join(func_names[:: -1])}")

f()
"""
函數調用鏈路:<module> -> f -> g -> h
"""

模塊 -> f -> g -> h,顯然我們獲取了整個調用鏈路,是不是很有趣呢?

struct _PyInterpreterFrame *previous

指向上一個 struct _PyInterpreterFrame,該字段底層沒有暴露出來。

PyObject *f_funcobj

指向對應的函數對象,該字段解釋器沒有暴露出來。

PyObject *f_globals

指向全局名字空間(一個字典),它是全局變量的容身之所。是的,Python 的全局變量是通過字典存儲的,調用函數 globals 即可拿到該字典。

# 等價于 name = "古明地覺"
globals()["name"] = "古明地覺"

# 等價于 print(name)
print(globals()["name"])  # 古明地覺

def foo():
    import inspect
    return inspect.currentframe()

frame = foo()
# frame.f_globals 同樣會返回全局名字空間
print(frame.f_globals is globals())  # True
# 相當于創建了一個全局變量 age
frame.f_globals["age"] = 18
print(age)  # 18

關于名字空間,我們后面會用專門的篇幅詳細說明。

PyObject *f_locals

指向局部名字空間(一個字典),但和全局變量不同,局部變量不存在局部名字空間中,而是靜態存儲在數組中。該字段先有個印象,后續再詳細說。

PyObject *f_builtins

指向內建名字空間(一個字典),顯然一些內置的變量都存在里面。

def foo():
    import inspect
    return inspect.currentframe()

frame = foo()
print(frame.f_builtins["list"]("abcd"))
"""
['a', 'b', 'c', 'd']
"""

和我們直接使用 list("abcd") 是等價的。

PyFrameObject *frame_obj

這個不用多說,負責指向 PyFrameObject 對象。

_Py_CODEUNIT *prev_instr

指向上一條已執行完畢的字節碼指令,比如虛擬機要執行第 n 條指令,那么 prev_instr 便指向第 n - 1 條指令。由于每個指令都帶有一個參數,所以 _Py_CODEUNIT 類型的大小是 2 字節。

int stacktop

表示棧頂相對于 localsplus 數組的偏移量。

uint16_t return_offset

表示 RETURN 指令相對 prev_instr 的偏移量,這個值只對被調用的函數有意義,它指示了函數返回后,調用者應該從哪里繼續執行。它會在 CALL 指令(調用函數時)和 SEND 指令(發送數據到協程或生成器時)中設置。

這個設計允許更高效的函數返回處理,因為虛擬機可以直接跳轉到正確的位置,而不需要額外的查找或計算。

def main():
    x = some_func()  # CALL 指令在這里
    y = x + 1     # 函數返回后應該執行的下一條指令

def some_func():
    return 42

當調用 some_func 時,虛擬機會執行 CALL 指令,在 CALL 指令中,會設置 return_offset。當執行完 some_func 的 RETURN 指令時,它會使用 return_offset 來決定跳轉到調用者(main)中的哪個位置。

這種機制的優點是不需要在運行時計算返回位置,因為它已經在調用時預先計算好了,特別適用于處理生成器和協程等復雜控制流。

char owner

表示幀的所有權信息,用于區分幀是在虛擬機棧上的,還是單獨分配的。

PyObject *localsplus[1]

一個柔性數組,負責維護 "局部變量 + cell 變量 + free 變量 + 運行時棧",大小在運行時確定。

以上就是棧幀內部的字段,這些字段先有個印象,后續在剖析虛擬機的時候還會繼續細說。

總之我們看到,PyCodeObject 并不是虛擬機的最終目標,虛擬機最終是在棧幀中執行的。每一個棧幀都會維護一個 PyCodeObject 對象,換句話說,每一個 PyCodeObject 對象都會隸屬于一個棧幀。并且從 f_back 可以看出,虛擬機在實際執行時,會產生很多的棧幀對象,而這些對象會被鏈接起來,形成一條執行環境鏈表,或者說棧幀鏈表。

而這正是 x64 機器上棧幀之間關系的模擬,在 x64 機器上,棧幀之間通過 RSP 和 RBP 指針建立了聯系,使得新棧幀在結束之后能夠順利地返回到舊棧幀中,而 Python 虛擬機則是利用 f_back 來完成這個動作。

當然,獲取棧幀除了通過 inspect 模塊之外,在捕獲異常時,也可以獲取棧幀。

def foo():
    try:
        1 / 0
    except ZeroDivisionError:
        import sys
        # exc_info 返回一個三元組
        # 分別是異常的類型、值、以及 traceback
        exc_type, exc_value, exc_tb = sys.exc_info()
        print(exc_type)  # <class 'ZeroDivisionError'>
        print(exc_value)  # division by zero
        print(exc_tb)  # <traceback object at 0x00000135CEFDF6C0>

        # 調用 exc_tb.tb_frame 即可拿到異常對應的棧幀
        # 另外這個 exc_tb 也可以通過下面這種方式獲取
        # except ZeroDivisionError as e; e.__traceback__
        print(exc_tb.tb_frame.f_code.co_name)  # foo
        print(exc_tb.tb_frame.f_back.f_code.co_name)  # <module>
        # 顯然 tb_frame 是當前函數 foo 的棧幀
        # 那么 tb_frame.f_back 就是整個模塊對應的棧幀
        # 而 tb_frame.f_back.f_back 顯然就是 None 了
        print(exc_tb.tb_frame.f_back.f_back)  # None

foo()

關于棧幀內部的字段的含義,我們就說完了。當然如果有些字段現在不是很理解,也沒關系,隨著不斷地學習,你會豁然開朗。

小結

因為很多動態信息無法靜態地存儲在 PyCodeObject 對象中,所以 PyCodeObject 對象在交給虛擬機之后,虛擬機會在其之上動態地構建出 PyFrameObject 對象,也就是棧幀。

因此虛擬機是在棧幀里面執行的字節碼,它包含了虛擬機在執行字節碼時依賴的全部信息。


責任編輯:武曉燕 來源: 古明地覺的編程教室
相關推薦

2010-02-24 10:39:28

Python虛擬機

2010-02-24 10:49:11

Python運行環境

2023-07-27 06:59:30

Native線程數據結構

2010-02-04 10:05:28

Dalvik虛擬機

2013-06-17 10:16:53

虛擬機虛擬化安全

2018-04-04 15:05:17

虛擬機字節碼引擎

2014-11-27 15:08:05

虛擬化動態遷移

2020-06-03 15:07:01

Java虛擬機棧JVM

2024-03-26 07:30:07

Java虛擬機源文件

2009-08-18 10:48:33

2012-05-18 10:22:23

2010-07-21 14:30:53

2010-06-11 14:50:48

虛擬機安裝openSU

2019-07-05 15:14:34

虛擬機WindowsWindows 10

2019-02-26 14:33:22

JVM內存虛擬機

2017-11-14 16:43:13

Java虛擬機線程

2020-01-17 10:52:37

無服務器容器技術

2013-07-17 09:32:58

2010-07-26 09:02:38

2013-08-16 11:17:35

虛擬桌面虛擬快照
點贊
收藏

51CTO技術棧公眾號

91久久久在线| 色偷偷91综合久久噜噜| 国自产拍偷拍精品啪啪一区二区| 天堂在线观看av| 免费欧美日韩| 在线观看欧美视频| 性生活在线视频| 欧美aa一级| 国产精品美女视频| 国产中文一区二区| 日韩一级理论片| 91在线不卡| 国产69精品一区二区亚洲孕妇| 97在线免费观看| 亚洲色图 激情小说| 亚洲伊人影院| 欧美自拍偷拍一区| 国产资源第一页| 天堂中文资源在线| 欧美日本不卡高清| 亚洲乱码av中文一区二区| 人人干人人干人人| 乱人伦视频在线| 成人免费视频在线观看| 久久riav| 国产99视频在线| 久久国产精品亚洲77777| 久久久av网站| www.黄色在线| 欧美aaaaa级| 欧美一级艳片视频免费观看| 日韩精品一区二区三区色欲av| 蜜桃av在线免费观看| 91麻豆福利精品推荐| 91亚洲人电影| 最近中文在线观看| 国产亚洲激情| 久久久久久亚洲精品| 女人18毛片毛片毛片毛片区二 | 一区二区三区影院| 日韩国产精品一区二区| 天天干天天色天天| 国产成人日日夜夜| 成人高清视频观看www| 黄色片视频免费| 国产欧美丝祙| 国内精品一区二区三区四区| 91视频综合网| 天天精品视频| 久久精品国产清自在天天线| 国产一级久久久久毛片精品| 天天躁日日躁成人字幕aⅴ| 日韩午夜精品视频| 国产又粗又猛大又黄又爽| 99蜜月精品久久91| 欧美体内she精视频| 妺妺窝人体色www在线观看| 中文字幕21页在线看| 黄色一区二区在线| www.99热这里只有精品| sm捆绑调教国产免费网站在线观看| 樱桃视频在线观看一区| 中国女人做爰视频| 2024短剧网剧在线观看| 一区二区三区精品| 国产精品国三级国产av| 免费男女羞羞的视频网站在线观看| 亚洲女与黑人做爰| 日韩精品久久一区二区| 蜜臀av在线| 亚洲1区2区3区4区| 国模吧无码一区二区三区| 中文在线最新版地址| 色999日韩国产欧美一区二区| 成人在线激情网| 麻豆精品蜜桃| 欧美日本韩国一区| 青青草精品在线| 国产福利一区二区精品秒拍| 日韩av中文在线| 成年人网站免费在线观看| 国产精品日韩精品中文字幕| 国产亚洲精品久久久久久777| 男女男精品视频网站| 午夜精品久久久久久久四虎美女版| 久久精品一区中文字幕| 激情综合五月网| 欧美日韩亚洲一区| 欧美中文字幕视频在线观看| 日韩中文字幕高清| 精品中文字幕一区二区| 国产福利久久| 男女视频在线观看| 中文字幕在线不卡| 国产96在线 | 亚洲| 精品无人乱码一区二区三区 | 免费在线不卡av| 久草中文综合在线| 国产亚洲欧美一区二区三区| 黄色av网站在线免费观看| 17c精品麻豆一区二区免费| 屁屁影院ccyy国产第一页| 91av亚洲| 在线综合+亚洲+欧美中文字幕| 白嫩情侣偷拍呻吟刺激| 欧美丝袜一区| 久久久久久一区二区三区| 青青艹在线观看| 丰满岳乱妇一区二区三区| 欧美日韩在线一区二区三区| 成a人片在线观看| 日本精品一区二区三区高清 | 亚洲美女久久精品| 欧美精品久久99久久在免费线 | 成人在线国产视频| 999国产精品亚洲77777| 亚洲第一区第一页| 波多野结衣久久久久| 欧美专区18| 91传媒在线免费观看| 国产精品天堂| 午夜精品久久久久久久蜜桃app| 美女网站视频黄色| 美腿丝袜亚洲图片| 精品国产一区二区三区久久| 青青草免费观看视频| 国产福利精品导航| 亚洲人成77777| h片视频在线观看| 欧美疯狂性受xxxxx喷水图片| 网站免费在线观看| 亚洲91中文字幕无线码三区| 日产精品99久久久久久| 高清一区二区三区四区| 亚洲欧美日韩久久精品| 欧美第一页浮力影院| 欧美精美视频| 欧美性资源免费| 人妻少妇一区二区三区| 亚洲综合色区另类av| 天天做天天干天天操| 国产综合久久久| 国产91ⅴ在线精品免费观看| 亚洲精品久久久久久久久久 | 日韩欧美精品久久| 国产直播在线| 精品久久久久久久久久久久久久久| 99成人在线观看| 久久国产成人午夜av影院| 日韩av大全| 成人在线爆射| 亚洲美女福利视频网站| 久久精品国产成人av| proumb性欧美在线观看| 日韩网站在线免费观看| 国产精品白浆| 国内精品久久久| 欧美一级片免费| 亚洲成人你懂的| 国产情侣久久久久aⅴ免费| 欧美精品一区二区三区久久久竹菊| 亚洲iv一区二区三区| 操你啦视频在线| 日韩一区二区三区高清免费看看| 69av.com| 福利一区在线观看| 国产成人精品视频免费看| 欧美色资源站| 日本韩国欧美精品大片卡二| 九色蝌蚪在线| 欧美日韩不卡一区二区| 久久久久亚洲av片无码| 国产成人av电影在线观看| 日韩 欧美 视频| 欧美日韩直播| 国产精品va在线播放我和闺蜜| 成年午夜在线| 91麻豆精品91久久久久久清纯| 极品久久久久久| 成人精品高清在线| 免费在线观看日韩视频| 不卡在线一区二区| 亚洲影院在线看| 成入视频在线观看| 色悠悠久久久久| 亚洲卡一卡二卡三| 色婷婷国产精品综合在线观看| 2017亚洲天堂| 国产成人av电影在线观看| 成人毛片视频网站| 色999日韩| 鬼打鬼之黄金道士1992林正英| caoprom在线| 国产亚洲精品va在线观看| 国产青青草视频| 午夜久久电影网| 国产综合精品久久久久成人av| 精品一区二区三区香蕉蜜桃| 国产精品12345| 日韩欧美在线中字| 国产另类自拍| 久久久免费人体| 久久久视频在线| 成人在线观看免费| 精品国产乱码久久久久久浪潮 | 麻豆传媒免费在线观看| 亚洲成年网站在线观看| 中文字幕日韩国产| 午夜视频在线观看一区二区| 18啪啪污污免费网站| 成人激情小说网站| 中文字幕国产免费| 日韩午夜一区| 天天干天天色天天爽| 性欧美lx╳lx╳| 999热视频在线观看| 欧美日韩精品免费观看视欧美高清免费大片 | 日韩欧美二区三区| www.欧美色| 性做久久久久久久免费看| 天海翼在线视频| 久久精品视频免费观看| 折磨小男生性器羞耻的故事| 蜜臀久久99精品久久久久宅男| 丝袜人妻一区二区三区| 婷婷精品进入| 深田咏美在线x99av| 成人av综合网| 3d动漫啪啪精品一区二区免费 | 韩国av在线免费观看| 欧美午夜寂寞影院| 欧美日韩一二三四区| 亚洲国产日韩a在线播放| 国产成人av免费在线观看| 日本一区二区三区免费乱视频| 无码av天堂一区二区三区| 国产特黄在线| 亚洲大尺度美女在线| 99re只有精品| 欧美视频在线一区二区三区 | 91蜜桃免费观看视频| 日本一二三四区视频| 蜜桃av一区二区在线观看| 日韩在线一级片| 亚洲国产三级| 小泽玛利亚av在线| 99久久.com| 亚洲乱码国产乱码精品天美传媒| 国产一区二区观看| 欧美精品一区二区三区在线四季 | 欧美日韩国产大片| 久久久久精彩视频| 欧美性生交片4| 免费黄色一级大片| 欧美色手机在线观看| 波多野结衣视频在线观看| 色综合久久久久综合体桃花网| 99精品视频99| 精品日韩中文字幕| 日韩精品一区二区亚洲av| 欧美视频免费在线观看| 伊人手机在线视频| 日韩欧美在线中文字幕| 男人天堂2024| 在线视频一区二区三| 国产精品露脸视频| 欧美久久一二三四区| 国产精品毛片一区视频播| 91精品国产全国免费观看| 中文字字幕在线中文乱码| 欧美日韩五月天| 国产视频www| 日韩女优毛片在线| 人妻妺妺窝人体色www聚色窝| 亚洲激情视频网站| 牛牛热在线视频| 中国人与牲禽动交精品| 色视频在线免费观看| 久久综合伊人77777蜜臀| 波多野结衣久久| 欧美孕妇孕交黑巨大网站| 欧洲av一区二区| 成人福利网站在线观看11| 视频精品一区| 久久综合伊人77777麻豆| 精品国产乱码久久久| 欧美一级免费在线观看| 伊人久久久大香线蕉综合直播| 欧美aⅴ在线观看| 另类综合日韩欧美亚洲| 欧美图片自拍偷拍| 久久香蕉国产线看观看99| 色婷婷粉嫩av| 亚洲国产精品自拍| 成年人视频免费| 欧美高清视频一二三区| 欧美自拍偷拍第一页| 亚洲天堂男人的天堂| 国产激情视频在线| 欧美性在线视频| av在线精品| 久久艳妇乳肉豪妇荡乳av| 99精品在线免费在线观看| 日本欧美黄色片| 精品一区二区三区视频在线观看| 欧美xxxx×黑人性爽| 国产欧美久久久精品影院| 欧美片一区二区| 欧美亚洲一区三区| 好吊色一区二区| 日韩中文av在线| 日本不卡1234视频| 亚洲tv在线观看| 国产精品免费99久久久| 青青在线视频免费观看| 蜜臀av一区二区在线免费观看| 国产精品成人免费一区久久羞羞| 中文字幕免费不卡在线| 亚洲天堂日韩av| 欧美一级片在线观看| www.国产精品.com| 欧美亚洲激情视频| jazzjazz国产精品久久| 国产又爽又黄ai换脸| 丝袜美腿亚洲综合| 美女久久久久久久久| 综合久久国产九一剧情麻豆| 国产亚洲欧美日韩高清| 日韩精品一二三四区| 最新超碰在线| 国产精品网址在线| 日韩欧美天堂| 国产 日韩 欧美在线| 国产精品一级在线| 黑人狂躁日本娇小| 在线视频中文字幕一区二区| 污污的视频网站在线观看| 欧美极品少妇xxxxx| 精品国产乱码久久久久久樱花| 色女孩综合网| 久久久精品午夜少妇| 99re久久精品国产| 夜夜精品视频一区二区| 国产熟女一区二区丰满| 久久精品精品电影网| 激情久久一区二区| 亚洲国产日韩欧美| 日本不卡一二三区黄网| 性猛交ⅹxxx富婆video| 一本到不卡免费一区二区| 日韩有码电影| 奇米影视亚洲狠狠色| 亚洲第一论坛sis| 日韩av资源在线| 久久精品一区二区三区不卡牛牛| 成人免费a视频| 精品在线小视频| 免费亚洲电影| 日韩啊v在线| 日本欧美久久久久免费播放网| 第一次破处视频| 欧美吞精做爰啪啪高潮| 日本韩国在线视频爽| 成人春色激情网| 91精品国产福利在线观看麻豆| 五月激情婷婷在线| 亚洲卡通欧美制服中文| 性生交大片免费看女人按摩| 久久久久久高潮国产精品视| 成人爽a毛片免费啪啪红桃视频| 国产中文字幕二区| 91色乱码一区二区三区| 无码人妻丰满熟妇区五十路| 伊人激情综合网| 成人豆花视频| 性高湖久久久久久久久aaaaa| 99久久精品国产精品久久| 日本视频在线观看免费| 色系列之999| 日韩精品成人在线观看| 日韩免费视频播放| 亚洲国产精品传媒在线观看| 国产三级小视频| 91av福利视频| 精品一区av| 亚洲三级在线视频| 欧美日韩免费网站| 日韩黄色影院| 国产精品大全| 视频一区在线视频| 黑人巨大精品一区二区在线| 亚洲福利视频专区| 韩日精品一区| 第九区2中文字幕| 久久久久久久久免费| 国产麻豆一精品一男同| 51久久精品夜色国产麻豆| 久久看人人摘| 中国一级特黄录像播放| 欧美日韩一级黄|