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

異常是怎么實現的?虛擬機是如何將異常拋出去的?

開發 前端
程序在運行的過程中,總是會不可避免地產生異常,此時為了讓程序不中斷,必須要將異常捕獲掉。如果能提前得知可能會發生哪些異常,建議使用精確捕獲,如果不知道會發生哪些異常,則使用 Exception 兜底。

楔子

程序在運行的過程中,總是會不可避免地產生異常,此時為了讓程序不中斷,必須要將異常捕獲掉。如果能提前得知可能會發生哪些異常,建議使用精確捕獲,如果不知道會發生哪些異常,則使用 Exception 兜底。

另外異常也可以用來傳遞信息,比如生成器。

def gen():
    yield 1
    yield 2
    return "result"

g = gen()
next(g)
next(g)
try:
    next(g)
except StopIteration as e:
    print(f"返回值: {e.value}")   # 返回值: result

如果想要拿到生成器的返回值,我們需要讓它拋出 StopIteration,然后進行捕獲,再通過 value 屬性拿到返回值。所以,Python 是將生成器的返回值封裝到了異常里面。

之所以舉這個例子,目的是想說明,異常并非是讓人嗤之以鼻的東西,它也可以作為信息傳遞的載體。特別是在 Java 語言中,引入了 checked exception,方法的所有者還可以聲明自己會拋出什么異常,然后調用者對異常進行處理。

在 Java 程序啟動時,拋出大量異常都是司空見慣的事情,并在相應的調用堆棧中將信息完整地記錄下來。至此,Java 的異常不再是異常,而是一種很普遍的結構,從良性到災難性都有所使用,異常的嚴重性由調用者來決定。

雖然在 Python 里面,異常還沒有達到像 Java 異常那么高的地位,但使用頻率也是很高的,下面我們就來剖析一下異常是怎么實現的?

異常的本質是什么

Python 解釋器 = Python 編譯器 + Python 虛擬機,所以異常可以由編譯器拋出,也可以由虛擬機剖出。如果是編譯器拋出的異常,那么基本上都是 SyntaxError,即語法錯誤。

try:
    >>>
except Exception as e:
    print(e)

比如上面這段代碼,你會發現異常捕獲根本沒用,因為這是編譯階段就發生的錯誤,而異常捕獲是在運行時進行的。當然語法不對屬于低級錯誤,所以不會留到運行時。

然后是運行時產生的異常:

try:
    1 / 0
except ZeroDivisionError:
    print("Division by zero")

像這種語法正確,但程序執行時因邏輯出現問題而導致的異常,是可以被捕獲的。對于我們來說,關注的顯然是運行時產生的隱藏,比如 TypeError、IndexError 等等。

那么問題來了,異常本質上是什么呢?我們以列表為例,看看 IndexError 是怎么產生的。

lst = [1, 2, 3]
print(lst[3])
"""
IndexError: list index out of range
"""

列表的最大索引是 2,但我們訪問了索引為 3 的元素,虛擬機就知道不能再執行下去了,否則會訪問非法內存。因此虛擬機的做法是:輸出異常信息,結束進程。我們通過源碼來驗證一下:

圖片圖片

在獲取列表元素時發現索引不合法,就知道要拋出 IndexError 了,會將異常寫入到標準錯誤輸出當中,并返回 NULL。正常情況下,返回值應該指向一個合法的對象,如果為 NULL,證明出現異常了。

此時虛擬機會將回溯棧里的異常拋出來(就是我們在控制臺看到的那一抹鮮紅),然后結束進程,這就是異常的本質。當然異常也是一個 Python 對象,虛擬機在退出前,會寫入到 stderr 中。

異常寫入的一些 C API

當我們用 C 編寫 Python 擴展時,如果想設置異常的話,該怎么做呢?首先設置異常之前,我們要知道有哪些異常。在 pyerrors.h 中,虛擬機內置了大量的異常,另外 Python 一切皆對象,因此異常也是一個對象。

圖片圖片

有了異常之后,怎么寫入呢?關于異常寫入,底層也提供了相應的 C API。

圖片圖片

相關的 API 有很多,我們來解釋一下。

"""
PyErr_SetNone:設置異常,不包含提示信息。

PyErr_SetObject:設置異常,包含提示信息(Python 字符串)。

PyErr_SetString:設置異常,包含提示信息(C 字符串)。

PyErr_Occurred:檢測回溯棧中是否有異常產生。

PyErr_Clear:將回溯棧中的異常清空,相當于 Python 的異常捕獲。

PyErr_Fetch:將回溯棧中的異常清空,同時拿到它的 exc_type、exc_value、exc_tb。

PyErr_Restore:基于 exc_type、exc_value、exc_tb 設置異常。
"""

