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

解讀SourceMap

開發 前端
針對不同類型的ast節點根據節點的含義執行word/space/token/newline等方法生成代碼,這些方法里都會執行append方法添加要生成的字符串代碼。

SourceMap的用途

前端工程打包后代碼會與源碼產生不一致,當代碼運行出錯時控制臺會定位出錯代碼的位置。SourceMap的用途是可以將轉換后的代碼映射回源碼,如果你部署了js文件對應的map文件資源,那么在控制臺里調試時可以直接定位到源碼的位置。

SourceMap的格式

我們可以生成一個SouceMap文件看看里面的字段分別都對應什么意思,這里使用webpack打包舉例。

源碼:

//src/index.js
function a() {
for (let i = 0; i < 3; i++) {
console.log('s');
}
}
a();

打包后的代碼:

//dist/main-145900df.js
!function(){for(let o=0;o<3;o++)console.log("s")}();
//# sourceMappingURL=main-145900df.js.map

.map文件:

//dist/main-145900df.js.map
{
"version": 3,
"file": "main-145900df.js",
"mappings": "CAAA,WACE,IAAK,IAAIA,
EAAI,EAAGA,EAAI,EAAGA,IACrBC,QAAQC,IAAI,KAGhBC",
"sources": ["webpack://source-map-webpack-demo/./src/index.js"],
"sourcesContent": ["function a() {\n for (let i = 0; i < 3; i++) {\n console.log('s');\n }\n}\na();"],
"names": ["i", "console", "log", "a"],
"sourceRoot": ""
}
  • version:目前source map標準的版本為3;
  • file:生成的文件名;
  • mappings:記錄位置信息的字符串;
  • sources:源文件地址列表;
  • sourcesContent:源文件的內容,一個可選的源文件內容列表;
  • names:轉換前的所有變量名和屬性名;
  • sourceRoot:源文件目錄地址,可以用于重新定位服務器上的源文件。

這些字段里大部分都很好理解,接下來主要解讀mappings這個字段是通過什么規則來記錄位置信息的。

?mappings字段的定義規則?

"mappings": "CAAA,WACE,IAAK,IAAIA,
EAAI,EAAGA,EAAI,EAAGA,IACrBC,QAAQC,IAAI,KAGhBC",

為了盡可能減少存儲空間但同時要達到記錄原始位置和目標位置映射關系的目的,mappings字段按照了一些特殊的規則來生成。

  1. 生成文件中的一行作為一組,用“;”隔開。
  2. 連續的字母共同表示一個位置信息,用逗號分隔每個位置信息。
  3. 一個位置信息由1、4或5個可變長度的字段組成。
  1. // generatedColumn, [sourceIndex, originalLine, orignalColumn, [nameIndex]]
  2. 第一位,表示這個位置在轉換后的代碼第幾列,使用的是相對于上一個的相對位置,除非這是這個字段的第一次出現。
  3. 第二位(可選),表示所在的文件是屬于sources屬性中的第幾個文件,這個字段使用的是相對位置。
  4. 第三位(可選),表示對應轉換前代碼的第幾行,這個字段使用的是相對位置。
  5. 第四位(可選),表示對應轉換前代碼的第幾列,這個字段使用的是相對位置。
  6. 第五位(可選),表示屬于names屬性中的第幾個變量,這個字段使用的是相對位置。
  1. 字段的生成原理是將數值通過vlq-base64編碼轉換成字母。

?vlq原理?

vlq是Variable-length quantity的縮寫,是一種通用的,使用任意位數的二進制來表示一個任意大的數字的一種編碼方式。

SourceMap中的編碼流程是將位置從十進制數值—>二進制數值—>vlq編碼—>base64編碼最終生成字母。

//   Continuation
// | Sign
// | |
// V V
// 101011

vlq編碼的規則:

  • 一個數值可能由多個字符組成
  • 對于每個字符使用6個2進制位表示

如果是表示數值的第一個字符中的最后一個位置,則為符號位。

否則用于實際有效值的一位。

