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

虛擬機是如何捕獲異常的?

云計算 虛擬化
本篇文章我們就分析了異常捕獲的實現原理,總的來說并不難,因為所有的信息都靜態保存在了異常跳轉表(簡稱異常表)中。并且在不報錯時,異常捕獲對程序性能沒有任何影響,所以放心使用。?

楔子

既然虛擬機內建的異常處理動作我們已經了解了,那么接下來就看看異常捕獲是如何實現的,還有它又是如何影響虛擬機的異常處理流程的。畢竟在大部分情況下,我們都不會將異常拋出去,而是將它捕獲起來。

異常捕獲語句

這里先來回顧一下異常捕獲語句,首先一個完整的異常捕獲語句如下。

try:
    pass
except IndexError as e:
    pass
except Exception as e:
    pass
else:
    pass
finally:
    pass

情況可以分為以下幾種:

1)如果 try 里面的代碼在執行時沒有出現異常,那么會執行 else ,然后執行 finally。

try:
    print("我是 try")
except Exception as e:
    print("我是 except")
else:
    print("我是 else")
finally:
    print("我是 finally")
"""
我是 try
我是 else
我是 finally
"""

2)如果 try 里面的代碼在執行時出現異常了(異常會被設置在線程狀態對象中),那么會依次判斷 except(可以有多個)能否匹配發生的異常。如果某個 except 將異常捕獲了,那么會將異常給清空,然后執行 finally。

try:
    raise IndexError("IndexError Occurred")
except ValueError as e:
    print("ValueError 匹配上了異常")
except IndexError as e:
    print("IndexError 匹配上了異常")
except Exception as e:
    print("Exception 匹配上了異常")
else:
    print("我是 else")
finally:
    print("我是 finally")
"""
IndexError 匹配上了異常
我是 finally
"""

except 子句可以有很多個,發生異常時會從上往下依次匹配。但是注意:多個 except 子句最多只有一個被執行,比如當前的 IndexError 和 Exception 都能匹配發生的異常,但只會執行匹配上的第一個 except 子句。

另外只要發生異常了,else 就不會執行了。不管 except 有沒有將異常捕獲到,都不會執行 else,因為 else 只有在 try 里面沒有發生異常的時候才會執行。

3)如果 try 里面的代碼在執行時出現異常了,但 except 沒有將異常捕獲掉,那么異常仍然被保存在線程狀態對象中,然后執行 finally。如果 finally 子句中沒有出現 return、break、continue 等關鍵字,再將異常拋出來。

try:
    raise IndexError("IndexError Occurred")
except ValueError:
    print("ValueError 匹配上了異常")
finally:
    print("我是 finally")
"""
我是 finally
Traceback (most recent call last):
  File "......", line 2, in <module>
    raise IndexError("IndexError Occurred")
IndexError: IndexError Occurred
"""

except 沒有將異常捕獲掉,所以執行完 finally 之后,異常又被拋出來了。但如果 finally 里面出現了 return、break、continue 等關鍵字,也不會拋出異常,而是將異常丟棄掉。

def f():
    try:
        raise IndexError("IndexError Occurred")
    except ValueError:
        print("ValueError 匹配上了異常")
    finally:
        print("我是 finally")
        return

f()
"""
我是 finally
"""

def g():
    for i in range(3):
        try:
            raise IndexError("IndexError Occurred")
        except ValueError:
            print("ValueError 匹配上了異常")
        finally:
            print(f"我是 finally,i = {i}")
            continue

g()
"""
我是 finally,i = 0
我是 finally,i = 1
我是 finally,i = 2
"""

由于 finally 里面出現了 return 和 continue,所以異常并沒有發生,而是被丟棄掉了。這個特性相信有很多小伙伴之前還是沒有發現的。

然后 try、except、else、finally 這幾個關鍵字不需要同時出現,可以有以下幾種組合。

try ... except

try ... finally

try ... except ... else

try ... except ... else ... finally

注意里面的 except,可以出現多次,但其它關鍵字在一個 try 語句內只能出現一次。

返回值問題

如果這幾個關鍵字對應的代碼塊都指定了返回值,那么聽誰的呢?下面解釋一下。

def retval():
    try:
        return 123
    except Exception:
        return 456

print(retval())  # 123

由于沒有發生異常,所以返回了 try 指定的返回值。

def retval():
    try:
        return 123
    except Exception:
        return 456
    else:
        return 789

print(retval())  # 123

雖然指定了 else,但是 try 里面已經執行 return 了,所以打印的仍是 try 的返回值。

def retval():
    try:
        1 / 0
        return 123
    except Exception:
        return 456

print(retval())  # 456

由于發生異常,所以返回了 except 指定的返回值。