我們以 PyErr_Restore 為例,看看異常的具體設置過程。

// Python/errors.c

// PyErr_SetObject、PyErr_SetString 等等,最終都會調用 PyErr_Restore
void
PyErr_Restore(PyObject *type, PyObject *value, PyObject *traceback)
{
    // 獲取線程狀態對象
    PyThreadState *tstate = _PyThreadState_GET();
    _PyErr_Restore(tstate, type, value, traceback);
}

void
_PyErr_Restore(PyThreadState *tstate, PyObject *type, PyObject *value,
               PyObject *traceback)
{
    // 對 type、value、traceback 做一些檢測
    // ...

    PyObject *old_traceback = ((PyBaseExceptionObject *)value)->traceback;
    ((PyBaseExceptionObject *)value)->traceback = traceback;
    Py_XDECREF(old_traceback);
    // 調用 _PyErr_SetRaisedException
    _PyErr_SetRaisedException(tstate, value);
    Py_DECREF(type);
}

void
_PyErr_SetRaisedException(PyThreadState *tstate, PyObject *exc)
{
    // 線程狀態對象的 current_exception 字段,負責保存當前異常
    PyObject *old_exc = tstate->current_exception;
    // 將它設置為 exc
    tstate->current_exception = exc;
    Py_XDECREF(old_exc);
}

我們再來看看 PyThreadState 對象,它是與線程相關的,但它只是線程信息的一個抽象描述,而真實的線程及狀態肯定是由操作系統來維護和管理的。

因為虛擬機在運行的時候總需要另外一些與線程相關的狀態和信息,比如是否發生了異常等等,這些信息顯然操作系統是沒有辦法提供的。而 PyThreadState 對象正是 Python 為線程準備的、在虛擬機層面保存線程狀態信息的對象(后面簡稱線程狀態對象、或者線程對象)。

當前活動線程(OS 原生線程)對應的 PyThreadState 對象可以通過 PyThreadState_GET 獲得,在得到了線程狀態對象之后,就將異常信息存放在里面。

關于線程相關的內容,后續會詳細說。

traceback 是什么?

程序產生的異常會被記錄在線程狀態對象當中,現在可以回頭看看,在跳出了分派字節碼指令的代碼塊之后,發生了什么動作。

在 ceval.c 里面有一個 _PyEval_EvalFrameDefault 函數,負責執行字節碼指令。該函數內部有一個代碼塊,包含了每個指令的處理邏輯,執行完畢后會跳出代碼塊。

圖片圖片

但跳出代碼塊的原因有兩種:

  • 執行完所有的字節碼指令之后正常跳出;
  • 發生異常后跳出;

那么虛擬機如何區分是哪一種呢?很簡單,通過 error 標簽實現,注意代碼塊里面有一個 error 標簽。

圖片圖片

如果在執行指令的時候出現了異常,那么會跳轉到 error 這里,否則會跳轉到其它地方。

另外當出現異常時,會在線程狀態對象中將異常信息記錄下來,包括異常類型、異常值、回溯棧(traceback),這個 traceback 就是在 error 標簽中調用 PyTraceBack_Here 創建的。

另外可能有人不清楚 traceback 是做什么的,我們舉個 Python 的例子。

def h():
    1 / 0

def g():
    h()

def f():
    g()

f()
"""
Traceback (most recent call last):
  File "/Users/.../main.py", line 10, in <module>
    f()
  File "/Users/.../main.py", line 8, in f
    g()
  File "/Users/.../main.py", line 5, in g
    h()
  File "/Users/.../main.py", line 2, in h
    1 / 0
ZeroDivisionError: division by zero
"""

這是腳本運行時產生的錯誤輸出,我們看到了函數調用的信息:比如在源代碼的哪一行調用了哪一個函數,那么這些信息是從何而來的呢?沒錯,顯然是 traceback 對象。

虛擬機在處理異常的時候,會創建 traceback 對象,在該對象中記錄棧幀的信息。虛擬機利用該對象來將棧幀鏈表中每一個棧幀的狀態進行可視化,可視化的結果就是上面輸出的異常信息。

而且我們發現輸出的信息也是一個鏈狀的結構,因為每一個棧幀都會對應一個 traceback 對象,這些 traceback 對象之間也會組成一個鏈表。