0為正,1為負(SourceMap的符號固定為0),

第一個位置是連續位,如果是1,代表下一個字符也屬于同一個數值;如果是0,表示這個字符是表示這個數值的最后一個字符。

最后一個位置

  • 至少含有4個有效值,所以數值范圍為(1111到-1111)即-15到15的可以由一個字符表示。

數值的第一個字符有4個有效值

之后的字符有5個有效值

最后將6個2進制位轉換成base64編碼的字母,如圖。

圖片

舉例編碼數值29

數值29(十進制)=11101(二進制)

1|1101

先取低四位,數值的第一個字符有四個有效值1101

11010-----------最后加上符號位

111010----------開頭加上連續位1(后面還有字符表示同一個數值)

6---------------轉換為base64編碼對應是6

數值的第二個字符

00001----------補充有效位

000001--------開頭加上連續位0(表示是數值的最后一個字符)

B---------------轉換為base64編碼

29=》6B

我們將上述轉換的規則通過代碼方式呈現:

代碼實現vlq編碼

先在最后添加一個符號位,從低位開始截取5位作為一個字符,截取完若還有數值則在截取的5位前添加連續位1,即生成好一個字符;最后一個字符的數值直接與011111進行與運算即可。

//https://github.com/mozilla/source-map/blob/HEAD/lib/base64-vlq.js
const base64 = require("./base64");

//移動位數
const VLQ_BASE_SHIFT = 5;

// binary: 100000
const VLQ_BASE = 1 << VLQ_BASE_SHIFT;
//1左移5位:100000=32

// binary: 011111
const VLQ_BASE_MASK = VLQ_BASE - 1;

// binary: 100000
const VLQ_CONTINUATION_BIT = VLQ_BASE;

//符號位在最低位
//1.1左移一位并在最后加一個符號位
function toVLQSigned(aValue) {
return aValue < 0 ? (-aValue << 1) + 1 : (aValue << 1) + 0;
}

/**
* Returns the base 64 VLQ encoded value.
*/
function base64VLQ_encode(aValue) {
let encoded = "";
let digit;

let vlq = toVLQSigned(aValue);//第一步:左移一位,最后添加符號位

do {
digit = vlq & VLQ_BASE_MASK;
//第二步:vlq和011111進行與運算,獲取字符中已經生成好的后5位
//從低位的5位開始作為第一個字符
vlq >>>= VLQ_BASE_SHIFT;//vlq=vlq>>>5
//第三步:vlq右移5位用于截取低位的5位,對剩下的數值繼續進行操作
if (vlq > 0) {
//說明后面還有數值,則要在現在這個字符開頭加上連續位1
digit |= VLQ_CONTINUATION_BIT;//digit=digit|100000,與100000進行或運算
}
encoded = encoded+base64.encode(digit);//第四步:生成的vlq字符進行base64編碼并拼接
} while (vlq > 0);

return encoded;
};
exports.encode = base64VLQ_encode;

舉例解碼字符6B

6B

第一個字符

6=>111010--------base64解碼并轉換為二進制

111010------------符號位

110110------------連續位(表示后面有字符表示同一個數值)

第一個字符有效值value=1101

第二個字符

B=>000001------base64解碼并轉換為二進制

000001----------有效值

000001----------連續位(表示后面沒有字符表示同一個數值)

第二個字符的有效值value=00001

合并value=000011101轉為十進制29

代碼實現vlq解碼

從左到右開始遍歷字符,對每個字符都先去除連續位剩下后5位數值,將每個字符的5位數值從低到高拼接,最后去除處在最低一位的符號位。

