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

V8 加速啟動的快照技術

開發 前端
如果啟動時傳了 --build_snapshot 表示需要在進程退出時構建快照,并且把構建的快照寫入到當前目錄到 snapshot.blob 文件中。否則就是正常啟動,如果正常啟動時傳了 --snapshop_blob snapshot.blob 則表示通過快照啟動。

V8 每次啟動時都需要創建新的 Isolate 和 Context,這需要一定的時間,V8 啟動快照是一種用于加速啟動性能的技術,它利用事先創建的快照直接初始化 Isolate 和 Context,加快啟動時間。同時 V8 還提供了一系列 API 給使用者,使用者可以把自己的數據寫入快照,然后在啟動的時候直接恢復數據,加快啟動速度,比如 Node.js 支持啟動快照。我最近給自己之前寫的玩具 JS 運行時 No.js 加入了啟動快照的功能,以此為例簡單介紹下 V8 的快照技術。

以下 No.js 的啟動代碼。

int main(int argc, char* argv[]) {
  if (argc > 1) {
    if (strcmp(argv[1], "--build_snapshot") == 0) {
      BuildSnapshot(argc, argv);
    } else {
      Start(argc, argv);
    }
  }
  return 0;
}

如果啟動時傳了 --build_snapshot 表示需要在進程退出時構建快照,并且把構建的快照寫入到當前目錄到 snapshot.blob 文件中。否則就是正常啟動,如果正常啟動時傳了 --snapshop_blob snapshot.blob 則表示通過快照啟動。

構建快照

void BuildSnapshot(int argc, char* argv[]) {
  {
    // 表示快照的信息
    No::Snapshot::SnapshotData snapshot_data;
    // No.js 實現的 C++ API 的地址數組
    No::ExternalReferenceRegistry external_reference_registry;
    conststd::vector<intptr_t>& external_references = external_reference_registry.external_references();
    v8::SnapshotCreator creator(external_references.data());
    // 啟動代碼
    Isolate* isolate = creator.GetIsolate();
    {
      Isolate::Scope isolate_scope(isolate);
      HandleScope handle_scope(isolate);
      Local<ObjectTemplate> global = ObjectTemplate::New(isolate);
      Local<Context> context = Context::New(isolate, nullptr, global);
      Context::Scope context_scope(context);
      Environment * env = new Environment(context);
      {
        No::MicroTask::MicroTaskScope microTaskScope(env);
        // 執行用戶 JS 代碼,啟動事件循環
        No::Core::Run(env);
      }
      // 執行完畢,處理快照的邏輯
      env->run_snapshot_serial_callback();
      // 設置上下文到快照中
      creator.SetDefaultContext(context, v8::SerializeInternalFieldsCallback());
      // 把 No.js 內部的信息寫入快照
      env->serialize(&creator, &snapshot_data);
      delete env;
    }
    // 創建快照
    snapshot_data.blob = creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kKeep);
    // 把快照內存寫到文件
    // ...
}

構建快照的過程和一般的啟動過程是類似的,區別是在進程退出前會執行構建和寫快照的步驟。下面來看下構建快照的過程。creator.SetDefaultContext 會把當前執行的 context 加入到快照中,假設我們在 JS 里設置了一個全局變量,那么后續通過快照啟動時,該全局變量還會存在,可以直接使用,除了把 V8 context 加入快照,No.js 還會把自己相關的信息加入快照中。