所以當虛擬機開始處理異常的時候,它首先的動作就是創建 traceback 對象,用于記錄異常發生時活動棧幀的狀態。創建方式是通過 PyTraceBack_Here 函數,它接收一個棧幀作為參數。

// Python/traceback.c
int
PyTraceBack_Here(PyFrameObject *frame)
{
    // 獲取當前的異常對象
    PyObject *exc = PyErr_GetRaisedException();
    assert(PyExceptionInstance_Check(exc));
    // 拿到當前異常的 traceback
    PyObject *tb = PyException_GetTraceback(exc);
    // 創建新的 traceback 對象,并和舊的 traceback 對象組成鏈表
    PyObject *newtb = _PyTraceBack_FromFrame(tb, frame);
    Py_XDECREF(tb);
    if (newtb == NULL) {
        _PyErr_ChainExceptions1(exc);
        return -1;
    }
    // 將新的 traceback 對象交給線程狀態對象
    PyException_SetTraceback(exc, newtb);
    Py_XDECREF(newtb);
    // 重新設置異常
    PyErr_SetRaisedException(exc);
    return 0;
}


// Python/errors.c
PyErr_GetRaisedException(void)
{
    PyThreadState *tstate = _PyThreadState_GET();
    return _PyErr_GetRaisedException(tstate);
}

PyObject *
_PyErr_GetRaisedException(PyThreadState *tstate) {
    // 返回當前的異常
    PyObject *exc = tstate->current_exception;
    tstate->current_exception = NULL;
    return exc;
}

那么這個 traceback 對象究竟長什么樣呢?

// Include/cpython/traceback.h
typedef struct _traceback PyTracebackObject;

struct _traceback {
    PyObject_HEAD
    PyTracebackObject *tb_next;
    PyFrameObject *tb_frame;
    int tb_lasti;
    int tb_lineno;
};

里面有一個 tb_next,所以很容易想到 traceback 也是一個鏈表結構。其實 traceback 對象的鏈表結構跟棧幀對象的鏈表結構是同構的、或者說一一對應的,即一個棧幀對象對應一個 traceback 對象。

traceback 創建

在 PyTraceBack_Here 函數中我們看到它是通過 _PyTraceBack_FromFrame 創建的,那么秘密就隱藏在這個函數中。

// Python/traceback.c
PyObject*
_PyTraceBack_FromFrame(PyObject *tb_next, PyFrameObject *frame)
{
    assert(tb_next == NULL || PyTraceBack_Check(tb_next));
    assert(frame != NULL);
    // 獲取最近一條執行完畢的字節碼指令的偏移量
    int addr = _PyInterpreterFrame_LASTI(frame->f_frame) * sizeof(_Py_CODEUNIT);
    // 創建 traceback
    return tb_create_raw((PyTracebackObject *)tb_next, frame, addr, -1);
}


static PyObject *
tb_create_raw(PyTracebackObject *next, PyFrameObject *frame, int lasti,
              int lineno)
{
    PyTracebackObject *tb;
    if ((next != NULL && !PyTraceBack_Check(next)) ||
                    frame == NULL || !PyFrame_Check(frame)) {
        PyErr_BadInternalCall();
        return NULL;
    }
    // 為 traceback 對象申請內存
    tb = PyObject_GC_New(PyTracebackObject, &PyTraceBack_Type);
    if (tb != NULL) {
        // 設置屬性
        tb->tb_next = (PyTracebackObject*)Py_XNewRef(next);
        // 注意 traceback 內部還保存了棧幀對象
        // 所以在 Python 中,except Exception as e 之后
        // 可以通過 e.__traceback__.tb_frame 獲取棧幀
        tb->tb_frame = (PyFrameObject*)Py_XNewRef(frame);
        tb->tb_lasti = lasti;
        tb->tb_lineno = lineno;
        // 加入 GC 追蹤, 參與垃圾回收
        PyObject_GC_Track(tb);
    }
    return (PyObject *)tb;
}

tb_next 將兩個 traceback 連接了起來,不過這個和棧幀的 f_back 正好相反,f_back 指向的是上一個棧幀,而 tb_next 指向的是下一個 traceback。

另外在 traceback 中,還通過 tb_frame 字段和對應的 PyFrameObject 對象建立了聯系,當然還有最后執行完畢時的字節碼偏移量、以及在源代碼中對應的行號。

棧幀展開

traceback 的創建我們知道了,那么它和棧幀對象是怎么聯系起來的呢?我們還以之前的代碼為例,來解釋一下。