//https://github.com/Rich-Harris/vlq/blob/HEAD/src/index.js
/** @param {string} string */
export function decode(string) {
/** @type {number[]} */
let result = [];

let shift = 0;
let value = 0;

for (let i = 0; i < string.length; i += 1) {//從左到右遍歷字母
let integer = char_to_integer[string[i]];//1.base64解碼

if (integer === undefined) {
throw new Error('Invalid character (' + string[i] + ')');
}

const has_continuation_bit = integer & 100000;//2.獲取連續位標識

integer =integer & 11111;//3.移除符號位獲取后5位

value = value + (integer << shift);
//4.從低到高拼接有效值

if (has_continuation_bit) {
//5.有連續位
shift += 5;//移動位數
} else {
//6.沒有連續位,處理獲取到的有效值value
const should_negate = value & 1;//獲取符號位

value =value >>>1;//7.右移一位去除符號位,獲取最終有效值

if (should_negate) {
result.push(value === 0 ? -0x80000000 : -value);
} else {
result.push(value);
}

// reset
value = shift = 0;
}
}

return result;
}

整個轉換流程舉例

源碼:

//src/index.js

function a() {
for (let i = 0; i < 3; i++) {
console.log('s');
}
}
a();

打包后的代碼:

//dist/main-145900df.js

!function(){for(let o=0;o<3;o++)console.log("s")}();
//# sourceMappingURL=main-145900df.js.map

.map文件:

//dist/main-145900df.js.map
{
"version": 3,
"file": "main-145900df.js",
"mappings": "CAAA,WACE,IAAK,IAAIA,
EAAI,EAAGA,EAAI,EAAGA,IACrBC,QAAQC,IAAI,KAGhBC",
"sources": ["webpack://source-map-webpack-demo/./src/index.js"],
"sourcesContent": ["function a() {\n for (let i = 0; i < 3; i++) {\n console.log('s');\n }\n}\na();"],
"names": ["i", "console", "log", "a"],
"sourceRoot": ""
}

CAAA

[1,0,0,0]

轉換后的代碼的第1列

sources屬性中的第0個文件

轉換前代碼的第0行。

轉換前代碼的第0列。

對應function

WACE

[11,0,1,2]

轉換后的代碼的第12(11+1)列

sources屬性中的第0個文件

轉換前代碼的第1行。

轉換前代碼的第2列。

對應for

IAAK

[4,0,0,5]

轉換后的代碼的第16(12+4)列

sources屬性中的第0個文件

轉換前代碼的第1行。

轉換前代碼的第7(2+5)列。

對應let

SourceMap使用的規則是如何優化存儲位置信息空間的?

SourceMap規范進行了版本迭代,最初,規范對所有映射都有非常詳細的輸出,導致SourceMap大約是生成代碼的10倍。第二個版本減少了50% 左右,第三個版本又減少了50% 。

因為如果生成的位置信息內容比源碼還多未免有些得不償失,所以這樣的規則是在盡可能的減小存儲空間。

我們可以來總結一下這個規則里使用到的優化點:

  1. 使用相對位置,使位置數值盡可能小,在后續計算中獲取真實的位置數值,從而減少存儲空間;
  2. 使用vlq-base64編碼減少存儲空間,如32000=》ggxT,通過計算減少存儲空間;
  3. 行數信息直接用;分割來表示。

解析babel生成SourceMap的實現方式

我們日常的各種轉譯/打包工具是如何生成SourceMap的,這里來解析一下babel生成SourceMap的實現方式。

我們大概需要以下三個步驟來生成SourceMap:

  1. 獲取源碼的行列信息
  2. 獲取生成代碼的行列信息
  3. 將前后一一對應起來,然后進行vlq-base64編碼并按照規則生成sourcemap文件。

babel流程

babel主要執行了三個流程:解析(parse),轉換(transform),生成(generate)。

parse解析階段(獲得源碼對應的ast)=》transform(plugin插件執行轉換ast)=》generate通過ast生成代碼

parse和transform階段

在解析和轉換的階段,源碼對應的ast經過一些plugin的執行后節點的類型或者值會發生改變,但節點中有一個loc屬性(類型為SourceLocation)會一直記錄著源碼最開始的行列位置,所以獲取到源碼的ast就能夠得到源碼中的行列信息。

generate階段生成SourceMap

generator階段通過ast生成轉譯后的代碼,在這個階段會對ast樹進行遍歷。

