亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

ASM2.0字節碼框架介紹

2019-11-18 11:48:23
字體:
來源:轉載
供稿:網友

  框架結構

  ASM字節碼處理框架是用java開發的而且使用基于訪問者模式生成字節碼及驅動類到字節碼的轉換。這答應開發人員避免直接處理方法字節碼中的類常量池及偏移,因此為開發人員隱藏了字節碼的復雜性并且相對于其他類似工具如BCEL, SERP, or Javassist提供了更好的性能。
ASM分為幾個包更方便靈活地構建。包結構圖如圖1。

ASM2.0字節碼框架介紹(圖一)


  Figure 1. Arrangement of ASM packages

  ·Core包提供了讀/寫/轉換字節碼的API而且是其他包的基礎。這個包已經足夠生成Java字節碼而且能夠實現大部分的字節碼轉換。
  ·Tree包提供了Java字節碼的內存內表示。
  ·Analysis包為存儲在來自Tree包結構中的Java方法字節碼提供了基礎的數據流分析和類型檢查算法。
  ·Commons包(ASM2.0增加)提供了幾個通用的字節碼轉換和簡化字節碼生成的適配器。
  ·Util包包含幾個助手類和簡單的字節碼較驗器來方便開發和測試。
  ·xml包提供了與XML文件相互轉換的字節碼結構適配器,及兼容SAX而且答應使用XSLT來定義字節碼轉換方式的適配器。

  后面幾節會給出ASM框架中Core包的介紹。為了更好地理解這個包的組織結構,你最好有一些在JVM規范中定義的字節碼結構的基礎了解。下面是較高級別的類文件格式圖([*]標識重復的結構)
    
  [1]-------------------------------------------+
   Header and Constant Stack                  
   +--------------------------------------------+
   [*] Class Attributes                      
  [2]------------+------------------------------+
   [*] Fields   Field Name, Descriptor, etc  
                +------------------------------+
                [*] Field Attributes          
  [3]------------+------------------------------+
   [*] Methods Method Name, Descriptor, etc
                +------------------------------
                Method max stack and locals  
                ------------------------------
                [*] Method Code table        
                ------------------------------
                [*] Method Exception table  
                ------------------------------
                [*] Method Code Attributes  
                +------------------------------
                [*] Method Attributes        
   +-------------+------------------------------+

  需要注重的一些地方:

  ·所有使用在類結構中的描述符,字符串和其他常量都存儲在類文件開始的常量堆棧中,來自其他結構的引用是基于堆棧的序號。

  ·每一個類必須包含頭部(包括類名,父類,接口等)和常量堆棧。而其他元素如字段列表/方法列表/屬性列表都是可選的。

  ·每一個方法段包含相同的頭信息和最大最小局部變量數的信息,這些是用來校驗字節碼的。對非抽象和非原生方法,還包含一個方法指令表,一個異常表及代碼屬性。此外,還可能有其他的方法屬性。

  ·類的每一個屬性,成員/方法/方法代碼都有自己的名字,具體細節可參考JVM規范的類文件格式部分。這些屬性代表字節碼的各種信息,如源文件名/內部類/標識(用來存儲泛型)/行號/局部變量表和注解。JVM規范也答應定義自定義的屬性來包含更多的信息但標準實現的VM不會識別。注:Java5注解實際上已經廢棄了那些自定義屬性,因為注解在主義上答應你表達更多的東西。

  ·方法代碼表包含JVM的指令列表。一些指令(就像異常/行號/局部變量表)使用代碼表中的偏移值并且所有這些偏移的值可能需要在指令從方法代碼表中增刪時相應調整。

  如你所見,字節碼轉換并不輕易。但是,ASM框架減少了潛在的結構復雜性并且提供簡化的API答應所有字節碼信息的訪問和復雜的轉換。

  基于事件的字節碼處理

  Core包使用推方案(類似訪問者模式,在SAX API就使用了這種模式處理XML)來遍歷復雜的字節碼結構。ASM定義了幾個接口,如ClassVisitor,FieldVisitor,MethodVisitor和AnnotationVisitor。AnnotationVisitor是一個非凡的接口答應你表達層次的注解結構。下面的幾幅圖顯示這些接口是如何相互交互及配合使用實現字節碼轉換和從字節碼獲取信息。

  Core包邏輯上可憐分為兩大部分:

  1、字節碼生產者,如ClassReader或者按正確順序調用了上面的訪問者類的方法的自定義類。
  2、字節碼消費者,如輸出器(ClassWriter, FieldWriter, MethodWriter, and AnnotationWriter),適配器(ClassAdapter and MethodAdapter)或者其他實現了訪問者接口的類。

  圖2給出了通用生產者/消費者交互過程的時序圖。