def h():
    1 / 0

def g():
    h()

def f():
    g()

f()

當執行到函數 h 的 1 / 0 這行代碼時,底層會執行 BINARY_OP 指令。

// Include/opcode.h
#define NB_ADD                  0
#define NB_AND                  1
#define NB_FLOOR_DIVIDE         2
#define NB_LSHIFT               3
#define NB_MATRIX_MULTIPLY      4
#define NB_MULTIPLY             5
#define NB_REMAINDER            6
#define NB_OR                   7
#define NB_POWER                8
#define NB_RSHIFT               9
#define NB_SUBTRACT            10
#define NB_TRUE_DIVIDE         11
// ...


// Python/generated_cases.c.h
TARGET(BINARY_OP) {
    // ...
    // 對于除法運算,指令參數 oparg 的值是 11
    res = binary_ops[oparg](lhs, rhs);
    // ...
}


// Python/ceval.c
static const binaryfunc binary_ops[] = {
    [NB_ADD] = PyNumber_Add,
    [NB_AND] = PyNumber_And,
    [NB_FLOOR_DIVIDE] = PyNumber_FloorDivide,
    // ...
    [NB_RSHIFT] = PyNumber_Rshift,
    [NB_SUBTRACT] = PyNumber_Subtract,
    [NB_TRUE_DIVIDE] = PyNumber_TrueDivide,
    // ...
};
// 毫無疑問,binary_ops[11] 會得到 PyNumber_TrueDivide 函數


// Objects/abstract.c
PyObject *
PyNumber_TrueDivide(PyObject *v, PyObject *w)
{
    return binary_op(v, w, NB_SLOT(nb_true_divide), "/");
}

#define NB_SLOT(x) offsetof(PyNumberMethods, x)
// 最終會執行 (&PyLong_Type) -> tp_as_methods -> nb_true_divide
// 即 long_true_divice 函數,看一下它的邏輯


// Objects/longobject.c
static PyObject *
long_true_divide(PyObject *v, PyObject *w)
{
    // ...

    a_size = _PyLong_DigitCount(a);
    b_size = _PyLong_DigitCount(b);
    negate = (_PyLong_IsNegative(a)) != (_PyLong_IsNegative(b));
    if (b_size == 0) {
        PyErr_SetString(PyExc_ZeroDivisionError,
                        "division by zero");
        goto error;
    }
    // ...

    success:
      return PyFloat_FromDouble(negate ? -result : result);

    underflow_or_zero:
      return PyFloat_FromDouble(negate ? -0.0 : 0.0);

    overflow:
      PyErr_SetString(PyExc_OverflowError,
                      "integer division result too large for a float");
    error:
      return NULL;

}

由于除數為 0,因此會通過 PyErr_SetString 設置一個異常進去,最終將異常類型、異常值、以及 traceback 保存到線程狀態對象中。但此時 traceback 實際上是為空的,因為目前還沒有涉及到 traceback 的創建,那么它是什么時候創建的呢?繼續往下看。

由于出現了異常,那么 long_true_divide 會返回NULL。

圖片圖片

當返回值為 NULL 時,虛擬機就意識到發生異常了,這時候會跳轉到 pop_2_error 標簽。

圖片圖片

當出現除零錯誤時,運行時棧里面還有兩個元素,所以跳轉到 pop_2_error。將棧里的兩個元素彈出之后,進入 error 標簽。

在里面會先取出線程狀態對象中已有的 traceback 對象(此時為空),然后以函數 h 的棧幀為參數,創建一個新的 traceback 對象,將兩者通過 tb_next 關聯起來。最后,再替換掉線程狀態對象里面的 traceback 對象。

在虛擬機意識到有異常拋出,并創建了 traceback 之后,它會在當前棧幀中尋找 try except 語句,來執行開發人員指定的捕捉異常動作。如果沒有找到,那么虛擬機將退出當前的活動棧幀,并沿著棧幀鏈回退到上一個棧幀(這里是函數 g 的棧幀),在上一個棧幀中尋找 try except 語句。

就像我們之前說的,函數調用會創建棧幀,當函數執行完畢或者出現異常時,會回退到上一級棧幀。一層一層創建、一層一層返回。至于回退的這個動作,則是在 _PyEval_EvalFrameDefault 的最后完成。

圖片圖片