針對不同類型的ast節點根據節點的含義執行word/space/token/newline等方法生成代碼,這些方法里都會執行append方法添加要生成的字符串代碼。

在此之中有一個記錄生成代碼的行列信息屬性會按照添加的字符串長度進行不斷的累加,從而得到轉譯前后行列信息的對應。

//packages/babel-generator/src/index.ts
export default function generate(
ast: t.Node,
opts?: GeneratorOptions,
code?: string | { [filename: string]: string },
) {
const gen = new Generator(ast, opts, code);
//1.傳遞ast新建一個Generator對象
return gen.generate();
}
class Generator extends Printer {
generate() {
return super.generate(this.ast);
}
}

//packages/babel-generator/src/printer.ts
class Printer {
generate(ast) {
this.print(ast);
//2.通過ast生成代碼
this._maybeAddAuxComment();

return this._buf.get();
}

print(node, parent?) {

if (!node) return;

const oldConcise = this.format.concise;
if (node._compact) {
this.format.concise = true;
}

const printMethod = this[node.type];
//獲取不同節點類型對應的生成方法

//....


//調用
this.withSource("start", loc, () => {
printMethod.call(this, node, parent);
});

// this._printTrailingComments(node);

// if (shouldPrintParens) this.token(")");

// end
this._printStack.pop();

this.format.concise = oldConcise;
this._insideAux = oldInAux;
}
}

例如,遍歷到一個SwitchCase類型的ast節點,會在里面調用Printer對象的word/space/print/token等方法,而這些方法內部都會調用append方法用于逐個添加要生成的字符串,并計算得到對應的行列信息。

//packages/babel-generator/src/generators/statements.ts
export function SwitchCase(this: Printer, node: t.SwitchCase) {
if (node.test) {
this.word("case");
this.space();
this.print(node.test, node);//用于遍歷,執行節點下的節點的方法
this.token(":");
} else {
this.word("default");
this.token(":");
}

if (node.consequent.length) {
this.newline();
this.printSequence(node.consequent, node, { indent: true });
}
}

Printer對象中聲明了word/space/print/token等方法,這些方法都會將字符串添加到Buffer對象中。

//packages/babel-generator/src/printer.ts
class Printer {
constructor(format: Format, map: SourceMap) {
this._buf = new Buffer(map);
}

//...

_append(str: string, queue: boolean = false) {
if (queue) this._buf.queue(str);
else this._buf.append(str);
}

word(str: string): void {
// prevent concatenating words and creating // comment out of division and regex
if (
this._endsWithWord ||
(this.endsWith(charCodes.slash) && str.charCodeAt(0) === charCodes.slash)
) {
this._space();
}

this._maybeAddAuxComment();

this._append(str);

this._endsWithWord = true;
}

token(str: string): void {
// space is mandatory to avoid outputting <!--
// http://javascript.spec.whatwg.org/#comment-syntax
const lastChar = this.getLastChar();
const strFirst = str.charCodeAt(0);
if (
(str === "--" && lastChar === charCodes.exclamationMark) ||
// Need spaces for operators of the same kind to avoid: `a+++b`
(strFirst === charCodes.plusSign && lastChar === charCodes.plusSign) ||
(strFirst === charCodes.dash && lastChar === charCodes.dash) ||
// Needs spaces to avoid changing '34' to '34.', which would still be a valid number.
(strFirst === charCodes.dot && this._endsWithInteger)
) {
this._space();
}

this._maybeAddAuxComment();
this._append(str);
}

}

Buffer對象的append方法會去計算生成代碼的行列信息,并將生成代碼的行列信息和原始代碼的行列信息傳遞給SourceMap對象,SourceMap對象將前后位置信息對應起來并進行編碼從而生成最終的SourceMap。