ASM2.0字節碼框架介紹(圖二)


  Figure 2. Sequence diagram for PRodUCer-consumer interaction

  在這個交互過程中,客戶端應用首先創建了ClassReader并調用accept()方法(以ClassVisitor實例作為參數)。然后ClassReader解析類并對每一個字節碼斷發送“visit”事務給ClassVisitor。對循環的上下文,如成員/方法/注解,ClassVisitor可以創建繼續撲克相應接口(FieldVisitor, MethodVisitor, or AnnotationVisitor)的子訪問者并返回給生產者。假如生產者接收到一個空值,他簡單地忽略類的那部分(如在由訪問者驅動的“延遲加載”特性時就不需要解析相應的字節碼部分);否則相應的子上下文事件就傳遞給子訪問者實例。當子上下文結束時,生產者調用visitEnd()方法然后移到下一部分。

  字節碼消費者可以通過手工傳遞事件給下一個鏈中的訪問者或者使用來自傳遞所有訪問方法給內部的訪問者的ClassAdapter/ MethodAdapter的訪問者通過“響應鏈”模式連接起來。這些代理者一方面字節碼的消費者方面另一方面也作為字節碼的生產者。他們在實現特定的字節碼轉換時可以修改原始的代理方式:
  1、訪問調用代理可以在刪除類成員/方法/方法指令時被忽略。
  2、訪問調用參數可以在重命名類/方法/類型時被修改。
  3、新訪問調用可以在引入新成員/方法/注入新代碼到現存代碼時被增加。

  ClassWriter訪問者可以終結整個處理鏈,他也是最終字節碼的生成者。例如:

  ClassWriter cw = new ClassWriter(computeMax);
  ClassVisitor cc = new CheckClassAdapter(cw);
  ClassVisitor tv =
    new TraceClassVisitor(cc, new PrintWriter(System.out));
  ClassVisitor cv = new TransformingClassAdapter(tv);
  ClassReader cr = new ClassReader(bytecode);
  cr.accept(cv, skipDebug);
  byte[] newBytecode = cw.toByteArray();


  在上面的代碼中,實現了自定義的類轉換并且將結果人作為參數傳給TraceClassVisitor的構造函數。TraceClassVisitor打印轉換的類并傳遞給CheckClassAdapter(這是用來作簡單的字節校驗后傳遞給ClassWriter)。

  大部分的訪問方法接收簡單的參數如int,boolean和String。在所有的方法中String參數是字節碼中常量的引用,ASM使用與JVM一致的方式。例如,所有類名都應該定義在內部格式中。成員和方法描述符應該跟JVM表示一致。泛型信息的表示也類似。這種方式避免了在沒有轉換時不必要的計算。為了便于構建和解析這樣的描述,系統提供了包含一些靜態方法的Type類:
  ·String getMethodDescriptor(Type returnType, Type[] argumentTypes)
  ·String getInternalName(Class c)
  ·String getDescriptor(Class c)
  ·String getMethodDescriptor(Method m)
  ·Type getType(String typeDescriptor)
  ·Type getType(Class c)
  ·Type getReturnType(String methodDescriptor)
  ·Type getReturnType(Method m)
  ·Type[] getArgumentTypes(String methodDescriptor)
  ·Type[] getArgumentTypes(Method m)

  注重這些描述符使用了“簡單”表示,這意味著不包含泛型信息。泛型信息實際上作為一個單獨的字節屬性存儲,但ASM專門對待這個屬性并且在相應訪問方法中傳遞泛型標識串作為參數。這個標識串的值也是參照JVM規范,與Java代碼中的泛型定義唯一映射,并且為工具增加獲取額外細節的機會。ASM提供了與其他訪問者類似的SignatureVisitor, SignatureReader, and SignatureWriter類,如圖3所示。