當出現異常時,虛擬機會進入 exception_unwind 標簽尋找異常捕獲邏輯,相關細節下一篇文章再說,這里就讓它拋出去。然后來到 exit_unwind 標簽,將當前線程狀態對象中的活動棧幀,設置為上一級棧幀,從而完成棧幀回退的動作。

當棧幀回退時,會進入函數 g 的棧幀,由于返回值為 NULL,所以知道自己調用的函數 h 的內部發生異常了(否則返回值一定會指向一個合法的 PyObject),那么繼續尋找異常捕獲語句。

對于當前這個例子來說,顯然是找不到的,于是會從線程狀態對象中取出已有的 traceback 對象(函數 h 的棧幀對應的 traceback)。然后以函數 g 的棧幀為參數,創建新的 traceback 對象,再將兩者通過 tb_next 關聯起來,并重新設置到線程狀態對象中。

異常會沿著棧幀鏈進行反向傳播,函數 h 出現的異常被傳播到了函數 g 中,顯然接下來函數 g 要將異常傳播到函數 f 中。因為函數 g 在無法捕獲異常時,那么返回值也是 NULL,而函數 f 看到返回值為 NULL 時,同樣會去尋找異常捕獲語句。但是找不到,于是會從線程狀態對象中取出已有的 traceback 對象(此時是函數 g 的棧幀對應的 traceback),然后以函數 f 的棧幀為參數,創建新的 traceback 對象,再將兩者通過 tb_next 關聯起來,并重新設置到線程狀態對象中。

最后再傳播到模塊對應的棧幀中,如果還無法捕獲發生的異常,那么虛擬機就要將異常拋出來了。

這個沿著棧幀鏈不斷回退的過程我們稱之為棧幀展開,在棧幀展開的過程中,虛擬機不斷地創建與各個棧幀對應的 traceback,并將其鏈接成鏈表。

圖片圖片

由于沒有異常捕獲,那么接下來會調用 PyErr_Print。然后在 PyErr_Print 中,虛擬機取出維護的 traceback 鏈表,并進行遍歷,將里面的信息逐個輸出到 stderr 當中,最終就是我們在 Python 中看到的異常信息。

并且打印順序是:.py文件、函數f、函數g、函數h。因為每一個棧幀對應一個 traceback,而棧幀又是往后退的,因此顯然會從 .py文件對應的 traceback 開始打印,然后通過 tb_next 找到函數f 對應的 traceback,依次下去。當異常信息全部輸出完畢之后,解釋器就結束運行了。

因此從鏈路的開始位置到結束位置,將整個調用過程都輸出出來,可以很方便地定位問題出現在哪里。

Traceback (most recent call last):
  File "/Users/.../main.py", line 10, in <module>
    f()
  File "/Users/.../main.py", line 8, in f
    g()
  File "/Users/.../main.py", line 5, in g
    h()
  File "/Users/.../main.py", line 2, in h
    1 / 0
ZeroDivisionError: division by zero

另外,雖然 traceback 一直在更新(因為要對整個調用鏈路進行追蹤),但是異常類型和異常值始終是不變的,就是函數 h 中拋出的 ZeroDivisionError: division by zero。

小結

以上就是虛擬機拋異常的過程,異常在 Python 里面也是一個對象,和其它的實例對象并無本質區別。

exc = StopIteration("迭代結束了")
print(exc.value)  # 我是一個異常
print(exc.args)  # ('迭代結束了',)

exc = IndexError("索引越界了")
print(exc.args)  # ('索引越界了',)

exc = Exception("不知道是啥異常,總之出問題了")
print(exc.args)  # ('不知道是啥異常,總之出問題了',)

# 異常都有一個 args 屬性,以元組的形式保存傳遞的參數

所謂拋出異常,就是將錯誤信息輸出到 stderr 中,然后停止進程。并且除了虛擬機內部會拋出異常之外,我們還可以使用 raise 關鍵字手動引發一個異常。

def judge_score(score: int):
    if score > 100 or score < 0:
        raise ValueError("Score must be between 0 and 100")

站在虛擬機的角度,score 取任何值都是合理的,但對于我們來說,希望 score 位于 0 ~ 100。那么當 score 不滿足 0 ~ 100 時,可以手動 raise 一個異常。

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

2024-11-11 11:21:30

虛擬機Python跳轉表

2017-11-21 18:05:00

云計算虛擬機遷移

2022-05-23 08:00:00

Windows 11虛擬機操作系統

2009-03-18 08:59:28

throw異常Java

2011-09-07 09:30:57

服務器虛擬機

2020-11-04 08:00:57

虛擬機stio網格