//packages/babel-generator/src/buffer.ts
class Buffer {
constructor(map?: SourceMap | null) {
this._map = map;
}

//用于記錄生成代碼的位置
_position = {
line: 1,
column: 0,
};


//第1步:執行內部_append方法
append(str: string): void {
this._flush();
const { line, column, filename, identifierName } = this._sourcePosition;
this._append(str, line, column, identifierName, filename);
}

//第2步:計算傳遞進來的字符串參數對應的位置
_append(
str: string,
line: number | undefined,
column: number | undefined,
identifierName: string | undefined,
filename: string | undefined,
): void {
this._buf += str;
this._last = str.charCodeAt(str.length - 1);

let i = str.indexOf("\n");//查找換行符位置
let last = 0;

if (i !== 0) {
//排除開頭是換行符的情況,其他情況執行標記
this._mark(line, column, identifierName, filename);
}

// Now, find each reamining newline char in the string.
while (i !== -1) {
//2-1.當存在換行符時,改變行數
this._position.line++;
this._position.column = 0;
last = i + 1;//換行符后一位

// We mark the start of each line, which happens directly after this newline char
// unless this is the last char.
if (last < str.length) {
this._mark(++line, 0, identifierName, filename);//改變行數,行數+1
}
i = str.indexOf("\n", last);//尋找下一個換行符
}
//2-2.改變列數,列數加上字符的長度
this._position.column += str.length - last;
}

//第3步:調用sourcemap對象的mark方法
_mark(
line: number | undefined,
column: number | undefined,
identifierName: string | undefined,
filename: string | undefined,
): void {
this._map?.mark(this._position, line, column, identifierName, filename);
}
}

export default class SourceMap {
//第4步:將前后行列信息對應起來后對位置信息進行編碼
mark(
generated: { line: number; column: number },
line: number,
column: number,
identifierName?: string | null,
filename?: string | null,
) {
this._rawMappings = undefined;

maybeAddMapping(this._map, {
name: identifierName,
generated,
source:
line == null
? undefined
: filename?.replace(/\/g, "/") || this._sourceFileName,
original:
line == null
? undefined
: {
line: line,
column: column,
},
});
}
}

相關鏈接

Introduction to JavaScript Source Maps

Source Map Revision 3 Proposal

https://github.com/babel/babel

https://github.com/Rich-Harris/vlq

https://github.com/mozilla/source-map

責任編輯:武曉燕 來源: ELab.zengjiaxin
相關推薦

2022-08-26 13:24:03

version源碼sources

2021-12-15 09:21:59

Webpack 前端Sourcemap

2023-05-31 08:19:23

Webpack4Webpack 5

2023-09-28 08:41:11

OpenAILLMLangChain

2023-05-04 08:54:08

Toolformer語言模型

2024-11-26 07:20:25

2021-06-04 07:27:24

sourcemap前端技術

2012-11-30 11:12:03

2010-08-26 22:05:39

DHCP服務

2022-10-21 13:52:56

JS 報錯調試本地源碼

2010-09-02 14:49:27

非法DHCP服務

2012-02-03 11:31:33

HibernateJava

2011-12-19 10:38:01

網絡虛擬化

2009-12-15 15:35:56

Ruby symbol

2010-05-05 22:58:46

2010-09-03 09:13:53

2010-05-10 16:20:32

負載均衡策略

2023-04-28 07:36:43

人工智能AIAPI

2017-12-07 16:27:30

Zookeeper架構設計

2009-12-16 15:03:13

LPI Linux 認
點贊
收藏

51CTO技術棧公眾號