def retval():
    try:
        1 / 0
        return 123
    except Exception:
        return 456
    else:
        return 789

print(retval())  # 456

一旦發生異常,else 就不可能執行,所以此時仍然返回 456。

def retval():
    try:
        return 123
    except Exception:
        return 456
    finally:
        pass

print(retval())  # 123

finally 永遠會執行,但它沒有指定返回值,所以此時返回的是 123。

def retval():
    try:
        return 123
    except Exception:
        return 456
    finally:
        return

print(retval())  # None

一旦 finally 中出現了 return,那么返回的都是 finally 指定的返回值。并且此時即便出現了沒有捕獲的異常,也不會報錯,因為會將異常丟棄掉。

def retval():
    try:
        return 123
    except Exception:
        return 456
    finally:
        pass
    return 789

print(retval())  # 123

函數一旦 return,就表示要返回了,但如果這個 return 是位于出現了 finally 的異常捕獲語句中,那么會先執行 finally,然后再返回。所以最后的 return 789 是不會執行的,因為已經出現 return 了,finally 執行完畢之后就直接返回了。

def retval():
    try:
        pass
    except Exception:
        return 456
    finally:
        pass
    return 789

print(retval())  # 789

沒有異常,所以 except 里的 return 不會執行,而 try 和 finally 里面也沒有 return,因此返回 789。

一個簡單的異常捕獲,總結起來還稍微有點繞呢。

從 Python 的層面理解完異常捕獲之后,再來看看虛擬機是如何實現這一機制的?想要搞清楚這一點,還是得從字節碼入手。

異常捕獲對應的字節碼

隨便寫一段代碼,然后反編譯一下。

import dis

code_string = """
try:
    raise Exception("拋出一個異常")
except Exception as e:
    print(e)
finally:
    print("我一定會被執行的")
"""

dis.dis(compile(code_string, "exception", "exec"))

拋異常有兩種方式,一種是虛擬機執行的時候出現錯誤而拋出異常,另一種是使用 raise 關鍵字手動拋出異常。這里我們就用第二種方式,來看一下反編譯的結果(為了清晰,省略掉了源代碼行號)。

0 RESUME                   0

      2 NOP

      4 PUSH_NULL
      6 LOAD_NAME                0 (Exception)
      8 LOAD_CONST               0 ('拋出一個異常')
     10 CALL                     1
     18 RAISE_VARARGS            1
>>   20 PUSH_EXC_INFO

     22 LOAD_NAME                0 (Exception)
     24 CHECK_EXC_MATCH
     26 POP_JUMP_IF_FALSE       18 (to 64)
     28 STORE_NAME               1 (e)

     30 PUSH_NULL
     32 LOAD_NAME                2 (print)
     34 LOAD_NAME                1 (e)
     36 CALL                     1
     44 POP_TOP
     46 POP_EXCEPT
     48 LOAD_CONST               1 (None)
     50 STORE_NAME               1 (e)
     52 DELETE_NAME              1 (e)
     54 JUMP_FORWARD             8 (to 72)
>>   56 LOAD_CONST               1 (None)
     58 STORE_NAME               1 (e)
     60 DELETE_NAME              1 (e)
     62 RERAISE                  1

>>   64 RERAISE                  0
>>   66 COPY                     3
     68 POP_EXCEPT
     70 RERAISE                  1

>>   72 NOP

     74 PUSH_NULL
     76 LOAD_NAME                2 (print)
     78 LOAD_CONST               2 ('我一定會被執行的')
     80 CALL                     1
     88 POP_TOP
     90 RETURN_CONST             1 (None)
>>   92 PUSH_EXC_INFO
     94 PUSH_NULL
     96 LOAD_NAME                2 (print)
     98 LOAD_CONST               2 ('我一定會被執行的')
    100 CALL                     1
    108 POP_TOP
    110 RERAISE                  0
>>  112 COPY                     3
    114 POP_EXCEPT
    116 RERAISE                  1
ExceptionTable:
  4 to 18 -> 20 [0]
  20 to 28 -> 66 [1] lasti
  30 to 44 -> 56 [1] lasti
  46 to 54 -> 92 [0]
  56 to 64 -> 66 [1] lasti
  66 to 70 -> 92 [0]
  92 to 110 -> 112 [1] lasti

字節碼指令還是比較多的,我們來分段解釋。

try 子句的指令

try 子句的指令如下。

6 LOAD_NAME                0 (Exception)
      8 LOAD_CONST               0 ('拋出一個異常')
     10 CALL                     1
     18 RAISE_VARARGS            1