2020-12-15 10:44:47

Progressive實習CIO

2023-09-02 21:35:39

Linux虛擬機

2017-11-14 16:43:13

Java虛擬機線程

2023-09-03 17:05:20

虛擬機

2012-06-12 09:51:29

虛擬機

2010-02-01 15:01:34

C++拋出異常

2023-12-12 13:21:00

Java異常程序

2021-01-13 11:55:39

Spring代碼Java

2020-01-17 10:52:37

無服務器容器技術

2012-04-10 10:29:29

2010-12-23 14:05:12

虛擬機

2010-12-27 14:11:55

虛擬機配置CPU

2019-03-05 14:59:42

Java虛擬機加載類

2010-01-18 10:15:50

虛擬機ubuntu
點贊
收藏

51CTO技術棧公眾號

午夜欧美激情| 久久国产视频一区| 9999精品| 午夜精品福利一区二区蜜股av | 成人av电影在线网| 91福利视频网| 久久精品日韩无码| 久久人人爽人人爽人人片av不| 色综合咪咪久久| 先锋在线资源一区二区三区| 99久久国产免费| 国产精品主播| 久热在线中文字幕色999舞| 手机免费看av片| 成人四虎影院| 精品国产鲁一鲁一区二区张丽 | 永久免费成人代码| 日本成人精品| 欧洲在线/亚洲| 男的插女的下面视频| 99视频在线观看地址| 国产呦精品一区二区三区网站| 538国产精品一区二区在线| 视频国产一区二区| 精品一区av| 日韩av网站在线| 91插插插影院| 欧美日一区二区三区| 天天操天天综合网| 久久久久久久香蕉| 黄色片网站在线| 日本一区二区综合亚洲| 九色综合日本| 亚洲欧美激情国产综合久久久| 蜜乳av一区二区三区| 欧美在线观看网站| 日本一区二区免费在线观看| 91高潮大合集爽到抽搐| 麻豆视频在线观看免费| 91麻豆免费看片| 国产精品对白一区二区三区| 91麻豆国产在线| 蜜桃视频在线观看一区| 国产成人精品久久二区二区| 久久露脸国语精品国产91| 午夜久久美女| 欧美高清无遮挡| 在线免费日韩av| 2023国产精品久久久精品双| 日韩有码视频在线| 三级黄色片在线观看| 欧美日韩精品一区二区视频| 亚洲欧美日韩在线一区| 亚洲一级中文字幕| 一呦二呦三呦国产精品| 日韩精品黄色网| 波多野结衣 在线| 妖精视频一区二区三区| 亚洲乱码一区二区| a级大片在线观看| 国产精品欧美日韩一区| 国产亚洲精品一区二555| 亚洲精品一区二区三区影院忠贞| 国产欧美日韩免费观看| 国产一区二区美女视频| 亚洲熟女少妇一区二区| 99久久夜色精品国产亚洲1000部| 久久er精品视频| 日韩精品视频中文在线观看| 大地资源二中文在线影视观看| 老司机凹凸av亚洲导航| 亚洲老板91色精品久久| 欧美偷拍一区二区三区| 91日韩在线| 欧美日韩xxx| 日韩欧美三级在线观看| 石原莉奈在线亚洲三区| 国产精品日韩久久久久| 国产精品一级视频| 国产99久久精品| 欧美日本韩国一区二区三区| 91涩漫在线观看| 亚洲日本丝袜连裤袜办公室| 日韩精品在线观看av| 中文字幕乱码中文乱码51精品| 欧美在线视频不卡| 精品国产乱码久久久久久图片| 九九久久九九久久| 97蜜桃久久| 欧美三级电影在线看| 又黄又爽又色的视频| 日韩欧美黄色| 精品国产一区二区三区久久久| 久草免费在线视频观看| 久热re这里精品视频在线6| 国产在线观看一区二区三区| 精品久久无码中文字幕| 久久久久久久久99精品| 中文字幕一区二区三区乱码 | 国产成人精品999在线观看| 日韩亚洲综合在线| 国产欧美日韩另类| 久久99热99| 久久99国产精品| 秋霞午夜理伦电影在线观看| 午夜天堂影视香蕉久久| 日本中文字幕精品—区二区| 女同另类激情重口| 久久精品国产欧美亚洲人人爽| 五月天婷婷综合网| 国产一区二区电影| 日本亚洲自拍| 日韩在线伦理| 日韩女优电影在线观看| 色www亚洲国产阿娇yao| 9国产精品视频| 96久久精品| 在线观看h片| 欧美日韩亚洲国产一区| 国产精品欧美性爱| 91影院成人| 国产成人综合精品在线| 日本高清视频免费观看| 亚洲视频一二区| 一级在线免费视频| 蜜桃成人av| 8090成年在线看片午夜| 亚洲黄色一级大片| 亚洲欧美日韩国产另类专区| 日韩av手机版| 国产欧美日韩在线一区二区| 69视频在线免费观看| 精品国产伦一区二区三| 日韩毛片在线免费观看| 精品999在线| 欧洲grand老妇人| 日本高清视频一区| 人成在线免费视频| 天天综合网天天综合色| 国产精品久久久久久亚洲色 | 99国产精品一区二区三区| 中文在线一区二区| jizz大全欧美jizzcom| 国产va免费精品观看精品视频| 91精品国产91久久久久久| 亚洲免费国产视频| 亚洲一区二区欧美| 成人在线观看一区二区| 国产一区欧美| 国产精品一区二区欧美| ****av在线网毛片| 亚洲黄色在线观看| 久久亚洲综合国产精品99麻豆精品福利| 阿v天堂2014| 日韩高清在线一区| 亚洲欧洲精品一区二区| 91九色综合| 色偷偷偷亚洲综合网另类| 在线播放成人av| 中文字幕在线观看不卡| 国产欧美激情视频| 欧美久久成人| 国内一区二区在线视频观看| 在线天堂资源| 在线观看中文字幕亚洲| 91禁在线观看| 玉米视频成人免费看| 91九色蝌蚪porny| 宅男噜噜噜66国产日韩在线观看| 久久99精品久久久久久久青青日本 | 农民人伦一区二区三区| 亚洲高清极品| 国产精品美女久久| 久久久久久久久免费视频| 日韩午夜小视频| 国产成人一区二区三区影院在线| 久久噜噜亚洲综合| 污污网站在线观看视频| 欧美天堂亚洲电影院在线观看| 国产精品一区视频| 久久野战av| 美女福利精品视频| 午夜视频福利在线| 欧美日韩国产123区| 18岁成人毛片| 337p粉嫩大胆色噜噜噜噜亚洲| 日韩av一二三四| 91九色精品国产一区二区| 高清国产一区| 亚洲电影有码| 欧美极品少妇xxxxⅹ免费视频| 青青免费在线视频| 777奇米成人网| 国产超碰人人爽人人做人人爱| 中文字幕 久热精品 视频在线| 无码人妻丰满熟妇啪啪网站| 久久精品麻豆| 肉大捧一出免费观看网站在线播放| 嫩草国产精品入口| 成人性生交大片免费看小说| 国产精品vvv| www日韩欧美| 天堂在线免费av| 欧美电影在线免费观看| 日韩一区二区视频在线| 国产毛片在线| 亚洲成人久久影院| 国产人妻大战黑人20p| 国产麻豆视频一区二区| 亚洲中文字幕无码专区| 亚洲色图网站| 日韩黄色影视| 国产一区二区三区亚洲| 国产一区视频在线播放| 男女羞羞在线观看| 欧美裸体男粗大视频在线观看| 男男电影完整版在线观看| 欧美一三区三区四区免费在线看| 中文字幕免费在线观看视频| 一区二区三区成人| av资源在线免费观看| 久久亚洲一级片| 最新日本中文字幕| 国产一区二区三区四区五区美女 | 国产精品蜜芽在线观看| 久久精品成人一区二区三区| 青青草免费在线| 亚洲成人久久一区| 国产成年妇视频| 在线电影一区二区三区| 超碰在线观看91| 欧美日韩亚洲国产一区| 国产福利拍拍拍| 五月婷婷激情综合网| 精品午夜福利视频| 又紧又大又爽精品一区二区| 黄视频网站免费看| 国产精品第五页| 91动漫免费网站| 国产日韩欧美在线一区| 久久久久亚洲av无码专区桃色| 成人av网站在线观看| 国产艳妇疯狂做爰视频 | 色天使色偷偷av一区二区| 天天操天天射天天爽| 亚洲在线免费播放| 久久久久久国产精品免费播放| 亚洲色图欧美偷拍| 亚洲色图综合区| 亚洲美女在线国产| 999精品在线视频| 中文字幕中文字幕中文字幕亚洲无线| 色噜噜噜噜噜噜| 中文天堂在线一区| 任我爽在线视频| 亚洲欧洲www| 男人在线观看视频| 亚洲精选视频在线| 久久久国产成人| 午夜久久电影网| 免费av网站在线| 欧美性大战久久久久久久蜜臀| 中文字幕免费高清网站| 欧美三级午夜理伦三级中视频| 成人性生交大片免费看视频直播| 98在线视频| 色青青草原桃花久久综合| 好了av在线| 欧美理论电影在线观看| www.综合网.com| 欧美一级大片在线观看| 成人免费av电影| 亚洲aa在线观看| 久久久精品国产**网站| 欧美日韩三区四区| 99久久精品国产亚洲精品| 日韩精品一区二区在线视频| 一区二区91| www.xxx亚洲| 国产一区二区三区av电影| 88av在线播放| 国产亚洲欧美色| 好吊日在线视频| 精品色蜜蜜精品视频在线观看| 国产美女www| 91精品国产乱码久久蜜臀| 蜜桃av中文字幕| 国产一区二区三区视频| 2024最新电影免费在线观看| 国语自产精品视频在线看| 亚洲va中文在线播放免费| 国产精品色视频| 日本亚州欧洲精品不卡| 久久久婷婷一区二区三区不卡| 成人在线免费小视频| 免费看欧美一级片| 日韩国产成人精品| 丰满人妻一区二区三区免费视频棣| 久久噜噜亚洲综合| 欧美日韩一级在线观看| 日韩欧中文字幕| 99久久久国产精品无码免费| 亚洲免费中文字幕| 日本在线视频网址| 国产精品久久久久久久久久| 777久久精品| 亚洲午夜在线观看| 国产欧美日韩一级| 国产欧美一区二| 国产婷婷色一区二区三区| 精品在线视频免费观看| 精品视频一区二区不卡| 午夜在线视频观看| 久久99国产精品自在自在app| 国产 日韩 欧美一区| 国产精品一区二区三区不卡| 天天操综合网| 五月婷婷深爱五月| 97久久精品人人爽人人爽蜜臀| 99久久99久久精品国产| 在线看不卡av| 深夜福利免费在线观看| 欧美精品在线免费播放| 日韩黄色三级| 天天人人精品| 久久综合狠狠| 好吊日免费视频| 亚洲成人激情av| www.蜜臀av.com| 久久成人精品电影| 欧美成人家庭影院| 亚洲婷婷综合久久一本伊一区| 久久久久久91亚洲精品中文字幕| 日韩亚洲欧美一区| 黄av在线播放| 91精品久久久久久久久中文字幕 | 国产一区av在线| 竹内纱里奈兽皇系列在线观看| 成人av片网址| 国产综合视频| 国产精品99精品无码视亚| 亚洲人精品一区| 国产人妖一区二区三区| 久久久999精品免费| 日韩综合久久| 中文字幕色一区二区| 精品一区二区免费| 男人的午夜天堂| 欧美老女人第四色| 久草资源在线| 亚洲综合日韩在线| 午夜国产精品视频免费体验区| 久久精品国产99久久99久久久| 国产精品久久久久影院色老大 | 日韩精品一区二区三区四区| 中文字幕有码在线观看| 97久久人人超碰caoprom欧美| 欧美喷水视频| 无码人妻精品一区二区三| 亚洲成人一区二区| 色综合888| 国产精品一久久香蕉国产线看观看| 日本久久精品| 欧美性受xxxx黒人xyx性爽| 亚洲日本一区二区| 色呦呦中文字幕| 欧美与黑人午夜性猛交久久久| 国产精品亚洲人成在99www| www.日本一区| 一区二区三区资源| 五月婷婷开心中文字幕| 国产精品久久久久久久电影| 久久久久国产精品| 成人一区二区三区仙踪林| 黑人巨大精品欧美一区二区| 黄色网址在线播放| 成人精品在线观看| 黄色成人在线网址| 无码 人妻 在线 视频| 欧美丰满少妇xxxbbb| 91黄页在线观看| 日韩一区二区三区资源| 国模娜娜一区二区三区| 日韩成人免费在线视频| 中文字幕免费精品一区| 日本一区影院| 精品一卡二卡三卡| 亚洲欧美激情小说另类| 天天干,天天操,天天射| 国产精品直播网红| 亚洲国产国产亚洲一二三| www亚洲色图| 精品国产一区二区三区av性色 | 久操免费在线| 久久精品日韩精品| 国内精品写真在线观看| 91午夜视频在线观看| 日韩在线观看免费高清| 日本国产精品| 一级黄色在线播放|