亚洲在线观看av| 人妻激情偷乱视频一区二区三区| 日本一级在线观看| 日韩精品免费视频人成| 久久久国产一区| 国产十八熟妇av成人一区| 忘忧草在线www成人影院| 亚洲品质自拍视频| 久久久久久国产精品免费免费| 中文字幕1区2区3区| 激情综合激情| 日韩在线小视频| youjizz.com国产| 国产激情久久| 精品国产精品三级精品av网址| 日韩成人av网站| 好吊色在线观看| 激情国产一区二区| 热门国产精品亚洲第一区在线| av成人免费网站| 国产精品欧美在线观看| 精品久久久久久久一区二区蜜臀| 啊啊啊国产视频| 久久久男人天堂| 一区二区三区日韩精品| 亚洲欧美久久234| 亚洲AV无码一区二区三区性| 欧美aⅴ一区二区三区视频| 97在线视频免费观看| 国产午夜手机精彩视频| 久久美女视频| 亚洲图片欧美日产| 精品人妻无码一区二区三区| 成人中文字幕视频| 欧美一区二区三区精品| 九九热免费精品视频| 天堂电影一区| 性欧美疯狂xxxxbbbb| 国产又粗又长又爽视频| 日韩av中文| 国产精品全国免费观看高清| 欧日韩一区二区三区| 日韩专区一区二区| 99久久精品国产麻豆演员表| 国产精品免费一区二区三区四区 | 亚洲香蕉av| 中文字幕综合一区| a资源在线观看| 国产中文字幕一区二区三区| 亚洲欧洲xxxx| 老鸭窝一区二区| 欧美极品中文字幕| 亚洲人线精品午夜| 非洲一级黄色片| 精品视频日韩| 亚洲欧美tv| 日韩毛片高清在线播放| 一区二区视频在线免费| 在线观看麻豆| 最新欧美精品一区二区三区| 在线一区日本视频| av片哪里在线观看| 亚洲欧美另类在线| 日韩在线视频在线| 日本高清成人vr专区| 亚洲一区二区影院| 欧美 国产 综合| 樱桃视频成人在线观看| 欧美亚洲精品一区| 欧美成人手机在线视频| 日韩视频一二区| 欧美精品一区二区三区高清aⅴ| 一边摸一边做爽的视频17国产| 极品一区美女高清| 亚洲欧洲xxxx| 精品无码久久久久成人漫画| 国产精品分类| 国产成+人+综合+亚洲欧洲| 在线视频 91| 国产成人精品免费在线| 免费精品视频一区二区三区| h视频在线观看免费| 亚洲欧美二区三区| 欧美视频在线观看网站 | 国产精品成人免费电影| 国产精品无码在线播放| 成人精品视频一区| 日韩一区国产在线观看| 色在线视频网| 91精品1区2区| www.黄色网| 精品午夜久久| 欧美国产欧美亚洲国产日韩mv天天看完整| 你懂的国产在线| 九色综合狠狠综合久久| 国产综合欧美在线看| av男人的天堂在线| 香蕉久久一区二区不卡无毒影院| av在线无限看| 国产精东传媒成人av电影| 伊人av综合网| 国产无套内射又大又猛又粗又爽| 日本强好片久久久久久aaa| 99久久伊人精品影院| 高清日韩av电影| 亚洲国产综合色| 小泽玛利亚视频在线观看| 国产精品任我爽爆在线播放| 久久精品福利视频| 免费观看一区二区三区毛片| 国产精品综合一区二区| 日韩在线三区| 久草在线资源站手机版| 日韩欧美一卡二卡| 又色又爽的视频| 久久激情网站| 精品日本一区二区三区| 伊人影院在线视频| 欧美人牲a欧美精品| 魔女鞋交玉足榨精调教| 亚洲午夜一区| 亚洲影视九九影院在线观看| 成人不用播放器| 色综合中文字幕国产| 久草免费资源站| 亚洲国产精品日韩专区av有中文| 国产精品第一页在线| 天堂在线观看免费视频| 夜夜精品视频一区二区| 精品人妻一区二区三| 成人嫩草影院| 国产精品爱久久久久久久| 天堂在线观看免费视频| 好吊日视频在线观看| 成人黄色网址在线观看| av磁力番号网| 成人国产精品久久| 日韩一区av在线| 中文字幕免费高清在线观看| 久久久精品日韩欧美| 日本免费黄视频| 日韩高清三区| 欧美一区二区三区……| 手机看片1024日韩| 香蕉加勒比综合久久| 国产极品一区二区| 亚洲激情一区| 国产91亚洲精品一区二区三区| 色呦呦久久久| 精品国产乱码久久久久久蜜臀| 欧美日韩精品一区二区三区视频播放| 国产美女主播视频一区| 精品国产三级a∨在线| 秋霞影院一区| 欧美福利视频网站| 欧性猛交ⅹxxx乱大交| 午夜在线成人av| 9.1成人看片| 石原莉奈在线亚洲三区| 欧美一区免费视频| 视频在线日韩| 精品国产区一区二区三区在线观看| 中文字幕+乱码+中文字幕明步| 国产精品福利在线播放| 国产欧美精品一二三| 国产精品v日韩精品v欧美精品网站 | 97久久国产亚洲精品超碰热| 国产精品一线| 日本高清久久天堂| 一区二区高清不卡| 日韩视频免费观看高清完整版 | 亚洲激情av| 日本午夜精品电影| 成人在线视频区| 久久久久一本一区二区青青蜜月| 婷婷婷国产在线视频| 在线欧美日韩国产| 51精品免费网站| av高清不卡在线| 香港日本韩国三级网站| 自拍偷拍欧美| 日本一区二区免费看| 伊人国产精品| 77777少妇光屁股久久一区| 国产高清视频免费最新在线| 日韩一区二区三区免费看| 久久一区二区三区视频| 国产精品第四页| 色哟哟视频在线| 蜜臀av一级做a爰片久久| 国产91在线亚洲| 精品国产乱码久久久久久蜜坠欲下| 成人精品一区二区三区电影免费| caoporn视频在线| zzijzzij亚洲日本成熟少妇| 欧美 日韩 国产 成人 在线 91| 欧美性高清videossexo| 久久精品一区二区三| 久久精品亚洲麻豆av一区二区| 亚洲人a成www在线影院| 国产成人精品综合久久久久99 | 日韩黄色一区二区| 日韩不卡一区二区三区| 免费超爽大片黄| 国产精品99在线观看| 蜜桃狠狠色伊人亚洲综合网站| 免费观看在线一区二区三区| 国产999在线观看| 久久亚洲导航| 精品国产网站地址| 国产一级网站视频在线| 亚洲成人久久久| av网站在线观看免费| 在线观看视频一区| 中文字幕在线观看免费视频| 亚洲丝袜自拍清纯另类| 天堂在线中文视频| 91网站最新网址| av在线播放网址| 国产91色综合久久免费分享| 天天摸天天舔天天操| 日韩激情视频网站| 免费毛片小视频| 日韩图片一区| 欧美视频在线观看视频| 中出一区二区| 中文字幕一区二区三区四区五区人 | 中文字幕21页在线看| 欧美激情高清视频| v片在线观看| 日韩少妇与小伙激情| 最新97超碰在线| 在线观看欧美日韩国产| 国产中文字幕在线| 亚洲欧美成人一区二区在线电影| 少妇高潮一区二区三区69| 日韩精品一区二区三区蜜臀 | 久久99国产精品一区| 欧美3p视频| 亚洲人成人77777线观看| 精品国产网站| 欧美一区二区三区电影在线观看 | 国产一二三在线视频| 午夜精品久久久久99热蜜桃导演 | 激情小说中文字幕| 亚洲激情一二三区| 亚洲成人生活片| 亚洲激情五月婷婷| 久久在线视频精品| 亚洲成人综合视频| 日韩av无码中文字幕| 午夜av区久久| 国语对白永久免费| 成人a免费在线看| 亚洲天堂第一页| 国产免费高清av| 日韩一区二区三区在线| 国产xxxxxx| 亚洲国产精品va| 日本免费一区二区三区最新| 亚洲美女视频网站| 国产98在线| 久久精品成人欧美大片古装| 在线三级电影| 午夜精品久久久久久久99热| 爱搞国产精品| 日韩av电影中文字幕| 美女视频一区| av观看久久| 自拍偷拍一区| 一级二级三级欧美| 亚洲视频高清| 欧美少妇性生活视频| 久久99精品国产麻豆婷婷洗澡| 国产裸体视频网站| 91美女片黄在线| 日韩免费av一区| 夜夜嗨av一区二区三区中文字幕 | 日韩欧美一区在线| 凸凹人妻人人澡人人添| 有码中文亚洲精品| 欧美videosex性欧美黑吊| 热久久免费视频精品| 91麻豆精品| 久久精品国产一区二区三区不卡| 精品视频97| 成人免费播放器| 日韩成人av影视| 中文字幕人妻一区二区三区| 欧美国产成人在线| 国产一级视频在线观看| 在线视频欧美精品| 成人免费视频国产免费麻豆| 伊人激情综合网| 大黄网站在线观看| 国产视频观看一区| 亚洲免费观看高清完整版在线观| 97精品国产97久久久久久粉红| 99精品热视频只有精品10| 中文字幕22页| 久久综合久久久久88| 欧美精品入口蜜桃| 欧美视频在线一区| 色窝窝无码一区二区三区成人网站 | 91精品美女在线| 天天久久夜夜| 国产尤物av一区二区三区| 日韩一区精品字幕| 欧美xxxx×黑人性爽| 亚洲天堂网中文字| 无码一区二区三区在线观看| 亚洲精品一区二区三区蜜桃下载 | 久久久一二三区| 狠狠躁夜夜躁久久躁别揉| 26uuu久久天堂性欧美| 日韩在线一卡二卡| 色婷婷精品大在线视频| www.天堂在线| 日韩中文字幕免费看| 欧美自拍电影| 久久精品中文字幕一区二区三区 | 国产精品极品在线观看| 26uuu成人| 男女性色大片免费观看一区二区| 国产 中文 字幕 日韩 在线| 亚洲码国产岛国毛片在线| 五月激情丁香网| 国产丝袜一区二区三区| av福利在线导航| 91超碰在线电影| 99视频精品全部免费在线视频| 超碰在线97免费| 国产色综合久久| 国产精品视频一区在线观看| 亚洲激情电影中文字幕| 福利影院在线看| 国产一区二区三区色淫影院| 影音先锋一区| 久久久久久婷婷| 亚洲第一主播视频| 丰满人妻一区二区三区免费视频| 欧美乱妇40p| 亚洲精品黑牛一区二区三区| 路边理发店露脸熟妇泻火| 国产在线不卡一卡二卡三卡四卡| 日韩在线一卡二卡| 91精品一区二区三区在线观看| 日韩三级影院| 91青草视频久久| 欧美久久99| 野战少妇38p| 精品国产鲁一鲁一区二区张丽| 四虎成人免费在线| 日本久久久久亚洲中字幕| 蜜乳av综合| 久久久精品麻豆| 国产精品网友自拍| 国产又粗又大又爽| 欧美精品在线观看| 国内自拍在线观看| 喷白浆一区二区| 影音先锋男人资源在线观看| 欧美高清精品3d| 色在线视频网| 久久精品国产美女| 免费成人av资源网| 欧美做爰爽爽爽爽爽爽| 日韩欧美国产午夜精品| 999福利在线视频| 欧美精品一区二区三区久久| 奇米影视一区二区三区| 天天鲁一鲁摸一摸爽一爽| 日韩欧美区一区二| 精品极品在线| 亚洲精品一区二区三| 国产精品一区在线观看你懂的| 天海翼一区二区| 中文字幕亚洲欧美在线| 日本精品在线播放| 国产精品50p| 国产精品国模大尺度视频| 亚洲国产精品久久久久爰性色| 51精品在线观看| 婷婷亚洲五月色综合| 日本69式三人交| 欧美日韩亚洲国产综合| xxx在线免费观看| 日韩成人av网站| 成人免费电影视频| 国产精品xxxxxx| 久久99久久久久久久噜噜| 欧美美乳视频| 在线播放国产视频| 欧美影视一区在线| av伦理在线| 久久视频免费在线| 国产色综合久久| 香港三日本三级少妇66| 91久久精品国产91久久| 久久久亚洲人|