6 LOAD_NAME 指令會將 <class 'Exception'> 壓入運行時棧。8 LOAD_CONST 指令會將字符串常量壓入運行時棧。然后 10 CALL 指令將運行時棧里的元素彈出,進行調用??梢钥吹讲还苁钦{用函數,還是調用類,執行的都是 CALL 指令,然后將返回值(這里就是 Exception 對象,即異常)壓入棧中。

接著執行 18 RAISE_VARARGS,這是一條新指令,看一下它的邏輯。

TARGET(RAISE_VARARGS) {
    PyObject **args = (stack_pointer - oparg);
    #line 606 "Python/bytecodes.c"
    PyObject *cause = NULL, *exc = NULL;
    switch (oparg) {
    case 2:
        cause = args[1];
        /* fall through */
    case 1:
        exc = args[0];
        /* fall through */
    case 0:
        // 調用 do_raise 設置異常
        if (do_raise(tstate, exc, cause)) {
            assert(oparg == 0);
            monitor_reraise(tstate, frame, next_instr-1);
            goto exception_unwind;
        }
        break;
    default:
        _PyErr_SetString(tstate, PyExc_SystemError,
                         "bad RAISE_VARARGS oparg");
        break;
    }
    if (true) { STACK_SHRINK(oparg); goto error; }
    #line 912 "Python/generated_cases.c.h"
}

因為 RAISE_VARARGS 指令的參數是 1,所以 case 1 成立,于是將異常從運行時棧中彈出,并賦值給變量 exc,然后調用 do_raise 函數。

在 do_raise 中,最終會調用之前說過的 PyErr_Restore 函數,將異常對象存儲到當前的線程狀態對象中,然后跳轉到標簽為 exception_unwind 的地方開始異常捕獲。

exception_unwind:
{
    // INSTR_OFFSET 是一個宏,定義在 Python/ceval_macros.h 中
    // #define INSTR_OFFSET() ((int)(next_instr - _PyCode_CODE(frame->f_code)))
    int offset = INSTR_OFFSET()-1;
    int level, handler, lasti;
    // 查詢 co_exceptiontable,即異常處理表
    // 當 try 里面產生異常時,那么必須跳轉到相應的 except 或 finally 里面
    // 在 Python 3.10 以及之前的版本,這個機制是通過引入一個獨立的動態棧,跟蹤 try 語句塊實現的
    // 但從 3.11 開始,動態棧被替換成了靜態表,即異常處理表,由 co_exceptiontable 字段維護
    // 并且表在編譯期間就靜態生成了,是一段字節序列,里面包含了 try / except / finally 信息
    // 當代碼在執行過程中出現異常時,解釋器會查詢這張表,尋找與之匹配的 except / finall 塊
    if (get_exception_handler(frame->f_code, offset, &level, &handler, &lasti) == 0) 
    {
        // No handlers, so exit.
        // ...
        // 如果 get_exception_handler 返回值等于 0,說明沒有找到
        // 那么跳轉到 exit_unwind 標簽,退出當前棧幀
        goto exit_unwind;
    }
    // 否則說明找到了,那么要進行跳轉,而跳轉地址保存在 handler 中
    assert(STACK_LEVEL() >= level);
    // ...
    // 獲取 tstate->current_exception,即當前線程狀態對象保存的異常
    PyObject *exc = _PyErr_GetRaisedException(tstate);
    // 壓入棧中
    PUSH(exc);
    // 跳轉到指定指令,即 except / finally 塊對應的指令
    JUMPTO(handler);
    if (monitor_handled(tstate, frame, next_instr, exc) < 0) {
        goto exception_unwind;
    }
    /* Resume normal execution */
    DISPATCH();
}

該指令執行后,異常會被壓入棧中,虛擬機也知道該跳轉到什么地方了。

except 子句的指令

try 子句的指令我們說完了,再來看看 except 子句。

>>   20 PUSH_EXC_INFO
     22 LOAD_NAME                0 (Exception)
     24 CHECK_EXC_MATCH
     26 POP_JUMP_IF_FALSE       18 (to 64)
     28 STORE_NAME               1 (e)

     30 PUSH_NULL
     32 LOAD_NAME                2 (print)
     34 LOAD_NAME                1 (e)
     36 CALL                     1
     44 POP_TOP
     46 POP_EXCEPT
     48 LOAD_CONST               1 (None)
     50 STORE_NAME               1 (e)
     52 DELETE_NAME              1 (e)
     54 JUMP_FORWARD             8 (to 72)

首先執行 20 PUSH_EXC_INFO 指令,內部邏輯如下。

TARGET(PUSH_EXC_INFO) {
    // RAISE_VARARGS 指令將異常設置在了線程狀態對象中
    // 然后跳轉到 exception_unwind 標簽,將異常壓入運行時棧
    PyObject *new_exc = stack_pointer[-1];
    PyObject *prev_exc;
    #line 2543 "Python/bytecodes.c"
    /* tstate->current_exception 表示當前存儲的異常
     * tstate->exc_info 是一個結構體,相當于對異常做了一個封裝
     *
     * typedef struct _err_stackitem {
     *     PyObject *exc_value;
     *     struct _err_stackitem *previous_item;
     * } _PyErr_StackItem;
     */
    _PyErr_StackItem *exc_info = tstate->exc_info;
    // exc_info->exc_value 還是之前存儲的異常
    if (exc_info->exc_value != NULL) {
        prev_exc = exc_info->exc_value;
    }
    else {
        prev_exc = Py_None;
    }
    assert(PyExceptionInstance_Check(new_exc));
    // 將 exc_info->exc_value 替換為新產生的異常
    exc_info->exc_value = Py_NewRef(new_exc);
    #line 3584 "Python/generated_cases.c.h"
    // 此時棧里面有兩個元素,從棧底到棧頂分別是舊異常、新異常
    STACK_GROW(1);
    stack_pointer[-1] = new_exc;
    stack_pointer[-2] = prev_exc;
    DISPATCH();
}

該指令做的事情是將舊異常和新異常壓入運行時棧。

22 LOAD_NAME 加載 Exception,然后執行 24 CHECK_EXC_MATCH,邏輯如下。

TARGET(CHECK_EXC_MATCH) {
    // 獲取棧頂元素,由于源碼中是 except Exception as e
    // 所以會得到上一條 LOAD_NAME 指令壓入的 class Exception
    PyObject *right = stack_pointer[-1];
    // 執行 exception_unwind 標簽內的邏輯時壓入的異常
    PyObject *left = stack_pointer[-2];
    PyObject *b;
    #line 2122 "Python/bytecodes.c"
    // ...
    // 判斷異常對象和指定的異常類能否匹配
    int res = PyErr_GivenExceptionMatches(left, right);
    #line 2981 "Python/generated_cases.c.h"
    Py_DECREF(right);
    #line 2130 "Python/bytecodes.c"
    b = res ? Py_True : Py_False;
    #line 2985 "Python/generated_cases.c.h"
    // 將棧頂元素用 res 替換掉,此時棧里面有兩個元素
    // 從棧底到棧頂分別是:舊異常對象,新異常對象,布爾值(異常是否可以被捕獲)
    stack_pointer[-1] = b;
    DISPATCH();
}

26 POP_JUMP_IF_FALSE 會彈出棧頂元素,如果為 False,說明異常無法被捕獲,那么要跳轉到下一個 except 或者 finally。如果可以被捕獲,那么執行 28 STORE_NAME,再將棧里的異常對象彈出,賦值給變量 e。

到此 except Exception as e 這一行語句便已經完成,至于接下來的 4 條指令應該不需要解釋了。

圖片圖片

很好理解,這 4 條就是 print(e) 對應的指令,然后執行 46 POP_EXCEPT,邏輯如下。

TARGET(POP_EXCEPT) {
    // 此時運行時棧里面還剩下一個舊異常
    PyObject *exc_value = stack_pointer[-1];
    #line 930 "Python/bytecodes.c"
    _PyErr_StackItem *exc_info = tstate->exc_info;
    // 更新引用計數
    Py_XSETREF(exc_info->exc_value, exc_value);
    #line 1274 "Python/generated_cases.c.h"
    STACK_SHRINK(1);
    DISPATCH();
}

但是接下來的幾條指令是干嘛的,估計有人會感到困惑。

圖片圖片

這幾條指令的具體作用,我們稍后解釋。

異常跳轉表

finally 子句對應的指令比較簡單,我們就不看了。相比之前版本,3.12 的異常捕獲變得簡單許多,因為相關信息都靜態化了。在以前的版本中是使用 SETUP_FINALLY 等指令來處理異常,而 3.12 換成了更高效的異常表結構,類似于 Java 的異常表。

我們來看一下異常表的結構,它由 PyCodeObject 對象的 co_exceptiontable 字段負責維護。

圖片圖片

4 to 18 -> 20 

表示 try 子句內部對應偏移量為 4 ~ 18 的指令,并且如果出現異常,那么跳轉到偏移量為 20 的指令。

20 to 28 -> 66 

偏移量為 20 ~ 28 的指令對應 except 子句本身,如果執行出錯,跳轉到偏移量為 66 的指令去清理異常。

30 to 44 -> 56

偏移量為 30 ~ 44 的指令對應 except 子句內部的處理邏輯,如果執行出錯則跳轉到第 56 條指令。

圖片圖片

注意里面的 DELETE_NAME,它是 del 語句對應的指令。所以跳轉之后的這幾條指令,負責刪除變量 e,怎么理解呢?我們舉個例子。

e = 2.71

try:
    raise Exception("xx")
except Exception as e:
    pass

print(e)
"""
NameError: name 'e' is not defined
"""

奇怪,為什么在外面打印變量 e 報錯了呢?其實 Python 會對 except 子句內部做一些處理,以上代碼最終會變成下面這個樣子。

e = 2.71

try:
    raise Exception("xx")
except Exception as e:
    e = None
    try:
        pass
    finally:
        del e
finally:
    print(e)

至于這么做的原因,稍后解釋。

46 to 54 -> 92

del e 相關指令,但它對應的是存在 finally 的情況,刪除之后會跳轉到偏移量為 92 的指令。

56 to 64 -> 66

del e 相關指令,對應不存在 finally 的情況。

66 to 70 -> 92

異常清理相關指令。

92 to 110 -> 112

finally 子句對應的指令。

我們看到  try / except / finally 塊的范圍信息、異常處理的起始位置、需要執行的清理操作都被靜態化了,在編譯階段就已經確定,所以性能方面比之前要更高。并且當 try 子句內的代碼沒有出現錯誤時,和不使用異常捕獲之間基本沒有性能差異。

總之 Python 中一旦出現異常了,那么會將異常類型、異常值、異?;厮輻TO置在線程狀態對象中,然后棧幀一步一步地回退,尋找異常捕獲代碼(從內向外)。如果退到了模塊級別還沒有發現異常捕獲,那么從外向內打印 traceback 中的信息,當走到最內層的時候再將線程中設置的異常類型和異常值打印出來。

def h():
    1 / 0

def g():
    h()

def f():
    g()

f()

# traceback 回溯棧
Traceback (most recent call last):
  # 打印模塊的 traceback
  # 并提示:發生錯誤是因為在第 10 行調用了 f()
  File "/Users/.../main.py", line 10, in <module>
    f()

  # 打印函數 f 的 traceback
  # 并提示:發生錯誤是因為在第 8 行調用了 g()
  File "/Users/.../main.py", line 8, in f
    g()

  # 打印函數 g 的 traceback
  # 并提示:發生錯誤是因為在第 5 行調用了 h()
  File "/Users/.../main.py", line 5, in g
    h()

  # 打印函數 h 的 traceback
  # 并提示:發生錯誤是因為在第 2 行執行了 1 / 0
  File "/Users/.../main.py", line 2, in h
    1 / 0

# 函數 h 的 traceback -> tb_next 為 None,證明錯誤是發生在函數 h 中
# 在模塊中調用函數 f 相當于導火索,然后一層一層輸出,最終定位到函數 h
# 然后再將之前設置在線程狀態對象中的異常類型和異常值打印出來即可
ZeroDivisionError: division by zero

模塊中調用了函數 f,函數 f 調用了函數 g,函數 g 調用了函數 h。然后在函數 h 中執行出錯了,但又沒有異常捕獲,那么會將執行權交給函數 g 對應的棧幀,但是函數 g 也沒有異常捕獲,那么再將執行權交給函數 f 對應的棧幀。所以調用的時候棧幀一層一層創建,當執行完畢或者出現異常時,棧幀再一層層回退。

圖片圖片

因此棧幀的遍歷順序是從函數 h 到模塊,traceback 的遍歷順序是從模塊到函數 h。

為什么要執行 del

前面說了,在 except 語句塊內,如果將異常賦給了某個變量,那么 except 結束時會將變量刪掉。

e = 2.71

def get_e():
    return e

try:
    raise Exception("我要引發異常了")
except Exception as e:
    # 因為 except Exception as e 位于全局作用域
    # 所以執行完之后,全局變量 e 就被修改了
    print(get_e())  # 我要引發異常了
    # 但是在最后還會隱式地執行 del e,那為什么要這么做呢?
    # 因為 except 子句結束后,變量 e 指向的異常對象就沒用了
    # 而如果不 del e 的話,那么異常對象不會被銷毀
    # 此外還有一個原因,通過 __traceback__ 可以拿到當前的回溯棧,即 traceback 對象
    print(e.__traceback__)  # <traceback object at 0x104a98b80>
    # 而 traceback 對象保存當前的棧幀,然后棧幀又保存了包含變量 e 的名字空間
    print(e.__traceback__.tb_frame.f_locals["e"] is e)  # True
    # 相信你能猜到這會帶來什么后果,沒錯,就是循環引用
    # 因此在 except 結束時會隱式地 del e

# 顯然當 except 結束后,全局變量 e 就無法訪問了
print(e)
"""
NameError: name 'e' is not defined
"""

所以在附加了回溯信息的情況下,它們會形成堆棧幀的循環引用,在下一次垃圾回收執行之前,會使所有變量都保持存活。

小結

本篇文章我們就分析了異常捕獲的實現原理,總的來說并不難,因為所有的信息都靜態保存在了異常跳轉表(簡稱異常表)中。并且在不報錯時,異常捕獲對程序性能沒有任何影響,所以放心使用。

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

2024-11-07 11:04:55

2023-09-03 17:05:20

虛擬機

2017-11-14 16:43:13

Java虛擬機線程

2010-12-23 14:05:12

虛擬機

2012-04-10 10:29:29

2012-08-08 11:12:40

IBMdW

2017-03-21 16:34:38

iOS捕獲異常

2022-08-14 09:11:13

Kubernetes容器云原生

2012-05-18 10:22:23

2009-10-13 15:00:36

物理機虛擬機網絡安全

2010-12-27 14:11:55

虛擬機配置CPU

2019-03-05 14:59:42

Java虛擬機加載類

2010-01-18 10:15:50

虛擬機ubuntu

2020-01-17 10:52:37

無服務器容器技術

2023-09-02 21:35:39

Linux虛擬機

2010-07-26 09:02:38

2013-07-17 09:32:58

2010-02-26 15:28:15

Python虛擬機

2009-06-12 16:15:42

死鎖Java虛擬機

2013-11-19 14:05:08

VDP虛擬機
點贊
收藏

51CTO技術棧公眾號

色综合久久久久久久| 国产毛片精品一区| 中文字幕亚洲一区二区三区| 日日干日日操日日射| 男插女视频久久久| 国产亚洲成av人在线观看导航 | 久久国产剧场电影| 久久全球大尺度高清视频| 国产精品无码永久免费不卡| 91麻豆精品国产综合久久久| 午夜日韩在线观看| 在线精品日韩| 久蕉依人在线视频| 国产成人午夜电影网| 国产精品久久9| 国产在线精品观看| 亚洲国产精品91| 亚洲视频视频在线| 视频免费在线观看| 日本免费一区二区三区等视频| 亚洲成av人片一区二区梦乃| 一区一区视频| yourporn在线观看中文站| 成人国产视频在线观看| 成人免费在线网址| 中文字幕天堂在线| 亚洲伊人观看| 久久久久亚洲精品| 久久精品www| 999久久久国产精品| 亚洲无限av看| 搡老熟女老女人一区二区| 一区视频网站| 日韩欧美的一区| 久久精品一卡二卡| 国产精品xnxxcom| 欧美日韩精品一区二区三区| 91精品91久久久中77777老牛| 污网站在线免费看| 一区二区三区在线观看国产| 中文字幕一区二区三区5566| www黄在线观看| 欧美韩日一区二区三区| 欧美综合77777色婷婷| 日本中文字幕电影在线观看| 91一区二区三区在线播放| 国产精品二区三区| 男人天堂综合网| 成人激情小说乱人伦| 春色成人在线视频| 日韩中文字幕观看| 99热99精品| 久久精品中文字幕一区二区三区| 日本人妻丰满熟妇久久久久久| 成人免费毛片高清视频| 国产精品一区视频| 天堂成人在线| 国产亚洲欧美日韩俺去了| 三级三级久久三级久久18| 成人福利在线| 亚洲日本一区二区| 国产在线xxxx| 国产三级电影在线播放| 日韩欧中文字幕| 五月婷婷之综合激情| 成人黄色免费观看| 欧美一区二区三区在线观看| 美女流白浆视频| 人人网欧美视频| 亚洲视频在线免费观看| 天天操天天摸天天舔| 91精品国产福利在线观看麻豆| 欧美精品在线播放| 日韩特黄一级片| 蜜臀av一区二区在线免费观看| 成人精品视频久久久久| 亚洲男女视频在线观看| 久久综合九色综合久久久精品综合| 牛人盗摄一区二区三区视频| 中文字幕日本在线观看| 一区二区激情视频| 男女午夜激情视频| 在线免费成人| 日韩电影中文字幕av| 免费一级特黄3大片视频| 在线中文字幕第一区| 午夜精品一区二区三区在线| 波多野结衣爱爱| 国产成人综合自拍| 青青成人在线| 三级网站视频在在线播放| 欧美性猛交xxxx久久久| 8x8x成人免费视频| 日韩影视高清在线观看| 久久综合伊人77777尤物| 日本在线小视频| 激情五月婷婷综合| 久久精品久久精品国产大片| 成人ww免费完整版在线观看| 欧美日韩在线免费观看| 欧美日韩精品区别| 亚洲人挤奶视频| 欧美乱大交做爰xxxⅹ性3| 日批视频免费在线观看| 国产福利91精品| 日韩av高清| eeuss鲁一区二区三区| 欧美日韩视频一区二区| 大乳护士喂奶hd| 中文一区一区三区免费在线观看| 日本一区二区三区四区视频| 国产99久久九九精品无码免费| 久久精品这里都是精品| 无码 制服 丝袜 国产 另类| 996久久国产精品线观看| 亚洲免费视频观看| 影音先锋亚洲天堂| 丰满放荡岳乱妇91ww| 日本不卡一区二区三区四区| 成人日韩精品| 日韩理论片久久| 日本熟妇毛耸耸xxxxxx| 国产在线精品不卡| 亚洲视频精品一区| 91九色综合| 亚洲天堂色网站| 视频一区二区三区四区五区| 成人蜜臀av电影| 六月婷婷激情综合| 国产精品亚洲四区在线观看| 最近2019中文字幕一页二页| 久久亚洲精品石原莉奈 | 97伦伦午夜电影理伦片| 亚洲二区精品| 国产精品国产精品| 国精一区二区三区| 精品三级在线观看| 久久久无码精品亚洲国产| 国产一区二区导航在线播放| 正在播放一区| 亚洲欧洲日韩精品在线| 神马久久久久久| 一起草av在线| 综合在线观看色| 古装做爰无遮挡三级聊斋艳谭| 久久一区二区三区喷水| 成人动漫网站在线观看| 蜜桃视频网站在线观看| 欧美精品色一区二区三区| 肉色超薄丝袜脚交69xx图片| 黄网站免费久久| 99精品一级欧美片免费播放| 精品国产三级| 欧美床上激情在线观看| 亚洲精品视频91| 午夜伊人狠狠久久| 日韩中文字幕电影| 日韩高清在线电影| 最新不卡av| 五月亚洲婷婷| 91成人免费观看网站| 美丽的姑娘在线观看免费动漫| 欧美视频在线免费看| 朝桐光av一区二区三区| 模特精品在线| 一区二区视频在线观看| 日韩欧美中文字幕一区二区三区 | 欧美大胆成人| 色婷婷综合成人av| 亚洲精品久久久狠狠狠爱| 亚洲va欧美va国产va天堂影院| 欧美丰满少妇人妻精品| 蜜芽一区二区三区| 日韩欧美猛交xxxxx无码| 美女视频免费精品| 国产精品直播网红| 香蕉久久aⅴ一区二区三区| 亚洲黄色在线看| 中文字幕理论片| 亚洲愉拍自拍另类高清精品| 人妻丰满熟妇av无码久久洗澡| 日韩制服丝袜av| 粉嫩av一区二区三区天美传媒| 欧美五码在线| 国产欧美一区二区白浆黑人| 男女视频在线| 中文字幕视频在线免费欧美日韩综合在线看 | 国产鲁鲁视频在线观看特色| 亚洲激情在线观看| 国产精品嫩草影院精东| 精品久久久久久中文字幕大豆网| 国产成人免费观看网站| www.亚洲激情.com| 91热视频在线观看| 久久久久国内| 欧美视频在线第一页| 成人精品影院| 精品人伦一区二区三区| 亚洲成人毛片| 日本三级韩国三级久久| 美女精品导航| 久久精品99久久香蕉国产色戒| 性xxxx视频| 欧美电影免费观看完整版| 在线视频 中文字幕| 婷婷激情综合网| 免费人成在线观看| 国产精品第一页第二页第三页| 中文字幕xxx| 成人免费视频caoporn| 国产探花在线观看视频| 天堂精品中文字幕在线| www.射射射| 一区二区三区国产精华| 水蜜桃一区二区三区| 色婷婷狠狠五月综合天色拍| 成人自拍爱视频| 亚洲福利合集| 成人h视频在线| 日韩av懂色| 国产精品露脸自拍| 二吊插入一穴一区二区| 国产91精品视频在线观看| 亚洲区欧洲区| 美女扒开尿口让男人操亚洲视频网站| 国产最新视频在线观看| 亚洲精品97久久| 欧美视频xxx| 精品日韩99亚洲| 99草在线视频| 337p亚洲精品色噜噜| 一区二区三区日| 欧美精品久久天天躁| 97超碰国产在线| 欧美另类高清zo欧美| 亚洲午夜激情视频| 欧美视频一区二区三区四区| 在线观看亚洲黄色| 欧美主播一区二区三区| 国产裸体美女永久免费无遮挡| 91福利在线免费观看| 无码人妻av一区二区三区波多野| 欧美性猛xxx| 无码人妻熟妇av又粗又大| 一本大道久久a久久精品综合| 丰满少妇xoxoxo视频| 日韩欧美国产骚| 亚洲大尺度在线观看| 欧美性色综合网| 国产又粗又猛又爽又黄视频| 欧美日韩aaaaaa| a级片免费视频| 精品少妇一区二区三区| 偷拍自拍在线| 在线观看国产成人av片| 欧美激情午夜| 欧美日韩成人在线播放| wwwwxxxx在线观看| 日本aⅴ大伊香蕉精品视频| 黄瓜视频成人app免费| 国产精品久久久久久久7电影| 99只有精品| 91亚洲精品丁香在线观看| 国产精品99久久免费观看| 欧美极品日韩| 999久久久91| 青青青在线视频播放| 久久久精品五月天| 亚洲美女爱爱视频| 丁香一区二区三区| 成人国产精品久久久网站| 国产精品美女视频| 中文字幕另类日韩欧美亚洲嫩草| 亚洲网友自拍偷拍| 国产又大又粗又爽| 在线不卡免费av| 深夜福利视频网站| 日韩在线观看网站| 欧美hdxxx| 国产精品视频区| 99这里只有精品视频| 欧美日韩在线精品| 欧美黄污视频| 黄色片一级视频| 国产精一区二区三区| 老司机福利av| 亚洲免费在线观看| 天天操天天操天天操天天| 欧美精品久久一区二区三区| 特黄视频在线观看| www日韩中文字幕在线看| 国产免费拔擦拔擦8x高清在线人| 国产精品亚洲欧美导航| 激情小说亚洲色图| 中文字幕99| 久久国产精品久久w女人spa| 四虎1515hh.com| 国产日韩v精品一区二区| 国产精品不卡av| 制服丝袜亚洲精品中文字幕| 色吊丝在线永久观看最新版本| 久久人人爽人人爽人人片亚洲| 成人欧美大片| 国产日韩欧美一区二区| 亚州av乱码久久精品蜜桃| 国产女女做受ⅹxx高潮| 成人丝袜高跟foot| 麻豆精品国产免费| 欧美日韩一区二区在线观看| 色视频在线观看| 久久久免费精品视频| 高清国产一区二区三区四区五区| 欧洲精品码一区二区三区免费看| 亚洲婷婷在线| 美女被艹视频网站| 国产精品视频在线看| av图片在线观看| 亚洲国产精品中文| 欧美大片黄色| 91免费看国产| 91日韩在线| 久久撸在线视频| 欧美激情一区在线观看| 天堂中文字幕在线观看| 亚洲激情视频在线| av岛国在线| 国产一级精品aaaaa看| 亚洲高清在线| 最新日本中文字幕| 洋洋成人永久网站入口| 成人黄色在线观看视频| 久久精品国产2020观看福利| 先锋影音一区二区| 亚洲一区三区视频在线观看| 男人的j进女人的j一区| 日韩视频在线观看免费视频| 色综合天天综合网天天狠天天| 免费国产羞羞网站视频| 亚洲18私人小影院| 日韩高清成人在线| 99色精品视频| 久久久久国产精品麻豆ai换脸 | 欧美日韩国产一级二级| 粉嫩av一区| 国产精品一二区| 91精品一区国产高清在线gif | 97青娱国产盛宴精品视频| 大西瓜av在线| 成人91在线观看| 欧美啪啪小视频| 亚洲桃花岛网站| 丁香久久综合| 伊人久久大香线蕉av一区| 韩日欧美一区二区三区| 亚洲色图综合区| 亚洲国产天堂久久综合| 高清不卡av| 亚洲综合首页| 国产麻豆成人精品| 日本少妇激情视频| 亚洲欧洲日韩国产| 四虎视频在线精品免费网址| 国产 欧美 日本| 91丝袜国产在线播放| 最近中文字幕在线观看| 久久精品99国产精品酒店日本| 亚洲精品影片| 国产成人久久婷婷精品流白浆| 中文久久乱码一区二区| 国产三级伦理片| 91国内在线视频| 日韩.com| 亚洲熟妇一区二区| 欧美日韩中文字幕日韩欧美| 在线播放麻豆| av日韩中文字幕| 日韩高清在线电影| 免费在线观看国产精品| 亚洲裸体xxxx| 日本精品在线观看| 91黄色小网站| 一区二区在线观看视频在线观看| 神马午夜一区二区| 国产精品女人网站| 亚洲成人资源| 一级性生活免费视频| 亚洲国产精品推荐| 欧美成a人片免费观看久久五月天| 国产一级大片免费看| 久久你懂得1024| 亚洲AV午夜精品| 国产精品劲爆视频| 一本色道久久综合亚洲精品不卡 | 人妻精品久久久久中文字幕69| 狠狠躁夜夜躁人人躁婷婷91 | 欧美日韩国产一中文字不卡| 含羞草www国产在线视频| 蜜桃免费一区二区三区| 国产精品一区在线观看你懂的| 国产精品免费精品一区|