ASM2.0字節碼框架介紹(圖三)


  Figure 3. Sequence diagram for Signature classes

  Util包中包含了TraceSignatureVisitor,已經實現了SignatureVisitor而且可以將一個標識值轉換成Java的泛型定義。下面的例子將一個方法標識轉換為Java方法定義。
  TraceSignatureVisitor v = 
      new TraceSignatureVisitor(access);
  SignatureReader r = new SignatureReader(sign);
  r.accept(v);
  String genericDecl = v.getDeclaration();
  String genericReturn = v.getReturnType();
  String genericExceptions = v.getExceptions();

  String methodDecl = genericReturn + " " +
    methodName + genericDecl;
  if(genericExceptions!=null) {
    methodDecl += " throws " + genericExceptions;
  }


  到目前為止,我們已經討論了ASM框架的基本設計方式及類結構處理。但最有趣的部分是ASM如何處理方法代碼。

  訪問方法代碼

  在ASM中,方法定義是由ClassVisitor.visitMethod()來表示,剩下的方法字節碼則由MethodVisitor中的許多訪問方法來表示。這些方法按照下面的順序來調用,“*”表示重復的方法而“?”表示方法只能被調用一次。此外,visit...Insn 和visitLabel方法必須按照訪問代碼的字節碼指令順序調用,而visitTryCatchBlock, visitLocalVariable和visitLineNumber方法必須在標簽作為參數傳遞被訪問后才能調用。

ASM2.0字節碼框架介紹(圖四)



  注重visitEnd方法必須在方法處理完成后被調用。雖然ClassReader已經做了這一步,但在使用自定義字節碼生產者時要注重一點。還要注重假如一個方法包含字節碼(也就是說方法是非抽象或非源生的),那么visitCode必須在第一個visit...Insn調用前被調用,而visitMaxs必須在最后一個visit...Insn調用后被調用。

  每一個visitIincInsn, visitLdcInsn, visitMultiANewArrayInsn, visitLookupSwitchInsn, and visitTableSwitchInsn方法唯一對應一個字節碼指令。剩下的visit...Insn方法對應多個字節碼指令,他們的操作碼作為第一個方法參數被傳入。所有這些操作碼常量被定義在Opcodes接口中。這種方式對字節碼的解析和格式化非常有效率。不幸的是,這給開發人員生成非法代碼的可能,因為ClassWriter不會校驗這些限制。但是,還是有一個CheckClassAdapter可以被用來在開發期間測試生成的代碼。

  另一個機會是對所有字節碼生成或轉換可以修改方法代碼的偏移并且在方法代碼中增刪額外的指令時應該自動調整。這對所有的跳轉偽指令的參數都兼容的,就如try-catch塊,行號和局部變量定義及一些非凡屬性一樣。但是,ASM為開發人員隱藏了這些復雜性。為了定義方法字節碼中的位置且不需要使用絕對偏移值,需要傳遞一個唯一的標簽類的實例給visitLabel方法。其他MethodVisitor方法如visitJumpInsn, visitLookupSwitchInsn, visitTableSwitchInsn, visitTryCatchBlock, visitLocalVariable, and visitLineNumber可以使用這些標簽實例在visitLabel調用之前,就像實例后在方法后被調用。

  上面的內容看起來很復雜,似乎需要很深奧的字節碼指令知識。但是在編譯的類上使用ASMifierClassVisitor就可以讓你知道如何用ASM生成給定的字節碼。此外,在兩個編譯的類上(一個原始的和另一個應用特定的轉換)使用然后進行比較就可以給出什么樣的ASM調用應該被使用在轉換器上。這個過程在幾篇文章中已經具體解釋了(可以參看最后的資源部分)。目前已經有了Eclipse使用的插件了,如圖4,提供了從Java源生成ASM代碼及比較ASMifier輸出的良好支持,還包含了上下文字節碼的參考。

ASM2.0字節碼框架介紹(圖五)

點擊查看大圖


  Figure 4. Eclipse ASM plugin (Click on the picture to see a full-size image)

  用ASM的訪問者來跟蹤類的依靠

  已經有一些文章介紹了如何用ASM生成字節碼?,F在,我們來看一下如何用ASM分析已有的類。我們來做一個有趣的應用來獲取給定的.jar文件中使用的外部類和包。簡單起見,這個例子僅獲取外部的依靠而不會取依靠的類型(如父類/方法參數/局部變量類型等)。僅為分析,我們不會創建那些注解/成員/方法的子訪問者實例。所有使用的訪問者(包括類和標識訪問者)都在一個類中實現:
public class DependencyVisitor implements 
    AnnotationVisitor, SignatureVisitor,
    ClassVisitor, FieldVisitor, MethodVisitor {
...


  在這個例子中,我們會跟蹤包之間的依靠,因此私有類必須包含包名:
  private String getGroupKey(String name) {
    int n = name.lastIndexOf('/');
    if(n>-1) name = name.substring(0, n);
    packages.add(name);
    return name;
  }
  為了獲取依靠關系,訪問者接口如ClassVisitor, AnnotationVisitor, FieldVisitor, and MethodVisitor應該選擇性地集成方法的參數。幾個常見的樣例如下:
  private void addName(String name) {
    if(name==null) return;
    String p = getGroupKey(name);
    if(current.containsKey(p)) {
      current.put(p, current.get(p)+1);
    } else {
      current.put(p, 1);
    }
  }


  在這個例子中,current是依靠的當前包。另一個例子是類型描述符(注解/枚舉/成員類型/newarray指令的參數等);如Ljava/lang/String;, J, and [[[I。這些可以用Type.getType( desc)來獲取內部格式的類名:
  private void addDesc(String desc) {
    addType(Type.getType(desc));
  }

  private void addType(Type t) {
    switch(t.getSort()) {
      case Type.ARRAY:
        addType(t.getElementType());
        break;
      case Type.OBJECT:
        addName(t.getClassName().replace('.','/'));
        break;
    }
  }


  在方法定義中的方法描述法及激活指令中的描述參數類型及返回類型。可以通過Type.getReturnType(methodDescriptor) 和Type.getArgumentTypes(methodDescriptor)來解析并取得參數和返回類型。
  private void addMethodDesc(String desc) {
    addType(Type.getReturnType(desc));
    Type[] types = Type.getArgumentTypes(desc);
    for(int i = 0; i < types.length; i++) {
      addType(types[ i]);
    }
  }


  而使用在許多“訪問”方法中的用來定義Java5泛型信息的標識參數是個特例。假如存在,這個參數重寫描述符參數并包含編碼后的泛型信息??梢员挥肧ignatureReader來解析這個值。所以我們可以實現SignatureVisitor來被每一個標識工件來調用。
  private void addSignature(String sign) {
    if(sign!=null) {
      new SignatureReader(sign).accept(this);
    }
  }
  
  private void addTypeSignature(String sign) {
    if(sign!=null) {
      new SignatureReader(sign).acceptType(this);
    }
  }


  實現ClassVisitor接口的方法,如such as visit(), visitField(), visitMethod(), and visitAnnotation()就可以獲取在父類/接口/成員類型/方法參數/返回值/異常上的依靠信息,就如注解一樣。例如:
  public void visit(int version, int access, 
      String name, String signature,
      String superName, String[] interfaces) {
    String p = getGroupKey(name);
    current = groups.get(p);
    if(current==null) {
      current = new HashMap();
      groups.put(p, current);
    }
    
    if(signature==null) {
      addName(superName);
      addNames(interfaces);
    } else {
      addSignature(signature);
    }
  }

  public FieldVisitor visitField(int access,
      String name, String desc,
      String signature, Object value) {
    if(signature==null) {
      addDesc(desc);
    } else {
      addTypeSignature(signature);
    }
    if(value instanceof Type) {
      addType((Type) value);
    }
    return this;
  }
  
  public MethodVisitor visitMethod(int access,
      String name, String desc,
      String signature, String[] exceptions) {
    if(signature==null) {
      addMethodDesc(desc);
    } else {
      addSignature(signature);
    }
    addNames(exceptions);
    return this;
  }
  
  public AnnotationVisitor visitAnnotation(
      String desc, boolean visible) {
    addDesc(desc);
    return this;
  }


  實現MethodVisitor接口的方法就可以獲取關于參數注解類型和使用在可以使用對象引用的字節碼指令上的依靠:
  public AnnotationVisitor 
      visitParameterAnnotation(int parameter,
          String desc, boolean visible) {
    addDesc(desc);
    return this;
  }

  /**
   * Visits a type instruction
   * NEW, ANEWARRAY, CHECKCAST or INSTANCEOF.
   */
  public void visitTypeInsn(int opcode,
        String desc) {
    if(desc.charAt(0)=='[') {
      addDesc(desc);
    } else {
      addName(desc);
    }
  }

  /**
   * Visits a field instruction
   * GETSTATIC, PUTSTATIC, GETFIELD or PUTFIELD.
   */
  public void visitFieldInsn(int opcode,
        String owner, String name, String desc) {
    addName(owner);
    addDesc(desc);
  }

  /**
   * Visits a method instruction INVOKEVIRTUAL,
   * INVOKESPECIAL, INVOKESTATIC or
   * INVOKEINTERFACE.
   */
  public void visitMethodInsn(int opcode,
        String owner, String name, String desc) {
    addName(owner);
    addMethodDesc(desc);
  }

  /**
   * Visits a LDC instruction.
   */
  public void visitLdcInsn(Object cst) {
    if(cst instanceof Type) {
      addType((Type) cst);
    }
  }

  /**
   * Visits a MULTIANEWARRAY instruction.
   */
  public void visitMultiANewArrayInsn(
        String desc, int dims) {
    addDesc(desc);
  }

  /**
   * Visits a try catch block.
   */
  public void visitTryCatchBlock(Label start,
        Label end, Label handler, String type) {
    addName(type);
  }


  現在我們可以用DependencyVisitor來獲取整個.jar文件的依靠關系了。例如:
  DependencyVisitor v = new DependencyVisitor();
  ZipFile f = new ZipFile(jarName);
  Enumeration en = f.entries();
  while(en.hasMoreElements()) {
    ZipEntry e = en.nextElement();
    String name = e.getName();
    if(name.endsWith(".class")) {
      ClassReader cr =
          new ClassReader(f.getInputStream(e));
      cr.accept(v, false);
    }
  }


  可以用很多不同的方式來表示得到的信息。一種方式是構建依靠樹并計算相關數據或者創建可視化的東西。例如,圖5顯示了ant1.6.5 jar包中的依靠關系的可視化表現,這是我使用一些簡單的Java2D代碼寫的。下面的圖在水平軸上顯示包,在垂直軸上顯示依靠。陰影部分表示包被多次引用。

ASM2.0字節碼框架介紹(圖六)


  Figure 5. Dependencies in ant.1.6.5.jar, as discovered with ASM

  這個工具的全部代碼會被包含在下一個ASM發布中。你可以從ASM CVS獲取。

  ASM1.x后的改變

  假如你沒有使用ASM1.x可以略過這個段。2.0中主要的結構變化是所有J2SE5.0的特性都被內建到訪問者/過濾器的事件流中。因此新的API答應你用更輕便和自然的方式來處理泛型和注解。不需要顯式創建注解屬性實例,因為在事件流中已經包含了泛型和注解數據。例如,在1.x,ClassVisitor接口如下使用:
  CodeVisitor visitMethod(int access, String name, 
      String desc, String[] exceptions,
      Attribute attrs);
This has been split into several methods in ASM 2.0:
  在2.0中已經分為多個方法:
  MethodVisitor visitMethod(int access,
      String name, String desc, String signature,
      String[] exceptions)

  AnnotationVisitor visitAnnotation(String desc,
      boolean visible)

  void visitAttribute(Attribute attr)



發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
日韩有码片在线观看| 国产成人精品综合| 理论片在线不卡免费观看| 在线视频欧美日韩| 久久精品国产免费观看| 成年无码av片在线| 欧美日韩一区二区免费视频| 精品久久香蕉国产线看观看gif| 亚洲第一页自拍| 国产精品专区一| 97久久精品人搡人人玩| 最近中文字幕日韩精品| 中文字幕无线精品亚洲乱码一区| 91av在线不卡| 亚洲欧洲自拍偷拍| 自拍偷拍亚洲一区| 91视频-88av| 在线观看日韩欧美| 国产成人短视频| 91牛牛免费视频| 国产精品久久久久久久美男| 亚洲最新中文字幕| 欧美成人在线网站| 蜜臀久久99精品久久久无需会员| 亚洲高清福利视频| 日韩视频第一页| 91老司机精品视频| 日韩**中文字幕毛片| 色噜噜狠狠狠综合曰曰曰88av| 日韩欧美成人网| 久久久午夜视频| 亚洲自拍偷拍第一页| 九九热最新视频//这里只有精品| 亚洲视频精品在线| 另类专区欧美制服同性| 欧美性猛交xxxx偷拍洗澡| 国产精品视频久久| 亚洲国产精品国自产拍av秋霞| 亚洲福利在线播放| 成人免费高清完整版在线观看| 欧美网站在线观看| 91啪国产在线| 精品无人区太爽高潮在线播放| 97久久精品视频| 亚洲天堂第一页| 国产精品男人的天堂| 国产欧美一区二区三区久久| 亚洲人在线视频| 在线观看精品自拍私拍| 岛国精品视频在线播放| 欧美午夜久久久| 福利视频一区二区| 日韩av电影在线网| 国语自产精品视频在线看抢先版图片| 亚洲片在线观看| 欧美午夜视频一区二区| 日韩欧美亚洲国产一区| 亚洲精品狠狠操| 91精品在线观看视频| 欧美孕妇性xx| 懂色av影视一区二区三区| 亚洲在线视频福利| 亚洲欧美综合精品久久成人| 精品亚洲aⅴ在线观看| 97久久精品人搡人人玩| 欧美精品在线免费观看| 成人黄色av播放免费| 国产国语刺激对白av不卡| 欧美性猛交视频| 91国内精品久久| 国产美女久久久| 欧美激情综合色| 91美女高潮出水| 成人免费看吃奶视频网站| 国产精品一区二区电影| 亚洲欧美在线播放| 亚洲网站视频福利| 欧美福利视频在线观看| 午夜免费在线观看精品视频| www高清在线视频日韩欧美| 欧美精品国产精品日韩精品| 亚洲第一页中文字幕| 欧美日韩成人在线播放| 久久综合88中文色鬼| 欧美日韩高清区| 亚洲iv一区二区三区| 国产欧美婷婷中文| 亚洲国产精品久久久久秋霞不卡| 亚洲香蕉成视频在线观看| 欧美高清理论片| 久久成人av网站| 岛国av一区二区在线在线观看| 日本一区二区在线播放| 精品亚洲夜色av98在线观看| 国产精品免费视频xxxx| 欧美电影免费播放| 国产美女久久久| 国产精品稀缺呦系列在线| 亚洲最大的免费| 欧美性猛交xxxx偷拍洗澡| 亚洲欧洲自拍偷拍| 亚洲欧洲偷拍精品| 黑人精品xxx一区| 欧美黄色www| 91av视频在线播放| 日韩av免费在线| 国产不卡视频在线| 国产精品吹潮在线观看| 国产精品99久久99久久久二8| 亚洲精品日韩欧美| 亚洲午夜精品视频| 国产在线日韩在线| 欧美性videos高清精品| 欧美片一区二区三区| 国产91在线高潮白浆在线观看| 九九热r在线视频精品| 日韩欧美成人网| 久久夜精品va视频免费观看| 日韩国产欧美精品一区二区三区| 精品亚洲精品福利线在观看| 欧美日韩一区二区三区在线免费观看| 国产精品高清在线观看| 久久大大胆人体| 蜜臀久久99精品久久久无需会员| 中文字幕v亚洲ⅴv天堂| 亚洲美女视频网| 国产激情综合五月久久| 国产精品影片在线观看| 国产精品视频午夜| 欧美一性一乱一交一视频| 中文字幕欧美精品在线| 日韩成人av网址| 最新日韩中文字幕| 热99在线视频| 国产综合福利在线| 91精品免费久久久久久久久| 国产精品成人久久久久| 国产亚洲xxx| 久久99精品视频一区97| 一区二区三区回区在观看免费视频| 欧美日韩精品在线观看| 91精品综合久久久久久五月天| 欧美日韩国产91| 亚洲一区亚洲二区| 亚洲国语精品自产拍在线观看| 亚洲国产精品成人va在线观看| 国产欧美一区二区三区在线看| 国产99视频在线观看| 亚洲片av在线| 久久成人精品一区二区三区| 久久久久久久999精品视频| 欧洲成人在线视频| 欧美一区二区视频97| 国外日韩电影在线观看| 国产精品免费视频久久久| 午夜欧美大片免费观看| 国产成人精品在线视频| 97在线视频国产| 欧美激情亚洲视频| 欧美孕妇毛茸茸xxxx| 国产成人涩涩涩视频在线观看| 久久人人爽人人爽人人片亚洲| 日韩视频免费在线观看| 国产精品综合网站|