void Environment::serialize(v8::SnapshotCreator* creator, No::Snapshot::SnapshotData* snapshot_data) {  
    uint32_t id = 0;
    #define V(PropertyName, TypeName)                                              \
        if (!PropertyName().IsEmpty()) {                                 \
            size_t index = creator->AddData(GetContext(), PropertyName());         \
            snapshot_data->env_info.props.push_back({#PropertyName, index, id++}); \
        }       
        PER_ISOLATE_TEMPLATE_PROPERTIES(V)
        PER_ISOLATE_OBJECT_PROPERTIES(V)
        PER_ISOLATE_FUNCTION_PROPERTIES(V)
    #undef V
}

Environment 是 No.js 運行時用到的一些公共信息,serialize 里是把 Environment 的各種信息加入到快照中,下面看一個例子。

if (!snapshot_serialize_cb.IsEmpty()) {                                 
    size_t index = creator->AddData(GetContext(), snapshot_serialize_cb());         
    snapshot_data->env_info.props.push_back({"snapshot_serialize_cb", index, id++}); 
}

上面代碼通過 V8 的 AddData API 把 V8 對象加入到快照中,V8 會返回一個索引,我們需要記錄這個索引,后續通過快照啟動時需要用到(這是實現快照加速非常關鍵的邏輯)。執行完這些操作后,最后通過 V8 的 creator.CreateBlob API 創建快照,然后寫入文件中。

std::ofstream out("snapshot.blob", std::ios::out | std::ios::binary);
// 寫入一些元信息
for (size_t i = 0; i < snapshot_data.env_info.props.size(); i++) {
    std::string name = snapshot_data.env_info.props[i].name;
    std::string id = std::to_string(snapshot_data.env_info.props[i].id);
    std::string index = std::to_string(snapshot_data.env_info.props[i].index);
    out.write(name.data(), name.size());
    out.write(":", 1);
    out.write(id.data(), id.size());
    out.write(":", 1);
    out.write(index.data(), index.size());
    if (i != (snapshot_data.env_info.props.size() - 1)) {
    out.write("|", 1);
    }
}
out.write("\n", 1);
// 寫入 V8 快照信息
out.write(snapshot_data.blob.data, snapshot_data.blob.raw_size);
out.close();

前面說過我們把額外的信息加入 V8 快照時會返回一個索引,我們需要收集這些索引并寫入文件中,后續通過快照啟動時使用,否則無法從快照中找到我們需要的信息。

通過快照啟動

有了快照后,我們就可以通過快照啟動了。

void Start(int argc, char* argv[]) {
  Isolate::CreateParams create_params;
  No::Snapshot::SnapshotData snapshot_data;
  No::ExternalReferenceRegistry external_reference_registry;
bool startup_from_snapshot = false;
// 通過快照啟動
if (strcmp(argv[1], "--snapshot_blob") == 0) {
    //  buffer 表示快照的內容
    std::string s(buffer.data(), buffer.size());
    int end = s.find("\n"); 
    // 讀取 No.js 自己寫入的索引元信息
    std::string prop_data = s.substr(0, end);
    std::vector<std::string> props = No::Util::Split(prop_data, '|');
    for (auto& prop : props) {
      std::vector<std::string> prop_fields = No::Util::Split(prop, ':');
      snapshot_data.env_info.props.push_back({prop_fields[0],static_cast<size_t>(std::stoi(prop_fields[1])), static_cast<uint32_t>(std::stoi(prop_fields[2]))});
    }
    // 讀取 V8 的快照信息
    s = s.substr(end + 1);
    char * blob = newchar[s.size()];
    memcpy(blob, s.data(), s.size());
    snapshot_data.blob = v8::StartupData{blob, static_cast<int>(s.size())};
    // 設置到啟動參數 create_params 重
    create_params.snapshot_blob = &snapshot_data.blob;
    conststd::vector<intptr_t>& external_references = external_reference_registry.external_references();
    create_params.external_references = external_references.data();
    startup_from_snapshot = true;
  }

  Isolate* isolate = Isolate::New(create_params);
  {
    Isolate::Scope isolate_scope(isolate);
    HandleScope handle_scope(isolate);
    // 創建 Context,因為 create_params 中設置了快照,這里會直接從快照構建 Context,而不是重新創建
    Local<Context> context = Context::New(isolate);
    Context::Scope context_scope(context);
    Environment * env = new Environment(context);
    // 從快照中獲取之前設置到信息
    env->deserialize(&snapshot_data);
    env->run_snapshot_deserial_callback();
    // 正常啟動,執行 JS 和事件循環
    {
      No::MicroTask::MicroTaskScope microTaskScope(env);
      if (startup_from_snapshot && !env->snapshot_deserialize_main().IsEmpty()) {
        env->run_snapshot_deserialize_main();
      } else {
        No::Core::Run(env);
      }
    }
    delete env;
  }
}

首先讀取快照文件內容,內容分為兩部分,分別是 No.js 本身的元信息和 V8 的快照內容,前者 No.js 自己使用,后者提供給 V8 用于啟動初始化,等 V8 初始化完畢后我們通過 env->deserialize 從快照中恢復額外的數據。

void Environment::deserialize(No::Snapshot::SnapshotData* snapshot_data) {  
    #define V(PropertyName, TypeName)                                              \
        for (auto& prop : snapshot_data->env_info.props) {\
            if (prop.name == #PropertyName) {\
                Local<TypeName> obj = GetContext()->GetDataFromSnapshotOnce<TypeName>(prop.index).ToLocalChecked();\
                set_##PropertyName(obj);\
            }\
        }
        PER_ISOLATE_TEMPLATE_PROPERTIES(V)
        PER_ISOLATE_OBJECT_PROPERTIES(V)
        PER_ISOLATE_FUNCTION_PROPERTIES(V)
    #undef V
}

以上代碼大致就是執行 context->GetDataFromSnapshotOnce(prop.index) API 并傳入對應的索引從快照中獲取之前設置的信息并設置到 Environment 中,這樣就完成了數據的恢復。

內部模塊快照

JS 運行時有很多內置模塊,每次執行時都需要編譯執行浪費時間,我們可以把它直接寫入快照中,后續通過快照啟動時直接使用,避免重復處理。下面看了一個例子。

const snapshot = require("snapshot");

if (snapshot.isBuildSnapshot()) {
    snapshot.hello="world"
} else {
    console.log(snapshot.hello)
}

snapshot 是 No.js 的內置模塊,第一次執行時我們在 snapshot 對象上設置了一個 hello 屬性,然后再次啟動時輸出該屬性可以看到還存在。下面看看實現原理。No.js 的 C++ 模塊和 JS 模塊都是寫到一個對象中的,大概如下:

const No = {
  buildin: { "tcp": {} },
  libs: { "net": {} },
};

下面是 No.js 啟動時的邏輯。

void No::Core::Run(Environment * env) {
    Isolate * isolate = env->GetIsolate();
    Local<Context> context = env->GetContext();
    // 不是通過快照啟動則創建新的對象,否則復用快照的對象
    if (!env->has_startup_snapshot()) {
        // 創建新的則設置到 env,進程退出后 No 會被寫入快照,再次通過快照啟動時可以直接復用
        env->set_no(Object::New(isolate));
    }
   
    Local<Object> No = env->no();
    // 執行 No.js 文件
    func->Call(context, context->Global(), 1, argv).ToLocalChecked();  
    {
        No::MicroTask::MicroTaskScope microTaskScope(env);
    }
    // 啟動事件循環
    uv_run(env->loop(), UV_RUN_DEFAULT);
    
}

No.js 文件如下。

const {
    loader,
    process,
    snapshot,
} = No.buildin;

// 內置 JS 模塊
class NativeModule {
    exports
    constructor(filename) {
        this.filename = filename;
        this.exports = {};
    }
    load() {
        const func = loader.compileNative(this.filename)
        func.call(null, loader.compile, this.exports, this, No);
    }
}

// 加載內置 JS 模塊
function require(filename) {
    constmodule = new NativeModule(filename);
    module.load();
    returnmodule.exports;
}

function loaderNativeModules() {
    const modules = [
        {
            filename: 'libs/uv/index.js',
            name: 'uv',
        },
    ];
    No.libs = {};
    for (let i = 0; i < modules.length; i++) {
        const { name, filename } = modules[i];
        No.libs[name] = require(filename);
    }
}
                                       
// 如果通過快照啟動則不需要重新加載內置 JS 模塊,直接復用快照的
if (!snapshot.hasStartupSnapshot()) {
    loaderNativeModules();
}

function runMain() {
    constmodule = require("libs/module/index.js");
    let entry;
    for (let i = 0; i < process.argv.length; i++) {
        if (process.argv[i].endsWith('.js')) {
            entry = process.argv[i];
        }
    }
    if (process.isMainThread) {
        module.load(entry);
    }
}

runMain();

用戶自定義快照

除了可以把 No.js 內部的信息寫入快照外,No.js 也支持用戶把自己的信息寫入快照。看下面的一個使用例子。

const snapshot = require("snapshot");

let now = Date.now();

if (snapshot.isBuildSnapshot()) {
    snapshot.addSerialCallback(function() {
        console.log("serial:now=", now);
    });
    snapshot.addDeSerialCallback(function() {
        console.log("deserial:now=", now);
    });
}

addSerialCallback 的函數參數會在構建快照的過程中被調用,用戶可以在這里把信息寫入快照,addDeSerialCallback 的函數參數會在通過快照啟動時被執行,這里可以進行數據恢復。

  1. No --bild_snapshot demo.js 時會輸出:serial:sum=100000000。
  2. No --snapshot_blob snapshot.blob 時會輸出:serial:sum=100000000。 實現原理是通過把一個函數記錄到快照中,然后通過閉包記錄了之前的上下文,當通過快照啟動時恢復該快照并找到之前的上下文。下面看下實現。
function addSerialCallback(callback, data) {
    serialCallbackQueue.push(new SnapshotTask(callback, data));
    if (serialCallbackQueue.length === 1) {
        snapshot.addSerialCallback(runSerialCallback)
    }
}
```js
addSerialCallback 在 JS 層維護了一個函數隊列,并設置 runSerialCallback 到 C++ 層。
```c++
void SetSerializeCallback(V8_ARGS) {
    Environment *env = Environment::GetCurrent(args.GetIsolate());
    // snapshot_serialize_cb 函數會被寫入快照,在通過快照啟動時被恢復,可以參考之前介紹的內容
    env->set_snapshot_serialize_cb(args[0].As<Function>());
}

runSerialCallback 會在進程退出時被執行,從而執行 addSerialCallback 中的函數數組。

{
  No::MicroTask::MicroTaskScope microTaskScope(env);
  No::Core::Run(env);
}
// 用戶代碼執行完畢,執行 runSerialCallback
env->run_snapshot_serial_callback();
creator.SetDefaultContext(context, v8::SerializeInternalFieldsCallback());
env->serialize(&creator, &snapshot_data);

runSerialCallback 就是遍歷函數逐個執行。

function runSerialCallback() {
    serialCallbackQueue.forEach(task => {
        task.callback()(task.data());
    })
}

addDeSerialCallback 的實現是一樣的,區別是執行時機不同,addDeSerialCallback 的函數參數也會被記錄到快照中,在通過快照啟動時被執行。

單體應用

一般來說,執行 JS 運行時需要提供一個入口文件,單體應用則不需要,因為它可以在快照中記錄入口函數,從而在通過快照啟動時直接執行入口函數,并且可以使用之前的上下文信息。下面是一個例子。

const snapshot = require("snapshot");
// 第一次啟動時計算一個值
let sum = 0;
for (let i = 0; i < 100000000; i++) {
    sum += 1;
}
if (snapshot.isBuildSnapshot()) {
    // 進程退出前執行
    snapshot.addSerialCallback(function() {
        console.log("serial:sum=", sum);
    });
    // 通過快照啟動時執行
    snapshot.addDeSerialCallback(function() {
        sum++;
        console.log("deserial:sum=", sum);
    });
    // 通過快照啟動時執行
    snapshot.setDeserializeMain(function() {
        console.log("setDeserializeMain", sum);
    });
}

執行 No --biuld_snapshot demo.js 時 addSerialCallback 的函數參數會被執行,執行 No --snapshot_blob snapshot.blob 時就會執行 addDeSerialCallback 函數參數,最后執行 setDeserializeMain 函數參數啟動進程。

外部 C++ API

JS 運行時會設置很多 C++ 層的 API 到 JS 層使用,而這些 C++ API 的函數地址在不同進程(每次啟動時)是不一樣的,所以我們需要把這些信息告訴 V8。

class ExternalReferenceRegistry {
  public:
  ExternalReferenceRegistry();

const std::vector<intptr_t>& external_references();

bool is_empty() { return external_references_.empty(); }

template <typename T>
void Register(T* address) {
    external_references_.push_back(reinterpret_cast<intptr_t>(address));
  }

private:

bool is_finalized_ = false;
std::vector<intptr_t> external_references_;
};

實現比較簡單,每個注冊到 JS 層的 C++ API 都調 Register 把自己的地址注冊到 ExternalReferenceRegistry 中,在創建快照和通過快照啟動時都傳入順序一樣的函數地址數組給 V8 即可,假設我們有個 C++ API A,第一次啟動構建快照時,寫入快照的地址是 0x1,后續通過快照啟動時 A 的地址變成了 0x2,V8 還通過 0x1 訪問機會報錯,所以我們每次都需要把最新的地址告訴 V8,V8 會重寫函數對應的地址。

  1. 構建快照時:
No::ExternalReferenceRegistry external_reference_registry;
const std::vector<intptr_t>& external_references = external_reference_registry.external_references();
v8::SnapshotCreator creator(external_references.data());
Isolate* isolate = creator.GetIsolate();
creator.CreateBlob(...);
  1. 通過快照啟動時:
Isolate::CreateParams create_params;
No::ExternalReferenceRegistry external_reference_registry;
const std::vector<intptr_t>& external_references = external_reference_registry.external_references();
create_params.external_references = external_references.data();

總結

V8 快照的內容還是挺多的,對于 JS 運行時來說需要處理的細節也比較多,很多地方的代碼可能都需要改造。但是對于需要啟動加速的場景是非常有意義的,比如 serverless,下面是一個啟動加速的例子。

const snapshot = require("snapshot");

if (snapshot.isBuildSnapshot()) {
  global.sum = 0
  for (let i = 0; i < 100000000; i++) {
    global.sum += 1;
  }
} else {
  console.log(global.sum);
}

不通過快照啟動時時間是 0.912501s,通過快照啟動時是 0.00955017s。當然這只是個例子,而且通過快照啟動時處理快照也是需要時間的,具體的情況需要具體分析。

以上是最近業余時間對快照的一些探索(可以參考 https://github.com/theanarkh/nojs),大家如果有興趣的話也可以自行研究,后面會再介紹下 Node.js 中的實現。

責任編輯:武曉燕 來源: 編程雜技
相關推薦

2023-10-10 10:23:50

JavaScriptV8

2010-07-20 16:35:52

V8JavaScript瀏覽器

2022-09-16 08:32:25

JavaC++語言

2023-06-05 16:38:51

JavaScript編程語言V8

2022-04-01 08:02:32

Node.js快照加速hooks

2020-06-02 13:34:16

支付寶小程序 V8 Worker

2014-11-26 09:51:24

GithubGoogleV8

2010-08-31 11:42:03

DB2MDC

2022-04-29 08:00:51

V8垃圾回收

2021-05-28 05:30:55

HandleV8代碼

2023-02-28 07:56:07

V8內存管理

2011-10-19 13:47:57

ibmdwRationalWAS

2016-10-18 15:18:48

JEECMS V*javaCMS系統

2021-08-29 18:34:44

編譯V8C++

2023-03-09 09:43:56

架構技術

2022-10-24 09:11:05

TypeScriptV8

2022-04-29 08:05:06

內存堆外GC

2022-05-06 23:03:48

V8CPUProfiler

2022-08-19 06:40:02

V8GC

2021-10-22 21:39:11

InspectorV8 JS
點贊
收藏

51CTO技術棧公眾號

99久久国产综合精品女不卡| 亚洲草久电影| 欧美日韩色婷婷| 精品国产综合| 亚洲一卡二卡在线观看| 欧美精品不卡| 亚洲丝袜在线视频| 91精品国产三级| 午夜影院在线观看国产主播| 欧美国产乱子伦| 99久久精品久久久久久ai换脸| 日韩欧美高清在线观看| 欧美日韩国产一区二区三区不卡| 欧美一级生活片| 丰满少妇被猛烈进入高清播放| www亚洲人| 成人福利视频在线| 国产精品一区二区久久精品| 精品视频久久久久| 精品欧美久久| 亚洲精品美女网站| 肉色超薄丝袜脚交| 丝袜美腿诱惑一区二区三区| 一区二区三区四区不卡视频| 色综合久久av| 午夜视频福利在线| 国产一区二区三区四区五区美女| 欧美孕妇毛茸茸xxxx| 欧美成人免费看| 色琪琪久久se色| 亚洲欧洲xxxx| 国产又粗又猛又色| 日韩在线视频一区二区三区| 欧美综合在线视频| 欧美日韩黄色一级片| 在线观看中文| 国产精品视频一二三| 精品国产一区二区三区麻豆小说| 成人1区2区3区| 精品在线你懂的| 国产福利视频一区二区| 日韩免费视频一区二区视频在线观看| 女人天堂亚洲aⅴ在线观看| 一区二区三区四区视频| 这里只有久久精品| 群体交乱之放荡娇妻一区二区| 日韩精品一区二区三区四区 | 欧美人与性动交α欧美精品济南到| 亚洲国产精品二十页| 欧美日韩在线一区二区三区| 天天综合在线视频| 成人免费电影视频| 成人免费视频观看视频| 精品久久久久成人码免费动漫| 久久99久久99精品免视看婷婷| 国产精品男人的天堂| 国产精品久久久久久久久夜色| 欧美一区=区| 国产成人精品一区二区三区| 人人爽人人爽人人片av| 性欧美暴力猛交另类hd| 欧美怡春院一区二区三区| 中文字幕av影院| 日本在线播放一区二区三区| 国产精品激情av在线播放| 少妇一级淫片日本| 美女视频一区二区三区| 91精品国产综合久久久久久久久| 国产精品无码免费播放| 国产精品一区二区你懂的| 91亚洲国产成人精品性色| 精品国产乱码久久久久久蜜臀网站| 国产盗摄女厕一区二区三区 | 免费一区二区三区在线观看 | 成人午夜电影免费在线观看| 亚洲欧美黄色片| bt欧美亚洲午夜电影天堂| 国产欧美一区二区三区另类精品 | 一区二区三区播放| 国产伦精品一区二区三区免费 | 亚洲精选视频免费看| 无码日本精品xxxxxxxxx| h片精品在线观看| 欧美性猛交xxxx黑人| 久久精品影视大全| 国产专区精品| 日韩电影中文字幕在线观看| www.99热| 欧美777四色影| 国产91成人在在线播放| 中文字幕免费高清在线观看| 国产精品一色哟哟哟| 激情五月综合色婷婷一区二区| 国产精品一区二区三区四区色| 国产精品国产馆在线真实露脸| 国产91在线亚洲| 久久91导航| 日韩午夜精品视频| www.av天天| 国产精品vip| 国产精品久久久久久久久久小说| 99热这里只有精品9| 91网站最新网址| 中文字幕成人一区| 校园春色亚洲| 日韩午夜在线影院| 五月天婷婷丁香网| 精品二区久久| 国产日韩中文字幕| 人人九九精品| 亚洲一区二区三区自拍| the porn av| 丝袜av一区| 免费av一区二区| 国产99免费视频| 99久久国产综合精品麻豆| 成人短视频在线看| 日韩在线免费| 日韩高清a**址| 久久久久成人网站| 精品一区二区三区在线视频| 免费看污久久久| 青草影视电视剧免费播放在线观看| 在线视频一区二区免费| 污污内射在线观看一区二区少妇 | 在线视频一区二区| 国产黄色片免费看| 国产69精品久久久久777| 亚洲综合网中心| 美女写真久久影院| 亚洲精品福利在线观看| 久草免费在线视频观看| 久久精品国产久精国产| 欧美日韩亚洲在线| 中文字幕乱码中文乱码51精品| 精品日韩成人av| 91精品国产高清一区二区三蜜臀| 青青草精品视频| 欧美日韩精品不卡| 人人草在线视频| 日韩国产欧美区| 国产黄色片免费看| 91色视频在线| 国产黄色特级片| 日本在线中文字幕一区| 2024亚洲男人天堂| 天堂v视频永久在线播放| 精品欧美国产一区二区三区| 男男一级淫片免费播放| 黄色成人精品网站| 国产精品久久久久久久久久久久午夜片 | 国产在线一区观看| 国产伦一区二区三区色一情| www.综合网.com| 亚洲国产欧美一区| 天堂а√在线中文在线新版| 91在线丨porny丨国产| 国产成人无码精品久久久性色| 嫩草国产精品入口| 欧美中文字幕在线| 精品三级久久久久久久电影聊斋| 一本大道久久a久久精二百| 丰满圆润老女人hd| 日本欧美一区二区在线观看| 在线观看日韩片| 久久99成人| 欧美精品久久久久a| 欧美一级做性受免费大片免费| 亚洲va韩国va欧美va精品| av网页在线观看| 日韩av电影一区| 国产福利片一区二区| 欧美电影在线观看一区| 国模精品一区二区三区色天香| 天堂中文在线资源| 色噜噜狠狠成人中文综合 | 香蕉久久一区二区三区| 色综合欧美在线| 波多野结衣家庭教师在线观看| 国产一区美女在线| 九色在线视频观看| 国产精品传媒精东影业在线 | 免费看污污网站| 一区二区三区四区在线观看国产日韩 | 在线视频一区二区三区四区| 国产精品久久久久天堂| 亚洲精品一区二区18漫画| 宅男噜噜噜66国产日韩在线观看| 日韩福利影院| 日韩欧美中文字幕一区二区三区| 97免费中文视频在线观看| 国产片在线观看| 欧美第一区第二区| 亚洲免费视频二区| 亚洲综合无码一区二区| 91激情视频在线观看| 国产精品夜夜嗨| 婷婷丁香激情网| 亚洲午夜视频| 亚洲一区二区三区欧美| 免费成人蒂法| 91精品视频观看| 亚洲天堂一区二区| 欧美黑人xxx| 香蕉视频在线播放| 日韩高清中文字幕| www.国产免费| 欧美日韩和欧美的一区二区| 99国产超薄丝袜足j在线观看| 五月花成人网| 亚洲香蕉av在线一区二区三区| a网站在线观看| 91豆麻精品91久久久久久| 久一区二区三区| 国产精品久久久久久亚洲毛片 | www黄色日本| 欧美激情91| 一本一道久久a久久综合精品| 窝窝社区一区二区| 99在线国产| 成人污污www网站免费丝瓜| 国产成人在线精品| 99thz桃花论族在线播放| 萌白酱国产一区二区| 日韩子在线观看| 国产午夜精品一区二区三区| 亚欧洲精品视频| 欧美mv日韩mv国产网站app| 国产人妖一区二区| 欧美色国产精品| 岛国av中文字幕| 精品久久久在线观看| 精品午夜福利视频| 亚洲乱码中文字幕| 看黄色录像一级片| 中文字幕欧美日韩一区| 国产成人av一区二区三区不卡| 成人精品免费网站| 无码人妻一区二区三区精品视频| 国产成人综合自拍| 中文字幕55页| 国产一区二区看久久| 日本网站在线看| 韩日av一区二区| 日本不卡一区二区在线观看| 免费在线一区观看| 黄色aaa级片| 免费成人在线观看视频| a在线观看免费视频| 久久国产福利国产秒拍| 国产探花在线看| 激情五月播播久久久精品| 午夜剧场高清版免费观看| 久久99久久99小草精品免视看| 亚洲精品免费一区亚洲精品免费精品一区| 蜜桃在线一区二区三区| 亚洲xxx在线观看| 国产激情视频一区二区在线观看| 毛毛毛毛毛毛毛片123| 国产一区在线观看麻豆| 9.1在线观看免费| 97久久超碰国产精品| 久久久久亚洲av成人无码电影| 国产性做久久久久久| 日本午夜精品视频| 亚洲黄一区二区三区| 欧美成人手机视频| 懂色av中文一区二区三区天美| 久久久精品视频网站| 欧美另类z0zxhd电影| 亚洲成人一级片| 亚洲精品久久久久| 国产在线三区| 久久在线免费视频| av老司机在线观看| 国产极品jizzhd欧美| 9.1麻豆精品| 国产在线欧美日韩| 精品一区二区三| 波多野结衣 作品| 国产欧美日本| av免费一区二区| 不卡的av网站| 91成人精品一区二区| 一区二区视频在线看| 国产性生活视频| 欧美一区二区精美| 欧美日韩国产综合视频| 久久久精品在线| av高清不卡| 91欧美日韩一区| 要久久爱电视剧全集完整观看 | 激情久久久久久久| 噼里啪啦国语在线观看免费版高清版| 国内成人免费视频| 色呦呦一区二区| 17c精品麻豆一区二区免费| 黄色小视频在线免费看| 欧美日韩三级在线| 日韩一级片免费观看| 日韩一区二区三区xxxx| 岛国av在线播放| 91超碰在线免费观看| 欧美美女在线| 国产传媒久久久| 日本成人中文字幕| 真人bbbbbbbbb毛片| 亚洲精品va在线观看| 亚洲精品毛片一区二区三区| 精品国产免费人成电影在线观看四季 | 国产成年精品| 日韩欧美国产二区| 99精品视频免费观看| 亚洲国产日韩在线一区| 国产欧美一区视频| 中文字幕激情小说| 精品国产免费人成在线观看| fc2ppv国产精品久久| 国产精品久久久久久久天堂| 欧美**vk| 日韩在线一级片| 成人激情综合网站| 男女羞羞免费视频| 3d动漫精品啪啪一区二区竹菊| 国产精品视频二区三区| 情事1991在线| 国产精品自在线拍| 阿v天堂2018| 国产99一区视频免费| 一级片一级片一级片| 欧美日韩一级片在线观看| 国产小视频免费在线观看| 91精品国产91久久久久久| 国产+成+人+亚洲欧洲在线| 99久久久精品视频| 国产a精品视频| 国产香蕉在线视频| 精品99一区二区三区| 免费污视频在线| 99在线热播| 亚洲福利一区| aaaa黄色片| 粉嫩av一区二区三区免费野| 色屁屁草草影院ccyycom| 久久久噜噜噜久久中文字免| 一区三区自拍| 91午夜在线观看| 不卡视频在线观看| 亚洲天堂日韩av| 亚洲精品一区中文字幕乱码| 牛牛精品一区二区| 热舞福利精品大尺度视频| 日日夜夜免费精品视频| 谁有免费的黄色网址| 欧美午夜精品免费| 男人天堂久久久| 1卡2卡3卡精品视频| 亚洲激情成人| 四虎影成人精品a片| 在线观看亚洲精品| 91短视频版在线观看www免费| 成人精品久久久| 国自产拍偷拍福利精品免费一 | 亚洲欧美另类小说视频| 精品国产va久久久久久久| 国内精久久久久久久久久人| 日韩精品丝袜美腿| 中文字幕第21页| 一区二区中文视频| 精品国产亚洲AV| 91成人在线观看国产| 精品国产成人| 91香蕉视频免费看| 欧美日韩另类在线| p色视频免费在线观看| 成人综合国产精品| 亚洲激情二区| 黄色av免费播放| 日韩欧美亚洲另类制服综合在线| 成人免费图片免费观看| 亚洲v日韩v欧美v综合| 国产91丝袜在线播放九色| 少妇太紧太爽又黄又硬又爽| 中文字幕日本精品| 成人h动漫免费观看网站| 欧美日韩亚洲第一| 最近日韩中文字幕| 性高潮久久久久久久久久| 国产精品夜色7777狼人| 影音先锋亚洲精品| 亚洲一二三精品| 亚洲成人激情图| 巨大黑人极品videos精品| 日本a视频在线观看| 中文字幕av一区二区三区| 国产成人手机在线| 国产欧美精品在线播放| 性伦欧美刺激片在线观看| 美女福利视频在线观看| 中日韩午夜理伦电影免费 |