diff --git a/src/main/java/javax/persistence/Column.java b/src/main/java/javax/persistence/Column.java index 1ea7a0f58..6d508d0a6 100644 --- a/src/main/java/javax/persistence/Column.java +++ b/src/main/java/javax/persistence/Column.java @@ -1,147 +1,147 @@ -/** - * ***************************************************************************** Copyright (c) 2008 - 2013 Oracle - * Corporation. All rights reserved. - * - *
This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v. 1.0 which accompanies this distribution. The Eclipse Public License is available - * at http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - *
Contributors: Linda DeMichiel - Java Persistence 2.1 Linda DeMichiel - Java Persistence 2.0 - * - *
****************************************************************************
- */
-package javax.persistence;
-
-import static java.lang.annotation.ElementType.*;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.*;
-
-/**
- * Specifies the mapped column for a persistent property or field. If no Column annotation is specified,
- * the default values apply.
- *
- *
- *
- *
- * Example 1:
- *
- * @Column(name="DESC", nullable=false, length=512)
- * public String getDescription() { return description; }
- *
- * Example 2:
- *
- * @Column(name="DESC",
- * columnDefinition="CLOB NOT NULL",
- * table="EMP_DETAIL")
- * @Lob
- * public String getDescription() { return description; }
- *
- * Example 3:
- *
- * @Column(name="ORDER_COST", updatable=false, precision=12, scale=2)
- * public BigDecimal getCost() { return cost; }
- *
- *
- *
- *
- *
- * @since Java Persistence 1.0
- * @deprecated replace by {@link org.redkale.persistence.Column}
- * @see org.redkale.persistence.Column
- */
-@Deprecated(since = "2.8.0")
-@Target({METHOD, FIELD})
-@Retention(RUNTIME)
-public @interface Column {
-
- /**
- * (Optional) The name of the column. Defaults to the property or field name.
- *
- * @return String
- */
- String name() default "";
-
- /**
- * (Optional) The comment of the column.
- *
- * @return String
- */
- String comment() default "";
-
- /**
- * (Optional) Whether the column is a unique key. This is a shortcut for the UniqueConstraint
- * annotation at the table level and is useful for when the unique key constraint corresponds to only a single
- * column. This constraint applies in addition to any constraint entailed by primary key mapping and to constraints
- * specified at the table level.
- *
- * @return boolean
- */
- boolean unique() default false;
-
- /**
- * (Optional) Whether the database column is required.
- *
- * @return boolean
- */
- boolean nullable() default true;
-
- /**
- * for OpenAPI Specification 3
- *
- * @return String
- */
- String example() default "";
-
- /**
- * (Optional) Whether the column is included in SQL INSERT statements generated by the persistence provider.
- *
- * @return boolean
- */
- boolean insertable() default true;
-
- /**
- * (Optional) Whether the column is included in SQL UPDATE statements generated by the persistence provider.
- *
- * @return boolean
- */
- boolean updatable() default true;
-
- /**
- * (Optional) The name of the table that contains the column. If absent the column is assumed to be in the primary
- * table.
- *
- * @return String
- */
- @Deprecated
- String table() default "";
-
- /**
- * (Optional) The column length. (Applies only if a string-valued column is used.) if type==String and length ==
- * 65535 then sqltype is TEXT This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v. 1.0 which accompanies this distribution. The Eclipse Public License is available + * at http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + *
Contributors: Linda DeMichiel - Java Persistence 2.1 Linda DeMichiel - Java Persistence 2.0 + * + *
****************************************************************************
+ */
+package javax.persistence;
+
+import static java.lang.annotation.ElementType.*;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.*;
+
+/**
+ * Specifies the mapped column for a persistent property or field. If no Column annotation is specified,
+ * the default values apply.
+ *
+ *
+ *
+ *
+ * Example 1:
+ *
+ * @Column(name="DESC", nullable=false, length=512)
+ * public String getDescription() { return description; }
+ *
+ * Example 2:
+ *
+ * @Column(name="DESC",
+ * columnDefinition="CLOB NOT NULL",
+ * table="EMP_DETAIL")
+ * @Lob
+ * public String getDescription() { return description; }
+ *
+ * Example 3:
+ *
+ * @Column(name="ORDER_COST", updatable=false, precision=12, scale=2)
+ * public BigDecimal getCost() { return cost; }
+ *
+ *
+ *
+ *
+ *
+ * @since Java Persistence 1.0
+ * @deprecated replace by {@link org.redkale.persistence.Column}
+ * @see org.redkale.persistence.Column
+ */
+@Deprecated(since = "2.8.0")
+@Target({METHOD, FIELD})
+@Retention(RUNTIME)
+public @interface Column {
+
+ /**
+ * (Optional) The name of the column. Defaults to the property or field name.
+ *
+ * @return String
+ */
+ String name() default "";
+
+ /**
+ * (Optional) The comment of the column.
+ *
+ * @return String
+ */
+ String comment() default "";
+
+ /**
+ * (Optional) Whether the column is a unique key. This is a shortcut for the UniqueConstraint
+ * annotation at the table level and is useful for when the unique key constraint corresponds to only a single
+ * column. This constraint applies in addition to any constraint entailed by primary key mapping and to constraints
+ * specified at the table level.
+ *
+ * @return boolean
+ */
+ boolean unique() default false;
+
+ /**
+ * (Optional) Whether the database column is required.
+ *
+ * @return boolean
+ */
+ boolean nullable() default true;
+
+ /**
+ * for OpenAPI Specification 3
+ *
+ * @return String
+ */
+ String example() default "";
+
+ /**
+ * (Optional) Whether the column is included in SQL INSERT statements generated by the persistence provider.
+ *
+ * @return boolean
+ */
+ boolean insertable() default true;
+
+ /**
+ * (Optional) Whether the column is included in SQL UPDATE statements generated by the persistence provider.
+ *
+ * @return boolean
+ */
+ boolean updatable() default true;
+
+ /**
+ * (Optional) The name of the table that contains the column. If absent the column is assumed to be in the primary
+ * table.
+ *
+ * @return String
+ */
+ @Deprecated
+ String table() default "";
+
+ /**
+ * (Optional) The column length. (Applies only if a string-valued column is used.) if type==String and length ==
+ * 65535 then sqltype is TEXT This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v. 1.0 which accompanies this distribution. The Eclipse Public License is available - * at http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - *
Contributors: Linda DeMichiel - Java Persistence 2.1 Linda DeMichiel - Java Persistence 2.0 - * - *
**************************************************************************** - */ -package javax.persistence; - -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.*; - -/** - * Specifies that the class is an entity. This annotation is applied to the entity class. - * - * @since Java Persistence 1.0 - * @deprecated replace by {@link org.redkale.persistence.Entity} - * @see org.redkale.persistence.Entity - */ -@Deprecated(since = "2.8.0") -@Inherited -@Documented -@Target(TYPE) -@Retention(RUNTIME) -public @interface Entity { - - /** - * (Optional) The entity name. Defaults to the unqualified name of the entity class. This name is used to refer to - * the entity in queries. The name must not be a reserved literal in the Java Persistence query language. - * - * @return String - */ - String name() default ""; - - /** - * (Optional) The comment of the entity. - * - * @return String - */ - String comment() default ""; -} +/** + * ***************************************************************************** Copyright (c) 2008 - 2013 Oracle + * Corporation. All rights reserved. + * + *
This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v. 1.0 which accompanies this distribution. The Eclipse Public License is available + * at http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + *
Contributors: Linda DeMichiel - Java Persistence 2.1 Linda DeMichiel - Java Persistence 2.0 + * + *
**************************************************************************** + */ +package javax.persistence; + +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.*; + +/** + * Specifies that the class is an entity. This annotation is applied to the entity class. + * + * @since Java Persistence 1.0 + * @deprecated replace by {@link org.redkale.persistence.Entity} + * @see org.redkale.persistence.Entity + */ +@Deprecated(since = "2.8.0") +@Inherited +@Documented +@Target(TYPE) +@Retention(RUNTIME) +public @interface Entity { + + /** + * (Optional) The entity name. Defaults to the unqualified name of the entity class. This name is used to refer to + * the entity in queries. The name must not be a reserved literal in the Java Persistence query language. + * + * @return String + */ + String name() default ""; + + /** + * (Optional) The comment of the entity. + * + * @return String + */ + String comment() default ""; +} diff --git a/src/main/java/javax/persistence/Id.java b/src/main/java/javax/persistence/Id.java index 862ddc8cc..c4712f6f7 100644 --- a/src/main/java/javax/persistence/Id.java +++ b/src/main/java/javax/persistence/Id.java @@ -1,46 +1,46 @@ -/** - * ***************************************************************************** Copyright (c) 2008 - 2013 Oracle - * Corporation. All rights reserved. - * - *
This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v. 1.0 which accompanies this distribution. The Eclipse Public License is available - * at http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - *
Contributors: Linda DeMichiel - Java Persistence 2.1 Linda DeMichiel - Java Persistence 2.0 - * - *
****************************************************************************
- */
-package javax.persistence;
-
-import static java.lang.annotation.ElementType.*;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.*;
-
-/**
- * Specifies the primary key of an entity. The field or property to which the Id annotation is applied
- * should be one of the following types: any Java primitive type; any primitive wrapper type; String;
- * java.util.Date; java.sql.Date; java.math.BigDecimal;
- * java.math.BigInteger.
- *
- *
The mapped column for the primary key of the entity is assumed to be the primary key of the primary table. If no
- * Column annotation is specified, the primary key column name is assumed to be the name of the primary key
- * property or field.
- *
- *
- * Example:
- *
- * @Id
- * public Long getId() { return id; }
- *
- *
- * @see Column see GeneratedValue
- * @since Java Persistence 1.0
- * @deprecated replace by {@link org.redkale.persistence.Id}
- * @see org.redkale.persistence.Id
- */
-@Deprecated(since = "2.8.0")
-@Target({METHOD, FIELD})
-@Retention(RUNTIME)
-public @interface Id {}
+/**
+ * ***************************************************************************** Copyright (c) 2008 - 2013 Oracle
+ * Corporation. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v. 1.0 which accompanies this distribution. The Eclipse Public License is available + * at http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + *
Contributors: Linda DeMichiel - Java Persistence 2.1 Linda DeMichiel - Java Persistence 2.0 + * + *
****************************************************************************
+ */
+package javax.persistence;
+
+import static java.lang.annotation.ElementType.*;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.*;
+
+/**
+ * Specifies the primary key of an entity. The field or property to which the Id annotation is applied
+ * should be one of the following types: any Java primitive type; any primitive wrapper type; String;
+ * java.util.Date; java.sql.Date; java.math.BigDecimal;
+ * java.math.BigInteger.
+ *
+ *
The mapped column for the primary key of the entity is assumed to be the primary key of the primary table. If no
+ * Column annotation is specified, the primary key column name is assumed to be the name of the primary key
+ * property or field.
+ *
+ *
+ * Example:
+ *
+ * @Id
+ * public Long getId() { return id; }
+ *
+ *
+ * @see Column see GeneratedValue
+ * @since Java Persistence 1.0
+ * @deprecated replace by {@link org.redkale.persistence.Id}
+ * @see org.redkale.persistence.Id
+ */
+@Deprecated(since = "2.8.0")
+@Target({METHOD, FIELD})
+@Retention(RUNTIME)
+public @interface Id {}
diff --git a/src/main/java/javax/persistence/Index.java b/src/main/java/javax/persistence/Index.java
index f0429ad33..70b659d6c 100644
--- a/src/main/java/javax/persistence/Index.java
+++ b/src/main/java/javax/persistence/Index.java
@@ -1,64 +1,64 @@
-/**
- * ***************************************************************************** Copyright (c) 2011 - 2013 Oracle
- * Corporation. All rights reserved.
- *
- * This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v. 1.0 which accompanies this distribution. The Eclipse Public License is available - * at http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - *
Contributors: Linda DeMichiel - Java Persistence 2.1 - * - *
**************************************************************************** - */ -package javax.persistence; - -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.*; - -/** - * Used in schema generation to specify creation of an index. - * - *
Note that it is not necessary to specify an index for a primary key, as the primary key index will be created - * automatically. - * - *
The syntax of the columnList element is a column_list, as follows:
- *
- *
- * column::= index_column [,index_column]* - * index_column::= column_name [ASC | DESC] - *- * - *
If ASC or DESC is not specified, ASC (ascending order) is assumed.
- *
- * @since Java Persistence 2.1
- * @deprecated replace by {@link org.redkale.persistence.Index}
- * @see org.redkale.persistence.Index
- */
-@Deprecated(since = "2.8.0")
-@Target({})
-@Retention(RUNTIME)
-public @interface Index {
-
- /**
- * (Optional) The name of the index; defaults to a provider-generated name.
- *
- * @return String
- */
- String name() default "";
-
- /**
- * (Required) The names of the columns to be included in the index, in order.
- *
- * @return String
- */
- String columnList();
-
- /**
- * (Optional) Whether the index is unique.
- *
- * @return boolean
- */
- boolean unique() default false;
-}
+/**
+ * ***************************************************************************** Copyright (c) 2011 - 2013 Oracle
+ * Corporation. All rights reserved.
+ *
+ *
This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v. 1.0 which accompanies this distribution. The Eclipse Public License is available + * at http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + *
Contributors: Linda DeMichiel - Java Persistence 2.1 + * + *
**************************************************************************** + */ +package javax.persistence; + +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.*; + +/** + * Used in schema generation to specify creation of an index. + * + *
Note that it is not necessary to specify an index for a primary key, as the primary key index will be created + * automatically. + * + *
The syntax of the columnList element is a column_list, as follows:
+ *
+ *
+ * column::= index_column [,index_column]* + * index_column::= column_name [ASC | DESC] + *+ * + *
If ASC or DESC is not specified, ASC (ascending order) is assumed.
+ *
+ * @since Java Persistence 2.1
+ * @deprecated replace by {@link org.redkale.persistence.Index}
+ * @see org.redkale.persistence.Index
+ */
+@Deprecated(since = "2.8.0")
+@Target({})
+@Retention(RUNTIME)
+public @interface Index {
+
+ /**
+ * (Optional) The name of the index; defaults to a provider-generated name.
+ *
+ * @return String
+ */
+ String name() default "";
+
+ /**
+ * (Required) The names of the columns to be included in the index, in order.
+ *
+ * @return String
+ */
+ String columnList();
+
+ /**
+ * (Optional) Whether the index is unique.
+ *
+ * @return boolean
+ */
+ boolean unique() default false;
+}
diff --git a/src/main/java/javax/persistence/Table.java b/src/main/java/javax/persistence/Table.java
index 7f8a5cc13..cf66fd85e 100644
--- a/src/main/java/javax/persistence/Table.java
+++ b/src/main/java/javax/persistence/Table.java
@@ -1,88 +1,88 @@
-/**
- * ***************************************************************************** Copyright (c) 2008 - 2013 Oracle
- * Corporation. All rights reserved.
- *
- *
This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v. 1.0 which accompanies this distribution. The Eclipse Public License is available - * at http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - *
Contributors: Linda DeMichiel - Java Persistence 2.1 Linda DeMichiel - Java Persistence 2.0 - * - *
**************************************************************************** - */ -package javax.persistence; - -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.*; - -/** - * Specifies the primary table for the annotated entity. Additional tables may be specified using SecondaryTable or - * SecondaryTables annotation. - * - *
If no Table annotation is specified for an entity class, the default values apply.
- *
- *
- * Example:
- *
- * @Entity
- * @Table(name="CUST", schema="RECORDS")
- * public class Customer { ... }
- *
- *
- * @since Java Persistence 1.0
- * @deprecated replace by {@link org.redkale.persistence.Table}
- * @see org.redkale.persistence.Table
- */
-@Deprecated(since = "2.8.0")
-@Target(TYPE)
-@Retention(RUNTIME)
-public @interface Table {
-
- /**
- * (Optional) The name of the table.
- *
- * Defaults to the entity name. - * - * @return String - */ - String name() default ""; - - /** - * (Optional) The catalog of the table. - * - *
Defaults to the default catalog.
- *
- * @return String
- */
- String catalog() default "";
-
- /**
- * (Optional) Unique constraints that are to be placed on the table. These are only used if table generation is in
- * effect. These constraints apply in addition to any constraints specified by the Column and
- * JoinColumn annotations and constraints entailed by primary key mappings.
- *
- *
Defaults to no additional constraints. - * - * @return UniqueConstraint[] - */ - UniqueConstraint[] uniqueConstraints() default {}; - - /** - * (Optional) Indexes for the table. These are only used if table generation is in effect. Note that it is not - * necessary to specify an index for a primary key, as the primary key index will be created automatically. - * - * @return indexes - * @since Java Persistence 2.1 - */ - Index[] indexes() default {}; - - /** - * comment - * - * @return String - */ - String comment() default ""; -} +/** + * ***************************************************************************** Copyright (c) 2008 - 2013 Oracle + * Corporation. All rights reserved. + * + *
This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v. 1.0 which accompanies this distribution. The Eclipse Public License is available + * at http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + *
Contributors: Linda DeMichiel - Java Persistence 2.1 Linda DeMichiel - Java Persistence 2.0 + * + *
**************************************************************************** + */ +package javax.persistence; + +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.*; + +/** + * Specifies the primary table for the annotated entity. Additional tables may be specified using SecondaryTable or + * SecondaryTables annotation. + * + *
If no Table annotation is specified for an entity class, the default values apply.
+ *
+ *
+ * Example:
+ *
+ * @Entity
+ * @Table(name="CUST", schema="RECORDS")
+ * public class Customer { ... }
+ *
+ *
+ * @since Java Persistence 1.0
+ * @deprecated replace by {@link org.redkale.persistence.Table}
+ * @see org.redkale.persistence.Table
+ */
+@Deprecated(since = "2.8.0")
+@Target(TYPE)
+@Retention(RUNTIME)
+public @interface Table {
+
+ /**
+ * (Optional) The name of the table.
+ *
+ * Defaults to the entity name. + * + * @return String + */ + String name() default ""; + + /** + * (Optional) The catalog of the table. + * + *
Defaults to the default catalog.
+ *
+ * @return String
+ */
+ String catalog() default "";
+
+ /**
+ * (Optional) Unique constraints that are to be placed on the table. These are only used if table generation is in
+ * effect. These constraints apply in addition to any constraints specified by the Column and
+ * JoinColumn annotations and constraints entailed by primary key mappings.
+ *
+ *
Defaults to no additional constraints. + * + * @return UniqueConstraint[] + */ + UniqueConstraint[] uniqueConstraints() default {}; + + /** + * (Optional) Indexes for the table. These are only used if table generation is in effect. Note that it is not + * necessary to specify an index for a primary key, as the primary key index will be created automatically. + * + * @return indexes + * @since Java Persistence 2.1 + */ + Index[] indexes() default {}; + + /** + * comment + * + * @return String + */ + String comment() default ""; +} diff --git a/src/main/java/javax/persistence/Transient.java b/src/main/java/javax/persistence/Transient.java index 0ca77614a..171894982 100644 --- a/src/main/java/javax/persistence/Transient.java +++ b/src/main/java/javax/persistence/Transient.java @@ -1,43 +1,43 @@ -/** - * ***************************************************************************** Copyright (c) 2008 - 2013 Oracle - * Corporation. All rights reserved. - * - *
This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v. 1.0 which accompanies this distribution. The Eclipse Public License is available - * at http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - *
Contributors: Linda DeMichiel - Java Persistence 2.1 Linda DeMichiel - Java Persistence 2.0 - * - *
**************************************************************************** - */ -package javax.persistence; - -import static java.lang.annotation.ElementType.*; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.*; - -/** - * Specifies that the property or field is not persistent. It is used to annotate a property or field of an entity - * class, mapped superclass, or embeddable class. - * - *
- * Example:
- *
- * @Entity
- * public class Employee {
- * @Id int id;
- * @Transient User currentUser;
- * ...
- * }
- *
- *
- * @since Java Persistence 1.0
- * @deprecated replace by {@link org.redkale.persistence.Transient}
- * @see org.redkale.persistence.Transient
- */
-@Deprecated(since = "2.8.0")
-@Target({METHOD, FIELD})
-@Retention(RUNTIME)
-public @interface Transient {}
+/**
+ * ***************************************************************************** Copyright (c) 2008 - 2013 Oracle
+ * Corporation. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v. 1.0 which accompanies this distribution. The Eclipse Public License is available + * at http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + *
Contributors: Linda DeMichiel - Java Persistence 2.1 Linda DeMichiel - Java Persistence 2.0 + * + *
**************************************************************************** + */ +package javax.persistence; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.*; + +/** + * Specifies that the property or field is not persistent. It is used to annotate a property or field of an entity + * class, mapped superclass, or embeddable class. + * + *
+ * Example:
+ *
+ * @Entity
+ * public class Employee {
+ * @Id int id;
+ * @Transient User currentUser;
+ * ...
+ * }
+ *
+ *
+ * @since Java Persistence 1.0
+ * @deprecated replace by {@link org.redkale.persistence.Transient}
+ * @see org.redkale.persistence.Transient
+ */
+@Deprecated(since = "2.8.0")
+@Target({METHOD, FIELD})
+@Retention(RUNTIME)
+public @interface Transient {}
diff --git a/src/main/java/javax/persistence/UniqueConstraint.java b/src/main/java/javax/persistence/UniqueConstraint.java
index b01e8b1df..4c210bb4a 100644
--- a/src/main/java/javax/persistence/UniqueConstraint.java
+++ b/src/main/java/javax/persistence/UniqueConstraint.java
@@ -1,57 +1,57 @@
-/**
- * ***************************************************************************** Copyright (c) 2008 - 2013 Oracle
- * Corporation. All rights reserved.
- *
- * This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v. 1.0 which accompanies this distribution. The Eclipse Public License is available - * at http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - *
Contributors: Linda DeMichiel - Java Persistence 2.1 Linda DeMichiel - Java Persistence 2.0 - * - *
**************************************************************************** - */ -package javax.persistence; - -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.*; - -/** - * Specifies that a unique constraint is to be included in the generated DDL for a primary or secondary table. - * - *
- * Example:
- * @Entity
- * @Table(
- * name="EMPLOYEE",
- * uniqueConstraints=
- * @UniqueConstraint(columnNames={"EMP_ID", "EMP_NAME"})
- * )
- * public class Employee { ... }
- *
- *
- * @since Java Persistence 1.0
- * @deprecated replace by {@link org.redkale.persistence.UniqueConstraint}
- * @see org.redkale.persistence.UniqueConstraint
- */
-@Deprecated(since = "2.8.0")
-@Target({})
-@Retention(RUNTIME)
-public @interface UniqueConstraint {
-
- /**
- * (Optional) Constraint name. A provider-chosen name will be chosen if a name is not specified.
- *
- * @return String
- * @since Java Persistence 2.0
- */
- String name() default "";
-
- /**
- * (Required) An array of the column names that make up the constraint.
- *
- * @return String[]
- */
- String[] columnNames();
-}
+/**
+ * ***************************************************************************** Copyright (c) 2008 - 2013 Oracle
+ * Corporation. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v. 1.0 which accompanies this distribution. The Eclipse Public License is available + * at http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + *
Contributors: Linda DeMichiel - Java Persistence 2.1 Linda DeMichiel - Java Persistence 2.0 + * + *
**************************************************************************** + */ +package javax.persistence; + +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.*; + +/** + * Specifies that a unique constraint is to be included in the generated DDL for a primary or secondary table. + * + *
+ * Example:
+ * @Entity
+ * @Table(
+ * name="EMPLOYEE",
+ * uniqueConstraints=
+ * @UniqueConstraint(columnNames={"EMP_ID", "EMP_NAME"})
+ * )
+ * public class Employee { ... }
+ *
+ *
+ * @since Java Persistence 1.0
+ * @deprecated replace by {@link org.redkale.persistence.UniqueConstraint}
+ * @see org.redkale.persistence.UniqueConstraint
+ */
+@Deprecated(since = "2.8.0")
+@Target({})
+@Retention(RUNTIME)
+public @interface UniqueConstraint {
+
+ /**
+ * (Optional) Constraint name. A provider-chosen name will be chosen if a name is not specified.
+ *
+ * @return String
+ * @since Java Persistence 2.0
+ */
+ String name() default "";
+
+ /**
+ * (Required) An array of the column names that make up the constraint.
+ *
+ * @return String[]
+ */
+ String[] columnNames();
+}
diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java
index 230b47278..74ec1a88b 100644
--- a/src/main/java/module-info.java
+++ b/src/main/java/module-info.java
@@ -1,54 +1,54 @@
-/**
- * see: https://redkale.org
- *
- * @author zhangjx
- */
-module org.redkale {
- requires java.base;
- requires java.logging;
- requires java.net.http;
- requires java.sql;
- requires jdk.unsupported; // sun.misc.Unsafe
-
- exports org.redkale.annotation;
- exports org.redkale.boot;
- exports org.redkale.boot.watch;
- exports org.redkale.cache;
- exports org.redkale.cache.spi;
- exports org.redkale.cluster;
- exports org.redkale.cluster.spi;
- exports org.redkale.convert;
- exports org.redkale.convert.bson;
- exports org.redkale.convert.ext;
- exports org.redkale.convert.json;
- exports org.redkale.convert.proto;
- exports org.redkale.convert.spi;
- exports org.redkale.inject;
- exports org.redkale.lock;
- exports org.redkale.lock.spi;
- exports org.redkale.mq;
- exports org.redkale.mq.spi;
- exports org.redkale.net;
- exports org.redkale.net.client;
- exports org.redkale.net.http;
- exports org.redkale.net.sncp;
- exports org.redkale.persistence;
- exports org.redkale.props.spi;
- exports org.redkale.schedule;
- exports org.redkale.schedule.spi;
- exports org.redkale.service;
- exports org.redkale.source;
- exports org.redkale.source.spi;
- exports org.redkale.util;
- exports org.redkale.watch;
-
- uses org.redkale.props.spi.PropertiesAgentProvider;
- uses org.redkale.cache.spi.CacheManagerProvider;
- uses org.redkale.cluster.spi.ClusterAgentProvider;
- uses org.redkale.convert.spi.ConvertProvider;
- uses org.redkale.mq.spi.MessageAgentProvider;
- uses org.redkale.schedule.spi.ScheduleManagerProvider;
- uses org.redkale.source.spi.CacheSourceProvider;
- uses org.redkale.source.spi.DataSourceProvider;
- uses org.redkale.source.spi.DataNativeSqlParserProvider;
-}
+/**
+ * see: https://redkale.org
+ *
+ * @author zhangjx
+ */
+module org.redkale {
+ requires java.base;
+ requires java.logging;
+ requires java.net.http;
+ requires java.sql;
+ requires jdk.unsupported; // sun.misc.Unsafe
+
+ exports org.redkale.annotation;
+ exports org.redkale.boot;
+ exports org.redkale.boot.watch;
+ exports org.redkale.cache;
+ exports org.redkale.cache.spi;
+ exports org.redkale.cluster;
+ exports org.redkale.cluster.spi;
+ exports org.redkale.convert;
+ exports org.redkale.convert.bson;
+ exports org.redkale.convert.ext;
+ exports org.redkale.convert.json;
+ exports org.redkale.convert.proto;
+ exports org.redkale.convert.spi;
+ exports org.redkale.inject;
+ exports org.redkale.lock;
+ exports org.redkale.lock.spi;
+ exports org.redkale.mq;
+ exports org.redkale.mq.spi;
+ exports org.redkale.net;
+ exports org.redkale.net.client;
+ exports org.redkale.net.http;
+ exports org.redkale.net.sncp;
+ exports org.redkale.persistence;
+ exports org.redkale.props.spi;
+ exports org.redkale.schedule;
+ exports org.redkale.schedule.spi;
+ exports org.redkale.service;
+ exports org.redkale.source;
+ exports org.redkale.source.spi;
+ exports org.redkale.util;
+ exports org.redkale.watch;
+
+ uses org.redkale.props.spi.PropertiesAgentProvider;
+ uses org.redkale.cache.spi.CacheManagerProvider;
+ uses org.redkale.cluster.spi.ClusterAgentProvider;
+ uses org.redkale.convert.spi.ConvertProvider;
+ uses org.redkale.mq.spi.MessageAgentProvider;
+ uses org.redkale.schedule.spi.ScheduleManagerProvider;
+ uses org.redkale.source.spi.CacheSourceProvider;
+ uses org.redkale.source.spi.DataSourceProvider;
+ uses org.redkale.source.spi.DataNativeSqlParserProvider;
+}
diff --git a/src/main/java/org/redkale/annotation/ClassDepends.java b/src/main/java/org/redkale/annotation/ClassDepends.java
index 0ef4a58c7..e34828021 100644
--- a/src/main/java/org/redkale/annotation/ClassDepends.java
+++ b/src/main/java/org/redkale/annotation/ClassDepends.java
@@ -1,25 +1,25 @@
-/*
- *
- */
-package org.redkale.annotation;
-
-import static java.lang.annotation.ElementType.*;
-import static java.lang.annotation.RetentionPolicy.*;
-
-import java.lang.annotation.*;
-
-/**
- * 被标记的元素表示会被动态字节码调用
- *
- * 详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -@Documented -@Target({TYPE, METHOD, FIELD}) -@Retention(SOURCE) -public @interface ClassDepends { - - Class[] value() default {}; -} +/* + * + */ +package org.redkale.annotation; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.*; + +import java.lang.annotation.*; + +/** + * 被标记的元素表示会被动态字节码调用 + * + *
详情见: https://redkale.org
+ *
+ * @author zhangjx
+ * @since 2.8.0
+ */
+@Documented
+@Target({TYPE, METHOD, FIELD})
+@Retention(SOURCE)
+public @interface ClassDepends {
+
+ Class[] value() default {};
+}
diff --git a/src/main/java/org/redkale/annotation/Component.java b/src/main/java/org/redkale/annotation/Component.java
index 4cdc230a2..a698b392d 100644
--- a/src/main/java/org/redkale/annotation/Component.java
+++ b/src/main/java/org/redkale/annotation/Component.java
@@ -1,22 +1,22 @@
-package org.redkale.annotation;
-
-import static java.lang.annotation.ElementType.TYPE;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.*;
-
-/**
- * 标记Component的Service类特点:
- * 1、直接构造, 不使用Sncp动态构建对象
- * 2、不会生成对应协议的Servlet
- *
- *
详情见: https://redkale.org
- *
- * @author zhangjx
- * @since 2.8.0
- */
-@Inherited
-@Documented
-@Target({TYPE})
-@Retention(RUNTIME)
-public @interface Component {}
+package org.redkale.annotation;
+
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.*;
+
+/**
+ * 标记Component的Service类特点:
+ * 1、直接构造, 不使用Sncp动态构建对象
+ * 2、不会生成对应协议的Servlet
+ *
+ *
详情见: https://redkale.org
+ *
+ * @author zhangjx
+ * @since 2.8.0
+ */
+@Inherited
+@Documented
+@Target({TYPE})
+@Retention(RUNTIME)
+public @interface Component {}
diff --git a/src/main/java/org/redkale/annotation/NonBlocking.java b/src/main/java/org/redkale/annotation/NonBlocking.java
index ade4b3b16..530847bbc 100644
--- a/src/main/java/org/redkale/annotation/NonBlocking.java
+++ b/src/main/java/org/redkale/annotation/NonBlocking.java
@@ -1,25 +1,25 @@
-/*
- *
- */
-package org.redkale.annotation;
-
-import java.lang.annotation.*;
-
-/**
- * 非阻塞模式标记, 标记在Service类和方法、Filter类、HttpServlet类上
- * 一般情况下,没有显注此注解的方法视为阻塞时, 以下两种情况除外:
- * 1、返回类型是CompletionStage
- * 2、返回类型是void且参数存在CompletionHandler类型
- * 阻塞模式的方法会在work线程池中运行, 非阻塞在IO线程中运行。
- *
- *
详情见: https://redkale.org
- *
- * @author zhangjx
- * @since 2.8.0
- */
-@Target({ElementType.TYPE, ElementType.METHOD})
-@Retention(RetentionPolicy.RUNTIME)
-public @interface NonBlocking { // 不可使用@Inherited,防止被继承, 见HttpServlet.preExecute/authenticate/execute
-
- boolean value() default true;
-}
+/*
+ *
+ */
+package org.redkale.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * 非阻塞模式标记, 标记在Service类和方法、Filter类、HttpServlet类上
+ * 一般情况下,没有显注此注解的方法视为阻塞时, 以下两种情况除外:
+ * 1、返回类型是CompletionStage
+ * 2、返回类型是void且参数存在CompletionHandler类型
+ * 阻塞模式的方法会在work线程池中运行, 非阻塞在IO线程中运行。
+ *
+ *
详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +@Target({ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface NonBlocking { // 不可使用@Inherited,防止被继承, 见HttpServlet.preExecute/authenticate/execute + + boolean value() default true; +} diff --git a/src/main/java/org/redkale/annotation/Nonnull.java b/src/main/java/org/redkale/annotation/Nonnull.java index 467954d07..dca9bf6cd 100644 --- a/src/main/java/org/redkale/annotation/Nonnull.java +++ b/src/main/java/org/redkale/annotation/Nonnull.java @@ -1,18 +1,18 @@ -/* - * - */ -package org.redkale.annotation; - -import java.lang.annotation.*; - -/** - * 标记值可以为null - * - *
详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -@Documented -@Retention(RetentionPolicy.RUNTIME) -public @interface Nonnull {} +/* + * + */ +package org.redkale.annotation; + +import java.lang.annotation.*; + +/** + * 标记值可以为null + * + *
详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +public @interface Nonnull {} diff --git a/src/main/java/org/redkale/annotation/Nullable.java b/src/main/java/org/redkale/annotation/Nullable.java index c7722e9d9..4bae5f1f0 100644 --- a/src/main/java/org/redkale/annotation/Nullable.java +++ b/src/main/java/org/redkale/annotation/Nullable.java @@ -1,18 +1,18 @@ -/* - * - */ -package org.redkale.annotation; - -import java.lang.annotation.*; - -/** - * 标记值可以为null - * - *
详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -@Documented -@Retention(RetentionPolicy.RUNTIME) -public @interface Nullable {} +/* + * + */ +package org.redkale.annotation; + +import java.lang.annotation.*; + +/** + * 标记值可以为null + * + *
详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +public @interface Nullable {} diff --git a/src/main/java/org/redkale/annotation/Param.java b/src/main/java/org/redkale/annotation/Param.java index 4630d2773..b0001f21a 100644 --- a/src/main/java/org/redkale/annotation/Param.java +++ b/src/main/java/org/redkale/annotation/Param.java @@ -1,29 +1,29 @@ -/* - * - */ -package org.redkale.annotation; - -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * 参数名注解,编译时加上 -parameters 参数可以不用此注解 - * - *
详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -@Documented -@Target({PARAMETER}) -@Retention(RUNTIME) -public @interface Param { - - String value(); - - String comment() default ""; -} +/* + * + */ +package org.redkale.annotation; + +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +/** + * 参数名注解,编译时加上 -parameters 参数可以不用此注解 + * + *
详情见: https://redkale.org
+ *
+ * @author zhangjx
+ * @since 2.8.0
+ */
+@Documented
+@Target({PARAMETER})
+@Retention(RUNTIME)
+public @interface Param {
+
+ String value();
+
+ String comment() default "";
+}
diff --git a/src/main/java/org/redkale/annotation/PostConstruct.java b/src/main/java/org/redkale/annotation/PostConstruct.java
index 2cbbe75ad..72a8813ad 100644
--- a/src/main/java/org/redkale/annotation/PostConstruct.java
+++ b/src/main/java/org/redkale/annotation/PostConstruct.java
@@ -1,20 +1,20 @@
-/*
- *
- */
-package org.redkale.annotation;
-
-import static java.lang.annotation.ElementType.*;
-import static java.lang.annotation.RetentionPolicy.*;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-/**
- * @since Common Annotations 1.0
- * @since 2.8.0
- */
-@Documented
-@Retention(RUNTIME)
-@Target(METHOD)
-public @interface PostConstruct {}
+/*
+ *
+ */
+package org.redkale.annotation;
+
+import static java.lang.annotation.ElementType.*;
+import static java.lang.annotation.RetentionPolicy.*;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * @since Common Annotations 1.0
+ * @since 2.8.0
+ */
+@Documented
+@Retention(RUNTIME)
+@Target(METHOD)
+public @interface PostConstruct {}
diff --git a/src/main/java/org/redkale/annotation/PreDestroy.java b/src/main/java/org/redkale/annotation/PreDestroy.java
index 8e490eb68..aeeb6d532 100644
--- a/src/main/java/org/redkale/annotation/PreDestroy.java
+++ b/src/main/java/org/redkale/annotation/PreDestroy.java
@@ -1,18 +1,18 @@
-/*
- *
- */
-package org.redkale.annotation;
-
-import static java.lang.annotation.ElementType.*;
-import static java.lang.annotation.RetentionPolicy.*;
-
-import java.lang.annotation.*;
-
-/**
- * @since Common Annotations 1.0
- * @since 2.8.0
- */
-@Documented
-@Retention(RUNTIME)
-@Target(METHOD)
-public @interface PreDestroy {}
+/*
+ *
+ */
+package org.redkale.annotation;
+
+import static java.lang.annotation.ElementType.*;
+import static java.lang.annotation.RetentionPolicy.*;
+
+import java.lang.annotation.*;
+
+/**
+ * @since Common Annotations 1.0
+ * @since 2.8.0
+ */
+@Documented
+@Retention(RUNTIME)
+@Target(METHOD)
+public @interface PreDestroy {}
diff --git a/src/main/java/org/redkale/annotation/ResourceInjected.java b/src/main/java/org/redkale/annotation/ResourceInjected.java
index 9c865ad8c..1131b80ef 100644
--- a/src/main/java/org/redkale/annotation/ResourceInjected.java
+++ b/src/main/java/org/redkale/annotation/ResourceInjected.java
@@ -1,65 +1,65 @@
-/*
- * To change this license header, choose License Headers in Project Properties.
- * To change this template file, choose Tools | Templates
- * and open the template in the editor.
- */
-package org.redkale.annotation;
-
-import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.*;
-
-/**
- * @Resource资源被依赖注入时的监听事件。
- * 本注解只能标记在空参数或者(String、Object、java.lang.reflect.Field)三个参数类型的任意组合方法上
- * 方法在资源被依赖注入后调用。
- *
- *
- *
- *
- * public class ResourceService implements Service {
- *
- * @Resource(name = "res.id")
- * private int id;
- *
- * @Resource(name = "res.name")
- * private String name;
- *
- * @ResourceInjected
- * private void onInjected(Object src, String fieldName) {
- * System.out .println("资源被注入到对象(" + src + ")的字段(" + fieldName + ")上");
- * }
- * }
- *
- * public class RecordService implements Service {
- *
- * @Resource
- * private ResourceService resService;
- *
- * public void test() {
- * }
- *
- * public static void main(String[] args) throws Exception {
- * ResourceFactory factory = ResourceFactory.create();
- * factory.register("res.id", "2345");
- * factory.register("res.name", "my old name");
- * ResourceService res = new ResourceService();
- * factory.inject(res);
- * factory.register("", res);
- * RecordService serice = new RecordService();
- * factory.inject(record);
- * }
- * }
- *
- *
- *
- *
- * 详情见: https://redkale.org
- *
- * @author zhangjx
- */
-@Documented
-@Target({METHOD})
-@Retention(RUNTIME)
-public @interface ResourceInjected {}
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.redkale.annotation;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.*;
+
+/**
+ * @Resource资源被依赖注入时的监听事件。
+ * 本注解只能标记在空参数或者(String、Object、java.lang.reflect.Field)三个参数类型的任意组合方法上
+ * 方法在资源被依赖注入后调用。
+ *
+ *
+ *
+ *
+ * public class ResourceService implements Service {
+ *
+ * @Resource(name = "res.id")
+ * private int id;
+ *
+ * @Resource(name = "res.name")
+ * private String name;
+ *
+ * @ResourceInjected
+ * private void onInjected(Object src, String fieldName) {
+ * System.out .println("资源被注入到对象(" + src + ")的字段(" + fieldName + ")上");
+ * }
+ * }
+ *
+ * public class RecordService implements Service {
+ *
+ * @Resource
+ * private ResourceService resService;
+ *
+ * public void test() {
+ * }
+ *
+ * public static void main(String[] args) throws Exception {
+ * ResourceFactory factory = ResourceFactory.create();
+ * factory.register("res.id", "2345");
+ * factory.register("res.name", "my old name");
+ * ResourceService res = new ResourceService();
+ * factory.inject(res);
+ * factory.register("", res);
+ * RecordService serice = new RecordService();
+ * factory.inject(record);
+ * }
+ * }
+ *
+ *
+ *
+ *
+ * 详情见: https://redkale.org
+ *
+ * @author zhangjx
+ */
+@Documented
+@Target({METHOD})
+@Retention(RUNTIME)
+public @interface ResourceInjected {}
diff --git a/src/main/java/org/redkale/asm/AnnotationVisitor.java b/src/main/java/org/redkale/asm/AnnotationVisitor.java
index 9ace2e08f..2d944c6fa 100644
--- a/src/main/java/org/redkale/asm/AnnotationVisitor.java
+++ b/src/main/java/org/redkale/asm/AnnotationVisitor.java
@@ -1,170 +1,170 @@
-/*
- * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- */
-
-/*
- *
- *
- *
- *
- *
- * ASM: a very small and fast Java bytecode manipulation framework
- * Copyright (c) 2000-2011 INRIA, France Telecom
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-package org.redkale.asm;
-
-/**
- * A visitor to visit a Java annotation. The methods of this class must be called in the following order: (
- * <tt>visit</tt> | <tt>visitEnum</tt> | <tt>visitAnnotation</tt> |
- * <tt>visitArray</tt> )* <tt>visitEnd</tt>.
- *
- * @author Eric Bruneton
- * @author Eugene Kuleshov
- */
-public abstract class AnnotationVisitor {
-
- /**
- * The ASM API version implemented by this visitor. The value of this field must be one of {@link Opcodes#ASM4},
- * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
- */
- protected final int api;
-
- /** The annotation visitor to which this visitor must delegate method calls. May be null. */
- protected AnnotationVisitor av;
-
- /**
- * Constructs a new {@link AnnotationVisitor}.
- *
- * @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM4},
- * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
- */
- public AnnotationVisitor(final int api) {
- this(api, null);
- }
-
- /**
- * Constructs a new {@link AnnotationVisitor}.
- *
- * @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM4},
- * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
- * @param av the annotation visitor to which this visitor must delegate method calls. May be null.
- */
- public AnnotationVisitor(final int api, final AnnotationVisitor av) {
- this.api = api;
- this.av = av;
- }
-
- /**
- * Visits a primitive value of the annotation.
- *
- * @param name the value name.
- * @param value the actual value, whose type must be {@link Byte}, {@link Boolean}, {@link Character},
- * {@link Short}, {@link Integer} , {@link Long}, {@link Float}, {@link Double}, {@link String} or {@link Type}
- * of OBJECT or ARRAY sort. This value can also be an array of byte, boolean, short, char, int, long, float or
- * double values (this is equivalent to using {@link #visitArray visitArray} and visiting each array element in
- * turn, but is more convenient).
- */
- public void visit(String name, Object value) {
- if (av != null) {
- av.visit(name, value);
- }
- }
-
- /**
- * Visits an enumeration value of the annotation.
- *
- * @param name the value name.
- * @param desc the class descriptor of the enumeration class.
- * @param value the actual enumeration value.
- */
- public void visitEnum(String name, String desc, String value) {
- if (av != null) {
- av.visitEnum(name, desc, value);
- }
- }
-
- /**
- * Visits a nested annotation value of the annotation.
- *
- * @param name the value name.
- * @param desc the class descriptor of the nested annotation class.
- * @return a visitor to visit the actual nested annotation value, or <tt>null</tt> if this visitor
- * is not interested in visiting this nested annotation. The nested annotation value must be fully visited
- * before calling other methods on this annotation visitor.
- */
- public AnnotationVisitor visitAnnotation(String name, String desc) {
- if (av != null) {
- return av.visitAnnotation(name, desc);
- }
- return null;
- }
-
- /**
- * Visits an array value of the annotation. Note that arrays of primitive types (such as byte, boolean, short, char,
- * int, long, float or double) can be passed as value to {@link #visit visit}. This is what {@link ClassReader}
- * does.
- *
- * @param name the value name.
- * @return a visitor to visit the actual array value elements, or <tt>null</tt> if this visitor is
- * not interested in visiting these values. The 'name' parameters passed to the methods of this visitor are
- * ignored. All the array values must be visited before calling other methods on this annotation visitor.
- */
- public AnnotationVisitor visitArray(String name) {
- if (av != null) {
- return av.visitArray(name);
- }
- return null;
- }
-
- /** Visits the end of the annotation. */
- public void visitEnd() {
- if (av != null) {
- av.visitEnd();
- }
- }
-}
+/*
+ * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ */
+
+/*
+ *
+ *
+ *
+ *
+ *
+ * ASM: a very small and fast Java bytecode manipulation framework
+ * Copyright (c) 2000-2011 INRIA, France Telecom
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.redkale.asm;
+
+/**
+ * A visitor to visit a Java annotation. The methods of this class must be called in the following order: (
+ * <tt>visit</tt> | <tt>visitEnum</tt> | <tt>visitAnnotation</tt> |
+ * <tt>visitArray</tt> )* <tt>visitEnd</tt>.
+ *
+ * @author Eric Bruneton
+ * @author Eugene Kuleshov
+ */
+public abstract class AnnotationVisitor {
+
+ /**
+ * The ASM API version implemented by this visitor. The value of this field must be one of {@link Opcodes#ASM4},
+ * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
+ */
+ protected final int api;
+
+ /** The annotation visitor to which this visitor must delegate method calls. May be null. */
+ protected AnnotationVisitor av;
+
+ /**
+ * Constructs a new {@link AnnotationVisitor}.
+ *
+ * @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM4},
+ * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
+ */
+ public AnnotationVisitor(final int api) {
+ this(api, null);
+ }
+
+ /**
+ * Constructs a new {@link AnnotationVisitor}.
+ *
+ * @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM4},
+ * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
+ * @param av the annotation visitor to which this visitor must delegate method calls. May be null.
+ */
+ public AnnotationVisitor(final int api, final AnnotationVisitor av) {
+ this.api = api;
+ this.av = av;
+ }
+
+ /**
+ * Visits a primitive value of the annotation.
+ *
+ * @param name the value name.
+ * @param value the actual value, whose type must be {@link Byte}, {@link Boolean}, {@link Character},
+ * {@link Short}, {@link Integer} , {@link Long}, {@link Float}, {@link Double}, {@link String} or {@link Type}
+ * of OBJECT or ARRAY sort. This value can also be an array of byte, boolean, short, char, int, long, float or
+ * double values (this is equivalent to using {@link #visitArray visitArray} and visiting each array element in
+ * turn, but is more convenient).
+ */
+ public void visit(String name, Object value) {
+ if (av != null) {
+ av.visit(name, value);
+ }
+ }
+
+ /**
+ * Visits an enumeration value of the annotation.
+ *
+ * @param name the value name.
+ * @param desc the class descriptor of the enumeration class.
+ * @param value the actual enumeration value.
+ */
+ public void visitEnum(String name, String desc, String value) {
+ if (av != null) {
+ av.visitEnum(name, desc, value);
+ }
+ }
+
+ /**
+ * Visits a nested annotation value of the annotation.
+ *
+ * @param name the value name.
+ * @param desc the class descriptor of the nested annotation class.
+ * @return a visitor to visit the actual nested annotation value, or <tt>null</tt> if this visitor
+ * is not interested in visiting this nested annotation. The nested annotation value must be fully visited
+ * before calling other methods on this annotation visitor.
+ */
+ public AnnotationVisitor visitAnnotation(String name, String desc) {
+ if (av != null) {
+ return av.visitAnnotation(name, desc);
+ }
+ return null;
+ }
+
+ /**
+ * Visits an array value of the annotation. Note that arrays of primitive types (such as byte, boolean, short, char,
+ * int, long, float or double) can be passed as value to {@link #visit visit}. This is what {@link ClassReader}
+ * does.
+ *
+ * @param name the value name.
+ * @return a visitor to visit the actual array value elements, or <tt>null</tt> if this visitor is
+ * not interested in visiting these values. The 'name' parameters passed to the methods of this visitor are
+ * ignored. All the array values must be visited before calling other methods on this annotation visitor.
+ */
+ public AnnotationVisitor visitArray(String name) {
+ if (av != null) {
+ return av.visitArray(name);
+ }
+ return null;
+ }
+
+ /** Visits the end of the annotation. */
+ public void visitEnd() {
+ if (av != null) {
+ av.visitEnd();
+ }
+ }
+}
diff --git a/src/main/java/org/redkale/asm/AnnotationWriter.java b/src/main/java/org/redkale/asm/AnnotationWriter.java
index b0fb93fec..165ecf86b 100644
--- a/src/main/java/org/redkale/asm/AnnotationWriter.java
+++ b/src/main/java/org/redkale/asm/AnnotationWriter.java
@@ -1,366 +1,366 @@
-/*
- * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- */
-
-/*
- *
- *
- *
- *
- *
- * ASM: a very small and fast Java bytecode manipulation framework
- * Copyright (c) 2000-2011 INRIA, France Telecom
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-package org.redkale.asm;
-
-/**
- * An {@link AnnotationVisitor} that generates annotations in bytecode form.
- *
- * @author Eric Bruneton
- * @author Eugene Kuleshov
- */
-final class AnnotationWriter extends AnnotationVisitor {
-
- /** The class writer to which this annotation must be added. */
- private final ClassWriter cw;
-
- /** The number of values in this annotation. */
- private int size;
-
- /**
- * <tt>true<tt> if values are named, <tt>false</tt> otherwise. Annotation writers
- * used for annotation default and annotation arrays use unnamed values.
- */
- private final boolean named;
-
- /**
- * The annotation values in bytecode form. This byte vector only contains the values themselves, i.e. the number of
- * values must be stored as a unsigned short just before these bytes.
- */
- private final ByteVector bv;
-
- /** The byte vector to be used to store the number of values of this annotation. See {@link #bv}. */
- private final ByteVector parent;
-
- /** Where the number of values of this annotation must be stored in {@link #parent}. */
- private final int offset;
-
- /** Next annotation writer. This field is used to store annotation lists. */
- AnnotationWriter next;
-
- /** Previous annotation writer. This field is used to store annotation lists. */
- AnnotationWriter prev;
-
- // ------------------------------------------------------------------------
- // Constructor
- // ------------------------------------------------------------------------
-
- /**
- * Constructs a new {@link AnnotationWriter}.
- *
- * @param cw the class writer to which this annotation must be added.
- * @param named <tt>true<tt> if values are named, <tt>false</tt> otherwise.
- * @param bv where the annotation values must be stored.
- * @param parent where the number of annotation values must be stored.
- * @param offset where in <tt>parent</tt> the number of annotation values must be stored.
- */
- AnnotationWriter(
- final ClassWriter cw, final boolean named, final ByteVector bv, final ByteVector parent, final int offset) {
- super(Opcodes.ASM6);
- this.cw = cw;
- this.named = named;
- this.bv = bv;
- this.parent = parent;
- this.offset = offset;
- }
-
- // ------------------------------------------------------------------------
- // Implementation of the AnnotationVisitor abstract class
- // ------------------------------------------------------------------------
-
- @Override
- public void visit(final String name, final Object value) {
- ++size;
- if (named) {
- bv.putShort(cw.newUTF8(name));
- }
- if (value instanceof String) {
- bv.put12('s', cw.newUTF8((String) value));
- } else if (value instanceof Byte) {
- bv.put12('B', cw.newInteger(((Byte) value).byteValue()).index);
- } else if (value instanceof Boolean) {
- int v = ((Boolean) value).booleanValue() ? 1 : 0;
- bv.put12('Z', cw.newInteger(v).index);
- } else if (value instanceof Character) {
- bv.put12('C', cw.newInteger(((Character) value).charValue()).index);
- } else if (value instanceof Short) {
- bv.put12('S', cw.newInteger(((Short) value).shortValue()).index);
- } else if (value instanceof Type) {
- bv.put12('c', cw.newUTF8(((Type) value).getDescriptor()));
- } else if (value instanceof byte[]) {
- byte[] v = (byte[]) value;
- bv.put12('[', v.length);
- for (int i = 0; i < v.length; i++) {
- bv.put12('B', cw.newInteger(v[i]).index);
- }
- } else if (value instanceof boolean[]) {
- boolean[] v = (boolean[]) value;
- bv.put12('[', v.length);
- for (int i = 0; i < v.length; i++) {
- bv.put12('Z', cw.newInteger(v[i] ? 1 : 0).index);
- }
- } else if (value instanceof short[]) {
- short[] v = (short[]) value;
- bv.put12('[', v.length);
- for (int i = 0; i < v.length; i++) {
- bv.put12('S', cw.newInteger(v[i]).index);
- }
- } else if (value instanceof char[]) {
- char[] v = (char[]) value;
- bv.put12('[', v.length);
- for (int i = 0; i < v.length; i++) {
- bv.put12('C', cw.newInteger(v[i]).index);
- }
- } else if (value instanceof int[]) {
- int[] v = (int[]) value;
- bv.put12('[', v.length);
- for (int i = 0; i < v.length; i++) {
- bv.put12('I', cw.newInteger(v[i]).index);
- }
- } else if (value instanceof long[]) {
- long[] v = (long[]) value;
- bv.put12('[', v.length);
- for (int i = 0; i < v.length; i++) {
- bv.put12('J', cw.newLong(v[i]).index);
- }
- } else if (value instanceof float[]) {
- float[] v = (float[]) value;
- bv.put12('[', v.length);
- for (int i = 0; i < v.length; i++) {
- bv.put12('F', cw.newFloat(v[i]).index);
- }
- } else if (value instanceof double[]) {
- double[] v = (double[]) value;
- bv.put12('[', v.length);
- for (int i = 0; i < v.length; i++) {
- bv.put12('D', cw.newDouble(v[i]).index);
- }
- } else {
- Item i = cw.newConstItem(value);
- bv.put12(".s.IFJDCS".charAt(i.type), i.index);
- }
- }
-
- @Override
- public void visitEnum(final String name, final String desc, final String value) {
- ++size;
- if (named) {
- bv.putShort(cw.newUTF8(name));
- }
- bv.put12('e', cw.newUTF8(desc)).putShort(cw.newUTF8(value));
- }
-
- @Override
- public AnnotationVisitor visitAnnotation(final String name, final String desc) {
- ++size;
- if (named) {
- bv.putShort(cw.newUTF8(name));
- }
- // write tag and type, and reserve space for values count
- bv.put12('@', cw.newUTF8(desc)).putShort(0);
- return new AnnotationWriter(cw, true, bv, bv, bv.length - 2);
- }
-
- @Override
- public AnnotationVisitor visitArray(final String name) {
- ++size;
- if (named) {
- bv.putShort(cw.newUTF8(name));
- }
- // write tag, and reserve space for array size
- bv.put12('[', 0);
- return new AnnotationWriter(cw, false, bv, bv, bv.length - 2);
- }
-
- @Override
- public void visitEnd() {
- if (parent != null) {
- byte[] data = parent.data;
- data[offset] = (byte) (size >>> 8);
- data[offset + 1] = (byte) size;
- }
- }
-
- // ------------------------------------------------------------------------
- // Utility methods
- // ------------------------------------------------------------------------
-
- /**
- * Returns the size of this annotation writer list.
- *
- * @return the size of this annotation writer list.
- */
- int getSize() {
- int size = 0;
- AnnotationWriter aw = this;
- while (aw != null) {
- size += aw.bv.length;
- aw = aw.next;
- }
- return size;
- }
-
- /**
- * Puts the annotations of this annotation writer list into the given byte vector.
- *
- * @param out where the annotations must be put.
- */
- void put(final ByteVector out) {
- int n = 0;
- int size = 2;
- AnnotationWriter aw = this;
- AnnotationWriter last = null;
- while (aw != null) {
- ++n;
- size += aw.bv.length;
- aw.visitEnd(); // in case user forgot to call visitEnd
- aw.prev = last;
- last = aw;
- aw = aw.next;
- }
- out.putInt(size);
- out.putShort(n);
- aw = last;
- while (aw != null) {
- out.putByteArray(aw.bv.data, 0, aw.bv.length);
- aw = aw.prev;
- }
- }
-
- /**
- * Puts the given annotation lists into the given byte vector.
- *
- * @param panns an array of annotation writer lists.
- * @param off index of the first annotation to be written.
- * @param out where the annotations must be put.
- */
- static void put(final AnnotationWriter[] panns, final int off, final ByteVector out) {
- int size = 1 + 2 * (panns.length - off);
- for (int i = off; i < panns.length; ++i) {
- size += panns[i] == null ? 0 : panns[i].getSize();
- }
- out.putInt(size).putByte(panns.length - off);
- for (int i = off; i < panns.length; ++i) {
- AnnotationWriter aw = panns[i];
- AnnotationWriter last = null;
- int n = 0;
- while (aw != null) {
- ++n;
- aw.visitEnd(); // in case user forgot to call visitEnd
- aw.prev = last;
- last = aw;
- aw = aw.next;
- }
- out.putShort(n);
- aw = last;
- while (aw != null) {
- out.putByteArray(aw.bv.data, 0, aw.bv.length);
- aw = aw.prev;
- }
- }
- }
-
- /**
- * Puts the given type reference and type path into the given bytevector. LOCAL_VARIABLE and RESOURCE_VARIABLE
- * target types are not supported.
- *
- * @param typeRef a reference to the annotated type. See {@link TypeReference}.
- * @param typePath the path to the annotated type argument, wildcard bound, array element type, or static inner type
- * within 'typeRef'. May be <tt>null</tt> if the annotation targets 'typeRef' as a whole.
- * @param out where the type reference and type path must be put.
- */
- static void putTarget(int typeRef, TypePath typePath, ByteVector out) {
- switch (typeRef >>> 24) {
- case 0x00: // CLASS_TYPE_PARAMETER
- case 0x01: // METHOD_TYPE_PARAMETER
- case 0x16: // METHOD_FORMAL_PARAMETER
- out.putShort(typeRef >>> 16);
- break;
- case 0x13: // FIELD
- case 0x14: // METHOD_RETURN
- case 0x15: // METHOD_RECEIVER
- out.putByte(typeRef >>> 24);
- break;
- case 0x47: // CAST
- case 0x48: // CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
- case 0x49: // METHOD_INVOCATION_TYPE_ARGUMENT
- case 0x4A: // CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
- case 0x4B: // METHOD_REFERENCE_TYPE_ARGUMENT
- out.putInt(typeRef);
- break;
- // case 0x10: // CLASS_EXTENDS
- // case 0x11: // CLASS_TYPE_PARAMETER_BOUND
- // case 0x12: // METHOD_TYPE_PARAMETER_BOUND
- // case 0x17: // THROWS
- // case 0x42: // EXCEPTION_PARAMETER
- // case 0x43: // INSTANCEOF
- // case 0x44: // NEW
- // case 0x45: // CONSTRUCTOR_REFERENCE
- // case 0x46: // METHOD_REFERENCE
- default:
- out.put12(typeRef >>> 24, (typeRef & 0xFFFF00) >> 8);
- break;
- }
- if (typePath == null) {
- out.putByte(0);
- } else {
- int length = typePath.b[typePath.offset] * 2 + 1;
- out.putByteArray(typePath.b, typePath.offset, length);
- }
- }
-}
+/*
+ * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ */
+
+/*
+ *
+ *
+ *
+ *
+ *
+ * ASM: a very small and fast Java bytecode manipulation framework
+ * Copyright (c) 2000-2011 INRIA, France Telecom
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.redkale.asm;
+
+/**
+ * An {@link AnnotationVisitor} that generates annotations in bytecode form.
+ *
+ * @author Eric Bruneton
+ * @author Eugene Kuleshov
+ */
+final class AnnotationWriter extends AnnotationVisitor {
+
+ /** The class writer to which this annotation must be added. */
+ private final ClassWriter cw;
+
+ /** The number of values in this annotation. */
+ private int size;
+
+ /**
+ * <tt>true<tt> if values are named, <tt>false</tt> otherwise. Annotation writers
+ * used for annotation default and annotation arrays use unnamed values.
+ */
+ private final boolean named;
+
+ /**
+ * The annotation values in bytecode form. This byte vector only contains the values themselves, i.e. the number of
+ * values must be stored as a unsigned short just before these bytes.
+ */
+ private final ByteVector bv;
+
+ /** The byte vector to be used to store the number of values of this annotation. See {@link #bv}. */
+ private final ByteVector parent;
+
+ /** Where the number of values of this annotation must be stored in {@link #parent}. */
+ private final int offset;
+
+ /** Next annotation writer. This field is used to store annotation lists. */
+ AnnotationWriter next;
+
+ /** Previous annotation writer. This field is used to store annotation lists. */
+ AnnotationWriter prev;
+
+ // ------------------------------------------------------------------------
+ // Constructor
+ // ------------------------------------------------------------------------
+
+ /**
+ * Constructs a new {@link AnnotationWriter}.
+ *
+ * @param cw the class writer to which this annotation must be added.
+ * @param named <tt>true<tt> if values are named, <tt>false</tt> otherwise.
+ * @param bv where the annotation values must be stored.
+ * @param parent where the number of annotation values must be stored.
+ * @param offset where in <tt>parent</tt> the number of annotation values must be stored.
+ */
+ AnnotationWriter(
+ final ClassWriter cw, final boolean named, final ByteVector bv, final ByteVector parent, final int offset) {
+ super(Opcodes.ASM6);
+ this.cw = cw;
+ this.named = named;
+ this.bv = bv;
+ this.parent = parent;
+ this.offset = offset;
+ }
+
+ // ------------------------------------------------------------------------
+ // Implementation of the AnnotationVisitor abstract class
+ // ------------------------------------------------------------------------
+
+ @Override
+ public void visit(final String name, final Object value) {
+ ++size;
+ if (named) {
+ bv.putShort(cw.newUTF8(name));
+ }
+ if (value instanceof String) {
+ bv.put12('s', cw.newUTF8((String) value));
+ } else if (value instanceof Byte) {
+ bv.put12('B', cw.newInteger(((Byte) value).byteValue()).index);
+ } else if (value instanceof Boolean) {
+ int v = ((Boolean) value).booleanValue() ? 1 : 0;
+ bv.put12('Z', cw.newInteger(v).index);
+ } else if (value instanceof Character) {
+ bv.put12('C', cw.newInteger(((Character) value).charValue()).index);
+ } else if (value instanceof Short) {
+ bv.put12('S', cw.newInteger(((Short) value).shortValue()).index);
+ } else if (value instanceof Type) {
+ bv.put12('c', cw.newUTF8(((Type) value).getDescriptor()));
+ } else if (value instanceof byte[]) {
+ byte[] v = (byte[]) value;
+ bv.put12('[', v.length);
+ for (int i = 0; i < v.length; i++) {
+ bv.put12('B', cw.newInteger(v[i]).index);
+ }
+ } else if (value instanceof boolean[]) {
+ boolean[] v = (boolean[]) value;
+ bv.put12('[', v.length);
+ for (int i = 0; i < v.length; i++) {
+ bv.put12('Z', cw.newInteger(v[i] ? 1 : 0).index);
+ }
+ } else if (value instanceof short[]) {
+ short[] v = (short[]) value;
+ bv.put12('[', v.length);
+ for (int i = 0; i < v.length; i++) {
+ bv.put12('S', cw.newInteger(v[i]).index);
+ }
+ } else if (value instanceof char[]) {
+ char[] v = (char[]) value;
+ bv.put12('[', v.length);
+ for (int i = 0; i < v.length; i++) {
+ bv.put12('C', cw.newInteger(v[i]).index);
+ }
+ } else if (value instanceof int[]) {
+ int[] v = (int[]) value;
+ bv.put12('[', v.length);
+ for (int i = 0; i < v.length; i++) {
+ bv.put12('I', cw.newInteger(v[i]).index);
+ }
+ } else if (value instanceof long[]) {
+ long[] v = (long[]) value;
+ bv.put12('[', v.length);
+ for (int i = 0; i < v.length; i++) {
+ bv.put12('J', cw.newLong(v[i]).index);
+ }
+ } else if (value instanceof float[]) {
+ float[] v = (float[]) value;
+ bv.put12('[', v.length);
+ for (int i = 0; i < v.length; i++) {
+ bv.put12('F', cw.newFloat(v[i]).index);
+ }
+ } else if (value instanceof double[]) {
+ double[] v = (double[]) value;
+ bv.put12('[', v.length);
+ for (int i = 0; i < v.length; i++) {
+ bv.put12('D', cw.newDouble(v[i]).index);
+ }
+ } else {
+ Item i = cw.newConstItem(value);
+ bv.put12(".s.IFJDCS".charAt(i.type), i.index);
+ }
+ }
+
+ @Override
+ public void visitEnum(final String name, final String desc, final String value) {
+ ++size;
+ if (named) {
+ bv.putShort(cw.newUTF8(name));
+ }
+ bv.put12('e', cw.newUTF8(desc)).putShort(cw.newUTF8(value));
+ }
+
+ @Override
+ public AnnotationVisitor visitAnnotation(final String name, final String desc) {
+ ++size;
+ if (named) {
+ bv.putShort(cw.newUTF8(name));
+ }
+ // write tag and type, and reserve space for values count
+ bv.put12('@', cw.newUTF8(desc)).putShort(0);
+ return new AnnotationWriter(cw, true, bv, bv, bv.length - 2);
+ }
+
+ @Override
+ public AnnotationVisitor visitArray(final String name) {
+ ++size;
+ if (named) {
+ bv.putShort(cw.newUTF8(name));
+ }
+ // write tag, and reserve space for array size
+ bv.put12('[', 0);
+ return new AnnotationWriter(cw, false, bv, bv, bv.length - 2);
+ }
+
+ @Override
+ public void visitEnd() {
+ if (parent != null) {
+ byte[] data = parent.data;
+ data[offset] = (byte) (size >>> 8);
+ data[offset + 1] = (byte) size;
+ }
+ }
+
+ // ------------------------------------------------------------------------
+ // Utility methods
+ // ------------------------------------------------------------------------
+
+ /**
+ * Returns the size of this annotation writer list.
+ *
+ * @return the size of this annotation writer list.
+ */
+ int getSize() {
+ int size = 0;
+ AnnotationWriter aw = this;
+ while (aw != null) {
+ size += aw.bv.length;
+ aw = aw.next;
+ }
+ return size;
+ }
+
+ /**
+ * Puts the annotations of this annotation writer list into the given byte vector.
+ *
+ * @param out where the annotations must be put.
+ */
+ void put(final ByteVector out) {
+ int n = 0;
+ int size = 2;
+ AnnotationWriter aw = this;
+ AnnotationWriter last = null;
+ while (aw != null) {
+ ++n;
+ size += aw.bv.length;
+ aw.visitEnd(); // in case user forgot to call visitEnd
+ aw.prev = last;
+ last = aw;
+ aw = aw.next;
+ }
+ out.putInt(size);
+ out.putShort(n);
+ aw = last;
+ while (aw != null) {
+ out.putByteArray(aw.bv.data, 0, aw.bv.length);
+ aw = aw.prev;
+ }
+ }
+
+ /**
+ * Puts the given annotation lists into the given byte vector.
+ *
+ * @param panns an array of annotation writer lists.
+ * @param off index of the first annotation to be written.
+ * @param out where the annotations must be put.
+ */
+ static void put(final AnnotationWriter[] panns, final int off, final ByteVector out) {
+ int size = 1 + 2 * (panns.length - off);
+ for (int i = off; i < panns.length; ++i) {
+ size += panns[i] == null ? 0 : panns[i].getSize();
+ }
+ out.putInt(size).putByte(panns.length - off);
+ for (int i = off; i < panns.length; ++i) {
+ AnnotationWriter aw = panns[i];
+ AnnotationWriter last = null;
+ int n = 0;
+ while (aw != null) {
+ ++n;
+ aw.visitEnd(); // in case user forgot to call visitEnd
+ aw.prev = last;
+ last = aw;
+ aw = aw.next;
+ }
+ out.putShort(n);
+ aw = last;
+ while (aw != null) {
+ out.putByteArray(aw.bv.data, 0, aw.bv.length);
+ aw = aw.prev;
+ }
+ }
+ }
+
+ /**
+ * Puts the given type reference and type path into the given bytevector. LOCAL_VARIABLE and RESOURCE_VARIABLE
+ * target types are not supported.
+ *
+ * @param typeRef a reference to the annotated type. See {@link TypeReference}.
+ * @param typePath the path to the annotated type argument, wildcard bound, array element type, or static inner type
+ * within 'typeRef'. May be <tt>null</tt> if the annotation targets 'typeRef' as a whole.
+ * @param out where the type reference and type path must be put.
+ */
+ static void putTarget(int typeRef, TypePath typePath, ByteVector out) {
+ switch (typeRef >>> 24) {
+ case 0x00: // CLASS_TYPE_PARAMETER
+ case 0x01: // METHOD_TYPE_PARAMETER
+ case 0x16: // METHOD_FORMAL_PARAMETER
+ out.putShort(typeRef >>> 16);
+ break;
+ case 0x13: // FIELD
+ case 0x14: // METHOD_RETURN
+ case 0x15: // METHOD_RECEIVER
+ out.putByte(typeRef >>> 24);
+ break;
+ case 0x47: // CAST
+ case 0x48: // CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
+ case 0x49: // METHOD_INVOCATION_TYPE_ARGUMENT
+ case 0x4A: // CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
+ case 0x4B: // METHOD_REFERENCE_TYPE_ARGUMENT
+ out.putInt(typeRef);
+ break;
+ // case 0x10: // CLASS_EXTENDS
+ // case 0x11: // CLASS_TYPE_PARAMETER_BOUND
+ // case 0x12: // METHOD_TYPE_PARAMETER_BOUND
+ // case 0x17: // THROWS
+ // case 0x42: // EXCEPTION_PARAMETER
+ // case 0x43: // INSTANCEOF
+ // case 0x44: // NEW
+ // case 0x45: // CONSTRUCTOR_REFERENCE
+ // case 0x46: // METHOD_REFERENCE
+ default:
+ out.put12(typeRef >>> 24, (typeRef & 0xFFFF00) >> 8);
+ break;
+ }
+ if (typePath == null) {
+ out.putByte(0);
+ } else {
+ int length = typePath.b[typePath.offset] * 2 + 1;
+ out.putByteArray(typePath.b, typePath.offset, length);
+ }
+ }
+}
diff --git a/src/main/java/org/redkale/asm/AsmMethodBean.java b/src/main/java/org/redkale/asm/AsmMethodBean.java
index 77ab704bd..3fd003e59 100644
--- a/src/main/java/org/redkale/asm/AsmMethodBean.java
+++ b/src/main/java/org/redkale/asm/AsmMethodBean.java
@@ -1,140 +1,140 @@
-/*
- *
- */
-package org.redkale.asm;
-
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import org.redkale.convert.json.JsonConvert;
-
-/**
- * 存放方法的字节信息
- *
- * @see org.redkale.asm.AsmMethodBoost
- * @since 2.8.0
- */
-public class AsmMethodBean {
-
- private List 详情见: https://redkale.org
- *
- * @author zhangjx
- * @since 2.8.0
- */
-public final class Asms {
-
- private Asms() {}
-
- public static Handle createLambdaMetaHandle() {
- return new Handle(
- Opcodes.H_INVOKESTATIC,
- "java/lang/invoke/LambdaMetafactory",
- "metafactory",
- "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;",
- false);
- }
-
- public static void visitAnnotation(final AnnotationVisitor av, final Annotation ann) {
- try {
- for (Method anm : ann.annotationType().getMethods()) {
- final String mname = anm.getName();
- if ("equals".equals(mname)
- || "hashCode".equals(mname)
- || "toString".equals(mname)
- || "annotationType".equals(mname)) {
- continue;
- }
- final Object r = anm.invoke(ann);
- if (r instanceof String[]) {
- AnnotationVisitor av1 = av.visitArray(mname);
- for (String item : (String[]) r) {
- av1.visit(null, item);
- }
- av1.visitEnd();
- } else if (r instanceof Class[]) {
- AnnotationVisitor av1 = av.visitArray(mname);
- for (Class item : (Class[]) r) {
- av1.visit(null, Type.getType(item));
- }
- av1.visitEnd();
- } else if (r instanceof Enum[]) {
- AnnotationVisitor av1 = av.visitArray(mname);
- for (Enum item : (Enum[]) r) {
- av1.visitEnum(null, Type.getDescriptor(item.getClass()), ((Enum) item).name());
- }
- av1.visitEnd();
- } else if (r instanceof Annotation[]) {
- AnnotationVisitor av1 = av.visitArray(mname);
- for (Annotation item : (Annotation[]) r) {
- visitAnnotation(
- av1.visitAnnotation(null, Type.getDescriptor(((Annotation) item).annotationType())),
- item);
- }
- av1.visitEnd();
- } else if (r instanceof Class) {
- av.visit(mname, Type.getType((Class) r));
- } else if (r instanceof Enum) {
- av.visitEnum(mname, Type.getDescriptor(r.getClass()), ((Enum) r).name());
- } else if (r instanceof Annotation) {
- visitAnnotation(
- av.visitAnnotation(null, Type.getDescriptor(((Annotation) r).annotationType())),
- (Annotation) r);
- } else {
- av.visit(mname, r);
- }
- }
- av.visitEnd();
- } catch (Exception e) {
- throw new RedkaleException(e);
- }
- }
-
- public static void visitInsn(MethodVisitor mv, int num) {
- if (num < 6) {
- mv.visitInsn(ICONST_0 + num);
- } else if (num <= Byte.MAX_VALUE) {
- mv.visitIntInsn(BIPUSH, num);
- } else if (num <= Short.MAX_VALUE) {
- mv.visitIntInsn(SIPUSH, num);
- } else {
- mv.visitLdcInsn(num);
- }
- }
-
- public static void visitFieldInsn(MethodVisitor mv, Class clazz) {
- if (clazz == boolean.class) {
- mv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", "TYPE", "Ljava/lang/Class;");
- } else if (clazz == byte.class) {
- mv.visitFieldInsn(GETSTATIC, "java/lang/Byte", "TYPE", "Ljava/lang/Class;");
- } else if (clazz == char.class) {
- mv.visitFieldInsn(GETSTATIC, "java/lang/Character", "TYPE", "Ljava/lang/Class;");
- } else if (clazz == short.class) {
- mv.visitFieldInsn(GETSTATIC, "java/lang/Short", "TYPE", "Ljava/lang/Class;");
- } else if (clazz == int.class) {
- mv.visitFieldInsn(GETSTATIC, "java/lang/Integer", "TYPE", "Ljava/lang/Class;");
- } else if (clazz == float.class) {
- mv.visitFieldInsn(GETSTATIC, "java/lang/Float", "TYPE", "Ljava/lang/Class;");
- } else if (clazz == long.class) {
- mv.visitFieldInsn(GETSTATIC, "java/lang/Long", "TYPE", "Ljava/lang/Class;");
- } else if (clazz == double.class) {
- mv.visitFieldInsn(GETSTATIC, "java/lang/Double", "TYPE", "Ljava/lang/Class;");
- } else {
- mv.visitLdcInsn(Type.getType(Type.getDescriptor(clazz)));
- }
- }
-
- public static void visitPrimitiveValueOf(MethodVisitor mv, Class clazz) {
- if (clazz == boolean.class) {
- mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", false);
- } else if (clazz == byte.class) {
- mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;", false);
- } else if (clazz == short.class) {
- mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;", false);
- } else if (clazz == char.class) {
- mv.visitMethodInsn(INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;", false);
- } else if (clazz == int.class) {
- mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false);
- } else if (clazz == float.class) {
- mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;", false);
- } else if (clazz == long.class) {
- mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;", false);
- } else if (clazz == double.class) {
- mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;", false);
- }
- }
-
- public static void visitCheckCast(MethodVisitor mv, Class clazz) {
- if (clazz == boolean.class) {
- mv.visitTypeInsn(CHECKCAST, "java/lang/Boolean");
- mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z", false);
- } else if (clazz == byte.class) {
- mv.visitTypeInsn(CHECKCAST, "java/lang/Byte");
- mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B", false);
- } else if (clazz == short.class) {
- mv.visitTypeInsn(CHECKCAST, "java/lang/Short");
- mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S", false);
- } else if (clazz == char.class) {
- mv.visitTypeInsn(CHECKCAST, "java/lang/Character");
- mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C", false);
- } else if (clazz == int.class) {
- mv.visitTypeInsn(CHECKCAST, "java/lang/Integer");
- mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false);
- } else if (clazz == float.class) {
- mv.visitTypeInsn(CHECKCAST, "java/lang/Float");
- mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F", false);
- } else if (clazz == long.class) {
- mv.visitTypeInsn(CHECKCAST, "java/lang/Long");
- mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J", false);
- } else if (clazz == double.class) {
- mv.visitTypeInsn(CHECKCAST, "java/lang/Double");
- mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D", false);
- } else {
- mv.visitTypeInsn(CHECKCAST, clazz.getName().replace('.', '/'));
- }
- }
-
- public static void visitPrimitiveVirtual(MethodVisitor mv, Class clazz) {
- if (clazz == boolean.class) {
- mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z", false);
- } else if (clazz == byte.class) {
- mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B", false);
- } else if (clazz == short.class) {
- mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S", false);
- } else if (clazz == char.class) {
- mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C", false);
- } else if (clazz == int.class) {
- mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false);
- } else if (clazz == float.class) {
- mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F", false);
- } else if (clazz == long.class) {
- mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J", false);
- } else if (clazz == double.class) {
- mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D", false);
- }
- }
-}
+/*
+ *
+ */
+package org.redkale.asm;
+
+import static org.redkale.asm.Opcodes.BIPUSH;
+import static org.redkale.asm.Opcodes.CHECKCAST;
+import static org.redkale.asm.Opcodes.GETSTATIC;
+import static org.redkale.asm.Opcodes.ICONST_0;
+import static org.redkale.asm.Opcodes.INVOKESTATIC;
+import static org.redkale.asm.Opcodes.INVOKEVIRTUAL;
+import static org.redkale.asm.Opcodes.SIPUSH;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import org.redkale.util.RedkaleException;
+
+/**
+ * ASM简单的工具方法 详情见: https://redkale.org
+ *
+ * @author zhangjx
+ * @since 2.8.0
+ */
+public final class Asms {
+
+ private Asms() {}
+
+ public static Handle createLambdaMetaHandle() {
+ return new Handle(
+ Opcodes.H_INVOKESTATIC,
+ "java/lang/invoke/LambdaMetafactory",
+ "metafactory",
+ "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;",
+ false);
+ }
+
+ public static void visitAnnotation(final AnnotationVisitor av, final Annotation ann) {
+ try {
+ for (Method anm : ann.annotationType().getMethods()) {
+ final String mname = anm.getName();
+ if ("equals".equals(mname)
+ || "hashCode".equals(mname)
+ || "toString".equals(mname)
+ || "annotationType".equals(mname)) {
+ continue;
+ }
+ final Object r = anm.invoke(ann);
+ if (r instanceof String[]) {
+ AnnotationVisitor av1 = av.visitArray(mname);
+ for (String item : (String[]) r) {
+ av1.visit(null, item);
+ }
+ av1.visitEnd();
+ } else if (r instanceof Class[]) {
+ AnnotationVisitor av1 = av.visitArray(mname);
+ for (Class item : (Class[]) r) {
+ av1.visit(null, Type.getType(item));
+ }
+ av1.visitEnd();
+ } else if (r instanceof Enum[]) {
+ AnnotationVisitor av1 = av.visitArray(mname);
+ for (Enum item : (Enum[]) r) {
+ av1.visitEnum(null, Type.getDescriptor(item.getClass()), ((Enum) item).name());
+ }
+ av1.visitEnd();
+ } else if (r instanceof Annotation[]) {
+ AnnotationVisitor av1 = av.visitArray(mname);
+ for (Annotation item : (Annotation[]) r) {
+ visitAnnotation(
+ av1.visitAnnotation(null, Type.getDescriptor(((Annotation) item).annotationType())),
+ item);
+ }
+ av1.visitEnd();
+ } else if (r instanceof Class) {
+ av.visit(mname, Type.getType((Class) r));
+ } else if (r instanceof Enum) {
+ av.visitEnum(mname, Type.getDescriptor(r.getClass()), ((Enum) r).name());
+ } else if (r instanceof Annotation) {
+ visitAnnotation(
+ av.visitAnnotation(null, Type.getDescriptor(((Annotation) r).annotationType())),
+ (Annotation) r);
+ } else {
+ av.visit(mname, r);
+ }
+ }
+ av.visitEnd();
+ } catch (Exception e) {
+ throw new RedkaleException(e);
+ }
+ }
+
+ public static void visitInsn(MethodVisitor mv, int num) {
+ if (num < 6) {
+ mv.visitInsn(ICONST_0 + num);
+ } else if (num <= Byte.MAX_VALUE) {
+ mv.visitIntInsn(BIPUSH, num);
+ } else if (num <= Short.MAX_VALUE) {
+ mv.visitIntInsn(SIPUSH, num);
+ } else {
+ mv.visitLdcInsn(num);
+ }
+ }
+
+ public static void visitFieldInsn(MethodVisitor mv, Class clazz) {
+ if (clazz == boolean.class) {
+ mv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", "TYPE", "Ljava/lang/Class;");
+ } else if (clazz == byte.class) {
+ mv.visitFieldInsn(GETSTATIC, "java/lang/Byte", "TYPE", "Ljava/lang/Class;");
+ } else if (clazz == char.class) {
+ mv.visitFieldInsn(GETSTATIC, "java/lang/Character", "TYPE", "Ljava/lang/Class;");
+ } else if (clazz == short.class) {
+ mv.visitFieldInsn(GETSTATIC, "java/lang/Short", "TYPE", "Ljava/lang/Class;");
+ } else if (clazz == int.class) {
+ mv.visitFieldInsn(GETSTATIC, "java/lang/Integer", "TYPE", "Ljava/lang/Class;");
+ } else if (clazz == float.class) {
+ mv.visitFieldInsn(GETSTATIC, "java/lang/Float", "TYPE", "Ljava/lang/Class;");
+ } else if (clazz == long.class) {
+ mv.visitFieldInsn(GETSTATIC, "java/lang/Long", "TYPE", "Ljava/lang/Class;");
+ } else if (clazz == double.class) {
+ mv.visitFieldInsn(GETSTATIC, "java/lang/Double", "TYPE", "Ljava/lang/Class;");
+ } else {
+ mv.visitLdcInsn(Type.getType(Type.getDescriptor(clazz)));
+ }
+ }
+
+ public static void visitPrimitiveValueOf(MethodVisitor mv, Class clazz) {
+ if (clazz == boolean.class) {
+ mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", false);
+ } else if (clazz == byte.class) {
+ mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;", false);
+ } else if (clazz == short.class) {
+ mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;", false);
+ } else if (clazz == char.class) {
+ mv.visitMethodInsn(INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;", false);
+ } else if (clazz == int.class) {
+ mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false);
+ } else if (clazz == float.class) {
+ mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;", false);
+ } else if (clazz == long.class) {
+ mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;", false);
+ } else if (clazz == double.class) {
+ mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;", false);
+ }
+ }
+
+ public static void visitCheckCast(MethodVisitor mv, Class clazz) {
+ if (clazz == boolean.class) {
+ mv.visitTypeInsn(CHECKCAST, "java/lang/Boolean");
+ mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z", false);
+ } else if (clazz == byte.class) {
+ mv.visitTypeInsn(CHECKCAST, "java/lang/Byte");
+ mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B", false);
+ } else if (clazz == short.class) {
+ mv.visitTypeInsn(CHECKCAST, "java/lang/Short");
+ mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S", false);
+ } else if (clazz == char.class) {
+ mv.visitTypeInsn(CHECKCAST, "java/lang/Character");
+ mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C", false);
+ } else if (clazz == int.class) {
+ mv.visitTypeInsn(CHECKCAST, "java/lang/Integer");
+ mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false);
+ } else if (clazz == float.class) {
+ mv.visitTypeInsn(CHECKCAST, "java/lang/Float");
+ mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F", false);
+ } else if (clazz == long.class) {
+ mv.visitTypeInsn(CHECKCAST, "java/lang/Long");
+ mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J", false);
+ } else if (clazz == double.class) {
+ mv.visitTypeInsn(CHECKCAST, "java/lang/Double");
+ mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D", false);
+ } else {
+ mv.visitTypeInsn(CHECKCAST, clazz.getName().replace('.', '/'));
+ }
+ }
+
+ public static void visitPrimitiveVirtual(MethodVisitor mv, Class clazz) {
+ if (clazz == boolean.class) {
+ mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z", false);
+ } else if (clazz == byte.class) {
+ mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B", false);
+ } else if (clazz == short.class) {
+ mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S", false);
+ } else if (clazz == char.class) {
+ mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C", false);
+ } else if (clazz == int.class) {
+ mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false);
+ } else if (clazz == float.class) {
+ mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F", false);
+ } else if (clazz == long.class) {
+ mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J", false);
+ } else if (clazz == double.class) {
+ mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D", false);
+ }
+ }
+}
diff --git a/src/main/java/org/redkale/asm/Attribute.java b/src/main/java/org/redkale/asm/Attribute.java
index 20ef03d5a..0cf206b99 100644
--- a/src/main/java/org/redkale/asm/Attribute.java
+++ b/src/main/java/org/redkale/asm/Attribute.java
@@ -1,312 +1,312 @@
-/*
- * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- */
-
-/*
- *
- *
- *
- *
- *
- * ASM: a very small and fast Java bytecode manipulation framework
- * Copyright (c) 2000-2011 INRIA, France Telecom
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-package org.redkale.asm;
-
-import java.util.Arrays;
-
-/**
- * A non standard class, field, method or code attribute.
- *
- * @author Eric Bruneton
- * @author Eugene Kuleshov
- */
-public class Attribute {
-
- /** The type of this attribute. */
- public final String type;
-
- /** The raw value of this attribute, used only for unknown attributes. */
- byte[] value;
-
- /** The next attribute in this attribute list. May be <tt>null</tt>. */
- Attribute next;
-
- /**
- * Constructs a new empty attribute.
- *
- * @param type the type of the attribute.
- */
- protected Attribute(final String type) {
- this.type = type;
- }
-
- /**
- * Returns <tt>true</tt> if this type of attribute is unknown. The default implementation of this
- * method always returns <tt>true</tt>.
- *
- * @return <tt>true</tt> if this type of attribute is unknown.
- */
- public boolean isUnknown() {
- return true;
- }
-
- /**
- * Returns <tt>true</tt> if this type of attribute is a code attribute.
- *
- * @return <tt>true</tt> if this type of attribute is a code attribute.
- */
- public boolean isCodeAttribute() {
- return false;
- }
-
- /**
- * Returns the labels corresponding to this attribute.
- *
- * @return the labels corresponding to this attribute, or <tt>null</tt> if this attribute is not a
- * code attribute that contains labels.
- */
- protected Label[] getLabels() {
- return null;
- }
-
- /**
- * Reads a {@link #type type} attribute. This method must return a new {@link Attribute} object, of type
- * {@link #type type}, corresponding to the <tt>len</tt> bytes starting at the given offset, in the
- * given class reader.
- *
- * @param cr the class that contains the attribute to be read.
- * @param off index of the first byte of the attribute's content in {@link ClassReader#b cr.b}. The 6 attribute
- * header bytes, containing the type and the length of the attribute, are not taken into account here.
- * @param len the length of the attribute's content.
- * @param buf buffer to be used to call {@link ClassReader#readUTF8 readUTF8},
- * {@link ClassReader#readClass(int,char[]) readClass} or {@link ClassReader#readConst readConst}.
- * @param codeOff index of the first byte of code's attribute content in {@link ClassReader#b cr.b}, or -1 if the
- * attribute to be read is not a code attribute. The 6 attribute header bytes, containing the type and the
- * length of the attribute, are not taken into account here.
- * @param labels the labels of the method's code, or <tt>null</tt> if the attribute to be read is
- * not a code attribute.
- * @return a new {@link Attribute} object corresponding to the given bytes.
- */
- protected Attribute read(
- final ClassReader cr,
- final int off,
- final int len,
- final char[] buf,
- final int codeOff,
- final Label[] labels) {
- Attribute attr = new Attribute(type);
- attr.value = new byte[len];
- System.arraycopy(cr.b, off, attr.value, 0, len);
- return attr;
- }
-
- /**
- * Returns the byte array form of this attribute.
- *
- * @param cw the class to which this attribute must be added. This parameter can be used to add to the constant pool
- * of this class the items that corresponds to this attribute.
- * @param code the bytecode of the method corresponding to this code attribute, or <tt>null</tt> if
- * this attribute is not a code attributes.
- * @param len the length of the bytecode of the method corresponding to this code attribute, or
- * <tt>null</tt> if this attribute is not a code attribute.
- * @param maxStack the maximum stack size of the method corresponding to this code attribute, or -1 if this
- * attribute is not a code attribute.
- * @param maxLocals the maximum number of local variables of the method corresponding to this code attribute, or -1
- * if this attribute is not a code attribute.
- * @return the byte array form of this attribute.
- */
- protected ByteVector write(
- final ClassWriter cw, final byte[] code, final int len, final int maxStack, final int maxLocals) {
- ByteVector v = new ByteVector();
- v.data = value;
- v.length = value.length;
- return v;
- }
-
- /**
- * Returns the length of the attribute list that begins with this attribute.
- *
- * @return the length of the attribute list that begins with this attribute.
- */
- final int getCount() {
- int count = 0;
- Attribute attr = this;
- while (attr != null) {
- count += 1;
- attr = attr.next;
- }
- return count;
- }
-
- /**
- * Returns the size of all the attributes in this attribute list.
- *
- * @param cw the class writer to be used to convert the attributes into byte arrays, with the {@link #write write}
- * method.
- * @param code the bytecode of the method corresponding to these code attributes, or <tt>null</tt>
- * if these attributes are not code attributes.
- * @param len the length of the bytecode of the method corresponding to these code attributes, or
- * <tt>null</tt> if these attributes are not code attributes.
- * @param maxStack the maximum stack size of the method corresponding to these code attributes, or -1 if these
- * attributes are not code attributes.
- * @param maxLocals the maximum number of local variables of the method corresponding to these code attributes, or
- * -1 if these attributes are not code attributes.
- * @return the size of all the attributes in this attribute list. This size includes the size of the attribute
- * headers.
- */
- final int getSize(final ClassWriter cw, final byte[] code, final int len, final int maxStack, final int maxLocals) {
- Attribute attr = this;
- int size = 0;
- while (attr != null) {
- cw.newUTF8(attr.type);
- size += attr.write(cw, code, len, maxStack, maxLocals).length + 6;
- attr = attr.next;
- }
- return size;
- }
-
- /**
- * Writes all the attributes of this attribute list in the given byte vector.
- *
- * @param cw the class writer to be used to convert the attributes into byte arrays, with the {@link #write write}
- * method.
- * @param code the bytecode of the method corresponding to these code attributes, or <tt>null</tt>
- * if these attributes are not code attributes.
- * @param len the length of the bytecode of the method corresponding to these code attributes, or
- * <tt>null</tt> if these attributes are not code attributes.
- * @param maxStack the maximum stack size of the method corresponding to these code attributes, or -1 if these
- * attributes are not code attributes.
- * @param maxLocals the maximum number of local variables of the method corresponding to these code attributes, or
- * -1 if these attributes are not code attributes.
- * @param out where the attributes must be written.
- */
- final void put(
- final ClassWriter cw,
- final byte[] code,
- final int len,
- final int maxStack,
- final int maxLocals,
- final ByteVector out) {
- Attribute attr = this;
- while (attr != null) {
- ByteVector b = attr.write(cw, code, len, maxStack, maxLocals);
- out.putShort(cw.newUTF8(attr.type)).putInt(b.length);
- out.putByteArray(b.data, 0, b.length);
- attr = attr.next;
- }
- }
-
- // The stuff below is temporary - once proper support for nestmate attribute has been added, it can be safely
- // removed.
- // see also changes in ClassReader.accept.
- /** */
- public static class NestMembers extends Attribute {
- /** */
- public NestMembers() {
- super("NestMembers");
- }
-
- byte[] bytes;
- String[] classes;
-
- @Override
- protected Attribute read(ClassReader cr, int off, int len, char[] buf, int codeOff, Label[] labels) {
- int offset = off;
- NestMembers a = new NestMembers();
- int size = cr.readShort(off);
- a.classes = new String[size];
- off += 2;
- for (int i = 0; i < size; i++) {
- a.classes[i] = cr.readClass(off, buf);
- off += 2;
- }
- a.bytes = Arrays.copyOfRange(cr.b, offset, offset + len);
- return a;
- }
-
- @Override
- protected ByteVector write(ClassWriter cw, byte[] code, int len, int maxStack, int maxLocals) {
- ByteVector v = new ByteVector(bytes.length);
- v.putShort(classes.length);
- for (String s : classes) {
- v.putShort(cw.newClass(s));
- }
- return v;
- }
- }
-
- /** */
- public static class NestHost extends Attribute {
-
- byte[] bytes;
- String clazz;
- /** */
- public NestHost() {
- super("NestHost");
- }
-
- @Override
- protected Attribute read(ClassReader cr, int off, int len, char[] buf, int codeOff, Label[] labels) {
- int offset = off;
- NestHost a = new NestHost();
- a.clazz = cr.readClass(off, buf);
- a.bytes = Arrays.copyOfRange(cr.b, offset, offset + len);
- return a;
- }
-
- @Override
- protected ByteVector write(ClassWriter cw, byte[] code, int len, int maxStack, int maxLocals) {
- ByteVector v = new ByteVector(bytes.length);
- v.putShort(cw.newClass(clazz));
- return v;
- }
- }
-
- static final Attribute[] DEFAULT_ATTRIBUTE_PROTOS = new Attribute[] {new NestMembers(), new NestHost()};
-}
+/*
+ * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ */
+
+/*
+ *
+ *
+ *
+ *
+ *
+ * ASM: a very small and fast Java bytecode manipulation framework
+ * Copyright (c) 2000-2011 INRIA, France Telecom
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.redkale.asm;
+
+import java.util.Arrays;
+
+/**
+ * A non standard class, field, method or code attribute.
+ *
+ * @author Eric Bruneton
+ * @author Eugene Kuleshov
+ */
+public class Attribute {
+
+ /** The type of this attribute. */
+ public final String type;
+
+ /** The raw value of this attribute, used only for unknown attributes. */
+ byte[] value;
+
+ /** The next attribute in this attribute list. May be <tt>null</tt>. */
+ Attribute next;
+
+ /**
+ * Constructs a new empty attribute.
+ *
+ * @param type the type of the attribute.
+ */
+ protected Attribute(final String type) {
+ this.type = type;
+ }
+
+ /**
+ * Returns <tt>true</tt> if this type of attribute is unknown. The default implementation of this
+ * method always returns <tt>true</tt>.
+ *
+ * @return <tt>true</tt> if this type of attribute is unknown.
+ */
+ public boolean isUnknown() {
+ return true;
+ }
+
+ /**
+ * Returns <tt>true</tt> if this type of attribute is a code attribute.
+ *
+ * @return <tt>true</tt> if this type of attribute is a code attribute.
+ */
+ public boolean isCodeAttribute() {
+ return false;
+ }
+
+ /**
+ * Returns the labels corresponding to this attribute.
+ *
+ * @return the labels corresponding to this attribute, or <tt>null</tt> if this attribute is not a
+ * code attribute that contains labels.
+ */
+ protected Label[] getLabels() {
+ return null;
+ }
+
+ /**
+ * Reads a {@link #type type} attribute. This method must return a new {@link Attribute} object, of type
+ * {@link #type type}, corresponding to the <tt>len</tt> bytes starting at the given offset, in the
+ * given class reader.
+ *
+ * @param cr the class that contains the attribute to be read.
+ * @param off index of the first byte of the attribute's content in {@link ClassReader#b cr.b}. The 6 attribute
+ * header bytes, containing the type and the length of the attribute, are not taken into account here.
+ * @param len the length of the attribute's content.
+ * @param buf buffer to be used to call {@link ClassReader#readUTF8 readUTF8},
+ * {@link ClassReader#readClass(int,char[]) readClass} or {@link ClassReader#readConst readConst}.
+ * @param codeOff index of the first byte of code's attribute content in {@link ClassReader#b cr.b}, or -1 if the
+ * attribute to be read is not a code attribute. The 6 attribute header bytes, containing the type and the
+ * length of the attribute, are not taken into account here.
+ * @param labels the labels of the method's code, or <tt>null</tt> if the attribute to be read is
+ * not a code attribute.
+ * @return a new {@link Attribute} object corresponding to the given bytes.
+ */
+ protected Attribute read(
+ final ClassReader cr,
+ final int off,
+ final int len,
+ final char[] buf,
+ final int codeOff,
+ final Label[] labels) {
+ Attribute attr = new Attribute(type);
+ attr.value = new byte[len];
+ System.arraycopy(cr.b, off, attr.value, 0, len);
+ return attr;
+ }
+
+ /**
+ * Returns the byte array form of this attribute.
+ *
+ * @param cw the class to which this attribute must be added. This parameter can be used to add to the constant pool
+ * of this class the items that corresponds to this attribute.
+ * @param code the bytecode of the method corresponding to this code attribute, or <tt>null</tt> if
+ * this attribute is not a code attributes.
+ * @param len the length of the bytecode of the method corresponding to this code attribute, or
+ * <tt>null</tt> if this attribute is not a code attribute.
+ * @param maxStack the maximum stack size of the method corresponding to this code attribute, or -1 if this
+ * attribute is not a code attribute.
+ * @param maxLocals the maximum number of local variables of the method corresponding to this code attribute, or -1
+ * if this attribute is not a code attribute.
+ * @return the byte array form of this attribute.
+ */
+ protected ByteVector write(
+ final ClassWriter cw, final byte[] code, final int len, final int maxStack, final int maxLocals) {
+ ByteVector v = new ByteVector();
+ v.data = value;
+ v.length = value.length;
+ return v;
+ }
+
+ /**
+ * Returns the length of the attribute list that begins with this attribute.
+ *
+ * @return the length of the attribute list that begins with this attribute.
+ */
+ final int getCount() {
+ int count = 0;
+ Attribute attr = this;
+ while (attr != null) {
+ count += 1;
+ attr = attr.next;
+ }
+ return count;
+ }
+
+ /**
+ * Returns the size of all the attributes in this attribute list.
+ *
+ * @param cw the class writer to be used to convert the attributes into byte arrays, with the {@link #write write}
+ * method.
+ * @param code the bytecode of the method corresponding to these code attributes, or <tt>null</tt>
+ * if these attributes are not code attributes.
+ * @param len the length of the bytecode of the method corresponding to these code attributes, or
+ * <tt>null</tt> if these attributes are not code attributes.
+ * @param maxStack the maximum stack size of the method corresponding to these code attributes, or -1 if these
+ * attributes are not code attributes.
+ * @param maxLocals the maximum number of local variables of the method corresponding to these code attributes, or
+ * -1 if these attributes are not code attributes.
+ * @return the size of all the attributes in this attribute list. This size includes the size of the attribute
+ * headers.
+ */
+ final int getSize(final ClassWriter cw, final byte[] code, final int len, final int maxStack, final int maxLocals) {
+ Attribute attr = this;
+ int size = 0;
+ while (attr != null) {
+ cw.newUTF8(attr.type);
+ size += attr.write(cw, code, len, maxStack, maxLocals).length + 6;
+ attr = attr.next;
+ }
+ return size;
+ }
+
+ /**
+ * Writes all the attributes of this attribute list in the given byte vector.
+ *
+ * @param cw the class writer to be used to convert the attributes into byte arrays, with the {@link #write write}
+ * method.
+ * @param code the bytecode of the method corresponding to these code attributes, or <tt>null</tt>
+ * if these attributes are not code attributes.
+ * @param len the length of the bytecode of the method corresponding to these code attributes, or
+ * <tt>null</tt> if these attributes are not code attributes.
+ * @param maxStack the maximum stack size of the method corresponding to these code attributes, or -1 if these
+ * attributes are not code attributes.
+ * @param maxLocals the maximum number of local variables of the method corresponding to these code attributes, or
+ * -1 if these attributes are not code attributes.
+ * @param out where the attributes must be written.
+ */
+ final void put(
+ final ClassWriter cw,
+ final byte[] code,
+ final int len,
+ final int maxStack,
+ final int maxLocals,
+ final ByteVector out) {
+ Attribute attr = this;
+ while (attr != null) {
+ ByteVector b = attr.write(cw, code, len, maxStack, maxLocals);
+ out.putShort(cw.newUTF8(attr.type)).putInt(b.length);
+ out.putByteArray(b.data, 0, b.length);
+ attr = attr.next;
+ }
+ }
+
+ // The stuff below is temporary - once proper support for nestmate attribute has been added, it can be safely
+ // removed.
+ // see also changes in ClassReader.accept.
+ /** */
+ public static class NestMembers extends Attribute {
+ /** */
+ public NestMembers() {
+ super("NestMembers");
+ }
+
+ byte[] bytes;
+ String[] classes;
+
+ @Override
+ protected Attribute read(ClassReader cr, int off, int len, char[] buf, int codeOff, Label[] labels) {
+ int offset = off;
+ NestMembers a = new NestMembers();
+ int size = cr.readShort(off);
+ a.classes = new String[size];
+ off += 2;
+ for (int i = 0; i < size; i++) {
+ a.classes[i] = cr.readClass(off, buf);
+ off += 2;
+ }
+ a.bytes = Arrays.copyOfRange(cr.b, offset, offset + len);
+ return a;
+ }
+
+ @Override
+ protected ByteVector write(ClassWriter cw, byte[] code, int len, int maxStack, int maxLocals) {
+ ByteVector v = new ByteVector(bytes.length);
+ v.putShort(classes.length);
+ for (String s : classes) {
+ v.putShort(cw.newClass(s));
+ }
+ return v;
+ }
+ }
+
+ /** */
+ public static class NestHost extends Attribute {
+
+ byte[] bytes;
+ String clazz;
+ /** */
+ public NestHost() {
+ super("NestHost");
+ }
+
+ @Override
+ protected Attribute read(ClassReader cr, int off, int len, char[] buf, int codeOff, Label[] labels) {
+ int offset = off;
+ NestHost a = new NestHost();
+ a.clazz = cr.readClass(off, buf);
+ a.bytes = Arrays.copyOfRange(cr.b, offset, offset + len);
+ return a;
+ }
+
+ @Override
+ protected ByteVector write(ClassWriter cw, byte[] code, int len, int maxStack, int maxLocals) {
+ ByteVector v = new ByteVector(bytes.length);
+ v.putShort(cw.newClass(clazz));
+ return v;
+ }
+ }
+
+ static final Attribute[] DEFAULT_ATTRIBUTE_PROTOS = new Attribute[] {new NestMembers(), new NestHost()};
+}
diff --git a/src/main/java/org/redkale/asm/ByteVector.java b/src/main/java/org/redkale/asm/ByteVector.java
index 9341072c6..70840aacd 100644
--- a/src/main/java/org/redkale/asm/ByteVector.java
+++ b/src/main/java/org/redkale/asm/ByteVector.java
@@ -1,331 +1,331 @@
-/*
- * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- */
-
-/*
- *
- *
- *
- *
- *
- * ASM: a very small and fast Java bytecode manipulation framework
- * Copyright (c) 2000-2011 INRIA, France Telecom
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-package org.redkale.asm;
-
-/**
- * A dynamically extensible vector of bytes. This class is roughly equivalent to a DataOutputStream on top of a
- * ByteArrayOutputStream, but is more efficient.
- *
- * @author Eric Bruneton
- */
-public class ByteVector {
-
- /** The content of this vector. */
- byte[] data;
-
- /** Actual number of bytes in this vector. */
- int length;
-
- /** Constructs a new {@link ByteVector ByteVector} with a default initial size. */
- public ByteVector() {
- data = new byte[64];
- }
-
- /**
- * Constructs a new {@link ByteVector ByteVector} with the given initial size.
- *
- * @param initialSize the initial size of the byte vector to be constructed.
- */
- public ByteVector(final int initialSize) {
- data = new byte[initialSize];
- }
-
- /**
- * Puts a byte into this byte vector. The byte vector is automatically enlarged if necessary.
- *
- * @param b a byte.
- * @return this byte vector.
- */
- public ByteVector putByte(final int b) {
- int length = this.length;
- if (length + 1 > data.length) {
- enlarge(1);
- }
- data[length++] = (byte) b;
- this.length = length;
- return this;
- }
-
- /**
- * Puts two bytes into this byte vector. The byte vector is automatically enlarged if necessary.
- *
- * @param b1 a byte.
- * @param b2 another byte.
- * @return this byte vector.
- */
- ByteVector put11(final int b1, final int b2) {
- int length = this.length;
- if (length + 2 > data.length) {
- enlarge(2);
- }
- byte[] data = this.data;
- data[length++] = (byte) b1;
- data[length++] = (byte) b2;
- this.length = length;
- return this;
- }
-
- /**
- * Puts a short into this byte vector. The byte vector is automatically enlarged if necessary.
- *
- * @param s a short.
- * @return this byte vector.
- */
- public ByteVector putShort(final int s) {
- int length = this.length;
- if (length + 2 > data.length) {
- enlarge(2);
- }
- byte[] data = this.data;
- data[length++] = (byte) (s >>> 8);
- data[length++] = (byte) s;
- this.length = length;
- return this;
- }
-
- /**
- * Puts a byte and a short into this byte vector. The byte vector is automatically enlarged if necessary.
- *
- * @param b a byte.
- * @param s a short.
- * @return this byte vector.
- */
- ByteVector put12(final int b, final int s) {
- int length = this.length;
- if (length + 3 > data.length) {
- enlarge(3);
- }
- byte[] data = this.data;
- data[length++] = (byte) b;
- data[length++] = (byte) (s >>> 8);
- data[length++] = (byte) s;
- this.length = length;
- return this;
- }
-
- /**
- * Puts an int into this byte vector. The byte vector is automatically enlarged if necessary.
- *
- * @param i an int.
- * @return this byte vector.
- */
- public ByteVector putInt(final int i) {
- int length = this.length;
- if (length + 4 > data.length) {
- enlarge(4);
- }
- byte[] data = this.data;
- data[length++] = (byte) (i >>> 24);
- data[length++] = (byte) (i >>> 16);
- data[length++] = (byte) (i >>> 8);
- data[length++] = (byte) i;
- this.length = length;
- return this;
- }
-
- /**
- * Puts a long into this byte vector. The byte vector is automatically enlarged if necessary.
- *
- * @param l a long.
- * @return this byte vector.
- */
- public ByteVector putLong(final long l) {
- int length = this.length;
- if (length + 8 > data.length) {
- enlarge(8);
- }
- byte[] data = this.data;
- int i = (int) (l >>> 32);
- data[length++] = (byte) (i >>> 24);
- data[length++] = (byte) (i >>> 16);
- data[length++] = (byte) (i >>> 8);
- data[length++] = (byte) i;
- i = (int) l;
- data[length++] = (byte) (i >>> 24);
- data[length++] = (byte) (i >>> 16);
- data[length++] = (byte) (i >>> 8);
- data[length++] = (byte) i;
- this.length = length;
- return this;
- }
-
- /**
- * Puts an UTF8 string into this byte vector. The byte vector is automatically enlarged if necessary.
- *
- * @param s a String whose UTF8 encoded length must be less than 65536.
- * @return this byte vector.
- */
- public ByteVector putUTF8(final String s) {
- int charLength = s.length();
- if (charLength > 65535) {
- throw new IllegalArgumentException();
- }
- int len = length;
- if (len + 2 + charLength > data.length) {
- enlarge(2 + charLength);
- }
- byte[] data = this.data;
- // optimistic algorithm: instead of computing the byte length and then
- // serializing the string (which requires two loops), we assume the byte
- // length is equal to char length (which is the most frequent case), and
- // we start serializing the string right away. During the serialization,
- // if we find that this assumption is wrong, we continue with the
- // general method.
- data[len++] = (byte) (charLength >>> 8);
- data[len++] = (byte) charLength;
- for (int i = 0; i < charLength; ++i) {
- char c = s.charAt(i);
- if (c >= '\001' && c <= '\177') {
- data[len++] = (byte) c;
- } else {
- length = len;
- return encodeUTF8(s, i, 65535);
- }
- }
- length = len;
- return this;
- }
-
- /**
- * Puts an UTF8 string into this byte vector. The byte vector is automatically enlarged if necessary. The string
- * length is encoded in two bytes before the encoded characters, if there is space for that (i.e. if this.length - i
- * - 2 >= 0).
- *
- * @param s the String to encode.
- * @param i the index of the first character to encode. The previous characters are supposed to have already been
- * encoded, using only one byte per character.
- * @param maxByteLength the maximum byte length of the encoded string, including the already encoded characters.
- * @return this byte vector.
- */
- ByteVector encodeUTF8(final String s, int i, int maxByteLength) {
- int charLength = s.length();
- int byteLength = i;
- char c;
- for (int j = i; j < charLength; ++j) {
- c = s.charAt(j);
- if (c >= '\001' && c <= '\177') {
- byteLength++;
- } else if (c > '\u07FF') {
- byteLength += 3;
- } else {
- byteLength += 2;
- }
- }
- if (byteLength > maxByteLength) {
- throw new IllegalArgumentException();
- }
- int start = length - i - 2;
- if (start >= 0) {
- data[start] = (byte) (byteLength >>> 8);
- data[start + 1] = (byte) byteLength;
- }
- if (length + byteLength - i > data.length) {
- enlarge(byteLength - i);
- }
- int len = length;
- for (int j = i; j < charLength; ++j) {
- c = s.charAt(j);
- if (c >= '\001' && c <= '\177') {
- data[len++] = (byte) c;
- } else if (c > '\u07FF') {
- data[len++] = (byte) (0xE0 | c >> 12 & 0xF);
- data[len++] = (byte) (0x80 | c >> 6 & 0x3F);
- data[len++] = (byte) (0x80 | c & 0x3F);
- } else {
- data[len++] = (byte) (0xC0 | c >> 6 & 0x1F);
- data[len++] = (byte) (0x80 | c & 0x3F);
- }
- }
- length = len;
- return this;
- }
-
- /**
- * Puts an array of bytes into this byte vector. The byte vector is automatically enlarged if necessary.
- *
- * @param b an array of bytes. May be <tt>null</tt> to put <tt>len</tt> null bytes
- * into this byte vector.
- * @param off index of the fist byte of b that must be copied.
- * @param len number of bytes of b that must be copied.
- * @return this byte vector.
- */
- public ByteVector putByteArray(final byte[] b, final int off, final int len) {
- if (length + len > data.length) {
- enlarge(len);
- }
- if (b != null) {
- System.arraycopy(b, off, data, length, len);
- }
- length += len;
- return this;
- }
-
- /**
- * Enlarge this byte vector so that it can receive n more bytes.
- *
- * @param size number of additional bytes that this byte vector should be able to receive.
- */
- private void enlarge(final int size) {
- int length1 = 2 * data.length;
- int length2 = length + size;
- byte[] newData = new byte[length1 > length2 ? length1 : length2];
- System.arraycopy(data, 0, newData, 0, length);
- data = newData;
- }
-}
+/*
+ * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ */
+
+/*
+ *
+ *
+ *
+ *
+ *
+ * ASM: a very small and fast Java bytecode manipulation framework
+ * Copyright (c) 2000-2011 INRIA, France Telecom
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.redkale.asm;
+
+/**
+ * A dynamically extensible vector of bytes. This class is roughly equivalent to a DataOutputStream on top of a
+ * ByteArrayOutputStream, but is more efficient.
+ *
+ * @author Eric Bruneton
+ */
+public class ByteVector {
+
+ /** The content of this vector. */
+ byte[] data;
+
+ /** Actual number of bytes in this vector. */
+ int length;
+
+ /** Constructs a new {@link ByteVector ByteVector} with a default initial size. */
+ public ByteVector() {
+ data = new byte[64];
+ }
+
+ /**
+ * Constructs a new {@link ByteVector ByteVector} with the given initial size.
+ *
+ * @param initialSize the initial size of the byte vector to be constructed.
+ */
+ public ByteVector(final int initialSize) {
+ data = new byte[initialSize];
+ }
+
+ /**
+ * Puts a byte into this byte vector. The byte vector is automatically enlarged if necessary.
+ *
+ * @param b a byte.
+ * @return this byte vector.
+ */
+ public ByteVector putByte(final int b) {
+ int length = this.length;
+ if (length + 1 > data.length) {
+ enlarge(1);
+ }
+ data[length++] = (byte) b;
+ this.length = length;
+ return this;
+ }
+
+ /**
+ * Puts two bytes into this byte vector. The byte vector is automatically enlarged if necessary.
+ *
+ * @param b1 a byte.
+ * @param b2 another byte.
+ * @return this byte vector.
+ */
+ ByteVector put11(final int b1, final int b2) {
+ int length = this.length;
+ if (length + 2 > data.length) {
+ enlarge(2);
+ }
+ byte[] data = this.data;
+ data[length++] = (byte) b1;
+ data[length++] = (byte) b2;
+ this.length = length;
+ return this;
+ }
+
+ /**
+ * Puts a short into this byte vector. The byte vector is automatically enlarged if necessary.
+ *
+ * @param s a short.
+ * @return this byte vector.
+ */
+ public ByteVector putShort(final int s) {
+ int length = this.length;
+ if (length + 2 > data.length) {
+ enlarge(2);
+ }
+ byte[] data = this.data;
+ data[length++] = (byte) (s >>> 8);
+ data[length++] = (byte) s;
+ this.length = length;
+ return this;
+ }
+
+ /**
+ * Puts a byte and a short into this byte vector. The byte vector is automatically enlarged if necessary.
+ *
+ * @param b a byte.
+ * @param s a short.
+ * @return this byte vector.
+ */
+ ByteVector put12(final int b, final int s) {
+ int length = this.length;
+ if (length + 3 > data.length) {
+ enlarge(3);
+ }
+ byte[] data = this.data;
+ data[length++] = (byte) b;
+ data[length++] = (byte) (s >>> 8);
+ data[length++] = (byte) s;
+ this.length = length;
+ return this;
+ }
+
+ /**
+ * Puts an int into this byte vector. The byte vector is automatically enlarged if necessary.
+ *
+ * @param i an int.
+ * @return this byte vector.
+ */
+ public ByteVector putInt(final int i) {
+ int length = this.length;
+ if (length + 4 > data.length) {
+ enlarge(4);
+ }
+ byte[] data = this.data;
+ data[length++] = (byte) (i >>> 24);
+ data[length++] = (byte) (i >>> 16);
+ data[length++] = (byte) (i >>> 8);
+ data[length++] = (byte) i;
+ this.length = length;
+ return this;
+ }
+
+ /**
+ * Puts a long into this byte vector. The byte vector is automatically enlarged if necessary.
+ *
+ * @param l a long.
+ * @return this byte vector.
+ */
+ public ByteVector putLong(final long l) {
+ int length = this.length;
+ if (length + 8 > data.length) {
+ enlarge(8);
+ }
+ byte[] data = this.data;
+ int i = (int) (l >>> 32);
+ data[length++] = (byte) (i >>> 24);
+ data[length++] = (byte) (i >>> 16);
+ data[length++] = (byte) (i >>> 8);
+ data[length++] = (byte) i;
+ i = (int) l;
+ data[length++] = (byte) (i >>> 24);
+ data[length++] = (byte) (i >>> 16);
+ data[length++] = (byte) (i >>> 8);
+ data[length++] = (byte) i;
+ this.length = length;
+ return this;
+ }
+
+ /**
+ * Puts an UTF8 string into this byte vector. The byte vector is automatically enlarged if necessary.
+ *
+ * @param s a String whose UTF8 encoded length must be less than 65536.
+ * @return this byte vector.
+ */
+ public ByteVector putUTF8(final String s) {
+ int charLength = s.length();
+ if (charLength > 65535) {
+ throw new IllegalArgumentException();
+ }
+ int len = length;
+ if (len + 2 + charLength > data.length) {
+ enlarge(2 + charLength);
+ }
+ byte[] data = this.data;
+ // optimistic algorithm: instead of computing the byte length and then
+ // serializing the string (which requires two loops), we assume the byte
+ // length is equal to char length (which is the most frequent case), and
+ // we start serializing the string right away. During the serialization,
+ // if we find that this assumption is wrong, we continue with the
+ // general method.
+ data[len++] = (byte) (charLength >>> 8);
+ data[len++] = (byte) charLength;
+ for (int i = 0; i < charLength; ++i) {
+ char c = s.charAt(i);
+ if (c >= '\001' && c <= '\177') {
+ data[len++] = (byte) c;
+ } else {
+ length = len;
+ return encodeUTF8(s, i, 65535);
+ }
+ }
+ length = len;
+ return this;
+ }
+
+ /**
+ * Puts an UTF8 string into this byte vector. The byte vector is automatically enlarged if necessary. The string
+ * length is encoded in two bytes before the encoded characters, if there is space for that (i.e. if this.length - i
+ * - 2 >= 0).
+ *
+ * @param s the String to encode.
+ * @param i the index of the first character to encode. The previous characters are supposed to have already been
+ * encoded, using only one byte per character.
+ * @param maxByteLength the maximum byte length of the encoded string, including the already encoded characters.
+ * @return this byte vector.
+ */
+ ByteVector encodeUTF8(final String s, int i, int maxByteLength) {
+ int charLength = s.length();
+ int byteLength = i;
+ char c;
+ for (int j = i; j < charLength; ++j) {
+ c = s.charAt(j);
+ if (c >= '\001' && c <= '\177') {
+ byteLength++;
+ } else if (c > '\u07FF') {
+ byteLength += 3;
+ } else {
+ byteLength += 2;
+ }
+ }
+ if (byteLength > maxByteLength) {
+ throw new IllegalArgumentException();
+ }
+ int start = length - i - 2;
+ if (start >= 0) {
+ data[start] = (byte) (byteLength >>> 8);
+ data[start + 1] = (byte) byteLength;
+ }
+ if (length + byteLength - i > data.length) {
+ enlarge(byteLength - i);
+ }
+ int len = length;
+ for (int j = i; j < charLength; ++j) {
+ c = s.charAt(j);
+ if (c >= '\001' && c <= '\177') {
+ data[len++] = (byte) c;
+ } else if (c > '\u07FF') {
+ data[len++] = (byte) (0xE0 | c >> 12 & 0xF);
+ data[len++] = (byte) (0x80 | c >> 6 & 0x3F);
+ data[len++] = (byte) (0x80 | c & 0x3F);
+ } else {
+ data[len++] = (byte) (0xC0 | c >> 6 & 0x1F);
+ data[len++] = (byte) (0x80 | c & 0x3F);
+ }
+ }
+ length = len;
+ return this;
+ }
+
+ /**
+ * Puts an array of bytes into this byte vector. The byte vector is automatically enlarged if necessary.
+ *
+ * @param b an array of bytes. May be <tt>null</tt> to put <tt>len</tt> null bytes
+ * into this byte vector.
+ * @param off index of the fist byte of b that must be copied.
+ * @param len number of bytes of b that must be copied.
+ * @return this byte vector.
+ */
+ public ByteVector putByteArray(final byte[] b, final int off, final int len) {
+ if (length + len > data.length) {
+ enlarge(len);
+ }
+ if (b != null) {
+ System.arraycopy(b, off, data, length, len);
+ }
+ length += len;
+ return this;
+ }
+
+ /**
+ * Enlarge this byte vector so that it can receive n more bytes.
+ *
+ * @param size number of additional bytes that this byte vector should be able to receive.
+ */
+ private void enlarge(final int size) {
+ int length1 = 2 * data.length;
+ int length2 = length + size;
+ byte[] newData = new byte[length1 > length2 ? length1 : length2];
+ System.arraycopy(data, 0, newData, 0, length);
+ data = newData;
+ }
+}
diff --git a/src/main/java/org/redkale/asm/ClassReader.java b/src/main/java/org/redkale/asm/ClassReader.java
index 9c0092f45..fd7c0b0e0 100644
--- a/src/main/java/org/redkale/asm/ClassReader.java
+++ b/src/main/java/org/redkale/asm/ClassReader.java
@@ -1,2610 +1,2610 @@
-/*
- * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- */
-
-/*
- *
- *
- *
- *
- *
- * ASM: a very small and fast Java bytecode manipulation framework
- * Copyright (c) 2000-2011 INRIA, France Telecom
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-package org.redkale.asm;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * A Java class parser to make a {@link ClassVisitor} visit an existing class. This class parses a byte array conforming
- * to the Java class file format and calls the appropriate visit methods of a given class visitor for each field, method
- * and bytecode instruction encountered.
- *
- * @author Eric Bruneton
- * @author Eugene Kuleshov
- */
-public class ClassReader {
-
- /**
- * Flag to skip method code. If this class is set When only the maximum stack size is computed, this field is the size of the output stack relatively to the top
- * of the input stack.
- *
- * When the stack map frames are completely computed, this field is the actual number of types in
- * {@link #outputStack}.
- */
- int outputStackTop;
-
- /**
- * Number of types that are initialized in the basic block.
- *
- * @see #initializations
- */
- private int initializationCount;
-
- /**
- * The types that are initialized in the basic block. A constructor invocation on an UNINITIALIZED or
- * UNINITIALIZED_THIS type must replace every occurence of this type in the local variables and in the
- * operand stack. This cannot be done during the first phase of the algorithm since, during this phase, the local
- * variables and the operand stack are not completely computed. It is therefore necessary to store the types on
- * which constructors are invoked in the basic block, in order to do this replacement during the second phase of the
- * algorithm, where the frames are fully computed. Note that this array can contain types that are relative to input
- * locals or to the input stack (see below for the description of the algorithm).
- */
- private int[] initializations;
-
- /**
- * Sets this frame to the given value.
- *
- * @param cw the ClassWriter to which this label belongs.
- * @param nLocal the number of local variables.
- * @param local the local variable types. Primitive types are represented by {@link Opcodes#TOP},
- * {@link Opcodes#INTEGER}, {@link Opcodes#FLOAT}, {@link Opcodes#LONG},
- * {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or {@link Opcodes#UNINITIALIZED_THIS} (long and double are
- * represented by a single element). Reference types are represented by String objects (representing internal
- * names), and uninitialized types by Label objects (this label designates the NEW instruction that created this
- * uninitialized value).
- * @param nStack the number of operand stack elements.
- * @param stack the operand stack types (same format as the "local" array).
- */
- final void set(ClassWriter cw, final int nLocal, final Object[] local, final int nStack, final Object[] stack) {
- int i = convert(cw, nLocal, local, inputLocals);
- while (i < local.length) {
- inputLocals[i++] = TOP;
- }
- int nStackTop = 0;
- for (int j = 0; j < nStack; ++j) {
- if (stack[j] == Opcodes.LONG || stack[j] == Opcodes.DOUBLE) {
- ++nStackTop;
- }
- }
- inputStack = new int[nStack + nStackTop];
- convert(cw, nStack, stack, inputStack);
- outputStackTop = 0;
- initializationCount = 0;
- }
-
- /**
- * Converts types from the MethodWriter.visitFrame() format to the Frame format.
- *
- * @param cw the ClassWriter to which this label belongs.
- * @param nInput the number of types to convert.
- * @param input the types to convert. Primitive types are represented by {@link Opcodes#TOP},
- * {@link Opcodes#INTEGER}, {@link Opcodes#FLOAT}, {@link Opcodes#LONG},
- * {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or {@link Opcodes#UNINITIALIZED_THIS} (long and double are
- * represented by a single element). Reference types are represented by String objects (representing internal
- * names), and uninitialized types by Label objects (this label designates the NEW instruction that created this
- * uninitialized value).
- * @param output where to store the converted types.
- * @return the number of output elements.
- */
- private static int convert(ClassWriter cw, int nInput, Object[] input, int[] output) {
- int i = 0;
- for (int j = 0; j < nInput; ++j) {
- if (input[j] instanceof Integer) {
- output[i++] = BASE | ((Integer) input[j]).intValue();
- if (input[j] == Opcodes.LONG || input[j] == Opcodes.DOUBLE) {
- output[i++] = TOP;
- }
- } else if (input[j] instanceof String) {
- output[i++] = type(cw, Type.getObjectType((String) input[j]).getDescriptor());
- } else {
- output[i++] = UNINITIALIZED | cw.addUninitializedType("", ((Label) input[j]).position);
- }
- }
- return i;
- }
-
- /**
- * Sets this frame to the value of the given frame. WARNING: after this method is called the two frames share the
- * same data structures. It is recommended to discard the given frame f to avoid unexpected side effects.
- *
- * @param f The new frame value.
- */
- final void set(final Frame f) {
- inputLocals = f.inputLocals;
- inputStack = f.inputStack;
- outputLocals = f.outputLocals;
- outputStack = f.outputStack;
- outputStackTop = f.outputStackTop;
- initializationCount = f.initializationCount;
- initializations = f.initializations;
- }
-
- /**
- * Returns the output frame local variable type at the given index.
- *
- * @param local the index of the local that must be returned.
- * @return the output frame local variable type at the given index.
- */
- private int get(final int local) {
- if (outputLocals == null || local >= outputLocals.length) {
- // this local has never been assigned in this basic block,
- // so it is still equal to its value in the input frame
- return LOCAL | local;
- } else {
- int type = outputLocals[local];
- if (type == 0) {
- // this local has never been assigned in this basic block,
- // so it is still equal to its value in the input frame
- type = outputLocals[local] = LOCAL | local;
- }
- return type;
- }
- }
-
- /**
- * Sets the output frame local variable type at the given index.
- *
- * @param local the index of the local that must be set.
- * @param type the value of the local that must be set.
- */
- private void set(final int local, final int type) {
- // creates and/or resizes the output local variables array if necessary
- if (outputLocals == null) {
- outputLocals = new int[10];
- }
- int n = outputLocals.length;
- if (local >= n) {
- int[] t = new int[Math.max(local + 1, 2 * n)];
- System.arraycopy(outputLocals, 0, t, 0, n);
- outputLocals = t;
- }
- // sets the local variable
- outputLocals[local] = type;
- }
-
- /**
- * Pushes a new type onto the output frame stack.
- *
- * @param type the type that must be pushed.
- */
- private void push(final int type) {
- // creates and/or resizes the output stack array if necessary
- if (outputStack == null) {
- outputStack = new int[10];
- }
- int n = outputStack.length;
- if (outputStackTop >= n) {
- int[] t = new int[Math.max(outputStackTop + 1, 2 * n)];
- System.arraycopy(outputStack, 0, t, 0, n);
- outputStack = t;
- }
- // pushes the type on the output stack
- outputStack[outputStackTop++] = type;
- // updates the maximum height reached by the output stack, if needed
- int top = owner.inputStackTop + outputStackTop;
- if (top > owner.outputStackMax) {
- owner.outputStackMax = top;
- }
- }
-
- /**
- * Pushes a new type onto the output frame stack.
- *
- * @param cw the ClassWriter to which this label belongs.
- * @param desc the descriptor of the type to be pushed. Can also be a method descriptor (in this case this method
- * pushes its return type onto the output frame stack).
- */
- private void push(final ClassWriter cw, final String desc) {
- int type = type(cw, desc);
- if (type != 0) {
- push(type);
- if (type == LONG || type == DOUBLE) {
- push(TOP);
- }
- }
- }
-
- /**
- * Returns the int encoding of the given type.
- *
- * @param cw the ClassWriter to which this label belongs.
- * @param desc a type descriptor.
- * @return the int encoding of the given type.
- */
- static int type(final ClassWriter cw, final String desc) {
- String t;
- int index = desc.charAt(0) == '(' ? desc.indexOf(')') + 1 : 0;
- switch (desc.charAt(index)) {
- case 'V':
- return 0;
- case 'Z':
- case 'C':
- case 'B':
- case 'S':
- case 'I':
- return INTEGER;
- case 'F':
- return FLOAT;
- case 'J':
- return LONG;
- case 'D':
- return DOUBLE;
- case 'L':
- // stores the internal name, not the descriptor!
- t = desc.substring(index + 1, desc.length() - 1);
- return OBJECT | cw.addType(t);
- // case '[':
- default:
- // extracts the dimensions and the element type
- int data;
- int dims = index + 1;
- while (desc.charAt(dims) == '[') {
- ++dims;
- }
- switch (desc.charAt(dims)) {
- case 'Z':
- data = BOOLEAN;
- break;
- case 'C':
- data = CHAR;
- break;
- case 'B':
- data = BYTE;
- break;
- case 'S':
- data = SHORT;
- break;
- case 'I':
- data = INTEGER;
- break;
- case 'F':
- data = FLOAT;
- break;
- case 'J':
- data = LONG;
- break;
- case 'D':
- data = DOUBLE;
- break;
- // case 'L':
- default:
- // stores the internal name, not the descriptor
- t = desc.substring(dims + 1, desc.length() - 1);
- data = OBJECT | cw.addType(t);
- }
- return (dims - index) << 28 | data;
- }
- }
-
- /**
- * Pops a type from the output frame stack and returns its value.
- *
- * @return the type that has been popped from the output frame stack.
- */
- private int pop() {
- if (outputStackTop > 0) {
- return outputStack[--outputStackTop];
- } else {
- // if the output frame stack is empty, pops from the input stack
- return STACK | -(--owner.inputStackTop);
- }
- }
-
- /**
- * Pops the given number of types from the output frame stack.
- *
- * @param elements the number of types that must be popped.
- */
- private void pop(final int elements) {
- if (outputStackTop >= elements) {
- outputStackTop -= elements;
- } else {
- // if the number of elements to be popped is greater than the number
- // of elements in the output stack, clear it, and pops the remaining
- // elements from the input stack.
- owner.inputStackTop -= elements - outputStackTop;
- outputStackTop = 0;
- }
- }
-
- /**
- * Pops a type from the output frame stack.
- *
- * @param desc the descriptor of the type to be popped. Can also be a method descriptor (in this case this method
- * pops the types corresponding to the method arguments).
- */
- private void pop(final String desc) {
- char c = desc.charAt(0);
- if (c == '(') {
- pop((Type.getArgumentsAndReturnSizes(desc) >> 2) - 1);
- } else if (c == 'J' || c == 'D') {
- pop(2);
- } else {
- pop(1);
- }
- }
-
- /**
- * Adds a new type to the list of types on which a constructor is invoked in the basic block.
- *
- * @param var a type on a which a constructor is invoked.
- */
- private void init(final int var) {
- // creates and/or resizes the initializations array if necessary
- if (initializations == null) {
- initializations = new int[2];
- }
- int n = initializations.length;
- if (initializationCount >= n) {
- int[] t = new int[Math.max(initializationCount + 1, 2 * n)];
- System.arraycopy(initializations, 0, t, 0, n);
- initializations = t;
- }
- // stores the type to be initialized
- initializations[initializationCount++] = var;
- }
-
- /**
- * Replaces the given type with the appropriate type if it is one of the types on which a constructor is invoked in
- * the basic block.
- *
- * @param cw the ClassWriter to which this label belongs.
- * @param t a type
- * @return t or, if t is one of the types on which a constructor is invoked in the basic block, the type
- * corresponding to this constructor.
- */
- private int init(final ClassWriter cw, final int t) {
- int s;
- if (t == UNINITIALIZED_THIS) {
- s = OBJECT | cw.addType(cw.thisName);
- } else if ((t & (DIM | BASE_KIND)) == UNINITIALIZED) {
- String type = cw.typeTable[t & BASE_VALUE].strVal1;
- s = OBJECT | cw.addType(type);
- } else {
- return t;
- }
- for (int j = 0; j < initializationCount; ++j) {
- int u = initializations[j];
- int dim = u & DIM;
- int kind = u & KIND;
- if (kind == LOCAL) {
- u = dim + inputLocals[u & VALUE];
- } else if (kind == STACK) {
- u = dim + inputStack[inputStack.length - (u & VALUE)];
- }
- if (t == u) {
- return s;
- }
- }
- return t;
- }
-
- /**
- * Initializes the input frame of the first basic block from the method descriptor.
- *
- * @param cw the ClassWriter to which this label belongs.
- * @param access the access flags of the method to which this label belongs.
- * @param args the formal parameter types of this method.
- * @param maxLocals the maximum number of local variables of this method.
- */
- final void initInputFrame(final ClassWriter cw, final int access, final Type[] args, final int maxLocals) {
- inputLocals = new int[maxLocals];
- inputStack = new int[0];
- int i = 0;
- if ((access & Opcodes.ACC_STATIC) == 0) {
- if ((access & MethodWriter.ACC_CONSTRUCTOR) == 0) {
- inputLocals[i++] = OBJECT | cw.addType(cw.thisName);
- } else {
- inputLocals[i++] = UNINITIALIZED_THIS;
- }
- }
- for (int j = 0; j < args.length; ++j) {
- int t = type(cw, args[j].getDescriptor());
- inputLocals[i++] = t;
- if (t == LONG || t == DOUBLE) {
- inputLocals[i++] = TOP;
- }
- }
- while (i < maxLocals) {
- inputLocals[i++] = TOP;
- }
- }
-
- /**
- * Simulates the action of the given instruction on the output stack frame.
- *
- * @param opcode the opcode of the instruction.
- * @param arg the operand of the instruction, if any.
- * @param cw the class writer to which this label belongs.
- * @param item the operand of the instructions, if any.
- */
- void execute(final int opcode, final int arg, final ClassWriter cw, final Item item) {
- int t1, t2, t3, t4;
- switch (opcode) {
- case Opcodes.NOP:
- case Opcodes.INEG:
- case Opcodes.LNEG:
- case Opcodes.FNEG:
- case Opcodes.DNEG:
- case Opcodes.I2B:
- case Opcodes.I2C:
- case Opcodes.I2S:
- case Opcodes.GOTO:
- case Opcodes.RETURN:
- break;
- case Opcodes.ACONST_NULL:
- push(NULL);
- break;
- case Opcodes.ICONST_M1:
- case Opcodes.ICONST_0:
- case Opcodes.ICONST_1:
- case Opcodes.ICONST_2:
- case Opcodes.ICONST_3:
- case Opcodes.ICONST_4:
- case Opcodes.ICONST_5:
- case Opcodes.BIPUSH:
- case Opcodes.SIPUSH:
- case Opcodes.ILOAD:
- push(INTEGER);
- break;
- case Opcodes.LCONST_0:
- case Opcodes.LCONST_1:
- case Opcodes.LLOAD:
- push(LONG);
- push(TOP);
- break;
- case Opcodes.FCONST_0:
- case Opcodes.FCONST_1:
- case Opcodes.FCONST_2:
- case Opcodes.FLOAD:
- push(FLOAT);
- break;
- case Opcodes.DCONST_0:
- case Opcodes.DCONST_1:
- case Opcodes.DLOAD:
- push(DOUBLE);
- push(TOP);
- break;
- case Opcodes.LDC:
- switch (item.type) {
- case ClassWriter.INT:
- push(INTEGER);
- break;
- case ClassWriter.LONG:
- push(LONG);
- push(TOP);
- break;
- case ClassWriter.FLOAT:
- push(FLOAT);
- break;
- case ClassWriter.DOUBLE:
- push(DOUBLE);
- push(TOP);
- break;
- case ClassWriter.CLASS:
- push(OBJECT | cw.addType("java/lang/Class"));
- break;
- case ClassWriter.STR:
- push(OBJECT | cw.addType("java/lang/String"));
- break;
- case ClassWriter.MTYPE:
- push(OBJECT | cw.addType("java/lang/invoke/MethodType"));
- break;
- // case ClassWriter.HANDLE_BASE + [1..9]:
- default:
- push(OBJECT | cw.addType("java/lang/invoke/MethodHandle"));
- }
- break;
- case Opcodes.ALOAD:
- push(get(arg));
- break;
- case Opcodes.IALOAD:
- case Opcodes.BALOAD:
- case Opcodes.CALOAD:
- case Opcodes.SALOAD:
- pop(2);
- push(INTEGER);
- break;
- case Opcodes.LALOAD:
- case Opcodes.D2L:
- pop(2);
- push(LONG);
- push(TOP);
- break;
- case Opcodes.FALOAD:
- pop(2);
- push(FLOAT);
- break;
- case Opcodes.DALOAD:
- case Opcodes.L2D:
- pop(2);
- push(DOUBLE);
- push(TOP);
- break;
- case Opcodes.AALOAD:
- pop(1);
- t1 = pop();
- push(t1 == NULL ? t1 : ELEMENT_OF + t1);
- break;
- case Opcodes.ISTORE:
- case Opcodes.FSTORE:
- case Opcodes.ASTORE:
- t1 = pop();
- set(arg, t1);
- if (arg > 0) {
- t2 = get(arg - 1);
- // if t2 is of kind STACK or LOCAL we cannot know its size!
- if (t2 == LONG || t2 == DOUBLE) {
- set(arg - 1, TOP);
- } else if ((t2 & KIND) != BASE) {
- set(arg - 1, t2 | TOP_IF_LONG_OR_DOUBLE);
- }
- }
- break;
- case Opcodes.LSTORE:
- case Opcodes.DSTORE:
- pop(1);
- t1 = pop();
- set(arg, t1);
- set(arg + 1, TOP);
- if (arg > 0) {
- t2 = get(arg - 1);
- // if t2 is of kind STACK or LOCAL we cannot know its size!
- if (t2 == LONG || t2 == DOUBLE) {
- set(arg - 1, TOP);
- } else if ((t2 & KIND) != BASE) {
- set(arg - 1, t2 | TOP_IF_LONG_OR_DOUBLE);
- }
- }
- break;
- case Opcodes.IASTORE:
- case Opcodes.BASTORE:
- case Opcodes.CASTORE:
- case Opcodes.SASTORE:
- case Opcodes.FASTORE:
- case Opcodes.AASTORE:
- pop(3);
- break;
- case Opcodes.LASTORE:
- case Opcodes.DASTORE:
- pop(4);
- break;
- case Opcodes.POP:
- case Opcodes.IFEQ:
- case Opcodes.IFNE:
- case Opcodes.IFLT:
- case Opcodes.IFGE:
- case Opcodes.IFGT:
- case Opcodes.IFLE:
- case Opcodes.IRETURN:
- case Opcodes.FRETURN:
- case Opcodes.ARETURN:
- case Opcodes.TABLESWITCH:
- case Opcodes.LOOKUPSWITCH:
- case Opcodes.ATHROW:
- case Opcodes.MONITORENTER:
- case Opcodes.MONITOREXIT:
- case Opcodes.IFNULL:
- case Opcodes.IFNONNULL:
- pop(1);
- break;
- case Opcodes.POP2:
- case Opcodes.IF_ICMPEQ:
- case Opcodes.IF_ICMPNE:
- case Opcodes.IF_ICMPLT:
- case Opcodes.IF_ICMPGE:
- case Opcodes.IF_ICMPGT:
- case Opcodes.IF_ICMPLE:
- case Opcodes.IF_ACMPEQ:
- case Opcodes.IF_ACMPNE:
- case Opcodes.LRETURN:
- case Opcodes.DRETURN:
- pop(2);
- break;
- case Opcodes.DUP:
- t1 = pop();
- push(t1);
- push(t1);
- break;
- case Opcodes.DUP_X1:
- t1 = pop();
- t2 = pop();
- push(t1);
- push(t2);
- push(t1);
- break;
- case Opcodes.DUP_X2:
- t1 = pop();
- t2 = pop();
- t3 = pop();
- push(t1);
- push(t3);
- push(t2);
- push(t1);
- break;
- case Opcodes.DUP2:
- t1 = pop();
- t2 = pop();
- push(t2);
- push(t1);
- push(t2);
- push(t1);
- break;
- case Opcodes.DUP2_X1:
- t1 = pop();
- t2 = pop();
- t3 = pop();
- push(t2);
- push(t1);
- push(t3);
- push(t2);
- push(t1);
- break;
- case Opcodes.DUP2_X2:
- t1 = pop();
- t2 = pop();
- t3 = pop();
- t4 = pop();
- push(t2);
- push(t1);
- push(t4);
- push(t3);
- push(t2);
- push(t1);
- break;
- case Opcodes.SWAP:
- t1 = pop();
- t2 = pop();
- push(t1);
- push(t2);
- break;
- case Opcodes.IADD:
- case Opcodes.ISUB:
- case Opcodes.IMUL:
- case Opcodes.IDIV:
- case Opcodes.IREM:
- case Opcodes.IAND:
- case Opcodes.IOR:
- case Opcodes.IXOR:
- case Opcodes.ISHL:
- case Opcodes.ISHR:
- case Opcodes.IUSHR:
- case Opcodes.L2I:
- case Opcodes.D2I:
- case Opcodes.FCMPL:
- case Opcodes.FCMPG:
- pop(2);
- push(INTEGER);
- break;
- case Opcodes.LADD:
- case Opcodes.LSUB:
- case Opcodes.LMUL:
- case Opcodes.LDIV:
- case Opcodes.LREM:
- case Opcodes.LAND:
- case Opcodes.LOR:
- case Opcodes.LXOR:
- pop(4);
- push(LONG);
- push(TOP);
- break;
- case Opcodes.FADD:
- case Opcodes.FSUB:
- case Opcodes.FMUL:
- case Opcodes.FDIV:
- case Opcodes.FREM:
- case Opcodes.L2F:
- case Opcodes.D2F:
- pop(2);
- push(FLOAT);
- break;
- case Opcodes.DADD:
- case Opcodes.DSUB:
- case Opcodes.DMUL:
- case Opcodes.DDIV:
- case Opcodes.DREM:
- pop(4);
- push(DOUBLE);
- push(TOP);
- break;
- case Opcodes.LSHL:
- case Opcodes.LSHR:
- case Opcodes.LUSHR:
- pop(3);
- push(LONG);
- push(TOP);
- break;
- case Opcodes.IINC:
- set(arg, INTEGER);
- break;
- case Opcodes.I2L:
- case Opcodes.F2L:
- pop(1);
- push(LONG);
- push(TOP);
- break;
- case Opcodes.I2F:
- pop(1);
- push(FLOAT);
- break;
- case Opcodes.I2D:
- case Opcodes.F2D:
- pop(1);
- push(DOUBLE);
- push(TOP);
- break;
- case Opcodes.F2I:
- case Opcodes.ARRAYLENGTH:
- case Opcodes.INSTANCEOF:
- pop(1);
- push(INTEGER);
- break;
- case Opcodes.LCMP:
- case Opcodes.DCMPL:
- case Opcodes.DCMPG:
- pop(4);
- push(INTEGER);
- break;
- case Opcodes.JSR:
- case Opcodes.RET:
- throw new RuntimeException("JSR/RET are not supported with computeFrames option");
- case Opcodes.GETSTATIC:
- push(cw, item.strVal3);
- break;
- case Opcodes.PUTSTATIC:
- pop(item.strVal3);
- break;
- case Opcodes.GETFIELD:
- pop(1);
- push(cw, item.strVal3);
- break;
- case Opcodes.PUTFIELD:
- pop(item.strVal3);
- pop();
- break;
- case Opcodes.INVOKEVIRTUAL:
- case Opcodes.INVOKESPECIAL:
- case Opcodes.INVOKESTATIC:
- case Opcodes.INVOKEINTERFACE:
- pop(item.strVal3);
- if (opcode != Opcodes.INVOKESTATIC) {
- t1 = pop();
- if (opcode == Opcodes.INVOKESPECIAL && item.strVal2.charAt(0) == '<') {
- init(t1);
- }
- }
- push(cw, item.strVal3);
- break;
- case Opcodes.INVOKEDYNAMIC:
- pop(item.strVal2);
- push(cw, item.strVal2);
- break;
- case Opcodes.NEW:
- push(UNINITIALIZED | cw.addUninitializedType(item.strVal1, arg));
- break;
- case Opcodes.NEWARRAY:
- pop();
- switch (arg) {
- case Opcodes.T_BOOLEAN:
- push(ARRAY_OF | BOOLEAN);
- break;
- case Opcodes.T_CHAR:
- push(ARRAY_OF | CHAR);
- break;
- case Opcodes.T_BYTE:
- push(ARRAY_OF | BYTE);
- break;
- case Opcodes.T_SHORT:
- push(ARRAY_OF | SHORT);
- break;
- case Opcodes.T_INT:
- push(ARRAY_OF | INTEGER);
- break;
- case Opcodes.T_FLOAT:
- push(ARRAY_OF | FLOAT);
- break;
- case Opcodes.T_DOUBLE:
- push(ARRAY_OF | DOUBLE);
- break;
- // case Opcodes.T_LONG:
- default:
- push(ARRAY_OF | LONG);
- break;
- }
- break;
- case Opcodes.ANEWARRAY:
- String s = item.strVal1;
- pop();
- if (s.charAt(0) == '[') {
- push(cw, '[' + s);
- } else {
- push(ARRAY_OF | OBJECT | cw.addType(s));
- }
- break;
- case Opcodes.CHECKCAST:
- s = item.strVal1;
- pop();
- if (s.charAt(0) == '[') {
- push(cw, s);
- } else {
- push(OBJECT | cw.addType(s));
- }
- break;
- // case Opcodes.MULTIANEWARRAY:
- default:
- pop(arg);
- push(cw, item.strVal1);
- break;
- }
- }
-
- /**
- * Merges the input frame of the given basic block with the input and output frames of this basic block. Returns
- * <tt>true</tt> if the input frame of the given label has been changed by this operation.
- *
- * @param cw the ClassWriter to which this label belongs.
- * @param frame the basic block whose input frame must be updated.
- * @param edge the kind of the {@link Edge} between this label and 'label'. See {@link Edge#info}.
- * @return <tt>true</tt> if the input frame of the given label has been changed by this operation.
- */
- final boolean merge(final ClassWriter cw, final Frame frame, final int edge) {
- boolean changed = false;
- int i, s, dim, kind, t;
-
- int nLocal = inputLocals.length;
- int nStack = inputStack.length;
- if (frame.inputLocals == null) {
- frame.inputLocals = new int[nLocal];
- changed = true;
- }
-
- for (i = 0; i < nLocal; ++i) {
- if (outputLocals != null && i < outputLocals.length) {
- s = outputLocals[i];
- if (s == 0) {
- t = inputLocals[i];
- } else {
- dim = s & DIM;
- kind = s & KIND;
- if (kind == BASE) {
- t = s;
- } else {
- if (kind == LOCAL) {
- t = dim + inputLocals[s & VALUE];
- } else {
- t = dim + inputStack[nStack - (s & VALUE)];
- }
- if ((s & TOP_IF_LONG_OR_DOUBLE) != 0 && (t == LONG || t == DOUBLE)) {
- t = TOP;
- }
- }
- }
- } else {
- t = inputLocals[i];
- }
- if (initializations != null) {
- t = init(cw, t);
- }
- changed |= merge(cw, t, frame.inputLocals, i);
- }
-
- if (edge > 0) {
- for (i = 0; i < nLocal; ++i) {
- t = inputLocals[i];
- changed |= merge(cw, t, frame.inputLocals, i);
- }
- if (frame.inputStack == null) {
- frame.inputStack = new int[1];
- changed = true;
- }
- changed |= merge(cw, edge, frame.inputStack, 0);
- return changed;
- }
-
- int nInputStack = inputStack.length + owner.inputStackTop;
- if (frame.inputStack == null) {
- frame.inputStack = new int[nInputStack + outputStackTop];
- changed = true;
- }
-
- for (i = 0; i < nInputStack; ++i) {
- t = inputStack[i];
- if (initializations != null) {
- t = init(cw, t);
- }
- changed |= merge(cw, t, frame.inputStack, i);
- }
- for (i = 0; i < outputStackTop; ++i) {
- s = outputStack[i];
- dim = s & DIM;
- kind = s & KIND;
- if (kind == BASE) {
- t = s;
- } else {
- if (kind == LOCAL) {
- t = dim + inputLocals[s & VALUE];
- } else {
- t = dim + inputStack[nStack - (s & VALUE)];
- }
- if ((s & TOP_IF_LONG_OR_DOUBLE) != 0 && (t == LONG || t == DOUBLE)) {
- t = TOP;
- }
- }
- if (initializations != null) {
- t = init(cw, t);
- }
- changed |= merge(cw, t, frame.inputStack, nInputStack + i);
- }
- return changed;
- }
-
- /**
- * Merges the type at the given index in the given type array with the given type. Returns
- * <tt>true</tt> if the type array has been modified by this operation.
- *
- * @param cw the ClassWriter to which this label belongs.
- * @param t the type with which the type array element must be merged.
- * @param types an array of types.
- * @param index the index of the type that must be merged in 'types'.
- * @return <tt>true</tt> if the type array has been modified by this operation.
- */
- private static boolean merge(final ClassWriter cw, int t, final int[] types, final int index) {
- int u = types[index];
- if (u == t) {
- // if the types are equal, merge(u,t)=u, so there is no change
- return false;
- }
- if ((t & ~DIM) == NULL) {
- if (u == NULL) {
- return false;
- }
- t = NULL;
- }
- if (u == 0) {
- // if types[index] has never been assigned, merge(u,t)=t
- types[index] = t;
- return true;
- }
- int v;
- if ((u & BASE_KIND) == OBJECT || (u & DIM) != 0) {
- // if u is a reference type of any dimension
- if (t == NULL) {
- // if t is the NULL type, merge(u,t)=u, so there is no change
- return false;
- } else if ((t & (DIM | BASE_KIND)) == (u & (DIM | BASE_KIND))) {
- // if t and u have the same dimension and same base kind
- if ((u & BASE_KIND) == OBJECT) {
- // if t is also a reference type, and if u and t have the
- // same dimension merge(u,t) = dim(t) | common parent of the
- // element types of u and t
- v = (t & DIM) | OBJECT | cw.getMergedType(t & BASE_VALUE, u & BASE_VALUE);
- } else {
- // if u and t are array types, but not with the same element
- // type, merge(u,t) = dim(u) - 1 | java/lang/Object
- int vdim = ELEMENT_OF + (u & DIM);
- v = vdim | OBJECT | cw.addType("java/lang/Object");
- }
- } else if ((t & BASE_KIND) == OBJECT || (t & DIM) != 0) {
- // if t is any other reference or array type, the merged type
- // is min(udim, tdim) | java/lang/Object, where udim is the
- // array dimension of u, minus 1 if u is an array type with a
- // primitive element type (and similarly for tdim).
- int tdim = (((t & DIM) == 0 || (t & BASE_KIND) == OBJECT) ? 0 : ELEMENT_OF) + (t & DIM);
- int udim = (((u & DIM) == 0 || (u & BASE_KIND) == OBJECT) ? 0 : ELEMENT_OF) + (u & DIM);
- v = Math.min(tdim, udim) | OBJECT | cw.addType("java/lang/Object");
- } else {
- // if t is any other type, merge(u,t)=TOP
- v = TOP;
- }
- } else if (u == NULL) {
- // if u is the NULL type, merge(u,t)=t,
- // or TOP if t is not a reference type
- v = (t & BASE_KIND) == OBJECT || (t & DIM) != 0 ? t : TOP;
- } else {
- // if u is any other type, merge(u,t)=TOP whatever t
- v = TOP;
- }
- if (u != v) {
- types[index] = v;
- return true;
- }
- return false;
- }
-}
+/*
+ * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ */
+
+/*
+ *
+ *
+ *
+ *
+ *
+ * ASM: a very small and fast Java bytecode manipulation framework
+ * Copyright (c) 2000-2011 INRIA, France Telecom
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.redkale.asm;
+
+/**
+ * Information about the input and output stack map frames of a basic block.
+ *
+ * @author Eric Bruneton
+ */
+class Frame {
+
+ /*
+ * Frames are computed in a two steps process: during the visit of each
+ * instruction, the state of the frame at the end of current basic block is
+ * updated by simulating the action of the instruction on the previous state
+ * of this so called "output frame". In visitMaxs, a fix point algorithm is
+ * used to compute the "input frame" of each basic block, i.e. the stack map
+ * frame at the beginning of the basic block, starting from the input frame
+ * of the first basic block (which is computed from the method descriptor),
+ * and by using the previously computed output frames to compute the input
+ * state of the other blocks.
+ *
+ * All output and input frames are stored as arrays of integers. Reference
+ * and array types are represented by an index into a type table (which is
+ * not the same as the constant pool of the class, in order to avoid adding
+ * unnecessary constants in the pool - not all computed frames will end up
+ * being stored in the stack map table). This allows very fast type
+ * comparisons.
+ *
+ * Output stack map frames are computed relatively to the input frame of the
+ * basic block, which is not yet known when output frames are computed. It
+ * is therefore necessary to be able to represent abstract types such as
+ * "the type at position x in the input frame locals" or "the type at
+ * position x from the top of the input frame stack" or even "the type at
+ * position x in the input frame, with y more (or less) array dimensions".
+ * This explains the rather complicated type format used in output frames.
+ *
+ * This format is the following: DIM KIND VALUE (4, 4 and 24 bits). DIM is a
+ * signed number of array dimensions (from -8 to 7). KIND is either BASE,
+ * LOCAL or STACK. BASE is used for types that are not relative to the input
+ * frame. LOCAL is used for types that are relative to the input local
+ * variable types. STACK is used for types that are relative to the input
+ * stack types. VALUE depends on KIND. For LOCAL types, it is an index in
+ * the input local variable types. For STACK types, it is a position
+ * relatively to the top of input frame stack. For BASE types, it is either
+ * one of the constants defined below, or for OBJECT and UNINITIALIZED
+ * types, a tag and an index in the type table.
+ *
+ * Output frames can contain types of any kind and with a positive or
+ * negative dimension (and even unassigned types, represented by 0 - which
+ * does not correspond to any valid type value). Input frames can only
+ * contain BASE types of positive or null dimension. In all cases the type
+ * table contains only internal type names (array type descriptors are
+ * forbidden - dimensions must be represented through the DIM field).
+ *
+ * The LONG and DOUBLE types are always represented by using two slots (LONG
+ * + TOP or DOUBLE + TOP), for local variable types as well as in the
+ * operand stack. This is necessary to be able to simulate DUPx_y
+ * instructions, whose effect would be dependent on the actual type values
+ * if types were always represented by a single slot in the stack (and this
+ * is not possible, since actual type values are not always known - cf LOCAL
+ * and STACK type kinds).
+ */
+
+ /** Mask to get the dimension of a frame type. This dimension is a signed integer between -8 and 7. */
+ static final int DIM = 0xF0000000;
+
+ /** Constant to be added to a type to get a type with one more dimension. */
+ static final int ARRAY_OF = 0x10000000;
+
+ /** Constant to be added to a type to get a type with one less dimension. */
+ static final int ELEMENT_OF = 0xF0000000;
+
+ /**
+ * Mask to get the kind of a frame type.
+ *
+ * @see #BASE
+ * @see #LOCAL
+ * @see #STACK
+ */
+ static final int KIND = 0xF000000;
+
+ /**
+ * Flag used for LOCAL and STACK types. Indicates that if this type happens to be a long or double type (during the
+ * computations of input frames), then it must be set to TOP because the second word of this value has been reused
+ * to store other data in the basic block. Hence the first word no longer stores a valid long or double value.
+ */
+ static final int TOP_IF_LONG_OR_DOUBLE = 0x800000;
+
+ /** Mask to get the value of a frame type. */
+ static final int VALUE = 0x7FFFFF;
+
+ /** Mask to get the kind of base types. */
+ static final int BASE_KIND = 0xFF00000;
+
+ /** Mask to get the value of base types. */
+ static final int BASE_VALUE = 0xFFFFF;
+
+ /** Kind of the types that are not relative to an input stack map frame. */
+ static final int BASE = 0x1000000;
+
+ /** Base kind of the base reference types. The BASE_VALUE of such types is an index into the type table. */
+ static final int OBJECT = BASE | 0x700000;
+
+ /**
+ * Base kind of the uninitialized base types. The BASE_VALUE of such types in an index into the type table (the Item
+ * at that index contains both an instruction offset and an internal class name).
+ */
+ static final int UNINITIALIZED = BASE | 0x800000;
+
+ /**
+ * Kind of the types that are relative to the local variable types of an input stack map frame. The value of such
+ * types is a local variable index.
+ */
+ private static final int LOCAL = 0x2000000;
+
+ /**
+ * Kind of the types that are relative to the stack of an input stack map frame. The value of such types is a
+ * position relatively to the top of this stack.
+ */
+ private static final int STACK = 0x3000000;
+
+ /** The TOP type. This is a BASE type. */
+ static final int TOP = BASE | 0;
+
+ /** The BOOLEAN type. This is a BASE type mainly used for array types. */
+ static final int BOOLEAN = BASE | 9;
+
+ /** The BYTE type. This is a BASE type mainly used for array types. */
+ static final int BYTE = BASE | 10;
+
+ /** The CHAR type. This is a BASE type mainly used for array types. */
+ static final int CHAR = BASE | 11;
+
+ /** The SHORT type. This is a BASE type mainly used for array types. */
+ static final int SHORT = BASE | 12;
+
+ /** The INTEGER type. This is a BASE type. */
+ static final int INTEGER = BASE | 1;
+
+ /** The FLOAT type. This is a BASE type. */
+ static final int FLOAT = BASE | 2;
+
+ /** The DOUBLE type. This is a BASE type. */
+ static final int DOUBLE = BASE | 3;
+
+ /** The LONG type. This is a BASE type. */
+ static final int LONG = BASE | 4;
+
+ /** The NULL type. This is a BASE type. */
+ static final int NULL = BASE | 5;
+
+ /** The UNINITIALIZED_THIS type. This is a BASE type. */
+ static final int UNINITIALIZED_THIS = BASE | 6;
+
+ /**
+ * The stack size variation corresponding to each JVM instruction. This stack variation is equal to the size of the
+ * values produced by an instruction, minus the size of the values consumed by this instruction.
+ */
+ static final int[] SIZE;
+
+ /** Computes the stack size variation corresponding to each JVM instruction. */
+ static {
+ int i;
+ int[] b = new int[202];
+ String s = "EFFFFFFFFGGFFFGGFFFEEFGFGFEEEEEEEEEEEEEEEEEEEEDEDEDDDDD"
+ + "CDCDEEEEEEEEEEEEEEEEEEEEBABABBBBDCFFFGGGEDCDCDCDCDCDCDCDCD"
+ + "CDCEEEEDDDDDDDCDCDCEFEFDDEEFFDEDEEEBDDBBDDDDDDCCCCCCCCEFED"
+ + "DDCDCDEEEEEEEEEEFEEEEEEDDEEDDEE";
+ for (i = 0; i < b.length; ++i) {
+ b[i] = s.charAt(i) - 'E';
+ }
+ SIZE = b;
+
+ // code to generate the above string
+ //
+ // int NA = 0; // not applicable (unused opcode or variable size opcode)
+ //
+ // b = new int[] {
+ // 0, //NOP, // visitInsn
+ // 1, //ACONST_NULL, // -
+ // 1, //ICONST_M1, // -
+ // 1, //ICONST_0, // -
+ // 1, //ICONST_1, // -
+ // 1, //ICONST_2, // -
+ // 1, //ICONST_3, // -
+ // 1, //ICONST_4, // -
+ // 1, //ICONST_5, // -
+ // 2, //LCONST_0, // -
+ // 2, //LCONST_1, // -
+ // 1, //FCONST_0, // -
+ // 1, //FCONST_1, // -
+ // 1, //FCONST_2, // -
+ // 2, //DCONST_0, // -
+ // 2, //DCONST_1, // -
+ // 1, //BIPUSH, // visitIntInsn
+ // 1, //SIPUSH, // -
+ // 1, //LDC, // visitLdcInsn
+ // NA, //LDC_W, // -
+ // NA, //LDC2_W, // -
+ // 1, //ILOAD, // visitVarInsn
+ // 2, //LLOAD, // -
+ // 1, //FLOAD, // -
+ // 2, //DLOAD, // -
+ // 1, //ALOAD, // -
+ // NA, //ILOAD_0, // -
+ // NA, //ILOAD_1, // -
+ // NA, //ILOAD_2, // -
+ // NA, //ILOAD_3, // -
+ // NA, //LLOAD_0, // -
+ // NA, //LLOAD_1, // -
+ // NA, //LLOAD_2, // -
+ // NA, //LLOAD_3, // -
+ // NA, //FLOAD_0, // -
+ // NA, //FLOAD_1, // -
+ // NA, //FLOAD_2, // -
+ // NA, //FLOAD_3, // -
+ // NA, //DLOAD_0, // -
+ // NA, //DLOAD_1, // -
+ // NA, //DLOAD_2, // -
+ // NA, //DLOAD_3, // -
+ // NA, //ALOAD_0, // -
+ // NA, //ALOAD_1, // -
+ // NA, //ALOAD_2, // -
+ // NA, //ALOAD_3, // -
+ // -1, //IALOAD, // visitInsn
+ // 0, //LALOAD, // -
+ // -1, //FALOAD, // -
+ // 0, //DALOAD, // -
+ // -1, //AALOAD, // -
+ // -1, //BALOAD, // -
+ // -1, //CALOAD, // -
+ // -1, //SALOAD, // -
+ // -1, //ISTORE, // visitVarInsn
+ // -2, //LSTORE, // -
+ // -1, //FSTORE, // -
+ // -2, //DSTORE, // -
+ // -1, //ASTORE, // -
+ // NA, //ISTORE_0, // -
+ // NA, //ISTORE_1, // -
+ // NA, //ISTORE_2, // -
+ // NA, //ISTORE_3, // -
+ // NA, //LSTORE_0, // -
+ // NA, //LSTORE_1, // -
+ // NA, //LSTORE_2, // -
+ // NA, //LSTORE_3, // -
+ // NA, //FSTORE_0, // -
+ // NA, //FSTORE_1, // -
+ // NA, //FSTORE_2, // -
+ // NA, //FSTORE_3, // -
+ // NA, //DSTORE_0, // -
+ // NA, //DSTORE_1, // -
+ // NA, //DSTORE_2, // -
+ // NA, //DSTORE_3, // -
+ // NA, //ASTORE_0, // -
+ // NA, //ASTORE_1, // -
+ // NA, //ASTORE_2, // -
+ // NA, //ASTORE_3, // -
+ // -3, //IASTORE, // visitInsn
+ // -4, //LASTORE, // -
+ // -3, //FASTORE, // -
+ // -4, //DASTORE, // -
+ // -3, //AASTORE, // -
+ // -3, //BASTORE, // -
+ // -3, //CASTORE, // -
+ // -3, //SASTORE, // -
+ // -1, //POP, // -
+ // -2, //POP2, // -
+ // 1, //DUP, // -
+ // 1, //DUP_X1, // -
+ // 1, //DUP_X2, // -
+ // 2, //DUP2, // -
+ // 2, //DUP2_X1, // -
+ // 2, //DUP2_X2, // -
+ // 0, //SWAP, // -
+ // -1, //IADD, // -
+ // -2, //LADD, // -
+ // -1, //FADD, // -
+ // -2, //DADD, // -
+ // -1, //ISUB, // -
+ // -2, //LSUB, // -
+ // -1, //FSUB, // -
+ // -2, //DSUB, // -
+ // -1, //IMUL, // -
+ // -2, //LMUL, // -
+ // -1, //FMUL, // -
+ // -2, //DMUL, // -
+ // -1, //IDIV, // -
+ // -2, //LDIV, // -
+ // -1, //FDIV, // -
+ // -2, //DDIV, // -
+ // -1, //IREM, // -
+ // -2, //LREM, // -
+ // -1, //FREM, // -
+ // -2, //DREM, // -
+ // 0, //INEG, // -
+ // 0, //LNEG, // -
+ // 0, //FNEG, // -
+ // 0, //DNEG, // -
+ // -1, //ISHL, // -
+ // -1, //LSHL, // -
+ // -1, //ISHR, // -
+ // -1, //LSHR, // -
+ // -1, //IUSHR, // -
+ // -1, //LUSHR, // -
+ // -1, //IAND, // -
+ // -2, //LAND, // -
+ // -1, //IOR, // -
+ // -2, //LOR, // -
+ // -1, //IXOR, // -
+ // -2, //LXOR, // -
+ // 0, //IINC, // visitIincInsn
+ // 1, //I2L, // visitInsn
+ // 0, //I2F, // -
+ // 1, //I2D, // -
+ // -1, //L2I, // -
+ // -1, //L2F, // -
+ // 0, //L2D, // -
+ // 0, //F2I, // -
+ // 1, //F2L, // -
+ // 1, //F2D, // -
+ // -1, //D2I, // -
+ // 0, //D2L, // -
+ // -1, //D2F, // -
+ // 0, //I2B, // -
+ // 0, //I2C, // -
+ // 0, //I2S, // -
+ // -3, //LCMP, // -
+ // -1, //FCMPL, // -
+ // -1, //FCMPG, // -
+ // -3, //DCMPL, // -
+ // -3, //DCMPG, // -
+ // -1, //IFEQ, // visitJumpInsn
+ // -1, //IFNE, // -
+ // -1, //IFLT, // -
+ // -1, //IFGE, // -
+ // -1, //IFGT, // -
+ // -1, //IFLE, // -
+ // -2, //IF_ICMPEQ, // -
+ // -2, //IF_ICMPNE, // -
+ // -2, //IF_ICMPLT, // -
+ // -2, //IF_ICMPGE, // -
+ // -2, //IF_ICMPGT, // -
+ // -2, //IF_ICMPLE, // -
+ // -2, //IF_ACMPEQ, // -
+ // -2, //IF_ACMPNE, // -
+ // 0, //GOTO, // -
+ // 1, //JSR, // -
+ // 0, //RET, // visitVarInsn
+ // -1, //TABLESWITCH, // visiTableSwitchInsn
+ // -1, //LOOKUPSWITCH, // visitLookupSwitch
+ // -1, //IRETURN, // visitInsn
+ // -2, //LRETURN, // -
+ // -1, //FRETURN, // -
+ // -2, //DRETURN, // -
+ // -1, //ARETURN, // -
+ // 0, //RETURN, // -
+ // NA, //GETSTATIC, // visitFieldInsn
+ // NA, //PUTSTATIC, // -
+ // NA, //GETFIELD, // -
+ // NA, //PUTFIELD, // -
+ // NA, //INVOKEVIRTUAL, // visitMethodInsn
+ // NA, //INVOKESPECIAL, // -
+ // NA, //INVOKESTATIC, // -
+ // NA, //INVOKEINTERFACE, // -
+ // NA, //INVOKEDYNAMIC, // visitInvokeDynamicInsn
+ // 1, //NEW, // visitTypeInsn
+ // 0, //NEWARRAY, // visitIntInsn
+ // 0, //ANEWARRAY, // visitTypeInsn
+ // 0, //ARRAYLENGTH, // visitInsn
+ // NA, //ATHROW, // -
+ // 0, //CHECKCAST, // visitTypeInsn
+ // 0, //INSTANCEOF, // -
+ // -1, //MONITORENTER, // visitInsn
+ // -1, //MONITOREXIT, // -
+ // NA, //WIDE, // NOT VISITED
+ // NA, //MULTIANEWARRAY, // visitMultiANewArrayInsn
+ // -1, //IFNULL, // visitJumpInsn
+ // -1, //IFNONNULL, // -
+ // NA, //GOTO_W, // -
+ // NA, //JSR_W, // -
+ // };
+ // for (i = 0; i < b.length; ++i) {
+ // System.err.print((char)('E' + b[i]));
+ // }
+ // System.err.println();
+ }
+
+ /** The label (i.e. basic block) to which these input and output stack map frames correspond. */
+ Label owner;
+
+ /** The input stack map frame locals. */
+ int[] inputLocals;
+
+ /** The input stack map frame stack. */
+ int[] inputStack;
+
+ /** The output stack map frame locals. */
+ private int[] outputLocals;
+
+ /** The output stack map frame stack. */
+ private int[] outputStack;
+
+ /**
+ * Relative size of the output stack. The exact semantics of this field depends on the algorithm that is used.
+ *
+ * When only the maximum stack size is computed, this field is the size of the output stack relatively to the top
+ * of the input stack.
+ *
+ * When the stack map frames are completely computed, this field is the actual number of types in
+ * {@link #outputStack}.
+ */
+ int outputStackTop;
+
+ /**
+ * Number of types that are initialized in the basic block.
+ *
+ * @see #initializations
+ */
+ private int initializationCount;
+
+ /**
+ * The types that are initialized in the basic block. A constructor invocation on an UNINITIALIZED or
+ * UNINITIALIZED_THIS type must replace every occurence of this type in the local variables and in the
+ * operand stack. This cannot be done during the first phase of the algorithm since, during this phase, the local
+ * variables and the operand stack are not completely computed. It is therefore necessary to store the types on
+ * which constructors are invoked in the basic block, in order to do this replacement during the second phase of the
+ * algorithm, where the frames are fully computed. Note that this array can contain types that are relative to input
+ * locals or to the input stack (see below for the description of the algorithm).
+ */
+ private int[] initializations;
+
+ /**
+ * Sets this frame to the given value.
+ *
+ * @param cw the ClassWriter to which this label belongs.
+ * @param nLocal the number of local variables.
+ * @param local the local variable types. Primitive types are represented by {@link Opcodes#TOP},
+ * {@link Opcodes#INTEGER}, {@link Opcodes#FLOAT}, {@link Opcodes#LONG},
+ * {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or {@link Opcodes#UNINITIALIZED_THIS} (long and double are
+ * represented by a single element). Reference types are represented by String objects (representing internal
+ * names), and uninitialized types by Label objects (this label designates the NEW instruction that created this
+ * uninitialized value).
+ * @param nStack the number of operand stack elements.
+ * @param stack the operand stack types (same format as the "local" array).
+ */
+ final void set(ClassWriter cw, final int nLocal, final Object[] local, final int nStack, final Object[] stack) {
+ int i = convert(cw, nLocal, local, inputLocals);
+ while (i < local.length) {
+ inputLocals[i++] = TOP;
+ }
+ int nStackTop = 0;
+ for (int j = 0; j < nStack; ++j) {
+ if (stack[j] == Opcodes.LONG || stack[j] == Opcodes.DOUBLE) {
+ ++nStackTop;
+ }
+ }
+ inputStack = new int[nStack + nStackTop];
+ convert(cw, nStack, stack, inputStack);
+ outputStackTop = 0;
+ initializationCount = 0;
+ }
+
+ /**
+ * Converts types from the MethodWriter.visitFrame() format to the Frame format.
+ *
+ * @param cw the ClassWriter to which this label belongs.
+ * @param nInput the number of types to convert.
+ * @param input the types to convert. Primitive types are represented by {@link Opcodes#TOP},
+ * {@link Opcodes#INTEGER}, {@link Opcodes#FLOAT}, {@link Opcodes#LONG},
+ * {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or {@link Opcodes#UNINITIALIZED_THIS} (long and double are
+ * represented by a single element). Reference types are represented by String objects (representing internal
+ * names), and uninitialized types by Label objects (this label designates the NEW instruction that created this
+ * uninitialized value).
+ * @param output where to store the converted types.
+ * @return the number of output elements.
+ */
+ private static int convert(ClassWriter cw, int nInput, Object[] input, int[] output) {
+ int i = 0;
+ for (int j = 0; j < nInput; ++j) {
+ if (input[j] instanceof Integer) {
+ output[i++] = BASE | ((Integer) input[j]).intValue();
+ if (input[j] == Opcodes.LONG || input[j] == Opcodes.DOUBLE) {
+ output[i++] = TOP;
+ }
+ } else if (input[j] instanceof String) {
+ output[i++] = type(cw, Type.getObjectType((String) input[j]).getDescriptor());
+ } else {
+ output[i++] = UNINITIALIZED | cw.addUninitializedType("", ((Label) input[j]).position);
+ }
+ }
+ return i;
+ }
+
+ /**
+ * Sets this frame to the value of the given frame. WARNING: after this method is called the two frames share the
+ * same data structures. It is recommended to discard the given frame f to avoid unexpected side effects.
+ *
+ * @param f The new frame value.
+ */
+ final void set(final Frame f) {
+ inputLocals = f.inputLocals;
+ inputStack = f.inputStack;
+ outputLocals = f.outputLocals;
+ outputStack = f.outputStack;
+ outputStackTop = f.outputStackTop;
+ initializationCount = f.initializationCount;
+ initializations = f.initializations;
+ }
+
+ /**
+ * Returns the output frame local variable type at the given index.
+ *
+ * @param local the index of the local that must be returned.
+ * @return the output frame local variable type at the given index.
+ */
+ private int get(final int local) {
+ if (outputLocals == null || local >= outputLocals.length) {
+ // this local has never been assigned in this basic block,
+ // so it is still equal to its value in the input frame
+ return LOCAL | local;
+ } else {
+ int type = outputLocals[local];
+ if (type == 0) {
+ // this local has never been assigned in this basic block,
+ // so it is still equal to its value in the input frame
+ type = outputLocals[local] = LOCAL | local;
+ }
+ return type;
+ }
+ }
+
+ /**
+ * Sets the output frame local variable type at the given index.
+ *
+ * @param local the index of the local that must be set.
+ * @param type the value of the local that must be set.
+ */
+ private void set(final int local, final int type) {
+ // creates and/or resizes the output local variables array if necessary
+ if (outputLocals == null) {
+ outputLocals = new int[10];
+ }
+ int n = outputLocals.length;
+ if (local >= n) {
+ int[] t = new int[Math.max(local + 1, 2 * n)];
+ System.arraycopy(outputLocals, 0, t, 0, n);
+ outputLocals = t;
+ }
+ // sets the local variable
+ outputLocals[local] = type;
+ }
+
+ /**
+ * Pushes a new type onto the output frame stack.
+ *
+ * @param type the type that must be pushed.
+ */
+ private void push(final int type) {
+ // creates and/or resizes the output stack array if necessary
+ if (outputStack == null) {
+ outputStack = new int[10];
+ }
+ int n = outputStack.length;
+ if (outputStackTop >= n) {
+ int[] t = new int[Math.max(outputStackTop + 1, 2 * n)];
+ System.arraycopy(outputStack, 0, t, 0, n);
+ outputStack = t;
+ }
+ // pushes the type on the output stack
+ outputStack[outputStackTop++] = type;
+ // updates the maximum height reached by the output stack, if needed
+ int top = owner.inputStackTop + outputStackTop;
+ if (top > owner.outputStackMax) {
+ owner.outputStackMax = top;
+ }
+ }
+
+ /**
+ * Pushes a new type onto the output frame stack.
+ *
+ * @param cw the ClassWriter to which this label belongs.
+ * @param desc the descriptor of the type to be pushed. Can also be a method descriptor (in this case this method
+ * pushes its return type onto the output frame stack).
+ */
+ private void push(final ClassWriter cw, final String desc) {
+ int type = type(cw, desc);
+ if (type != 0) {
+ push(type);
+ if (type == LONG || type == DOUBLE) {
+ push(TOP);
+ }
+ }
+ }
+
+ /**
+ * Returns the int encoding of the given type.
+ *
+ * @param cw the ClassWriter to which this label belongs.
+ * @param desc a type descriptor.
+ * @return the int encoding of the given type.
+ */
+ static int type(final ClassWriter cw, final String desc) {
+ String t;
+ int index = desc.charAt(0) == '(' ? desc.indexOf(')') + 1 : 0;
+ switch (desc.charAt(index)) {
+ case 'V':
+ return 0;
+ case 'Z':
+ case 'C':
+ case 'B':
+ case 'S':
+ case 'I':
+ return INTEGER;
+ case 'F':
+ return FLOAT;
+ case 'J':
+ return LONG;
+ case 'D':
+ return DOUBLE;
+ case 'L':
+ // stores the internal name, not the descriptor!
+ t = desc.substring(index + 1, desc.length() - 1);
+ return OBJECT | cw.addType(t);
+ // case '[':
+ default:
+ // extracts the dimensions and the element type
+ int data;
+ int dims = index + 1;
+ while (desc.charAt(dims) == '[') {
+ ++dims;
+ }
+ switch (desc.charAt(dims)) {
+ case 'Z':
+ data = BOOLEAN;
+ break;
+ case 'C':
+ data = CHAR;
+ break;
+ case 'B':
+ data = BYTE;
+ break;
+ case 'S':
+ data = SHORT;
+ break;
+ case 'I':
+ data = INTEGER;
+ break;
+ case 'F':
+ data = FLOAT;
+ break;
+ case 'J':
+ data = LONG;
+ break;
+ case 'D':
+ data = DOUBLE;
+ break;
+ // case 'L':
+ default:
+ // stores the internal name, not the descriptor
+ t = desc.substring(dims + 1, desc.length() - 1);
+ data = OBJECT | cw.addType(t);
+ }
+ return (dims - index) << 28 | data;
+ }
+ }
+
+ /**
+ * Pops a type from the output frame stack and returns its value.
+ *
+ * @return the type that has been popped from the output frame stack.
+ */
+ private int pop() {
+ if (outputStackTop > 0) {
+ return outputStack[--outputStackTop];
+ } else {
+ // if the output frame stack is empty, pops from the input stack
+ return STACK | -(--owner.inputStackTop);
+ }
+ }
+
+ /**
+ * Pops the given number of types from the output frame stack.
+ *
+ * @param elements the number of types that must be popped.
+ */
+ private void pop(final int elements) {
+ if (outputStackTop >= elements) {
+ outputStackTop -= elements;
+ } else {
+ // if the number of elements to be popped is greater than the number
+ // of elements in the output stack, clear it, and pops the remaining
+ // elements from the input stack.
+ owner.inputStackTop -= elements - outputStackTop;
+ outputStackTop = 0;
+ }
+ }
+
+ /**
+ * Pops a type from the output frame stack.
+ *
+ * @param desc the descriptor of the type to be popped. Can also be a method descriptor (in this case this method
+ * pops the types corresponding to the method arguments).
+ */
+ private void pop(final String desc) {
+ char c = desc.charAt(0);
+ if (c == '(') {
+ pop((Type.getArgumentsAndReturnSizes(desc) >> 2) - 1);
+ } else if (c == 'J' || c == 'D') {
+ pop(2);
+ } else {
+ pop(1);
+ }
+ }
+
+ /**
+ * Adds a new type to the list of types on which a constructor is invoked in the basic block.
+ *
+ * @param var a type on a which a constructor is invoked.
+ */
+ private void init(final int var) {
+ // creates and/or resizes the initializations array if necessary
+ if (initializations == null) {
+ initializations = new int[2];
+ }
+ int n = initializations.length;
+ if (initializationCount >= n) {
+ int[] t = new int[Math.max(initializationCount + 1, 2 * n)];
+ System.arraycopy(initializations, 0, t, 0, n);
+ initializations = t;
+ }
+ // stores the type to be initialized
+ initializations[initializationCount++] = var;
+ }
+
+ /**
+ * Replaces the given type with the appropriate type if it is one of the types on which a constructor is invoked in
+ * the basic block.
+ *
+ * @param cw the ClassWriter to which this label belongs.
+ * @param t a type
+ * @return t or, if t is one of the types on which a constructor is invoked in the basic block, the type
+ * corresponding to this constructor.
+ */
+ private int init(final ClassWriter cw, final int t) {
+ int s;
+ if (t == UNINITIALIZED_THIS) {
+ s = OBJECT | cw.addType(cw.thisName);
+ } else if ((t & (DIM | BASE_KIND)) == UNINITIALIZED) {
+ String type = cw.typeTable[t & BASE_VALUE].strVal1;
+ s = OBJECT | cw.addType(type);
+ } else {
+ return t;
+ }
+ for (int j = 0; j < initializationCount; ++j) {
+ int u = initializations[j];
+ int dim = u & DIM;
+ int kind = u & KIND;
+ if (kind == LOCAL) {
+ u = dim + inputLocals[u & VALUE];
+ } else if (kind == STACK) {
+ u = dim + inputStack[inputStack.length - (u & VALUE)];
+ }
+ if (t == u) {
+ return s;
+ }
+ }
+ return t;
+ }
+
+ /**
+ * Initializes the input frame of the first basic block from the method descriptor.
+ *
+ * @param cw the ClassWriter to which this label belongs.
+ * @param access the access flags of the method to which this label belongs.
+ * @param args the formal parameter types of this method.
+ * @param maxLocals the maximum number of local variables of this method.
+ */
+ final void initInputFrame(final ClassWriter cw, final int access, final Type[] args, final int maxLocals) {
+ inputLocals = new int[maxLocals];
+ inputStack = new int[0];
+ int i = 0;
+ if ((access & Opcodes.ACC_STATIC) == 0) {
+ if ((access & MethodWriter.ACC_CONSTRUCTOR) == 0) {
+ inputLocals[i++] = OBJECT | cw.addType(cw.thisName);
+ } else {
+ inputLocals[i++] = UNINITIALIZED_THIS;
+ }
+ }
+ for (int j = 0; j < args.length; ++j) {
+ int t = type(cw, args[j].getDescriptor());
+ inputLocals[i++] = t;
+ if (t == LONG || t == DOUBLE) {
+ inputLocals[i++] = TOP;
+ }
+ }
+ while (i < maxLocals) {
+ inputLocals[i++] = TOP;
+ }
+ }
+
+ /**
+ * Simulates the action of the given instruction on the output stack frame.
+ *
+ * @param opcode the opcode of the instruction.
+ * @param arg the operand of the instruction, if any.
+ * @param cw the class writer to which this label belongs.
+ * @param item the operand of the instructions, if any.
+ */
+ void execute(final int opcode, final int arg, final ClassWriter cw, final Item item) {
+ int t1, t2, t3, t4;
+ switch (opcode) {
+ case Opcodes.NOP:
+ case Opcodes.INEG:
+ case Opcodes.LNEG:
+ case Opcodes.FNEG:
+ case Opcodes.DNEG:
+ case Opcodes.I2B:
+ case Opcodes.I2C:
+ case Opcodes.I2S:
+ case Opcodes.GOTO:
+ case Opcodes.RETURN:
+ break;
+ case Opcodes.ACONST_NULL:
+ push(NULL);
+ break;
+ case Opcodes.ICONST_M1:
+ case Opcodes.ICONST_0:
+ case Opcodes.ICONST_1:
+ case Opcodes.ICONST_2:
+ case Opcodes.ICONST_3:
+ case Opcodes.ICONST_4:
+ case Opcodes.ICONST_5:
+ case Opcodes.BIPUSH:
+ case Opcodes.SIPUSH:
+ case Opcodes.ILOAD:
+ push(INTEGER);
+ break;
+ case Opcodes.LCONST_0:
+ case Opcodes.LCONST_1:
+ case Opcodes.LLOAD:
+ push(LONG);
+ push(TOP);
+ break;
+ case Opcodes.FCONST_0:
+ case Opcodes.FCONST_1:
+ case Opcodes.FCONST_2:
+ case Opcodes.FLOAD:
+ push(FLOAT);
+ break;
+ case Opcodes.DCONST_0:
+ case Opcodes.DCONST_1:
+ case Opcodes.DLOAD:
+ push(DOUBLE);
+ push(TOP);
+ break;
+ case Opcodes.LDC:
+ switch (item.type) {
+ case ClassWriter.INT:
+ push(INTEGER);
+ break;
+ case ClassWriter.LONG:
+ push(LONG);
+ push(TOP);
+ break;
+ case ClassWriter.FLOAT:
+ push(FLOAT);
+ break;
+ case ClassWriter.DOUBLE:
+ push(DOUBLE);
+ push(TOP);
+ break;
+ case ClassWriter.CLASS:
+ push(OBJECT | cw.addType("java/lang/Class"));
+ break;
+ case ClassWriter.STR:
+ push(OBJECT | cw.addType("java/lang/String"));
+ break;
+ case ClassWriter.MTYPE:
+ push(OBJECT | cw.addType("java/lang/invoke/MethodType"));
+ break;
+ // case ClassWriter.HANDLE_BASE + [1..9]:
+ default:
+ push(OBJECT | cw.addType("java/lang/invoke/MethodHandle"));
+ }
+ break;
+ case Opcodes.ALOAD:
+ push(get(arg));
+ break;
+ case Opcodes.IALOAD:
+ case Opcodes.BALOAD:
+ case Opcodes.CALOAD:
+ case Opcodes.SALOAD:
+ pop(2);
+ push(INTEGER);
+ break;
+ case Opcodes.LALOAD:
+ case Opcodes.D2L:
+ pop(2);
+ push(LONG);
+ push(TOP);
+ break;
+ case Opcodes.FALOAD:
+ pop(2);
+ push(FLOAT);
+ break;
+ case Opcodes.DALOAD:
+ case Opcodes.L2D:
+ pop(2);
+ push(DOUBLE);
+ push(TOP);
+ break;
+ case Opcodes.AALOAD:
+ pop(1);
+ t1 = pop();
+ push(t1 == NULL ? t1 : ELEMENT_OF + t1);
+ break;
+ case Opcodes.ISTORE:
+ case Opcodes.FSTORE:
+ case Opcodes.ASTORE:
+ t1 = pop();
+ set(arg, t1);
+ if (arg > 0) {
+ t2 = get(arg - 1);
+ // if t2 is of kind STACK or LOCAL we cannot know its size!
+ if (t2 == LONG || t2 == DOUBLE) {
+ set(arg - 1, TOP);
+ } else if ((t2 & KIND) != BASE) {
+ set(arg - 1, t2 | TOP_IF_LONG_OR_DOUBLE);
+ }
+ }
+ break;
+ case Opcodes.LSTORE:
+ case Opcodes.DSTORE:
+ pop(1);
+ t1 = pop();
+ set(arg, t1);
+ set(arg + 1, TOP);
+ if (arg > 0) {
+ t2 = get(arg - 1);
+ // if t2 is of kind STACK or LOCAL we cannot know its size!
+ if (t2 == LONG || t2 == DOUBLE) {
+ set(arg - 1, TOP);
+ } else if ((t2 & KIND) != BASE) {
+ set(arg - 1, t2 | TOP_IF_LONG_OR_DOUBLE);
+ }
+ }
+ break;
+ case Opcodes.IASTORE:
+ case Opcodes.BASTORE:
+ case Opcodes.CASTORE:
+ case Opcodes.SASTORE:
+ case Opcodes.FASTORE:
+ case Opcodes.AASTORE:
+ pop(3);
+ break;
+ case Opcodes.LASTORE:
+ case Opcodes.DASTORE:
+ pop(4);
+ break;
+ case Opcodes.POP:
+ case Opcodes.IFEQ:
+ case Opcodes.IFNE:
+ case Opcodes.IFLT:
+ case Opcodes.IFGE:
+ case Opcodes.IFGT:
+ case Opcodes.IFLE:
+ case Opcodes.IRETURN:
+ case Opcodes.FRETURN:
+ case Opcodes.ARETURN:
+ case Opcodes.TABLESWITCH:
+ case Opcodes.LOOKUPSWITCH:
+ case Opcodes.ATHROW:
+ case Opcodes.MONITORENTER:
+ case Opcodes.MONITOREXIT:
+ case Opcodes.IFNULL:
+ case Opcodes.IFNONNULL:
+ pop(1);
+ break;
+ case Opcodes.POP2:
+ case Opcodes.IF_ICMPEQ:
+ case Opcodes.IF_ICMPNE:
+ case Opcodes.IF_ICMPLT:
+ case Opcodes.IF_ICMPGE:
+ case Opcodes.IF_ICMPGT:
+ case Opcodes.IF_ICMPLE:
+ case Opcodes.IF_ACMPEQ:
+ case Opcodes.IF_ACMPNE:
+ case Opcodes.LRETURN:
+ case Opcodes.DRETURN:
+ pop(2);
+ break;
+ case Opcodes.DUP:
+ t1 = pop();
+ push(t1);
+ push(t1);
+ break;
+ case Opcodes.DUP_X1:
+ t1 = pop();
+ t2 = pop();
+ push(t1);
+ push(t2);
+ push(t1);
+ break;
+ case Opcodes.DUP_X2:
+ t1 = pop();
+ t2 = pop();
+ t3 = pop();
+ push(t1);
+ push(t3);
+ push(t2);
+ push(t1);
+ break;
+ case Opcodes.DUP2:
+ t1 = pop();
+ t2 = pop();
+ push(t2);
+ push(t1);
+ push(t2);
+ push(t1);
+ break;
+ case Opcodes.DUP2_X1:
+ t1 = pop();
+ t2 = pop();
+ t3 = pop();
+ push(t2);
+ push(t1);
+ push(t3);
+ push(t2);
+ push(t1);
+ break;
+ case Opcodes.DUP2_X2:
+ t1 = pop();
+ t2 = pop();
+ t3 = pop();
+ t4 = pop();
+ push(t2);
+ push(t1);
+ push(t4);
+ push(t3);
+ push(t2);
+ push(t1);
+ break;
+ case Opcodes.SWAP:
+ t1 = pop();
+ t2 = pop();
+ push(t1);
+ push(t2);
+ break;
+ case Opcodes.IADD:
+ case Opcodes.ISUB:
+ case Opcodes.IMUL:
+ case Opcodes.IDIV:
+ case Opcodes.IREM:
+ case Opcodes.IAND:
+ case Opcodes.IOR:
+ case Opcodes.IXOR:
+ case Opcodes.ISHL:
+ case Opcodes.ISHR:
+ case Opcodes.IUSHR:
+ case Opcodes.L2I:
+ case Opcodes.D2I:
+ case Opcodes.FCMPL:
+ case Opcodes.FCMPG:
+ pop(2);
+ push(INTEGER);
+ break;
+ case Opcodes.LADD:
+ case Opcodes.LSUB:
+ case Opcodes.LMUL:
+ case Opcodes.LDIV:
+ case Opcodes.LREM:
+ case Opcodes.LAND:
+ case Opcodes.LOR:
+ case Opcodes.LXOR:
+ pop(4);
+ push(LONG);
+ push(TOP);
+ break;
+ case Opcodes.FADD:
+ case Opcodes.FSUB:
+ case Opcodes.FMUL:
+ case Opcodes.FDIV:
+ case Opcodes.FREM:
+ case Opcodes.L2F:
+ case Opcodes.D2F:
+ pop(2);
+ push(FLOAT);
+ break;
+ case Opcodes.DADD:
+ case Opcodes.DSUB:
+ case Opcodes.DMUL:
+ case Opcodes.DDIV:
+ case Opcodes.DREM:
+ pop(4);
+ push(DOUBLE);
+ push(TOP);
+ break;
+ case Opcodes.LSHL:
+ case Opcodes.LSHR:
+ case Opcodes.LUSHR:
+ pop(3);
+ push(LONG);
+ push(TOP);
+ break;
+ case Opcodes.IINC:
+ set(arg, INTEGER);
+ break;
+ case Opcodes.I2L:
+ case Opcodes.F2L:
+ pop(1);
+ push(LONG);
+ push(TOP);
+ break;
+ case Opcodes.I2F:
+ pop(1);
+ push(FLOAT);
+ break;
+ case Opcodes.I2D:
+ case Opcodes.F2D:
+ pop(1);
+ push(DOUBLE);
+ push(TOP);
+ break;
+ case Opcodes.F2I:
+ case Opcodes.ARRAYLENGTH:
+ case Opcodes.INSTANCEOF:
+ pop(1);
+ push(INTEGER);
+ break;
+ case Opcodes.LCMP:
+ case Opcodes.DCMPL:
+ case Opcodes.DCMPG:
+ pop(4);
+ push(INTEGER);
+ break;
+ case Opcodes.JSR:
+ case Opcodes.RET:
+ throw new RuntimeException("JSR/RET are not supported with computeFrames option");
+ case Opcodes.GETSTATIC:
+ push(cw, item.strVal3);
+ break;
+ case Opcodes.PUTSTATIC:
+ pop(item.strVal3);
+ break;
+ case Opcodes.GETFIELD:
+ pop(1);
+ push(cw, item.strVal3);
+ break;
+ case Opcodes.PUTFIELD:
+ pop(item.strVal3);
+ pop();
+ break;
+ case Opcodes.INVOKEVIRTUAL:
+ case Opcodes.INVOKESPECIAL:
+ case Opcodes.INVOKESTATIC:
+ case Opcodes.INVOKEINTERFACE:
+ pop(item.strVal3);
+ if (opcode != Opcodes.INVOKESTATIC) {
+ t1 = pop();
+ if (opcode == Opcodes.INVOKESPECIAL && item.strVal2.charAt(0) == '<') {
+ init(t1);
+ }
+ }
+ push(cw, item.strVal3);
+ break;
+ case Opcodes.INVOKEDYNAMIC:
+ pop(item.strVal2);
+ push(cw, item.strVal2);
+ break;
+ case Opcodes.NEW:
+ push(UNINITIALIZED | cw.addUninitializedType(item.strVal1, arg));
+ break;
+ case Opcodes.NEWARRAY:
+ pop();
+ switch (arg) {
+ case Opcodes.T_BOOLEAN:
+ push(ARRAY_OF | BOOLEAN);
+ break;
+ case Opcodes.T_CHAR:
+ push(ARRAY_OF | CHAR);
+ break;
+ case Opcodes.T_BYTE:
+ push(ARRAY_OF | BYTE);
+ break;
+ case Opcodes.T_SHORT:
+ push(ARRAY_OF | SHORT);
+ break;
+ case Opcodes.T_INT:
+ push(ARRAY_OF | INTEGER);
+ break;
+ case Opcodes.T_FLOAT:
+ push(ARRAY_OF | FLOAT);
+ break;
+ case Opcodes.T_DOUBLE:
+ push(ARRAY_OF | DOUBLE);
+ break;
+ // case Opcodes.T_LONG:
+ default:
+ push(ARRAY_OF | LONG);
+ break;
+ }
+ break;
+ case Opcodes.ANEWARRAY:
+ String s = item.strVal1;
+ pop();
+ if (s.charAt(0) == '[') {
+ push(cw, '[' + s);
+ } else {
+ push(ARRAY_OF | OBJECT | cw.addType(s));
+ }
+ break;
+ case Opcodes.CHECKCAST:
+ s = item.strVal1;
+ pop();
+ if (s.charAt(0) == '[') {
+ push(cw, s);
+ } else {
+ push(OBJECT | cw.addType(s));
+ }
+ break;
+ // case Opcodes.MULTIANEWARRAY:
+ default:
+ pop(arg);
+ push(cw, item.strVal1);
+ break;
+ }
+ }
+
+ /**
+ * Merges the input frame of the given basic block with the input and output frames of this basic block. Returns
+ * <tt>true</tt> if the input frame of the given label has been changed by this operation.
+ *
+ * @param cw the ClassWriter to which this label belongs.
+ * @param frame the basic block whose input frame must be updated.
+ * @param edge the kind of the {@link Edge} between this label and 'label'. See {@link Edge#info}.
+ * @return <tt>true</tt> if the input frame of the given label has been changed by this operation.
+ */
+ final boolean merge(final ClassWriter cw, final Frame frame, final int edge) {
+ boolean changed = false;
+ int i, s, dim, kind, t;
+
+ int nLocal = inputLocals.length;
+ int nStack = inputStack.length;
+ if (frame.inputLocals == null) {
+ frame.inputLocals = new int[nLocal];
+ changed = true;
+ }
+
+ for (i = 0; i < nLocal; ++i) {
+ if (outputLocals != null && i < outputLocals.length) {
+ s = outputLocals[i];
+ if (s == 0) {
+ t = inputLocals[i];
+ } else {
+ dim = s & DIM;
+ kind = s & KIND;
+ if (kind == BASE) {
+ t = s;
+ } else {
+ if (kind == LOCAL) {
+ t = dim + inputLocals[s & VALUE];
+ } else {
+ t = dim + inputStack[nStack - (s & VALUE)];
+ }
+ if ((s & TOP_IF_LONG_OR_DOUBLE) != 0 && (t == LONG || t == DOUBLE)) {
+ t = TOP;
+ }
+ }
+ }
+ } else {
+ t = inputLocals[i];
+ }
+ if (initializations != null) {
+ t = init(cw, t);
+ }
+ changed |= merge(cw, t, frame.inputLocals, i);
+ }
+
+ if (edge > 0) {
+ for (i = 0; i < nLocal; ++i) {
+ t = inputLocals[i];
+ changed |= merge(cw, t, frame.inputLocals, i);
+ }
+ if (frame.inputStack == null) {
+ frame.inputStack = new int[1];
+ changed = true;
+ }
+ changed |= merge(cw, edge, frame.inputStack, 0);
+ return changed;
+ }
+
+ int nInputStack = inputStack.length + owner.inputStackTop;
+ if (frame.inputStack == null) {
+ frame.inputStack = new int[nInputStack + outputStackTop];
+ changed = true;
+ }
+
+ for (i = 0; i < nInputStack; ++i) {
+ t = inputStack[i];
+ if (initializations != null) {
+ t = init(cw, t);
+ }
+ changed |= merge(cw, t, frame.inputStack, i);
+ }
+ for (i = 0; i < outputStackTop; ++i) {
+ s = outputStack[i];
+ dim = s & DIM;
+ kind = s & KIND;
+ if (kind == BASE) {
+ t = s;
+ } else {
+ if (kind == LOCAL) {
+ t = dim + inputLocals[s & VALUE];
+ } else {
+ t = dim + inputStack[nStack - (s & VALUE)];
+ }
+ if ((s & TOP_IF_LONG_OR_DOUBLE) != 0 && (t == LONG || t == DOUBLE)) {
+ t = TOP;
+ }
+ }
+ if (initializations != null) {
+ t = init(cw, t);
+ }
+ changed |= merge(cw, t, frame.inputStack, nInputStack + i);
+ }
+ return changed;
+ }
+
+ /**
+ * Merges the type at the given index in the given type array with the given type. Returns
+ * <tt>true</tt> if the type array has been modified by this operation.
+ *
+ * @param cw the ClassWriter to which this label belongs.
+ * @param t the type with which the type array element must be merged.
+ * @param types an array of types.
+ * @param index the index of the type that must be merged in 'types'.
+ * @return <tt>true</tt> if the type array has been modified by this operation.
+ */
+ private static boolean merge(final ClassWriter cw, int t, final int[] types, final int index) {
+ int u = types[index];
+ if (u == t) {
+ // if the types are equal, merge(u,t)=u, so there is no change
+ return false;
+ }
+ if ((t & ~DIM) == NULL) {
+ if (u == NULL) {
+ return false;
+ }
+ t = NULL;
+ }
+ if (u == 0) {
+ // if types[index] has never been assigned, merge(u,t)=t
+ types[index] = t;
+ return true;
+ }
+ int v;
+ if ((u & BASE_KIND) == OBJECT || (u & DIM) != 0) {
+ // if u is a reference type of any dimension
+ if (t == NULL) {
+ // if t is the NULL type, merge(u,t)=u, so there is no change
+ return false;
+ } else if ((t & (DIM | BASE_KIND)) == (u & (DIM | BASE_KIND))) {
+ // if t and u have the same dimension and same base kind
+ if ((u & BASE_KIND) == OBJECT) {
+ // if t is also a reference type, and if u and t have the
+ // same dimension merge(u,t) = dim(t) | common parent of the
+ // element types of u and t
+ v = (t & DIM) | OBJECT | cw.getMergedType(t & BASE_VALUE, u & BASE_VALUE);
+ } else {
+ // if u and t are array types, but not with the same element
+ // type, merge(u,t) = dim(u) - 1 | java/lang/Object
+ int vdim = ELEMENT_OF + (u & DIM);
+ v = vdim | OBJECT | cw.addType("java/lang/Object");
+ }
+ } else if ((t & BASE_KIND) == OBJECT || (t & DIM) != 0) {
+ // if t is any other reference or array type, the merged type
+ // is min(udim, tdim) | java/lang/Object, where udim is the
+ // array dimension of u, minus 1 if u is an array type with a
+ // primitive element type (and similarly for tdim).
+ int tdim = (((t & DIM) == 0 || (t & BASE_KIND) == OBJECT) ? 0 : ELEMENT_OF) + (t & DIM);
+ int udim = (((u & DIM) == 0 || (u & BASE_KIND) == OBJECT) ? 0 : ELEMENT_OF) + (u & DIM);
+ v = Math.min(tdim, udim) | OBJECT | cw.addType("java/lang/Object");
+ } else {
+ // if t is any other type, merge(u,t)=TOP
+ v = TOP;
+ }
+ } else if (u == NULL) {
+ // if u is the NULL type, merge(u,t)=t,
+ // or TOP if t is not a reference type
+ v = (t & BASE_KIND) == OBJECT || (t & DIM) != 0 ? t : TOP;
+ } else {
+ // if u is any other type, merge(u,t)=TOP whatever t
+ v = TOP;
+ }
+ if (u != v) {
+ types[index] = v;
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/src/main/java/org/redkale/asm/Handle.java b/src/main/java/org/redkale/asm/Handle.java
index cd3d9008f..d3da4d3d1 100644
--- a/src/main/java/org/redkale/asm/Handle.java
+++ b/src/main/java/org/redkale/asm/Handle.java
@@ -1,190 +1,190 @@
-/*
- * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- */
-
-/*
- *
- *
- *
- *
- *
- * ASM: a very small and fast Java bytecode manipulation framework
- * Copyright (c) 2000-2011 INRIA, France Telecom
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package org.redkale.asm;
-
-/**
- * A reference to a field or a method.
- *
- * @author Remi Forax
- * @author Eric Bruneton
- */
-public final class Handle {
-
- /**
- * The kind of field or method designated by this Handle. Should be {@link Opcodes#H_GETFIELD},
- * {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC},
- * {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL},
- * {@link Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}.
- */
- final int tag;
-
- /** The internal name of the class that owns the field or method designated by this handle. */
- final String owner;
-
- /** The name of the field or method designated by this handle. */
- final String name;
-
- /** The descriptor of the field or method designated by this handle. */
- final String desc;
-
- /** Indicate if the owner is an interface or not. */
- final boolean itf;
-
- /**
- * Constructs a new field or method handle.
- *
- * @param tag the kind of field or method designated by this Handle. Must be {@link Opcodes#H_GETFIELD},
- * {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC},
- * {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL},
- * {@link Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}.
- * @param owner the internal name of the class that owns the field or method designated by this handle.
- * @param name the name of the field or method designated by this handle.
- * @param desc the descriptor of the field or method designated by this handle.
- * @param itf true if the owner is an interface.
- */
- public Handle(int tag, String owner, String name, String desc, boolean itf) {
- this.tag = tag;
- this.owner = owner;
- this.name = name;
- this.desc = desc;
- this.itf = itf;
- }
-
- /**
- * Returns the kind of field or method designated by this handle.
- *
- * @return {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD},
- * {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC},
- * {@link Opcodes#H_INVOKESPECIAL}, {@link Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}.
- */
- public int getTag() {
- return tag;
- }
-
- /**
- * Returns the internal name of the class that owns the field or method designated by this handle.
- *
- * @return the internal name of the class that owns the field or method designated by this handle.
- */
- public String getOwner() {
- return owner;
- }
-
- /**
- * Returns the name of the field or method designated by this handle.
- *
- * @return the name of the field or method designated by this handle.
- */
- public String getName() {
- return name;
- }
-
- /**
- * Returns the descriptor of the field or method designated by this handle.
- *
- * @return the descriptor of the field or method designated by this handle.
- */
- public String getDesc() {
- return desc;
- }
-
- /**
- * Returns true if the owner of the field or method designated by this handle is an interface.
- *
- * @return true if the owner of the field or method designated by this handle is an interface.
- */
- public boolean isInterface() {
- return itf;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (obj == this) {
- return true;
- }
- if (!(obj instanceof Handle)) {
- return false;
- }
- Handle h = (Handle) obj;
- return tag == h.tag && itf == h.itf && owner.equals(h.owner) && name.equals(h.name) && desc.equals(h.desc);
- }
-
- @Override
- public int hashCode() {
- return tag + (itf ? 64 : 0) + owner.hashCode() * name.hashCode() * desc.hashCode();
- }
-
- /**
- * Returns the textual representation of this handle. The textual representation is:
- *
- * MethodHandle constant 9 variations are stored using a range of 9 values from {@link ClassWriter#HANDLE_BASE} +
- * 1 to {@link ClassWriter#HANDLE_BASE} + 9.
- *
- * Special Item types are used for Items that are stored in the ClassWriter {@link ClassWriter#typeTable},
- * instead of the constant pool, in order to avoid clashes with normal constant pool items in the ClassWriter
- * constant pool's hash table. These special item types are {@link ClassWriter#TYPE_NORMAL},
- * {@link ClassWriter#TYPE_UNINIT} and {@link ClassWriter#TYPE_MERGED}.
- */
- int type;
-
- /** Value of this item, for an integer item. */
- int intVal;
-
- /** Value of this item, for a long item. */
- long longVal;
-
- /** First part of the value of this item, for items that do not hold a primitive value. */
- String strVal1;
-
- /** Second part of the value of this item, for items that do not hold a primitive value. */
- String strVal2;
-
- /** Third part of the value of this item, for items that do not hold a primitive value. */
- String strVal3;
-
- /** The hash code value of this constant pool item. */
- int hashCode;
-
- /** Link to another constant pool item, used for collision lists in the constant pool's hash table. */
- Item next;
-
- /** Constructs an uninitialized {@link Item}. */
- Item() {}
-
- /**
- * Constructs an uninitialized {@link Item} for constant pool element at given position.
- *
- * @param index index of the item to be constructed.
- */
- Item(final int index) {
- this.index = index;
- }
-
- /**
- * Constructs a copy of the given item.
- *
- * @param index index of the item to be constructed.
- * @param i the item that must be copied into the item to be constructed.
- */
- Item(final int index, final Item i) {
- this.index = index;
- type = i.type;
- intVal = i.intVal;
- longVal = i.longVal;
- strVal1 = i.strVal1;
- strVal2 = i.strVal2;
- strVal3 = i.strVal3;
- hashCode = i.hashCode;
- }
-
- /**
- * Sets this item to an integer item.
- *
- * @param intVal the value of this item.
- */
- void set(final int intVal) {
- this.type = ClassWriter.INT;
- this.intVal = intVal;
- this.hashCode = 0x7FFFFFFF & (type + intVal);
- }
-
- /**
- * Sets this item to a long item.
- *
- * @param longVal the value of this item.
- */
- void set(final long longVal) {
- this.type = ClassWriter.LONG;
- this.longVal = longVal;
- this.hashCode = 0x7FFFFFFF & (type + (int) longVal);
- }
-
- /**
- * Sets this item to a float item.
- *
- * @param floatVal the value of this item.
- */
- void set(final float floatVal) {
- this.type = ClassWriter.FLOAT;
- this.intVal = Float.floatToRawIntBits(floatVal);
- this.hashCode = 0x7FFFFFFF & (type + (int) floatVal);
- }
-
- /**
- * Sets this item to a double item.
- *
- * @param doubleVal the value of this item.
- */
- void set(final double doubleVal) {
- this.type = ClassWriter.DOUBLE;
- this.longVal = Double.doubleToRawLongBits(doubleVal);
- this.hashCode = 0x7FFFFFFF & (type + (int) doubleVal);
- }
-
- /**
- * Sets this item to an item that do not hold a primitive value.
- *
- * @param type the type of this item.
- * @param strVal1 first part of the value of this item.
- * @param strVal2 second part of the value of this item.
- * @param strVal3 third part of the value of this item.
- */
- @SuppressWarnings("fallthrough")
- void set(final int type, final String strVal1, final String strVal2, final String strVal3) {
- this.type = type;
- this.strVal1 = strVal1;
- this.strVal2 = strVal2;
- this.strVal3 = strVal3;
- switch (type) {
- case ClassWriter.CLASS:
- this.intVal = 0; // intVal of a class must be zero, see visitInnerClass
- case ClassWriter.UTF8:
- case ClassWriter.STR:
- case ClassWriter.MTYPE:
- case ClassWriter.MODULE:
- case ClassWriter.PACKAGE:
- case ClassWriter.TYPE_NORMAL:
- hashCode = 0x7FFFFFFF & (type + strVal1.hashCode());
- return;
- case ClassWriter.NAME_TYPE: {
- hashCode = 0x7FFFFFFF & (type + strVal1.hashCode() * strVal2.hashCode());
- return;
- }
- // ClassWriter.FIELD:
- // ClassWriter.METH:
- // ClassWriter.IMETH:
- // ClassWriter.HANDLE_BASE + 1..9
- default:
- hashCode = 0x7FFFFFFF & (type + strVal1.hashCode() * strVal2.hashCode() * strVal3.hashCode());
- }
- }
-
- /**
- * Sets the item to an InvokeDynamic item.
- *
- * @param name invokedynamic's name.
- * @param desc invokedynamic's desc.
- * @param bsmIndex zero based index into the class attribute BootrapMethods.
- */
- void set(String name, String desc, int bsmIndex) {
- this.type = ClassWriter.INDY;
- this.longVal = bsmIndex;
- this.strVal1 = name;
- this.strVal2 = desc;
- this.hashCode = 0x7FFFFFFF & (ClassWriter.INDY + bsmIndex * strVal1.hashCode() * strVal2.hashCode());
- }
-
- /**
- * Sets the item to a BootstrapMethod item.
- *
- * @param position position in byte in the class attribute BootrapMethods.
- * @param hashCode hashcode of the item. This hashcode is processed from the hashcode of the bootstrap method and
- * the hashcode of all bootstrap arguments.
- */
- void set(int position, int hashCode) {
- this.type = ClassWriter.BSM;
- this.intVal = position;
- this.hashCode = hashCode;
- }
-
- /**
- * Indicates if the given item is equal to this one. This method assumes that the two items have the same
- * {@link #type}.
- *
- * @param i the item to be compared to this one. Both items must have the same {@link #type}.
- * @return <tt>true</tt> if the given item if equal to this one, <tt>false</tt>
- * otherwise.
- */
- boolean isEqualTo(final Item i) {
- switch (type) {
- case ClassWriter.UTF8:
- case ClassWriter.STR:
- case ClassWriter.CLASS:
- case ClassWriter.MODULE:
- case ClassWriter.PACKAGE:
- case ClassWriter.MTYPE:
- case ClassWriter.TYPE_NORMAL:
- return i.strVal1.equals(strVal1);
- case ClassWriter.TYPE_MERGED:
- case ClassWriter.LONG:
- case ClassWriter.DOUBLE:
- return i.longVal == longVal;
- case ClassWriter.INT:
- case ClassWriter.FLOAT:
- return i.intVal == intVal;
- case ClassWriter.TYPE_UNINIT:
- return i.intVal == intVal && i.strVal1.equals(strVal1);
- case ClassWriter.NAME_TYPE:
- return i.strVal1.equals(strVal1) && i.strVal2.equals(strVal2);
- case ClassWriter.INDY: {
- return i.longVal == longVal && i.strVal1.equals(strVal1) && i.strVal2.equals(strVal2);
- }
- // case ClassWriter.FIELD:
- // case ClassWriter.METH:
- // case ClassWriter.IMETH:
- // case ClassWriter.HANDLE_BASE + 1..9
- default:
- return i.strVal1.equals(strVal1) && i.strVal2.equals(strVal2) && i.strVal3.equals(strVal3);
- }
- }
-}
+/*
+ * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ */
+
+/*
+ *
+ *
+ *
+ *
+ *
+ * ASM: a very small and fast Java bytecode manipulation framework
+ * Copyright (c) 2000-2011 INRIA, France Telecom
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.redkale.asm;
+
+/**
+ * A constant pool item. Constant pool items can be created with the 'newXXX' methods in the {@link ClassWriter} class.
+ *
+ * @author Eric Bruneton
+ */
+final class Item {
+
+ /** Index of this item in the constant pool. */
+ int index;
+
+ /**
+ * Type of this constant pool item. A single class is used to represent all constant pool item types, in order to
+ * minimize the bytecode size of this package. The value of this field is one of {@link ClassWriter#INT},
+ * {@link ClassWriter#LONG}, {@link ClassWriter#FLOAT}, {@link ClassWriter#DOUBLE}, {@link ClassWriter#UTF8},
+ * {@link ClassWriter#STR}, {@link ClassWriter#CLASS}, {@link ClassWriter#NAME_TYPE}, {@link ClassWriter#FIELD},
+ * {@link ClassWriter#METH}, {@link ClassWriter#IMETH}, {@link ClassWriter#MODULE}, {@link ClassWriter#PACKAGE},
+ * {@link ClassWriter#MTYPE}, {@link ClassWriter#INDY}.
+ *
+ * MethodHandle constant 9 variations are stored using a range of 9 values from {@link ClassWriter#HANDLE_BASE} +
+ * 1 to {@link ClassWriter#HANDLE_BASE} + 9.
+ *
+ * Special Item types are used for Items that are stored in the ClassWriter {@link ClassWriter#typeTable},
+ * instead of the constant pool, in order to avoid clashes with normal constant pool items in the ClassWriter
+ * constant pool's hash table. These special item types are {@link ClassWriter#TYPE_NORMAL},
+ * {@link ClassWriter#TYPE_UNINIT} and {@link ClassWriter#TYPE_MERGED}.
+ */
+ int type;
+
+ /** Value of this item, for an integer item. */
+ int intVal;
+
+ /** Value of this item, for a long item. */
+ long longVal;
+
+ /** First part of the value of this item, for items that do not hold a primitive value. */
+ String strVal1;
+
+ /** Second part of the value of this item, for items that do not hold a primitive value. */
+ String strVal2;
+
+ /** Third part of the value of this item, for items that do not hold a primitive value. */
+ String strVal3;
+
+ /** The hash code value of this constant pool item. */
+ int hashCode;
+
+ /** Link to another constant pool item, used for collision lists in the constant pool's hash table. */
+ Item next;
+
+ /** Constructs an uninitialized {@link Item}. */
+ Item() {}
+
+ /**
+ * Constructs an uninitialized {@link Item} for constant pool element at given position.
+ *
+ * @param index index of the item to be constructed.
+ */
+ Item(final int index) {
+ this.index = index;
+ }
+
+ /**
+ * Constructs a copy of the given item.
+ *
+ * @param index index of the item to be constructed.
+ * @param i the item that must be copied into the item to be constructed.
+ */
+ Item(final int index, final Item i) {
+ this.index = index;
+ type = i.type;
+ intVal = i.intVal;
+ longVal = i.longVal;
+ strVal1 = i.strVal1;
+ strVal2 = i.strVal2;
+ strVal3 = i.strVal3;
+ hashCode = i.hashCode;
+ }
+
+ /**
+ * Sets this item to an integer item.
+ *
+ * @param intVal the value of this item.
+ */
+ void set(final int intVal) {
+ this.type = ClassWriter.INT;
+ this.intVal = intVal;
+ this.hashCode = 0x7FFFFFFF & (type + intVal);
+ }
+
+ /**
+ * Sets this item to a long item.
+ *
+ * @param longVal the value of this item.
+ */
+ void set(final long longVal) {
+ this.type = ClassWriter.LONG;
+ this.longVal = longVal;
+ this.hashCode = 0x7FFFFFFF & (type + (int) longVal);
+ }
+
+ /**
+ * Sets this item to a float item.
+ *
+ * @param floatVal the value of this item.
+ */
+ void set(final float floatVal) {
+ this.type = ClassWriter.FLOAT;
+ this.intVal = Float.floatToRawIntBits(floatVal);
+ this.hashCode = 0x7FFFFFFF & (type + (int) floatVal);
+ }
+
+ /**
+ * Sets this item to a double item.
+ *
+ * @param doubleVal the value of this item.
+ */
+ void set(final double doubleVal) {
+ this.type = ClassWriter.DOUBLE;
+ this.longVal = Double.doubleToRawLongBits(doubleVal);
+ this.hashCode = 0x7FFFFFFF & (type + (int) doubleVal);
+ }
+
+ /**
+ * Sets this item to an item that do not hold a primitive value.
+ *
+ * @param type the type of this item.
+ * @param strVal1 first part of the value of this item.
+ * @param strVal2 second part of the value of this item.
+ * @param strVal3 third part of the value of this item.
+ */
+ @SuppressWarnings("fallthrough")
+ void set(final int type, final String strVal1, final String strVal2, final String strVal3) {
+ this.type = type;
+ this.strVal1 = strVal1;
+ this.strVal2 = strVal2;
+ this.strVal3 = strVal3;
+ switch (type) {
+ case ClassWriter.CLASS:
+ this.intVal = 0; // intVal of a class must be zero, see visitInnerClass
+ case ClassWriter.UTF8:
+ case ClassWriter.STR:
+ case ClassWriter.MTYPE:
+ case ClassWriter.MODULE:
+ case ClassWriter.PACKAGE:
+ case ClassWriter.TYPE_NORMAL:
+ hashCode = 0x7FFFFFFF & (type + strVal1.hashCode());
+ return;
+ case ClassWriter.NAME_TYPE: {
+ hashCode = 0x7FFFFFFF & (type + strVal1.hashCode() * strVal2.hashCode());
+ return;
+ }
+ // ClassWriter.FIELD:
+ // ClassWriter.METH:
+ // ClassWriter.IMETH:
+ // ClassWriter.HANDLE_BASE + 1..9
+ default:
+ hashCode = 0x7FFFFFFF & (type + strVal1.hashCode() * strVal2.hashCode() * strVal3.hashCode());
+ }
+ }
+
+ /**
+ * Sets the item to an InvokeDynamic item.
+ *
+ * @param name invokedynamic's name.
+ * @param desc invokedynamic's desc.
+ * @param bsmIndex zero based index into the class attribute BootrapMethods.
+ */
+ void set(String name, String desc, int bsmIndex) {
+ this.type = ClassWriter.INDY;
+ this.longVal = bsmIndex;
+ this.strVal1 = name;
+ this.strVal2 = desc;
+ this.hashCode = 0x7FFFFFFF & (ClassWriter.INDY + bsmIndex * strVal1.hashCode() * strVal2.hashCode());
+ }
+
+ /**
+ * Sets the item to a BootstrapMethod item.
+ *
+ * @param position position in byte in the class attribute BootrapMethods.
+ * @param hashCode hashcode of the item. This hashcode is processed from the hashcode of the bootstrap method and
+ * the hashcode of all bootstrap arguments.
+ */
+ void set(int position, int hashCode) {
+ this.type = ClassWriter.BSM;
+ this.intVal = position;
+ this.hashCode = hashCode;
+ }
+
+ /**
+ * Indicates if the given item is equal to this one. This method assumes that the two items have the same
+ * {@link #type}.
+ *
+ * @param i the item to be compared to this one. Both items must have the same {@link #type}.
+ * @return <tt>true</tt> if the given item if equal to this one, <tt>false</tt>
+ * otherwise.
+ */
+ boolean isEqualTo(final Item i) {
+ switch (type) {
+ case ClassWriter.UTF8:
+ case ClassWriter.STR:
+ case ClassWriter.CLASS:
+ case ClassWriter.MODULE:
+ case ClassWriter.PACKAGE:
+ case ClassWriter.MTYPE:
+ case ClassWriter.TYPE_NORMAL:
+ return i.strVal1.equals(strVal1);
+ case ClassWriter.TYPE_MERGED:
+ case ClassWriter.LONG:
+ case ClassWriter.DOUBLE:
+ return i.longVal == longVal;
+ case ClassWriter.INT:
+ case ClassWriter.FLOAT:
+ return i.intVal == intVal;
+ case ClassWriter.TYPE_UNINIT:
+ return i.intVal == intVal && i.strVal1.equals(strVal1);
+ case ClassWriter.NAME_TYPE:
+ return i.strVal1.equals(strVal1) && i.strVal2.equals(strVal2);
+ case ClassWriter.INDY: {
+ return i.longVal == longVal && i.strVal1.equals(strVal1) && i.strVal2.equals(strVal2);
+ }
+ // case ClassWriter.FIELD:
+ // case ClassWriter.METH:
+ // case ClassWriter.IMETH:
+ // case ClassWriter.HANDLE_BASE + 1..9
+ default:
+ return i.strVal1.equals(strVal1) && i.strVal2.equals(strVal2) && i.strVal3.equals(strVal3);
+ }
+ }
+}
diff --git a/src/main/java/org/redkale/asm/Label.java b/src/main/java/org/redkale/asm/Label.java
index 04cc983ea..f2baeb3d0 100644
--- a/src/main/java/org/redkale/asm/Label.java
+++ b/src/main/java/org/redkale/asm/Label.java
@@ -1,509 +1,509 @@
-/*
- * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- */
-
-/*
- *
- *
- *
- *
- *
- * ASM: a very small and fast Java bytecode manipulation framework
- * Copyright (c) 2000-2011 INRIA, France Telecom
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-package org.redkale.asm;
-
-/**
- * A label represents a position in the bytecode of a method. Labels are used for jump, goto, and switch instructions,
- * and for try catch blocks. A label designates the instruction that is just after. Note however that there can
- * be other elements between a label and the instruction it designates (such as other labels, stack map frames, line
- * numbers, etc.).
- *
- * @author Eric Bruneton
- */
-public class Label {
-
- /**
- * Indicates if this label is only used for debug attributes. Such a label is not the start of a basic block, the
- * target of a jump instruction, or an exception handler. It can be safely ignored in control flow graph analysis
- * algorithms (for optimization purposes).
- */
- static final int DEBUG = 1;
-
- /** Indicates if the position of this label is known. */
- static final int RESOLVED = 2;
-
- /** Indicates if this label has been updated, after instruction resizing. */
- static final int RESIZED = 4;
-
- /**
- * Indicates if this basic block has been pushed in the basic block stack. See {@link MethodWriter#visitMaxs
- * visitMaxs}.
- */
- static final int PUSHED = 8;
-
- /** Indicates if this label is the target of a jump instruction, or the start of an exception handler. */
- static final int TARGET = 16;
-
- /** Indicates if a stack map frame must be stored for this label. */
- static final int STORE = 32;
-
- /** Indicates if this label corresponds to a reachable basic block. */
- static final int REACHABLE = 64;
-
- /** Indicates if this basic block ends with a JSR instruction. */
- static final int JSR = 128;
-
- /** Indicates if this basic block ends with a RET instruction. */
- static final int RET = 256;
-
- /** Indicates if this basic block is the start of a subroutine. */
- static final int SUBROUTINE = 512;
-
- /** Indicates if this subroutine basic block has been visited by a visitSubroutine(null, ...) call. */
- static final int VISITED = 1024;
-
- /** Indicates if this subroutine basic block has been visited by a visitSubroutine(!null, ...) call. */
- static final int VISITED2 = 2048;
-
- /**
- * Field used to associate user information to a label. Warning: this field is used by the ASM tree package. In
- * order to use it with the ASM tree package you must override the
- */
- public Object info;
-
- /**
- * Flags that indicate the status of this label.
- *
- * @see #DEBUG
- * @see #RESOLVED
- * @see #RESIZED
- * @see #PUSHED
- * @see #TARGET
- * @see #STORE
- * @see #REACHABLE
- * @see #JSR
- * @see #RET
- */
- int status;
-
- /**
- * The line number corresponding to this label, if known. If there are several lines, each line is stored in a
- * separate label, all linked via their next field (these links are created in ClassReader and removed just before
- * visitLabel is called, so that this does not impact the rest of the code).
- */
- int line;
-
- /** The position of this label in the code, if known. */
- int position;
-
- /** Number of forward references to this label, times two. */
- private int referenceCount;
-
- /**
- * Informations about forward references. Each forward reference is described by two consecutive integers in this
- * array: the first one is the position of the first byte of the bytecode instruction that contains the forward
- * reference, while the second is the position of the first byte of the forward reference itself. In fact the sign
- * of the first integer indicates if this reference uses 2 or 4 bytes, and its absolute value gives the position of
- * the bytecode instruction. This array is also used as a bitset to store the subroutines to which a basic block
- * belongs. This information is needed in {@linked MethodWriter#visitMaxs}, after all forward references have been
- * resolved. Hence the same array can be used for both purposes without problems.
- */
- private int[] srcAndRefPositions;
-
- // ------------------------------------------------------------------------
-
- /*
- * Fields for the control flow and data flow graph analysis algorithms (used
- * to compute the maximum stack size or the stack map frames). A control
- * flow graph contains one node per "basic block", and one edge per "jump"
- * from one basic block to another. Each node (i.e., each basic block) is
- * represented by the Label object that corresponds to the first instruction
- * of this basic block. Each node also stores the list of its successors in
- * the graph, as a linked list of Edge objects.
- *
- * The control flow analysis algorithms used to compute the maximum stack
- * size or the stack map frames are similar and use two steps. The first
- * step, during the visit of each instruction, builds information about the
- * state of the local variables and the operand stack at the end of each
- * basic block, called the "output frame", relatively to the frame
- * state at the beginning of the basic block, which is called the "input
- * frame", and which is unknown during this step. The second step, in
- * {@link MethodWriter#visitMaxs}, is a fix point algorithm that computes
- * information about the input frame of each basic block, from the input
- * state of the first basic block (known from the method signature), and by
- * the using the previously computed relative output frames.
- *
- * The algorithm used to compute the maximum stack size only computes the
- * relative output and absolute input stack heights, while the algorithm
- * used to compute stack map frames computes relative output frames and
- * absolute input frames.
- */
-
- /**
- * Start of the output stack relatively to the input stack. The exact semantics of this field depends on the
- * algorithm that is used.
- *
- * When only the maximum stack size is computed, this field is the number of elements in the input stack.
- *
- * When the stack map frames are completely computed, this field is the offset of the first output stack element
- * relatively to the top of the input stack. This offset is always negative or null. A null offset means that the
- * output stack must be appended to the input stack. A -n offset means that the first n output stack elements must
- * replace the top n input stack elements, and that the other elements must be appended to the input stack.
- */
- int inputStackTop;
-
- /**
- * Maximum height reached by the output stack, relatively to the top of the input stack. This maximum is always
- * positive or null.
- */
- int outputStackMax;
-
- /**
- * Information about the input and output stack map frames of this basic block. This field is only used when
- * {@link ClassWriter#COMPUTE_FRAMES} option is used.
- */
- Frame frame;
-
- /**
- * The successor of this label, in the order they are visited. This linked list does not include labels used for
- * debug info only. If {@link ClassWriter#COMPUTE_FRAMES} option is used then, in addition, it does not contain
- * successive labels that denote the same bytecode position (in this case only the first label appears in this
- * list).
- */
- Label successor;
-
- /**
- * The successors of this node in the control flow graph. These successors are stored in a linked list of
- * {@link Edge Edge} objects, linked to each other by their {@link Edge#next} field.
- */
- Edge successors;
-
- /**
- * The next basic block in the basic block stack. This stack is used in the main loop of the fix point algorithm
- * used in the second step of the control flow analysis algorithms. It is also used in {@link #visitSubroutine} to
- * avoid using a recursive method, and in ClassReader to temporarily store multiple source lines for a label.
- *
- * @see MethodWriter#visitMaxs
- */
- Label next;
-
- // ------------------------------------------------------------------------
- // Constructor
- // ------------------------------------------------------------------------
-
- /** Constructs a new label. */
- public Label() {
- // do nothing
- }
-
- // ------------------------------------------------------------------------
- // Methods to compute offsets and to manage forward references
- // ------------------------------------------------------------------------
-
- /**
- * Returns the offset corresponding to this label. This offset is computed from the start of the method's bytecode.
- * This method is intended for {@link Attribute} sub classes, and is normally not needed by class generators or
- * adapters.
- *
- * @return the offset corresponding to this label.
- * @throws IllegalStateException if this label is not resolved yet.
- */
- public int getOffset() {
- if ((status & RESOLVED) == 0) {
- throw new IllegalStateException("Label offset position has not been resolved yet");
- }
- return position;
- }
-
- /**
- * Puts a reference to this label in the bytecode of a method. If the position of the label is known, the offset is
- * computed and written directly. Otherwise, a null offset is written and a new forward reference is declared for
- * this label.
- *
- * @param owner the code writer that calls this method.
- * @param out the bytecode of the method.
- * @param source the position of first byte of the bytecode instruction that contains this label.
- * @param wideOffset <tt>true</tt> if the reference must be stored in 4 bytes, or
- * <tt>false</tt> if it must be stored with 2 bytes.
- * @throws IllegalArgumentException if this label has not been created by the given code writer.
- */
- void put(final MethodWriter owner, final ByteVector out, final int source, final boolean wideOffset) {
- if ((status & RESOLVED) == 0) {
- if (wideOffset) {
- addReference(-1 - source, out.length);
- out.putInt(-1);
- } else {
- addReference(source, out.length);
- out.putShort(-1);
- }
- } else {
- if (wideOffset) {
- out.putInt(position - source);
- } else {
- out.putShort(position - source);
- }
- }
- }
-
- /**
- * Adds a forward reference to this label. This method must be called only for a true forward reference, i.e. only
- * if this label is not resolved yet. For backward references, the offset of the reference can be, and must be,
- * computed and stored directly.
- *
- * @param sourcePosition the position of the referencing instruction. This position will be used to compute the
- * offset of this forward reference.
- * @param referencePosition the position where the offset for this forward reference must be stored.
- */
- private void addReference(final int sourcePosition, final int referencePosition) {
- if (srcAndRefPositions == null) {
- srcAndRefPositions = new int[6];
- }
- if (referenceCount >= srcAndRefPositions.length) {
- int[] a = new int[srcAndRefPositions.length + 6];
- System.arraycopy(srcAndRefPositions, 0, a, 0, srcAndRefPositions.length);
- srcAndRefPositions = a;
- }
- srcAndRefPositions[referenceCount++] = sourcePosition;
- srcAndRefPositions[referenceCount++] = referencePosition;
- }
-
- /**
- * Resolves all forward references to this label. This method must be called when this label is added to the
- * bytecode of the method, i.e. when its position becomes known. This method fills in the blanks that where left in
- * the bytecode by each forward reference previously added to this label.
- *
- * @param owner the code writer that calls this method.
- * @param position the position of this label in the bytecode.
- * @param data the bytecode of the method.
- * @return <tt>true</tt> if a blank that was left for this label was too small to store the offset.
- * In such a case the corresponding jump instruction is replaced with a pseudo instruction (using unused
- * opcodes) using an unsigned two bytes offset. These pseudo instructions will be replaced with standard
- * bytecode instructions with wider offsets (4 bytes instead of 2), in ClassReader.
- * @throws IllegalArgumentException if this label has already been resolved, or if it has not been created by the
- * given code writer.
- */
- boolean resolve(final MethodWriter owner, final int position, final byte[] data) {
- boolean needUpdate = false;
- this.status |= RESOLVED;
- this.position = position;
- int i = 0;
- while (i < referenceCount) {
- int source = srcAndRefPositions[i++];
- int reference = srcAndRefPositions[i++];
- int offset;
- if (source >= 0) {
- offset = position - source;
- if (offset < Short.MIN_VALUE || offset > Short.MAX_VALUE) {
- /*
- * changes the opcode of the jump instruction, in order to
- * be able to find it later (see resizeInstructions in
- * MethodWriter). These temporary opcodes are similar to
- * jump instruction opcodes, except that the 2 bytes offset
- * is unsigned (and can therefore represent values from 0 to
- * 65535, which is sufficient since the size of a method is
- * limited to 65535 bytes).
- */
- int opcode = data[reference - 1] & 0xFF;
- if (opcode <= Opcodes.JSR) {
- // changes IFEQ ... JSR to opcodes 202 to 217
- data[reference - 1] = (byte) (opcode + 49);
- } else {
- // changes IFNULL and IFNONNULL to opcodes 218 and 219
- data[reference - 1] = (byte) (opcode + 20);
- }
- needUpdate = true;
- }
- data[reference++] = (byte) (offset >>> 8);
- data[reference] = (byte) offset;
- } else {
- offset = position + source + 1;
- data[reference++] = (byte) (offset >>> 24);
- data[reference++] = (byte) (offset >>> 16);
- data[reference++] = (byte) (offset >>> 8);
- data[reference] = (byte) offset;
- }
- }
- return needUpdate;
- }
-
- /**
- * Returns the first label of the series to which this label belongs. For an isolated label or for the first label
- * in a series of successive labels, this method returns the label itself. For other labels it returns the first
- * label of the series.
- *
- * @return the first label of the series to which this label belongs.
- */
- Label getFirst() {
- return frame == null ? this : frame.owner;
- }
-
- // ------------------------------------------------------------------------
- // Methods related to subroutines
- // ------------------------------------------------------------------------
-
- /**
- * Returns true is this basic block belongs to the given subroutine.
- *
- * @param id a subroutine id.
- * @return true is this basic block belongs to the given subroutine.
- */
- boolean inSubroutine(final long id) {
- if ((status & Label.VISITED) != 0) {
- return (srcAndRefPositions[(int) (id >>> 32)] & (int) id) != 0;
- }
- return false;
- }
-
- /**
- * Returns true if this basic block and the given one belong to a common subroutine.
- *
- * @param block another basic block.
- * @return true if this basic block and the given one belong to a common subroutine.
- */
- boolean inSameSubroutine(final Label block) {
- if ((status & VISITED) == 0 || (block.status & VISITED) == 0) {
- return false;
- }
- for (int i = 0; i < srcAndRefPositions.length; ++i) {
- if ((srcAndRefPositions[i] & block.srcAndRefPositions[i]) != 0) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Marks this basic block as belonging to the given subroutine.
- *
- * @param id a subroutine id.
- * @param nbSubroutines the total number of subroutines in the method.
- */
- void addToSubroutine(final long id, final int nbSubroutines) {
- if ((status & VISITED) == 0) {
- status |= VISITED;
- srcAndRefPositions = new int[nbSubroutines / 32 + 1];
- }
- srcAndRefPositions[(int) (id >>> 32)] |= (int) id;
- }
-
- /**
- * Finds the basic blocks that belong to a given subroutine, and marks these blocks as belonging to this subroutine.
- * This method follows the control flow graph to find all the blocks that are reachable from the current block
- * WITHOUT following any JSR target.
- *
- * @param JSR a JSR block that jumps to this subroutine. If this JSR is not null it is added to the successor of the
- * RET blocks found in the subroutine.
- * @param id the id of this subroutine.
- * @param nbSubroutines the total number of subroutines in the method.
- */
- void visitSubroutine(final Label JSR, final long id, final int nbSubroutines) {
- // user managed stack of labels, to avoid using a recursive method
- // (recursivity can lead to stack overflow with very large methods)
- Label stack = this;
- while (stack != null) {
- // removes a label l from the stack
- Label l = stack;
- stack = l.next;
- l.next = null;
-
- if (JSR != null) {
- if ((l.status & VISITED2) != 0) {
- continue;
- }
- l.status |= VISITED2;
- // adds JSR to the successors of l, if it is a RET block
- if ((l.status & RET) != 0) {
- if (!l.inSameSubroutine(JSR)) {
- Edge e = new Edge();
- e.info = l.inputStackTop;
- e.successor = JSR.successors.successor;
- e.next = l.successors;
- l.successors = e;
- }
- }
- } else {
- // if the l block already belongs to subroutine 'id', continue
- if (l.inSubroutine(id)) {
- continue;
- }
- // marks the l block as belonging to subroutine 'id'
- l.addToSubroutine(id, nbSubroutines);
- }
- // pushes each successor of l on the stack, except JSR targets
- Edge e = l.successors;
- while (e != null) {
- // if the l block is a JSR block, then 'l.successors.next' leads
- // to the JSR target (see {@link #visitJumpInsn}) and must
- // therefore not be followed
- if ((l.status & Label.JSR) == 0 || e != l.successors.next) {
- // pushes e.successor on the stack if it not already added
- if (e.successor.next == null) {
- e.successor.next = stack;
- stack = e.successor;
- }
- }
- e = e.next;
- }
- }
- }
-
- // ------------------------------------------------------------------------
- // Overriden Object methods
- // ------------------------------------------------------------------------
-
- /**
- * Returns a string representation of this label.
- *
- * @return a string representation of this label.
- */
- @Override
- public String toString() {
- return "L" + System.identityHashCode(this);
- }
-}
+/*
+ * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ */
+
+/*
+ *
+ *
+ *
+ *
+ *
+ * ASM: a very small and fast Java bytecode manipulation framework
+ * Copyright (c) 2000-2011 INRIA, France Telecom
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.redkale.asm;
+
+/**
+ * A label represents a position in the bytecode of a method. Labels are used for jump, goto, and switch instructions,
+ * and for try catch blocks. A label designates the instruction that is just after. Note however that there can
+ * be other elements between a label and the instruction it designates (such as other labels, stack map frames, line
+ * numbers, etc.).
+ *
+ * @author Eric Bruneton
+ */
+public class Label {
+
+ /**
+ * Indicates if this label is only used for debug attributes. Such a label is not the start of a basic block, the
+ * target of a jump instruction, or an exception handler. It can be safely ignored in control flow graph analysis
+ * algorithms (for optimization purposes).
+ */
+ static final int DEBUG = 1;
+
+ /** Indicates if the position of this label is known. */
+ static final int RESOLVED = 2;
+
+ /** Indicates if this label has been updated, after instruction resizing. */
+ static final int RESIZED = 4;
+
+ /**
+ * Indicates if this basic block has been pushed in the basic block stack. See {@link MethodWriter#visitMaxs
+ * visitMaxs}.
+ */
+ static final int PUSHED = 8;
+
+ /** Indicates if this label is the target of a jump instruction, or the start of an exception handler. */
+ static final int TARGET = 16;
+
+ /** Indicates if a stack map frame must be stored for this label. */
+ static final int STORE = 32;
+
+ /** Indicates if this label corresponds to a reachable basic block. */
+ static final int REACHABLE = 64;
+
+ /** Indicates if this basic block ends with a JSR instruction. */
+ static final int JSR = 128;
+
+ /** Indicates if this basic block ends with a RET instruction. */
+ static final int RET = 256;
+
+ /** Indicates if this basic block is the start of a subroutine. */
+ static final int SUBROUTINE = 512;
+
+ /** Indicates if this subroutine basic block has been visited by a visitSubroutine(null, ...) call. */
+ static final int VISITED = 1024;
+
+ /** Indicates if this subroutine basic block has been visited by a visitSubroutine(!null, ...) call. */
+ static final int VISITED2 = 2048;
+
+ /**
+ * Field used to associate user information to a label. Warning: this field is used by the ASM tree package. In
+ * order to use it with the ASM tree package you must override the
+ */
+ public Object info;
+
+ /**
+ * Flags that indicate the status of this label.
+ *
+ * @see #DEBUG
+ * @see #RESOLVED
+ * @see #RESIZED
+ * @see #PUSHED
+ * @see #TARGET
+ * @see #STORE
+ * @see #REACHABLE
+ * @see #JSR
+ * @see #RET
+ */
+ int status;
+
+ /**
+ * The line number corresponding to this label, if known. If there are several lines, each line is stored in a
+ * separate label, all linked via their next field (these links are created in ClassReader and removed just before
+ * visitLabel is called, so that this does not impact the rest of the code).
+ */
+ int line;
+
+ /** The position of this label in the code, if known. */
+ int position;
+
+ /** Number of forward references to this label, times two. */
+ private int referenceCount;
+
+ /**
+ * Informations about forward references. Each forward reference is described by two consecutive integers in this
+ * array: the first one is the position of the first byte of the bytecode instruction that contains the forward
+ * reference, while the second is the position of the first byte of the forward reference itself. In fact the sign
+ * of the first integer indicates if this reference uses 2 or 4 bytes, and its absolute value gives the position of
+ * the bytecode instruction. This array is also used as a bitset to store the subroutines to which a basic block
+ * belongs. This information is needed in {@linked MethodWriter#visitMaxs}, after all forward references have been
+ * resolved. Hence the same array can be used for both purposes without problems.
+ */
+ private int[] srcAndRefPositions;
+
+ // ------------------------------------------------------------------------
+
+ /*
+ * Fields for the control flow and data flow graph analysis algorithms (used
+ * to compute the maximum stack size or the stack map frames). A control
+ * flow graph contains one node per "basic block", and one edge per "jump"
+ * from one basic block to another. Each node (i.e., each basic block) is
+ * represented by the Label object that corresponds to the first instruction
+ * of this basic block. Each node also stores the list of its successors in
+ * the graph, as a linked list of Edge objects.
+ *
+ * The control flow analysis algorithms used to compute the maximum stack
+ * size or the stack map frames are similar and use two steps. The first
+ * step, during the visit of each instruction, builds information about the
+ * state of the local variables and the operand stack at the end of each
+ * basic block, called the "output frame", relatively to the frame
+ * state at the beginning of the basic block, which is called the "input
+ * frame", and which is unknown during this step. The second step, in
+ * {@link MethodWriter#visitMaxs}, is a fix point algorithm that computes
+ * information about the input frame of each basic block, from the input
+ * state of the first basic block (known from the method signature), and by
+ * the using the previously computed relative output frames.
+ *
+ * The algorithm used to compute the maximum stack size only computes the
+ * relative output and absolute input stack heights, while the algorithm
+ * used to compute stack map frames computes relative output frames and
+ * absolute input frames.
+ */
+
+ /**
+ * Start of the output stack relatively to the input stack. The exact semantics of this field depends on the
+ * algorithm that is used.
+ *
+ * When only the maximum stack size is computed, this field is the number of elements in the input stack.
+ *
+ * When the stack map frames are completely computed, this field is the offset of the first output stack element
+ * relatively to the top of the input stack. This offset is always negative or null. A null offset means that the
+ * output stack must be appended to the input stack. A -n offset means that the first n output stack elements must
+ * replace the top n input stack elements, and that the other elements must be appended to the input stack.
+ */
+ int inputStackTop;
+
+ /**
+ * Maximum height reached by the output stack, relatively to the top of the input stack. This maximum is always
+ * positive or null.
+ */
+ int outputStackMax;
+
+ /**
+ * Information about the input and output stack map frames of this basic block. This field is only used when
+ * {@link ClassWriter#COMPUTE_FRAMES} option is used.
+ */
+ Frame frame;
+
+ /**
+ * The successor of this label, in the order they are visited. This linked list does not include labels used for
+ * debug info only. If {@link ClassWriter#COMPUTE_FRAMES} option is used then, in addition, it does not contain
+ * successive labels that denote the same bytecode position (in this case only the first label appears in this
+ * list).
+ */
+ Label successor;
+
+ /**
+ * The successors of this node in the control flow graph. These successors are stored in a linked list of
+ * {@link Edge Edge} objects, linked to each other by their {@link Edge#next} field.
+ */
+ Edge successors;
+
+ /**
+ * The next basic block in the basic block stack. This stack is used in the main loop of the fix point algorithm
+ * used in the second step of the control flow analysis algorithms. It is also used in {@link #visitSubroutine} to
+ * avoid using a recursive method, and in ClassReader to temporarily store multiple source lines for a label.
+ *
+ * @see MethodWriter#visitMaxs
+ */
+ Label next;
+
+ // ------------------------------------------------------------------------
+ // Constructor
+ // ------------------------------------------------------------------------
+
+ /** Constructs a new label. */
+ public Label() {
+ // do nothing
+ }
+
+ // ------------------------------------------------------------------------
+ // Methods to compute offsets and to manage forward references
+ // ------------------------------------------------------------------------
+
+ /**
+ * Returns the offset corresponding to this label. This offset is computed from the start of the method's bytecode.
+ * This method is intended for {@link Attribute} sub classes, and is normally not needed by class generators or
+ * adapters.
+ *
+ * @return the offset corresponding to this label.
+ * @throws IllegalStateException if this label is not resolved yet.
+ */
+ public int getOffset() {
+ if ((status & RESOLVED) == 0) {
+ throw new IllegalStateException("Label offset position has not been resolved yet");
+ }
+ return position;
+ }
+
+ /**
+ * Puts a reference to this label in the bytecode of a method. If the position of the label is known, the offset is
+ * computed and written directly. Otherwise, a null offset is written and a new forward reference is declared for
+ * this label.
+ *
+ * @param owner the code writer that calls this method.
+ * @param out the bytecode of the method.
+ * @param source the position of first byte of the bytecode instruction that contains this label.
+ * @param wideOffset <tt>true</tt> if the reference must be stored in 4 bytes, or
+ * <tt>false</tt> if it must be stored with 2 bytes.
+ * @throws IllegalArgumentException if this label has not been created by the given code writer.
+ */
+ void put(final MethodWriter owner, final ByteVector out, final int source, final boolean wideOffset) {
+ if ((status & RESOLVED) == 0) {
+ if (wideOffset) {
+ addReference(-1 - source, out.length);
+ out.putInt(-1);
+ } else {
+ addReference(source, out.length);
+ out.putShort(-1);
+ }
+ } else {
+ if (wideOffset) {
+ out.putInt(position - source);
+ } else {
+ out.putShort(position - source);
+ }
+ }
+ }
+
+ /**
+ * Adds a forward reference to this label. This method must be called only for a true forward reference, i.e. only
+ * if this label is not resolved yet. For backward references, the offset of the reference can be, and must be,
+ * computed and stored directly.
+ *
+ * @param sourcePosition the position of the referencing instruction. This position will be used to compute the
+ * offset of this forward reference.
+ * @param referencePosition the position where the offset for this forward reference must be stored.
+ */
+ private void addReference(final int sourcePosition, final int referencePosition) {
+ if (srcAndRefPositions == null) {
+ srcAndRefPositions = new int[6];
+ }
+ if (referenceCount >= srcAndRefPositions.length) {
+ int[] a = new int[srcAndRefPositions.length + 6];
+ System.arraycopy(srcAndRefPositions, 0, a, 0, srcAndRefPositions.length);
+ srcAndRefPositions = a;
+ }
+ srcAndRefPositions[referenceCount++] = sourcePosition;
+ srcAndRefPositions[referenceCount++] = referencePosition;
+ }
+
+ /**
+ * Resolves all forward references to this label. This method must be called when this label is added to the
+ * bytecode of the method, i.e. when its position becomes known. This method fills in the blanks that where left in
+ * the bytecode by each forward reference previously added to this label.
+ *
+ * @param owner the code writer that calls this method.
+ * @param position the position of this label in the bytecode.
+ * @param data the bytecode of the method.
+ * @return <tt>true</tt> if a blank that was left for this label was too small to store the offset.
+ * In such a case the corresponding jump instruction is replaced with a pseudo instruction (using unused
+ * opcodes) using an unsigned two bytes offset. These pseudo instructions will be replaced with standard
+ * bytecode instructions with wider offsets (4 bytes instead of 2), in ClassReader.
+ * @throws IllegalArgumentException if this label has already been resolved, or if it has not been created by the
+ * given code writer.
+ */
+ boolean resolve(final MethodWriter owner, final int position, final byte[] data) {
+ boolean needUpdate = false;
+ this.status |= RESOLVED;
+ this.position = position;
+ int i = 0;
+ while (i < referenceCount) {
+ int source = srcAndRefPositions[i++];
+ int reference = srcAndRefPositions[i++];
+ int offset;
+ if (source >= 0) {
+ offset = position - source;
+ if (offset < Short.MIN_VALUE || offset > Short.MAX_VALUE) {
+ /*
+ * changes the opcode of the jump instruction, in order to
+ * be able to find it later (see resizeInstructions in
+ * MethodWriter). These temporary opcodes are similar to
+ * jump instruction opcodes, except that the 2 bytes offset
+ * is unsigned (and can therefore represent values from 0 to
+ * 65535, which is sufficient since the size of a method is
+ * limited to 65535 bytes).
+ */
+ int opcode = data[reference - 1] & 0xFF;
+ if (opcode <= Opcodes.JSR) {
+ // changes IFEQ ... JSR to opcodes 202 to 217
+ data[reference - 1] = (byte) (opcode + 49);
+ } else {
+ // changes IFNULL and IFNONNULL to opcodes 218 and 219
+ data[reference - 1] = (byte) (opcode + 20);
+ }
+ needUpdate = true;
+ }
+ data[reference++] = (byte) (offset >>> 8);
+ data[reference] = (byte) offset;
+ } else {
+ offset = position + source + 1;
+ data[reference++] = (byte) (offset >>> 24);
+ data[reference++] = (byte) (offset >>> 16);
+ data[reference++] = (byte) (offset >>> 8);
+ data[reference] = (byte) offset;
+ }
+ }
+ return needUpdate;
+ }
+
+ /**
+ * Returns the first label of the series to which this label belongs. For an isolated label or for the first label
+ * in a series of successive labels, this method returns the label itself. For other labels it returns the first
+ * label of the series.
+ *
+ * @return the first label of the series to which this label belongs.
+ */
+ Label getFirst() {
+ return frame == null ? this : frame.owner;
+ }
+
+ // ------------------------------------------------------------------------
+ // Methods related to subroutines
+ // ------------------------------------------------------------------------
+
+ /**
+ * Returns true is this basic block belongs to the given subroutine.
+ *
+ * @param id a subroutine id.
+ * @return true is this basic block belongs to the given subroutine.
+ */
+ boolean inSubroutine(final long id) {
+ if ((status & Label.VISITED) != 0) {
+ return (srcAndRefPositions[(int) (id >>> 32)] & (int) id) != 0;
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if this basic block and the given one belong to a common subroutine.
+ *
+ * @param block another basic block.
+ * @return true if this basic block and the given one belong to a common subroutine.
+ */
+ boolean inSameSubroutine(final Label block) {
+ if ((status & VISITED) == 0 || (block.status & VISITED) == 0) {
+ return false;
+ }
+ for (int i = 0; i < srcAndRefPositions.length; ++i) {
+ if ((srcAndRefPositions[i] & block.srcAndRefPositions[i]) != 0) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Marks this basic block as belonging to the given subroutine.
+ *
+ * @param id a subroutine id.
+ * @param nbSubroutines the total number of subroutines in the method.
+ */
+ void addToSubroutine(final long id, final int nbSubroutines) {
+ if ((status & VISITED) == 0) {
+ status |= VISITED;
+ srcAndRefPositions = new int[nbSubroutines / 32 + 1];
+ }
+ srcAndRefPositions[(int) (id >>> 32)] |= (int) id;
+ }
+
+ /**
+ * Finds the basic blocks that belong to a given subroutine, and marks these blocks as belonging to this subroutine.
+ * This method follows the control flow graph to find all the blocks that are reachable from the current block
+ * WITHOUT following any JSR target.
+ *
+ * @param JSR a JSR block that jumps to this subroutine. If this JSR is not null it is added to the successor of the
+ * RET blocks found in the subroutine.
+ * @param id the id of this subroutine.
+ * @param nbSubroutines the total number of subroutines in the method.
+ */
+ void visitSubroutine(final Label JSR, final long id, final int nbSubroutines) {
+ // user managed stack of labels, to avoid using a recursive method
+ // (recursivity can lead to stack overflow with very large methods)
+ Label stack = this;
+ while (stack != null) {
+ // removes a label l from the stack
+ Label l = stack;
+ stack = l.next;
+ l.next = null;
+
+ if (JSR != null) {
+ if ((l.status & VISITED2) != 0) {
+ continue;
+ }
+ l.status |= VISITED2;
+ // adds JSR to the successors of l, if it is a RET block
+ if ((l.status & RET) != 0) {
+ if (!l.inSameSubroutine(JSR)) {
+ Edge e = new Edge();
+ e.info = l.inputStackTop;
+ e.successor = JSR.successors.successor;
+ e.next = l.successors;
+ l.successors = e;
+ }
+ }
+ } else {
+ // if the l block already belongs to subroutine 'id', continue
+ if (l.inSubroutine(id)) {
+ continue;
+ }
+ // marks the l block as belonging to subroutine 'id'
+ l.addToSubroutine(id, nbSubroutines);
+ }
+ // pushes each successor of l on the stack, except JSR targets
+ Edge e = l.successors;
+ while (e != null) {
+ // if the l block is a JSR block, then 'l.successors.next' leads
+ // to the JSR target (see {@link #visitJumpInsn}) and must
+ // therefore not be followed
+ if ((l.status & Label.JSR) == 0 || e != l.successors.next) {
+ // pushes e.successor on the stack if it not already added
+ if (e.successor.next == null) {
+ e.successor.next = stack;
+ stack = e.successor;
+ }
+ }
+ e = e.next;
+ }
+ }
+ }
+
+ // ------------------------------------------------------------------------
+ // Overriden Object methods
+ // ------------------------------------------------------------------------
+
+ /**
+ * Returns a string representation of this label.
+ *
+ * @return a string representation of this label.
+ */
+ @Override
+ public String toString() {
+ return "L" + System.identityHashCode(this);
+ }
+}
diff --git a/src/main/java/org/redkale/asm/MethodVisitor.java b/src/main/java/org/redkale/asm/MethodVisitor.java
index 4e2ccd310..b16206bd0 100644
--- a/src/main/java/org/redkale/asm/MethodVisitor.java
+++ b/src/main/java/org/redkale/asm/MethodVisitor.java
@@ -1,670 +1,670 @@
-/*
- * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- */
-
-/*
- *
- *
- *
- *
- *
- * ASM: a very small and fast Java bytecode manipulation framework
- * Copyright (c) 2000-2011 INRIA, France Telecom
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-package org.redkale.asm;
-
-/**
- * A visitor to visit a Java method. The methods of this class must be called in the following order: (
- * <tt>visitParameter</tt> )* [ <tt>visitAnnotationDefault</tt> ] (
- * <tt>visitAnnotation</tt> | <tt>visitParameterAnnotation</tt>
- * <tt>visitTypeAnnotation</tt> | <tt>visitAttribute</tt> )* [
- * <tt>visitCode</tt> ( <tt>visitFrame</tt> | <tt>visitXInsn</tt>
- * | <tt>visitLabel</tt> | <tt>visitInsnAnnotation</tt> |
- * <tt>visitTryCatchBlock</tt> | <tt>visitTryCatchAnnotation</tt> |
- * <tt>visitLocalVariable</tt> | <tt>visitLocalVariableAnnotation</tt> |
- * <tt>visitLineNumber</tt> )* <tt>visitMaxs</tt> ] <tt>visitEnd</tt>.
- * In addition, the <tt>visitXInsn</tt> and <tt>visitLabel</tt> methods must be
- * called in the sequential order of the bytecode instructions of the visited code,
- * <tt>visitInsnAnnotation</tt> must be called after the annotated instruction,
- * <tt>visitTryCatchBlock</tt> must be called before the labels passed as arguments have been
- * visited, <tt>visitTryCatchBlockAnnotation</tt> must be called after the corresponding try
- * catch block has been visited, and the <tt>visitLocalVariable</tt>,
- * <tt>visitLocalVariableAnnotation</tt> and <tt>visitLineNumber</tt> methods must be
- * called after the labels passed as arguments have been visited.
- *
- * @author Eric Bruneton
- */
-public abstract class MethodVisitor {
-
- /**
- * The ASM API version implemented by this visitor. The value of this field must be one of {@link Opcodes#ASM4},
- * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
- */
- protected final int api;
-
- /** The method visitor to which this visitor must delegate method calls. May be null. */
- protected MethodVisitor mv;
-
- /**
- * Constructs a new {@link MethodVisitor}.
- *
- * @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM4},
- * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
- */
- public MethodVisitor(final int api) {
- this(api, null);
- }
-
- /**
- * Constructs a new {@link MethodVisitor}.
- *
- * @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM4},
- * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
- * @param mv the method visitor to which this visitor must delegate method calls. May be null.
- */
- public MethodVisitor(final int api, final MethodVisitor mv) {
- this.api = api;
- this.mv = mv;
- }
-
- // -------------------------------------------------------------------------
- // Parameters, annotations and non standard attributes
- // -------------------------------------------------------------------------
-
- /**
- * Visits a parameter of this method.
- *
- * @param name parameter name or null if none is provided.
- * @param access the parameter's access flags, only <tt>ACC_FINAL</tt>,
- * <tt>ACC_SYNTHETIC</tt> or/and <tt>ACC_MANDATED</tt> are allowed (see
- * {@link Opcodes}).
- */
- public void visitParameter(String name, int access) {
- if (mv != null) {
- mv.visitParameter(name, access);
- }
- }
-
- /**
- * Visits the default value of this annotation interface method.
- *
- * @return a visitor to the visit the actual default value of this annotation interface method, or
- * <tt>null</tt> if this visitor is not interested in visiting this default value. The 'name'
- * parameters passed to the methods of this annotation visitor are ignored. Moreover, exacly one visit method
- * must be called on this annotation visitor, followed by visitEnd.
- */
- public AnnotationVisitor visitAnnotationDefault() {
- if (mv != null) {
- return mv.visitAnnotationDefault();
- }
- return null;
- }
-
- /**
- * Visits an annotation of this method.
- *
- * @param desc the class descriptor of the annotation class.
- * @param visible <tt>true</tt> if the annotation is visible at runtime.
- * @return a visitor to visit the annotation values, or <tt>null</tt> if this visitor is not
- * interested in visiting this annotation.
- */
- public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
- if (mv != null) {
- return mv.visitAnnotation(desc, visible);
- }
- return null;
- }
-
- /**
- * Visits an annotation on a type in the method signature.
- *
- * @param typeRef a reference to the annotated type. The sort of this type reference must be
- * {@link TypeReference#METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER},
- * {@link TypeReference#METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND},
- * {@link TypeReference#METHOD_RETURN METHOD_RETURN}, {@link TypeReference#METHOD_RECEIVER METHOD_RECEIVER},
- * {@link TypeReference#METHOD_FORMAL_PARAMETER METHOD_FORMAL_PARAMETER} or {@link TypeReference#THROWS THROWS}.
- * See {@link TypeReference}.
- * @param typePath the path to the annotated type argument, wildcard bound, array element type, or static inner type
- * within 'typeRef'. May be <tt>null</tt> if the annotation targets 'typeRef' as a whole.
- * @param desc the class descriptor of the annotation class.
- * @param visible <tt>true</tt> if the annotation is visible at runtime.
- * @return a visitor to visit the annotation values, or <tt>null</tt> if this visitor is not
- * interested in visiting this annotation.
- */
- public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {
- if (mv != null) {
- return mv.visitTypeAnnotation(typeRef, typePath, desc, visible);
- }
- return null;
- }
-
- /**
- * Visits an annotation of a parameter this method.
- *
- * @param parameter the parameter index.
- * @param desc the class descriptor of the annotation class.
- * @param visible <tt>true</tt> if the annotation is visible at runtime.
- * @return a visitor to visit the annotation values, or <tt>null</tt> if this visitor is not
- * interested in visiting this annotation.
- */
- public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, boolean visible) {
- if (mv != null) {
- return mv.visitParameterAnnotation(parameter, desc, visible);
- }
- return null;
- }
-
- /**
- * Visits a non standard attribute of this method.
- *
- * @param attr an attribute.
- */
- public void visitAttribute(Attribute attr) {
- if (mv != null) {
- mv.visitAttribute(attr);
- }
- }
-
- /** Starts the visit of the method's code, if any (i.e. non abstract method). */
- public void visitCode() {
- if (mv != null) {
- mv.visitCode();
- }
- }
-
- /**
- * Visits the current state of the local variables and operand stack elements. This method must(*) be called just
- * before any instruction i that follows an unconditional branch instruction such as GOTO or THROW, that
- * is the target of a jump instruction, or that starts an exception handler block. The visited types must describe
- * the values of the local variables and of the operand stack elements just before i is executed. The methods {@link #visitRequire(String, int, String)}, {@link #visitExport(String, int, String...)},
- * {@link #visitOpen(String, int, String...)} and {@link #visitPackage(String)} take as parameter a package name or a
- * module name. Unlike the other names which are internal names (names separated by slash), module and package names are
- * qualified names (names separated by dot).
- *
- * @author Remi Forax
- */
-public abstract class ModuleVisitor {
- /** The ASM API version implemented by this visitor. The value of this field must be {@link Opcodes#ASM6}. */
- protected final int api;
-
- /** The module visitor to which this visitor must delegate method calls. May be null. */
- protected ModuleVisitor mv;
-
- /**
- * Constructs a new {@link ModuleVisitor}.
- *
- * @param api the ASM API version implemented by this visitor. Must be {@link Opcodes#ASM6}.
- */
- public ModuleVisitor(final int api) {
- this(api, null);
- }
-
- /**
- * Constructs a new {@link ModuleVisitor}.
- *
- * @param api the ASM API version implemented by this visitor. Must be {@link Opcodes#ASM6}.
- * @param mv the module visitor to which this visitor must delegate method calls. May be null.
- */
- public ModuleVisitor(final int api, final ModuleVisitor mv) {
- if (api != Opcodes.ASM6) {
- throw new IllegalArgumentException();
- }
- this.api = api;
- this.mv = mv;
- }
-
- /**
- * Visit the main class of the current module.
- *
- * @param mainClass the internal name of the main class of the current module.
- */
- public void visitMainClass(String mainClass) {
- if (mv != null) {
- mv.visitMainClass(mainClass);
- }
- }
-
- /**
- * Visit a package of the current module.
- *
- * @param packaze the qualified name of a package.
- */
- public void visitPackage(String packaze) {
- if (mv != null) {
- mv.visitPackage(packaze);
- }
- }
-
- /**
- * Visits a dependence of the current module.
- *
- * @param module the qualified name of the dependence.
- * @param access the access flag of the dependence among ACC_TRANSITIVE, ACC_STATIC_PHASE, ACC_SYNTHETIC and
- * ACC_MANDATED.
- * @param version the module version at compile time or null.
- */
- public void visitRequire(String module, int access, String version) {
- if (mv != null) {
- mv.visitRequire(module, access, version);
- }
- }
-
- /**
- * Visit an exported package of the current module.
- *
- * @param packaze the qualified name of the exported package.
- * @param access the access flag of the exported package, valid values are among {@code ACC_SYNTHETIC} and
- * {@code ACC_MANDATED}.
- * @param modules the qualified names of the modules that can access to the public classes of the exported package
- * or <tt>null</tt>.
- */
- public void visitExport(String packaze, int access, String... modules) {
- if (mv != null) {
- mv.visitExport(packaze, access, modules);
- }
- }
-
- /**
- * Visit an open package of the current module.
- *
- * @param packaze the qualified name of the opened package.
- * @param access the access flag of the opened package, valid values are among {@code ACC_SYNTHETIC} and
- * {@code ACC_MANDATED}.
- * @param modules the qualified names of the modules that can use deep reflection to the classes of the open package
- * or <tt>null</tt>.
- */
- public void visitOpen(String packaze, int access, String... modules) {
- if (mv != null) {
- mv.visitOpen(packaze, access, modules);
- }
- }
-
- /**
- * Visit a service used by the current module. The name must be the internal name of an interface or a class.
- *
- * @param service the internal name of the service.
- */
- public void visitUse(String service) {
- if (mv != null) {
- mv.visitUse(service);
- }
- }
-
- /**
- * Visit an implementation of a service.
- *
- * @param service the internal name of the service
- * @param providers the internal names of the implementations of the service (there is at least one provider).
- */
- public void visitProvide(String service, String... providers) {
- if (mv != null) {
- mv.visitProvide(service, providers);
- }
- }
-
- /**
- * Visits the end of the module. This method, which is the last one to be called, is used to inform the visitor that
- * everything have been visited.
- */
- public void visitEnd() {
- if (mv != null) {
- mv.visitEnd();
- }
- }
-}
+/*
+ * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ */
+
+/*
+ *
+ *
+ *
+ *
+ *
+ * ASM: a very small and fast Java bytecode manipulation framework
+ * Copyright (c) 2000-2011 INRIA, France Telecom
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.redkale.asm;
+
+/**
+ * A visitor to visit a Java module. The methods of this class must be called in the following order:
+ * <tt>visitMainClass</tt> | ( <tt>visitPackage</tt> |
+ * <tt>visitRequire</tt> | <tt>visitExport</tt> | <tt>visitOpen</tt> |
+ * <tt>visitUse</tt> | <tt>visitProvide</tt> )* <tt>visitEnd</tt>.
+ *
+ * The methods {@link #visitRequire(String, int, String)}, {@link #visitExport(String, int, String...)},
+ * {@link #visitOpen(String, int, String...)} and {@link #visitPackage(String)} take as parameter a package name or a
+ * module name. Unlike the other names which are internal names (names separated by slash), module and package names are
+ * qualified names (names separated by dot).
+ *
+ * @author Remi Forax
+ */
+public abstract class ModuleVisitor {
+ /** The ASM API version implemented by this visitor. The value of this field must be {@link Opcodes#ASM6}. */
+ protected final int api;
+
+ /** The module visitor to which this visitor must delegate method calls. May be null. */
+ protected ModuleVisitor mv;
+
+ /**
+ * Constructs a new {@link ModuleVisitor}.
+ *
+ * @param api the ASM API version implemented by this visitor. Must be {@link Opcodes#ASM6}.
+ */
+ public ModuleVisitor(final int api) {
+ this(api, null);
+ }
+
+ /**
+ * Constructs a new {@link ModuleVisitor}.
+ *
+ * @param api the ASM API version implemented by this visitor. Must be {@link Opcodes#ASM6}.
+ * @param mv the module visitor to which this visitor must delegate method calls. May be null.
+ */
+ public ModuleVisitor(final int api, final ModuleVisitor mv) {
+ if (api != Opcodes.ASM6) {
+ throw new IllegalArgumentException();
+ }
+ this.api = api;
+ this.mv = mv;
+ }
+
+ /**
+ * Visit the main class of the current module.
+ *
+ * @param mainClass the internal name of the main class of the current module.
+ */
+ public void visitMainClass(String mainClass) {
+ if (mv != null) {
+ mv.visitMainClass(mainClass);
+ }
+ }
+
+ /**
+ * Visit a package of the current module.
+ *
+ * @param packaze the qualified name of a package.
+ */
+ public void visitPackage(String packaze) {
+ if (mv != null) {
+ mv.visitPackage(packaze);
+ }
+ }
+
+ /**
+ * Visits a dependence of the current module.
+ *
+ * @param module the qualified name of the dependence.
+ * @param access the access flag of the dependence among ACC_TRANSITIVE, ACC_STATIC_PHASE, ACC_SYNTHETIC and
+ * ACC_MANDATED.
+ * @param version the module version at compile time or null.
+ */
+ public void visitRequire(String module, int access, String version) {
+ if (mv != null) {
+ mv.visitRequire(module, access, version);
+ }
+ }
+
+ /**
+ * Visit an exported package of the current module.
+ *
+ * @param packaze the qualified name of the exported package.
+ * @param access the access flag of the exported package, valid values are among {@code ACC_SYNTHETIC} and
+ * {@code ACC_MANDATED}.
+ * @param modules the qualified names of the modules that can access to the public classes of the exported package
+ * or <tt>null</tt>.
+ */
+ public void visitExport(String packaze, int access, String... modules) {
+ if (mv != null) {
+ mv.visitExport(packaze, access, modules);
+ }
+ }
+
+ /**
+ * Visit an open package of the current module.
+ *
+ * @param packaze the qualified name of the opened package.
+ * @param access the access flag of the opened package, valid values are among {@code ACC_SYNTHETIC} and
+ * {@code ACC_MANDATED}.
+ * @param modules the qualified names of the modules that can use deep reflection to the classes of the open package
+ * or <tt>null</tt>.
+ */
+ public void visitOpen(String packaze, int access, String... modules) {
+ if (mv != null) {
+ mv.visitOpen(packaze, access, modules);
+ }
+ }
+
+ /**
+ * Visit a service used by the current module. The name must be the internal name of an interface or a class.
+ *
+ * @param service the internal name of the service.
+ */
+ public void visitUse(String service) {
+ if (mv != null) {
+ mv.visitUse(service);
+ }
+ }
+
+ /**
+ * Visit an implementation of a service.
+ *
+ * @param service the internal name of the service
+ * @param providers the internal names of the implementations of the service (there is at least one provider).
+ */
+ public void visitProvide(String service, String... providers) {
+ if (mv != null) {
+ mv.visitProvide(service, providers);
+ }
+ }
+
+ /**
+ * Visits the end of the module. This method, which is the last one to be called, is used to inform the visitor that
+ * everything have been visited.
+ */
+ public void visitEnd() {
+ if (mv != null) {
+ mv.visitEnd();
+ }
+ }
+}
diff --git a/src/main/java/org/redkale/asm/ModuleWriter.java b/src/main/java/org/redkale/asm/ModuleWriter.java
index dbbdacd28..2e2659fd6 100644
--- a/src/main/java/org/redkale/asm/ModuleWriter.java
+++ b/src/main/java/org/redkale/asm/ModuleWriter.java
@@ -1,288 +1,288 @@
-/*
- * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- */
-
-/*
- *
- *
- *
- *
- *
- * ASM: a very small and fast Java bytecode manipulation framework
- * Copyright (c) 2000-2011 INRIA, France Telecom
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package org.redkale.asm;
-
-/** @author Remi Forax */
-final class ModuleWriter extends ModuleVisitor {
- /** The class writer to which this Module attribute must be added. */
- private final ClassWriter cw;
-
- /** size in byte of the Module attribute. */
- int size;
-
- /** Number of attributes associated with the current module (Version, ConcealPackages, etc) */
- int attributeCount;
-
- /** Size in bytes of the attributes associated with the current module */
- int attributesSize;
-
- /** module name index in the constant pool */
- private final int name;
-
- /** module access flags */
- private final int access;
-
- /** module version index in the constant pool or 0 */
- private final int version;
-
- /** module main class index in the constant pool or 0 */
- private int mainClass;
-
- /** number of packages */
- private int packageCount;
-
- /**
- * The packages in bytecode form. This byte vector only contains the items themselves, the number of items is store
- * in packageCount
- */
- private ByteVector packages;
-
- /** number of requires items */
- private int requireCount;
-
- /**
- * The requires items in bytecode form. This byte vector only contains the items themselves, the number of items is
- * store in requireCount
- */
- private ByteVector requires;
-
- /** number of exports items */
- private int exportCount;
-
- /**
- * The exports items in bytecode form. This byte vector only contains the items themselves, the number of items is
- * store in exportCount
- */
- private ByteVector exports;
-
- /** number of opens items */
- private int openCount;
-
- /**
- * The opens items in bytecode form. This byte vector only contains the items themselves, the number of items is
- * store in openCount
- */
- private ByteVector opens;
-
- /** number of uses items */
- private int useCount;
-
- /**
- * The uses items in bytecode form. This byte vector only contains the items themselves, the number of items is
- * store in useCount
- */
- private ByteVector uses;
-
- /** number of provides items */
- private int provideCount;
-
- /**
- * The uses provides in bytecode form. This byte vector only contains the items themselves, the number of items is
- * store in provideCount
- */
- private ByteVector provides;
-
- ModuleWriter(final ClassWriter cw, final int name, final int access, final int version) {
- super(Opcodes.ASM6);
- this.cw = cw;
- this.size = 16; // name + access + version + 5 counts
- this.name = name;
- this.access = access;
- this.version = version;
- }
-
- @Override
- public void visitMainClass(String mainClass) {
- if (this.mainClass == 0) { // protect against several calls to visitMainClass
- cw.newUTF8("ModuleMainClass");
- attributeCount++;
- attributesSize += 8;
- }
- this.mainClass = cw.newClass(mainClass);
- }
-
- @Override
- public void visitPackage(String packaze) {
- if (packages == null) {
- // protect against several calls to visitPackage
- cw.newUTF8("ModulePackages");
- packages = new ByteVector();
- attributeCount++;
- attributesSize += 8;
- }
- packages.putShort(cw.newPackage(packaze));
- packageCount++;
- attributesSize += 2;
- }
-
- @Override
- public void visitRequire(String module, int access, String version) {
- if (requires == null) {
- requires = new ByteVector();
- }
- requires.putShort(cw.newModule(module)).putShort(access).putShort(version == null ? 0 : cw.newUTF8(version));
- requireCount++;
- size += 6;
- }
-
- @Override
- public void visitExport(String packaze, int access, String... modules) {
- if (exports == null) {
- exports = new ByteVector();
- }
- exports.putShort(cw.newPackage(packaze)).putShort(access);
- if (modules == null) {
- exports.putShort(0);
- size += 6;
- } else {
- exports.putShort(modules.length);
- for (String module : modules) {
- exports.putShort(cw.newModule(module));
- }
- size += 6 + 2 * modules.length;
- }
- exportCount++;
- }
-
- @Override
- public void visitOpen(String packaze, int access, String... modules) {
- if (opens == null) {
- opens = new ByteVector();
- }
- opens.putShort(cw.newPackage(packaze)).putShort(access);
- if (modules == null) {
- opens.putShort(0);
- size += 6;
- } else {
- opens.putShort(modules.length);
- for (String module : modules) {
- opens.putShort(cw.newModule(module));
- }
- size += 6 + 2 * modules.length;
- }
- openCount++;
- }
-
- @Override
- public void visitUse(String service) {
- if (uses == null) {
- uses = new ByteVector();
- }
- uses.putShort(cw.newClass(service));
- useCount++;
- size += 2;
- }
-
- @Override
- public void visitProvide(String service, String... providers) {
- if (provides == null) {
- provides = new ByteVector();
- }
- provides.putShort(cw.newClass(service));
- provides.putShort(providers.length);
- for (String provider : providers) {
- provides.putShort(cw.newClass(provider));
- }
- provideCount++;
- size += 4 + 2 * providers.length;
- }
-
- @Override
- public void visitEnd() {
- // empty
- }
-
- void putAttributes(ByteVector out) {
- if (mainClass != 0) {
- out.putShort(cw.newUTF8("ModuleMainClass")).putInt(2).putShort(mainClass);
- }
- if (packages != null) {
- out.putShort(cw.newUTF8("ModulePackages"))
- .putInt(2 + 2 * packageCount)
- .putShort(packageCount)
- .putByteArray(packages.data, 0, packages.length);
- }
- }
-
- void put(ByteVector out) {
- out.putInt(size);
- out.putShort(name).putShort(access).putShort(version);
- out.putShort(requireCount);
- if (requires != null) {
- out.putByteArray(requires.data, 0, requires.length);
- }
- out.putShort(exportCount);
- if (exports != null) {
- out.putByteArray(exports.data, 0, exports.length);
- }
- out.putShort(openCount);
- if (opens != null) {
- out.putByteArray(opens.data, 0, opens.length);
- }
- out.putShort(useCount);
- if (uses != null) {
- out.putByteArray(uses.data, 0, uses.length);
- }
- out.putShort(provideCount);
- if (provides != null) {
- out.putByteArray(provides.data, 0, provides.length);
- }
- }
-}
+/*
+ * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ */
+
+/*
+ *
+ *
+ *
+ *
+ *
+ * ASM: a very small and fast Java bytecode manipulation framework
+ * Copyright (c) 2000-2011 INRIA, France Telecom
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.redkale.asm;
+
+/** @author Remi Forax */
+final class ModuleWriter extends ModuleVisitor {
+ /** The class writer to which this Module attribute must be added. */
+ private final ClassWriter cw;
+
+ /** size in byte of the Module attribute. */
+ int size;
+
+ /** Number of attributes associated with the current module (Version, ConcealPackages, etc) */
+ int attributeCount;
+
+ /** Size in bytes of the attributes associated with the current module */
+ int attributesSize;
+
+ /** module name index in the constant pool */
+ private final int name;
+
+ /** module access flags */
+ private final int access;
+
+ /** module version index in the constant pool or 0 */
+ private final int version;
+
+ /** module main class index in the constant pool or 0 */
+ private int mainClass;
+
+ /** number of packages */
+ private int packageCount;
+
+ /**
+ * The packages in bytecode form. This byte vector only contains the items themselves, the number of items is store
+ * in packageCount
+ */
+ private ByteVector packages;
+
+ /** number of requires items */
+ private int requireCount;
+
+ /**
+ * The requires items in bytecode form. This byte vector only contains the items themselves, the number of items is
+ * store in requireCount
+ */
+ private ByteVector requires;
+
+ /** number of exports items */
+ private int exportCount;
+
+ /**
+ * The exports items in bytecode form. This byte vector only contains the items themselves, the number of items is
+ * store in exportCount
+ */
+ private ByteVector exports;
+
+ /** number of opens items */
+ private int openCount;
+
+ /**
+ * The opens items in bytecode form. This byte vector only contains the items themselves, the number of items is
+ * store in openCount
+ */
+ private ByteVector opens;
+
+ /** number of uses items */
+ private int useCount;
+
+ /**
+ * The uses items in bytecode form. This byte vector only contains the items themselves, the number of items is
+ * store in useCount
+ */
+ private ByteVector uses;
+
+ /** number of provides items */
+ private int provideCount;
+
+ /**
+ * The uses provides in bytecode form. This byte vector only contains the items themselves, the number of items is
+ * store in provideCount
+ */
+ private ByteVector provides;
+
+ ModuleWriter(final ClassWriter cw, final int name, final int access, final int version) {
+ super(Opcodes.ASM6);
+ this.cw = cw;
+ this.size = 16; // name + access + version + 5 counts
+ this.name = name;
+ this.access = access;
+ this.version = version;
+ }
+
+ @Override
+ public void visitMainClass(String mainClass) {
+ if (this.mainClass == 0) { // protect against several calls to visitMainClass
+ cw.newUTF8("ModuleMainClass");
+ attributeCount++;
+ attributesSize += 8;
+ }
+ this.mainClass = cw.newClass(mainClass);
+ }
+
+ @Override
+ public void visitPackage(String packaze) {
+ if (packages == null) {
+ // protect against several calls to visitPackage
+ cw.newUTF8("ModulePackages");
+ packages = new ByteVector();
+ attributeCount++;
+ attributesSize += 8;
+ }
+ packages.putShort(cw.newPackage(packaze));
+ packageCount++;
+ attributesSize += 2;
+ }
+
+ @Override
+ public void visitRequire(String module, int access, String version) {
+ if (requires == null) {
+ requires = new ByteVector();
+ }
+ requires.putShort(cw.newModule(module)).putShort(access).putShort(version == null ? 0 : cw.newUTF8(version));
+ requireCount++;
+ size += 6;
+ }
+
+ @Override
+ public void visitExport(String packaze, int access, String... modules) {
+ if (exports == null) {
+ exports = new ByteVector();
+ }
+ exports.putShort(cw.newPackage(packaze)).putShort(access);
+ if (modules == null) {
+ exports.putShort(0);
+ size += 6;
+ } else {
+ exports.putShort(modules.length);
+ for (String module : modules) {
+ exports.putShort(cw.newModule(module));
+ }
+ size += 6 + 2 * modules.length;
+ }
+ exportCount++;
+ }
+
+ @Override
+ public void visitOpen(String packaze, int access, String... modules) {
+ if (opens == null) {
+ opens = new ByteVector();
+ }
+ opens.putShort(cw.newPackage(packaze)).putShort(access);
+ if (modules == null) {
+ opens.putShort(0);
+ size += 6;
+ } else {
+ opens.putShort(modules.length);
+ for (String module : modules) {
+ opens.putShort(cw.newModule(module));
+ }
+ size += 6 + 2 * modules.length;
+ }
+ openCount++;
+ }
+
+ @Override
+ public void visitUse(String service) {
+ if (uses == null) {
+ uses = new ByteVector();
+ }
+ uses.putShort(cw.newClass(service));
+ useCount++;
+ size += 2;
+ }
+
+ @Override
+ public void visitProvide(String service, String... providers) {
+ if (provides == null) {
+ provides = new ByteVector();
+ }
+ provides.putShort(cw.newClass(service));
+ provides.putShort(providers.length);
+ for (String provider : providers) {
+ provides.putShort(cw.newClass(provider));
+ }
+ provideCount++;
+ size += 4 + 2 * providers.length;
+ }
+
+ @Override
+ public void visitEnd() {
+ // empty
+ }
+
+ void putAttributes(ByteVector out) {
+ if (mainClass != 0) {
+ out.putShort(cw.newUTF8("ModuleMainClass")).putInt(2).putShort(mainClass);
+ }
+ if (packages != null) {
+ out.putShort(cw.newUTF8("ModulePackages"))
+ .putInt(2 + 2 * packageCount)
+ .putShort(packageCount)
+ .putByteArray(packages.data, 0, packages.length);
+ }
+ }
+
+ void put(ByteVector out) {
+ out.putInt(size);
+ out.putShort(name).putShort(access).putShort(version);
+ out.putShort(requireCount);
+ if (requires != null) {
+ out.putByteArray(requires.data, 0, requires.length);
+ }
+ out.putShort(exportCount);
+ if (exports != null) {
+ out.putByteArray(exports.data, 0, exports.length);
+ }
+ out.putShort(openCount);
+ if (opens != null) {
+ out.putByteArray(opens.data, 0, opens.length);
+ }
+ out.putShort(useCount);
+ if (uses != null) {
+ out.putByteArray(uses.data, 0, uses.length);
+ }
+ out.putShort(provideCount);
+ if (provides != null) {
+ out.putByteArray(provides.data, 0, provides.length);
+ }
+ }
+}
diff --git a/src/main/java/org/redkale/asm/Opcodes.java b/src/main/java/org/redkale/asm/Opcodes.java
index 8bec065f3..03981ef29 100644
--- a/src/main/java/org/redkale/asm/Opcodes.java
+++ b/src/main/java/org/redkale/asm/Opcodes.java
@@ -1,402 +1,402 @@
-/*
- * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- */
-
-/*
- *
- *
- *
- *
- *
- * ASM: a very small and fast Java bytecode manipulation framework
- * Copyright (c) 2000-2011 INRIA, France Telecom
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-package org.redkale.asm;
-
-/**
- * Defines the JVM opcodes, access flags and array type codes. This interface does not define all the JVM opcodes
- * because some opcodes are automatically handled. For example, the xLOAD and xSTORE opcodes are automatically replaced
- * by xLOAD_n and xSTORE_n opcodes when possible. The xLOAD_n and xSTORE_n opcodes are therefore not defined in this
- * interface. Likewise for LDC, automatically replaced by LDC_W or LDC2_W when necessary, WIDE, GOTO_W and JSR_W.
- *
- * @author Eric Bruneton
- * @author Eugene Kuleshov
- */
-public interface Opcodes {
-
- // ASM API versions
- int ASM4 = 4 << 16 | 0 << 8;
- int ASM5 = 5 << 16 | 0 << 8;
- int ASM6 = 6 << 16 | 0 << 8;
-
- // versions
-
- int V1_1 = 3 << 16 | 45;
- int V1_2 = 0 << 16 | 46;
- int V1_3 = 0 << 16 | 47;
- int V1_4 = 0 << 16 | 48;
- int V1_5 = 0 << 16 | 49;
- int V1_6 = 0 << 16 | 50;
- int V1_7 = 0 << 16 | 51;
- int V1_8 = 0 << 16 | 52;
- int V9 = 0 << 16 | 53;
- int V10 = 0 << 16 | 54;
- int V11 = 0 << 16 | 55;
-
- // access flags
-
- int ACC_PUBLIC = 0x0001; // class, field, method
- int ACC_PRIVATE = 0x0002; // class, field, method
- int ACC_PROTECTED = 0x0004; // class, field, method
- int ACC_STATIC = 0x0008; // field, method
- int ACC_FINAL = 0x0010; // class, field, method, parameter
- int ACC_SUPER = 0x0020; // class
- int ACC_SYNCHRONIZED = 0x0020; // method
- int ACC_OPEN = 0x0020; // module
- int ACC_TRANSITIVE = 0x0020; // module requires
- int ACC_VOLATILE = 0x0040; // field
- int ACC_BRIDGE = 0x0040; // method
- int ACC_STATIC_PHASE = 0x0040; // module requires
- int ACC_VARARGS = 0x0080; // method
- int ACC_TRANSIENT = 0x0080; // field
- int ACC_NATIVE = 0x0100; // method
- int ACC_INTERFACE = 0x0200; // class
- int ACC_ABSTRACT = 0x0400; // class, method
- int ACC_STRICT = 0x0800; // method
- int ACC_SYNTHETIC = 0x1000; // class, field, method, parameter, module *
- int ACC_ANNOTATION = 0x2000; // class
- int ACC_ENUM = 0x4000; // class(?) field inner
- int ACC_MANDATED = 0x8000; // parameter, module, module *
- int ACC_MODULE = 0x8000; // class
-
- // ASM specific pseudo access flags
-
- int ACC_DEPRECATED = 0x20000; // class, field, method
-
- // types for NEWARRAY
-
- int T_BOOLEAN = 4;
- int T_CHAR = 5;
- int T_FLOAT = 6;
- int T_DOUBLE = 7;
- int T_BYTE = 8;
- int T_SHORT = 9;
- int T_INT = 10;
- int T_LONG = 11;
-
- // tags for Handle
-
- int H_GETFIELD = 1;
- int H_GETSTATIC = 2;
- int H_PUTFIELD = 3;
- int H_PUTSTATIC = 4;
- int H_INVOKEVIRTUAL = 5;
- int H_INVOKESTATIC = 6;
- int H_INVOKESPECIAL = 7;
- int H_NEWINVOKESPECIAL = 8;
- int H_INVOKEINTERFACE = 9;
-
- // stack map frame types
-
- /** Represents an expanded frame. See {@link ClassReader#EXPAND_FRAMES}. */
- int F_NEW = -1;
-
- /** Represents a compressed frame with complete frame data. */
- int F_FULL = 0;
-
- /**
- * Represents a compressed frame where locals are the same as the locals in the previous frame, except that
- * additional 1-3 locals are defined, and with an empty stack.
- */
- int F_APPEND = 1;
-
- /**
- * Represents a compressed frame where locals are the same as the locals in the previous frame, except that the last
- * 1-3 locals are absent and with an empty stack.
- */
- int F_CHOP = 2;
-
- /** Represents a compressed frame with exactly the same locals as the previous frame and with an empty stack. */
- int F_SAME = 3;
-
- /**
- * Represents a compressed frame with exactly the same locals as the previous frame and with a single value on the
- * stack.
- */
- int F_SAME1 = 4;
-
- // Do not try to change the following code to use auto-boxing,
- // these values are compared by reference and not by value
- // The constructor of Integer was deprecated in 9
- // but we are stuck with it by backward compatibility
- @SuppressWarnings("deprecation")
- Integer TOP = new Integer(0);
-
- @SuppressWarnings("deprecation")
- Integer INTEGER = new Integer(1);
-
- @SuppressWarnings("deprecation")
- Integer FLOAT = new Integer(2);
-
- @SuppressWarnings("deprecation")
- Integer DOUBLE = new Integer(3);
-
- @SuppressWarnings("deprecation")
- Integer LONG = new Integer(4);
-
- @SuppressWarnings("deprecation")
- Integer NULL = new Integer(5);
-
- @SuppressWarnings("deprecation")
- Integer UNINITIALIZED_THIS = new Integer(6);
-
- // opcodes // visit method (- = idem)
-
- int NOP = 0; // visitInsn
- int ACONST_NULL = 1; // -
- int ICONST_M1 = 2; // -
- int ICONST_0 = 3; // -
- int ICONST_1 = 4; // -
- int ICONST_2 = 5; // -
- int ICONST_3 = 6; // -
- int ICONST_4 = 7; // -
- int ICONST_5 = 8; // -
- int LCONST_0 = 9; // -
- int LCONST_1 = 10; // -
- int FCONST_0 = 11; // -
- int FCONST_1 = 12; // -
- int FCONST_2 = 13; // -
- int DCONST_0 = 14; // -
- int DCONST_1 = 15; // -
- int BIPUSH = 16; // visitIntInsn
- int SIPUSH = 17; // -
- int LDC = 18; // visitLdcInsn
- // int LDC_W = 19; // -
- // int LDC2_W = 20; // -
- int ILOAD = 21; // visitVarInsn
- int LLOAD = 22; // -
- int FLOAD = 23; // -
- int DLOAD = 24; // -
- int ALOAD = 25; // -
- // int ILOAD_0 = 26; // -
- // int ILOAD_1 = 27; // -
- // int ILOAD_2 = 28; // -
- // int ILOAD_3 = 29; // -
- // int LLOAD_0 = 30; // -
- // int LLOAD_1 = 31; // -
- // int LLOAD_2 = 32; // -
- // int LLOAD_3 = 33; // -
- // int FLOAD_0 = 34; // -
- // int FLOAD_1 = 35; // -
- // int FLOAD_2 = 36; // -
- // int FLOAD_3 = 37; // -
- // int DLOAD_0 = 38; // -
- // int DLOAD_1 = 39; // -
- // int DLOAD_2 = 40; // -
- // int DLOAD_3 = 41; // -
- // int ALOAD_0 = 42; // -
- // int ALOAD_1 = 43; // -
- // int ALOAD_2 = 44; // -
- // int ALOAD_3 = 45; // -
- int IALOAD = 46; // visitInsn
- int LALOAD = 47; // -
- int FALOAD = 48; // -
- int DALOAD = 49; // -
- int AALOAD = 50; // -
- int BALOAD = 51; // -
- int CALOAD = 52; // -
- int SALOAD = 53; // -
- int ISTORE = 54; // visitVarInsn
- int LSTORE = 55; // -
- int FSTORE = 56; // -
- int DSTORE = 57; // -
- int ASTORE = 58; // -
- // int ISTORE_0 = 59; // -
- // int ISTORE_1 = 60; // -
- // int ISTORE_2 = 61; // -
- // int ISTORE_3 = 62; // -
- // int LSTORE_0 = 63; // -
- // int LSTORE_1 = 64; // -
- // int LSTORE_2 = 65; // -
- // int LSTORE_3 = 66; // -
- // int FSTORE_0 = 67; // -
- // int FSTORE_1 = 68; // -
- // int FSTORE_2 = 69; // -
- // int FSTORE_3 = 70; // -
- // int DSTORE_0 = 71; // -
- // int DSTORE_1 = 72; // -
- // int DSTORE_2 = 73; // -
- // int DSTORE_3 = 74; // -
- // int ASTORE_0 = 75; // -
- // int ASTORE_1 = 76; // -
- // int ASTORE_2 = 77; // -
- // int ASTORE_3 = 78; // -
- int IASTORE = 79; // visitInsn
- int LASTORE = 80; // -
- int FASTORE = 81; // -
- int DASTORE = 82; // -
- int AASTORE = 83; // -
- int BASTORE = 84; // -
- int CASTORE = 85; // -
- int SASTORE = 86; // -
- int POP = 87; // -
- int POP2 = 88; // -
- int DUP = 89; // -
- int DUP_X1 = 90; // -
- int DUP_X2 = 91; // -
- int DUP2 = 92; // -
- int DUP2_X1 = 93; // -
- int DUP2_X2 = 94; // -
- int SWAP = 95; // -
- int IADD = 96; // -
- int LADD = 97; // -
- int FADD = 98; // -
- int DADD = 99; // -
- int ISUB = 100; // -
- int LSUB = 101; // -
- int FSUB = 102; // -
- int DSUB = 103; // -
- int IMUL = 104; // -
- int LMUL = 105; // -
- int FMUL = 106; // -
- int DMUL = 107; // -
- int IDIV = 108; // -
- int LDIV = 109; // -
- int FDIV = 110; // -
- int DDIV = 111; // -
- int IREM = 112; // -
- int LREM = 113; // -
- int FREM = 114; // -
- int DREM = 115; // -
- int INEG = 116; // -
- int LNEG = 117; // -
- int FNEG = 118; // -
- int DNEG = 119; // -
- int ISHL = 120; // -
- int LSHL = 121; // -
- int ISHR = 122; // -
- int LSHR = 123; // -
- int IUSHR = 124; // -
- int LUSHR = 125; // -
- int IAND = 126; // -
- int LAND = 127; // -
- int IOR = 128; // -
- int LOR = 129; // -
- int IXOR = 130; // -
- int LXOR = 131; // -
- int IINC = 132; // visitIincInsn
- int I2L = 133; // visitInsn
- int I2F = 134; // -
- int I2D = 135; // -
- int L2I = 136; // -
- int L2F = 137; // -
- int L2D = 138; // -
- int F2I = 139; // -
- int F2L = 140; // -
- int F2D = 141; // -
- int D2I = 142; // -
- int D2L = 143; // -
- int D2F = 144; // -
- int I2B = 145; // -
- int I2C = 146; // -
- int I2S = 147; // -
- int LCMP = 148; // -
- int FCMPL = 149; // -
- int FCMPG = 150; // -
- int DCMPL = 151; // -
- int DCMPG = 152; // -
- int IFEQ = 153; // visitJumpInsn
- int IFNE = 154; // -
- int IFLT = 155; // -
- int IFGE = 156; // -
- int IFGT = 157; // -
- int IFLE = 158; // -
- int IF_ICMPEQ = 159; // -
- int IF_ICMPNE = 160; // -
- int IF_ICMPLT = 161; // -
- int IF_ICMPGE = 162; // -
- int IF_ICMPGT = 163; // -
- int IF_ICMPLE = 164; // -
- int IF_ACMPEQ = 165; // -
- int IF_ACMPNE = 166; // -
- int GOTO = 167; // -
- int JSR = 168; // -
- int RET = 169; // visitVarInsn
- int TABLESWITCH = 170; // visiTableSwitchInsn
- int LOOKUPSWITCH = 171; // visitLookupSwitch
- int IRETURN = 172; // visitInsn
- int LRETURN = 173; // -
- int FRETURN = 174; // -
- int DRETURN = 175; // -
- int ARETURN = 176; // -
- int RETURN = 177; // -
- int GETSTATIC = 178; // visitFieldInsn
- int PUTSTATIC = 179; // -
- int GETFIELD = 180; // -
- int PUTFIELD = 181; // -
- int INVOKEVIRTUAL = 182; // visitMethodInsn
- int INVOKESPECIAL = 183; // -
- int INVOKESTATIC = 184; // -
- int INVOKEINTERFACE = 185; // -
- int INVOKEDYNAMIC = 186; // visitInvokeDynamicInsn
- int NEW = 187; // visitTypeInsn
- int NEWARRAY = 188; // visitIntInsn
- int ANEWARRAY = 189; // visitTypeInsn
- int ARRAYLENGTH = 190; // visitInsn
- int ATHROW = 191; // -
- int CHECKCAST = 192; // visitTypeInsn
- int INSTANCEOF = 193; // -
- int MONITORENTER = 194; // visitInsn
- int MONITOREXIT = 195; // -
- // int WIDE = 196; // NOT VISITED
- int MULTIANEWARRAY = 197; // visitMultiANewArrayInsn
- int IFNULL = 198; // visitJumpInsn
- int IFNONNULL = 199; // -
- // int GOTO_W = 200; // -
- // int JSR_W = 201; // -
-}
+/*
+ * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ */
+
+/*
+ *
+ *
+ *
+ *
+ *
+ * ASM: a very small and fast Java bytecode manipulation framework
+ * Copyright (c) 2000-2011 INRIA, France Telecom
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.redkale.asm;
+
+/**
+ * Defines the JVM opcodes, access flags and array type codes. This interface does not define all the JVM opcodes
+ * because some opcodes are automatically handled. For example, the xLOAD and xSTORE opcodes are automatically replaced
+ * by xLOAD_n and xSTORE_n opcodes when possible. The xLOAD_n and xSTORE_n opcodes are therefore not defined in this
+ * interface. Likewise for LDC, automatically replaced by LDC_W or LDC2_W when necessary, WIDE, GOTO_W and JSR_W.
+ *
+ * @author Eric Bruneton
+ * @author Eugene Kuleshov
+ */
+public interface Opcodes {
+
+ // ASM API versions
+ int ASM4 = 4 << 16 | 0 << 8;
+ int ASM5 = 5 << 16 | 0 << 8;
+ int ASM6 = 6 << 16 | 0 << 8;
+
+ // versions
+
+ int V1_1 = 3 << 16 | 45;
+ int V1_2 = 0 << 16 | 46;
+ int V1_3 = 0 << 16 | 47;
+ int V1_4 = 0 << 16 | 48;
+ int V1_5 = 0 << 16 | 49;
+ int V1_6 = 0 << 16 | 50;
+ int V1_7 = 0 << 16 | 51;
+ int V1_8 = 0 << 16 | 52;
+ int V9 = 0 << 16 | 53;
+ int V10 = 0 << 16 | 54;
+ int V11 = 0 << 16 | 55;
+
+ // access flags
+
+ int ACC_PUBLIC = 0x0001; // class, field, method
+ int ACC_PRIVATE = 0x0002; // class, field, method
+ int ACC_PROTECTED = 0x0004; // class, field, method
+ int ACC_STATIC = 0x0008; // field, method
+ int ACC_FINAL = 0x0010; // class, field, method, parameter
+ int ACC_SUPER = 0x0020; // class
+ int ACC_SYNCHRONIZED = 0x0020; // method
+ int ACC_OPEN = 0x0020; // module
+ int ACC_TRANSITIVE = 0x0020; // module requires
+ int ACC_VOLATILE = 0x0040; // field
+ int ACC_BRIDGE = 0x0040; // method
+ int ACC_STATIC_PHASE = 0x0040; // module requires
+ int ACC_VARARGS = 0x0080; // method
+ int ACC_TRANSIENT = 0x0080; // field
+ int ACC_NATIVE = 0x0100; // method
+ int ACC_INTERFACE = 0x0200; // class
+ int ACC_ABSTRACT = 0x0400; // class, method
+ int ACC_STRICT = 0x0800; // method
+ int ACC_SYNTHETIC = 0x1000; // class, field, method, parameter, module *
+ int ACC_ANNOTATION = 0x2000; // class
+ int ACC_ENUM = 0x4000; // class(?) field inner
+ int ACC_MANDATED = 0x8000; // parameter, module, module *
+ int ACC_MODULE = 0x8000; // class
+
+ // ASM specific pseudo access flags
+
+ int ACC_DEPRECATED = 0x20000; // class, field, method
+
+ // types for NEWARRAY
+
+ int T_BOOLEAN = 4;
+ int T_CHAR = 5;
+ int T_FLOAT = 6;
+ int T_DOUBLE = 7;
+ int T_BYTE = 8;
+ int T_SHORT = 9;
+ int T_INT = 10;
+ int T_LONG = 11;
+
+ // tags for Handle
+
+ int H_GETFIELD = 1;
+ int H_GETSTATIC = 2;
+ int H_PUTFIELD = 3;
+ int H_PUTSTATIC = 4;
+ int H_INVOKEVIRTUAL = 5;
+ int H_INVOKESTATIC = 6;
+ int H_INVOKESPECIAL = 7;
+ int H_NEWINVOKESPECIAL = 8;
+ int H_INVOKEINTERFACE = 9;
+
+ // stack map frame types
+
+ /** Represents an expanded frame. See {@link ClassReader#EXPAND_FRAMES}. */
+ int F_NEW = -1;
+
+ /** Represents a compressed frame with complete frame data. */
+ int F_FULL = 0;
+
+ /**
+ * Represents a compressed frame where locals are the same as the locals in the previous frame, except that
+ * additional 1-3 locals are defined, and with an empty stack.
+ */
+ int F_APPEND = 1;
+
+ /**
+ * Represents a compressed frame where locals are the same as the locals in the previous frame, except that the last
+ * 1-3 locals are absent and with an empty stack.
+ */
+ int F_CHOP = 2;
+
+ /** Represents a compressed frame with exactly the same locals as the previous frame and with an empty stack. */
+ int F_SAME = 3;
+
+ /**
+ * Represents a compressed frame with exactly the same locals as the previous frame and with a single value on the
+ * stack.
+ */
+ int F_SAME1 = 4;
+
+ // Do not try to change the following code to use auto-boxing,
+ // these values are compared by reference and not by value
+ // The constructor of Integer was deprecated in 9
+ // but we are stuck with it by backward compatibility
+ @SuppressWarnings("deprecation")
+ Integer TOP = new Integer(0);
+
+ @SuppressWarnings("deprecation")
+ Integer INTEGER = new Integer(1);
+
+ @SuppressWarnings("deprecation")
+ Integer FLOAT = new Integer(2);
+
+ @SuppressWarnings("deprecation")
+ Integer DOUBLE = new Integer(3);
+
+ @SuppressWarnings("deprecation")
+ Integer LONG = new Integer(4);
+
+ @SuppressWarnings("deprecation")
+ Integer NULL = new Integer(5);
+
+ @SuppressWarnings("deprecation")
+ Integer UNINITIALIZED_THIS = new Integer(6);
+
+ // opcodes // visit method (- = idem)
+
+ int NOP = 0; // visitInsn
+ int ACONST_NULL = 1; // -
+ int ICONST_M1 = 2; // -
+ int ICONST_0 = 3; // -
+ int ICONST_1 = 4; // -
+ int ICONST_2 = 5; // -
+ int ICONST_3 = 6; // -
+ int ICONST_4 = 7; // -
+ int ICONST_5 = 8; // -
+ int LCONST_0 = 9; // -
+ int LCONST_1 = 10; // -
+ int FCONST_0 = 11; // -
+ int FCONST_1 = 12; // -
+ int FCONST_2 = 13; // -
+ int DCONST_0 = 14; // -
+ int DCONST_1 = 15; // -
+ int BIPUSH = 16; // visitIntInsn
+ int SIPUSH = 17; // -
+ int LDC = 18; // visitLdcInsn
+ // int LDC_W = 19; // -
+ // int LDC2_W = 20; // -
+ int ILOAD = 21; // visitVarInsn
+ int LLOAD = 22; // -
+ int FLOAD = 23; // -
+ int DLOAD = 24; // -
+ int ALOAD = 25; // -
+ // int ILOAD_0 = 26; // -
+ // int ILOAD_1 = 27; // -
+ // int ILOAD_2 = 28; // -
+ // int ILOAD_3 = 29; // -
+ // int LLOAD_0 = 30; // -
+ // int LLOAD_1 = 31; // -
+ // int LLOAD_2 = 32; // -
+ // int LLOAD_3 = 33; // -
+ // int FLOAD_0 = 34; // -
+ // int FLOAD_1 = 35; // -
+ // int FLOAD_2 = 36; // -
+ // int FLOAD_3 = 37; // -
+ // int DLOAD_0 = 38; // -
+ // int DLOAD_1 = 39; // -
+ // int DLOAD_2 = 40; // -
+ // int DLOAD_3 = 41; // -
+ // int ALOAD_0 = 42; // -
+ // int ALOAD_1 = 43; // -
+ // int ALOAD_2 = 44; // -
+ // int ALOAD_3 = 45; // -
+ int IALOAD = 46; // visitInsn
+ int LALOAD = 47; // -
+ int FALOAD = 48; // -
+ int DALOAD = 49; // -
+ int AALOAD = 50; // -
+ int BALOAD = 51; // -
+ int CALOAD = 52; // -
+ int SALOAD = 53; // -
+ int ISTORE = 54; // visitVarInsn
+ int LSTORE = 55; // -
+ int FSTORE = 56; // -
+ int DSTORE = 57; // -
+ int ASTORE = 58; // -
+ // int ISTORE_0 = 59; // -
+ // int ISTORE_1 = 60; // -
+ // int ISTORE_2 = 61; // -
+ // int ISTORE_3 = 62; // -
+ // int LSTORE_0 = 63; // -
+ // int LSTORE_1 = 64; // -
+ // int LSTORE_2 = 65; // -
+ // int LSTORE_3 = 66; // -
+ // int FSTORE_0 = 67; // -
+ // int FSTORE_1 = 68; // -
+ // int FSTORE_2 = 69; // -
+ // int FSTORE_3 = 70; // -
+ // int DSTORE_0 = 71; // -
+ // int DSTORE_1 = 72; // -
+ // int DSTORE_2 = 73; // -
+ // int DSTORE_3 = 74; // -
+ // int ASTORE_0 = 75; // -
+ // int ASTORE_1 = 76; // -
+ // int ASTORE_2 = 77; // -
+ // int ASTORE_3 = 78; // -
+ int IASTORE = 79; // visitInsn
+ int LASTORE = 80; // -
+ int FASTORE = 81; // -
+ int DASTORE = 82; // -
+ int AASTORE = 83; // -
+ int BASTORE = 84; // -
+ int CASTORE = 85; // -
+ int SASTORE = 86; // -
+ int POP = 87; // -
+ int POP2 = 88; // -
+ int DUP = 89; // -
+ int DUP_X1 = 90; // -
+ int DUP_X2 = 91; // -
+ int DUP2 = 92; // -
+ int DUP2_X1 = 93; // -
+ int DUP2_X2 = 94; // -
+ int SWAP = 95; // -
+ int IADD = 96; // -
+ int LADD = 97; // -
+ int FADD = 98; // -
+ int DADD = 99; // -
+ int ISUB = 100; // -
+ int LSUB = 101; // -
+ int FSUB = 102; // -
+ int DSUB = 103; // -
+ int IMUL = 104; // -
+ int LMUL = 105; // -
+ int FMUL = 106; // -
+ int DMUL = 107; // -
+ int IDIV = 108; // -
+ int LDIV = 109; // -
+ int FDIV = 110; // -
+ int DDIV = 111; // -
+ int IREM = 112; // -
+ int LREM = 113; // -
+ int FREM = 114; // -
+ int DREM = 115; // -
+ int INEG = 116; // -
+ int LNEG = 117; // -
+ int FNEG = 118; // -
+ int DNEG = 119; // -
+ int ISHL = 120; // -
+ int LSHL = 121; // -
+ int ISHR = 122; // -
+ int LSHR = 123; // -
+ int IUSHR = 124; // -
+ int LUSHR = 125; // -
+ int IAND = 126; // -
+ int LAND = 127; // -
+ int IOR = 128; // -
+ int LOR = 129; // -
+ int IXOR = 130; // -
+ int LXOR = 131; // -
+ int IINC = 132; // visitIincInsn
+ int I2L = 133; // visitInsn
+ int I2F = 134; // -
+ int I2D = 135; // -
+ int L2I = 136; // -
+ int L2F = 137; // -
+ int L2D = 138; // -
+ int F2I = 139; // -
+ int F2L = 140; // -
+ int F2D = 141; // -
+ int D2I = 142; // -
+ int D2L = 143; // -
+ int D2F = 144; // -
+ int I2B = 145; // -
+ int I2C = 146; // -
+ int I2S = 147; // -
+ int LCMP = 148; // -
+ int FCMPL = 149; // -
+ int FCMPG = 150; // -
+ int DCMPL = 151; // -
+ int DCMPG = 152; // -
+ int IFEQ = 153; // visitJumpInsn
+ int IFNE = 154; // -
+ int IFLT = 155; // -
+ int IFGE = 156; // -
+ int IFGT = 157; // -
+ int IFLE = 158; // -
+ int IF_ICMPEQ = 159; // -
+ int IF_ICMPNE = 160; // -
+ int IF_ICMPLT = 161; // -
+ int IF_ICMPGE = 162; // -
+ int IF_ICMPGT = 163; // -
+ int IF_ICMPLE = 164; // -
+ int IF_ACMPEQ = 165; // -
+ int IF_ACMPNE = 166; // -
+ int GOTO = 167; // -
+ int JSR = 168; // -
+ int RET = 169; // visitVarInsn
+ int TABLESWITCH = 170; // visiTableSwitchInsn
+ int LOOKUPSWITCH = 171; // visitLookupSwitch
+ int IRETURN = 172; // visitInsn
+ int LRETURN = 173; // -
+ int FRETURN = 174; // -
+ int DRETURN = 175; // -
+ int ARETURN = 176; // -
+ int RETURN = 177; // -
+ int GETSTATIC = 178; // visitFieldInsn
+ int PUTSTATIC = 179; // -
+ int GETFIELD = 180; // -
+ int PUTFIELD = 181; // -
+ int INVOKEVIRTUAL = 182; // visitMethodInsn
+ int INVOKESPECIAL = 183; // -
+ int INVOKESTATIC = 184; // -
+ int INVOKEINTERFACE = 185; // -
+ int INVOKEDYNAMIC = 186; // visitInvokeDynamicInsn
+ int NEW = 187; // visitTypeInsn
+ int NEWARRAY = 188; // visitIntInsn
+ int ANEWARRAY = 189; // visitTypeInsn
+ int ARRAYLENGTH = 190; // visitInsn
+ int ATHROW = 191; // -
+ int CHECKCAST = 192; // visitTypeInsn
+ int INSTANCEOF = 193; // -
+ int MONITORENTER = 194; // visitInsn
+ int MONITOREXIT = 195; // -
+ // int WIDE = 196; // NOT VISITED
+ int MULTIANEWARRAY = 197; // visitMultiANewArrayInsn
+ int IFNULL = 198; // visitJumpInsn
+ int IFNONNULL = 199; // -
+ // int GOTO_W = 200; // -
+ // int JSR_W = 201; // -
+}
diff --git a/src/main/java/org/redkale/asm/Type.java b/src/main/java/org/redkale/asm/Type.java
index 24ff609a4..ea9e82612 100644
--- a/src/main/java/org/redkale/asm/Type.java
+++ b/src/main/java/org/redkale/asm/Type.java
@@ -1,815 +1,815 @@
-/*
- * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- */
-
-/*
- *
- *
- *
- *
- *
- * ASM: a very small and fast Java bytecode manipulation framework
- * Copyright (c) 2000-2011 INRIA, France Telecom
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-package org.redkale.asm;
-
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Method;
-
-/**
- * A Java field or method type. This class can be used to make it easier to manipulate type and method descriptors.
- *
- * @author Eric Bruneton
- * @author Chris Nokleberg
- */
-public class Type {
-
- /** The sort of the <tt>void</tt> type. See {@link #getSort getSort}. */
- public static final int VOID = 0;
-
- /** The sort of the <tt>boolean</tt> type. See {@link #getSort getSort}. */
- public static final int BOOLEAN = 1;
-
- /** The sort of the <tt>char</tt> type. See {@link #getSort getSort}. */
- public static final int CHAR = 2;
-
- /** The sort of the <tt>byte</tt> type. See {@link #getSort getSort}. */
- public static final int BYTE = 3;
-
- /** The sort of the <tt>short</tt> type. See {@link #getSort getSort}. */
- public static final int SHORT = 4;
-
- /** The sort of the <tt>int</tt> type. See {@link #getSort getSort}. */
- public static final int INT = 5;
-
- /** The sort of the <tt>float</tt> type. See {@link #getSort getSort}. */
- public static final int FLOAT = 6;
-
- /** The sort of the <tt>long</tt> type. See {@link #getSort getSort}. */
- public static final int LONG = 7;
-
- /** The sort of the <tt>double</tt> type. See {@link #getSort getSort}. */
- public static final int DOUBLE = 8;
-
- /** The sort of array reference types. See {@link #getSort getSort}. */
- public static final int ARRAY = 9;
-
- /** The sort of object reference types. See {@link #getSort getSort}. */
- public static final int OBJECT = 10;
-
- /** The sort of method types. See {@link #getSort getSort}. */
- public static final int METHOD = 11;
-
- /** The <tt>void</tt> type. */
- public static final Type VOID_TYPE = new Type(VOID, null, ('V' << 24) | (5 << 16) | (0 << 8) | 0, 1);
-
- /** The <tt>boolean</tt> type. */
- public static final Type BOOLEAN_TYPE = new Type(BOOLEAN, null, ('Z' << 24) | (0 << 16) | (5 << 8) | 1, 1);
-
- /** The <tt>char</tt> type. */
- public static final Type CHAR_TYPE = new Type(CHAR, null, ('C' << 24) | (0 << 16) | (6 << 8) | 1, 1);
-
- /** The <tt>byte</tt> type. */
- public static final Type BYTE_TYPE = new Type(BYTE, null, ('B' << 24) | (0 << 16) | (5 << 8) | 1, 1);
-
- /** The <tt>short</tt> type. */
- public static final Type SHORT_TYPE = new Type(SHORT, null, ('S' << 24) | (0 << 16) | (7 << 8) | 1, 1);
-
- /** The <tt>int</tt> type. */
- public static final Type INT_TYPE = new Type(INT, null, ('I' << 24) | (0 << 16) | (0 << 8) | 1, 1);
-
- /** The <tt>float</tt> type. */
- public static final Type FLOAT_TYPE = new Type(FLOAT, null, ('F' << 24) | (2 << 16) | (2 << 8) | 1, 1);
-
- /** The <tt>long</tt> type. */
- public static final Type LONG_TYPE = new Type(LONG, null, ('J' << 24) | (1 << 16) | (1 << 8) | 2, 1);
-
- /** The <tt>double</tt> type. */
- public static final Type DOUBLE_TYPE = new Type(DOUBLE, null, ('D' << 24) | (3 << 16) | (3 << 8) | 2, 1);
-
- // ------------------------------------------------------------------------
- // Fields
- // ------------------------------------------------------------------------
-
- /** The sort of this Java type. */
- private final int sort;
-
- /** A buffer containing the internal name of this Java type. This field is only used for reference types. */
- private final char[] buf;
-
- /**
- * The offset of the internal name of this Java type in {@link #buf buf} or, for primitive types, the size,
- * descriptor and getOpcode offsets for this type (byte 0 contains the size, byte 1 the descriptor, byte 2 the
- * offset for IALOAD or IASTORE, byte 3 the offset for all other instructions).
- */
- private final int off;
-
- /** The length of the internal name of this Java type. */
- private final int len;
-
- // ------------------------------------------------------------------------
- // Constructors
- // ------------------------------------------------------------------------
-
- /**
- * Constructs a reference type.
- *
- * @param sort the sort of the reference type to be constructed.
- * @param buf a buffer containing the descriptor of the previous type.
- * @param off the offset of this descriptor in the previous buffer.
- * @param len the length of this descriptor.
- */
- private Type(final int sort, final char[] buf, final int off, final int len) {
- this.sort = sort;
- this.buf = buf;
- this.off = off;
- this.len = len;
- }
-
- /**
- * Returns the Java type corresponding to the given type descriptor.
- *
- * @param typeDescriptor a field or method type descriptor.
- * @return the Java type corresponding to the given type descriptor.
- */
- public static Type getType(final String typeDescriptor) {
- return getType(typeDescriptor.toCharArray(), 0);
- }
-
- /**
- * Returns the Java type corresponding to the given internal name.
- *
- * @param internalName an internal name.
- * @return the Java type corresponding to the given internal name.
- */
- public static Type getObjectType(final String internalName) {
- char[] buf = internalName.toCharArray();
- return new Type(buf[0] == '[' ? ARRAY : OBJECT, buf, 0, buf.length);
- }
-
- /**
- * Returns the Java type corresponding to the given method descriptor. Equivalent to 详情见: https://redkale.org
- *
- * @author zhangjx
- */
-public final class Application {
-
- /** 当前进程启动的时间, 类型: long */
- public static final String RESNAME_APP_TIME = "APP_TIME";
-
- /** 当前进程服务的名称, 类型:String */
- public static final String RESNAME_APP_NAME = "APP_NAME";
-
- /** 当前进程的根目录, 类型:String、File、Path、URI */
- public static final String RESNAME_APP_HOME = "APP_HOME";
-
- /**
- * 当前进程的配置目录URI,如果不是绝对路径则视为HOME目录下的相对路径 类型:String、URI、File、Path
- *
- *
+ *
+ * CODE attribute won't be visited. This can be used,
- * for example, to retrieve annotations for methods and method parameters.
- */
- public static final int SKIP_CODE = 1;
-
- /**
- * Flag to skip the debug information in the class. If this flag is set the debug information of the class is not
- * visited, i.e. the {@link MethodVisitor#visitLocalVariable visitLocalVariable} and
- * {@link MethodVisitor#visitLineNumber visitLineNumber} methods will not be called.
- */
- public static final int SKIP_DEBUG = 2;
-
- /**
- * Flag to skip the stack map frames in the class. If this flag is set the stack map frames of the class is not
- * visited, i.e. the {@link MethodVisitor#visitFrame visitFrame} method will not be called. This flag is useful when
- * the {@link ClassWriter#COMPUTE_FRAMES} option is used: it avoids visiting frames that will be ignored and
- * recomputed from scratch in the class writer.
- */
- public static final int SKIP_FRAMES = 4;
-
- /**
- * Flag to expand the stack map frames. By default stack map frames are visited in their original format (i.e.
- * "expanded" for classes whose version is less than V1_6, and "compressed" for the other classes). If this flag is
- * set, stack map frames are always visited in expanded format (this option adds a decompression/recompression step
- * in ClassReader and ClassWriter which degrades performances quite a lot).
- */
- public static final int EXPAND_FRAMES = 8;
-
- /**
- * Flag to expand the ASM pseudo instructions into an equivalent sequence of standard bytecode instructions. When
- * resolving a forward jump it may happen that the signed 2 bytes offset reserved for it is not sufficient to store
- * the bytecode offset. In this case the jump instruction is replaced with a temporary ASM pseudo instruction using
- * an unsigned 2 bytes offset (see Label#resolve). This internal flag is used to re-read classes containing such
- * instructions, in order to replace them with standard instructions. In addition, when this flag is used, GOTO_W
- * and JSR_W are not converted into GOTO and JSR, to make sure that infinite loops where a GOTO_W is replaced
- * with a GOTO in ClassReader and converted back to a GOTO_W in ClassWriter cannot occur.
- */
- static final int EXPAND_ASM_INSNS = 256;
-
- /**
- * The class to be parsed. The content of this array must not be modified. This field is intended for
- * {@link Attribute} sub classes, and is normally not needed by class generators or adapters.
- */
- public final byte[] b;
-
- /**
- * The start index of each constant pool item in {@link #b b}, plus one. The one byte offset skips the constant pool
- * item tag that indicates its type.
- */
- private final int[] items;
-
- /**
- * The String objects corresponding to the CONSTANT_Utf8 items. This cache avoids multiple parsing of a given
- * CONSTANT_Utf8 constant pool item, which GREATLY improves performances (by a factor 2 to 3). This caching strategy
- * could be extended to all constant pool items, but its benefit would not be so great for these items (because they
- * are much less expensive to parse than CONSTANT_Utf8 items).
- */
- private final String[] strings;
-
- /** Maximum length of the strings contained in the constant pool of the class. */
- private final int maxStringLength;
-
- /** Start index of the class header information (access, name...) in {@link #b b}. */
- public final int header;
-
- // ------------------------------------------------------------------------
- // Constructors
- // ------------------------------------------------------------------------
-
- /**
- * Constructs a new {@link ClassReader} object.
- *
- * @param b the bytecode of the class to be read.
- */
- public ClassReader(final byte[] b) {
- this(b, 0, b.length);
- }
-
- /**
- * Constructs a new {@link ClassReader} object.
- *
- * @param b the bytecode of the class to be read.
- * @param off the start offset of the class data.
- * @param len the length of the class data.
- */
- public ClassReader(final byte[] b, final int off, final int len) {
- this.b = b;
- // checks the class version
- // if (readShort(off + 6) > Opcodes.V11) {
- // throw new IllegalArgumentException();
- // }
- // parses the constant pool
- items = new int[readUnsignedShort(off + 8)];
- int n = items.length;
- strings = new String[n];
- int max = 0;
- int index = off + 10;
- for (int i = 1; i < n; ++i) {
- items[i] = index + 1;
- int size;
- switch (b[index]) {
- case ClassWriter.FIELD:
- case ClassWriter.METH:
- case ClassWriter.IMETH:
- case ClassWriter.INT:
- case ClassWriter.FLOAT:
- case ClassWriter.NAME_TYPE:
- case ClassWriter.INDY:
- // @@@ ClassWriter.CONDY
- // Enables MethodHandles.lookup().defineClass to function correctly
- // when it reads the class name
- case 17:
- size = 5;
- break;
- case ClassWriter.LONG:
- case ClassWriter.DOUBLE:
- size = 9;
- ++i;
- break;
- case ClassWriter.UTF8:
- size = 3 + readUnsignedShort(index + 1);
- if (size > max) {
- max = size;
- }
- break;
- case ClassWriter.HANDLE:
- size = 4;
- break;
- // case ClassWriter.CLASS:
- // case ClassWriter.STR:
- // case ClassWriter.MTYPE
- // case ClassWriter.PACKAGE:
- // case ClassWriter.MODULE:
- default:
- size = 3;
- break;
- }
- index += size;
- }
- maxStringLength = max;
- // the class header information starts just after the constant pool
- header = index;
- }
-
- /**
- * Returns the class's access flags (see {@link Opcodes}). This value may not reflect Deprecated and Synthetic flags
- * when bytecode is before 1.5 and those flags are represented by attributes.
- *
- * @return the class access flags
- * @see ClassVisitor#visit(int, int, String, String, String, String[])
- */
- public int getAccess() {
- return readUnsignedShort(header);
- }
-
- /**
- * Returns the internal name of the class (see {@link Type#getInternalName() getInternalName}).
- *
- * @return the internal class name
- * @see ClassVisitor#visit(int, int, String, String, String, String[])
- */
- public String getClassName() {
- return readClass(header + 2, new char[maxStringLength]);
- }
-
- /**
- * Returns the internal of name of the super class (see {@link Type#getInternalName() getInternalName}). For
- * interfaces, the super class is {@link Object}.
- *
- * @return the internal name of super class, or <tt>null</tt> for {@link Object} class.
- * @see ClassVisitor#visit(int, int, String, String, String, String[])
- */
- public String getSuperName() {
- return readClass(header + 4, new char[maxStringLength]);
- }
-
- /**
- * Returns the internal names of the class's interfaces (see {@link Type#getInternalName() getInternalName}).
- *
- * @return the array of internal names for all implemented interfaces or <tt>null</tt>.
- * @see ClassVisitor#visit(int, int, String, String, String, String[])
- */
- public String[] getInterfaces() {
- int index = header + 6;
- int n = readUnsignedShort(index);
- String[] interfaces = new String[n];
- if (n > 0) {
- char[] buf = new char[maxStringLength];
- for (int i = 0; i < n; ++i) {
- index += 2;
- interfaces[i] = readClass(index, buf);
- }
- }
- return interfaces;
- }
-
- /**
- * Copies the constant pool data into the given {@link ClassWriter}. Should be called before the
- * {@link #accept(ClassVisitor,int)} method.
- *
- * @param classWriter the {@link ClassWriter} to copy constant pool into.
- */
- void copyPool(final ClassWriter classWriter) {
- char[] buf = new char[maxStringLength];
- int ll = items.length;
- Item[] items2 = new Item[ll];
- for (int i = 1; i < ll; i++) {
- int index = items[i];
- int tag = b[index - 1];
- Item item = new Item(i);
- int nameType;
- switch (tag) {
- case ClassWriter.FIELD:
- case ClassWriter.METH:
- case ClassWriter.IMETH:
- nameType = items[readUnsignedShort(index + 2)];
- item.set(tag, readClass(index, buf), readUTF8(nameType, buf), readUTF8(nameType + 2, buf));
- break;
- case ClassWriter.INT:
- item.set(readInt(index));
- break;
- case ClassWriter.FLOAT:
- item.set(Float.intBitsToFloat(readInt(index)));
- break;
- case ClassWriter.NAME_TYPE:
- item.set(tag, readUTF8(index, buf), readUTF8(index + 2, buf), null);
- break;
- case ClassWriter.LONG:
- item.set(readLong(index));
- ++i;
- break;
- case ClassWriter.DOUBLE:
- item.set(Double.longBitsToDouble(readLong(index)));
- ++i;
- break;
- case ClassWriter.UTF8: {
- String s = strings[i];
- if (s == null) {
- index = items[i];
- s = strings[i] = readUTF(index + 2, readUnsignedShort(index), buf);
- }
- item.set(tag, s, null, null);
- break;
- }
- case ClassWriter.HANDLE: {
- int fieldOrMethodRef = items[readUnsignedShort(index + 1)];
- nameType = items[readUnsignedShort(fieldOrMethodRef + 2)];
- item.set(
- ClassWriter.HANDLE_BASE + readByte(index),
- readClass(fieldOrMethodRef, buf),
- readUTF8(nameType, buf),
- readUTF8(nameType + 2, buf));
- break;
- }
- case ClassWriter.INDY:
- if (classWriter.bootstrapMethods == null) {
- copyBootstrapMethods(classWriter, items2, buf);
- }
- nameType = items[readUnsignedShort(index + 2)];
- item.set(readUTF8(nameType, buf), readUTF8(nameType + 2, buf), readUnsignedShort(index));
- break;
- // case ClassWriter.STR:
- // case ClassWriter.CLASS:
- // case ClassWriter.MTYPE:
- // case ClassWriter.MODULE:
- // case ClassWriter.PACKAGE:
- default:
- item.set(tag, readUTF8(index, buf), null, null);
- break;
- }
-
- int index2 = item.hashCode % items2.length;
- item.next = items2[index2];
- items2[index2] = item;
- }
-
- int off = items[1] - 1;
- classWriter.pool.putByteArray(b, off, header - off);
- classWriter.items = items2;
- classWriter.threshold = (int) (0.75d * ll);
- classWriter.index = ll;
- }
-
- /**
- * Copies the bootstrap method data into the given {@link ClassWriter}. Should be called before the
- * {@link #accept(ClassVisitor,int)} method.
- *
- * @param classWriter the {@link ClassWriter} to copy bootstrap methods into.
- */
- private void copyBootstrapMethods(final ClassWriter classWriter, final Item[] items, final char[] c) {
- // finds the "BootstrapMethods" attribute
- int u = getAttributes();
- boolean found = false;
- for (int i = readUnsignedShort(u); i > 0; --i) {
- String attrName = readUTF8(u + 2, c);
- if ("BootstrapMethods".equals(attrName)) {
- found = true;
- break;
- }
- u += 6 + readInt(u + 4);
- }
- if (!found) {
- return;
- }
- // copies the bootstrap methods in the class writer
- int boostrapMethodCount = readUnsignedShort(u + 8);
- for (int j = 0, v = u + 10; j < boostrapMethodCount; j++) {
- int position = v - u - 10;
- int hashCode = readConst(readUnsignedShort(v), c).hashCode();
- for (int k = readUnsignedShort(v + 2); k > 0; --k) {
- hashCode ^= readConst(readUnsignedShort(v + 4), c).hashCode();
- v += 2;
- }
- v += 4;
- Item item = new Item(j);
- item.set(position, hashCode & 0x7FFFFFFF);
- int index = item.hashCode % items.length;
- item.next = items[index];
- items[index] = item;
- }
- int attrSize = readInt(u + 4);
- ByteVector bootstrapMethods = new ByteVector(attrSize + 62);
- bootstrapMethods.putByteArray(b, u + 10, attrSize - 2);
- classWriter.bootstrapMethodsCount = boostrapMethodCount;
- classWriter.bootstrapMethods = bootstrapMethods;
- }
-
- /**
- * Constructs a new {@link ClassReader} object.
- *
- * @param is an input stream from which to read the class.
- * @throws IOException if a problem occurs during reading.
- */
- public ClassReader(final InputStream is) throws IOException {
- this(readClass(is, false));
- }
-
- /**
- * Constructs a new {@link ClassReader} object.
- *
- * @param name the binary qualified name of the class to be read.
- * @throws IOException if an exception occurs during reading.
- */
- public ClassReader(final String name) throws IOException {
- this(readClass(ClassLoader.getSystemResourceAsStream(name.replace('.', '/') + ".class"), true));
- }
-
- /**
- * Reads the bytecode of a class.
- *
- * @param is an input stream from which to read the class.
- * @param close true to close the input stream after reading.
- * @return the bytecode read from the given input stream.
- * @throws IOException if a problem occurs during reading.
- */
- private static byte[] readClass(final InputStream is, boolean close) throws IOException {
- if (is == null) {
- throw new IOException("Class not found");
- }
- try {
- byte[] b = new byte[is.available()];
- int len = 0;
- while (true) {
- int n = is.read(b, len, b.length - len);
- if (n == -1) {
- if (len < b.length) {
- byte[] c = new byte[len];
- System.arraycopy(b, 0, c, 0, len);
- b = c;
- }
- return b;
- }
- len += n;
- if (len == b.length) {
- int last = is.read();
- if (last < 0) {
- return b;
- }
- byte[] c = new byte[b.length + 1000];
- System.arraycopy(b, 0, c, 0, len);
- c[len++] = (byte) last;
- b = c;
- }
- }
- } finally {
- if (close) {
- is.close();
- }
- }
- }
-
- // ------------------------------------------------------------------------
- // Public methods
- // ------------------------------------------------------------------------
-
- /**
- * Makes the given visitor visit the Java class of this {@link ClassReader} . This class is the one specified in the
- * constructor (see {@link #ClassReader(byte[]) ClassReader}).
- *
- * @param classVisitor the visitor that must visit this class.
- * @param flags option flags that can be used to modify the default behavior of this class. See {@link #SKIP_DEBUG},
- * {@link #EXPAND_FRAMES} , {@link #SKIP_FRAMES}, {@link #SKIP_CODE}.
- */
- public void accept(final ClassVisitor classVisitor, final int flags) {
- accept(classVisitor, Attribute.DEFAULT_ATTRIBUTE_PROTOS, flags);
- }
-
- /**
- * Makes the given visitor visit the Java class of this {@link ClassReader}. This class is the one specified in the
- * constructor (see {@link #ClassReader(byte[]) ClassReader}).
- *
- * @param classVisitor the visitor that must visit this class.
- * @param attrs prototypes of the attributes that must be parsed during the visit of the class. Any attribute whose
- * type is not equal to the type of one the prototypes will not be parsed: its byte array value will be passed
- * unchanged to the ClassWriter. This may corrupt it if this value contains references to the constant pool,
- * or has syntactic or semantic links with a class element that has been transformed by a class adapter between
- * the reader and the writer.
- * @param flags option flags that can be used to modify the default behavior of this class. See {@link #SKIP_DEBUG},
- * {@link #EXPAND_FRAMES} , {@link #SKIP_FRAMES}, {@link #SKIP_CODE}.
- */
- public void accept(final ClassVisitor classVisitor, final Attribute[] attrs, final int flags) {
- int u = header; // current offset in the class file
- char[] c = new char[maxStringLength]; // buffer used to read strings
-
- Context context = new Context();
- context.attrs = attrs;
- context.flags = flags;
- context.buffer = c;
-
- // reads the class declaration
- int access = readUnsignedShort(u);
- String name = readClass(u + 2, c);
- String superClass = readClass(u + 4, c);
- String[] interfaces = new String[readUnsignedShort(u + 6)];
- u += 8;
- for (int i = 0; i < interfaces.length; ++i) {
- interfaces[i] = readClass(u, c);
- u += 2;
- }
-
- // reads the class attributes
- String signature = null;
- String sourceFile = null;
- String sourceDebug = null;
- String enclosingOwner = null;
- String enclosingName = null;
- String enclosingDesc = null;
- String moduleMainClass = null;
- int anns = 0;
- int ianns = 0;
- int tanns = 0;
- int itanns = 0;
- int innerClasses = 0;
- int module = 0;
- int packages = 0;
- Attribute attributes = null;
-
- u = getAttributes();
- for (int i = readUnsignedShort(u); i > 0; --i) {
- String attrName = readUTF8(u + 2, c);
- // tests are sorted in decreasing frequency order
- // (based on frequencies observed on typical classes)
- if ("SourceFile".equals(attrName)) {
- sourceFile = readUTF8(u + 8, c);
- } else if ("InnerClasses".equals(attrName)) {
- innerClasses = u + 8;
- } else if ("EnclosingMethod".equals(attrName)) {
- enclosingOwner = readClass(u + 8, c);
- int item = readUnsignedShort(u + 10);
- if (item != 0) {
- enclosingName = readUTF8(items[item], c);
- enclosingDesc = readUTF8(items[item] + 2, c);
- }
- } else if ("Signature".equals(attrName)) {
- signature = readUTF8(u + 8, c);
- } else if ("RuntimeVisibleAnnotations".equals(attrName)) {
- anns = u + 8;
- } else if ("RuntimeVisibleTypeAnnotations".equals(attrName)) {
- tanns = u + 8;
- } else if ("Deprecated".equals(attrName)) {
- access |= Opcodes.ACC_DEPRECATED;
- } else if ("Synthetic".equals(attrName)) {
- access |= Opcodes.ACC_SYNTHETIC | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE;
- } else if ("SourceDebugExtension".equals(attrName)) {
- int len = readInt(u + 4);
- sourceDebug = readUTF(u + 8, len, new char[len]);
- } else if ("RuntimeInvisibleAnnotations".equals(attrName)) {
- ianns = u + 8;
- } else if ("RuntimeInvisibleTypeAnnotations".equals(attrName)) {
- itanns = u + 8;
- } else if ("Module".equals(attrName)) {
- module = u + 8;
- } else if ("ModuleMainClass".equals(attrName)) {
- moduleMainClass = readClass(u + 8, c);
- } else if ("ModulePackages".equals(attrName)) {
- packages = u + 10;
- } else if ("BootstrapMethods".equals(attrName)) {
- int[] bootstrapMethods = new int[readUnsignedShort(u + 8)];
- for (int j = 0, v = u + 10; j < bootstrapMethods.length; j++) {
- bootstrapMethods[j] = v;
- v += 2 + readUnsignedShort(v + 2) << 1;
- }
- context.bootstrapMethods = bootstrapMethods;
- } else {
- Attribute attr = readAttribute(attrs, attrName, u + 8, readInt(u + 4), c, -1, null);
- if (attr != null) {
- attr.next = attributes;
- attributes = attr;
- }
- }
- u += 6 + readInt(u + 4);
- }
-
- // visits the class declaration
- classVisitor.visit(readInt(items[1] - 7), access, name, signature, superClass, interfaces);
-
- // visits the source and debug info
- if ((flags & SKIP_DEBUG) == 0 && (sourceFile != null || sourceDebug != null)) {
- classVisitor.visitSource(sourceFile, sourceDebug);
- }
-
- // visits the module info and associated attributes
- if (module != 0) {
- readModule(classVisitor, context, module, moduleMainClass, packages);
- }
-
- // visits the outer class
- if (enclosingOwner != null) {
- classVisitor.visitOuterClass(enclosingOwner, enclosingName, enclosingDesc);
- }
-
- // visits the class annotations and type annotations
- if (anns != 0) {
- for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) {
- v = readAnnotationValues(v + 2, c, true, classVisitor.visitAnnotation(readUTF8(v, c), true));
- }
- }
- if (ianns != 0) {
- for (int i = readUnsignedShort(ianns), v = ianns + 2; i > 0; --i) {
- v = readAnnotationValues(v + 2, c, true, classVisitor.visitAnnotation(readUTF8(v, c), false));
- }
- }
- if (tanns != 0) {
- for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) {
- v = readAnnotationTarget(context, v);
- v = readAnnotationValues(
- v + 2,
- c,
- true,
- classVisitor.visitTypeAnnotation(context.typeRef, context.typePath, readUTF8(v, c), true));
- }
- }
- if (itanns != 0) {
- for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) {
- v = readAnnotationTarget(context, v);
- v = readAnnotationValues(
- v + 2,
- c,
- true,
- classVisitor.visitTypeAnnotation(context.typeRef, context.typePath, readUTF8(v, c), false));
- }
- }
-
- // visits the attributes
- while (attributes != null) {
- Attribute attr = attributes.next;
- attributes.next = null;
- classVisitor.visitAttribute(attributes);
- attributes = attr;
- }
-
- // visits the inner classes
- if (innerClasses != 0) {
- int v = innerClasses + 2;
- for (int i = readUnsignedShort(innerClasses); i > 0; --i) {
- classVisitor.visitInnerClass(
- readClass(v, c), readClass(v + 2, c), readUTF8(v + 4, c), readUnsignedShort(v + 6));
- v += 8;
- }
- }
-
- // visits the fields and methods
- u = header + 10 + 2 * interfaces.length;
- for (int i = readUnsignedShort(u - 2); i > 0; --i) {
- u = readField(classVisitor, context, u);
- }
- u += 2;
- for (int i = readUnsignedShort(u - 2); i > 0; --i) {
- u = readMethod(classVisitor, context, u);
- }
-
- // visits the end of the class
- classVisitor.visitEnd();
- }
-
- /**
- * Reads the module attribute and visit it.
- *
- * @param classVisitor the current class visitor
- * @param context information about the class being parsed.
- * @param u start offset of the module attribute in the class file.
- * @param mainClass name of the main class of a module or null.
- * @param packages start offset of the concealed package attribute.
- */
- private void readModule(
- final ClassVisitor classVisitor, final Context context, int u, final String mainClass, int packages) {
-
- char[] buffer = context.buffer;
-
- // reads module name, flags and version
- String name = readModule(u, buffer);
- int flags = readUnsignedShort(u + 2);
- String version = readUTF8(u + 4, buffer);
- u += 6;
-
- ModuleVisitor mv = classVisitor.visitModule(name, flags, version);
- if (mv == null) {
- return;
- }
-
- // module attributes (main class, packages)
- if (mainClass != null) {
- mv.visitMainClass(mainClass);
- }
-
- if (packages != 0) {
- for (int i = readUnsignedShort(packages - 2); i > 0; --i) {
- String packaze = readPackage(packages, buffer);
- mv.visitPackage(packaze);
- packages += 2;
- }
- }
-
- // reads requires
- u += 2;
- for (int i = readUnsignedShort(u - 2); i > 0; --i) {
- String module = readModule(u, buffer);
- int access = readUnsignedShort(u + 2);
- String requireVersion = readUTF8(u + 4, buffer);
- mv.visitRequire(module, access, requireVersion);
- u += 6;
- }
-
- // reads exports
- u += 2;
- for (int i = readUnsignedShort(u - 2); i > 0; --i) {
- String export = readPackage(u, buffer);
- int access = readUnsignedShort(u + 2);
- int exportToCount = readUnsignedShort(u + 4);
- u += 6;
- String[] tos = null;
- if (exportToCount != 0) {
- tos = new String[exportToCount];
- for (int j = 0; j < tos.length; ++j) {
- tos[j] = readModule(u, buffer);
- u += 2;
- }
- }
- mv.visitExport(export, access, tos);
- }
-
- // reads opens
- u += 2;
- for (int i = readUnsignedShort(u - 2); i > 0; --i) {
- String open = readPackage(u, buffer);
- int access = readUnsignedShort(u + 2);
- int openToCount = readUnsignedShort(u + 4);
- u += 6;
- String[] tos = null;
- if (openToCount != 0) {
- tos = new String[openToCount];
- for (int j = 0; j < tos.length; ++j) {
- tos[j] = readModule(u, buffer);
- u += 2;
- }
- }
- mv.visitOpen(open, access, tos);
- }
-
- // read uses
- u += 2;
- for (int i = readUnsignedShort(u - 2); i > 0; --i) {
- mv.visitUse(readClass(u, buffer));
- u += 2;
- }
-
- // read provides
- u += 2;
- for (int i = readUnsignedShort(u - 2); i > 0; --i) {
- String service = readClass(u, buffer);
- int provideWithCount = readUnsignedShort(u + 2);
- u += 4;
- String[] withs = new String[provideWithCount];
- for (int j = 0; j < withs.length; ++j) {
- withs[j] = readClass(u, buffer);
- u += 2;
- }
- mv.visitProvide(service, withs);
- }
-
- mv.visitEnd();
- }
-
- /**
- * Reads a field and makes the given visitor visit it.
- *
- * @param classVisitor the visitor that must visit the field.
- * @param context information about the class being parsed.
- * @param u the start offset of the field in the class file.
- * @return the offset of the first byte following the field in the class.
- */
- private int readField(final ClassVisitor classVisitor, final Context context, int u) {
- // reads the field declaration
- char[] c = context.buffer;
- int access = readUnsignedShort(u);
- String name = readUTF8(u + 2, c);
- String desc = readUTF8(u + 4, c);
- u += 6;
-
- // reads the field attributes
- String signature = null;
- int anns = 0;
- int ianns = 0;
- int tanns = 0;
- int itanns = 0;
- Object value = null;
- Attribute attributes = null;
-
- for (int i = readUnsignedShort(u); i > 0; --i) {
- String attrName = readUTF8(u + 2, c);
- // tests are sorted in decreasing frequency order
- // (based on frequencies observed on typical classes)
- if ("ConstantValue".equals(attrName)) {
- int item = readUnsignedShort(u + 8);
- value = item == 0 ? null : readConst(item, c);
- } else if ("Signature".equals(attrName)) {
- signature = readUTF8(u + 8, c);
- } else if ("Deprecated".equals(attrName)) {
- access |= Opcodes.ACC_DEPRECATED;
- } else if ("Synthetic".equals(attrName)) {
- access |= Opcodes.ACC_SYNTHETIC | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE;
- } else if ("RuntimeVisibleAnnotations".equals(attrName)) {
- anns = u + 8;
- } else if ("RuntimeVisibleTypeAnnotations".equals(attrName)) {
- tanns = u + 8;
- } else if ("RuntimeInvisibleAnnotations".equals(attrName)) {
- ianns = u + 8;
- } else if ("RuntimeInvisibleTypeAnnotations".equals(attrName)) {
- itanns = u + 8;
- } else {
- Attribute attr = readAttribute(context.attrs, attrName, u + 8, readInt(u + 4), c, -1, null);
- if (attr != null) {
- attr.next = attributes;
- attributes = attr;
- }
- }
- u += 6 + readInt(u + 4);
- }
- u += 2;
-
- // visits the field declaration
- FieldVisitor fv = classVisitor.visitField(access, name, desc, signature, value);
- if (fv == null) {
- return u;
- }
-
- // visits the field annotations and type annotations
- if (anns != 0) {
- for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) {
- v = readAnnotationValues(v + 2, c, true, fv.visitAnnotation(readUTF8(v, c), true));
- }
- }
- if (ianns != 0) {
- for (int i = readUnsignedShort(ianns), v = ianns + 2; i > 0; --i) {
- v = readAnnotationValues(v + 2, c, true, fv.visitAnnotation(readUTF8(v, c), false));
- }
- }
- if (tanns != 0) {
- for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) {
- v = readAnnotationTarget(context, v);
- v = readAnnotationValues(
- v + 2,
- c,
- true,
- fv.visitTypeAnnotation(context.typeRef, context.typePath, readUTF8(v, c), true));
- }
- }
- if (itanns != 0) {
- for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) {
- v = readAnnotationTarget(context, v);
- v = readAnnotationValues(
- v + 2,
- c,
- true,
- fv.visitTypeAnnotation(context.typeRef, context.typePath, readUTF8(v, c), false));
- }
- }
-
- // visits the field attributes
- while (attributes != null) {
- Attribute attr = attributes.next;
- attributes.next = null;
- fv.visitAttribute(attributes);
- attributes = attr;
- }
-
- // visits the end of the field
- fv.visitEnd();
-
- return u;
- }
-
- /**
- * Reads a method and makes the given visitor visit it.
- *
- * @param classVisitor the visitor that must visit the method.
- * @param context information about the class being parsed.
- * @param u the start offset of the method in the class file.
- * @return the offset of the first byte following the method in the class.
- */
- private int readMethod(final ClassVisitor classVisitor, final Context context, int u) {
- // reads the method declaration
- char[] c = context.buffer;
- context.access = readUnsignedShort(u);
- context.name = readUTF8(u + 2, c);
- context.desc = readUTF8(u + 4, c);
- u += 6;
-
- // reads the method attributes
- int code = 0;
- int exception = 0;
- String[] exceptions = null;
- String signature = null;
- int methodParameters = 0;
- int anns = 0;
- int ianns = 0;
- int tanns = 0;
- int itanns = 0;
- int dann = 0;
- int mpanns = 0;
- int impanns = 0;
- int firstAttribute = u;
- Attribute attributes = null;
-
- for (int i = readUnsignedShort(u); i > 0; --i) {
- String attrName = readUTF8(u + 2, c);
- // tests are sorted in decreasing frequency order
- // (based on frequencies observed on typical classes)
- if ("Code".equals(attrName)) {
- if ((context.flags & SKIP_CODE) == 0) {
- code = u + 8;
- }
- } else if ("Exceptions".equals(attrName)) {
- exceptions = new String[readUnsignedShort(u + 8)];
- exception = u + 10;
- for (int j = 0; j < exceptions.length; ++j) {
- exceptions[j] = readClass(exception, c);
- exception += 2;
- }
- } else if ("Signature".equals(attrName)) {
- signature = readUTF8(u + 8, c);
- } else if ("Deprecated".equals(attrName)) {
- context.access |= Opcodes.ACC_DEPRECATED;
- } else if ("RuntimeVisibleAnnotations".equals(attrName)) {
- anns = u + 8;
- } else if ("RuntimeVisibleTypeAnnotations".equals(attrName)) {
- tanns = u + 8;
- } else if ("AnnotationDefault".equals(attrName)) {
- dann = u + 8;
- } else if ("Synthetic".equals(attrName)) {
- context.access |= Opcodes.ACC_SYNTHETIC | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE;
- } else if ("RuntimeInvisibleAnnotations".equals(attrName)) {
- ianns = u + 8;
- } else if ("RuntimeInvisibleTypeAnnotations".equals(attrName)) {
- itanns = u + 8;
- } else if ("RuntimeVisibleParameterAnnotations".equals(attrName)) {
- mpanns = u + 8;
- } else if ("RuntimeInvisibleParameterAnnotations".equals(attrName)) {
- impanns = u + 8;
- } else if ("MethodParameters".equals(attrName)) {
- methodParameters = u + 8;
- } else {
- Attribute attr = readAttribute(context.attrs, attrName, u + 8, readInt(u + 4), c, -1, null);
- if (attr != null) {
- attr.next = attributes;
- attributes = attr;
- }
- }
- u += 6 + readInt(u + 4);
- }
- u += 2;
-
- // visits the method declaration
- MethodVisitor mv = classVisitor.visitMethod(context.access, context.name, context.desc, signature, exceptions);
- if (mv == null) {
- return u;
- }
-
- /*
- * if the returned MethodVisitor is in fact a MethodWriter, it means
- * there is no method adapter between the reader and the writer. If, in
- * addition, the writer's constant pool was copied from this reader
- * (mw.cw.cr == this), and the signature and exceptions of the method
- * have not been changed, then it is possible to skip all visit events
- * and just copy the original code of the method to the writer (the
- * access, name and descriptor can have been changed, this is not
- * important since they are not copied as is from the reader).
- */
- if (mv instanceof MethodWriter) {
- MethodWriter mw = (MethodWriter) mv;
- if (mw.cw.cr == this && signature == mw.signature) {
- boolean sameExceptions = false;
- if (exceptions == null) {
- sameExceptions = mw.exceptionCount == 0;
- } else if (exceptions.length == mw.exceptionCount) {
- sameExceptions = true;
- for (int j = exceptions.length - 1; j >= 0; --j) {
- exception -= 2;
- if (mw.exceptions[j] != readUnsignedShort(exception)) {
- sameExceptions = false;
- break;
- }
- }
- }
- if (sameExceptions) {
- /*
- * we do not copy directly the code into MethodWriter to
- * save a byte array copy operation. The real copy will be
- * done in ClassWriter.toByteArray().
- */
- mw.classReaderOffset = firstAttribute;
- mw.classReaderLength = u - firstAttribute;
- return u;
- }
- }
- }
-
- // visit the method parameters
- if (methodParameters != 0) {
- for (int i = b[methodParameters] & 0xFF, v = methodParameters + 1; i > 0; --i, v = v + 4) {
- mv.visitParameter(readUTF8(v, c), readUnsignedShort(v + 2));
- }
- }
-
- // visits the method annotations
- if (dann != 0) {
- AnnotationVisitor dv = mv.visitAnnotationDefault();
- readAnnotationValue(dann, c, null, dv);
- if (dv != null) {
- dv.visitEnd();
- }
- }
- if (anns != 0) {
- for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) {
- v = readAnnotationValues(v + 2, c, true, mv.visitAnnotation(readUTF8(v, c), true));
- }
- }
- if (ianns != 0) {
- for (int i = readUnsignedShort(ianns), v = ianns + 2; i > 0; --i) {
- v = readAnnotationValues(v + 2, c, true, mv.visitAnnotation(readUTF8(v, c), false));
- }
- }
- if (tanns != 0) {
- for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) {
- v = readAnnotationTarget(context, v);
- v = readAnnotationValues(
- v + 2,
- c,
- true,
- mv.visitTypeAnnotation(context.typeRef, context.typePath, readUTF8(v, c), true));
- }
- }
- if (itanns != 0) {
- for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) {
- v = readAnnotationTarget(context, v);
- v = readAnnotationValues(
- v + 2,
- c,
- true,
- mv.visitTypeAnnotation(context.typeRef, context.typePath, readUTF8(v, c), false));
- }
- }
- if (mpanns != 0) {
- readParameterAnnotations(mv, context, mpanns, true);
- }
- if (impanns != 0) {
- readParameterAnnotations(mv, context, impanns, false);
- }
-
- // visits the method attributes
- while (attributes != null) {
- Attribute attr = attributes.next;
- attributes.next = null;
- mv.visitAttribute(attributes);
- attributes = attr;
- }
-
- // visits the method code
- if (code != 0) {
- mv.visitCode();
- readCode(mv, context, code);
- }
-
- // visits the end of the method
- mv.visitEnd();
-
- return u;
- }
-
- /**
- * Reads the bytecode of a method and makes the given visitor visit it.
- *
- * @param mv the visitor that must visit the method's code.
- * @param context information about the class being parsed.
- * @param u the start offset of the code attribute in the class file.
- */
- private void readCode(final MethodVisitor mv, final Context context, int u) {
- // reads the header
- byte[] b = this.b;
- char[] c = context.buffer;
- int maxStack = readUnsignedShort(u);
- int maxLocals = readUnsignedShort(u + 2);
- int codeLength = readInt(u + 4);
- u += 8;
-
- // reads the bytecode to find the labels
- int codeStart = u;
- int codeEnd = u + codeLength;
- Label[] labels = context.labels = new Label[codeLength + 2];
- createLabel(codeLength + 1, labels);
- while (u < codeEnd) {
- int offset = u - codeStart;
- int opcode = b[u] & 0xFF;
- switch (ClassWriter.TYPE[opcode]) {
- case ClassWriter.NOARG_INSN:
- case ClassWriter.IMPLVAR_INSN:
- u += 1;
- break;
- case ClassWriter.LABEL_INSN:
- createLabel(offset + readShort(u + 1), labels);
- u += 3;
- break;
- case ClassWriter.ASM_LABEL_INSN:
- createLabel(offset + readUnsignedShort(u + 1), labels);
- u += 3;
- break;
- case ClassWriter.LABELW_INSN:
- case ClassWriter.ASM_LABELW_INSN:
- createLabel(offset + readInt(u + 1), labels);
- u += 5;
- break;
- case ClassWriter.WIDE_INSN:
- opcode = b[u + 1] & 0xFF;
- if (opcode == Opcodes.IINC) {
- u += 6;
- } else {
- u += 4;
- }
- break;
- case ClassWriter.TABL_INSN:
- // skips 0 to 3 padding bytes
- u = u + 4 - (offset & 3);
- // reads instruction
- createLabel(offset + readInt(u), labels);
- for (int i = readInt(u + 8) - readInt(u + 4) + 1; i > 0; --i) {
- createLabel(offset + readInt(u + 12), labels);
- u += 4;
- }
- u += 12;
- break;
- case ClassWriter.LOOK_INSN:
- // skips 0 to 3 padding bytes
- u = u + 4 - (offset & 3);
- // reads instruction
- createLabel(offset + readInt(u), labels);
- for (int i = readInt(u + 4); i > 0; --i) {
- createLabel(offset + readInt(u + 12), labels);
- u += 8;
- }
- u += 8;
- break;
- case ClassWriter.VAR_INSN:
- case ClassWriter.SBYTE_INSN:
- case ClassWriter.LDC_INSN:
- u += 2;
- break;
- case ClassWriter.SHORT_INSN:
- case ClassWriter.LDCW_INSN:
- case ClassWriter.FIELDORMETH_INSN:
- case ClassWriter.TYPE_INSN:
- case ClassWriter.IINC_INSN:
- u += 3;
- break;
- case ClassWriter.ITFMETH_INSN:
- case ClassWriter.INDYMETH_INSN:
- u += 5;
- break;
- // case MANA_INSN:
- default:
- u += 4;
- break;
- }
- }
-
- // reads the try catch entries to find the labels, and also visits them
- for (int i = readUnsignedShort(u); i > 0; --i) {
- Label start = createLabel(readUnsignedShort(u + 2), labels);
- Label end = createLabel(readUnsignedShort(u + 4), labels);
- Label handler = createLabel(readUnsignedShort(u + 6), labels);
- String type = readUTF8(items[readUnsignedShort(u + 8)], c);
- mv.visitTryCatchBlock(start, end, handler, type);
- u += 8;
- }
- u += 2;
-
- // reads the code attributes
- int[] tanns = null; // start index of each visible type annotation
- int[] itanns = null; // start index of each invisible type annotation
- int tann = 0; // current index in tanns array
- int itann = 0; // current index in itanns array
- int ntoff = -1; // next visible type annotation code offset
- int nitoff = -1; // next invisible type annotation code offset
- int varTable = 0;
- int varTypeTable = 0;
- boolean zip = true;
- boolean unzip = (context.flags & EXPAND_FRAMES) != 0;
- int stackMap = 0;
- int stackMapSize = 0;
- int frameCount = 0;
- Context frame = null;
- Attribute attributes = null;
-
- for (int i = readUnsignedShort(u); i > 0; --i) {
- String attrName = readUTF8(u + 2, c);
- if ("LocalVariableTable".equals(attrName)) {
- if ((context.flags & SKIP_DEBUG) == 0) {
- varTable = u + 8;
- for (int j = readUnsignedShort(u + 8), v = u; j > 0; --j) {
- int label = readUnsignedShort(v + 10);
- createDebugLabel(label, labels);
- label += readUnsignedShort(v + 12);
- createDebugLabel(label, labels);
- v += 10;
- }
- }
- } else if ("LocalVariableTypeTable".equals(attrName)) {
- varTypeTable = u + 8;
- } else if ("LineNumberTable".equals(attrName)) {
- if ((context.flags & SKIP_DEBUG) == 0) {
- for (int j = readUnsignedShort(u + 8), v = u; j > 0; --j) {
- int label = readUnsignedShort(v + 10);
- createDebugLabel(label, labels);
- Label l = labels[label];
- while (l.line > 0) {
- if (l.next == null) {
- l.next = new Label();
- }
- l = l.next;
- }
- l.line = readUnsignedShort(v + 12);
- v += 4;
- }
- }
- } else if ("RuntimeVisibleTypeAnnotations".equals(attrName)) {
- tanns = readTypeAnnotations(mv, context, u + 8, true);
- ntoff = tanns.length == 0 || readByte(tanns[0]) < 0x43 ? -1 : readUnsignedShort(tanns[0] + 1);
- } else if ("RuntimeInvisibleTypeAnnotations".equals(attrName)) {
- itanns = readTypeAnnotations(mv, context, u + 8, false);
- nitoff = itanns.length == 0 || readByte(itanns[0]) < 0x43 ? -1 : readUnsignedShort(itanns[0] + 1);
- } else if ("StackMapTable".equals(attrName)) {
- if ((context.flags & SKIP_FRAMES) == 0) {
- stackMap = u + 10;
- stackMapSize = readInt(u + 4);
- frameCount = readUnsignedShort(u + 8);
- }
- /*
- * here we do not extract the labels corresponding to the
- * attribute content. This would require a full parsing of the
- * attribute, which would need to be repeated in the second
- * phase (see below). Instead the content of the attribute is
- * read one frame at a time (i.e. after a frame has been
- * visited, the next frame is read), and the labels it contains
- * are also extracted one frame at a time. Thanks to the
- * ordering of frames, having only a "one frame lookahead" is
- * not a problem, i.e. it is not possible to see an offset
- * smaller than the offset of the current insn and for which no
- * Label exist.
- */
- /*
- * This is not true for UNINITIALIZED type offsets. We solve
- * this by parsing the stack map table without a full decoding
- * (see below).
- */
- } else if ("StackMap".equals(attrName)) {
- if ((context.flags & SKIP_FRAMES) == 0) {
- zip = false;
- stackMap = u + 10;
- stackMapSize = readInt(u + 4);
- frameCount = readUnsignedShort(u + 8);
- }
- /*
- * IMPORTANT! here we assume that the frames are ordered, as in
- * the StackMapTable attribute, although this is not guaranteed
- * by the attribute format.
- */
- } else {
- for (int j = 0; j < context.attrs.length; ++j) {
- if (context.attrs[j].type.equals(attrName)) {
- Attribute attr = context.attrs[j].read(this, u + 8, readInt(u + 4), c, codeStart - 8, labels);
- if (attr != null) {
- attr.next = attributes;
- attributes = attr;
- }
- }
- }
- }
- u += 6 + readInt(u + 4);
- }
- u += 2;
-
- // generates the first (implicit) stack map frame
- if (stackMap != 0) {
- /*
- * for the first explicit frame the offset is not offset_delta + 1
- * but only offset_delta; setting the implicit frame offset to -1
- * allow the use of the "offset_delta + 1" rule in all cases
- */
- frame = context;
- frame.offset = -1;
- frame.mode = 0;
- frame.localCount = 0;
- frame.localDiff = 0;
- frame.stackCount = 0;
- frame.local = new Object[maxLocals];
- frame.stack = new Object[maxStack];
- if (unzip) {
- getImplicitFrame(context);
- }
- /*
- * Finds labels for UNINITIALIZED frame types. Instead of decoding
- * each element of the stack map table, we look for 3 consecutive
- * bytes that "look like" an UNINITIALIZED type (tag 8, offset
- * within code bounds, NEW instruction at this offset). We may find
- * false positives (i.e. not real UNINITIALIZED types), but this
- * should be rare, and the only consequence will be the creation of
- * an unneeded label. This is better than creating a label for each
- * NEW instruction, and faster than fully decoding the whole stack
- * map table.
- */
- for (int i = stackMap; i < stackMap + stackMapSize - 2; ++i) {
- if (b[i] == 8) { // UNINITIALIZED FRAME TYPE
- int v = readUnsignedShort(i + 1);
- if (v >= 0 && v < codeLength) {
- if ((b[codeStart + v] & 0xFF) == Opcodes.NEW) {
- createLabel(v, labels);
- }
- }
- }
- }
- }
- if ((context.flags & EXPAND_ASM_INSNS) != 0 && (context.flags & EXPAND_FRAMES) != 0) {
- // Expanding the ASM pseudo instructions can introduce F_INSERT
- // frames, even if the method does not currently have any frame.
- // Also these inserted frames must be computed by simulating the
- // effect of the bytecode instructions one by one, starting from the
- // first one and the last existing frame (or the implicit first
- // one). Finally, due to the way MethodWriter computes this (with
- // the compute = INSERTED_FRAMES option), MethodWriter needs to know
- // maxLocals before the first instruction is visited. For all these
- // reasons we always visit the implicit first frame in this case
- // (passing only maxLocals - the rest can be and is computed in
- // MethodWriter).
- mv.visitFrame(Opcodes.F_NEW, maxLocals, null, 0, null);
- }
-
- // visits the instructions
- int opcodeDelta = (context.flags & EXPAND_ASM_INSNS) == 0 ? -33 : 0;
- boolean insertFrame = false;
- u = codeStart;
- while (u < codeEnd) {
- int offset = u - codeStart;
-
- // visits the label and line number for this offset, if any
- Label l = labels[offset];
- if (l != null) {
- Label next = l.next;
- l.next = null;
- mv.visitLabel(l);
- if ((context.flags & SKIP_DEBUG) == 0 && l.line > 0) {
- mv.visitLineNumber(l.line, l);
- while (next != null) {
- mv.visitLineNumber(next.line, l);
- next = next.next;
- }
- }
- }
-
- // visits the frame for this offset, if any
- while (frame != null && (frame.offset == offset || frame.offset == -1)) {
- // if there is a frame for this offset, makes the visitor visit
- // it, and reads the next frame if there is one.
- if (frame.offset != -1) {
- if (!zip || unzip) {
- mv.visitFrame(Opcodes.F_NEW, frame.localCount, frame.local, frame.stackCount, frame.stack);
- } else {
- mv.visitFrame(frame.mode, frame.localDiff, frame.local, frame.stackCount, frame.stack);
- }
- // if there is already a frame for this offset, there is no
- // need to insert a new one.
- insertFrame = false;
- }
- if (frameCount > 0) {
- stackMap = readFrame(stackMap, zip, unzip, frame);
- --frameCount;
- } else {
- frame = null;
- }
- }
- // inserts a frame for this offset, if requested by setting
- // insertFrame to true during the previous iteration. The actual
- // frame content will be computed in MethodWriter.
- if (insertFrame) {
- mv.visitFrame(ClassWriter.F_INSERT, 0, null, 0, null);
- insertFrame = false;
- }
-
- // visits the instruction at this offset
- int opcode = b[u] & 0xFF;
- switch (ClassWriter.TYPE[opcode]) {
- case ClassWriter.NOARG_INSN:
- mv.visitInsn(opcode);
- u += 1;
- break;
- case ClassWriter.IMPLVAR_INSN:
- if (opcode > Opcodes.ISTORE) {
- opcode -= 59; // ISTORE_0
- mv.visitVarInsn(Opcodes.ISTORE + (opcode >> 2), opcode & 0x3);
- } else {
- opcode -= 26; // ILOAD_0
- mv.visitVarInsn(Opcodes.ILOAD + (opcode >> 2), opcode & 0x3);
- }
- u += 1;
- break;
- case ClassWriter.LABEL_INSN:
- mv.visitJumpInsn(opcode, labels[offset + readShort(u + 1)]);
- u += 3;
- break;
- case ClassWriter.LABELW_INSN:
- mv.visitJumpInsn(opcode + opcodeDelta, labels[offset + readInt(u + 1)]);
- u += 5;
- break;
- case ClassWriter.ASM_LABEL_INSN: {
- // changes temporary opcodes 202 to 217 (inclusive), 218
- // and 219 to IFEQ ... JSR (inclusive), IFNULL and
- // IFNONNULL
- opcode = opcode < 218 ? opcode - 49 : opcode - 20;
- Label target = labels[offset + readUnsignedShort(u + 1)];
- // replaces GOTO with GOTO_W, JSR with JSR_W and IFxxx
- // CODE attribute won't be visited. This can be used,
+ * for example, to retrieve annotations for methods and method parameters.
+ */
+ public static final int SKIP_CODE = 1;
+
+ /**
+ * Flag to skip the debug information in the class. If this flag is set the debug information of the class is not
+ * visited, i.e. the {@link MethodVisitor#visitLocalVariable visitLocalVariable} and
+ * {@link MethodVisitor#visitLineNumber visitLineNumber} methods will not be called.
+ */
+ public static final int SKIP_DEBUG = 2;
+
+ /**
+ * Flag to skip the stack map frames in the class. If this flag is set the stack map frames of the class is not
+ * visited, i.e. the {@link MethodVisitor#visitFrame visitFrame} method will not be called. This flag is useful when
+ * the {@link ClassWriter#COMPUTE_FRAMES} option is used: it avoids visiting frames that will be ignored and
+ * recomputed from scratch in the class writer.
+ */
+ public static final int SKIP_FRAMES = 4;
+
+ /**
+ * Flag to expand the stack map frames. By default stack map frames are visited in their original format (i.e.
+ * "expanded" for classes whose version is less than V1_6, and "compressed" for the other classes). If this flag is
+ * set, stack map frames are always visited in expanded format (this option adds a decompression/recompression step
+ * in ClassReader and ClassWriter which degrades performances quite a lot).
+ */
+ public static final int EXPAND_FRAMES = 8;
+
+ /**
+ * Flag to expand the ASM pseudo instructions into an equivalent sequence of standard bytecode instructions. When
+ * resolving a forward jump it may happen that the signed 2 bytes offset reserved for it is not sufficient to store
+ * the bytecode offset. In this case the jump instruction is replaced with a temporary ASM pseudo instruction using
+ * an unsigned 2 bytes offset (see Label#resolve). This internal flag is used to re-read classes containing such
+ * instructions, in order to replace them with standard instructions. In addition, when this flag is used, GOTO_W
+ * and JSR_W are not converted into GOTO and JSR, to make sure that infinite loops where a GOTO_W is replaced
+ * with a GOTO in ClassReader and converted back to a GOTO_W in ClassWriter cannot occur.
+ */
+ static final int EXPAND_ASM_INSNS = 256;
+
+ /**
+ * The class to be parsed. The content of this array must not be modified. This field is intended for
+ * {@link Attribute} sub classes, and is normally not needed by class generators or adapters.
+ */
+ public final byte[] b;
+
+ /**
+ * The start index of each constant pool item in {@link #b b}, plus one. The one byte offset skips the constant pool
+ * item tag that indicates its type.
+ */
+ private final int[] items;
+
+ /**
+ * The String objects corresponding to the CONSTANT_Utf8 items. This cache avoids multiple parsing of a given
+ * CONSTANT_Utf8 constant pool item, which GREATLY improves performances (by a factor 2 to 3). This caching strategy
+ * could be extended to all constant pool items, but its benefit would not be so great for these items (because they
+ * are much less expensive to parse than CONSTANT_Utf8 items).
+ */
+ private final String[] strings;
+
+ /** Maximum length of the strings contained in the constant pool of the class. */
+ private final int maxStringLength;
+
+ /** Start index of the class header information (access, name...) in {@link #b b}. */
+ public final int header;
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+
+ /**
+ * Constructs a new {@link ClassReader} object.
+ *
+ * @param b the bytecode of the class to be read.
+ */
+ public ClassReader(final byte[] b) {
+ this(b, 0, b.length);
+ }
+
+ /**
+ * Constructs a new {@link ClassReader} object.
+ *
+ * @param b the bytecode of the class to be read.
+ * @param off the start offset of the class data.
+ * @param len the length of the class data.
+ */
+ public ClassReader(final byte[] b, final int off, final int len) {
+ this.b = b;
+ // checks the class version
+ // if (readShort(off + 6) > Opcodes.V11) {
+ // throw new IllegalArgumentException();
+ // }
+ // parses the constant pool
+ items = new int[readUnsignedShort(off + 8)];
+ int n = items.length;
+ strings = new String[n];
+ int max = 0;
+ int index = off + 10;
+ for (int i = 1; i < n; ++i) {
+ items[i] = index + 1;
+ int size;
+ switch (b[index]) {
+ case ClassWriter.FIELD:
+ case ClassWriter.METH:
+ case ClassWriter.IMETH:
+ case ClassWriter.INT:
+ case ClassWriter.FLOAT:
+ case ClassWriter.NAME_TYPE:
+ case ClassWriter.INDY:
+ // @@@ ClassWriter.CONDY
+ // Enables MethodHandles.lookup().defineClass to function correctly
+ // when it reads the class name
+ case 17:
+ size = 5;
+ break;
+ case ClassWriter.LONG:
+ case ClassWriter.DOUBLE:
+ size = 9;
+ ++i;
+ break;
+ case ClassWriter.UTF8:
+ size = 3 + readUnsignedShort(index + 1);
+ if (size > max) {
+ max = size;
+ }
+ break;
+ case ClassWriter.HANDLE:
+ size = 4;
+ break;
+ // case ClassWriter.CLASS:
+ // case ClassWriter.STR:
+ // case ClassWriter.MTYPE
+ // case ClassWriter.PACKAGE:
+ // case ClassWriter.MODULE:
+ default:
+ size = 3;
+ break;
+ }
+ index += size;
+ }
+ maxStringLength = max;
+ // the class header information starts just after the constant pool
+ header = index;
+ }
+
+ /**
+ * Returns the class's access flags (see {@link Opcodes}). This value may not reflect Deprecated and Synthetic flags
+ * when bytecode is before 1.5 and those flags are represented by attributes.
+ *
+ * @return the class access flags
+ * @see ClassVisitor#visit(int, int, String, String, String, String[])
+ */
+ public int getAccess() {
+ return readUnsignedShort(header);
+ }
+
+ /**
+ * Returns the internal name of the class (see {@link Type#getInternalName() getInternalName}).
+ *
+ * @return the internal class name
+ * @see ClassVisitor#visit(int, int, String, String, String, String[])
+ */
+ public String getClassName() {
+ return readClass(header + 2, new char[maxStringLength]);
+ }
+
+ /**
+ * Returns the internal of name of the super class (see {@link Type#getInternalName() getInternalName}). For
+ * interfaces, the super class is {@link Object}.
+ *
+ * @return the internal name of super class, or <tt>null</tt> for {@link Object} class.
+ * @see ClassVisitor#visit(int, int, String, String, String, String[])
+ */
+ public String getSuperName() {
+ return readClass(header + 4, new char[maxStringLength]);
+ }
+
+ /**
+ * Returns the internal names of the class's interfaces (see {@link Type#getInternalName() getInternalName}).
+ *
+ * @return the array of internal names for all implemented interfaces or <tt>null</tt>.
+ * @see ClassVisitor#visit(int, int, String, String, String, String[])
+ */
+ public String[] getInterfaces() {
+ int index = header + 6;
+ int n = readUnsignedShort(index);
+ String[] interfaces = new String[n];
+ if (n > 0) {
+ char[] buf = new char[maxStringLength];
+ for (int i = 0; i < n; ++i) {
+ index += 2;
+ interfaces[i] = readClass(index, buf);
+ }
+ }
+ return interfaces;
+ }
+
+ /**
+ * Copies the constant pool data into the given {@link ClassWriter}. Should be called before the
+ * {@link #accept(ClassVisitor,int)} method.
+ *
+ * @param classWriter the {@link ClassWriter} to copy constant pool into.
+ */
+ void copyPool(final ClassWriter classWriter) {
+ char[] buf = new char[maxStringLength];
+ int ll = items.length;
+ Item[] items2 = new Item[ll];
+ for (int i = 1; i < ll; i++) {
+ int index = items[i];
+ int tag = b[index - 1];
+ Item item = new Item(i);
+ int nameType;
+ switch (tag) {
+ case ClassWriter.FIELD:
+ case ClassWriter.METH:
+ case ClassWriter.IMETH:
+ nameType = items[readUnsignedShort(index + 2)];
+ item.set(tag, readClass(index, buf), readUTF8(nameType, buf), readUTF8(nameType + 2, buf));
+ break;
+ case ClassWriter.INT:
+ item.set(readInt(index));
+ break;
+ case ClassWriter.FLOAT:
+ item.set(Float.intBitsToFloat(readInt(index)));
+ break;
+ case ClassWriter.NAME_TYPE:
+ item.set(tag, readUTF8(index, buf), readUTF8(index + 2, buf), null);
+ break;
+ case ClassWriter.LONG:
+ item.set(readLong(index));
+ ++i;
+ break;
+ case ClassWriter.DOUBLE:
+ item.set(Double.longBitsToDouble(readLong(index)));
+ ++i;
+ break;
+ case ClassWriter.UTF8: {
+ String s = strings[i];
+ if (s == null) {
+ index = items[i];
+ s = strings[i] = readUTF(index + 2, readUnsignedShort(index), buf);
+ }
+ item.set(tag, s, null, null);
+ break;
+ }
+ case ClassWriter.HANDLE: {
+ int fieldOrMethodRef = items[readUnsignedShort(index + 1)];
+ nameType = items[readUnsignedShort(fieldOrMethodRef + 2)];
+ item.set(
+ ClassWriter.HANDLE_BASE + readByte(index),
+ readClass(fieldOrMethodRef, buf),
+ readUTF8(nameType, buf),
+ readUTF8(nameType + 2, buf));
+ break;
+ }
+ case ClassWriter.INDY:
+ if (classWriter.bootstrapMethods == null) {
+ copyBootstrapMethods(classWriter, items2, buf);
+ }
+ nameType = items[readUnsignedShort(index + 2)];
+ item.set(readUTF8(nameType, buf), readUTF8(nameType + 2, buf), readUnsignedShort(index));
+ break;
+ // case ClassWriter.STR:
+ // case ClassWriter.CLASS:
+ // case ClassWriter.MTYPE:
+ // case ClassWriter.MODULE:
+ // case ClassWriter.PACKAGE:
+ default:
+ item.set(tag, readUTF8(index, buf), null, null);
+ break;
+ }
+
+ int index2 = item.hashCode % items2.length;
+ item.next = items2[index2];
+ items2[index2] = item;
+ }
+
+ int off = items[1] - 1;
+ classWriter.pool.putByteArray(b, off, header - off);
+ classWriter.items = items2;
+ classWriter.threshold = (int) (0.75d * ll);
+ classWriter.index = ll;
+ }
+
+ /**
+ * Copies the bootstrap method data into the given {@link ClassWriter}. Should be called before the
+ * {@link #accept(ClassVisitor,int)} method.
+ *
+ * @param classWriter the {@link ClassWriter} to copy bootstrap methods into.
+ */
+ private void copyBootstrapMethods(final ClassWriter classWriter, final Item[] items, final char[] c) {
+ // finds the "BootstrapMethods" attribute
+ int u = getAttributes();
+ boolean found = false;
+ for (int i = readUnsignedShort(u); i > 0; --i) {
+ String attrName = readUTF8(u + 2, c);
+ if ("BootstrapMethods".equals(attrName)) {
+ found = true;
+ break;
+ }
+ u += 6 + readInt(u + 4);
+ }
+ if (!found) {
+ return;
+ }
+ // copies the bootstrap methods in the class writer
+ int boostrapMethodCount = readUnsignedShort(u + 8);
+ for (int j = 0, v = u + 10; j < boostrapMethodCount; j++) {
+ int position = v - u - 10;
+ int hashCode = readConst(readUnsignedShort(v), c).hashCode();
+ for (int k = readUnsignedShort(v + 2); k > 0; --k) {
+ hashCode ^= readConst(readUnsignedShort(v + 4), c).hashCode();
+ v += 2;
+ }
+ v += 4;
+ Item item = new Item(j);
+ item.set(position, hashCode & 0x7FFFFFFF);
+ int index = item.hashCode % items.length;
+ item.next = items[index];
+ items[index] = item;
+ }
+ int attrSize = readInt(u + 4);
+ ByteVector bootstrapMethods = new ByteVector(attrSize + 62);
+ bootstrapMethods.putByteArray(b, u + 10, attrSize - 2);
+ classWriter.bootstrapMethodsCount = boostrapMethodCount;
+ classWriter.bootstrapMethods = bootstrapMethods;
+ }
+
+ /**
+ * Constructs a new {@link ClassReader} object.
+ *
+ * @param is an input stream from which to read the class.
+ * @throws IOException if a problem occurs during reading.
+ */
+ public ClassReader(final InputStream is) throws IOException {
+ this(readClass(is, false));
+ }
+
+ /**
+ * Constructs a new {@link ClassReader} object.
+ *
+ * @param name the binary qualified name of the class to be read.
+ * @throws IOException if an exception occurs during reading.
+ */
+ public ClassReader(final String name) throws IOException {
+ this(readClass(ClassLoader.getSystemResourceAsStream(name.replace('.', '/') + ".class"), true));
+ }
+
+ /**
+ * Reads the bytecode of a class.
+ *
+ * @param is an input stream from which to read the class.
+ * @param close true to close the input stream after reading.
+ * @return the bytecode read from the given input stream.
+ * @throws IOException if a problem occurs during reading.
+ */
+ private static byte[] readClass(final InputStream is, boolean close) throws IOException {
+ if (is == null) {
+ throw new IOException("Class not found");
+ }
+ try {
+ byte[] b = new byte[is.available()];
+ int len = 0;
+ while (true) {
+ int n = is.read(b, len, b.length - len);
+ if (n == -1) {
+ if (len < b.length) {
+ byte[] c = new byte[len];
+ System.arraycopy(b, 0, c, 0, len);
+ b = c;
+ }
+ return b;
+ }
+ len += n;
+ if (len == b.length) {
+ int last = is.read();
+ if (last < 0) {
+ return b;
+ }
+ byte[] c = new byte[b.length + 1000];
+ System.arraycopy(b, 0, c, 0, len);
+ c[len++] = (byte) last;
+ b = c;
+ }
+ }
+ } finally {
+ if (close) {
+ is.close();
+ }
+ }
+ }
+
+ // ------------------------------------------------------------------------
+ // Public methods
+ // ------------------------------------------------------------------------
+
+ /**
+ * Makes the given visitor visit the Java class of this {@link ClassReader} . This class is the one specified in the
+ * constructor (see {@link #ClassReader(byte[]) ClassReader}).
+ *
+ * @param classVisitor the visitor that must visit this class.
+ * @param flags option flags that can be used to modify the default behavior of this class. See {@link #SKIP_DEBUG},
+ * {@link #EXPAND_FRAMES} , {@link #SKIP_FRAMES}, {@link #SKIP_CODE}.
+ */
+ public void accept(final ClassVisitor classVisitor, final int flags) {
+ accept(classVisitor, Attribute.DEFAULT_ATTRIBUTE_PROTOS, flags);
+ }
+
+ /**
+ * Makes the given visitor visit the Java class of this {@link ClassReader}. This class is the one specified in the
+ * constructor (see {@link #ClassReader(byte[]) ClassReader}).
+ *
+ * @param classVisitor the visitor that must visit this class.
+ * @param attrs prototypes of the attributes that must be parsed during the visit of the class. Any attribute whose
+ * type is not equal to the type of one the prototypes will not be parsed: its byte array value will be passed
+ * unchanged to the ClassWriter. This may corrupt it if this value contains references to the constant pool,
+ * or has syntactic or semantic links with a class element that has been transformed by a class adapter between
+ * the reader and the writer.
+ * @param flags option flags that can be used to modify the default behavior of this class. See {@link #SKIP_DEBUG},
+ * {@link #EXPAND_FRAMES} , {@link #SKIP_FRAMES}, {@link #SKIP_CODE}.
+ */
+ public void accept(final ClassVisitor classVisitor, final Attribute[] attrs, final int flags) {
+ int u = header; // current offset in the class file
+ char[] c = new char[maxStringLength]; // buffer used to read strings
+
+ Context context = new Context();
+ context.attrs = attrs;
+ context.flags = flags;
+ context.buffer = c;
+
+ // reads the class declaration
+ int access = readUnsignedShort(u);
+ String name = readClass(u + 2, c);
+ String superClass = readClass(u + 4, c);
+ String[] interfaces = new String[readUnsignedShort(u + 6)];
+ u += 8;
+ for (int i = 0; i < interfaces.length; ++i) {
+ interfaces[i] = readClass(u, c);
+ u += 2;
+ }
+
+ // reads the class attributes
+ String signature = null;
+ String sourceFile = null;
+ String sourceDebug = null;
+ String enclosingOwner = null;
+ String enclosingName = null;
+ String enclosingDesc = null;
+ String moduleMainClass = null;
+ int anns = 0;
+ int ianns = 0;
+ int tanns = 0;
+ int itanns = 0;
+ int innerClasses = 0;
+ int module = 0;
+ int packages = 0;
+ Attribute attributes = null;
+
+ u = getAttributes();
+ for (int i = readUnsignedShort(u); i > 0; --i) {
+ String attrName = readUTF8(u + 2, c);
+ // tests are sorted in decreasing frequency order
+ // (based on frequencies observed on typical classes)
+ if ("SourceFile".equals(attrName)) {
+ sourceFile = readUTF8(u + 8, c);
+ } else if ("InnerClasses".equals(attrName)) {
+ innerClasses = u + 8;
+ } else if ("EnclosingMethod".equals(attrName)) {
+ enclosingOwner = readClass(u + 8, c);
+ int item = readUnsignedShort(u + 10);
+ if (item != 0) {
+ enclosingName = readUTF8(items[item], c);
+ enclosingDesc = readUTF8(items[item] + 2, c);
+ }
+ } else if ("Signature".equals(attrName)) {
+ signature = readUTF8(u + 8, c);
+ } else if ("RuntimeVisibleAnnotations".equals(attrName)) {
+ anns = u + 8;
+ } else if ("RuntimeVisibleTypeAnnotations".equals(attrName)) {
+ tanns = u + 8;
+ } else if ("Deprecated".equals(attrName)) {
+ access |= Opcodes.ACC_DEPRECATED;
+ } else if ("Synthetic".equals(attrName)) {
+ access |= Opcodes.ACC_SYNTHETIC | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE;
+ } else if ("SourceDebugExtension".equals(attrName)) {
+ int len = readInt(u + 4);
+ sourceDebug = readUTF(u + 8, len, new char[len]);
+ } else if ("RuntimeInvisibleAnnotations".equals(attrName)) {
+ ianns = u + 8;
+ } else if ("RuntimeInvisibleTypeAnnotations".equals(attrName)) {
+ itanns = u + 8;
+ } else if ("Module".equals(attrName)) {
+ module = u + 8;
+ } else if ("ModuleMainClass".equals(attrName)) {
+ moduleMainClass = readClass(u + 8, c);
+ } else if ("ModulePackages".equals(attrName)) {
+ packages = u + 10;
+ } else if ("BootstrapMethods".equals(attrName)) {
+ int[] bootstrapMethods = new int[readUnsignedShort(u + 8)];
+ for (int j = 0, v = u + 10; j < bootstrapMethods.length; j++) {
+ bootstrapMethods[j] = v;
+ v += 2 + readUnsignedShort(v + 2) << 1;
+ }
+ context.bootstrapMethods = bootstrapMethods;
+ } else {
+ Attribute attr = readAttribute(attrs, attrName, u + 8, readInt(u + 4), c, -1, null);
+ if (attr != null) {
+ attr.next = attributes;
+ attributes = attr;
+ }
+ }
+ u += 6 + readInt(u + 4);
+ }
+
+ // visits the class declaration
+ classVisitor.visit(readInt(items[1] - 7), access, name, signature, superClass, interfaces);
+
+ // visits the source and debug info
+ if ((flags & SKIP_DEBUG) == 0 && (sourceFile != null || sourceDebug != null)) {
+ classVisitor.visitSource(sourceFile, sourceDebug);
+ }
+
+ // visits the module info and associated attributes
+ if (module != 0) {
+ readModule(classVisitor, context, module, moduleMainClass, packages);
+ }
+
+ // visits the outer class
+ if (enclosingOwner != null) {
+ classVisitor.visitOuterClass(enclosingOwner, enclosingName, enclosingDesc);
+ }
+
+ // visits the class annotations and type annotations
+ if (anns != 0) {
+ for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) {
+ v = readAnnotationValues(v + 2, c, true, classVisitor.visitAnnotation(readUTF8(v, c), true));
+ }
+ }
+ if (ianns != 0) {
+ for (int i = readUnsignedShort(ianns), v = ianns + 2; i > 0; --i) {
+ v = readAnnotationValues(v + 2, c, true, classVisitor.visitAnnotation(readUTF8(v, c), false));
+ }
+ }
+ if (tanns != 0) {
+ for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) {
+ v = readAnnotationTarget(context, v);
+ v = readAnnotationValues(
+ v + 2,
+ c,
+ true,
+ classVisitor.visitTypeAnnotation(context.typeRef, context.typePath, readUTF8(v, c), true));
+ }
+ }
+ if (itanns != 0) {
+ for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) {
+ v = readAnnotationTarget(context, v);
+ v = readAnnotationValues(
+ v + 2,
+ c,
+ true,
+ classVisitor.visitTypeAnnotation(context.typeRef, context.typePath, readUTF8(v, c), false));
+ }
+ }
+
+ // visits the attributes
+ while (attributes != null) {
+ Attribute attr = attributes.next;
+ attributes.next = null;
+ classVisitor.visitAttribute(attributes);
+ attributes = attr;
+ }
+
+ // visits the inner classes
+ if (innerClasses != 0) {
+ int v = innerClasses + 2;
+ for (int i = readUnsignedShort(innerClasses); i > 0; --i) {
+ classVisitor.visitInnerClass(
+ readClass(v, c), readClass(v + 2, c), readUTF8(v + 4, c), readUnsignedShort(v + 6));
+ v += 8;
+ }
+ }
+
+ // visits the fields and methods
+ u = header + 10 + 2 * interfaces.length;
+ for (int i = readUnsignedShort(u - 2); i > 0; --i) {
+ u = readField(classVisitor, context, u);
+ }
+ u += 2;
+ for (int i = readUnsignedShort(u - 2); i > 0; --i) {
+ u = readMethod(classVisitor, context, u);
+ }
+
+ // visits the end of the class
+ classVisitor.visitEnd();
+ }
+
+ /**
+ * Reads the module attribute and visit it.
+ *
+ * @param classVisitor the current class visitor
+ * @param context information about the class being parsed.
+ * @param u start offset of the module attribute in the class file.
+ * @param mainClass name of the main class of a module or null.
+ * @param packages start offset of the concealed package attribute.
+ */
+ private void readModule(
+ final ClassVisitor classVisitor, final Context context, int u, final String mainClass, int packages) {
+
+ char[] buffer = context.buffer;
+
+ // reads module name, flags and version
+ String name = readModule(u, buffer);
+ int flags = readUnsignedShort(u + 2);
+ String version = readUTF8(u + 4, buffer);
+ u += 6;
+
+ ModuleVisitor mv = classVisitor.visitModule(name, flags, version);
+ if (mv == null) {
+ return;
+ }
+
+ // module attributes (main class, packages)
+ if (mainClass != null) {
+ mv.visitMainClass(mainClass);
+ }
+
+ if (packages != 0) {
+ for (int i = readUnsignedShort(packages - 2); i > 0; --i) {
+ String packaze = readPackage(packages, buffer);
+ mv.visitPackage(packaze);
+ packages += 2;
+ }
+ }
+
+ // reads requires
+ u += 2;
+ for (int i = readUnsignedShort(u - 2); i > 0; --i) {
+ String module = readModule(u, buffer);
+ int access = readUnsignedShort(u + 2);
+ String requireVersion = readUTF8(u + 4, buffer);
+ mv.visitRequire(module, access, requireVersion);
+ u += 6;
+ }
+
+ // reads exports
+ u += 2;
+ for (int i = readUnsignedShort(u - 2); i > 0; --i) {
+ String export = readPackage(u, buffer);
+ int access = readUnsignedShort(u + 2);
+ int exportToCount = readUnsignedShort(u + 4);
+ u += 6;
+ String[] tos = null;
+ if (exportToCount != 0) {
+ tos = new String[exportToCount];
+ for (int j = 0; j < tos.length; ++j) {
+ tos[j] = readModule(u, buffer);
+ u += 2;
+ }
+ }
+ mv.visitExport(export, access, tos);
+ }
+
+ // reads opens
+ u += 2;
+ for (int i = readUnsignedShort(u - 2); i > 0; --i) {
+ String open = readPackage(u, buffer);
+ int access = readUnsignedShort(u + 2);
+ int openToCount = readUnsignedShort(u + 4);
+ u += 6;
+ String[] tos = null;
+ if (openToCount != 0) {
+ tos = new String[openToCount];
+ for (int j = 0; j < tos.length; ++j) {
+ tos[j] = readModule(u, buffer);
+ u += 2;
+ }
+ }
+ mv.visitOpen(open, access, tos);
+ }
+
+ // read uses
+ u += 2;
+ for (int i = readUnsignedShort(u - 2); i > 0; --i) {
+ mv.visitUse(readClass(u, buffer));
+ u += 2;
+ }
+
+ // read provides
+ u += 2;
+ for (int i = readUnsignedShort(u - 2); i > 0; --i) {
+ String service = readClass(u, buffer);
+ int provideWithCount = readUnsignedShort(u + 2);
+ u += 4;
+ String[] withs = new String[provideWithCount];
+ for (int j = 0; j < withs.length; ++j) {
+ withs[j] = readClass(u, buffer);
+ u += 2;
+ }
+ mv.visitProvide(service, withs);
+ }
+
+ mv.visitEnd();
+ }
+
+ /**
+ * Reads a field and makes the given visitor visit it.
+ *
+ * @param classVisitor the visitor that must visit the field.
+ * @param context information about the class being parsed.
+ * @param u the start offset of the field in the class file.
+ * @return the offset of the first byte following the field in the class.
+ */
+ private int readField(final ClassVisitor classVisitor, final Context context, int u) {
+ // reads the field declaration
+ char[] c = context.buffer;
+ int access = readUnsignedShort(u);
+ String name = readUTF8(u + 2, c);
+ String desc = readUTF8(u + 4, c);
+ u += 6;
+
+ // reads the field attributes
+ String signature = null;
+ int anns = 0;
+ int ianns = 0;
+ int tanns = 0;
+ int itanns = 0;
+ Object value = null;
+ Attribute attributes = null;
+
+ for (int i = readUnsignedShort(u); i > 0; --i) {
+ String attrName = readUTF8(u + 2, c);
+ // tests are sorted in decreasing frequency order
+ // (based on frequencies observed on typical classes)
+ if ("ConstantValue".equals(attrName)) {
+ int item = readUnsignedShort(u + 8);
+ value = item == 0 ? null : readConst(item, c);
+ } else if ("Signature".equals(attrName)) {
+ signature = readUTF8(u + 8, c);
+ } else if ("Deprecated".equals(attrName)) {
+ access |= Opcodes.ACC_DEPRECATED;
+ } else if ("Synthetic".equals(attrName)) {
+ access |= Opcodes.ACC_SYNTHETIC | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE;
+ } else if ("RuntimeVisibleAnnotations".equals(attrName)) {
+ anns = u + 8;
+ } else if ("RuntimeVisibleTypeAnnotations".equals(attrName)) {
+ tanns = u + 8;
+ } else if ("RuntimeInvisibleAnnotations".equals(attrName)) {
+ ianns = u + 8;
+ } else if ("RuntimeInvisibleTypeAnnotations".equals(attrName)) {
+ itanns = u + 8;
+ } else {
+ Attribute attr = readAttribute(context.attrs, attrName, u + 8, readInt(u + 4), c, -1, null);
+ if (attr != null) {
+ attr.next = attributes;
+ attributes = attr;
+ }
+ }
+ u += 6 + readInt(u + 4);
+ }
+ u += 2;
+
+ // visits the field declaration
+ FieldVisitor fv = classVisitor.visitField(access, name, desc, signature, value);
+ if (fv == null) {
+ return u;
+ }
+
+ // visits the field annotations and type annotations
+ if (anns != 0) {
+ for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) {
+ v = readAnnotationValues(v + 2, c, true, fv.visitAnnotation(readUTF8(v, c), true));
+ }
+ }
+ if (ianns != 0) {
+ for (int i = readUnsignedShort(ianns), v = ianns + 2; i > 0; --i) {
+ v = readAnnotationValues(v + 2, c, true, fv.visitAnnotation(readUTF8(v, c), false));
+ }
+ }
+ if (tanns != 0) {
+ for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) {
+ v = readAnnotationTarget(context, v);
+ v = readAnnotationValues(
+ v + 2,
+ c,
+ true,
+ fv.visitTypeAnnotation(context.typeRef, context.typePath, readUTF8(v, c), true));
+ }
+ }
+ if (itanns != 0) {
+ for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) {
+ v = readAnnotationTarget(context, v);
+ v = readAnnotationValues(
+ v + 2,
+ c,
+ true,
+ fv.visitTypeAnnotation(context.typeRef, context.typePath, readUTF8(v, c), false));
+ }
+ }
+
+ // visits the field attributes
+ while (attributes != null) {
+ Attribute attr = attributes.next;
+ attributes.next = null;
+ fv.visitAttribute(attributes);
+ attributes = attr;
+ }
+
+ // visits the end of the field
+ fv.visitEnd();
+
+ return u;
+ }
+
+ /**
+ * Reads a method and makes the given visitor visit it.
+ *
+ * @param classVisitor the visitor that must visit the method.
+ * @param context information about the class being parsed.
+ * @param u the start offset of the method in the class file.
+ * @return the offset of the first byte following the method in the class.
+ */
+ private int readMethod(final ClassVisitor classVisitor, final Context context, int u) {
+ // reads the method declaration
+ char[] c = context.buffer;
+ context.access = readUnsignedShort(u);
+ context.name = readUTF8(u + 2, c);
+ context.desc = readUTF8(u + 4, c);
+ u += 6;
+
+ // reads the method attributes
+ int code = 0;
+ int exception = 0;
+ String[] exceptions = null;
+ String signature = null;
+ int methodParameters = 0;
+ int anns = 0;
+ int ianns = 0;
+ int tanns = 0;
+ int itanns = 0;
+ int dann = 0;
+ int mpanns = 0;
+ int impanns = 0;
+ int firstAttribute = u;
+ Attribute attributes = null;
+
+ for (int i = readUnsignedShort(u); i > 0; --i) {
+ String attrName = readUTF8(u + 2, c);
+ // tests are sorted in decreasing frequency order
+ // (based on frequencies observed on typical classes)
+ if ("Code".equals(attrName)) {
+ if ((context.flags & SKIP_CODE) == 0) {
+ code = u + 8;
+ }
+ } else if ("Exceptions".equals(attrName)) {
+ exceptions = new String[readUnsignedShort(u + 8)];
+ exception = u + 10;
+ for (int j = 0; j < exceptions.length; ++j) {
+ exceptions[j] = readClass(exception, c);
+ exception += 2;
+ }
+ } else if ("Signature".equals(attrName)) {
+ signature = readUTF8(u + 8, c);
+ } else if ("Deprecated".equals(attrName)) {
+ context.access |= Opcodes.ACC_DEPRECATED;
+ } else if ("RuntimeVisibleAnnotations".equals(attrName)) {
+ anns = u + 8;
+ } else if ("RuntimeVisibleTypeAnnotations".equals(attrName)) {
+ tanns = u + 8;
+ } else if ("AnnotationDefault".equals(attrName)) {
+ dann = u + 8;
+ } else if ("Synthetic".equals(attrName)) {
+ context.access |= Opcodes.ACC_SYNTHETIC | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE;
+ } else if ("RuntimeInvisibleAnnotations".equals(attrName)) {
+ ianns = u + 8;
+ } else if ("RuntimeInvisibleTypeAnnotations".equals(attrName)) {
+ itanns = u + 8;
+ } else if ("RuntimeVisibleParameterAnnotations".equals(attrName)) {
+ mpanns = u + 8;
+ } else if ("RuntimeInvisibleParameterAnnotations".equals(attrName)) {
+ impanns = u + 8;
+ } else if ("MethodParameters".equals(attrName)) {
+ methodParameters = u + 8;
+ } else {
+ Attribute attr = readAttribute(context.attrs, attrName, u + 8, readInt(u + 4), c, -1, null);
+ if (attr != null) {
+ attr.next = attributes;
+ attributes = attr;
+ }
+ }
+ u += 6 + readInt(u + 4);
+ }
+ u += 2;
+
+ // visits the method declaration
+ MethodVisitor mv = classVisitor.visitMethod(context.access, context.name, context.desc, signature, exceptions);
+ if (mv == null) {
+ return u;
+ }
+
+ /*
+ * if the returned MethodVisitor is in fact a MethodWriter, it means
+ * there is no method adapter between the reader and the writer. If, in
+ * addition, the writer's constant pool was copied from this reader
+ * (mw.cw.cr == this), and the signature and exceptions of the method
+ * have not been changed, then it is possible to skip all visit events
+ * and just copy the original code of the method to the writer (the
+ * access, name and descriptor can have been changed, this is not
+ * important since they are not copied as is from the reader).
+ */
+ if (mv instanceof MethodWriter) {
+ MethodWriter mw = (MethodWriter) mv;
+ if (mw.cw.cr == this && signature == mw.signature) {
+ boolean sameExceptions = false;
+ if (exceptions == null) {
+ sameExceptions = mw.exceptionCount == 0;
+ } else if (exceptions.length == mw.exceptionCount) {
+ sameExceptions = true;
+ for (int j = exceptions.length - 1; j >= 0; --j) {
+ exception -= 2;
+ if (mw.exceptions[j] != readUnsignedShort(exception)) {
+ sameExceptions = false;
+ break;
+ }
+ }
+ }
+ if (sameExceptions) {
+ /*
+ * we do not copy directly the code into MethodWriter to
+ * save a byte array copy operation. The real copy will be
+ * done in ClassWriter.toByteArray().
+ */
+ mw.classReaderOffset = firstAttribute;
+ mw.classReaderLength = u - firstAttribute;
+ return u;
+ }
+ }
+ }
+
+ // visit the method parameters
+ if (methodParameters != 0) {
+ for (int i = b[methodParameters] & 0xFF, v = methodParameters + 1; i > 0; --i, v = v + 4) {
+ mv.visitParameter(readUTF8(v, c), readUnsignedShort(v + 2));
+ }
+ }
+
+ // visits the method annotations
+ if (dann != 0) {
+ AnnotationVisitor dv = mv.visitAnnotationDefault();
+ readAnnotationValue(dann, c, null, dv);
+ if (dv != null) {
+ dv.visitEnd();
+ }
+ }
+ if (anns != 0) {
+ for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) {
+ v = readAnnotationValues(v + 2, c, true, mv.visitAnnotation(readUTF8(v, c), true));
+ }
+ }
+ if (ianns != 0) {
+ for (int i = readUnsignedShort(ianns), v = ianns + 2; i > 0; --i) {
+ v = readAnnotationValues(v + 2, c, true, mv.visitAnnotation(readUTF8(v, c), false));
+ }
+ }
+ if (tanns != 0) {
+ for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) {
+ v = readAnnotationTarget(context, v);
+ v = readAnnotationValues(
+ v + 2,
+ c,
+ true,
+ mv.visitTypeAnnotation(context.typeRef, context.typePath, readUTF8(v, c), true));
+ }
+ }
+ if (itanns != 0) {
+ for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) {
+ v = readAnnotationTarget(context, v);
+ v = readAnnotationValues(
+ v + 2,
+ c,
+ true,
+ mv.visitTypeAnnotation(context.typeRef, context.typePath, readUTF8(v, c), false));
+ }
+ }
+ if (mpanns != 0) {
+ readParameterAnnotations(mv, context, mpanns, true);
+ }
+ if (impanns != 0) {
+ readParameterAnnotations(mv, context, impanns, false);
+ }
+
+ // visits the method attributes
+ while (attributes != null) {
+ Attribute attr = attributes.next;
+ attributes.next = null;
+ mv.visitAttribute(attributes);
+ attributes = attr;
+ }
+
+ // visits the method code
+ if (code != 0) {
+ mv.visitCode();
+ readCode(mv, context, code);
+ }
+
+ // visits the end of the method
+ mv.visitEnd();
+
+ return u;
+ }
+
+ /**
+ * Reads the bytecode of a method and makes the given visitor visit it.
+ *
+ * @param mv the visitor that must visit the method's code.
+ * @param context information about the class being parsed.
+ * @param u the start offset of the code attribute in the class file.
+ */
+ private void readCode(final MethodVisitor mv, final Context context, int u) {
+ // reads the header
+ byte[] b = this.b;
+ char[] c = context.buffer;
+ int maxStack = readUnsignedShort(u);
+ int maxLocals = readUnsignedShort(u + 2);
+ int codeLength = readInt(u + 4);
+ u += 8;
+
+ // reads the bytecode to find the labels
+ int codeStart = u;
+ int codeEnd = u + codeLength;
+ Label[] labels = context.labels = new Label[codeLength + 2];
+ createLabel(codeLength + 1, labels);
+ while (u < codeEnd) {
+ int offset = u - codeStart;
+ int opcode = b[u] & 0xFF;
+ switch (ClassWriter.TYPE[opcode]) {
+ case ClassWriter.NOARG_INSN:
+ case ClassWriter.IMPLVAR_INSN:
+ u += 1;
+ break;
+ case ClassWriter.LABEL_INSN:
+ createLabel(offset + readShort(u + 1), labels);
+ u += 3;
+ break;
+ case ClassWriter.ASM_LABEL_INSN:
+ createLabel(offset + readUnsignedShort(u + 1), labels);
+ u += 3;
+ break;
+ case ClassWriter.LABELW_INSN:
+ case ClassWriter.ASM_LABELW_INSN:
+ createLabel(offset + readInt(u + 1), labels);
+ u += 5;
+ break;
+ case ClassWriter.WIDE_INSN:
+ opcode = b[u + 1] & 0xFF;
+ if (opcode == Opcodes.IINC) {
+ u += 6;
+ } else {
+ u += 4;
+ }
+ break;
+ case ClassWriter.TABL_INSN:
+ // skips 0 to 3 padding bytes
+ u = u + 4 - (offset & 3);
+ // reads instruction
+ createLabel(offset + readInt(u), labels);
+ for (int i = readInt(u + 8) - readInt(u + 4) + 1; i > 0; --i) {
+ createLabel(offset + readInt(u + 12), labels);
+ u += 4;
+ }
+ u += 12;
+ break;
+ case ClassWriter.LOOK_INSN:
+ // skips 0 to 3 padding bytes
+ u = u + 4 - (offset & 3);
+ // reads instruction
+ createLabel(offset + readInt(u), labels);
+ for (int i = readInt(u + 4); i > 0; --i) {
+ createLabel(offset + readInt(u + 12), labels);
+ u += 8;
+ }
+ u += 8;
+ break;
+ case ClassWriter.VAR_INSN:
+ case ClassWriter.SBYTE_INSN:
+ case ClassWriter.LDC_INSN:
+ u += 2;
+ break;
+ case ClassWriter.SHORT_INSN:
+ case ClassWriter.LDCW_INSN:
+ case ClassWriter.FIELDORMETH_INSN:
+ case ClassWriter.TYPE_INSN:
+ case ClassWriter.IINC_INSN:
+ u += 3;
+ break;
+ case ClassWriter.ITFMETH_INSN:
+ case ClassWriter.INDYMETH_INSN:
+ u += 5;
+ break;
+ // case MANA_INSN:
+ default:
+ u += 4;
+ break;
+ }
+ }
+
+ // reads the try catch entries to find the labels, and also visits them
+ for (int i = readUnsignedShort(u); i > 0; --i) {
+ Label start = createLabel(readUnsignedShort(u + 2), labels);
+ Label end = createLabel(readUnsignedShort(u + 4), labels);
+ Label handler = createLabel(readUnsignedShort(u + 6), labels);
+ String type = readUTF8(items[readUnsignedShort(u + 8)], c);
+ mv.visitTryCatchBlock(start, end, handler, type);
+ u += 8;
+ }
+ u += 2;
+
+ // reads the code attributes
+ int[] tanns = null; // start index of each visible type annotation
+ int[] itanns = null; // start index of each invisible type annotation
+ int tann = 0; // current index in tanns array
+ int itann = 0; // current index in itanns array
+ int ntoff = -1; // next visible type annotation code offset
+ int nitoff = -1; // next invisible type annotation code offset
+ int varTable = 0;
+ int varTypeTable = 0;
+ boolean zip = true;
+ boolean unzip = (context.flags & EXPAND_FRAMES) != 0;
+ int stackMap = 0;
+ int stackMapSize = 0;
+ int frameCount = 0;
+ Context frame = null;
+ Attribute attributes = null;
+
+ for (int i = readUnsignedShort(u); i > 0; --i) {
+ String attrName = readUTF8(u + 2, c);
+ if ("LocalVariableTable".equals(attrName)) {
+ if ((context.flags & SKIP_DEBUG) == 0) {
+ varTable = u + 8;
+ for (int j = readUnsignedShort(u + 8), v = u; j > 0; --j) {
+ int label = readUnsignedShort(v + 10);
+ createDebugLabel(label, labels);
+ label += readUnsignedShort(v + 12);
+ createDebugLabel(label, labels);
+ v += 10;
+ }
+ }
+ } else if ("LocalVariableTypeTable".equals(attrName)) {
+ varTypeTable = u + 8;
+ } else if ("LineNumberTable".equals(attrName)) {
+ if ((context.flags & SKIP_DEBUG) == 0) {
+ for (int j = readUnsignedShort(u + 8), v = u; j > 0; --j) {
+ int label = readUnsignedShort(v + 10);
+ createDebugLabel(label, labels);
+ Label l = labels[label];
+ while (l.line > 0) {
+ if (l.next == null) {
+ l.next = new Label();
+ }
+ l = l.next;
+ }
+ l.line = readUnsignedShort(v + 12);
+ v += 4;
+ }
+ }
+ } else if ("RuntimeVisibleTypeAnnotations".equals(attrName)) {
+ tanns = readTypeAnnotations(mv, context, u + 8, true);
+ ntoff = tanns.length == 0 || readByte(tanns[0]) < 0x43 ? -1 : readUnsignedShort(tanns[0] + 1);
+ } else if ("RuntimeInvisibleTypeAnnotations".equals(attrName)) {
+ itanns = readTypeAnnotations(mv, context, u + 8, false);
+ nitoff = itanns.length == 0 || readByte(itanns[0]) < 0x43 ? -1 : readUnsignedShort(itanns[0] + 1);
+ } else if ("StackMapTable".equals(attrName)) {
+ if ((context.flags & SKIP_FRAMES) == 0) {
+ stackMap = u + 10;
+ stackMapSize = readInt(u + 4);
+ frameCount = readUnsignedShort(u + 8);
+ }
+ /*
+ * here we do not extract the labels corresponding to the
+ * attribute content. This would require a full parsing of the
+ * attribute, which would need to be repeated in the second
+ * phase (see below). Instead the content of the attribute is
+ * read one frame at a time (i.e. after a frame has been
+ * visited, the next frame is read), and the labels it contains
+ * are also extracted one frame at a time. Thanks to the
+ * ordering of frames, having only a "one frame lookahead" is
+ * not a problem, i.e. it is not possible to see an offset
+ * smaller than the offset of the current insn and for which no
+ * Label exist.
+ */
+ /*
+ * This is not true for UNINITIALIZED type offsets. We solve
+ * this by parsing the stack map table without a full decoding
+ * (see below).
+ */
+ } else if ("StackMap".equals(attrName)) {
+ if ((context.flags & SKIP_FRAMES) == 0) {
+ zip = false;
+ stackMap = u + 10;
+ stackMapSize = readInt(u + 4);
+ frameCount = readUnsignedShort(u + 8);
+ }
+ /*
+ * IMPORTANT! here we assume that the frames are ordered, as in
+ * the StackMapTable attribute, although this is not guaranteed
+ * by the attribute format.
+ */
+ } else {
+ for (int j = 0; j < context.attrs.length; ++j) {
+ if (context.attrs[j].type.equals(attrName)) {
+ Attribute attr = context.attrs[j].read(this, u + 8, readInt(u + 4), c, codeStart - 8, labels);
+ if (attr != null) {
+ attr.next = attributes;
+ attributes = attr;
+ }
+ }
+ }
+ }
+ u += 6 + readInt(u + 4);
+ }
+ u += 2;
+
+ // generates the first (implicit) stack map frame
+ if (stackMap != 0) {
+ /*
+ * for the first explicit frame the offset is not offset_delta + 1
+ * but only offset_delta; setting the implicit frame offset to -1
+ * allow the use of the "offset_delta + 1" rule in all cases
+ */
+ frame = context;
+ frame.offset = -1;
+ frame.mode = 0;
+ frame.localCount = 0;
+ frame.localDiff = 0;
+ frame.stackCount = 0;
+ frame.local = new Object[maxLocals];
+ frame.stack = new Object[maxStack];
+ if (unzip) {
+ getImplicitFrame(context);
+ }
+ /*
+ * Finds labels for UNINITIALIZED frame types. Instead of decoding
+ * each element of the stack map table, we look for 3 consecutive
+ * bytes that "look like" an UNINITIALIZED type (tag 8, offset
+ * within code bounds, NEW instruction at this offset). We may find
+ * false positives (i.e. not real UNINITIALIZED types), but this
+ * should be rare, and the only consequence will be the creation of
+ * an unneeded label. This is better than creating a label for each
+ * NEW instruction, and faster than fully decoding the whole stack
+ * map table.
+ */
+ for (int i = stackMap; i < stackMap + stackMapSize - 2; ++i) {
+ if (b[i] == 8) { // UNINITIALIZED FRAME TYPE
+ int v = readUnsignedShort(i + 1);
+ if (v >= 0 && v < codeLength) {
+ if ((b[codeStart + v] & 0xFF) == Opcodes.NEW) {
+ createLabel(v, labels);
+ }
+ }
+ }
+ }
+ }
+ if ((context.flags & EXPAND_ASM_INSNS) != 0 && (context.flags & EXPAND_FRAMES) != 0) {
+ // Expanding the ASM pseudo instructions can introduce F_INSERT
+ // frames, even if the method does not currently have any frame.
+ // Also these inserted frames must be computed by simulating the
+ // effect of the bytecode instructions one by one, starting from the
+ // first one and the last existing frame (or the implicit first
+ // one). Finally, due to the way MethodWriter computes this (with
+ // the compute = INSERTED_FRAMES option), MethodWriter needs to know
+ // maxLocals before the first instruction is visited. For all these
+ // reasons we always visit the implicit first frame in this case
+ // (passing only maxLocals - the rest can be and is computed in
+ // MethodWriter).
+ mv.visitFrame(Opcodes.F_NEW, maxLocals, null, 0, null);
+ }
+
+ // visits the instructions
+ int opcodeDelta = (context.flags & EXPAND_ASM_INSNS) == 0 ? -33 : 0;
+ boolean insertFrame = false;
+ u = codeStart;
+ while (u < codeEnd) {
+ int offset = u - codeStart;
+
+ // visits the label and line number for this offset, if any
+ Label l = labels[offset];
+ if (l != null) {
+ Label next = l.next;
+ l.next = null;
+ mv.visitLabel(l);
+ if ((context.flags & SKIP_DEBUG) == 0 && l.line > 0) {
+ mv.visitLineNumber(l.line, l);
+ while (next != null) {
+ mv.visitLineNumber(next.line, l);
+ next = next.next;
+ }
+ }
+ }
+
+ // visits the frame for this offset, if any
+ while (frame != null && (frame.offset == offset || frame.offset == -1)) {
+ // if there is a frame for this offset, makes the visitor visit
+ // it, and reads the next frame if there is one.
+ if (frame.offset != -1) {
+ if (!zip || unzip) {
+ mv.visitFrame(Opcodes.F_NEW, frame.localCount, frame.local, frame.stackCount, frame.stack);
+ } else {
+ mv.visitFrame(frame.mode, frame.localDiff, frame.local, frame.stackCount, frame.stack);
+ }
+ // if there is already a frame for this offset, there is no
+ // need to insert a new one.
+ insertFrame = false;
+ }
+ if (frameCount > 0) {
+ stackMap = readFrame(stackMap, zip, unzip, frame);
+ --frameCount;
+ } else {
+ frame = null;
+ }
+ }
+ // inserts a frame for this offset, if requested by setting
+ // insertFrame to true during the previous iteration. The actual
+ // frame content will be computed in MethodWriter.
+ if (insertFrame) {
+ mv.visitFrame(ClassWriter.F_INSERT, 0, null, 0, null);
+ insertFrame = false;
+ }
+
+ // visits the instruction at this offset
+ int opcode = b[u] & 0xFF;
+ switch (ClassWriter.TYPE[opcode]) {
+ case ClassWriter.NOARG_INSN:
+ mv.visitInsn(opcode);
+ u += 1;
+ break;
+ case ClassWriter.IMPLVAR_INSN:
+ if (opcode > Opcodes.ISTORE) {
+ opcode -= 59; // ISTORE_0
+ mv.visitVarInsn(Opcodes.ISTORE + (opcode >> 2), opcode & 0x3);
+ } else {
+ opcode -= 26; // ILOAD_0
+ mv.visitVarInsn(Opcodes.ILOAD + (opcode >> 2), opcode & 0x3);
+ }
+ u += 1;
+ break;
+ case ClassWriter.LABEL_INSN:
+ mv.visitJumpInsn(opcode, labels[offset + readShort(u + 1)]);
+ u += 3;
+ break;
+ case ClassWriter.LABELW_INSN:
+ mv.visitJumpInsn(opcode + opcodeDelta, labels[offset + readInt(u + 1)]);
+ u += 5;
+ break;
+ case ClassWriter.ASM_LABEL_INSN: {
+ // changes temporary opcodes 202 to 217 (inclusive), 218
+ // and 219 to IFEQ ... JSR (inclusive), IFNULL and
+ // IFNONNULL
+ opcode = opcode < 218 ? opcode - 49 : opcode - 20;
+ Label target = labels[offset + readUnsignedShort(u + 1)];
+ // replaces GOTO with GOTO_W, JSR with JSR_W and IFxxx
+ //
- *
- *
- * @param classReader the {@link ClassReader} used to read the original class. It will be used to copy the entire
- * constant pool from the original class and also to copy other fragments of original bytecode where applicable.
- * @param flags option flags that can be used to modify the default behavior of this class. These option flags do
- * not affect methods that are copied as is in the new class. This means that neither the maximum stack size nor
- * the stack frames will be computed for these methods. See {@link #COMPUTE_MAXS}, {@link #COMPUTE_FRAMES}.
- */
- public ClassWriter(final ClassReader classReader, final int flags) {
- this(flags);
- classReader.copyPool(this);
- this.cr = classReader;
- }
-
- // ------------------------------------------------------------------------
- // Implementation of the ClassVisitor abstract class
- // ------------------------------------------------------------------------
-
- @Override
- public final void visit(
- final int version,
- final int access,
- final String name,
- final String signature,
- final String superName,
- final String[] interfaces) {
- this.version = version;
- this.access = access;
- this.name = newClass(name);
- thisName = name;
- if (signature != null) {
- this.signature = newUTF8(signature);
- }
- this.superName = superName == null ? 0 : newClass(superName);
- if (interfaces != null && interfaces.length > 0) {
- interfaceCount = interfaces.length;
- this.interfaces = new int[interfaceCount];
- for (int i = 0; i < interfaceCount; ++i) {
- this.interfaces[i] = newClass(interfaces[i]);
- }
- }
- }
-
- @Override
- public final void visitSource(final String file, final String debug) {
- if (file != null) {
- sourceFile = newUTF8(file);
- }
- if (debug != null) {
- sourceDebug = new ByteVector().encodeUTF8(debug, 0, Integer.MAX_VALUE);
- }
- }
-
- @Override
- public final ModuleVisitor visitModule(final String name, final int access, final String version) {
- return moduleWriter = new ModuleWriter(this, newModule(name), access, version == null ? 0 : newUTF8(version));
- }
-
- @Override
- public final void visitOuterClass(final String owner, final String name, final String desc) {
- enclosingMethodOwner = newClass(owner);
- if (name != null && desc != null) {
- enclosingMethod = newNameType(name, desc);
- }
- }
-
- @Override
- public final AnnotationVisitor visitAnnotation(final String desc, final boolean visible) {
- ByteVector bv = new ByteVector();
- // write type, and reserve space for values count
- bv.putShort(newUTF8(desc)).putShort(0);
- AnnotationWriter aw = new AnnotationWriter(this, true, bv, bv, 2);
- if (visible) {
- aw.next = anns;
- anns = aw;
- } else {
- aw.next = ianns;
- ianns = aw;
- }
- return aw;
- }
-
- @Override
- public final AnnotationVisitor visitTypeAnnotation(
- int typeRef, TypePath typePath, final String desc, final boolean visible) {
- ByteVector bv = new ByteVector();
- // write target_type and target_info
- AnnotationWriter.putTarget(typeRef, typePath, bv);
- // write type, and reserve space for values count
- bv.putShort(newUTF8(desc)).putShort(0);
- AnnotationWriter aw = new AnnotationWriter(this, true, bv, bv, bv.length - 2);
- if (visible) {
- aw.next = tanns;
- tanns = aw;
- } else {
- aw.next = itanns;
- itanns = aw;
- }
- return aw;
- }
-
- @Override
- public final void visitAttribute(final Attribute attr) {
- attr.next = attrs;
- attrs = attr;
- }
-
- @Override
- public final void visitInnerClass(
- final String name, final String outerName, final String innerName, final int access) {
- if (innerClasses == null) {
- innerClasses = new ByteVector();
- }
- // Sec. 4.7.6 of the JVMS states "Every CONSTANT_Class_info entry in the
- // constant_pool table which represents a class or interface C that is
- // not a package member must have exactly one corresponding entry in the
- // classes array". To avoid duplicates we keep track in the intVal field
- // of the Item of each CONSTANT_Class_info entry C whether an inner
- // class entry has already been added for C (this field is unused for
- // class entries, and changing its value does not change the hashcode
- // and equality tests). If so we store the index of this inner class
- // entry (plus one) in intVal. This hack allows duplicate detection in
- // O(1) time.
- Item nameItem = newStringishItem(CLASS, name);
- if (nameItem.intVal == 0) {
- ++innerClassesCount;
- innerClasses.putShort(nameItem.index);
- innerClasses.putShort(outerName == null ? 0 : newClass(outerName));
- innerClasses.putShort(innerName == null ? 0 : newUTF8(innerName));
- innerClasses.putShort(access);
- nameItem.intVal = innerClassesCount;
- } else {
- // Compare the inner classes entry nameItem.intVal - 1 with the
- // arguments of this method and throw an exception if there is a
- // difference?
- }
- }
-
- @Override
- public final FieldVisitor visitField(
- final int access, final String name, final String desc, final String signature, final Object value) {
- return new FieldWriter(this, access, name, desc, signature, value);
- }
-
- @Override
- public final MethodVisitor visitMethod(
- final int access, final String name, final String desc, final String signature, final String[] exceptions) {
- return new MethodWriter(this, access, name, desc, signature, exceptions, compute);
- }
-
- @Override
- public final void visitEnd() {
- // do nothing
- }
-
- // ------------------------------------------------------------------------
- // Other public methods
- // ------------------------------------------------------------------------
-
- /**
- * Returns the bytecode of the class that was build with this class writer.
- *
- * @return the bytecode of the class that was build with this class writer.
- */
- public byte[] toByteArray() {
- if (index > 0xFFFF) {
- throw new RuntimeException("Class file too large!");
- }
- // computes the real size of the bytecode of this class
- int size = 24 + 2 * interfaceCount;
- int nbFields = 0;
- FieldWriter fb = firstField;
- while (fb != null) {
- ++nbFields;
- size += fb.getSize();
- fb = (FieldWriter) fb.fv;
- }
- int nbMethods = 0;
- MethodWriter mb = firstMethod;
- while (mb != null) {
- ++nbMethods;
- size += mb.getSize();
- mb = (MethodWriter) mb.mv;
- }
- int attributeCount = 0;
- if (bootstrapMethods != null) {
- // we put it as first attribute in order to improve a bit
- // ClassReader.copyBootstrapMethods
- ++attributeCount;
- size += 8 + bootstrapMethods.length;
- newUTF8("BootstrapMethods");
- }
- if (signature != 0) {
- ++attributeCount;
- size += 8;
- newUTF8("Signature");
- }
- if (sourceFile != 0) {
- ++attributeCount;
- size += 8;
- newUTF8("SourceFile");
- }
- if (sourceDebug != null) {
- ++attributeCount;
- size += sourceDebug.length + 6;
- newUTF8("SourceDebugExtension");
- }
- if (enclosingMethodOwner != 0) {
- ++attributeCount;
- size += 10;
- newUTF8("EnclosingMethod");
- }
- if ((access & Opcodes.ACC_DEPRECATED) != 0) {
- ++attributeCount;
- size += 6;
- newUTF8("Deprecated");
- }
- if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
- if ((version & 0xFFFF) < Opcodes.V1_5 || (access & ACC_SYNTHETIC_ATTRIBUTE) != 0) {
- ++attributeCount;
- size += 6;
- newUTF8("Synthetic");
- }
- }
- if (innerClasses != null) {
- ++attributeCount;
- size += 8 + innerClasses.length;
- newUTF8("InnerClasses");
- }
- if (anns != null) {
- ++attributeCount;
- size += 8 + anns.getSize();
- newUTF8("RuntimeVisibleAnnotations");
- }
- if (ianns != null) {
- ++attributeCount;
- size += 8 + ianns.getSize();
- newUTF8("RuntimeInvisibleAnnotations");
- }
- if (tanns != null) {
- ++attributeCount;
- size += 8 + tanns.getSize();
- newUTF8("RuntimeVisibleTypeAnnotations");
- }
- if (itanns != null) {
- ++attributeCount;
- size += 8 + itanns.getSize();
- newUTF8("RuntimeInvisibleTypeAnnotations");
- }
- if (moduleWriter != null) {
- attributeCount += 1 + moduleWriter.attributeCount;
- size += 6 + moduleWriter.size + moduleWriter.attributesSize;
- newUTF8("Module");
- }
- if (attrs != null) {
- attributeCount += attrs.getCount();
- size += attrs.getSize(this, null, 0, -1, -1);
- }
- size += pool.length;
- // allocates a byte vector of this size, in order to avoid unnecessary
- // arraycopy operations in the ByteVector.enlarge() method
- ByteVector out = new ByteVector(size);
- out.putInt(0xCAFEBABE).putInt(version);
- out.putShort(index).putByteArray(pool.data, 0, pool.length);
- int mask = Opcodes.ACC_DEPRECATED
- | ACC_SYNTHETIC_ATTRIBUTE
- | ((access & ACC_SYNTHETIC_ATTRIBUTE) / TO_ACC_SYNTHETIC);
- out.putShort(access & ~mask).putShort(name).putShort(superName);
- out.putShort(interfaceCount);
- for (int i = 0; i < interfaceCount; ++i) {
- out.putShort(interfaces[i]);
- }
- out.putShort(nbFields);
- fb = firstField;
- while (fb != null) {
- fb.put(out);
- fb = (FieldWriter) fb.fv;
- }
- out.putShort(nbMethods);
- mb = firstMethod;
- while (mb != null) {
- mb.put(out);
- mb = (MethodWriter) mb.mv;
- }
- out.putShort(attributeCount);
- if (bootstrapMethods != null) {
- out.putShort(newUTF8("BootstrapMethods"));
- out.putInt(bootstrapMethods.length + 2).putShort(bootstrapMethodsCount);
- out.putByteArray(bootstrapMethods.data, 0, bootstrapMethods.length);
- }
- if (signature != 0) {
- out.putShort(newUTF8("Signature")).putInt(2).putShort(signature);
- }
- if (sourceFile != 0) {
- out.putShort(newUTF8("SourceFile")).putInt(2).putShort(sourceFile);
- }
- if (sourceDebug != null) {
- int len = sourceDebug.length;
- out.putShort(newUTF8("SourceDebugExtension")).putInt(len);
- out.putByteArray(sourceDebug.data, 0, len);
- }
- if (moduleWriter != null) {
- out.putShort(newUTF8("Module"));
- moduleWriter.put(out);
- moduleWriter.putAttributes(out);
- }
- if (enclosingMethodOwner != 0) {
- out.putShort(newUTF8("EnclosingMethod")).putInt(4);
- out.putShort(enclosingMethodOwner).putShort(enclosingMethod);
- }
- if ((access & Opcodes.ACC_DEPRECATED) != 0) {
- out.putShort(newUTF8("Deprecated")).putInt(0);
- }
- if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
- if ((version & 0xFFFF) < Opcodes.V1_5 || (access & ACC_SYNTHETIC_ATTRIBUTE) != 0) {
- out.putShort(newUTF8("Synthetic")).putInt(0);
- }
- }
- if (innerClasses != null) {
- out.putShort(newUTF8("InnerClasses"));
- out.putInt(innerClasses.length + 2).putShort(innerClassesCount);
- out.putByteArray(innerClasses.data, 0, innerClasses.length);
- }
- if (anns != null) {
- out.putShort(newUTF8("RuntimeVisibleAnnotations"));
- anns.put(out);
- }
- if (ianns != null) {
- out.putShort(newUTF8("RuntimeInvisibleAnnotations"));
- ianns.put(out);
- }
- if (tanns != null) {
- out.putShort(newUTF8("RuntimeVisibleTypeAnnotations"));
- tanns.put(out);
- }
- if (itanns != null) {
- out.putShort(newUTF8("RuntimeInvisibleTypeAnnotations"));
- itanns.put(out);
- }
- if (attrs != null) {
- attrs.put(this, null, 0, -1, -1, out);
- }
- if (hasAsmInsns) {
- boolean hasFrames = false;
- mb = firstMethod;
- while (mb != null) {
- hasFrames |= mb.frameCount > 0;
- mb = (MethodWriter) mb.mv;
- }
- anns = null;
- ianns = null;
- attrs = null;
- moduleWriter = null;
- firstField = null;
- lastField = null;
- firstMethod = null;
- lastMethod = null;
- compute = hasFrames ? MethodWriter.INSERTED_FRAMES : MethodWriter.NOTHING;
- hasAsmInsns = false;
- new ClassReader(out.data)
- .accept(this, (hasFrames ? ClassReader.EXPAND_FRAMES : 0) | ClassReader.EXPAND_ASM_INSNS);
- return toByteArray();
- }
- return out.data;
- }
-
- // ------------------------------------------------------------------------
- // Utility methods: constant pool management
- // ------------------------------------------------------------------------
-
- /**
- * Adds a number or string constant to the constant pool of the class being build. Does nothing if the constant pool
- * already contains a similar item.
- *
- * @param cst the value of the constant to be added to the constant pool. This parameter must be an {@link Integer},
- * a {@link Float}, a {@link Long}, a {@link Double}, a {@link String} or a {@link Type}.
- * @return a new or already existing constant item with the given value.
- */
- Item newConstItem(final Object cst) {
- if (cst instanceof Integer) {
- int val = ((Integer) cst).intValue();
- return newInteger(val);
- } else if (cst instanceof Byte) {
- int val = ((Byte) cst).intValue();
- return newInteger(val);
- } else if (cst instanceof Character) {
- int val = ((Character) cst).charValue();
- return newInteger(val);
- } else if (cst instanceof Short) {
- int val = ((Short) cst).intValue();
- return newInteger(val);
- } else if (cst instanceof Boolean) {
- int val = ((Boolean) cst).booleanValue() ? 1 : 0;
- return newInteger(val);
- } else if (cst instanceof Float) {
- float val = ((Float) cst).floatValue();
- return newFloat(val);
- } else if (cst instanceof Long) {
- long val = ((Long) cst).longValue();
- return newLong(val);
- } else if (cst instanceof Double) {
- double val = ((Double) cst).doubleValue();
- return newDouble(val);
- } else if (cst instanceof String) {
- return newStringishItem(STR, (String) cst);
- } else if (cst instanceof Type) {
- Type t = (Type) cst;
- int s = t.getSort();
- if (s == Type.OBJECT) {
- return newStringishItem(CLASS, t.getInternalName());
- } else if (s == Type.METHOD) {
- return newStringishItem(MTYPE, t.getDescriptor());
- } else { // s == primitive type or array
- return newStringishItem(CLASS, t.getDescriptor());
- }
- } else if (cst instanceof Handle) {
- Handle h = (Handle) cst;
- return newHandleItem(h.tag, h.owner, h.name, h.desc, h.itf);
- } else {
- throw new IllegalArgumentException("value " + cst);
- }
- }
-
- /**
- * Adds a number or string constant to the constant pool of the class being build. Does nothing if the constant pool
- * already contains a similar item. This method is intended for {@link Attribute} sub classes, and is normally
- * not needed by class generators or adapters.
- *
- * @param cst the value of the constant to be added to the constant pool. This parameter must be an {@link Integer},
- * a {@link Float}, a {@link Long}, a {@link Double} or a {@link String}.
- * @return the index of a new or already existing constant item with the given value.
- */
- public int newConst(final Object cst) {
- return newConstItem(cst).index;
- }
-
- /**
- * Adds an UTF8 string to the constant pool of the class being build. Does nothing if the constant pool already
- * contains a similar item. This method is intended for {@link Attribute} sub classes, and is normally not needed
- * by class generators or adapters.
- *
- * @param value the String value.
- * @return the index of a new or already existing UTF8 item.
- */
- public int newUTF8(final String value) {
- key.set(UTF8, value, null, null);
- Item result = get(key);
- if (result == null) {
- pool.putByte(UTF8).putUTF8(value);
- result = new Item(index++, key);
- put(result);
- }
- return result.index;
- }
-
- /**
- * Adds a string reference, a class reference, a method type, a module or a package to the constant pool of the
- * class being build. Does nothing if the constant pool already contains a similar item.
- *
- * @param type a type among STR, CLASS, MTYPE, MODULE or PACKAGE
- * @param value string value of the reference.
- * @return a new or already existing reference item.
- */
- Item newStringishItem(final int type, final String value) {
- key2.set(type, value, null, null);
- Item result = get(key2);
- if (result == null) {
- pool.put12(type, newUTF8(value));
- result = new Item(index++, key2);
- put(result);
- }
- return result;
- }
-
- /**
- * Adds a class reference to the constant pool of the class being build. Does nothing if the constant pool already
- * contains a similar item. This method is intended for {@link Attribute} sub classes, and is normally not needed
- * by class generators or adapters.
- *
- * @param value the internal name of the class.
- * @return the index of a new or already existing class reference item.
- */
- public int newClass(final String value) {
- return newStringishItem(CLASS, value).index;
- }
-
- /**
- * Adds a method type reference to the constant pool of the class being build. Does nothing if the constant pool
- * already contains a similar item. This method is intended for {@link Attribute} sub classes, and is normally
- * not needed by class generators or adapters.
- *
- * @param methodDesc method descriptor of the method type.
- * @return the index of a new or already existing method type reference item.
- */
- public int newMethodType(final String methodDesc) {
- return newStringishItem(MTYPE, methodDesc).index;
- }
-
- /**
- * Adds a module reference to the constant pool of the class being build. Does nothing if the constant pool already
- * contains a similar item. This method is intended for {@link Attribute} sub classes, and is normally not needed
- * by class generators or adapters.
- *
- * @param moduleName name of the module.
- * @return the index of a new or already existing module reference item.
- */
- public int newModule(final String moduleName) {
- return newStringishItem(MODULE, moduleName).index;
- }
-
- /**
- * Adds a package reference to the constant pool of the class being build. Does nothing if the constant pool already
- * contains a similar item. This method is intended for {@link Attribute} sub classes, and is normally not needed
- * by class generators or adapters.
- *
- * @param packageName name of the package in its internal form.
- * @return the index of a new or already existing module reference item.
- */
- public int newPackage(final String packageName) {
- return newStringishItem(PACKAGE, packageName).index;
- }
-
- /**
- * Adds a handle to the constant pool of the class being build. Does nothing if the constant pool already contains a
- * similar item. This method is intended for {@link Attribute} sub classes, and is normally not needed by class
- * generators or adapters.
- *
- * @param tag the kind of this handle. Must be {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC},
- * {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL},
- * {@link Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL}, {@link Opcodes#H_NEWINVOKESPECIAL} or
- * {@link Opcodes#H_INVOKEINTERFACE}.
- * @param owner the internal name of the field or method owner class.
- * @param name the name of the field or method.
- * @param desc the descriptor of the field or method.
- * @param itf true if the owner is an interface.
- * @return a new or an already existing method type reference item.
- */
- Item newHandleItem(final int tag, final String owner, final String name, final String desc, final boolean itf) {
- key4.set(HANDLE_BASE + tag, owner, name, desc);
- Item result = get(key4);
- if (result == null) {
- if (tag <= Opcodes.H_PUTSTATIC) {
- put112(HANDLE, tag, newField(owner, name, desc));
- } else {
- put112(HANDLE, tag, newMethod(owner, name, desc, itf));
- }
- result = new Item(index++, key4);
- put(result);
- }
- return result;
- }
-
- /**
- * Adds a handle to the constant pool of the class being build. Does nothing if the constant pool already contains a
- * similar item. This method is intended for {@link Attribute} sub classes, and is normally not needed by class
- * generators or adapters.
- *
- * @param tag the kind of this handle. Must be {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC},
- * {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL},
- * {@link Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL}, {@link Opcodes#H_NEWINVOKESPECIAL} or
- * {@link Opcodes#H_INVOKEINTERFACE}.
- * @param owner the internal name of the field or method owner class.
- * @param name the name of the field or method.
- * @param desc the descriptor of the field or method.
- * @param itf true if the owner is an interface.
- * @return the index of a new or already existing method type reference item.
- */
- public int newHandle(final int tag, final String owner, final String name, final String desc, final boolean itf) {
- return newHandleItem(tag, owner, name, desc, itf).index;
- }
-
- /**
- * Adds an invokedynamic reference to the constant pool of the class being build. Does nothing if the constant pool
- * already contains a similar item. This method is intended for {@link Attribute} sub classes, and is normally
- * not needed by class generators or adapters.
- *
- * @param name name of the invoked method.
- * @param desc descriptor of the invoke method.
- * @param bsm the bootstrap method.
- * @param bsmArgs the bootstrap method constant arguments.
- * @return a new or an already existing invokedynamic type reference item.
- */
- Item newInvokeDynamicItem(final String name, final String desc, final Handle bsm, final Object... bsmArgs) {
- // cache for performance
- ByteVector bootstrapMethods = this.bootstrapMethods;
- if (bootstrapMethods == null) {
- bootstrapMethods = this.bootstrapMethods = new ByteVector();
- }
-
- int position = bootstrapMethods.length; // record current position
-
- int hashCode = bsm.hashCode();
- bootstrapMethods.putShort(newHandle(bsm.tag, bsm.owner, bsm.name, bsm.desc, bsm.isInterface()));
-
- int argsLength = bsmArgs.length;
- bootstrapMethods.putShort(argsLength);
-
- for (int i = 0; i < argsLength; i++) {
- Object bsmArg = bsmArgs[i];
- hashCode ^= bsmArg.hashCode();
- bootstrapMethods.putShort(newConst(bsmArg));
- }
-
- byte[] data = bootstrapMethods.data;
- int length = (1 + 1 + argsLength) << 1; // (bsm + argCount + arguments)
- hashCode &= 0x7FFFFFFF;
- Item result = items[hashCode % items.length];
- loop:
- while (result != null) {
- if (result.type != BSM || result.hashCode != hashCode) {
- result = result.next;
- continue;
- }
-
- // because the data encode the size of the argument
- // we don't need to test if these size are equals
- int resultPosition = result.intVal;
- for (int p = 0; p < length; p++) {
- if (data[position + p] != data[resultPosition + p]) {
- result = result.next;
- continue loop;
- }
- }
- break;
- }
-
- int bootstrapMethodIndex;
- if (result != null) {
- bootstrapMethodIndex = result.index;
- bootstrapMethods.length = position; // revert to old position
- } else {
- bootstrapMethodIndex = bootstrapMethodsCount++;
- result = new Item(bootstrapMethodIndex);
- result.set(position, hashCode);
- put(result);
- }
-
- // now, create the InvokeDynamic constant
- key3.set(name, desc, bootstrapMethodIndex);
- result = get(key3);
- if (result == null) {
- put122(INDY, bootstrapMethodIndex, newNameType(name, desc));
- result = new Item(index++, key3);
- put(result);
- }
- return result;
- }
-
- /**
- * Adds an invokedynamic reference to the constant pool of the class being build. Does nothing if the constant pool
- * already contains a similar item. This method is intended for {@link Attribute} sub classes, and is normally
- * not needed by class generators or adapters.
- *
- * @param name name of the invoked method.
- * @param desc descriptor of the invoke method.
- * @param bsm the bootstrap method.
- * @param bsmArgs the bootstrap method constant arguments.
- * @return the index of a new or already existing invokedynamic reference item.
- */
- public int newInvokeDynamic(final String name, final String desc, final Handle bsm, final Object... bsmArgs) {
- return newInvokeDynamicItem(name, desc, bsm, bsmArgs).index;
- }
-
- /**
- * Adds a field reference to the constant pool of the class being build. Does nothing if the constant pool already
- * contains a similar item.
- *
- * @param owner the internal name of the field's owner class.
- * @param name the field's name.
- * @param desc the field's descriptor.
- * @return a new or already existing field reference item.
- */
- Item newFieldItem(final String owner, final String name, final String desc) {
- key3.set(FIELD, owner, name, desc);
- Item result = get(key3);
- if (result == null) {
- put122(FIELD, newClass(owner), newNameType(name, desc));
- result = new Item(index++, key3);
- put(result);
- }
- return result;
- }
-
- /**
- * Adds a field reference to the constant pool of the class being build. Does nothing if the constant pool already
- * contains a similar item. This method is intended for {@link Attribute} sub classes, and is normally not needed
- * by class generators or adapters.
- *
- * @param owner the internal name of the field's owner class.
- * @param name the field's name.
- * @param desc the field's descriptor.
- * @return the index of a new or already existing field reference item.
- */
- public int newField(final String owner, final String name, final String desc) {
- return newFieldItem(owner, name, desc).index;
- }
-
- /**
- * Adds a method reference to the constant pool of the class being build. Does nothing if the constant pool already
- * contains a similar item.
- *
- * @param owner the internal name of the method's owner class.
- * @param name the method's name.
- * @param desc the method's descriptor.
- * @param itf <tt>true</tt> if <tt>owner</tt> is an interface.
- * @return a new or already existing method reference item.
- */
- Item newMethodItem(final String owner, final String name, final String desc, final boolean itf) {
- int type = itf ? IMETH : METH;
- key3.set(type, owner, name, desc);
- Item result = get(key3);
- if (result == null) {
- put122(type, newClass(owner), newNameType(name, desc));
- result = new Item(index++, key3);
- put(result);
- }
- return result;
- }
-
- /**
- * Adds a method reference to the constant pool of the class being build. Does nothing if the constant pool already
- * contains a similar item. This method is intended for {@link Attribute} sub classes, and is normally not needed
- * by class generators or adapters.
- *
- * @param owner the internal name of the method's owner class.
- * @param name the method's name.
- * @param desc the method's descriptor.
- * @param itf <tt>true</tt> if <tt>owner</tt> is an interface.
- * @return the index of a new or already existing method reference item.
- */
- public int newMethod(final String owner, final String name, final String desc, final boolean itf) {
- return newMethodItem(owner, name, desc, itf).index;
- }
-
- /**
- * Adds an integer to the constant pool of the class being build. Does nothing if the constant pool already contains
- * a similar item.
- *
- * @param value the int value.
- * @return a new or already existing int item.
- */
- Item newInteger(final int value) {
- key.set(value);
- Item result = get(key);
- if (result == null) {
- pool.putByte(INT).putInt(value);
- result = new Item(index++, key);
- put(result);
- }
- return result;
- }
-
- /**
- * Adds a float to the constant pool of the class being build. Does nothing if the constant pool already contains a
- * similar item.
- *
- * @param value the float value.
- * @return a new or already existing float item.
- */
- Item newFloat(final float value) {
- key.set(value);
- Item result = get(key);
- if (result == null) {
- pool.putByte(FLOAT).putInt(key.intVal);
- result = new Item(index++, key);
- put(result);
- }
- return result;
- }
-
- /**
- * Adds a long to the constant pool of the class being build. Does nothing if the constant pool already contains a
- * similar item.
- *
- * @param value the long value.
- * @return a new or already existing long item.
- */
- Item newLong(final long value) {
- key.set(value);
- Item result = get(key);
- if (result == null) {
- pool.putByte(LONG).putLong(value);
- result = new Item(index, key);
- index += 2;
- put(result);
- }
- return result;
- }
-
- /**
- * Adds a double to the constant pool of the class being build. Does nothing if the constant pool already contains a
- * similar item.
- *
- * @param value the double value.
- * @return a new or already existing double item.
- */
- Item newDouble(final double value) {
- key.set(value);
- Item result = get(key);
- if (result == null) {
- pool.putByte(DOUBLE).putLong(key.longVal);
- result = new Item(index, key);
- index += 2;
- put(result);
- }
- return result;
- }
-
- /**
- * Adds a name and type to the constant pool of the class being build. Does nothing if the constant pool already
- * contains a similar item. This method is intended for {@link Attribute} sub classes, and is normally not needed
- * by class generators or adapters.
- *
- * @param name a name.
- * @param desc a type descriptor.
- * @return the index of a new or already existing name and type item.
- */
- public int newNameType(final String name, final String desc) {
- return newNameTypeItem(name, desc).index;
- }
-
- /**
- * Adds a name and type to the constant pool of the class being build. Does nothing if the constant pool already
- * contains a similar item.
- *
- * @param name a name.
- * @param desc a type descriptor.
- * @return a new or already existing name and type item.
- */
- Item newNameTypeItem(final String name, final String desc) {
- key2.set(NAME_TYPE, name, desc, null);
- Item result = get(key2);
- if (result == null) {
- put122(NAME_TYPE, newUTF8(name), newUTF8(desc));
- result = new Item(index++, key2);
- put(result);
- }
- return result;
- }
-
- /**
- * Adds the given internal name to {@link #typeTable} and returns its index. Does nothing if the type table already
- * contains this internal name.
- *
- * @param type the internal name to be added to the type table.
- * @return the index of this internal name in the type table.
- */
- int addType(final String type) {
- key.set(TYPE_NORMAL, type, null, null);
- Item result = get(key);
- if (result == null) {
- result = addType(key);
- }
- return result.index;
- }
-
- /**
- * Adds the given "uninitialized" type to {@link #typeTable} and returns its index. This method is used for
- * UNINITIALIZED types, made of an internal name and a bytecode offset.
- *
- * @param type the internal name to be added to the type table.
- * @param offset the bytecode offset of the NEW instruction that created this UNINITIALIZED type value.
- * @return the index of this internal name in the type table.
- */
- int addUninitializedType(final String type, final int offset) {
- key.type = TYPE_UNINIT;
- key.intVal = offset;
- key.strVal1 = type;
- key.hashCode = 0x7FFFFFFF & (TYPE_UNINIT + type.hashCode() + offset);
- Item result = get(key);
- if (result == null) {
- result = addType(key);
- }
- return result.index;
- }
-
- /**
- * Adds the given Item to {@link #typeTable}.
- *
- * @param item the value to be added to the type table.
- * @return the added Item, which a new Item instance with the same value as the given Item.
- */
- private Item addType(final Item item) {
- ++typeCount;
- Item result = new Item(typeCount, key);
- put(result);
- if (typeTable == null) {
- typeTable = new Item[16];
- }
- if (typeCount == typeTable.length) {
- Item[] newTable = new Item[2 * typeTable.length];
- System.arraycopy(typeTable, 0, newTable, 0, typeTable.length);
- typeTable = newTable;
- }
- typeTable[typeCount] = result;
- return result;
- }
-
- /**
- * Returns the index of the common super type of the two given types. This method calls {@link #getCommonSuperClass}
- * and caches the result in the {@link #items} hash table to speedup future calls with the same parameters.
- *
- * @param type1 index of an internal name in {@link #typeTable}.
- * @param type2 index of an internal name in {@link #typeTable}.
- * @return the index of the common super type of the two given types.
- */
- int getMergedType(final int type1, final int type2) {
- key2.type = TYPE_MERGED;
- key2.longVal = type1 | (((long) type2) << 32);
- key2.hashCode = 0x7FFFFFFF & (TYPE_MERGED + type1 + type2);
- Item result = get(key2);
- if (result == null) {
- String t = typeTable[type1].strVal1;
- String u = typeTable[type2].strVal1;
- key2.intVal = addType(getCommonSuperClass(t, u));
- result = new Item((short) 0, key2);
- put(result);
- }
- return result.intVal;
- }
-
- /**
- * Returns the common super type of the two given types. The default implementation of this method loads the
- * two given classes and uses the java.lang.Class methods to find the common super class. It can be overridden to
- * compute this common super type in other ways, in particular without actually loading any class, or to take into
- * account the class that is currently being generated by this ClassWriter, which can of course not be loaded since
- * it is under construction.
- *
- * @param type1 the internal name of a class.
- * @param type2 the internal name of another class.
- * @return the internal name of the common super class of the two given classes.
- */
- protected String getCommonSuperClass(final String type1, final String type2) {
- Class> c, d;
- ClassLoader classLoader = getClass().getClassLoader();
- try {
- c = Class.forName(type1.replace('/', '.'), false, classLoader);
- d = Class.forName(type2.replace('/', '.'), false, classLoader);
- } catch (Exception e) {
- throw new RuntimeException(e.toString());
- }
- if (c.isAssignableFrom(d)) {
- return type1;
- }
- if (d.isAssignableFrom(c)) {
- return type2;
- }
- if (c.isInterface() || d.isInterface()) {
- return "java/lang/Object";
- } else {
- do {
- c = c.getSuperclass();
- } while (!c.isAssignableFrom(d));
- return c.getName().replace('.', '/');
- }
- }
-
- /**
- * Returns the constant pool's hash table item which is equal to the given item.
- *
- * @param key a constant pool item.
- * @return the constant pool's hash table item which is equal to the given item, or <tt>null</tt> if
- * there is no such item.
- */
- private Item get(final Item key) {
- Item i = items[key.hashCode % items.length];
- while (i != null && (i.type != key.type || !key.isEqualTo(i))) {
- i = i.next;
- }
- return i;
- }
-
- /**
- * Puts the given item in the constant pool's hash table. The hash table must not already contains this item.
- *
- * @param i the item to be added to the constant pool's hash table.
- */
- private void put(final Item i) {
- if (index + typeCount > threshold) {
- int ll = items.length;
- int nl = ll * 2 + 1;
- Item[] newItems = new Item[nl];
- for (int l = ll - 1; l >= 0; --l) {
- Item j = items[l];
- while (j != null) {
- int index = j.hashCode % newItems.length;
- Item k = j.next;
- j.next = newItems[index];
- newItems[index] = j;
- j = k;
- }
- }
- items = newItems;
- threshold = (int) (nl * 0.75);
- }
- int index = i.hashCode % items.length;
- i.next = items[index];
- items[index] = i;
- }
-
- /**
- * Puts one byte and two shorts into the constant pool.
- *
- * @param b a byte.
- * @param s1 a short.
- * @param s2 another short.
- */
- private void put122(final int b, final int s1, final int s2) {
- pool.put12(b, s1).putShort(s2);
- }
-
- /**
- * Puts two bytes and one short into the constant pool.
- *
- * @param b1 a byte.
- * @param b2 another byte.
- * @param s a short.
- */
- private void put112(final int b1, final int b2, final int s) {
- pool.put11(b1, b2).putShort(s);
- }
-}
+/*
+ * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ */
+
+/*
+ *
+ *
+ *
+ *
+ *
+ * ASM: a very small and fast Java bytecode manipulation framework
+ * Copyright (c) 2000-2011 INRIA, France Telecom
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.redkale.asm;
+
+/**
+ * A {@link ClassVisitor} that generates classes in bytecode form. More precisely this visitor generates a byte array
+ * conforming to the Java class file format. It can be used alone, to generate a Java class "from scratch", or with one
+ * or more {@link ClassReader ClassReader} and adapter class visitor to generate a modified class from one or more
+ * existing Java classes.
+ *
+ * @author Eric Bruneton
+ */
+public class ClassWriter extends ClassVisitor {
+
+ /**
+ * Flag to automatically compute the maximum stack size and the maximum number of local variables of methods. If
+ * this flag is set, then the arguments of the {@link MethodVisitor#visitMaxs visitMaxs} method of the
+ * {@link MethodVisitor} returned by the {@link #visitMethod visitMethod} method will be ignored, and computed
+ * automatically from the signature and the bytecode of each method.
+ *
+ * @see #ClassWriter(int)
+ */
+ public static final int COMPUTE_MAXS = 1;
+
+ /**
+ * Flag to automatically compute the stack map frames of methods from scratch. If this flag is set, then the calls
+ * to the {@link MethodVisitor#visitFrame} method are ignored, and the stack map frames are recomputed from the
+ * methods bytecode. The arguments of the {@link MethodVisitor#visitMaxs visitMaxs} method are also ignored and
+ * recomputed from the bytecode. In other words, COMPUTE_FRAMES implies COMPUTE_MAXS.
+ *
+ * @see #ClassWriter(int)
+ */
+ public static final int COMPUTE_FRAMES = 2;
+
+ /** Pseudo access flag to distinguish between the synthetic attribute and the synthetic access flag. */
+ static final int ACC_SYNTHETIC_ATTRIBUTE = 0x40000;
+
+ /** Factor to convert from ACC_SYNTHETIC_ATTRIBUTE to Opcode.ACC_SYNTHETIC. */
+ static final int TO_ACC_SYNTHETIC = ACC_SYNTHETIC_ATTRIBUTE / Opcodes.ACC_SYNTHETIC;
+
+ /** The type of instructions without any argument. */
+ static final int NOARG_INSN = 0;
+
+ /** The type of instructions with an signed byte argument. */
+ static final int SBYTE_INSN = 1;
+
+ /** The type of instructions with an signed short argument. */
+ static final int SHORT_INSN = 2;
+
+ /** The type of instructions with a local variable index argument. */
+ static final int VAR_INSN = 3;
+
+ /** The type of instructions with an implicit local variable index argument. */
+ static final int IMPLVAR_INSN = 4;
+
+ /** The type of instructions with a type descriptor argument. */
+ static final int TYPE_INSN = 5;
+
+ /** The type of field and method invocations instructions. */
+ static final int FIELDORMETH_INSN = 6;
+
+ /** The type of the INVOKEINTERFACE/INVOKEDYNAMIC instruction. */
+ static final int ITFMETH_INSN = 7;
+
+ /** The type of the INVOKEDYNAMIC instruction. */
+ static final int INDYMETH_INSN = 8;
+
+ /** The type of instructions with a 2 bytes bytecode offset label. */
+ static final int LABEL_INSN = 9;
+
+ /** The type of instructions with a 4 bytes bytecode offset label. */
+ static final int LABELW_INSN = 10;
+
+ /** The type of the LDC instruction. */
+ static final int LDC_INSN = 11;
+
+ /** The type of the LDC_W and LDC2_W instructions. */
+ static final int LDCW_INSN = 12;
+
+ /** The type of the IINC instruction. */
+ static final int IINC_INSN = 13;
+
+ /** The type of the TABLESWITCH instruction. */
+ static final int TABL_INSN = 14;
+
+ /** The type of the LOOKUPSWITCH instruction. */
+ static final int LOOK_INSN = 15;
+
+ /** The type of the MULTIANEWARRAY instruction. */
+ static final int MANA_INSN = 16;
+
+ /** The type of the WIDE instruction. */
+ static final int WIDE_INSN = 17;
+
+ /** The type of the ASM pseudo instructions with an unsigned 2 bytes offset label (see Label#resolve). */
+ static final int ASM_LABEL_INSN = 18;
+
+ /** The type of the ASM pseudo instructions with a 4 bytes offset label. */
+ static final int ASM_LABELW_INSN = 19;
+
+ /**
+ * Represents a frame inserted between already existing frames. This kind of frame can only be used if the frame
+ * content can be computed from the previous existing frame and from the instructions between this existing frame
+ * and the inserted one, without any knowledge of the type hierarchy. This kind of frame is only used when an
+ * unconditional jump is inserted in a method while expanding an ASM pseudo instruction (see ClassReader).
+ */
+ static final int F_INSERT = 256;
+
+ /** The instruction types of all JVM opcodes. */
+ static final byte[] TYPE;
+
+ /** The type of CONSTANT_Class constant pool items. */
+ static final int CLASS = 7;
+
+ /** The type of CONSTANT_Fieldref constant pool items. */
+ static final int FIELD = 9;
+
+ /** The type of CONSTANT_Methodref constant pool items. */
+ static final int METH = 10;
+
+ /** The type of CONSTANT_InterfaceMethodref constant pool items. */
+ static final int IMETH = 11;
+
+ /** The type of CONSTANT_String constant pool items. */
+ static final int STR = 8;
+
+ /** The type of CONSTANT_Integer constant pool items. */
+ static final int INT = 3;
+
+ /** The type of CONSTANT_Float constant pool items. */
+ static final int FLOAT = 4;
+
+ /** The type of CONSTANT_Long constant pool items. */
+ static final int LONG = 5;
+
+ /** The type of CONSTANT_Double constant pool items. */
+ static final int DOUBLE = 6;
+
+ /** The type of CONSTANT_NameAndType constant pool items. */
+ static final int NAME_TYPE = 12;
+
+ /** The type of CONSTANT_Utf8 constant pool items. */
+ static final int UTF8 = 1;
+
+ /** The type of CONSTANT_MethodType constant pool items. */
+ static final int MTYPE = 16;
+
+ /** The type of CONSTANT_MethodHandle constant pool items. */
+ static final int HANDLE = 15;
+
+ /** The type of CONSTANT_InvokeDynamic constant pool items. */
+ static final int INDY = 18;
+
+ /** The type of CONSTANT_Module constant pool items. */
+ static final int MODULE = 19;
+
+ /** The type of CONSTANT_Package constant pool items. */
+ static final int PACKAGE = 20;
+
+ /**
+ * The base value for all CONSTANT_MethodHandle constant pool items. Internally, ASM store the 9 variations of
+ * CONSTANT_MethodHandle into 9 different items (from 21 to 29).
+ */
+ static final int HANDLE_BASE = 20;
+
+ /**
+ * Normal type Item stored in the ClassWriter {@link ClassWriter#typeTable}, instead of the constant pool, in order
+ * to avoid clashes with normal constant pool items in the ClassWriter constant pool's hash table.
+ */
+ static final int TYPE_NORMAL = 30;
+
+ /**
+ * Uninitialized type Item stored in the ClassWriter {@link ClassWriter#typeTable}, instead of the constant pool, in
+ * order to avoid clashes with normal constant pool items in the ClassWriter constant pool's hash table.
+ */
+ static final int TYPE_UNINIT = 31;
+
+ /**
+ * Merged type Item stored in the ClassWriter {@link ClassWriter#typeTable}, instead of the constant pool, in order
+ * to avoid clashes with normal constant pool items in the ClassWriter constant pool's hash table.
+ */
+ static final int TYPE_MERGED = 32;
+
+ /**
+ * The type of BootstrapMethods items. These items are stored in a special class attribute named BootstrapMethods
+ * and not in the constant pool.
+ */
+ static final int BSM = 33;
+
+ /** The class reader from which this class writer was constructed, if any. */
+ ClassReader cr;
+
+ /** Minor and major version numbers of the class to be generated. */
+ int version;
+
+ /** Index of the next item to be added in the constant pool. */
+ int index;
+
+ /** The constant pool of this class. */
+ final ByteVector pool;
+
+ /** The constant pool's hash table data. */
+ Item[] items;
+
+ /** The threshold of the constant pool's hash table. */
+ int threshold;
+
+ /** A reusable key used to look for items in the {@link #items} hash table. */
+ final Item key;
+
+ /** A reusable key used to look for items in the {@link #items} hash table. */
+ final Item key2;
+
+ /** A reusable key used to look for items in the {@link #items} hash table. */
+ final Item key3;
+
+ /** A reusable key used to look for items in the {@link #items} hash table. */
+ final Item key4;
+
+ /**
+ * A type table used to temporarily store internal names that will not necessarily be stored in the constant pool.
+ * This type table is used by the control flow and data flow analysis algorithm used to compute stack map frames
+ * from scratch. This array associates to each index <tt>i</tt> the Item whose index is
+ * <tt>i</tt>. All Item objects stored in this array are also stored in the {@link #items} hash
+ * table. These two arrays allow to retrieve an Item from its index or, conversely, to get the index of an Item from
+ * its value. Each Item stores an internal name in its {@link Item#strVal1} field.
+ */
+ Item[] typeTable;
+
+ /** Number of elements in the {@link #typeTable} array. */
+ private short typeCount;
+
+ /** The access flags of this class. */
+ private int access;
+
+ /** The constant pool item that contains the internal name of this class. */
+ private int name;
+
+ /** The internal name of this class. */
+ String thisName;
+
+ /** The constant pool item that contains the signature of this class. */
+ private int signature;
+
+ /** The constant pool item that contains the internal name of the super class of this class. */
+ private int superName;
+
+ /** Number of interfaces implemented or extended by this class or interface. */
+ private int interfaceCount;
+
+ /**
+ * The interfaces implemented or extended by this class or interface. More precisely, this array contains the
+ * indexes of the constant pool items that contain the internal names of these interfaces.
+ */
+ private int[] interfaces;
+
+ /**
+ * The index of the constant pool item that contains the name of the source file from which this class was compiled.
+ */
+ private int sourceFile;
+
+ /** The SourceDebug attribute of this class. */
+ private ByteVector sourceDebug;
+
+ /** The module attribute of this class. */
+ private ModuleWriter moduleWriter;
+
+ /** The constant pool item that contains the name of the enclosing class of this class. */
+ private int enclosingMethodOwner;
+
+ /** The constant pool item that contains the name and descriptor of the enclosing method of this class. */
+ private int enclosingMethod;
+
+ /** The runtime visible annotations of this class. */
+ private AnnotationWriter anns;
+
+ /** The runtime invisible annotations of this class. */
+ private AnnotationWriter ianns;
+
+ /** The runtime visible type annotations of this class. */
+ private AnnotationWriter tanns;
+
+ /** The runtime invisible type annotations of this class. */
+ private AnnotationWriter itanns;
+
+ /** The non standard attributes of this class. */
+ private Attribute attrs;
+
+ /** The number of entries in the InnerClasses attribute. */
+ private int innerClassesCount;
+
+ /** The InnerClasses attribute. */
+ private ByteVector innerClasses;
+
+ /** The number of entries in the BootstrapMethods attribute. */
+ int bootstrapMethodsCount;
+
+ /** The BootstrapMethods attribute. */
+ ByteVector bootstrapMethods;
+
+ /**
+ * The fields of this class. These fields are stored in a linked list of {@link FieldWriter} objects, linked to each
+ * other by their {@link FieldWriter#fv} field. This field stores the first element of this list.
+ */
+ FieldWriter firstField;
+
+ /**
+ * The fields of this class. These fields are stored in a linked list of {@link FieldWriter} objects, linked to each
+ * other by their {@link FieldWriter#fv} field. This field stores the last element of this list.
+ */
+ FieldWriter lastField;
+
+ /**
+ * The methods of this class. These methods are stored in a linked list of {@link MethodWriter} objects, linked to
+ * each other by their {@link MethodWriter#mv} field. This field stores the first element of this list.
+ */
+ MethodWriter firstMethod;
+
+ /**
+ * The methods of this class. These methods are stored in a linked list of {@link MethodWriter} objects, linked to
+ * each other by their {@link MethodWriter#mv} field. This field stores the last element of this list.
+ */
+ MethodWriter lastMethod;
+
+ /**
+ * Indicates what must be automatically computed.
+ *
+ * @see MethodWriter#compute
+ */
+ private int compute;
+
+ /**
+ * <tt>true</tt> if some methods have wide forward jumps using ASM pseudo instructions, which need
+ * to be expanded into sequences of standard bytecode instructions. In this case the class is re-read and re-written
+ * with a ClassReader -> ClassWriter chain to perform this transformation.
+ */
+ boolean hasAsmInsns;
+
+ // ------------------------------------------------------------------------
+ // Static initializer
+ // ------------------------------------------------------------------------
+
+ /** Computes the instruction types of JVM opcodes. */
+ static {
+ int i;
+ byte[] b = new byte[221];
+ String s = "AAAAAAAAAAAAAAAABCLMMDDDDDEEEEEEEEEEEEEEEEEEEEAAAAAAAADD"
+ + "DDDEEEEEEEEEEEEEEEEEEEEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+ + "AAAAAAAAAAAAAAAAANAAAAAAAAAAAAAAAAAAAAJJJJJJJJJJJJJJJJDOPAA"
+ + "AAAAGGGGGGGHIFBFAAFFAARQJJKKSSSSSSSSSSSSSSSSSST";
+ for (i = 0; i < b.length; ++i) {
+ b[i] = (byte) (s.charAt(i) - 'A');
+ }
+ TYPE = b;
+
+ // code to generate the above string
+ //
+ // // SBYTE_INSN instructions
+ // b[Constants.NEWARRAY] = SBYTE_INSN;
+ // b[Constants.BIPUSH] = SBYTE_INSN;
+ //
+ // // SHORT_INSN instructions
+ // b[Constants.SIPUSH] = SHORT_INSN;
+ //
+ // // (IMPL)VAR_INSN instructions
+ // b[Constants.RET] = VAR_INSN;
+ // for (i = Constants.ILOAD; i <= Constants.ALOAD; ++i) {
+ // b[i] = VAR_INSN;
+ // }
+ // for (i = Constants.ISTORE; i <= Constants.ASTORE; ++i) {
+ // b[i] = VAR_INSN;
+ // }
+ // for (i = 26; i <= 45; ++i) { // ILOAD_0 to ALOAD_3
+ // b[i] = IMPLVAR_INSN;
+ // }
+ // for (i = 59; i <= 78; ++i) { // ISTORE_0 to ASTORE_3
+ // b[i] = IMPLVAR_INSN;
+ // }
+ //
+ // // TYPE_INSN instructions
+ // b[Constants.NEW] = TYPE_INSN;
+ // b[Constants.ANEWARRAY] = TYPE_INSN;
+ // b[Constants.CHECKCAST] = TYPE_INSN;
+ // b[Constants.INSTANCEOF] = TYPE_INSN;
+ //
+ // // (Set)FIELDORMETH_INSN instructions
+ // for (i = Constants.GETSTATIC; i <= Constants.INVOKESTATIC; ++i) {
+ // b[i] = FIELDORMETH_INSN;
+ // }
+ // b[Constants.INVOKEINTERFACE] = ITFMETH_INSN;
+ // b[Constants.INVOKEDYNAMIC] = INDYMETH_INSN;
+ //
+ // // LABEL(W)_INSN instructions
+ // for (i = Constants.IFEQ; i <= Constants.JSR; ++i) {
+ // b[i] = LABEL_INSN;
+ // }
+ // b[Constants.IFNULL] = LABEL_INSN;
+ // b[Constants.IFNONNULL] = LABEL_INSN;
+ // b[200] = LABELW_INSN; // GOTO_W
+ // b[201] = LABELW_INSN; // JSR_W
+ // // temporary opcodes used internally by ASM - see Label and
+ // MethodWriter
+ // for (i = 202; i < 220; ++i) {
+ // b[i] = ASM_LABEL_INSN;
+ // }
+ // b[220] = ASM_LABELW_INSN;
+ //
+ // // LDC(_W) instructions
+ // b[Constants.LDC] = LDC_INSN;
+ // b[19] = LDCW_INSN; // LDC_W
+ // b[20] = LDCW_INSN; // LDC2_W
+ //
+ // // special instructions
+ // b[Constants.IINC] = IINC_INSN;
+ // b[Constants.TABLESWITCH] = TABL_INSN;
+ // b[Constants.LOOKUPSWITCH] = LOOK_INSN;
+ // b[Constants.MULTIANEWARRAY] = MANA_INSN;
+ // b[196] = WIDE_INSN; // WIDE
+ //
+ // for (i = 0; i < b.length; ++i) {
+ // System.err.print((char)('A' + b[i]));
+ // }
+ // System.err.println();
+ }
+
+ // ------------------------------------------------------------------------
+ // Constructor
+ // ------------------------------------------------------------------------
+
+ /**
+ * Constructs a new {@link ClassWriter} object.
+ *
+ * @param flags option flags that can be used to modify the default behavior of this class. See
+ * {@link #COMPUTE_MAXS}, {@link #COMPUTE_FRAMES}.
+ */
+ public ClassWriter(final int flags) {
+ super(Opcodes.ASM6);
+ index = 1;
+ pool = new ByteVector();
+ items = new Item[256];
+ threshold = (int) (0.75d * items.length);
+ key = new Item();
+ key2 = new Item();
+ key3 = new Item();
+ key4 = new Item();
+ this.compute = (flags & COMPUTE_FRAMES) != 0
+ ? MethodWriter.FRAMES
+ : ((flags & COMPUTE_MAXS) != 0 ? MethodWriter.MAXS : MethodWriter.NOTHING);
+ }
+
+ /**
+ * Constructs a new {@link ClassWriter} object and enables optimizations for "mostly add" bytecode transformations.
+ * These optimizations are the following:
+ *
+ *
+ *
+ *
+ * @param classReader the {@link ClassReader} used to read the original class. It will be used to copy the entire
+ * constant pool from the original class and also to copy other fragments of original bytecode where applicable.
+ * @param flags option flags that can be used to modify the default behavior of this class. These option flags do
+ * not affect methods that are copied as is in the new class. This means that neither the maximum stack size nor
+ * the stack frames will be computed for these methods. See {@link #COMPUTE_MAXS}, {@link #COMPUTE_FRAMES}.
+ */
+ public ClassWriter(final ClassReader classReader, final int flags) {
+ this(flags);
+ classReader.copyPool(this);
+ this.cr = classReader;
+ }
+
+ // ------------------------------------------------------------------------
+ // Implementation of the ClassVisitor abstract class
+ // ------------------------------------------------------------------------
+
+ @Override
+ public final void visit(
+ final int version,
+ final int access,
+ final String name,
+ final String signature,
+ final String superName,
+ final String[] interfaces) {
+ this.version = version;
+ this.access = access;
+ this.name = newClass(name);
+ thisName = name;
+ if (signature != null) {
+ this.signature = newUTF8(signature);
+ }
+ this.superName = superName == null ? 0 : newClass(superName);
+ if (interfaces != null && interfaces.length > 0) {
+ interfaceCount = interfaces.length;
+ this.interfaces = new int[interfaceCount];
+ for (int i = 0; i < interfaceCount; ++i) {
+ this.interfaces[i] = newClass(interfaces[i]);
+ }
+ }
+ }
+
+ @Override
+ public final void visitSource(final String file, final String debug) {
+ if (file != null) {
+ sourceFile = newUTF8(file);
+ }
+ if (debug != null) {
+ sourceDebug = new ByteVector().encodeUTF8(debug, 0, Integer.MAX_VALUE);
+ }
+ }
+
+ @Override
+ public final ModuleVisitor visitModule(final String name, final int access, final String version) {
+ return moduleWriter = new ModuleWriter(this, newModule(name), access, version == null ? 0 : newUTF8(version));
+ }
+
+ @Override
+ public final void visitOuterClass(final String owner, final String name, final String desc) {
+ enclosingMethodOwner = newClass(owner);
+ if (name != null && desc != null) {
+ enclosingMethod = newNameType(name, desc);
+ }
+ }
+
+ @Override
+ public final AnnotationVisitor visitAnnotation(final String desc, final boolean visible) {
+ ByteVector bv = new ByteVector();
+ // write type, and reserve space for values count
+ bv.putShort(newUTF8(desc)).putShort(0);
+ AnnotationWriter aw = new AnnotationWriter(this, true, bv, bv, 2);
+ if (visible) {
+ aw.next = anns;
+ anns = aw;
+ } else {
+ aw.next = ianns;
+ ianns = aw;
+ }
+ return aw;
+ }
+
+ @Override
+ public final AnnotationVisitor visitTypeAnnotation(
+ int typeRef, TypePath typePath, final String desc, final boolean visible) {
+ ByteVector bv = new ByteVector();
+ // write target_type and target_info
+ AnnotationWriter.putTarget(typeRef, typePath, bv);
+ // write type, and reserve space for values count
+ bv.putShort(newUTF8(desc)).putShort(0);
+ AnnotationWriter aw = new AnnotationWriter(this, true, bv, bv, bv.length - 2);
+ if (visible) {
+ aw.next = tanns;
+ tanns = aw;
+ } else {
+ aw.next = itanns;
+ itanns = aw;
+ }
+ return aw;
+ }
+
+ @Override
+ public final void visitAttribute(final Attribute attr) {
+ attr.next = attrs;
+ attrs = attr;
+ }
+
+ @Override
+ public final void visitInnerClass(
+ final String name, final String outerName, final String innerName, final int access) {
+ if (innerClasses == null) {
+ innerClasses = new ByteVector();
+ }
+ // Sec. 4.7.6 of the JVMS states "Every CONSTANT_Class_info entry in the
+ // constant_pool table which represents a class or interface C that is
+ // not a package member must have exactly one corresponding entry in the
+ // classes array". To avoid duplicates we keep track in the intVal field
+ // of the Item of each CONSTANT_Class_info entry C whether an inner
+ // class entry has already been added for C (this field is unused for
+ // class entries, and changing its value does not change the hashcode
+ // and equality tests). If so we store the index of this inner class
+ // entry (plus one) in intVal. This hack allows duplicate detection in
+ // O(1) time.
+ Item nameItem = newStringishItem(CLASS, name);
+ if (nameItem.intVal == 0) {
+ ++innerClassesCount;
+ innerClasses.putShort(nameItem.index);
+ innerClasses.putShort(outerName == null ? 0 : newClass(outerName));
+ innerClasses.putShort(innerName == null ? 0 : newUTF8(innerName));
+ innerClasses.putShort(access);
+ nameItem.intVal = innerClassesCount;
+ } else {
+ // Compare the inner classes entry nameItem.intVal - 1 with the
+ // arguments of this method and throw an exception if there is a
+ // difference?
+ }
+ }
+
+ @Override
+ public final FieldVisitor visitField(
+ final int access, final String name, final String desc, final String signature, final Object value) {
+ return new FieldWriter(this, access, name, desc, signature, value);
+ }
+
+ @Override
+ public final MethodVisitor visitMethod(
+ final int access, final String name, final String desc, final String signature, final String[] exceptions) {
+ return new MethodWriter(this, access, name, desc, signature, exceptions, compute);
+ }
+
+ @Override
+ public final void visitEnd() {
+ // do nothing
+ }
+
+ // ------------------------------------------------------------------------
+ // Other public methods
+ // ------------------------------------------------------------------------
+
+ /**
+ * Returns the bytecode of the class that was build with this class writer.
+ *
+ * @return the bytecode of the class that was build with this class writer.
+ */
+ public byte[] toByteArray() {
+ if (index > 0xFFFF) {
+ throw new RuntimeException("Class file too large!");
+ }
+ // computes the real size of the bytecode of this class
+ int size = 24 + 2 * interfaceCount;
+ int nbFields = 0;
+ FieldWriter fb = firstField;
+ while (fb != null) {
+ ++nbFields;
+ size += fb.getSize();
+ fb = (FieldWriter) fb.fv;
+ }
+ int nbMethods = 0;
+ MethodWriter mb = firstMethod;
+ while (mb != null) {
+ ++nbMethods;
+ size += mb.getSize();
+ mb = (MethodWriter) mb.mv;
+ }
+ int attributeCount = 0;
+ if (bootstrapMethods != null) {
+ // we put it as first attribute in order to improve a bit
+ // ClassReader.copyBootstrapMethods
+ ++attributeCount;
+ size += 8 + bootstrapMethods.length;
+ newUTF8("BootstrapMethods");
+ }
+ if (signature != 0) {
+ ++attributeCount;
+ size += 8;
+ newUTF8("Signature");
+ }
+ if (sourceFile != 0) {
+ ++attributeCount;
+ size += 8;
+ newUTF8("SourceFile");
+ }
+ if (sourceDebug != null) {
+ ++attributeCount;
+ size += sourceDebug.length + 6;
+ newUTF8("SourceDebugExtension");
+ }
+ if (enclosingMethodOwner != 0) {
+ ++attributeCount;
+ size += 10;
+ newUTF8("EnclosingMethod");
+ }
+ if ((access & Opcodes.ACC_DEPRECATED) != 0) {
+ ++attributeCount;
+ size += 6;
+ newUTF8("Deprecated");
+ }
+ if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
+ if ((version & 0xFFFF) < Opcodes.V1_5 || (access & ACC_SYNTHETIC_ATTRIBUTE) != 0) {
+ ++attributeCount;
+ size += 6;
+ newUTF8("Synthetic");
+ }
+ }
+ if (innerClasses != null) {
+ ++attributeCount;
+ size += 8 + innerClasses.length;
+ newUTF8("InnerClasses");
+ }
+ if (anns != null) {
+ ++attributeCount;
+ size += 8 + anns.getSize();
+ newUTF8("RuntimeVisibleAnnotations");
+ }
+ if (ianns != null) {
+ ++attributeCount;
+ size += 8 + ianns.getSize();
+ newUTF8("RuntimeInvisibleAnnotations");
+ }
+ if (tanns != null) {
+ ++attributeCount;
+ size += 8 + tanns.getSize();
+ newUTF8("RuntimeVisibleTypeAnnotations");
+ }
+ if (itanns != null) {
+ ++attributeCount;
+ size += 8 + itanns.getSize();
+ newUTF8("RuntimeInvisibleTypeAnnotations");
+ }
+ if (moduleWriter != null) {
+ attributeCount += 1 + moduleWriter.attributeCount;
+ size += 6 + moduleWriter.size + moduleWriter.attributesSize;
+ newUTF8("Module");
+ }
+ if (attrs != null) {
+ attributeCount += attrs.getCount();
+ size += attrs.getSize(this, null, 0, -1, -1);
+ }
+ size += pool.length;
+ // allocates a byte vector of this size, in order to avoid unnecessary
+ // arraycopy operations in the ByteVector.enlarge() method
+ ByteVector out = new ByteVector(size);
+ out.putInt(0xCAFEBABE).putInt(version);
+ out.putShort(index).putByteArray(pool.data, 0, pool.length);
+ int mask = Opcodes.ACC_DEPRECATED
+ | ACC_SYNTHETIC_ATTRIBUTE
+ | ((access & ACC_SYNTHETIC_ATTRIBUTE) / TO_ACC_SYNTHETIC);
+ out.putShort(access & ~mask).putShort(name).putShort(superName);
+ out.putShort(interfaceCount);
+ for (int i = 0; i < interfaceCount; ++i) {
+ out.putShort(interfaces[i]);
+ }
+ out.putShort(nbFields);
+ fb = firstField;
+ while (fb != null) {
+ fb.put(out);
+ fb = (FieldWriter) fb.fv;
+ }
+ out.putShort(nbMethods);
+ mb = firstMethod;
+ while (mb != null) {
+ mb.put(out);
+ mb = (MethodWriter) mb.mv;
+ }
+ out.putShort(attributeCount);
+ if (bootstrapMethods != null) {
+ out.putShort(newUTF8("BootstrapMethods"));
+ out.putInt(bootstrapMethods.length + 2).putShort(bootstrapMethodsCount);
+ out.putByteArray(bootstrapMethods.data, 0, bootstrapMethods.length);
+ }
+ if (signature != 0) {
+ out.putShort(newUTF8("Signature")).putInt(2).putShort(signature);
+ }
+ if (sourceFile != 0) {
+ out.putShort(newUTF8("SourceFile")).putInt(2).putShort(sourceFile);
+ }
+ if (sourceDebug != null) {
+ int len = sourceDebug.length;
+ out.putShort(newUTF8("SourceDebugExtension")).putInt(len);
+ out.putByteArray(sourceDebug.data, 0, len);
+ }
+ if (moduleWriter != null) {
+ out.putShort(newUTF8("Module"));
+ moduleWriter.put(out);
+ moduleWriter.putAttributes(out);
+ }
+ if (enclosingMethodOwner != 0) {
+ out.putShort(newUTF8("EnclosingMethod")).putInt(4);
+ out.putShort(enclosingMethodOwner).putShort(enclosingMethod);
+ }
+ if ((access & Opcodes.ACC_DEPRECATED) != 0) {
+ out.putShort(newUTF8("Deprecated")).putInt(0);
+ }
+ if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
+ if ((version & 0xFFFF) < Opcodes.V1_5 || (access & ACC_SYNTHETIC_ATTRIBUTE) != 0) {
+ out.putShort(newUTF8("Synthetic")).putInt(0);
+ }
+ }
+ if (innerClasses != null) {
+ out.putShort(newUTF8("InnerClasses"));
+ out.putInt(innerClasses.length + 2).putShort(innerClassesCount);
+ out.putByteArray(innerClasses.data, 0, innerClasses.length);
+ }
+ if (anns != null) {
+ out.putShort(newUTF8("RuntimeVisibleAnnotations"));
+ anns.put(out);
+ }
+ if (ianns != null) {
+ out.putShort(newUTF8("RuntimeInvisibleAnnotations"));
+ ianns.put(out);
+ }
+ if (tanns != null) {
+ out.putShort(newUTF8("RuntimeVisibleTypeAnnotations"));
+ tanns.put(out);
+ }
+ if (itanns != null) {
+ out.putShort(newUTF8("RuntimeInvisibleTypeAnnotations"));
+ itanns.put(out);
+ }
+ if (attrs != null) {
+ attrs.put(this, null, 0, -1, -1, out);
+ }
+ if (hasAsmInsns) {
+ boolean hasFrames = false;
+ mb = firstMethod;
+ while (mb != null) {
+ hasFrames |= mb.frameCount > 0;
+ mb = (MethodWriter) mb.mv;
+ }
+ anns = null;
+ ianns = null;
+ attrs = null;
+ moduleWriter = null;
+ firstField = null;
+ lastField = null;
+ firstMethod = null;
+ lastMethod = null;
+ compute = hasFrames ? MethodWriter.INSERTED_FRAMES : MethodWriter.NOTHING;
+ hasAsmInsns = false;
+ new ClassReader(out.data)
+ .accept(this, (hasFrames ? ClassReader.EXPAND_FRAMES : 0) | ClassReader.EXPAND_ASM_INSNS);
+ return toByteArray();
+ }
+ return out.data;
+ }
+
+ // ------------------------------------------------------------------------
+ // Utility methods: constant pool management
+ // ------------------------------------------------------------------------
+
+ /**
+ * Adds a number or string constant to the constant pool of the class being build. Does nothing if the constant pool
+ * already contains a similar item.
+ *
+ * @param cst the value of the constant to be added to the constant pool. This parameter must be an {@link Integer},
+ * a {@link Float}, a {@link Long}, a {@link Double}, a {@link String} or a {@link Type}.
+ * @return a new or already existing constant item with the given value.
+ */
+ Item newConstItem(final Object cst) {
+ if (cst instanceof Integer) {
+ int val = ((Integer) cst).intValue();
+ return newInteger(val);
+ } else if (cst instanceof Byte) {
+ int val = ((Byte) cst).intValue();
+ return newInteger(val);
+ } else if (cst instanceof Character) {
+ int val = ((Character) cst).charValue();
+ return newInteger(val);
+ } else if (cst instanceof Short) {
+ int val = ((Short) cst).intValue();
+ return newInteger(val);
+ } else if (cst instanceof Boolean) {
+ int val = ((Boolean) cst).booleanValue() ? 1 : 0;
+ return newInteger(val);
+ } else if (cst instanceof Float) {
+ float val = ((Float) cst).floatValue();
+ return newFloat(val);
+ } else if (cst instanceof Long) {
+ long val = ((Long) cst).longValue();
+ return newLong(val);
+ } else if (cst instanceof Double) {
+ double val = ((Double) cst).doubleValue();
+ return newDouble(val);
+ } else if (cst instanceof String) {
+ return newStringishItem(STR, (String) cst);
+ } else if (cst instanceof Type) {
+ Type t = (Type) cst;
+ int s = t.getSort();
+ if (s == Type.OBJECT) {
+ return newStringishItem(CLASS, t.getInternalName());
+ } else if (s == Type.METHOD) {
+ return newStringishItem(MTYPE, t.getDescriptor());
+ } else { // s == primitive type or array
+ return newStringishItem(CLASS, t.getDescriptor());
+ }
+ } else if (cst instanceof Handle) {
+ Handle h = (Handle) cst;
+ return newHandleItem(h.tag, h.owner, h.name, h.desc, h.itf);
+ } else {
+ throw new IllegalArgumentException("value " + cst);
+ }
+ }
+
+ /**
+ * Adds a number or string constant to the constant pool of the class being build. Does nothing if the constant pool
+ * already contains a similar item. This method is intended for {@link Attribute} sub classes, and is normally
+ * not needed by class generators or adapters.
+ *
+ * @param cst the value of the constant to be added to the constant pool. This parameter must be an {@link Integer},
+ * a {@link Float}, a {@link Long}, a {@link Double} or a {@link String}.
+ * @return the index of a new or already existing constant item with the given value.
+ */
+ public int newConst(final Object cst) {
+ return newConstItem(cst).index;
+ }
+
+ /**
+ * Adds an UTF8 string to the constant pool of the class being build. Does nothing if the constant pool already
+ * contains a similar item. This method is intended for {@link Attribute} sub classes, and is normally not needed
+ * by class generators or adapters.
+ *
+ * @param value the String value.
+ * @return the index of a new or already existing UTF8 item.
+ */
+ public int newUTF8(final String value) {
+ key.set(UTF8, value, null, null);
+ Item result = get(key);
+ if (result == null) {
+ pool.putByte(UTF8).putUTF8(value);
+ result = new Item(index++, key);
+ put(result);
+ }
+ return result.index;
+ }
+
+ /**
+ * Adds a string reference, a class reference, a method type, a module or a package to the constant pool of the
+ * class being build. Does nothing if the constant pool already contains a similar item.
+ *
+ * @param type a type among STR, CLASS, MTYPE, MODULE or PACKAGE
+ * @param value string value of the reference.
+ * @return a new or already existing reference item.
+ */
+ Item newStringishItem(final int type, final String value) {
+ key2.set(type, value, null, null);
+ Item result = get(key2);
+ if (result == null) {
+ pool.put12(type, newUTF8(value));
+ result = new Item(index++, key2);
+ put(result);
+ }
+ return result;
+ }
+
+ /**
+ * Adds a class reference to the constant pool of the class being build. Does nothing if the constant pool already
+ * contains a similar item. This method is intended for {@link Attribute} sub classes, and is normally not needed
+ * by class generators or adapters.
+ *
+ * @param value the internal name of the class.
+ * @return the index of a new or already existing class reference item.
+ */
+ public int newClass(final String value) {
+ return newStringishItem(CLASS, value).index;
+ }
+
+ /**
+ * Adds a method type reference to the constant pool of the class being build. Does nothing if the constant pool
+ * already contains a similar item. This method is intended for {@link Attribute} sub classes, and is normally
+ * not needed by class generators or adapters.
+ *
+ * @param methodDesc method descriptor of the method type.
+ * @return the index of a new or already existing method type reference item.
+ */
+ public int newMethodType(final String methodDesc) {
+ return newStringishItem(MTYPE, methodDesc).index;
+ }
+
+ /**
+ * Adds a module reference to the constant pool of the class being build. Does nothing if the constant pool already
+ * contains a similar item. This method is intended for {@link Attribute} sub classes, and is normally not needed
+ * by class generators or adapters.
+ *
+ * @param moduleName name of the module.
+ * @return the index of a new or already existing module reference item.
+ */
+ public int newModule(final String moduleName) {
+ return newStringishItem(MODULE, moduleName).index;
+ }
+
+ /**
+ * Adds a package reference to the constant pool of the class being build. Does nothing if the constant pool already
+ * contains a similar item. This method is intended for {@link Attribute} sub classes, and is normally not needed
+ * by class generators or adapters.
+ *
+ * @param packageName name of the package in its internal form.
+ * @return the index of a new or already existing module reference item.
+ */
+ public int newPackage(final String packageName) {
+ return newStringishItem(PACKAGE, packageName).index;
+ }
+
+ /**
+ * Adds a handle to the constant pool of the class being build. Does nothing if the constant pool already contains a
+ * similar item. This method is intended for {@link Attribute} sub classes, and is normally not needed by class
+ * generators or adapters.
+ *
+ * @param tag the kind of this handle. Must be {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC},
+ * {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL},
+ * {@link Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL}, {@link Opcodes#H_NEWINVOKESPECIAL} or
+ * {@link Opcodes#H_INVOKEINTERFACE}.
+ * @param owner the internal name of the field or method owner class.
+ * @param name the name of the field or method.
+ * @param desc the descriptor of the field or method.
+ * @param itf true if the owner is an interface.
+ * @return a new or an already existing method type reference item.
+ */
+ Item newHandleItem(final int tag, final String owner, final String name, final String desc, final boolean itf) {
+ key4.set(HANDLE_BASE + tag, owner, name, desc);
+ Item result = get(key4);
+ if (result == null) {
+ if (tag <= Opcodes.H_PUTSTATIC) {
+ put112(HANDLE, tag, newField(owner, name, desc));
+ } else {
+ put112(HANDLE, tag, newMethod(owner, name, desc, itf));
+ }
+ result = new Item(index++, key4);
+ put(result);
+ }
+ return result;
+ }
+
+ /**
+ * Adds a handle to the constant pool of the class being build. Does nothing if the constant pool already contains a
+ * similar item. This method is intended for {@link Attribute} sub classes, and is normally not needed by class
+ * generators or adapters.
+ *
+ * @param tag the kind of this handle. Must be {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC},
+ * {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL},
+ * {@link Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL}, {@link Opcodes#H_NEWINVOKESPECIAL} or
+ * {@link Opcodes#H_INVOKEINTERFACE}.
+ * @param owner the internal name of the field or method owner class.
+ * @param name the name of the field or method.
+ * @param desc the descriptor of the field or method.
+ * @param itf true if the owner is an interface.
+ * @return the index of a new or already existing method type reference item.
+ */
+ public int newHandle(final int tag, final String owner, final String name, final String desc, final boolean itf) {
+ return newHandleItem(tag, owner, name, desc, itf).index;
+ }
+
+ /**
+ * Adds an invokedynamic reference to the constant pool of the class being build. Does nothing if the constant pool
+ * already contains a similar item. This method is intended for {@link Attribute} sub classes, and is normally
+ * not needed by class generators or adapters.
+ *
+ * @param name name of the invoked method.
+ * @param desc descriptor of the invoke method.
+ * @param bsm the bootstrap method.
+ * @param bsmArgs the bootstrap method constant arguments.
+ * @return a new or an already existing invokedynamic type reference item.
+ */
+ Item newInvokeDynamicItem(final String name, final String desc, final Handle bsm, final Object... bsmArgs) {
+ // cache for performance
+ ByteVector bootstrapMethods = this.bootstrapMethods;
+ if (bootstrapMethods == null) {
+ bootstrapMethods = this.bootstrapMethods = new ByteVector();
+ }
+
+ int position = bootstrapMethods.length; // record current position
+
+ int hashCode = bsm.hashCode();
+ bootstrapMethods.putShort(newHandle(bsm.tag, bsm.owner, bsm.name, bsm.desc, bsm.isInterface()));
+
+ int argsLength = bsmArgs.length;
+ bootstrapMethods.putShort(argsLength);
+
+ for (int i = 0; i < argsLength; i++) {
+ Object bsmArg = bsmArgs[i];
+ hashCode ^= bsmArg.hashCode();
+ bootstrapMethods.putShort(newConst(bsmArg));
+ }
+
+ byte[] data = bootstrapMethods.data;
+ int length = (1 + 1 + argsLength) << 1; // (bsm + argCount + arguments)
+ hashCode &= 0x7FFFFFFF;
+ Item result = items[hashCode % items.length];
+ loop:
+ while (result != null) {
+ if (result.type != BSM || result.hashCode != hashCode) {
+ result = result.next;
+ continue;
+ }
+
+ // because the data encode the size of the argument
+ // we don't need to test if these size are equals
+ int resultPosition = result.intVal;
+ for (int p = 0; p < length; p++) {
+ if (data[position + p] != data[resultPosition + p]) {
+ result = result.next;
+ continue loop;
+ }
+ }
+ break;
+ }
+
+ int bootstrapMethodIndex;
+ if (result != null) {
+ bootstrapMethodIndex = result.index;
+ bootstrapMethods.length = position; // revert to old position
+ } else {
+ bootstrapMethodIndex = bootstrapMethodsCount++;
+ result = new Item(bootstrapMethodIndex);
+ result.set(position, hashCode);
+ put(result);
+ }
+
+ // now, create the InvokeDynamic constant
+ key3.set(name, desc, bootstrapMethodIndex);
+ result = get(key3);
+ if (result == null) {
+ put122(INDY, bootstrapMethodIndex, newNameType(name, desc));
+ result = new Item(index++, key3);
+ put(result);
+ }
+ return result;
+ }
+
+ /**
+ * Adds an invokedynamic reference to the constant pool of the class being build. Does nothing if the constant pool
+ * already contains a similar item. This method is intended for {@link Attribute} sub classes, and is normally
+ * not needed by class generators or adapters.
+ *
+ * @param name name of the invoked method.
+ * @param desc descriptor of the invoke method.
+ * @param bsm the bootstrap method.
+ * @param bsmArgs the bootstrap method constant arguments.
+ * @return the index of a new or already existing invokedynamic reference item.
+ */
+ public int newInvokeDynamic(final String name, final String desc, final Handle bsm, final Object... bsmArgs) {
+ return newInvokeDynamicItem(name, desc, bsm, bsmArgs).index;
+ }
+
+ /**
+ * Adds a field reference to the constant pool of the class being build. Does nothing if the constant pool already
+ * contains a similar item.
+ *
+ * @param owner the internal name of the field's owner class.
+ * @param name the field's name.
+ * @param desc the field's descriptor.
+ * @return a new or already existing field reference item.
+ */
+ Item newFieldItem(final String owner, final String name, final String desc) {
+ key3.set(FIELD, owner, name, desc);
+ Item result = get(key3);
+ if (result == null) {
+ put122(FIELD, newClass(owner), newNameType(name, desc));
+ result = new Item(index++, key3);
+ put(result);
+ }
+ return result;
+ }
+
+ /**
+ * Adds a field reference to the constant pool of the class being build. Does nothing if the constant pool already
+ * contains a similar item. This method is intended for {@link Attribute} sub classes, and is normally not needed
+ * by class generators or adapters.
+ *
+ * @param owner the internal name of the field's owner class.
+ * @param name the field's name.
+ * @param desc the field's descriptor.
+ * @return the index of a new or already existing field reference item.
+ */
+ public int newField(final String owner, final String name, final String desc) {
+ return newFieldItem(owner, name, desc).index;
+ }
+
+ /**
+ * Adds a method reference to the constant pool of the class being build. Does nothing if the constant pool already
+ * contains a similar item.
+ *
+ * @param owner the internal name of the method's owner class.
+ * @param name the method's name.
+ * @param desc the method's descriptor.
+ * @param itf <tt>true</tt> if <tt>owner</tt> is an interface.
+ * @return a new or already existing method reference item.
+ */
+ Item newMethodItem(final String owner, final String name, final String desc, final boolean itf) {
+ int type = itf ? IMETH : METH;
+ key3.set(type, owner, name, desc);
+ Item result = get(key3);
+ if (result == null) {
+ put122(type, newClass(owner), newNameType(name, desc));
+ result = new Item(index++, key3);
+ put(result);
+ }
+ return result;
+ }
+
+ /**
+ * Adds a method reference to the constant pool of the class being build. Does nothing if the constant pool already
+ * contains a similar item. This method is intended for {@link Attribute} sub classes, and is normally not needed
+ * by class generators or adapters.
+ *
+ * @param owner the internal name of the method's owner class.
+ * @param name the method's name.
+ * @param desc the method's descriptor.
+ * @param itf <tt>true</tt> if <tt>owner</tt> is an interface.
+ * @return the index of a new or already existing method reference item.
+ */
+ public int newMethod(final String owner, final String name, final String desc, final boolean itf) {
+ return newMethodItem(owner, name, desc, itf).index;
+ }
+
+ /**
+ * Adds an integer to the constant pool of the class being build. Does nothing if the constant pool already contains
+ * a similar item.
+ *
+ * @param value the int value.
+ * @return a new or already existing int item.
+ */
+ Item newInteger(final int value) {
+ key.set(value);
+ Item result = get(key);
+ if (result == null) {
+ pool.putByte(INT).putInt(value);
+ result = new Item(index++, key);
+ put(result);
+ }
+ return result;
+ }
+
+ /**
+ * Adds a float to the constant pool of the class being build. Does nothing if the constant pool already contains a
+ * similar item.
+ *
+ * @param value the float value.
+ * @return a new or already existing float item.
+ */
+ Item newFloat(final float value) {
+ key.set(value);
+ Item result = get(key);
+ if (result == null) {
+ pool.putByte(FLOAT).putInt(key.intVal);
+ result = new Item(index++, key);
+ put(result);
+ }
+ return result;
+ }
+
+ /**
+ * Adds a long to the constant pool of the class being build. Does nothing if the constant pool already contains a
+ * similar item.
+ *
+ * @param value the long value.
+ * @return a new or already existing long item.
+ */
+ Item newLong(final long value) {
+ key.set(value);
+ Item result = get(key);
+ if (result == null) {
+ pool.putByte(LONG).putLong(value);
+ result = new Item(index, key);
+ index += 2;
+ put(result);
+ }
+ return result;
+ }
+
+ /**
+ * Adds a double to the constant pool of the class being build. Does nothing if the constant pool already contains a
+ * similar item.
+ *
+ * @param value the double value.
+ * @return a new or already existing double item.
+ */
+ Item newDouble(final double value) {
+ key.set(value);
+ Item result = get(key);
+ if (result == null) {
+ pool.putByte(DOUBLE).putLong(key.longVal);
+ result = new Item(index, key);
+ index += 2;
+ put(result);
+ }
+ return result;
+ }
+
+ /**
+ * Adds a name and type to the constant pool of the class being build. Does nothing if the constant pool already
+ * contains a similar item. This method is intended for {@link Attribute} sub classes, and is normally not needed
+ * by class generators or adapters.
+ *
+ * @param name a name.
+ * @param desc a type descriptor.
+ * @return the index of a new or already existing name and type item.
+ */
+ public int newNameType(final String name, final String desc) {
+ return newNameTypeItem(name, desc).index;
+ }
+
+ /**
+ * Adds a name and type to the constant pool of the class being build. Does nothing if the constant pool already
+ * contains a similar item.
+ *
+ * @param name a name.
+ * @param desc a type descriptor.
+ * @return a new or already existing name and type item.
+ */
+ Item newNameTypeItem(final String name, final String desc) {
+ key2.set(NAME_TYPE, name, desc, null);
+ Item result = get(key2);
+ if (result == null) {
+ put122(NAME_TYPE, newUTF8(name), newUTF8(desc));
+ result = new Item(index++, key2);
+ put(result);
+ }
+ return result;
+ }
+
+ /**
+ * Adds the given internal name to {@link #typeTable} and returns its index. Does nothing if the type table already
+ * contains this internal name.
+ *
+ * @param type the internal name to be added to the type table.
+ * @return the index of this internal name in the type table.
+ */
+ int addType(final String type) {
+ key.set(TYPE_NORMAL, type, null, null);
+ Item result = get(key);
+ if (result == null) {
+ result = addType(key);
+ }
+ return result.index;
+ }
+
+ /**
+ * Adds the given "uninitialized" type to {@link #typeTable} and returns its index. This method is used for
+ * UNINITIALIZED types, made of an internal name and a bytecode offset.
+ *
+ * @param type the internal name to be added to the type table.
+ * @param offset the bytecode offset of the NEW instruction that created this UNINITIALIZED type value.
+ * @return the index of this internal name in the type table.
+ */
+ int addUninitializedType(final String type, final int offset) {
+ key.type = TYPE_UNINIT;
+ key.intVal = offset;
+ key.strVal1 = type;
+ key.hashCode = 0x7FFFFFFF & (TYPE_UNINIT + type.hashCode() + offset);
+ Item result = get(key);
+ if (result == null) {
+ result = addType(key);
+ }
+ return result.index;
+ }
+
+ /**
+ * Adds the given Item to {@link #typeTable}.
+ *
+ * @param item the value to be added to the type table.
+ * @return the added Item, which a new Item instance with the same value as the given Item.
+ */
+ private Item addType(final Item item) {
+ ++typeCount;
+ Item result = new Item(typeCount, key);
+ put(result);
+ if (typeTable == null) {
+ typeTable = new Item[16];
+ }
+ if (typeCount == typeTable.length) {
+ Item[] newTable = new Item[2 * typeTable.length];
+ System.arraycopy(typeTable, 0, newTable, 0, typeTable.length);
+ typeTable = newTable;
+ }
+ typeTable[typeCount] = result;
+ return result;
+ }
+
+ /**
+ * Returns the index of the common super type of the two given types. This method calls {@link #getCommonSuperClass}
+ * and caches the result in the {@link #items} hash table to speedup future calls with the same parameters.
+ *
+ * @param type1 index of an internal name in {@link #typeTable}.
+ * @param type2 index of an internal name in {@link #typeTable}.
+ * @return the index of the common super type of the two given types.
+ */
+ int getMergedType(final int type1, final int type2) {
+ key2.type = TYPE_MERGED;
+ key2.longVal = type1 | (((long) type2) << 32);
+ key2.hashCode = 0x7FFFFFFF & (TYPE_MERGED + type1 + type2);
+ Item result = get(key2);
+ if (result == null) {
+ String t = typeTable[type1].strVal1;
+ String u = typeTable[type2].strVal1;
+ key2.intVal = addType(getCommonSuperClass(t, u));
+ result = new Item((short) 0, key2);
+ put(result);
+ }
+ return result.intVal;
+ }
+
+ /**
+ * Returns the common super type of the two given types. The default implementation of this method loads the
+ * two given classes and uses the java.lang.Class methods to find the common super class. It can be overridden to
+ * compute this common super type in other ways, in particular without actually loading any class, or to take into
+ * account the class that is currently being generated by this ClassWriter, which can of course not be loaded since
+ * it is under construction.
+ *
+ * @param type1 the internal name of a class.
+ * @param type2 the internal name of another class.
+ * @return the internal name of the common super class of the two given classes.
+ */
+ protected String getCommonSuperClass(final String type1, final String type2) {
+ Class> c, d;
+ ClassLoader classLoader = getClass().getClassLoader();
+ try {
+ c = Class.forName(type1.replace('/', '.'), false, classLoader);
+ d = Class.forName(type2.replace('/', '.'), false, classLoader);
+ } catch (Exception e) {
+ throw new RuntimeException(e.toString());
+ }
+ if (c.isAssignableFrom(d)) {
+ return type1;
+ }
+ if (d.isAssignableFrom(c)) {
+ return type2;
+ }
+ if (c.isInterface() || d.isInterface()) {
+ return "java/lang/Object";
+ } else {
+ do {
+ c = c.getSuperclass();
+ } while (!c.isAssignableFrom(d));
+ return c.getName().replace('.', '/');
+ }
+ }
+
+ /**
+ * Returns the constant pool's hash table item which is equal to the given item.
+ *
+ * @param key a constant pool item.
+ * @return the constant pool's hash table item which is equal to the given item, or <tt>null</tt> if
+ * there is no such item.
+ */
+ private Item get(final Item key) {
+ Item i = items[key.hashCode % items.length];
+ while (i != null && (i.type != key.type || !key.isEqualTo(i))) {
+ i = i.next;
+ }
+ return i;
+ }
+
+ /**
+ * Puts the given item in the constant pool's hash table. The hash table must not already contains this item.
+ *
+ * @param i the item to be added to the constant pool's hash table.
+ */
+ private void put(final Item i) {
+ if (index + typeCount > threshold) {
+ int ll = items.length;
+ int nl = ll * 2 + 1;
+ Item[] newItems = new Item[nl];
+ for (int l = ll - 1; l >= 0; --l) {
+ Item j = items[l];
+ while (j != null) {
+ int index = j.hashCode % newItems.length;
+ Item k = j.next;
+ j.next = newItems[index];
+ newItems[index] = j;
+ j = k;
+ }
+ }
+ items = newItems;
+ threshold = (int) (nl * 0.75);
+ }
+ int index = i.hashCode % items.length;
+ i.next = items[index];
+ items[index] = i;
+ }
+
+ /**
+ * Puts one byte and two shorts into the constant pool.
+ *
+ * @param b a byte.
+ * @param s1 a short.
+ * @param s2 another short.
+ */
+ private void put122(final int b, final int s1, final int s2) {
+ pool.put12(b, s1).putShort(s2);
+ }
+
+ /**
+ * Puts two bytes and one short into the constant pool.
+ *
+ * @param b1 a byte.
+ * @param b2 another byte.
+ * @param s a short.
+ */
+ private void put112(final int b1, final int b2, final int s) {
+ pool.put11(b1, b2).putShort(s);
+ }
+}
diff --git a/src/main/java/org/redkale/asm/Context.java b/src/main/java/org/redkale/asm/Context.java
index c3436c682..8e0397895 100644
--- a/src/main/java/org/redkale/asm/Context.java
+++ b/src/main/java/org/redkale/asm/Context.java
@@ -1,143 +1,143 @@
-/*
- * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- */
-
-/*
- *
- *
- *
- *
- *
- * ASM: a very small and fast Java bytecode manipulation framework
- * Copyright (c) 2000-2011 INRIA, France Telecom
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package org.redkale.asm;
-
-/**
- * Information about a class being parsed in a {@link ClassReader}.
- *
- * @author Eric Bruneton
- */
-class Context {
-
- /** Prototypes of the attributes that must be parsed for this class. */
- Attribute[] attrs;
-
- /** The {@link ClassReader} option flags for the parsing of this class. */
- int flags;
-
- /** The buffer used to read strings. */
- char[] buffer;
-
- /** The start index of each bootstrap method. */
- int[] bootstrapMethods;
-
- /** The access flags of the method currently being parsed. */
- int access;
-
- /** The name of the method currently being parsed. */
- String name;
-
- /** The descriptor of the method currently being parsed. */
- String desc;
-
- /**
- * The label objects, indexed by bytecode offset, of the method currently being parsed (only bytecode offsets for
- * which a label is needed have a non null associated Label object).
- */
- Label[] labels;
-
- /** The target of the type annotation currently being parsed. */
- int typeRef;
-
- /** The path of the type annotation currently being parsed. */
- TypePath typePath;
-
- /** The offset of the latest stack map frame that has been parsed. */
- int offset;
-
- /**
- * The labels corresponding to the start of the local variable ranges in the local variable type annotation
- * currently being parsed.
- */
- Label[] start;
-
- /**
- * The labels corresponding to the end of the local variable ranges in the local variable type annotation currently
- * being parsed.
- */
- Label[] end;
-
- /**
- * The local variable indices for each local variable range in the local variable type annotation currently being
- * parsed.
- */
- int[] index;
-
- /** The encoding of the latest stack map frame that has been parsed. */
- int mode;
-
- /** The number of locals in the latest stack map frame that has been parsed. */
- int localCount;
-
- /**
- * The number locals in the latest stack map frame that has been parsed, minus the number of locals in the previous
- * frame.
- */
- int localDiff;
-
- /** The local values of the latest stack map frame that has been parsed. */
- Object[] local;
-
- /** The stack size of the latest stack map frame that has been parsed. */
- int stackCount;
-
- /** The stack values of the latest stack map frame that has been parsed. */
- Object[] stack;
-}
+/*
+ * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ */
+
+/*
+ *
+ *
+ *
+ *
+ *
+ * ASM: a very small and fast Java bytecode manipulation framework
+ * Copyright (c) 2000-2011 INRIA, France Telecom
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.redkale.asm;
+
+/**
+ * Information about a class being parsed in a {@link ClassReader}.
+ *
+ * @author Eric Bruneton
+ */
+class Context {
+
+ /** Prototypes of the attributes that must be parsed for this class. */
+ Attribute[] attrs;
+
+ /** The {@link ClassReader} option flags for the parsing of this class. */
+ int flags;
+
+ /** The buffer used to read strings. */
+ char[] buffer;
+
+ /** The start index of each bootstrap method. */
+ int[] bootstrapMethods;
+
+ /** The access flags of the method currently being parsed. */
+ int access;
+
+ /** The name of the method currently being parsed. */
+ String name;
+
+ /** The descriptor of the method currently being parsed. */
+ String desc;
+
+ /**
+ * The label objects, indexed by bytecode offset, of the method currently being parsed (only bytecode offsets for
+ * which a label is needed have a non null associated Label object).
+ */
+ Label[] labels;
+
+ /** The target of the type annotation currently being parsed. */
+ int typeRef;
+
+ /** The path of the type annotation currently being parsed. */
+ TypePath typePath;
+
+ /** The offset of the latest stack map frame that has been parsed. */
+ int offset;
+
+ /**
+ * The labels corresponding to the start of the local variable ranges in the local variable type annotation
+ * currently being parsed.
+ */
+ Label[] start;
+
+ /**
+ * The labels corresponding to the end of the local variable ranges in the local variable type annotation currently
+ * being parsed.
+ */
+ Label[] end;
+
+ /**
+ * The local variable indices for each local variable range in the local variable type annotation currently being
+ * parsed.
+ */
+ int[] index;
+
+ /** The encoding of the latest stack map frame that has been parsed. */
+ int mode;
+
+ /** The number of locals in the latest stack map frame that has been parsed. */
+ int localCount;
+
+ /**
+ * The number locals in the latest stack map frame that has been parsed, minus the number of locals in the previous
+ * frame.
+ */
+ int localDiff;
+
+ /** The local values of the latest stack map frame that has been parsed. */
+ Object[] local;
+
+ /** The stack size of the latest stack map frame that has been parsed. */
+ int stackCount;
+
+ /** The stack values of the latest stack map frame that has been parsed. */
+ Object[] stack;
+}
diff --git a/src/main/java/org/redkale/asm/CurrentFrame.java b/src/main/java/org/redkale/asm/CurrentFrame.java
index 846fd9b25..329641787 100644
--- a/src/main/java/org/redkale/asm/CurrentFrame.java
+++ b/src/main/java/org/redkale/asm/CurrentFrame.java
@@ -1,83 +1,83 @@
-/*
- * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- */
-
-/*
- *
- *
- *
- *
- *
- * ASM: a very small and fast Java bytecode manipulation framework
- * Copyright (c) 2000-2011 INRIA, France Telecom
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package org.redkale.asm;
-
-/**
- * Information about the input stack map frame at the "current" instruction of a method. This is implemented as a Frame
- * subclass for a "basic block" containing only one instruction.
- *
- * @author Eric Bruneton
- */
-class CurrentFrame extends Frame {
-
- /**
- * Sets this CurrentFrame to the input stack map frame of the next "current" instruction, i.e. the instruction just
- * after the given one. It is assumed that the value of this object when this method is called is the stack map
- * frame status just before the given instruction is executed.
- */
- @Override
- void execute(int opcode, int arg, ClassWriter cw, Item item) {
- super.execute(opcode, arg, cw, item);
- Frame successor = new Frame();
- merge(cw, successor, 0);
- set(successor);
- owner.inputStackTop = 0;
- }
-}
+/*
+ * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ */
+
+/*
+ *
+ *
+ *
+ *
+ *
+ * ASM: a very small and fast Java bytecode manipulation framework
+ * Copyright (c) 2000-2011 INRIA, France Telecom
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.redkale.asm;
+
+/**
+ * Information about the input stack map frame at the "current" instruction of a method. This is implemented as a Frame
+ * subclass for a "basic block" containing only one instruction.
+ *
+ * @author Eric Bruneton
+ */
+class CurrentFrame extends Frame {
+
+ /**
+ * Sets this CurrentFrame to the input stack map frame of the next "current" instruction, i.e. the instruction just
+ * after the given one. It is assumed that the value of this object when this method is called is the stack map
+ * frame status just before the given instruction is executed.
+ */
+ @Override
+ void execute(int opcode, int arg, ClassWriter cw, Item item) {
+ super.execute(opcode, arg, cw, item);
+ Frame successor = new Frame();
+ merge(cw, successor, 0);
+ set(successor);
+ owner.inputStackTop = 0;
+ }
+}
diff --git a/src/main/java/org/redkale/asm/Edge.java b/src/main/java/org/redkale/asm/Edge.java
index c7ea12ac9..57da1c9d9 100644
--- a/src/main/java/org/redkale/asm/Edge.java
+++ b/src/main/java/org/redkale/asm/Edge.java
@@ -1,94 +1,94 @@
-/*
- * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- */
-
-/*
- *
- *
- *
- *
- *
- * ASM: a very small and fast Java bytecode manipulation framework
- * Copyright (c) 2000-2011 INRIA, France Telecom
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-package org.redkale.asm;
-
-/**
- * An edge in the control flow graph of a method body. See {@link Label Label}.
- *
- * @author Eric Bruneton
- */
-class Edge {
-
- /** Denotes a normal control flow graph edge. */
- static final int NORMAL = 0;
-
- /**
- * Denotes a control flow graph edge corresponding to an exception handler. More precisely any {@link Edge} whose
- * {@link #info} is strictly positive corresponds to an exception handler. The actual value of {@link #info} is the
- * index, in the {@link ClassWriter} type table, of the exception that is catched.
- */
- static final int EXCEPTION = 0x7FFFFFFF;
-
- /**
- * Information about this control flow graph edge. If {@link ClassWriter#COMPUTE_MAXS} is used this field is the
- * (relative) stack size in the basic block from which this edge originates. This size is equal to the stack size at
- * the "jump" instruction to which this edge corresponds, relatively to the stack size at the beginning of the
- * originating basic block. If {@link ClassWriter#COMPUTE_FRAMES} is used, this field is the kind of this control
- * flow graph edge (i.e. NORMAL or EXCEPTION).
- */
- int info;
-
- /** The successor block of the basic block from which this edge originates. */
- Label successor;
-
- /**
- * The next edge in the list of successors of the originating basic block. See {@link Label#successors successors}.
- */
- Edge next;
-}
+/*
+ * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ */
+
+/*
+ *
+ *
+ *
+ *
+ *
+ * ASM: a very small and fast Java bytecode manipulation framework
+ * Copyright (c) 2000-2011 INRIA, France Telecom
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.redkale.asm;
+
+/**
+ * An edge in the control flow graph of a method body. See {@link Label Label}.
+ *
+ * @author Eric Bruneton
+ */
+class Edge {
+
+ /** Denotes a normal control flow graph edge. */
+ static final int NORMAL = 0;
+
+ /**
+ * Denotes a control flow graph edge corresponding to an exception handler. More precisely any {@link Edge} whose
+ * {@link #info} is strictly positive corresponds to an exception handler. The actual value of {@link #info} is the
+ * index, in the {@link ClassWriter} type table, of the exception that is catched.
+ */
+ static final int EXCEPTION = 0x7FFFFFFF;
+
+ /**
+ * Information about this control flow graph edge. If {@link ClassWriter#COMPUTE_MAXS} is used this field is the
+ * (relative) stack size in the basic block from which this edge originates. This size is equal to the stack size at
+ * the "jump" instruction to which this edge corresponds, relatively to the stack size at the beginning of the
+ * originating basic block. If {@link ClassWriter#COMPUTE_FRAMES} is used, this field is the kind of this control
+ * flow graph edge (i.e. NORMAL or EXCEPTION).
+ */
+ int info;
+
+ /** The successor block of the basic block from which this edge originates. */
+ Label successor;
+
+ /**
+ * The next edge in the list of successors of the originating basic block. See {@link Label#successors successors}.
+ */
+ Edge next;
+}
diff --git a/src/main/java/org/redkale/asm/FieldVisitor.java b/src/main/java/org/redkale/asm/FieldVisitor.java
index f0af182bf..b506c4da9 100644
--- a/src/main/java/org/redkale/asm/FieldVisitor.java
+++ b/src/main/java/org/redkale/asm/FieldVisitor.java
@@ -1,155 +1,155 @@
-/*
- * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- */
-
-/*
- *
- *
- *
- *
- *
- * ASM: a very small and fast Java bytecode manipulation framework
- * Copyright (c) 2000-2011 INRIA, France Telecom
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-package org.redkale.asm;
-
-/**
- * A visitor to visit a Java field. The methods of this class must be called in the following order: (
- * <tt>visitAnnotation</tt> | <tt>visitTypeAnnotation</tt> |
- * <tt>visitAttribute</tt> )* <tt>visitEnd</tt>.
- *
- * @author Eric Bruneton
- */
-public abstract class FieldVisitor {
-
- /**
- * The ASM API version implemented by this visitor. The value of this field must be one of {@link Opcodes#ASM4},
- * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
- */
- protected final int api;
-
- /** The field visitor to which this visitor must delegate method calls. May be null. */
- protected FieldVisitor fv;
-
- /**
- * Constructs a new {@link FieldVisitor}.
- *
- * @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM4},
- * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
- */
- public FieldVisitor(final int api) {
- this(api, null);
- }
-
- /**
- * Constructs a new {@link FieldVisitor}.
- *
- * @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM4},
- * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
- * @param fv the field visitor to which this visitor must delegate method calls. May be null.
- */
- public FieldVisitor(final int api, final FieldVisitor fv) {
- this.api = api;
- this.fv = fv;
- }
-
- /**
- * Visits an annotation of the field.
- *
- * @param desc the class descriptor of the annotation class.
- * @param visible <tt>true</tt> if the annotation is visible at runtime.
- * @return a visitor to visit the annotation values, or <tt>null</tt> if this visitor is not
- * interested in visiting this annotation.
- */
- public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
- if (fv != null) {
- return fv.visitAnnotation(desc, visible);
- }
- return null;
- }
-
- /**
- * Visits an annotation on the type of the field.
- *
- * @param typeRef a reference to the annotated type. The sort of this type reference must be
- * {@link TypeReference#FIELD FIELD}. See {@link TypeReference}.
- * @param typePath the path to the annotated type argument, wildcard bound, array element type, or static inner type
- * within 'typeRef'. May be <tt>null</tt> if the annotation targets 'typeRef' as a whole.
- * @param desc the class descriptor of the annotation class.
- * @param visible <tt>true</tt> if the annotation is visible at runtime.
- * @return a visitor to visit the annotation values, or <tt>null</tt> if this visitor is not
- * interested in visiting this annotation.
- */
- public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {
- if (fv != null) {
- return fv.visitTypeAnnotation(typeRef, typePath, desc, visible);
- }
- return null;
- }
-
- /**
- * Visits a non standard attribute of the field.
- *
- * @param attr an attribute.
- */
- public void visitAttribute(Attribute attr) {
- if (fv != null) {
- fv.visitAttribute(attr);
- }
- }
-
- /**
- * Visits the end of the field. This method, which is the last one to be called, is used to inform the visitor that
- * all the annotations and attributes of the field have been visited.
- */
- public void visitEnd() {
- if (fv != null) {
- fv.visitEnd();
- }
- }
-}
+/*
+ * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ */
+
+/*
+ *
+ *
+ *
+ *
+ *
+ * ASM: a very small and fast Java bytecode manipulation framework
+ * Copyright (c) 2000-2011 INRIA, France Telecom
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.redkale.asm;
+
+/**
+ * A visitor to visit a Java field. The methods of this class must be called in the following order: (
+ * <tt>visitAnnotation</tt> | <tt>visitTypeAnnotation</tt> |
+ * <tt>visitAttribute</tt> )* <tt>visitEnd</tt>.
+ *
+ * @author Eric Bruneton
+ */
+public abstract class FieldVisitor {
+
+ /**
+ * The ASM API version implemented by this visitor. The value of this field must be one of {@link Opcodes#ASM4},
+ * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
+ */
+ protected final int api;
+
+ /** The field visitor to which this visitor must delegate method calls. May be null. */
+ protected FieldVisitor fv;
+
+ /**
+ * Constructs a new {@link FieldVisitor}.
+ *
+ * @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM4},
+ * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
+ */
+ public FieldVisitor(final int api) {
+ this(api, null);
+ }
+
+ /**
+ * Constructs a new {@link FieldVisitor}.
+ *
+ * @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM4},
+ * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
+ * @param fv the field visitor to which this visitor must delegate method calls. May be null.
+ */
+ public FieldVisitor(final int api, final FieldVisitor fv) {
+ this.api = api;
+ this.fv = fv;
+ }
+
+ /**
+ * Visits an annotation of the field.
+ *
+ * @param desc the class descriptor of the annotation class.
+ * @param visible <tt>true</tt> if the annotation is visible at runtime.
+ * @return a visitor to visit the annotation values, or <tt>null</tt> if this visitor is not
+ * interested in visiting this annotation.
+ */
+ public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+ if (fv != null) {
+ return fv.visitAnnotation(desc, visible);
+ }
+ return null;
+ }
+
+ /**
+ * Visits an annotation on the type of the field.
+ *
+ * @param typeRef a reference to the annotated type. The sort of this type reference must be
+ * {@link TypeReference#FIELD FIELD}. See {@link TypeReference}.
+ * @param typePath the path to the annotated type argument, wildcard bound, array element type, or static inner type
+ * within 'typeRef'. May be <tt>null</tt> if the annotation targets 'typeRef' as a whole.
+ * @param desc the class descriptor of the annotation class.
+ * @param visible <tt>true</tt> if the annotation is visible at runtime.
+ * @return a visitor to visit the annotation values, or <tt>null</tt> if this visitor is not
+ * interested in visiting this annotation.
+ */
+ public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {
+ if (fv != null) {
+ return fv.visitTypeAnnotation(typeRef, typePath, desc, visible);
+ }
+ return null;
+ }
+
+ /**
+ * Visits a non standard attribute of the field.
+ *
+ * @param attr an attribute.
+ */
+ public void visitAttribute(Attribute attr) {
+ if (fv != null) {
+ fv.visitAttribute(attr);
+ }
+ }
+
+ /**
+ * Visits the end of the field. This method, which is the last one to be called, is used to inform the visitor that
+ * all the annotations and attributes of the field have been visited.
+ */
+ public void visitEnd() {
+ if (fv != null) {
+ fv.visitEnd();
+ }
+ }
+}
diff --git a/src/main/java/org/redkale/asm/FieldWriter.java b/src/main/java/org/redkale/asm/FieldWriter.java
index b46c52dbb..afab5f93e 100644
--- a/src/main/java/org/redkale/asm/FieldWriter.java
+++ b/src/main/java/org/redkale/asm/FieldWriter.java
@@ -1,320 +1,320 @@
-/*
- * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- */
-
-/*
- *
- *
- *
- *
- *
- * ASM: a very small and fast Java bytecode manipulation framework
- * Copyright (c) 2000-2011 INRIA, France Telecom
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-package org.redkale.asm;
-
-/**
- * An {@link FieldVisitor} that generates Java fields in bytecode form.
- *
- * @author Eric Bruneton
- */
-final class FieldWriter extends FieldVisitor {
-
- /** The class writer to which this field must be added. */
- private final ClassWriter cw;
-
- /** Access flags of this field. */
- private final int access;
-
- /** The index of the constant pool item that contains the name of this method. */
- private final int name;
-
- /** The index of the constant pool item that contains the descriptor of this field. */
- private final int desc;
-
- /** The index of the constant pool item that contains the signature of this field. */
- private int signature;
-
- /** The index of the constant pool item that contains the constant value of this field. */
- private int value;
-
- /** The runtime visible annotations of this field. May be <tt>null</tt>. */
- private AnnotationWriter anns;
-
- /** The runtime invisible annotations of this field. May be <tt>null</tt>. */
- private AnnotationWriter ianns;
-
- /** The runtime visible type annotations of this field. May be <tt>null</tt>. */
- private AnnotationWriter tanns;
-
- /** The runtime invisible type annotations of this field. May be <tt>null</tt>. */
- private AnnotationWriter itanns;
-
- /** The non standard attributes of this field. May be <tt>null</tt>. */
- private Attribute attrs;
-
- // ------------------------------------------------------------------------
- // Constructor
- // ------------------------------------------------------------------------
-
- /**
- * Constructs a new {@link FieldWriter}.
- *
- * @param cw the class writer to which this field must be added.
- * @param access the field's access flags (see {@link Opcodes}).
- * @param name the field's name.
- * @param desc the field's descriptor (see {@link Type}).
- * @param signature the field's signature. May be <tt>null</tt>.
- * @param value the field's constant value. May be <tt>null</tt>.
- */
- FieldWriter(
- final ClassWriter cw,
- final int access,
- final String name,
- final String desc,
- final String signature,
- final Object value) {
- super(Opcodes.ASM6);
- if (cw.firstField == null) {
- cw.firstField = this;
- } else {
- cw.lastField.fv = this;
- }
- cw.lastField = this;
- this.cw = cw;
- this.access = access;
- this.name = cw.newUTF8(name);
- this.desc = cw.newUTF8(desc);
- if (signature != null) {
- this.signature = cw.newUTF8(signature);
- }
- if (value != null) {
- this.value = cw.newConstItem(value).index;
- }
- }
-
- // ------------------------------------------------------------------------
- // Implementation of the FieldVisitor abstract class
- // ------------------------------------------------------------------------
-
- @Override
- public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) {
- ByteVector bv = new ByteVector();
- // write type, and reserve space for values count
- bv.putShort(cw.newUTF8(desc)).putShort(0);
- AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2);
- if (visible) {
- aw.next = anns;
- anns = aw;
- } else {
- aw.next = ianns;
- ianns = aw;
- }
- return aw;
- }
-
- @Override
- public AnnotationVisitor visitTypeAnnotation(
- final int typeRef, final TypePath typePath, final String desc, final boolean visible) {
- ByteVector bv = new ByteVector();
- // write target_type and target_info
- AnnotationWriter.putTarget(typeRef, typePath, bv);
- // write type, and reserve space for values count
- bv.putShort(cw.newUTF8(desc)).putShort(0);
- AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, bv.length - 2);
- if (visible) {
- aw.next = tanns;
- tanns = aw;
- } else {
- aw.next = itanns;
- itanns = aw;
- }
- return aw;
- }
-
- @Override
- public void visitAttribute(final Attribute attr) {
- attr.next = attrs;
- attrs = attr;
- }
-
- @Override
- public void visitEnd() {
- // do nothing
- }
-
- // ------------------------------------------------------------------------
- // Utility methods
- // ------------------------------------------------------------------------
-
- /**
- * Returns the size of this field.
- *
- * @return the size of this field.
- */
- int getSize() {
- int size = 8;
- if (value != 0) {
- cw.newUTF8("ConstantValue");
- size += 8;
- }
- if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
- if ((cw.version & 0xFFFF) < Opcodes.V1_5 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
- cw.newUTF8("Synthetic");
- size += 6;
- }
- }
- if ((access & Opcodes.ACC_DEPRECATED) != 0) {
- cw.newUTF8("Deprecated");
- size += 6;
- }
- if (signature != 0) {
- cw.newUTF8("Signature");
- size += 8;
- }
- if (anns != null) {
- cw.newUTF8("RuntimeVisibleAnnotations");
- size += 8 + anns.getSize();
- }
- if (ianns != null) {
- cw.newUTF8("RuntimeInvisibleAnnotations");
- size += 8 + ianns.getSize();
- }
- if (tanns != null) {
- cw.newUTF8("RuntimeVisibleTypeAnnotations");
- size += 8 + tanns.getSize();
- }
- if (itanns != null) {
- cw.newUTF8("RuntimeInvisibleTypeAnnotations");
- size += 8 + itanns.getSize();
- }
- if (attrs != null) {
- size += attrs.getSize(cw, null, 0, -1, -1);
- }
- return size;
- }
-
- /**
- * Puts the content of this field into the given byte vector.
- *
- * @param out where the content of this field must be put.
- */
- void put(final ByteVector out) {
- final int FACTOR = ClassWriter.TO_ACC_SYNTHETIC;
- int mask = Opcodes.ACC_DEPRECATED
- | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE
- | ((access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) / FACTOR);
- out.putShort(access & ~mask).putShort(name).putShort(desc);
- int attributeCount = 0;
- if (value != 0) {
- ++attributeCount;
- }
- if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
- if ((cw.version & 0xFFFF) < Opcodes.V1_5 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
- ++attributeCount;
- }
- }
- if ((access & Opcodes.ACC_DEPRECATED) != 0) {
- ++attributeCount;
- }
- if (signature != 0) {
- ++attributeCount;
- }
- if (anns != null) {
- ++attributeCount;
- }
- if (ianns != null) {
- ++attributeCount;
- }
- if (tanns != null) {
- ++attributeCount;
- }
- if (itanns != null) {
- ++attributeCount;
- }
- if (attrs != null) {
- attributeCount += attrs.getCount();
- }
- out.putShort(attributeCount);
- if (value != 0) {
- out.putShort(cw.newUTF8("ConstantValue"));
- out.putInt(2).putShort(value);
- }
- if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
- if ((cw.version & 0xFFFF) < Opcodes.V1_5 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
- out.putShort(cw.newUTF8("Synthetic")).putInt(0);
- }
- }
- if ((access & Opcodes.ACC_DEPRECATED) != 0) {
- out.putShort(cw.newUTF8("Deprecated")).putInt(0);
- }
- if (signature != 0) {
- out.putShort(cw.newUTF8("Signature"));
- out.putInt(2).putShort(signature);
- }
- if (anns != null) {
- out.putShort(cw.newUTF8("RuntimeVisibleAnnotations"));
- anns.put(out);
- }
- if (ianns != null) {
- out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations"));
- ianns.put(out);
- }
- if (tanns != null) {
- out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations"));
- tanns.put(out);
- }
- if (itanns != null) {
- out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations"));
- itanns.put(out);
- }
- if (attrs != null) {
- attrs.put(cw, null, 0, -1, -1, out);
- }
- }
-}
+/*
+ * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ */
+
+/*
+ *
+ *
+ *
+ *
+ *
+ * ASM: a very small and fast Java bytecode manipulation framework
+ * Copyright (c) 2000-2011 INRIA, France Telecom
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.redkale.asm;
+
+/**
+ * An {@link FieldVisitor} that generates Java fields in bytecode form.
+ *
+ * @author Eric Bruneton
+ */
+final class FieldWriter extends FieldVisitor {
+
+ /** The class writer to which this field must be added. */
+ private final ClassWriter cw;
+
+ /** Access flags of this field. */
+ private final int access;
+
+ /** The index of the constant pool item that contains the name of this method. */
+ private final int name;
+
+ /** The index of the constant pool item that contains the descriptor of this field. */
+ private final int desc;
+
+ /** The index of the constant pool item that contains the signature of this field. */
+ private int signature;
+
+ /** The index of the constant pool item that contains the constant value of this field. */
+ private int value;
+
+ /** The runtime visible annotations of this field. May be <tt>null</tt>. */
+ private AnnotationWriter anns;
+
+ /** The runtime invisible annotations of this field. May be <tt>null</tt>. */
+ private AnnotationWriter ianns;
+
+ /** The runtime visible type annotations of this field. May be <tt>null</tt>. */
+ private AnnotationWriter tanns;
+
+ /** The runtime invisible type annotations of this field. May be <tt>null</tt>. */
+ private AnnotationWriter itanns;
+
+ /** The non standard attributes of this field. May be <tt>null</tt>. */
+ private Attribute attrs;
+
+ // ------------------------------------------------------------------------
+ // Constructor
+ // ------------------------------------------------------------------------
+
+ /**
+ * Constructs a new {@link FieldWriter}.
+ *
+ * @param cw the class writer to which this field must be added.
+ * @param access the field's access flags (see {@link Opcodes}).
+ * @param name the field's name.
+ * @param desc the field's descriptor (see {@link Type}).
+ * @param signature the field's signature. May be <tt>null</tt>.
+ * @param value the field's constant value. May be <tt>null</tt>.
+ */
+ FieldWriter(
+ final ClassWriter cw,
+ final int access,
+ final String name,
+ final String desc,
+ final String signature,
+ final Object value) {
+ super(Opcodes.ASM6);
+ if (cw.firstField == null) {
+ cw.firstField = this;
+ } else {
+ cw.lastField.fv = this;
+ }
+ cw.lastField = this;
+ this.cw = cw;
+ this.access = access;
+ this.name = cw.newUTF8(name);
+ this.desc = cw.newUTF8(desc);
+ if (signature != null) {
+ this.signature = cw.newUTF8(signature);
+ }
+ if (value != null) {
+ this.value = cw.newConstItem(value).index;
+ }
+ }
+
+ // ------------------------------------------------------------------------
+ // Implementation of the FieldVisitor abstract class
+ // ------------------------------------------------------------------------
+
+ @Override
+ public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) {
+ ByteVector bv = new ByteVector();
+ // write type, and reserve space for values count
+ bv.putShort(cw.newUTF8(desc)).putShort(0);
+ AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2);
+ if (visible) {
+ aw.next = anns;
+ anns = aw;
+ } else {
+ aw.next = ianns;
+ ianns = aw;
+ }
+ return aw;
+ }
+
+ @Override
+ public AnnotationVisitor visitTypeAnnotation(
+ final int typeRef, final TypePath typePath, final String desc, final boolean visible) {
+ ByteVector bv = new ByteVector();
+ // write target_type and target_info
+ AnnotationWriter.putTarget(typeRef, typePath, bv);
+ // write type, and reserve space for values count
+ bv.putShort(cw.newUTF8(desc)).putShort(0);
+ AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, bv.length - 2);
+ if (visible) {
+ aw.next = tanns;
+ tanns = aw;
+ } else {
+ aw.next = itanns;
+ itanns = aw;
+ }
+ return aw;
+ }
+
+ @Override
+ public void visitAttribute(final Attribute attr) {
+ attr.next = attrs;
+ attrs = attr;
+ }
+
+ @Override
+ public void visitEnd() {
+ // do nothing
+ }
+
+ // ------------------------------------------------------------------------
+ // Utility methods
+ // ------------------------------------------------------------------------
+
+ /**
+ * Returns the size of this field.
+ *
+ * @return the size of this field.
+ */
+ int getSize() {
+ int size = 8;
+ if (value != 0) {
+ cw.newUTF8("ConstantValue");
+ size += 8;
+ }
+ if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
+ if ((cw.version & 0xFFFF) < Opcodes.V1_5 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
+ cw.newUTF8("Synthetic");
+ size += 6;
+ }
+ }
+ if ((access & Opcodes.ACC_DEPRECATED) != 0) {
+ cw.newUTF8("Deprecated");
+ size += 6;
+ }
+ if (signature != 0) {
+ cw.newUTF8("Signature");
+ size += 8;
+ }
+ if (anns != null) {
+ cw.newUTF8("RuntimeVisibleAnnotations");
+ size += 8 + anns.getSize();
+ }
+ if (ianns != null) {
+ cw.newUTF8("RuntimeInvisibleAnnotations");
+ size += 8 + ianns.getSize();
+ }
+ if (tanns != null) {
+ cw.newUTF8("RuntimeVisibleTypeAnnotations");
+ size += 8 + tanns.getSize();
+ }
+ if (itanns != null) {
+ cw.newUTF8("RuntimeInvisibleTypeAnnotations");
+ size += 8 + itanns.getSize();
+ }
+ if (attrs != null) {
+ size += attrs.getSize(cw, null, 0, -1, -1);
+ }
+ return size;
+ }
+
+ /**
+ * Puts the content of this field into the given byte vector.
+ *
+ * @param out where the content of this field must be put.
+ */
+ void put(final ByteVector out) {
+ final int FACTOR = ClassWriter.TO_ACC_SYNTHETIC;
+ int mask = Opcodes.ACC_DEPRECATED
+ | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE
+ | ((access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) / FACTOR);
+ out.putShort(access & ~mask).putShort(name).putShort(desc);
+ int attributeCount = 0;
+ if (value != 0) {
+ ++attributeCount;
+ }
+ if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
+ if ((cw.version & 0xFFFF) < Opcodes.V1_5 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
+ ++attributeCount;
+ }
+ }
+ if ((access & Opcodes.ACC_DEPRECATED) != 0) {
+ ++attributeCount;
+ }
+ if (signature != 0) {
+ ++attributeCount;
+ }
+ if (anns != null) {
+ ++attributeCount;
+ }
+ if (ianns != null) {
+ ++attributeCount;
+ }
+ if (tanns != null) {
+ ++attributeCount;
+ }
+ if (itanns != null) {
+ ++attributeCount;
+ }
+ if (attrs != null) {
+ attributeCount += attrs.getCount();
+ }
+ out.putShort(attributeCount);
+ if (value != 0) {
+ out.putShort(cw.newUTF8("ConstantValue"));
+ out.putInt(2).putShort(value);
+ }
+ if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
+ if ((cw.version & 0xFFFF) < Opcodes.V1_5 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
+ out.putShort(cw.newUTF8("Synthetic")).putInt(0);
+ }
+ }
+ if ((access & Opcodes.ACC_DEPRECATED) != 0) {
+ out.putShort(cw.newUTF8("Deprecated")).putInt(0);
+ }
+ if (signature != 0) {
+ out.putShort(cw.newUTF8("Signature"));
+ out.putInt(2).putShort(signature);
+ }
+ if (anns != null) {
+ out.putShort(cw.newUTF8("RuntimeVisibleAnnotations"));
+ anns.put(out);
+ }
+ if (ianns != null) {
+ out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations"));
+ ianns.put(out);
+ }
+ if (tanns != null) {
+ out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations"));
+ tanns.put(out);
+ }
+ if (itanns != null) {
+ out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations"));
+ itanns.put(out);
+ }
+ if (attrs != null) {
+ attrs.put(cw, null, 0, -1, -1, out);
+ }
+ }
+}
diff --git a/src/main/java/org/redkale/asm/Frame.java b/src/main/java/org/redkale/asm/Frame.java
index 1d67bd8fa..22dae1486 100644
--- a/src/main/java/org/redkale/asm/Frame.java
+++ b/src/main/java/org/redkale/asm/Frame.java
@@ -1,1458 +1,1458 @@
-/*
- * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- */
-
-/*
- *
- *
- *
- *
- *
- * ASM: a very small and fast Java bytecode manipulation framework
- * Copyright (c) 2000-2011 INRIA, France Telecom
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-package org.redkale.asm;
-
-/**
- * Information about the input and output stack map frames of a basic block.
- *
- * @author Eric Bruneton
- */
-class Frame {
-
- /*
- * Frames are computed in a two steps process: during the visit of each
- * instruction, the state of the frame at the end of current basic block is
- * updated by simulating the action of the instruction on the previous state
- * of this so called "output frame". In visitMaxs, a fix point algorithm is
- * used to compute the "input frame" of each basic block, i.e. the stack map
- * frame at the beginning of the basic block, starting from the input frame
- * of the first basic block (which is computed from the method descriptor),
- * and by using the previously computed output frames to compute the input
- * state of the other blocks.
- *
- * All output and input frames are stored as arrays of integers. Reference
- * and array types are represented by an index into a type table (which is
- * not the same as the constant pool of the class, in order to avoid adding
- * unnecessary constants in the pool - not all computed frames will end up
- * being stored in the stack map table). This allows very fast type
- * comparisons.
- *
- * Output stack map frames are computed relatively to the input frame of the
- * basic block, which is not yet known when output frames are computed. It
- * is therefore necessary to be able to represent abstract types such as
- * "the type at position x in the input frame locals" or "the type at
- * position x from the top of the input frame stack" or even "the type at
- * position x in the input frame, with y more (or less) array dimensions".
- * This explains the rather complicated type format used in output frames.
- *
- * This format is the following: DIM KIND VALUE (4, 4 and 24 bits). DIM is a
- * signed number of array dimensions (from -8 to 7). KIND is either BASE,
- * LOCAL or STACK. BASE is used for types that are not relative to the input
- * frame. LOCAL is used for types that are relative to the input local
- * variable types. STACK is used for types that are relative to the input
- * stack types. VALUE depends on KIND. For LOCAL types, it is an index in
- * the input local variable types. For STACK types, it is a position
- * relatively to the top of input frame stack. For BASE types, it is either
- * one of the constants defined below, or for OBJECT and UNINITIALIZED
- * types, a tag and an index in the type table.
- *
- * Output frames can contain types of any kind and with a positive or
- * negative dimension (and even unassigned types, represented by 0 - which
- * does not correspond to any valid type value). Input frames can only
- * contain BASE types of positive or null dimension. In all cases the type
- * table contains only internal type names (array type descriptors are
- * forbidden - dimensions must be represented through the DIM field).
- *
- * The LONG and DOUBLE types are always represented by using two slots (LONG
- * + TOP or DOUBLE + TOP), for local variable types as well as in the
- * operand stack. This is necessary to be able to simulate DUPx_y
- * instructions, whose effect would be dependent on the actual type values
- * if types were always represented by a single slot in the stack (and this
- * is not possible, since actual type values are not always known - cf LOCAL
- * and STACK type kinds).
- */
-
- /** Mask to get the dimension of a frame type. This dimension is a signed integer between -8 and 7. */
- static final int DIM = 0xF0000000;
-
- /** Constant to be added to a type to get a type with one more dimension. */
- static final int ARRAY_OF = 0x10000000;
-
- /** Constant to be added to a type to get a type with one less dimension. */
- static final int ELEMENT_OF = 0xF0000000;
-
- /**
- * Mask to get the kind of a frame type.
- *
- * @see #BASE
- * @see #LOCAL
- * @see #STACK
- */
- static final int KIND = 0xF000000;
-
- /**
- * Flag used for LOCAL and STACK types. Indicates that if this type happens to be a long or double type (during the
- * computations of input frames), then it must be set to TOP because the second word of this value has been reused
- * to store other data in the basic block. Hence the first word no longer stores a valid long or double value.
- */
- static final int TOP_IF_LONG_OR_DOUBLE = 0x800000;
-
- /** Mask to get the value of a frame type. */
- static final int VALUE = 0x7FFFFF;
-
- /** Mask to get the kind of base types. */
- static final int BASE_KIND = 0xFF00000;
-
- /** Mask to get the value of base types. */
- static final int BASE_VALUE = 0xFFFFF;
-
- /** Kind of the types that are not relative to an input stack map frame. */
- static final int BASE = 0x1000000;
-
- /** Base kind of the base reference types. The BASE_VALUE of such types is an index into the type table. */
- static final int OBJECT = BASE | 0x700000;
-
- /**
- * Base kind of the uninitialized base types. The BASE_VALUE of such types in an index into the type table (the Item
- * at that index contains both an instruction offset and an internal class name).
- */
- static final int UNINITIALIZED = BASE | 0x800000;
-
- /**
- * Kind of the types that are relative to the local variable types of an input stack map frame. The value of such
- * types is a local variable index.
- */
- private static final int LOCAL = 0x2000000;
-
- /**
- * Kind of the types that are relative to the stack of an input stack map frame. The value of such types is a
- * position relatively to the top of this stack.
- */
- private static final int STACK = 0x3000000;
-
- /** The TOP type. This is a BASE type. */
- static final int TOP = BASE | 0;
-
- /** The BOOLEAN type. This is a BASE type mainly used for array types. */
- static final int BOOLEAN = BASE | 9;
-
- /** The BYTE type. This is a BASE type mainly used for array types. */
- static final int BYTE = BASE | 10;
-
- /** The CHAR type. This is a BASE type mainly used for array types. */
- static final int CHAR = BASE | 11;
-
- /** The SHORT type. This is a BASE type mainly used for array types. */
- static final int SHORT = BASE | 12;
-
- /** The INTEGER type. This is a BASE type. */
- static final int INTEGER = BASE | 1;
-
- /** The FLOAT type. This is a BASE type. */
- static final int FLOAT = BASE | 2;
-
- /** The DOUBLE type. This is a BASE type. */
- static final int DOUBLE = BASE | 3;
-
- /** The LONG type. This is a BASE type. */
- static final int LONG = BASE | 4;
-
- /** The NULL type. This is a BASE type. */
- static final int NULL = BASE | 5;
-
- /** The UNINITIALIZED_THIS type. This is a BASE type. */
- static final int UNINITIALIZED_THIS = BASE | 6;
-
- /**
- * The stack size variation corresponding to each JVM instruction. This stack variation is equal to the size of the
- * values produced by an instruction, minus the size of the values consumed by this instruction.
- */
- static final int[] SIZE;
-
- /** Computes the stack size variation corresponding to each JVM instruction. */
- static {
- int i;
- int[] b = new int[202];
- String s = "EFFFFFFFFGGFFFGGFFFEEFGFGFEEEEEEEEEEEEEEEEEEEEDEDEDDDDD"
- + "CDCDEEEEEEEEEEEEEEEEEEEEBABABBBBDCFFFGGGEDCDCDCDCDCDCDCDCD"
- + "CDCEEEEDDDDDDDCDCDCEFEFDDEEFFDEDEEEBDDBBDDDDDDCCCCCCCCEFED"
- + "DDCDCDEEEEEEEEEEFEEEEEEDDEEDDEE";
- for (i = 0; i < b.length; ++i) {
- b[i] = s.charAt(i) - 'E';
- }
- SIZE = b;
-
- // code to generate the above string
- //
- // int NA = 0; // not applicable (unused opcode or variable size opcode)
- //
- // b = new int[] {
- // 0, //NOP, // visitInsn
- // 1, //ACONST_NULL, // -
- // 1, //ICONST_M1, // -
- // 1, //ICONST_0, // -
- // 1, //ICONST_1, // -
- // 1, //ICONST_2, // -
- // 1, //ICONST_3, // -
- // 1, //ICONST_4, // -
- // 1, //ICONST_5, // -
- // 2, //LCONST_0, // -
- // 2, //LCONST_1, // -
- // 1, //FCONST_0, // -
- // 1, //FCONST_1, // -
- // 1, //FCONST_2, // -
- // 2, //DCONST_0, // -
- // 2, //DCONST_1, // -
- // 1, //BIPUSH, // visitIntInsn
- // 1, //SIPUSH, // -
- // 1, //LDC, // visitLdcInsn
- // NA, //LDC_W, // -
- // NA, //LDC2_W, // -
- // 1, //ILOAD, // visitVarInsn
- // 2, //LLOAD, // -
- // 1, //FLOAD, // -
- // 2, //DLOAD, // -
- // 1, //ALOAD, // -
- // NA, //ILOAD_0, // -
- // NA, //ILOAD_1, // -
- // NA, //ILOAD_2, // -
- // NA, //ILOAD_3, // -
- // NA, //LLOAD_0, // -
- // NA, //LLOAD_1, // -
- // NA, //LLOAD_2, // -
- // NA, //LLOAD_3, // -
- // NA, //FLOAD_0, // -
- // NA, //FLOAD_1, // -
- // NA, //FLOAD_2, // -
- // NA, //FLOAD_3, // -
- // NA, //DLOAD_0, // -
- // NA, //DLOAD_1, // -
- // NA, //DLOAD_2, // -
- // NA, //DLOAD_3, // -
- // NA, //ALOAD_0, // -
- // NA, //ALOAD_1, // -
- // NA, //ALOAD_2, // -
- // NA, //ALOAD_3, // -
- // -1, //IALOAD, // visitInsn
- // 0, //LALOAD, // -
- // -1, //FALOAD, // -
- // 0, //DALOAD, // -
- // -1, //AALOAD, // -
- // -1, //BALOAD, // -
- // -1, //CALOAD, // -
- // -1, //SALOAD, // -
- // -1, //ISTORE, // visitVarInsn
- // -2, //LSTORE, // -
- // -1, //FSTORE, // -
- // -2, //DSTORE, // -
- // -1, //ASTORE, // -
- // NA, //ISTORE_0, // -
- // NA, //ISTORE_1, // -
- // NA, //ISTORE_2, // -
- // NA, //ISTORE_3, // -
- // NA, //LSTORE_0, // -
- // NA, //LSTORE_1, // -
- // NA, //LSTORE_2, // -
- // NA, //LSTORE_3, // -
- // NA, //FSTORE_0, // -
- // NA, //FSTORE_1, // -
- // NA, //FSTORE_2, // -
- // NA, //FSTORE_3, // -
- // NA, //DSTORE_0, // -
- // NA, //DSTORE_1, // -
- // NA, //DSTORE_2, // -
- // NA, //DSTORE_3, // -
- // NA, //ASTORE_0, // -
- // NA, //ASTORE_1, // -
- // NA, //ASTORE_2, // -
- // NA, //ASTORE_3, // -
- // -3, //IASTORE, // visitInsn
- // -4, //LASTORE, // -
- // -3, //FASTORE, // -
- // -4, //DASTORE, // -
- // -3, //AASTORE, // -
- // -3, //BASTORE, // -
- // -3, //CASTORE, // -
- // -3, //SASTORE, // -
- // -1, //POP, // -
- // -2, //POP2, // -
- // 1, //DUP, // -
- // 1, //DUP_X1, // -
- // 1, //DUP_X2, // -
- // 2, //DUP2, // -
- // 2, //DUP2_X1, // -
- // 2, //DUP2_X2, // -
- // 0, //SWAP, // -
- // -1, //IADD, // -
- // -2, //LADD, // -
- // -1, //FADD, // -
- // -2, //DADD, // -
- // -1, //ISUB, // -
- // -2, //LSUB, // -
- // -1, //FSUB, // -
- // -2, //DSUB, // -
- // -1, //IMUL, // -
- // -2, //LMUL, // -
- // -1, //FMUL, // -
- // -2, //DMUL, // -
- // -1, //IDIV, // -
- // -2, //LDIV, // -
- // -1, //FDIV, // -
- // -2, //DDIV, // -
- // -1, //IREM, // -
- // -2, //LREM, // -
- // -1, //FREM, // -
- // -2, //DREM, // -
- // 0, //INEG, // -
- // 0, //LNEG, // -
- // 0, //FNEG, // -
- // 0, //DNEG, // -
- // -1, //ISHL, // -
- // -1, //LSHL, // -
- // -1, //ISHR, // -
- // -1, //LSHR, // -
- // -1, //IUSHR, // -
- // -1, //LUSHR, // -
- // -1, //IAND, // -
- // -2, //LAND, // -
- // -1, //IOR, // -
- // -2, //LOR, // -
- // -1, //IXOR, // -
- // -2, //LXOR, // -
- // 0, //IINC, // visitIincInsn
- // 1, //I2L, // visitInsn
- // 0, //I2F, // -
- // 1, //I2D, // -
- // -1, //L2I, // -
- // -1, //L2F, // -
- // 0, //L2D, // -
- // 0, //F2I, // -
- // 1, //F2L, // -
- // 1, //F2D, // -
- // -1, //D2I, // -
- // 0, //D2L, // -
- // -1, //D2F, // -
- // 0, //I2B, // -
- // 0, //I2C, // -
- // 0, //I2S, // -
- // -3, //LCMP, // -
- // -1, //FCMPL, // -
- // -1, //FCMPG, // -
- // -3, //DCMPL, // -
- // -3, //DCMPG, // -
- // -1, //IFEQ, // visitJumpInsn
- // -1, //IFNE, // -
- // -1, //IFLT, // -
- // -1, //IFGE, // -
- // -1, //IFGT, // -
- // -1, //IFLE, // -
- // -2, //IF_ICMPEQ, // -
- // -2, //IF_ICMPNE, // -
- // -2, //IF_ICMPLT, // -
- // -2, //IF_ICMPGE, // -
- // -2, //IF_ICMPGT, // -
- // -2, //IF_ICMPLE, // -
- // -2, //IF_ACMPEQ, // -
- // -2, //IF_ACMPNE, // -
- // 0, //GOTO, // -
- // 1, //JSR, // -
- // 0, //RET, // visitVarInsn
- // -1, //TABLESWITCH, // visiTableSwitchInsn
- // -1, //LOOKUPSWITCH, // visitLookupSwitch
- // -1, //IRETURN, // visitInsn
- // -2, //LRETURN, // -
- // -1, //FRETURN, // -
- // -2, //DRETURN, // -
- // -1, //ARETURN, // -
- // 0, //RETURN, // -
- // NA, //GETSTATIC, // visitFieldInsn
- // NA, //PUTSTATIC, // -
- // NA, //GETFIELD, // -
- // NA, //PUTFIELD, // -
- // NA, //INVOKEVIRTUAL, // visitMethodInsn
- // NA, //INVOKESPECIAL, // -
- // NA, //INVOKESTATIC, // -
- // NA, //INVOKEINTERFACE, // -
- // NA, //INVOKEDYNAMIC, // visitInvokeDynamicInsn
- // 1, //NEW, // visitTypeInsn
- // 0, //NEWARRAY, // visitIntInsn
- // 0, //ANEWARRAY, // visitTypeInsn
- // 0, //ARRAYLENGTH, // visitInsn
- // NA, //ATHROW, // -
- // 0, //CHECKCAST, // visitTypeInsn
- // 0, //INSTANCEOF, // -
- // -1, //MONITORENTER, // visitInsn
- // -1, //MONITOREXIT, // -
- // NA, //WIDE, // NOT VISITED
- // NA, //MULTIANEWARRAY, // visitMultiANewArrayInsn
- // -1, //IFNULL, // visitJumpInsn
- // -1, //IFNONNULL, // -
- // NA, //GOTO_W, // -
- // NA, //JSR_W, // -
- // };
- // for (i = 0; i < b.length; ++i) {
- // System.err.print((char)('E' + b[i]));
- // }
- // System.err.println();
- }
-
- /** The label (i.e. basic block) to which these input and output stack map frames correspond. */
- Label owner;
-
- /** The input stack map frame locals. */
- int[] inputLocals;
-
- /** The input stack map frame stack. */
- int[] inputStack;
-
- /** The output stack map frame locals. */
- private int[] outputLocals;
-
- /** The output stack map frame stack. */
- private int[] outputStack;
-
- /**
- * Relative size of the output stack. The exact semantics of this field depends on the algorithm that is used.
- *
- *
- * for a reference to a class:
- * owner '.' name desc ' ' '(' tag ')'
- * for a reference to an interface:
- * owner '.' name desc ' ' '(' tag ' ' itf ')'
- *
- *
- * . As this format is unambiguous, it can be parsed if necessary.
- */
- @Override
- public String toString() {
- return owner + '.' + name + desc + " (" + tag + (itf ? " itf" : "") + ')';
- }
-}
+/*
+ * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ */
+
+/*
+ *
+ *
+ *
+ *
+ *
+ * ASM: a very small and fast Java bytecode manipulation framework
+ * Copyright (c) 2000-2011 INRIA, France Telecom
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.redkale.asm;
+
+/**
+ * A reference to a field or a method.
+ *
+ * @author Remi Forax
+ * @author Eric Bruneton
+ */
+public final class Handle {
+
+ /**
+ * The kind of field or method designated by this Handle. Should be {@link Opcodes#H_GETFIELD},
+ * {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC},
+ * {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL},
+ * {@link Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}.
+ */
+ final int tag;
+
+ /** The internal name of the class that owns the field or method designated by this handle. */
+ final String owner;
+
+ /** The name of the field or method designated by this handle. */
+ final String name;
+
+ /** The descriptor of the field or method designated by this handle. */
+ final String desc;
+
+ /** Indicate if the owner is an interface or not. */
+ final boolean itf;
+
+ /**
+ * Constructs a new field or method handle.
+ *
+ * @param tag the kind of field or method designated by this Handle. Must be {@link Opcodes#H_GETFIELD},
+ * {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC},
+ * {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL},
+ * {@link Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}.
+ * @param owner the internal name of the class that owns the field or method designated by this handle.
+ * @param name the name of the field or method designated by this handle.
+ * @param desc the descriptor of the field or method designated by this handle.
+ * @param itf true if the owner is an interface.
+ */
+ public Handle(int tag, String owner, String name, String desc, boolean itf) {
+ this.tag = tag;
+ this.owner = owner;
+ this.name = name;
+ this.desc = desc;
+ this.itf = itf;
+ }
+
+ /**
+ * Returns the kind of field or method designated by this handle.
+ *
+ * @return {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD},
+ * {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC},
+ * {@link Opcodes#H_INVOKESPECIAL}, {@link Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}.
+ */
+ public int getTag() {
+ return tag;
+ }
+
+ /**
+ * Returns the internal name of the class that owns the field or method designated by this handle.
+ *
+ * @return the internal name of the class that owns the field or method designated by this handle.
+ */
+ public String getOwner() {
+ return owner;
+ }
+
+ /**
+ * Returns the name of the field or method designated by this handle.
+ *
+ * @return the name of the field or method designated by this handle.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Returns the descriptor of the field or method designated by this handle.
+ *
+ * @return the descriptor of the field or method designated by this handle.
+ */
+ public String getDesc() {
+ return desc;
+ }
+
+ /**
+ * Returns true if the owner of the field or method designated by this handle is an interface.
+ *
+ * @return true if the owner of the field or method designated by this handle is an interface.
+ */
+ public boolean isInterface() {
+ return itf;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (!(obj instanceof Handle)) {
+ return false;
+ }
+ Handle h = (Handle) obj;
+ return tag == h.tag && itf == h.itf && owner.equals(h.owner) && name.equals(h.name) && desc.equals(h.desc);
+ }
+
+ @Override
+ public int hashCode() {
+ return tag + (itf ? 64 : 0) + owner.hashCode() * name.hashCode() * desc.hashCode();
+ }
+
+ /**
+ * Returns the textual representation of this handle. The textual representation is:
+ *
+ *
+ * for a reference to a class:
+ * owner '.' name desc ' ' '(' tag ')'
+ * for a reference to an interface:
+ * owner '.' name desc ' ' '(' tag ' ' itf ')'
+ *
+ *
+ * . As this format is unambiguous, it can be parsed if necessary.
+ */
+ @Override
+ public String toString() {
+ return owner + '.' + name + desc + " (" + tag + (itf ? " itf" : "") + ')';
+ }
+}
diff --git a/src/main/java/org/redkale/asm/Handler.java b/src/main/java/org/redkale/asm/Handler.java
index b99109332..fb9f47dcd 100644
--- a/src/main/java/org/redkale/asm/Handler.java
+++ b/src/main/java/org/redkale/asm/Handler.java
@@ -1,138 +1,138 @@
-/*
- * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- */
-
-/*
- *
- *
- *
- *
- *
- * ASM: a very small and fast Java bytecode manipulation framework
- * Copyright (c) 2000-2011 INRIA, France Telecom
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-package org.redkale.asm;
-
-/**
- * Information about an exception handler block.
- *
- * @author Eric Bruneton
- */
-class Handler {
-
- /** Beginning of the exception handler's scope (inclusive). */
- Label start;
-
- /** End of the exception handler's scope (exclusive). */
- Label end;
-
- /** Beginning of the exception handler's code. */
- Label handler;
-
- /**
- * Internal name of the type of exceptions handled by this handler, or <tt>null</tt> to catch any
- * exceptions.
- */
- String desc;
-
- /**
- * Constant pool index of the internal name of the type of exceptions handled by this handler, or 0 to catch any
- * exceptions.
- */
- int type;
-
- /** Next exception handler block info. */
- Handler next;
-
- /**
- * Removes the range between start and end from the given exception handlers.
- *
- * @param h an exception handler list.
- * @param start the start of the range to be removed.
- * @param end the end of the range to be removed. Maybe null.
- * @return the exception handler list with the start-end range removed.
- */
- static Handler remove(Handler h, Label start, Label end) {
- if (h == null) {
- return null;
- } else {
- h.next = remove(h.next, start, end);
- }
- int hstart = h.start.position;
- int hend = h.end.position;
- int s = start.position;
- int e = end == null ? Integer.MAX_VALUE : end.position;
- // if [hstart,hend[ and [s,e[ intervals intersect...
- if (s < hend && e > hstart) {
- if (s <= hstart) {
- if (e >= hend) {
- // [hstart,hend[ fully included in [s,e[, h removed
- h = h.next;
- } else {
- // [hstart,hend[ minus [s,e[ = [e,hend[
- h.start = end;
- }
- } else if (e >= hend) {
- // [hstart,hend[ minus [s,e[ = [hstart,s[
- h.end = start;
- } else {
- // [hstart,hend[ minus [s,e[ = [hstart,s[ + [e,hend[
- Handler g = new Handler();
- g.start = end;
- g.end = h.end;
- g.handler = h.handler;
- g.desc = h.desc;
- g.type = h.type;
- g.next = h.next;
- h.end = start;
- h.next = g;
- }
- }
- return h;
- }
-}
+/*
+ * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ */
+
+/*
+ *
+ *
+ *
+ *
+ *
+ * ASM: a very small and fast Java bytecode manipulation framework
+ * Copyright (c) 2000-2011 INRIA, France Telecom
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.redkale.asm;
+
+/**
+ * Information about an exception handler block.
+ *
+ * @author Eric Bruneton
+ */
+class Handler {
+
+ /** Beginning of the exception handler's scope (inclusive). */
+ Label start;
+
+ /** End of the exception handler's scope (exclusive). */
+ Label end;
+
+ /** Beginning of the exception handler's code. */
+ Label handler;
+
+ /**
+ * Internal name of the type of exceptions handled by this handler, or <tt>null</tt> to catch any
+ * exceptions.
+ */
+ String desc;
+
+ /**
+ * Constant pool index of the internal name of the type of exceptions handled by this handler, or 0 to catch any
+ * exceptions.
+ */
+ int type;
+
+ /** Next exception handler block info. */
+ Handler next;
+
+ /**
+ * Removes the range between start and end from the given exception handlers.
+ *
+ * @param h an exception handler list.
+ * @param start the start of the range to be removed.
+ * @param end the end of the range to be removed. Maybe null.
+ * @return the exception handler list with the start-end range removed.
+ */
+ static Handler remove(Handler h, Label start, Label end) {
+ if (h == null) {
+ return null;
+ } else {
+ h.next = remove(h.next, start, end);
+ }
+ int hstart = h.start.position;
+ int hend = h.end.position;
+ int s = start.position;
+ int e = end == null ? Integer.MAX_VALUE : end.position;
+ // if [hstart,hend[ and [s,e[ intervals intersect...
+ if (s < hend && e > hstart) {
+ if (s <= hstart) {
+ if (e >= hend) {
+ // [hstart,hend[ fully included in [s,e[, h removed
+ h = h.next;
+ } else {
+ // [hstart,hend[ minus [s,e[ = [e,hend[
+ h.start = end;
+ }
+ } else if (e >= hend) {
+ // [hstart,hend[ minus [s,e[ = [hstart,s[
+ h.end = start;
+ } else {
+ // [hstart,hend[ minus [s,e[ = [hstart,s[ + [e,hend[
+ Handler g = new Handler();
+ g.start = end;
+ g.end = h.end;
+ g.handler = h.handler;
+ g.desc = h.desc;
+ g.type = h.type;
+ g.next = h.next;
+ h.end = start;
+ h.next = g;
+ }
+ }
+ return h;
+ }
+}
diff --git a/src/main/java/org/redkale/asm/Item.java b/src/main/java/org/redkale/asm/Item.java
index 453c71ca9..39a624a11 100644
--- a/src/main/java/org/redkale/asm/Item.java
+++ b/src/main/java/org/redkale/asm/Item.java
@@ -1,289 +1,289 @@
-/*
- * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- */
-
-/*
- *
- *
- *
- *
- *
- * ASM: a very small and fast Java bytecode manipulation framework
- * Copyright (c) 2000-2011 INRIA, France Telecom
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-package org.redkale.asm;
-
-/**
- * A constant pool item. Constant pool items can be created with the 'newXXX' methods in the {@link ClassWriter} class.
- *
- * @author Eric Bruneton
- */
-final class Item {
-
- /** Index of this item in the constant pool. */
- int index;
-
- /**
- * Type of this constant pool item. A single class is used to represent all constant pool item types, in order to
- * minimize the bytecode size of this package. The value of this field is one of {@link ClassWriter#INT},
- * {@link ClassWriter#LONG}, {@link ClassWriter#FLOAT}, {@link ClassWriter#DOUBLE}, {@link ClassWriter#UTF8},
- * {@link ClassWriter#STR}, {@link ClassWriter#CLASS}, {@link ClassWriter#NAME_TYPE}, {@link ClassWriter#FIELD},
- * {@link ClassWriter#METH}, {@link ClassWriter#IMETH}, {@link ClassWriter#MODULE}, {@link ClassWriter#PACKAGE},
- * {@link ClassWriter#MTYPE}, {@link ClassWriter#INDY}.
- *
- *
- *
- * (*) this is mandatory only for classes whose version is greater than or equal to {@link Opcodes#V1_6 V1_6}.
- *
- * The frames of a method must be given either in expanded form, or in compressed form (all frames must use the same
- * format, i.e. you must not mix expanded and compressed frames within a single method):
- *
- *
- *
- *
- *
- *
- * nStack is 1 and stack[0] contains value
- * for the type of the stack item).
- * nLocal is 1, 2 or 3 and
- * local elements contains values representing added types).
- * nLocals
- * is 1, 2 or 3).
- *
- * In both cases the first frame, corresponding to the method's parameters and access flags, is implicit and must
- * not be visited. Also, it is illegal to visit two or more frames for the same code location (i.e., at least one
- * instruction must be visited between two calls to visitFrame).
- *
- * @param type the type of this stack map frame. Must be {@link Opcodes#F_NEW} for expanded frames, or
- * {@link Opcodes#F_FULL}, {@link Opcodes#F_APPEND}, {@link Opcodes#F_CHOP}, {@link Opcodes#F_SAME} or
- * {@link Opcodes#F_APPEND}, {@link Opcodes#F_SAME1} for compressed frames.
- * @param nLocal the number of local variables in the visited frame.
- * @param local the local variable types in this frame. This array must not be modified. Primitive types are
- * represented by {@link Opcodes#TOP}, {@link Opcodes#INTEGER}, {@link Opcodes#FLOAT}, {@link Opcodes#LONG},
- * {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or {@link Opcodes#UNINITIALIZED_THIS} (long and double are
- * represented by a single element). Reference types are represented by String objects (representing internal
- * names), and uninitialized types by Label objects (this label designates the NEW instruction that created this
- * uninitialized value).
- * @param nStack the number of operand stack elements in the visited frame.
- * @param stack the operand stack types in this frame. This array must not be modified. Its content has the same
- * format as the "local" array.
- * @throws IllegalStateException if a frame is visited just after another one, without any instruction between the
- * two (unless this frame is a Opcodes#F_SAME frame, in which case it is silently ignored).
- */
- public void visitFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack) {
- if (mv != null) {
- mv.visitFrame(type, nLocal, local, nStack, stack);
- }
- }
-
- // -------------------------------------------------------------------------
- // Normal instructions
- // -------------------------------------------------------------------------
-
- /**
- * Visits a zero operand instruction.
- *
- * @param opcode the opcode of the instruction to be visited. This opcode is either NOP, ACONST_NULL, ICONST_M1,
- * ICONST_0, ICONST_1, ICONST_2, ICONST_3, ICONST_4, ICONST_5, LCONST_0, LCONST_1, FCONST_0, FCONST_1, FCONST_2,
- * DCONST_0, DCONST_1, IALOAD, LALOAD, FALOAD, DALOAD, AALOAD, BALOAD, CALOAD, SALOAD, IASTORE, LASTORE,
- * FASTORE, DASTORE, AASTORE, BASTORE, CASTORE, SASTORE, POP, POP2, DUP, DUP_X1, DUP_X2, DUP2, DUP2_X1, DUP2_X2,
- * SWAP, IADD, LADD, FADD, DADD, ISUB, LSUB, FSUB, DSUB, IMUL, LMUL, FMUL, DMUL, IDIV, LDIV, FDIV, DDIV, IREM,
- * LREM, FREM, DREM, INEG, LNEG, FNEG, DNEG, ISHL, LSHL, ISHR, LSHR, IUSHR, LUSHR, IAND, LAND, IOR, LOR, IXOR,
- * LXOR, I2L, I2F, I2D, L2I, L2F, L2D, F2I, F2L, F2D, D2I, D2L, D2F, I2B, I2C, I2S, LCMP, FCMPL, FCMPG, DCMPL,
- * DCMPG, IRETURN, LRETURN, FRETURN, DRETURN, ARETURN, RETURN, ARRAYLENGTH, ATHROW, MONITORENTER, or
- * MONITOREXIT.
- */
- public void visitInsn(int opcode) {
- if (mv != null) {
- mv.visitInsn(opcode);
- }
- }
-
- /**
- * Visits an instruction with a single int operand.
- *
- * @param opcode the opcode of the instruction to be visited. This opcode is either BIPUSH, SIPUSH or NEWARRAY.
- * @param operand the operand of the instruction to be visited.
- * When opcode is BIPUSH, operand value should be between Byte.MIN_VALUE and Byte.MAX_VALUE.
- * When opcode is SIPUSH, operand value should be between Short.MIN_VALUE and Short.MAX_VALUE.
- * When opcode is NEWARRAY, operand value should be one of {@link Opcodes#T_BOOLEAN}, {@link Opcodes#T_CHAR},
- * {@link Opcodes#T_FLOAT}, {@link Opcodes#T_DOUBLE}, {@link Opcodes#T_BYTE}, {@link Opcodes#T_SHORT},
- * {@link Opcodes#T_INT} or {@link Opcodes#T_LONG}.
- */
- public void visitIntInsn(int opcode, int operand) {
- if (mv != null) {
- mv.visitIntInsn(opcode, operand);
- }
- }
-
- /**
- * Visits a local variable instruction. A local variable instruction is an instruction that loads or stores the
- * value of a local variable.
- *
- * @param opcode the opcode of the local variable instruction to be visited. This opcode is either ILOAD, LLOAD,
- * FLOAD, DLOAD, ALOAD, ISTORE, LSTORE, FSTORE, DSTORE, ASTORE or RET.
- * @param var the operand of the instruction to be visited. This operand is the index of a local variable.
- */
- public void visitVarInsn(int opcode, int var) {
- if (mv != null) {
- mv.visitVarInsn(opcode, var);
- }
- }
-
- /**
- * Visits a type instruction. A type instruction is an instruction that takes the internal name of a class as
- * parameter.
- *
- * @param opcode the opcode of the type instruction to be visited. This opcode is either NEW, ANEWARRAY, CHECKCAST
- * or INSTANCEOF.
- * @param type the operand of the instruction to be visited. This operand must be the internal name of an object or
- * array class (see {@link Type#getInternalName() getInternalName}).
- */
- public void visitTypeInsn(int opcode, String type) {
- if (mv != null) {
- mv.visitTypeInsn(opcode, type);
- }
- }
-
- /**
- * Visits a field instruction. A field instruction is an instruction that loads or stores the value of a field of an
- * object.
- *
- * @param opcode the opcode of the type instruction to be visited. This opcode is either GETSTATIC, PUTSTATIC,
- * GETFIELD or PUTFIELD.
- * @param owner the internal name of the field's owner class (see {@link Type#getInternalName() getInternalName}).
- * @param name the field's name.
- * @param desc the field's descriptor (see {@link Type Type}).
- */
- public void visitFieldInsn(int opcode, String owner, String name, String desc) {
- if (mv != null) {
- mv.visitFieldInsn(opcode, owner, name, desc);
- }
- }
-
- /**
- * Visits a method instruction. A method instruction is an instruction that invokes a method.
- *
- * @param opcode the opcode of the type instruction to be visited. This opcode is either INVOKEVIRTUAL,
- * INVOKESPECIAL, INVOKESTATIC or INVOKEINTERFACE.
- * @param owner the internal name of the method's owner class (see {@link Type#getInternalName() getInternalName}).
- * @param name the method's name.
- * @param desc the method's descriptor (see {@link Type Type}).
- * @param itf if the method's owner class is an interface.
- */
- public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
- if (mv != null) {
- mv.visitMethodInsn(opcode, owner, name, desc, itf);
- }
- }
-
- /**
- * Visits an invokedynamic instruction.
- *
- * @param name the method's name.
- * @param desc the method's descriptor (see {@link Type Type}).
- * @param bsm the bootstrap method.
- * @param bsmArgs the bootstrap method constant arguments. Each argument must be an {@link Integer}, {@link Float},
- * {@link Long}, {@link Double}, {@link String}, {@link Type} or {@link Handle} value. This method is allowed to
- * modify the content of the array so a caller should expect that this array may change.
- */
- public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) {
- if (mv != null) {
- mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
- }
- }
-
- /**
- * Visits a jump instruction. A jump instruction is an instruction that may jump to another instruction.
- *
- * @param opcode the opcode of the type instruction to be visited. This opcode is either IFEQ, IFNE, IFLT, IFGE,
- * IFGT, IFLE, IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, IF_ACMPEQ, IF_ACMPNE, GOTO,
- * JSR, IFNULL or IFNONNULL.
- * @param label the operand of the instruction to be visited. This operand is a label that designates the
- * instruction to which the jump instruction may jump.
- */
- public void visitJumpInsn(int opcode, Label label) {
- if (mv != null) {
- mv.visitJumpInsn(opcode, label);
- }
- }
-
- /**
- * Visits a label. A label designates the instruction that will be visited just after it.
- *
- * @param label a {@link Label Label} object.
- */
- public void visitLabel(Label label) {
- if (mv != null) {
- mv.visitLabel(label);
- }
- }
-
- // -------------------------------------------------------------------------
- // Special instructions
- // -------------------------------------------------------------------------
-
- /**
- * Visits a LDC instruction. Note that new constant types may be added in future versions of the Java Virtual
- * Machine. To easily detect new constant types, implementations of this method should check for unexpected constant
- * types, like this:
- *
- *
- * if (cst instanceof Integer) {
- * // ...
- * } else if (cst instanceof Float) {
- * // ...
- * } else if (cst instanceof Long) {
- * // ...
- * } else if (cst instanceof Double) {
- * // ...
- * } else if (cst instanceof String) {
- * // ...
- * } else if (cst instanceof Type) {
- * int sort = ((Type) cst).getSort();
- * if (sort == Type.OBJECT) {
- * // ...
- * } else if (sort == Type.ARRAY) {
- * // ...
- * } else if (sort == Type.METHOD) {
- * // ...
- * } else {
- * // throw an exception
- * }
- * } else if (cst instanceof Handle) {
- * // ...
- * } else {
- * // throw an exception
- * }
- *
- *
- * @param cst the constant to be loaded on the stack. This parameter must be a non null {@link Integer}, a
- * {@link Float}, a {@link Long}, a {@link Double}, a {@link String}, a {@link Type} of OBJECT or ARRAY sort for
- * <tt>.class</tt> constants, for classes whose version is 49.0, a {@link Type} of METHOD sort
- * or a {@link Handle} for MethodType and MethodHandle constants, for classes whose version is 51.0.
- */
- public void visitLdcInsn(Object cst) {
- if (mv != null) {
- mv.visitLdcInsn(cst);
- }
- }
-
- /**
- * Visits an IINC instruction.
- *
- * @param var index of the local variable to be incremented.
- * @param increment amount to increment the local variable by.
- */
- public void visitIincInsn(int var, int increment) {
- if (mv != null) {
- mv.visitIincInsn(var, increment);
- }
- }
-
- /**
- * Visits a TABLESWITCH instruction.
- *
- * @param min the minimum key value.
- * @param max the maximum key value.
- * @param dflt beginning of the default handler block.
- * @param labels beginnings of the handler blocks. <tt>labels[i]</tt> is the beginning of the
- * handler block for the <tt>min + i</tt> key.
- */
- public void visitTableSwitchInsn(int min, int max, Label dflt, Label... labels) {
- if (mv != null) {
- mv.visitTableSwitchInsn(min, max, dflt, labels);
- }
- }
-
- /**
- * Visits a LOOKUPSWITCH instruction.
- *
- * @param dflt beginning of the default handler block.
- * @param keys the values of the keys.
- * @param labels beginnings of the handler blocks. <tt>labels[i]</tt> is the beginning of the
- * handler block for the <tt>keys[i]</tt> key.
- */
- public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
- if (mv != null) {
- mv.visitLookupSwitchInsn(dflt, keys, labels);
- }
- }
-
- /**
- * Visits a MULTIANEWARRAY instruction.
- *
- * @param desc an array type descriptor (see {@link Type Type}).
- * @param dims number of dimensions of the array to allocate.
- */
- public void visitMultiANewArrayInsn(String desc, int dims) {
- if (mv != null) {
- mv.visitMultiANewArrayInsn(desc, dims);
- }
- }
-
- /**
- * Visits an annotation on an instruction. This method must be called just after the annotated instruction.
- * It can be called several times for the same instruction.
- *
- * @param typeRef a reference to the annotated type. The sort of this type reference must be
- * {@link TypeReference#INSTANCEOF INSTANCEOF}, {@link TypeReference#NEW NEW},
- * {@link TypeReference#CONSTRUCTOR_REFERENCE CONSTRUCTOR_REFERENCE}, {@link TypeReference#METHOD_REFERENCE
- * METHOD_REFERENCE}, {@link TypeReference#CAST CAST}, {@link TypeReference#CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
- * CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, {@link TypeReference#METHOD_INVOCATION_TYPE_ARGUMENT
- * METHOD_INVOCATION_TYPE_ARGUMENT}, {@link TypeReference#CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
- * CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or {@link TypeReference#METHOD_REFERENCE_TYPE_ARGUMENT
- * METHOD_REFERENCE_TYPE_ARGUMENT}. See {@link TypeReference}.
- * @param typePath the path to the annotated type argument, wildcard bound, array element type, or static inner type
- * within 'typeRef'. May be <tt>null</tt> if the annotation targets 'typeRef' as a whole.
- * @param desc the class descriptor of the annotation class.
- * @param visible <tt>true</tt> if the annotation is visible at runtime.
- * @return a visitor to visit the annotation values, or <tt>null</tt> if this visitor is not
- * interested in visiting this annotation.
- */
- public AnnotationVisitor visitInsnAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {
- if (mv != null) {
- return mv.visitInsnAnnotation(typeRef, typePath, desc, visible);
- }
- return null;
- }
-
- // -------------------------------------------------------------------------
- // Exceptions table entries, debug information, max stack and max locals
- // -------------------------------------------------------------------------
-
- /**
- * Visits a try catch block.
- *
- * @param start beginning of the exception handler's scope (inclusive).
- * @param end end of the exception handler's scope (exclusive).
- * @param handler beginning of the exception handler's code.
- * @param type internal name of the type of exceptions handled by the handler, or <tt>null</tt> to
- * catch any exceptions (for "finally" blocks).
- * @throws IllegalArgumentException if one of the labels has already been visited by this visitor (by the
- * {@link #visitLabel visitLabel} method).
- */
- public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
- if (mv != null) {
- mv.visitTryCatchBlock(start, end, handler, type);
- }
- }
-
- /**
- * Visits an annotation on an exception handler type. This method must be called after the
- * {@link #visitTryCatchBlock} for the annotated exception handler. It can be called several times for the same
- * exception handler.
- *
- * @param typeRef a reference to the annotated type. The sort of this type reference must be
- * {@link TypeReference#EXCEPTION_PARAMETER EXCEPTION_PARAMETER}. See {@link TypeReference}.
- * @param typePath the path to the annotated type argument, wildcard bound, array element type, or static inner type
- * within 'typeRef'. May be <tt>null</tt> if the annotation targets 'typeRef' as a whole.
- * @param desc the class descriptor of the annotation class.
- * @param visible <tt>true</tt> if the annotation is visible at runtime.
- * @return a visitor to visit the annotation values, or <tt>null</tt> if this visitor is not
- * interested in visiting this annotation.
- */
- public AnnotationVisitor visitTryCatchAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {
- if (mv != null) {
- return mv.visitTryCatchAnnotation(typeRef, typePath, desc, visible);
- }
- return null;
- }
-
- /**
- * Visits a local variable declaration.
- *
- * @param name the name of a local variable.
- * @param desc the type descriptor of this local variable.
- * @param signature the type signature of this local variable. May be <tt>null</tt> if the local
- * variable type does not use generic types.
- * @param start the first instruction corresponding to the scope of this local variable (inclusive).
- * @param end the last instruction corresponding to the scope of this local variable (exclusive).
- * @param index the local variable's index.
- * @throws IllegalArgumentException if one of the labels has not already been visited by this visitor (by the
- * {@link #visitLabel visitLabel} method).
- */
- public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) {
- if (mv != null) {
- mv.visitLocalVariable(name, desc, signature, start, end, index);
- }
- }
-
- /**
- * Visits an annotation on a local variable type.
- *
- * @param typeRef a reference to the annotated type. The sort of this type reference must be
- * {@link TypeReference#LOCAL_VARIABLE LOCAL_VARIABLE} or {@link TypeReference#RESOURCE_VARIABLE
- * RESOURCE_VARIABLE}. See {@link TypeReference}.
- * @param typePath the path to the annotated type argument, wildcard bound, array element type, or static inner type
- * within 'typeRef'. May be <tt>null</tt> if the annotation targets 'typeRef' as a whole.
- * @param start the fist instructions corresponding to the continuous ranges that make the scope of this local
- * variable (inclusive).
- * @param end the last instructions corresponding to the continuous ranges that make the scope of this local
- * variable (exclusive). This array must have the same size as the 'start' array.
- * @param index the local variable's index in each range. This array must have the same size as the 'start' array.
- * @param desc the class descriptor of the annotation class.
- * @param visible <tt>true</tt> if the annotation is visible at runtime.
- * @return a visitor to visit the annotation values, or <tt>null</tt> if this visitor is not
- * interested in visiting this annotation.
- */
- public AnnotationVisitor visitLocalVariableAnnotation(
- int typeRef, TypePath typePath, Label[] start, Label[] end, int[] index, String desc, boolean visible) {
- if (mv != null) {
- return mv.visitLocalVariableAnnotation(typeRef, typePath, start, end, index, desc, visible);
- }
- return null;
- }
-
- /**
- * Visits a line number declaration.
- *
- * @param line a line number. This number refers to the source file from which the class was compiled.
- * @param start the first instruction corresponding to this line number.
- * @throws IllegalArgumentException if <tt>start</tt> has not already been visited by this visitor
- * (by the {@link #visitLabel visitLabel} method).
- */
- public void visitLineNumber(int line, Label start) {
- if (mv != null) {
- mv.visitLineNumber(line, start);
- }
- }
-
- /**
- * Visits the maximum stack size and the maximum number of local variables of the method.
- *
- * @param maxStack maximum stack size of the method.
- * @param maxLocals maximum number of local variables for the method.
- */
- public void visitMaxs(int maxStack, int maxLocals) {
- if (mv != null) {
- mv.visitMaxs(maxStack, maxLocals);
- }
- }
-
- /**
- * Visits the end of the method. This method, which is the last one to be called, is used to inform the visitor that
- * all the annotations and attributes of the method have been visited.
- */
- public void visitEnd() {
- if (mv != null) {
- mv.visitEnd();
- }
- }
-}
+/*
+ * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ */
+
+/*
+ *
+ *
+ *
+ *
+ *
+ * ASM: a very small and fast Java bytecode manipulation framework
+ * Copyright (c) 2000-2011 INRIA, France Telecom
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.redkale.asm;
+
+/**
+ * A visitor to visit a Java method. The methods of this class must be called in the following order: (
+ * <tt>visitParameter</tt> )* [ <tt>visitAnnotationDefault</tt> ] (
+ * <tt>visitAnnotation</tt> | <tt>visitParameterAnnotation</tt>
+ * <tt>visitTypeAnnotation</tt> | <tt>visitAttribute</tt> )* [
+ * <tt>visitCode</tt> ( <tt>visitFrame</tt> | <tt>visitXInsn</tt>
+ * | <tt>visitLabel</tt> | <tt>visitInsnAnnotation</tt> |
+ * <tt>visitTryCatchBlock</tt> | <tt>visitTryCatchAnnotation</tt> |
+ * <tt>visitLocalVariable</tt> | <tt>visitLocalVariableAnnotation</tt> |
+ * <tt>visitLineNumber</tt> )* <tt>visitMaxs</tt> ] <tt>visitEnd</tt>.
+ * In addition, the <tt>visitXInsn</tt> and <tt>visitLabel</tt> methods must be
+ * called in the sequential order of the bytecode instructions of the visited code,
+ * <tt>visitInsnAnnotation</tt> must be called after the annotated instruction,
+ * <tt>visitTryCatchBlock</tt> must be called before the labels passed as arguments have been
+ * visited, <tt>visitTryCatchBlockAnnotation</tt> must be called after the corresponding try
+ * catch block has been visited, and the <tt>visitLocalVariable</tt>,
+ * <tt>visitLocalVariableAnnotation</tt> and <tt>visitLineNumber</tt> methods must be
+ * called after the labels passed as arguments have been visited.
+ *
+ * @author Eric Bruneton
+ */
+public abstract class MethodVisitor {
+
+ /**
+ * The ASM API version implemented by this visitor. The value of this field must be one of {@link Opcodes#ASM4},
+ * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
+ */
+ protected final int api;
+
+ /** The method visitor to which this visitor must delegate method calls. May be null. */
+ protected MethodVisitor mv;
+
+ /**
+ * Constructs a new {@link MethodVisitor}.
+ *
+ * @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM4},
+ * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
+ */
+ public MethodVisitor(final int api) {
+ this(api, null);
+ }
+
+ /**
+ * Constructs a new {@link MethodVisitor}.
+ *
+ * @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM4},
+ * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
+ * @param mv the method visitor to which this visitor must delegate method calls. May be null.
+ */
+ public MethodVisitor(final int api, final MethodVisitor mv) {
+ this.api = api;
+ this.mv = mv;
+ }
+
+ // -------------------------------------------------------------------------
+ // Parameters, annotations and non standard attributes
+ // -------------------------------------------------------------------------
+
+ /**
+ * Visits a parameter of this method.
+ *
+ * @param name parameter name or null if none is provided.
+ * @param access the parameter's access flags, only <tt>ACC_FINAL</tt>,
+ * <tt>ACC_SYNTHETIC</tt> or/and <tt>ACC_MANDATED</tt> are allowed (see
+ * {@link Opcodes}).
+ */
+ public void visitParameter(String name, int access) {
+ if (mv != null) {
+ mv.visitParameter(name, access);
+ }
+ }
+
+ /**
+ * Visits the default value of this annotation interface method.
+ *
+ * @return a visitor to the visit the actual default value of this annotation interface method, or
+ * <tt>null</tt> if this visitor is not interested in visiting this default value. The 'name'
+ * parameters passed to the methods of this annotation visitor are ignored. Moreover, exacly one visit method
+ * must be called on this annotation visitor, followed by visitEnd.
+ */
+ public AnnotationVisitor visitAnnotationDefault() {
+ if (mv != null) {
+ return mv.visitAnnotationDefault();
+ }
+ return null;
+ }
+
+ /**
+ * Visits an annotation of this method.
+ *
+ * @param desc the class descriptor of the annotation class.
+ * @param visible <tt>true</tt> if the annotation is visible at runtime.
+ * @return a visitor to visit the annotation values, or <tt>null</tt> if this visitor is not
+ * interested in visiting this annotation.
+ */
+ public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+ if (mv != null) {
+ return mv.visitAnnotation(desc, visible);
+ }
+ return null;
+ }
+
+ /**
+ * Visits an annotation on a type in the method signature.
+ *
+ * @param typeRef a reference to the annotated type. The sort of this type reference must be
+ * {@link TypeReference#METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER},
+ * {@link TypeReference#METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND},
+ * {@link TypeReference#METHOD_RETURN METHOD_RETURN}, {@link TypeReference#METHOD_RECEIVER METHOD_RECEIVER},
+ * {@link TypeReference#METHOD_FORMAL_PARAMETER METHOD_FORMAL_PARAMETER} or {@link TypeReference#THROWS THROWS}.
+ * See {@link TypeReference}.
+ * @param typePath the path to the annotated type argument, wildcard bound, array element type, or static inner type
+ * within 'typeRef'. May be <tt>null</tt> if the annotation targets 'typeRef' as a whole.
+ * @param desc the class descriptor of the annotation class.
+ * @param visible <tt>true</tt> if the annotation is visible at runtime.
+ * @return a visitor to visit the annotation values, or <tt>null</tt> if this visitor is not
+ * interested in visiting this annotation.
+ */
+ public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {
+ if (mv != null) {
+ return mv.visitTypeAnnotation(typeRef, typePath, desc, visible);
+ }
+ return null;
+ }
+
+ /**
+ * Visits an annotation of a parameter this method.
+ *
+ * @param parameter the parameter index.
+ * @param desc the class descriptor of the annotation class.
+ * @param visible <tt>true</tt> if the annotation is visible at runtime.
+ * @return a visitor to visit the annotation values, or <tt>null</tt> if this visitor is not
+ * interested in visiting this annotation.
+ */
+ public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, boolean visible) {
+ if (mv != null) {
+ return mv.visitParameterAnnotation(parameter, desc, visible);
+ }
+ return null;
+ }
+
+ /**
+ * Visits a non standard attribute of this method.
+ *
+ * @param attr an attribute.
+ */
+ public void visitAttribute(Attribute attr) {
+ if (mv != null) {
+ mv.visitAttribute(attr);
+ }
+ }
+
+ /** Starts the visit of the method's code, if any (i.e. non abstract method). */
+ public void visitCode() {
+ if (mv != null) {
+ mv.visitCode();
+ }
+ }
+
+ /**
+ * Visits the current state of the local variables and operand stack elements. This method must(*) be called just
+ * before any instruction i that follows an unconditional branch instruction such as GOTO or THROW, that
+ * is the target of a jump instruction, or that starts an exception handler block. The visited types must describe
+ * the values of the local variables and of the operand stack elements just before i is executed.
+ *
+ * (*) this is mandatory only for classes whose version is greater than or equal to {@link Opcodes#V1_6 V1_6}.
+ *
+ * The frames of a method must be given either in expanded form, or in compressed form (all frames must use the same
+ * format, i.e. you must not mix expanded and compressed frames within a single method):
+ *
+ *
+ *
+ *
+ *
+ *
+ * nStack is 1 and stack[0] contains value
+ * for the type of the stack item).
+ * nLocal is 1, 2 or 3 and
+ * local elements contains values representing added types).
+ * nLocals
+ * is 1, 2 or 3).
+ *
+ * In both cases the first frame, corresponding to the method's parameters and access flags, is implicit and must
+ * not be visited. Also, it is illegal to visit two or more frames for the same code location (i.e., at least one
+ * instruction must be visited between two calls to visitFrame).
+ *
+ * @param type the type of this stack map frame. Must be {@link Opcodes#F_NEW} for expanded frames, or
+ * {@link Opcodes#F_FULL}, {@link Opcodes#F_APPEND}, {@link Opcodes#F_CHOP}, {@link Opcodes#F_SAME} or
+ * {@link Opcodes#F_APPEND}, {@link Opcodes#F_SAME1} for compressed frames.
+ * @param nLocal the number of local variables in the visited frame.
+ * @param local the local variable types in this frame. This array must not be modified. Primitive types are
+ * represented by {@link Opcodes#TOP}, {@link Opcodes#INTEGER}, {@link Opcodes#FLOAT}, {@link Opcodes#LONG},
+ * {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or {@link Opcodes#UNINITIALIZED_THIS} (long and double are
+ * represented by a single element). Reference types are represented by String objects (representing internal
+ * names), and uninitialized types by Label objects (this label designates the NEW instruction that created this
+ * uninitialized value).
+ * @param nStack the number of operand stack elements in the visited frame.
+ * @param stack the operand stack types in this frame. This array must not be modified. Its content has the same
+ * format as the "local" array.
+ * @throws IllegalStateException if a frame is visited just after another one, without any instruction between the
+ * two (unless this frame is a Opcodes#F_SAME frame, in which case it is silently ignored).
+ */
+ public void visitFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack) {
+ if (mv != null) {
+ mv.visitFrame(type, nLocal, local, nStack, stack);
+ }
+ }
+
+ // -------------------------------------------------------------------------
+ // Normal instructions
+ // -------------------------------------------------------------------------
+
+ /**
+ * Visits a zero operand instruction.
+ *
+ * @param opcode the opcode of the instruction to be visited. This opcode is either NOP, ACONST_NULL, ICONST_M1,
+ * ICONST_0, ICONST_1, ICONST_2, ICONST_3, ICONST_4, ICONST_5, LCONST_0, LCONST_1, FCONST_0, FCONST_1, FCONST_2,
+ * DCONST_0, DCONST_1, IALOAD, LALOAD, FALOAD, DALOAD, AALOAD, BALOAD, CALOAD, SALOAD, IASTORE, LASTORE,
+ * FASTORE, DASTORE, AASTORE, BASTORE, CASTORE, SASTORE, POP, POP2, DUP, DUP_X1, DUP_X2, DUP2, DUP2_X1, DUP2_X2,
+ * SWAP, IADD, LADD, FADD, DADD, ISUB, LSUB, FSUB, DSUB, IMUL, LMUL, FMUL, DMUL, IDIV, LDIV, FDIV, DDIV, IREM,
+ * LREM, FREM, DREM, INEG, LNEG, FNEG, DNEG, ISHL, LSHL, ISHR, LSHR, IUSHR, LUSHR, IAND, LAND, IOR, LOR, IXOR,
+ * LXOR, I2L, I2F, I2D, L2I, L2F, L2D, F2I, F2L, F2D, D2I, D2L, D2F, I2B, I2C, I2S, LCMP, FCMPL, FCMPG, DCMPL,
+ * DCMPG, IRETURN, LRETURN, FRETURN, DRETURN, ARETURN, RETURN, ARRAYLENGTH, ATHROW, MONITORENTER, or
+ * MONITOREXIT.
+ */
+ public void visitInsn(int opcode) {
+ if (mv != null) {
+ mv.visitInsn(opcode);
+ }
+ }
+
+ /**
+ * Visits an instruction with a single int operand.
+ *
+ * @param opcode the opcode of the instruction to be visited. This opcode is either BIPUSH, SIPUSH or NEWARRAY.
+ * @param operand the operand of the instruction to be visited.
+ * When opcode is BIPUSH, operand value should be between Byte.MIN_VALUE and Byte.MAX_VALUE.
+ * When opcode is SIPUSH, operand value should be between Short.MIN_VALUE and Short.MAX_VALUE.
+ * When opcode is NEWARRAY, operand value should be one of {@link Opcodes#T_BOOLEAN}, {@link Opcodes#T_CHAR},
+ * {@link Opcodes#T_FLOAT}, {@link Opcodes#T_DOUBLE}, {@link Opcodes#T_BYTE}, {@link Opcodes#T_SHORT},
+ * {@link Opcodes#T_INT} or {@link Opcodes#T_LONG}.
+ */
+ public void visitIntInsn(int opcode, int operand) {
+ if (mv != null) {
+ mv.visitIntInsn(opcode, operand);
+ }
+ }
+
+ /**
+ * Visits a local variable instruction. A local variable instruction is an instruction that loads or stores the
+ * value of a local variable.
+ *
+ * @param opcode the opcode of the local variable instruction to be visited. This opcode is either ILOAD, LLOAD,
+ * FLOAD, DLOAD, ALOAD, ISTORE, LSTORE, FSTORE, DSTORE, ASTORE or RET.
+ * @param var the operand of the instruction to be visited. This operand is the index of a local variable.
+ */
+ public void visitVarInsn(int opcode, int var) {
+ if (mv != null) {
+ mv.visitVarInsn(opcode, var);
+ }
+ }
+
+ /**
+ * Visits a type instruction. A type instruction is an instruction that takes the internal name of a class as
+ * parameter.
+ *
+ * @param opcode the opcode of the type instruction to be visited. This opcode is either NEW, ANEWARRAY, CHECKCAST
+ * or INSTANCEOF.
+ * @param type the operand of the instruction to be visited. This operand must be the internal name of an object or
+ * array class (see {@link Type#getInternalName() getInternalName}).
+ */
+ public void visitTypeInsn(int opcode, String type) {
+ if (mv != null) {
+ mv.visitTypeInsn(opcode, type);
+ }
+ }
+
+ /**
+ * Visits a field instruction. A field instruction is an instruction that loads or stores the value of a field of an
+ * object.
+ *
+ * @param opcode the opcode of the type instruction to be visited. This opcode is either GETSTATIC, PUTSTATIC,
+ * GETFIELD or PUTFIELD.
+ * @param owner the internal name of the field's owner class (see {@link Type#getInternalName() getInternalName}).
+ * @param name the field's name.
+ * @param desc the field's descriptor (see {@link Type Type}).
+ */
+ public void visitFieldInsn(int opcode, String owner, String name, String desc) {
+ if (mv != null) {
+ mv.visitFieldInsn(opcode, owner, name, desc);
+ }
+ }
+
+ /**
+ * Visits a method instruction. A method instruction is an instruction that invokes a method.
+ *
+ * @param opcode the opcode of the type instruction to be visited. This opcode is either INVOKEVIRTUAL,
+ * INVOKESPECIAL, INVOKESTATIC or INVOKEINTERFACE.
+ * @param owner the internal name of the method's owner class (see {@link Type#getInternalName() getInternalName}).
+ * @param name the method's name.
+ * @param desc the method's descriptor (see {@link Type Type}).
+ * @param itf if the method's owner class is an interface.
+ */
+ public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
+ if (mv != null) {
+ mv.visitMethodInsn(opcode, owner, name, desc, itf);
+ }
+ }
+
+ /**
+ * Visits an invokedynamic instruction.
+ *
+ * @param name the method's name.
+ * @param desc the method's descriptor (see {@link Type Type}).
+ * @param bsm the bootstrap method.
+ * @param bsmArgs the bootstrap method constant arguments. Each argument must be an {@link Integer}, {@link Float},
+ * {@link Long}, {@link Double}, {@link String}, {@link Type} or {@link Handle} value. This method is allowed to
+ * modify the content of the array so a caller should expect that this array may change.
+ */
+ public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) {
+ if (mv != null) {
+ mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
+ }
+ }
+
+ /**
+ * Visits a jump instruction. A jump instruction is an instruction that may jump to another instruction.
+ *
+ * @param opcode the opcode of the type instruction to be visited. This opcode is either IFEQ, IFNE, IFLT, IFGE,
+ * IFGT, IFLE, IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, IF_ACMPEQ, IF_ACMPNE, GOTO,
+ * JSR, IFNULL or IFNONNULL.
+ * @param label the operand of the instruction to be visited. This operand is a label that designates the
+ * instruction to which the jump instruction may jump.
+ */
+ public void visitJumpInsn(int opcode, Label label) {
+ if (mv != null) {
+ mv.visitJumpInsn(opcode, label);
+ }
+ }
+
+ /**
+ * Visits a label. A label designates the instruction that will be visited just after it.
+ *
+ * @param label a {@link Label Label} object.
+ */
+ public void visitLabel(Label label) {
+ if (mv != null) {
+ mv.visitLabel(label);
+ }
+ }
+
+ // -------------------------------------------------------------------------
+ // Special instructions
+ // -------------------------------------------------------------------------
+
+ /**
+ * Visits a LDC instruction. Note that new constant types may be added in future versions of the Java Virtual
+ * Machine. To easily detect new constant types, implementations of this method should check for unexpected constant
+ * types, like this:
+ *
+ *
+ * if (cst instanceof Integer) {
+ * // ...
+ * } else if (cst instanceof Float) {
+ * // ...
+ * } else if (cst instanceof Long) {
+ * // ...
+ * } else if (cst instanceof Double) {
+ * // ...
+ * } else if (cst instanceof String) {
+ * // ...
+ * } else if (cst instanceof Type) {
+ * int sort = ((Type) cst).getSort();
+ * if (sort == Type.OBJECT) {
+ * // ...
+ * } else if (sort == Type.ARRAY) {
+ * // ...
+ * } else if (sort == Type.METHOD) {
+ * // ...
+ * } else {
+ * // throw an exception
+ * }
+ * } else if (cst instanceof Handle) {
+ * // ...
+ * } else {
+ * // throw an exception
+ * }
+ *
+ *
+ * @param cst the constant to be loaded on the stack. This parameter must be a non null {@link Integer}, a
+ * {@link Float}, a {@link Long}, a {@link Double}, a {@link String}, a {@link Type} of OBJECT or ARRAY sort for
+ * <tt>.class</tt> constants, for classes whose version is 49.0, a {@link Type} of METHOD sort
+ * or a {@link Handle} for MethodType and MethodHandle constants, for classes whose version is 51.0.
+ */
+ public void visitLdcInsn(Object cst) {
+ if (mv != null) {
+ mv.visitLdcInsn(cst);
+ }
+ }
+
+ /**
+ * Visits an IINC instruction.
+ *
+ * @param var index of the local variable to be incremented.
+ * @param increment amount to increment the local variable by.
+ */
+ public void visitIincInsn(int var, int increment) {
+ if (mv != null) {
+ mv.visitIincInsn(var, increment);
+ }
+ }
+
+ /**
+ * Visits a TABLESWITCH instruction.
+ *
+ * @param min the minimum key value.
+ * @param max the maximum key value.
+ * @param dflt beginning of the default handler block.
+ * @param labels beginnings of the handler blocks. <tt>labels[i]</tt> is the beginning of the
+ * handler block for the <tt>min + i</tt> key.
+ */
+ public void visitTableSwitchInsn(int min, int max, Label dflt, Label... labels) {
+ if (mv != null) {
+ mv.visitTableSwitchInsn(min, max, dflt, labels);
+ }
+ }
+
+ /**
+ * Visits a LOOKUPSWITCH instruction.
+ *
+ * @param dflt beginning of the default handler block.
+ * @param keys the values of the keys.
+ * @param labels beginnings of the handler blocks. <tt>labels[i]</tt> is the beginning of the
+ * handler block for the <tt>keys[i]</tt> key.
+ */
+ public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
+ if (mv != null) {
+ mv.visitLookupSwitchInsn(dflt, keys, labels);
+ }
+ }
+
+ /**
+ * Visits a MULTIANEWARRAY instruction.
+ *
+ * @param desc an array type descriptor (see {@link Type Type}).
+ * @param dims number of dimensions of the array to allocate.
+ */
+ public void visitMultiANewArrayInsn(String desc, int dims) {
+ if (mv != null) {
+ mv.visitMultiANewArrayInsn(desc, dims);
+ }
+ }
+
+ /**
+ * Visits an annotation on an instruction. This method must be called just after the annotated instruction.
+ * It can be called several times for the same instruction.
+ *
+ * @param typeRef a reference to the annotated type. The sort of this type reference must be
+ * {@link TypeReference#INSTANCEOF INSTANCEOF}, {@link TypeReference#NEW NEW},
+ * {@link TypeReference#CONSTRUCTOR_REFERENCE CONSTRUCTOR_REFERENCE}, {@link TypeReference#METHOD_REFERENCE
+ * METHOD_REFERENCE}, {@link TypeReference#CAST CAST}, {@link TypeReference#CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
+ * CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, {@link TypeReference#METHOD_INVOCATION_TYPE_ARGUMENT
+ * METHOD_INVOCATION_TYPE_ARGUMENT}, {@link TypeReference#CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
+ * CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or {@link TypeReference#METHOD_REFERENCE_TYPE_ARGUMENT
+ * METHOD_REFERENCE_TYPE_ARGUMENT}. See {@link TypeReference}.
+ * @param typePath the path to the annotated type argument, wildcard bound, array element type, or static inner type
+ * within 'typeRef'. May be <tt>null</tt> if the annotation targets 'typeRef' as a whole.
+ * @param desc the class descriptor of the annotation class.
+ * @param visible <tt>true</tt> if the annotation is visible at runtime.
+ * @return a visitor to visit the annotation values, or <tt>null</tt> if this visitor is not
+ * interested in visiting this annotation.
+ */
+ public AnnotationVisitor visitInsnAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {
+ if (mv != null) {
+ return mv.visitInsnAnnotation(typeRef, typePath, desc, visible);
+ }
+ return null;
+ }
+
+ // -------------------------------------------------------------------------
+ // Exceptions table entries, debug information, max stack and max locals
+ // -------------------------------------------------------------------------
+
+ /**
+ * Visits a try catch block.
+ *
+ * @param start beginning of the exception handler's scope (inclusive).
+ * @param end end of the exception handler's scope (exclusive).
+ * @param handler beginning of the exception handler's code.
+ * @param type internal name of the type of exceptions handled by the handler, or <tt>null</tt> to
+ * catch any exceptions (for "finally" blocks).
+ * @throws IllegalArgumentException if one of the labels has already been visited by this visitor (by the
+ * {@link #visitLabel visitLabel} method).
+ */
+ public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
+ if (mv != null) {
+ mv.visitTryCatchBlock(start, end, handler, type);
+ }
+ }
+
+ /**
+ * Visits an annotation on an exception handler type. This method must be called after the
+ * {@link #visitTryCatchBlock} for the annotated exception handler. It can be called several times for the same
+ * exception handler.
+ *
+ * @param typeRef a reference to the annotated type. The sort of this type reference must be
+ * {@link TypeReference#EXCEPTION_PARAMETER EXCEPTION_PARAMETER}. See {@link TypeReference}.
+ * @param typePath the path to the annotated type argument, wildcard bound, array element type, or static inner type
+ * within 'typeRef'. May be <tt>null</tt> if the annotation targets 'typeRef' as a whole.
+ * @param desc the class descriptor of the annotation class.
+ * @param visible <tt>true</tt> if the annotation is visible at runtime.
+ * @return a visitor to visit the annotation values, or <tt>null</tt> if this visitor is not
+ * interested in visiting this annotation.
+ */
+ public AnnotationVisitor visitTryCatchAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {
+ if (mv != null) {
+ return mv.visitTryCatchAnnotation(typeRef, typePath, desc, visible);
+ }
+ return null;
+ }
+
+ /**
+ * Visits a local variable declaration.
+ *
+ * @param name the name of a local variable.
+ * @param desc the type descriptor of this local variable.
+ * @param signature the type signature of this local variable. May be <tt>null</tt> if the local
+ * variable type does not use generic types.
+ * @param start the first instruction corresponding to the scope of this local variable (inclusive).
+ * @param end the last instruction corresponding to the scope of this local variable (exclusive).
+ * @param index the local variable's index.
+ * @throws IllegalArgumentException if one of the labels has not already been visited by this visitor (by the
+ * {@link #visitLabel visitLabel} method).
+ */
+ public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) {
+ if (mv != null) {
+ mv.visitLocalVariable(name, desc, signature, start, end, index);
+ }
+ }
+
+ /**
+ * Visits an annotation on a local variable type.
+ *
+ * @param typeRef a reference to the annotated type. The sort of this type reference must be
+ * {@link TypeReference#LOCAL_VARIABLE LOCAL_VARIABLE} or {@link TypeReference#RESOURCE_VARIABLE
+ * RESOURCE_VARIABLE}. See {@link TypeReference}.
+ * @param typePath the path to the annotated type argument, wildcard bound, array element type, or static inner type
+ * within 'typeRef'. May be <tt>null</tt> if the annotation targets 'typeRef' as a whole.
+ * @param start the fist instructions corresponding to the continuous ranges that make the scope of this local
+ * variable (inclusive).
+ * @param end the last instructions corresponding to the continuous ranges that make the scope of this local
+ * variable (exclusive). This array must have the same size as the 'start' array.
+ * @param index the local variable's index in each range. This array must have the same size as the 'start' array.
+ * @param desc the class descriptor of the annotation class.
+ * @param visible <tt>true</tt> if the annotation is visible at runtime.
+ * @return a visitor to visit the annotation values, or <tt>null</tt> if this visitor is not
+ * interested in visiting this annotation.
+ */
+ public AnnotationVisitor visitLocalVariableAnnotation(
+ int typeRef, TypePath typePath, Label[] start, Label[] end, int[] index, String desc, boolean visible) {
+ if (mv != null) {
+ return mv.visitLocalVariableAnnotation(typeRef, typePath, start, end, index, desc, visible);
+ }
+ return null;
+ }
+
+ /**
+ * Visits a line number declaration.
+ *
+ * @param line a line number. This number refers to the source file from which the class was compiled.
+ * @param start the first instruction corresponding to this line number.
+ * @throws IllegalArgumentException if <tt>start</tt> has not already been visited by this visitor
+ * (by the {@link #visitLabel visitLabel} method).
+ */
+ public void visitLineNumber(int line, Label start) {
+ if (mv != null) {
+ mv.visitLineNumber(line, start);
+ }
+ }
+
+ /**
+ * Visits the maximum stack size and the maximum number of local variables of the method.
+ *
+ * @param maxStack maximum stack size of the method.
+ * @param maxLocals maximum number of local variables for the method.
+ */
+ public void visitMaxs(int maxStack, int maxLocals) {
+ if (mv != null) {
+ mv.visitMaxs(maxStack, maxLocals);
+ }
+ }
+
+ /**
+ * Visits the end of the method. This method, which is the last one to be called, is used to inform the visitor that
+ * all the annotations and attributes of the method have been visited.
+ */
+ public void visitEnd() {
+ if (mv != null) {
+ mv.visitEnd();
+ }
+ }
+}
diff --git a/src/main/java/org/redkale/asm/MethodWriter.java b/src/main/java/org/redkale/asm/MethodWriter.java
index b106d10a5..702094a90 100644
--- a/src/main/java/org/redkale/asm/MethodWriter.java
+++ b/src/main/java/org/redkale/asm/MethodWriter.java
@@ -1,2240 +1,2240 @@
-/*
- * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- */
-
-/*
- *
- *
- *
- *
- *
- * ASM: a very small and fast Java bytecode manipulation framework
- * Copyright (c) 2000-2011 INRIA, France Telecom
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-package org.redkale.asm;
-
-/**
- * A {@link MethodVisitor} that generates methods in bytecode form. Each visit method of this class appends the bytecode
- * corresponding to the visited instruction to a byte vector, in the order these methods are called.
- *
- * @author Eric Bruneton
- * @author Eugene Kuleshov
- */
-class MethodWriter extends MethodVisitor {
-
- /** Pseudo access flag used to denote constructors. */
- static final int ACC_CONSTRUCTOR = 0x80000;
-
- /** Frame has exactly the same locals as the previous stack map frame and number of stack items is zero. */
- static final int SAME_FRAME = 0; // to 63 (0-3f)
-
- /** Frame has exactly the same locals as the previous stack map frame and number of stack items is 1 */
- static final int SAME_LOCALS_1_STACK_ITEM_FRAME = 64; // to 127 (40-7f)
-
- /** Reserved for future use */
- static final int RESERVED = 128;
-
- /**
- * Frame has exactly the same locals as the previous stack map frame and number of stack items is 1. Offset is
- * bigger then 63;
- */
- static final int SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED = 247; // f7
-
- /**
- * Frame where current locals are the same as the locals in the previous frame, except that the k last locals are
- * absent. The value of k is given by the formula 251-frame_type.
- */
- static final int CHOP_FRAME = 248; // to 250 (f8-fA)
-
- /**
- * Frame has exactly the same locals as the previous stack map frame and number of stack items is zero. Offset is
- * bigger then 63;
- */
- static final int SAME_FRAME_EXTENDED = 251; // fb
-
- /**
- * Frame where current locals are the same as the locals in the previous frame, except that k additional locals are
- * defined. The value of k is given by the formula frame_type-251.
- */
- static final int APPEND_FRAME = 252; // to 254 // fc-fe
-
- /** Full frame */
- static final int FULL_FRAME = 255; // ff
-
- /**
- * Indicates that the stack map frames must be recomputed from scratch. In this case the maximum stack size and
- * number of local variables is also recomputed from scratch.
- *
- * @see #compute
- */
- static final int FRAMES = 0;
-
- /**
- * Indicates that the stack map frames of type F_INSERT must be computed. The other frames are not (re)computed.
- * They should all be of type F_NEW and should be sufficient to compute the content of the F_INSERT frames, together
- * with the bytecode instructions between a F_NEW and a F_INSERT frame - and without any knowledge of the type
- * hierarchy (by definition of F_INSERT).
- *
- * @see #compute
- */
- static final int INSERTED_FRAMES = 1;
-
- /**
- * Indicates that the maximum stack size and number of local variables must be automatically computed.
- *
- * @see #compute
- */
- static final int MAXS = 2;
-
- /**
- * Indicates that nothing must be automatically computed.
- *
- * @see #compute
- */
- static final int NOTHING = 3;
-
- /** The class writer to which this method must be added. */
- final ClassWriter cw;
-
- /** Access flags of this method. */
- private int access;
-
- /** The index of the constant pool item that contains the name of this method. */
- private final int name;
-
- /** The index of the constant pool item that contains the descriptor of this method. */
- private final int desc;
-
- /** The descriptor of this method. */
- private final String descriptor;
-
- /** The signature of this method. */
- String signature;
-
- /**
- * If not zero, indicates that the code of this method must be copied from the ClassReader associated to this writer
- * in cw.cr. More precisely, this field gives the index of the first byte to copied from cw.cr.b
- * .
- */
- int classReaderOffset;
-
- /**
- * If not zero, indicates that the code of this method must be copied from the ClassReader associated to this writer
- * in cw.cr. More precisely, this field gives the number of bytes to copied from cw.cr.b.
- */
- int classReaderLength;
-
- /** Number of exceptions that can be thrown by this method. */
- int exceptionCount;
-
- /**
- * The exceptions that can be thrown by this method. More precisely, this array contains the indexes of the constant
- * pool items that contain the internal names of these exception classes.
- */
- int[] exceptions;
-
- /** The annotation default attribute of this method. May be <tt>null</tt>. */
- private ByteVector annd;
-
- /** The runtime visible annotations of this method. May be <tt>null</tt>. */
- private AnnotationWriter anns;
-
- /** The runtime invisible annotations of this method. May be <tt>null</tt>. */
- private AnnotationWriter ianns;
-
- /** The runtime visible type annotations of this method. May be <tt>null</tt> . */
- private AnnotationWriter tanns;
-
- /** The runtime invisible type annotations of this method. May be <tt>null</tt>. */
- private AnnotationWriter itanns;
-
- /** The runtime visible parameter annotations of this method. May be <tt>null</tt>. */
- private AnnotationWriter[] panns;
-
- /** The runtime invisible parameter annotations of this method. May be <tt>null</tt>. */
- private AnnotationWriter[] ipanns;
-
- /** The number of synthetic parameters of this method. */
- private int synthetics;
-
- /** The non standard attributes of the method. */
- private Attribute attrs;
-
- /** The bytecode of this method. */
- private ByteVector code = new ByteVector();
-
- /** Maximum stack size of this method. */
- private int maxStack;
-
- /** Maximum number of local variables for this method. */
- private int maxLocals;
-
- /** Number of local variables in the current stack map frame. */
- private int currentLocals;
-
- /** Number of stack map frames in the StackMapTable attribute. */
- int frameCount;
-
- /** The StackMapTable attribute. */
- private ByteVector stackMap;
-
- /** The offset of the last frame that was written in the StackMapTable attribute. */
- private int previousFrameOffset;
-
- /**
- * The last frame that was written in the StackMapTable attribute.
- *
- * @see #frame
- */
- private int[] previousFrame;
-
- /**
- * The current stack map frame. The first element contains the offset of the instruction to which the frame
- * corresponds, the second element is the number of locals and the third one is the number of stack elements. The
- * local variables start at index 3 and are followed by the operand stack values. In summary frame[0] = offset,
- * frame[1] = nLocal, frame[2] = nStack, frame[3] = nLocal. All types are encoded as integers, with the same format
- * as the one used in {@link Label}, but limited to BASE types.
- */
- private int[] frame;
-
- /** Number of elements in the exception handler list. */
- private int handlerCount;
-
- /** The first element in the exception handler list. */
- private Handler firstHandler;
-
- /** The last element in the exception handler list. */
- private Handler lastHandler;
-
- /** Number of entries in the MethodParameters attribute. */
- private int methodParametersCount;
-
- /** The MethodParameters attribute. */
- private ByteVector methodParameters;
-
- /** Number of entries in the LocalVariableTable attribute. */
- private int localVarCount;
-
- /** The LocalVariableTable attribute. */
- private ByteVector localVar;
-
- /** Number of entries in the LocalVariableTypeTable attribute. */
- private int localVarTypeCount;
-
- /** The LocalVariableTypeTable attribute. */
- private ByteVector localVarType;
-
- /** Number of entries in the LineNumberTable attribute. */
- private int lineNumberCount;
-
- /** The LineNumberTable attribute. */
- private ByteVector lineNumber;
-
- /** The start offset of the last visited instruction. */
- private int lastCodeOffset;
-
- /** The runtime visible type annotations of the code. May be <tt>null</tt>. */
- private AnnotationWriter ctanns;
-
- /** The runtime invisible type annotations of the code. May be <tt>null</tt>. */
- private AnnotationWriter ictanns;
-
- /** The non standard attributes of the method's code. */
- private Attribute cattrs;
-
- /** The number of subroutines in this method. */
- private int subroutines;
-
- // ------------------------------------------------------------------------
-
- /*
- * Fields for the control flow graph analysis algorithm (used to compute the
- * maximum stack size). A control flow graph contains one node per "basic
- * block", and one edge per "jump" from one basic block to another. Each
- * node (i.e., each basic block) is represented by the Label object that
- * corresponds to the first instruction of this basic block. Each node also
- * stores the list of its successors in the graph, as a linked list of Edge
- * objects.
- */
-
- /**
- * Indicates what must be automatically computed.
- *
- * @see #FRAMES
- * @see #INSERTED_FRAMES
- * @see #MAXS
- * @see #NOTHING
- */
- private final int compute;
-
- /**
- * A list of labels. This list is the list of basic blocks in the method, i.e. a list of Label objects linked to
- * each other by their {@link Label#successor} field, in the order they are visited by
- * {@link MethodVisitor#visitLabel}, and starting with the first basic block.
- */
- private Label labels;
-
- /** The previous basic block. */
- private Label previousBlock;
-
- /** The current basic block. */
- private Label currentBlock;
-
- /**
- * The (relative) stack size after the last visited instruction. This size is relative to the beginning of the
- * current basic block, i.e., the true stack size after the last visited instruction is equal to the
- * {@link Label#inputStackTop beginStackSize} of the current basic block plus <tt>stackSize</tt>.
- */
- private int stackSize;
-
- /**
- * The (relative) maximum stack size after the last visited instruction. This size is relative to the beginning of
- * the current basic block, i.e., the true maximum stack size after the last visited instruction is equal to the
- * {@link Label#inputStackTop beginStackSize} of the current basic block plus <tt>stackSize</tt>.
- */
- private int maxStackSize;
-
- // ------------------------------------------------------------------------
- // Constructor
- // ------------------------------------------------------------------------
-
- /**
- * Constructs a new {@link MethodWriter}.
- *
- * @param cw the class writer in which the method must be added.
- * @param access the method's access flags (see {@link Opcodes}).
- * @param name the method's name.
- * @param desc the method's descriptor (see {@link Type}).
- * @param signature the method's signature. May be <tt>null</tt>.
- * @param exceptions the internal names of the method's exceptions. May be <tt>null</tt>.
- * @param compute Indicates what must be automatically computed (see #compute).
- */
- MethodWriter(
- final ClassWriter cw,
- final int access,
- final String name,
- final String desc,
- final String signature,
- final String[] exceptions,
- final int compute) {
- super(Opcodes.ASM6);
- if (cw.firstMethod == null) {
- cw.firstMethod = this;
- } else {
- cw.lastMethod.mv = this;
- }
- cw.lastMethod = this;
- this.cw = cw;
- this.access = access;
- if ("cw.cr. More precisely, this field gives the index of the first byte to copied from cw.cr.b
+ * .
+ */
+ int classReaderOffset;
+
+ /**
+ * If not zero, indicates that the code of this method must be copied from the ClassReader associated to this writer
+ * in cw.cr. More precisely, this field gives the number of bytes to copied from cw.cr.b.
+ */
+ int classReaderLength;
+
+ /** Number of exceptions that can be thrown by this method. */
+ int exceptionCount;
+
+ /**
+ * The exceptions that can be thrown by this method. More precisely, this array contains the indexes of the constant
+ * pool items that contain the internal names of these exception classes.
+ */
+ int[] exceptions;
+
+ /** The annotation default attribute of this method. May be <tt>null</tt>. */
+ private ByteVector annd;
+
+ /** The runtime visible annotations of this method. May be <tt>null</tt>. */
+ private AnnotationWriter anns;
+
+ /** The runtime invisible annotations of this method. May be <tt>null</tt>. */
+ private AnnotationWriter ianns;
+
+ /** The runtime visible type annotations of this method. May be <tt>null</tt> . */
+ private AnnotationWriter tanns;
+
+ /** The runtime invisible type annotations of this method. May be <tt>null</tt>. */
+ private AnnotationWriter itanns;
+
+ /** The runtime visible parameter annotations of this method. May be <tt>null</tt>. */
+ private AnnotationWriter[] panns;
+
+ /** The runtime invisible parameter annotations of this method. May be <tt>null</tt>. */
+ private AnnotationWriter[] ipanns;
+
+ /** The number of synthetic parameters of this method. */
+ private int synthetics;
+
+ /** The non standard attributes of the method. */
+ private Attribute attrs;
+
+ /** The bytecode of this method. */
+ private ByteVector code = new ByteVector();
+
+ /** Maximum stack size of this method. */
+ private int maxStack;
+
+ /** Maximum number of local variables for this method. */
+ private int maxLocals;
+
+ /** Number of local variables in the current stack map frame. */
+ private int currentLocals;
+
+ /** Number of stack map frames in the StackMapTable attribute. */
+ int frameCount;
+
+ /** The StackMapTable attribute. */
+ private ByteVector stackMap;
+
+ /** The offset of the last frame that was written in the StackMapTable attribute. */
+ private int previousFrameOffset;
+
+ /**
+ * The last frame that was written in the StackMapTable attribute.
+ *
+ * @see #frame
+ */
+ private int[] previousFrame;
+
+ /**
+ * The current stack map frame. The first element contains the offset of the instruction to which the frame
+ * corresponds, the second element is the number of locals and the third one is the number of stack elements. The
+ * local variables start at index 3 and are followed by the operand stack values. In summary frame[0] = offset,
+ * frame[1] = nLocal, frame[2] = nStack, frame[3] = nLocal. All types are encoded as integers, with the same format
+ * as the one used in {@link Label}, but limited to BASE types.
+ */
+ private int[] frame;
+
+ /** Number of elements in the exception handler list. */
+ private int handlerCount;
+
+ /** The first element in the exception handler list. */
+ private Handler firstHandler;
+
+ /** The last element in the exception handler list. */
+ private Handler lastHandler;
+
+ /** Number of entries in the MethodParameters attribute. */
+ private int methodParametersCount;
+
+ /** The MethodParameters attribute. */
+ private ByteVector methodParameters;
+
+ /** Number of entries in the LocalVariableTable attribute. */
+ private int localVarCount;
+
+ /** The LocalVariableTable attribute. */
+ private ByteVector localVar;
+
+ /** Number of entries in the LocalVariableTypeTable attribute. */
+ private int localVarTypeCount;
+
+ /** The LocalVariableTypeTable attribute. */
+ private ByteVector localVarType;
+
+ /** Number of entries in the LineNumberTable attribute. */
+ private int lineNumberCount;
+
+ /** The LineNumberTable attribute. */
+ private ByteVector lineNumber;
+
+ /** The start offset of the last visited instruction. */
+ private int lastCodeOffset;
+
+ /** The runtime visible type annotations of the code. May be <tt>null</tt>. */
+ private AnnotationWriter ctanns;
+
+ /** The runtime invisible type annotations of the code. May be <tt>null</tt>. */
+ private AnnotationWriter ictanns;
+
+ /** The non standard attributes of the method's code. */
+ private Attribute cattrs;
+
+ /** The number of subroutines in this method. */
+ private int subroutines;
+
+ // ------------------------------------------------------------------------
+
+ /*
+ * Fields for the control flow graph analysis algorithm (used to compute the
+ * maximum stack size). A control flow graph contains one node per "basic
+ * block", and one edge per "jump" from one basic block to another. Each
+ * node (i.e., each basic block) is represented by the Label object that
+ * corresponds to the first instruction of this basic block. Each node also
+ * stores the list of its successors in the graph, as a linked list of Edge
+ * objects.
+ */
+
+ /**
+ * Indicates what must be automatically computed.
+ *
+ * @see #FRAMES
+ * @see #INSERTED_FRAMES
+ * @see #MAXS
+ * @see #NOTHING
+ */
+ private final int compute;
+
+ /**
+ * A list of labels. This list is the list of basic blocks in the method, i.e. a list of Label objects linked to
+ * each other by their {@link Label#successor} field, in the order they are visited by
+ * {@link MethodVisitor#visitLabel}, and starting with the first basic block.
+ */
+ private Label labels;
+
+ /** The previous basic block. */
+ private Label previousBlock;
+
+ /** The current basic block. */
+ private Label currentBlock;
+
+ /**
+ * The (relative) stack size after the last visited instruction. This size is relative to the beginning of the
+ * current basic block, i.e., the true stack size after the last visited instruction is equal to the
+ * {@link Label#inputStackTop beginStackSize} of the current basic block plus <tt>stackSize</tt>.
+ */
+ private int stackSize;
+
+ /**
+ * The (relative) maximum stack size after the last visited instruction. This size is relative to the beginning of
+ * the current basic block, i.e., the true maximum stack size after the last visited instruction is equal to the
+ * {@link Label#inputStackTop beginStackSize} of the current basic block plus <tt>stackSize</tt>.
+ */
+ private int maxStackSize;
+
+ // ------------------------------------------------------------------------
+ // Constructor
+ // ------------------------------------------------------------------------
+
+ /**
+ * Constructs a new {@link MethodWriter}.
+ *
+ * @param cw the class writer in which the method must be added.
+ * @param access the method's access flags (see {@link Opcodes}).
+ * @param name the method's name.
+ * @param desc the method's descriptor (see {@link Type}).
+ * @param signature the method's signature. May be <tt>null</tt>.
+ * @param exceptions the internal names of the method's exceptions. May be <tt>null</tt>.
+ * @param compute Indicates what must be automatically computed (see #compute).
+ */
+ MethodWriter(
+ final ClassWriter cw,
+ final int access,
+ final String name,
+ final String desc,
+ final String signature,
+ final String[] exceptions,
+ final int compute) {
+ super(Opcodes.ASM6);
+ if (cw.firstMethod == null) {
+ cw.firstMethod = this;
+ } else {
+ cw.lastMethod.mv = this;
+ }
+ cw.lastMethod = this;
+ this.cw = cw;
+ this.access = access;
+ if ("
- * Type.getType(methodDescriptor).
- *
- * @param methodDescriptor a method descriptor.
- * @return the Java type corresponding to the given method descriptor.
- */
- public static Type getMethodType(final String methodDescriptor) {
- return getType(methodDescriptor.toCharArray(), 0);
- }
-
- /**
- * Returns the Java method type corresponding to the given argument and return types.
- *
- * @param returnType the return type of the method.
- * @param argumentTypes the argument types of the method.
- * @return the Java type corresponding to the given argument and return types.
- */
- public static Type getMethodType(final Type returnType, final Type... argumentTypes) {
- return getType(getMethodDescriptor(returnType, argumentTypes));
- }
-
- /**
- * Returns the Java type corresponding to the given class.
- *
- * @param c a class.
- * @return the Java type corresponding to the given class.
- */
- public static Type getType(final Class> c) {
- if (c.isPrimitive()) {
- if (c == Integer.TYPE) {
- return INT_TYPE;
- } else if (c == Void.TYPE) {
- return VOID_TYPE;
- } else if (c == Boolean.TYPE) {
- return BOOLEAN_TYPE;
- } else if (c == Byte.TYPE) {
- return BYTE_TYPE;
- } else if (c == Character.TYPE) {
- return CHAR_TYPE;
- } else if (c == Short.TYPE) {
- return SHORT_TYPE;
- } else if (c == Double.TYPE) {
- return DOUBLE_TYPE;
- } else if (c == Float.TYPE) {
- return FLOAT_TYPE;
- } else /* if (c == Long.TYPE) */ {
- return LONG_TYPE;
- }
- } else {
- return getType(getDescriptor(c));
- }
- }
-
- /**
- * Returns the Java method type corresponding to the given constructor.
- *
- * @param c a {@link Constructor Constructor} object.
- * @return the Java method type corresponding to the given constructor.
- */
- public static Type getType(final Constructor> c) {
- return getType(getConstructorDescriptor(c));
- }
-
- /**
- * Returns the Java method type corresponding to the given method.
- *
- * @param m a {@link Method Method} object.
- * @return the Java method type corresponding to the given method.
- */
- public static Type getType(final Method m) {
- return getType(getMethodDescriptor(m));
- }
-
- /**
- * Returns the Java types corresponding to the argument types of the given method descriptor.
- *
- * @param methodDescriptor a method descriptor.
- * @return the Java types corresponding to the argument types of the given method descriptor.
- */
- public static Type[] getArgumentTypes(final String methodDescriptor) {
- char[] buf = methodDescriptor.toCharArray();
- int off = 1;
- int size = 0;
- while (true) {
- char car = buf[off++];
- if (car == ')') {
- break;
- } else if (car == 'L') {
- while (buf[off++] != ';') {
- // do nothing
- }
- ++size;
- } else if (car != '[') {
- ++size;
- }
- }
- Type[] args = new Type[size];
- off = 1;
- size = 0;
- while (buf[off] != ')') {
- args[size] = getType(buf, off);
- off += args[size].len + (args[size].sort == OBJECT ? 2 : 0);
- size += 1;
- }
- return args;
- }
-
- /**
- * Returns the Java types corresponding to the argument types of the given method.
- *
- * @param method a method.
- * @return the Java types corresponding to the argument types of the given method.
- */
- public static Type[] getArgumentTypes(final Method method) {
- Class>[] classes = method.getParameterTypes();
- Type[] types = new Type[classes.length];
- for (int i = classes.length - 1; i >= 0; --i) {
- types[i] = getType(classes[i]);
- }
- return types;
- }
-
- /**
- * Returns the Java type corresponding to the return type of the given method descriptor.
- *
- * @param methodDescriptor a method descriptor.
- * @return the Java type corresponding to the return type of the given method descriptor.
- */
- public static Type getReturnType(final String methodDescriptor) {
- char[] buf = methodDescriptor.toCharArray();
- int off = 1;
- while (true) {
- char car = buf[off++];
- if (car == ')') {
- return getType(buf, off);
- } else if (car == 'L') {
- while (buf[off++] != ';') {
- // do nothing
- }
- }
- }
- }
-
- /**
- * Returns the Java type corresponding to the return type of the given method.
- *
- * @param method a method.
- * @return the Java type corresponding to the return type of the given method.
- */
- public static Type getReturnType(final Method method) {
- return getType(method.getReturnType());
- }
-
- /**
- * Computes the size of the arguments and of the return value of a method.
- *
- * @param desc the descriptor of a method.
- * @return the size of the arguments of the method (plus one for the implicit this argument), argSize, and the size
- * of its return value, retSize, packed into a single int i = <tt>(argSize << 2) |
- * retSize</tt> (argSize is therefore equal to <tt>i >> 2</tt>, and retSize to
- * <tt>i & 0x03</tt>).
- */
- public static int getArgumentsAndReturnSizes(final String desc) {
- int n = 1;
- int c = 1;
- while (true) {
- char car = desc.charAt(c++);
- if (car == ')') {
- car = desc.charAt(c);
- return n << 2 | (car == 'V' ? 0 : (car == 'D' || car == 'J' ? 2 : 1));
- } else if (car == 'L') {
- while (desc.charAt(c++) != ';') {
- // do nothing
- }
- n += 1;
- } else if (car == '[') {
- while ((car = desc.charAt(c)) == '[') {
- ++c;
- }
- if (car == 'D' || car == 'J') {
- n -= 1;
- }
- } else if (car == 'D' || car == 'J') {
- n += 2;
- } else {
- n += 1;
- }
- }
- }
-
- /**
- * Returns the Java type corresponding to the given type descriptor. For method descriptors, buf is supposed to
- * contain nothing more than the descriptor itself.
- *
- * @param buf a buffer containing a type descriptor.
- * @param off the offset of this descriptor in the previous buffer.
- * @return the Java type corresponding to the given type descriptor.
- */
- private static Type getType(final char[] buf, final int off) {
- int len;
- switch (buf[off]) {
- case 'V':
- return VOID_TYPE;
- case 'Z':
- return BOOLEAN_TYPE;
- case 'C':
- return CHAR_TYPE;
- case 'B':
- return BYTE_TYPE;
- case 'S':
- return SHORT_TYPE;
- case 'I':
- return INT_TYPE;
- case 'F':
- return FLOAT_TYPE;
- case 'J':
- return LONG_TYPE;
- case 'D':
- return DOUBLE_TYPE;
- case '[':
- len = 1;
- while (buf[off + len] == '[') {
- ++len;
- }
- if (buf[off + len] == 'L') {
- ++len;
- while (buf[off + len] != ';') {
- ++len;
- }
- }
- return new Type(ARRAY, buf, off, len + 1);
- case 'L':
- len = 1;
- while (buf[off + len] != ';') {
- ++len;
- }
- return new Type(OBJECT, buf, off + 1, len - 1);
- // case '(':
- default:
- return new Type(METHOD, buf, off, buf.length - off);
- }
- }
-
- // ------------------------------------------------------------------------
- // Accessors
- // ------------------------------------------------------------------------
-
- /**
- * Returns the sort of this Java type.
- *
- * @return {@link #VOID VOID}, {@link #BOOLEAN BOOLEAN}, {@link #CHAR CHAR}, {@link #BYTE BYTE}, {@link #SHORT
- * SHORT}, {@link #INT INT}, {@link #FLOAT FLOAT}, {@link #LONG LONG}, {@link #DOUBLE DOUBLE}, {@link #ARRAY
- * ARRAY}, {@link #OBJECT OBJECT} or {@link #METHOD METHOD}.
- */
- public int getSort() {
- return sort;
- }
-
- /**
- * Returns the number of dimensions of this array type. This method should only be used for an array type.
- *
- * @return the number of dimensions of this array type.
- */
- public int getDimensions() {
- int i = 1;
- while (buf[off + i] == '[') {
- ++i;
- }
- return i;
- }
-
- /**
- * Returns the type of the elements of this array type. This method should only be used for an array type.
- *
- * @return Returns the type of the elements of this array type.
- */
- public Type getElementType() {
- return getType(buf, off + getDimensions());
- }
-
- /**
- * Returns the binary name of the class corresponding to this type. This method must not be used on method types.
- *
- * @return the binary name of the class corresponding to this type.
- */
- public String getClassName() {
- switch (sort) {
- case VOID:
- return "void";
- case BOOLEAN:
- return "boolean";
- case CHAR:
- return "char";
- case BYTE:
- return "byte";
- case SHORT:
- return "short";
- case INT:
- return "int";
- case FLOAT:
- return "float";
- case LONG:
- return "long";
- case DOUBLE:
- return "double";
- case ARRAY:
- StringBuilder sb = new StringBuilder(getElementType().getClassName());
- for (int i = getDimensions(); i > 0; --i) {
- sb.append("[]");
- }
- return sb.toString();
- case OBJECT:
- return new String(buf, off, len).replace('/', '.');
- default:
- return null;
- }
- }
-
- /**
- * Returns the internal name of the class corresponding to this object or array type. The internal name of a class
- * is its fully qualified name (as returned by Class.getName(), where '.' are replaced by '/'. This method should
- * only be used for an object or array type.
- *
- * @return the internal name of the class corresponding to this object type.
- */
- public String getInternalName() {
- return new String(buf, off, len);
- }
-
- /**
- * Returns the argument types of methods of this type. This method should only be used for method types.
- *
- * @return the argument types of methods of this type.
- */
- public Type[] getArgumentTypes() {
- return getArgumentTypes(getDescriptor());
- }
-
- /**
- * Returns the return type of methods of this type. This method should only be used for method types.
- *
- * @return the return type of methods of this type.
- */
- public Type getReturnType() {
- return getReturnType(getDescriptor());
- }
-
- /**
- * Returns the size of the arguments and of the return value of methods of this type. This method should only be
- * used for method types.
- *
- * @return the size of the arguments (plus one for the implicit this argument), argSize, and the size of the return
- * value, retSize, packed into a single int i = <tt>(argSize << 2) | retSize</tt> (argSize
- * is therefore equal to <tt>i >> 2</tt>, and retSize to <tt>i &
- * 0x03</tt>).
- */
- public int getArgumentsAndReturnSizes() {
- return getArgumentsAndReturnSizes(getDescriptor());
- }
-
- // ------------------------------------------------------------------------
- // Conversion to type descriptors
- // ------------------------------------------------------------------------
-
- /**
- * Returns the descriptor corresponding to this Java type.
- *
- * @return the descriptor corresponding to this Java type.
- */
- public String getDescriptor() {
- StringBuilder buf = new StringBuilder();
- getDescriptor(buf);
- return buf.toString();
- }
-
- /**
- * Returns the descriptor corresponding to the given argument and return types.
- *
- * @param returnType the return type of the method.
- * @param argumentTypes the argument types of the method.
- * @return the descriptor corresponding to the given argument and return types.
- */
- public static String getMethodDescriptor(final Type returnType, final Type... argumentTypes) {
- StringBuilder buf = new StringBuilder();
- buf.append('(');
- for (int i = 0; i < argumentTypes.length; ++i) {
- argumentTypes[i].getDescriptor(buf);
- }
- buf.append(')');
- returnType.getDescriptor(buf);
- return buf.toString();
- }
-
- /**
- * Appends the descriptor corresponding to this Java type to the given string buffer.
- *
- * @param buf the string buffer to which the descriptor must be appended.
- */
- private void getDescriptor(final StringBuilder buf) {
- if (this.buf == null) {
- // descriptor is in byte 3 of 'off' for primitive types (buf ==
- // null)
- buf.append((char) ((off & 0xFF000000) >>> 24));
- } else if (sort == OBJECT) {
- buf.append('L');
- buf.append(this.buf, off, len);
- buf.append(';');
- } else { // sort == ARRAY || sort == METHOD
- buf.append(this.buf, off, len);
- }
- }
-
- // ------------------------------------------------------------------------
- // Direct conversion from classes to type descriptors,
- // without intermediate Type objects
- // ------------------------------------------------------------------------
-
- /**
- * Returns the internal name of the given class. The internal name of a class is its fully qualified name, as
- * returned by Class.getName(), where '.' are replaced by '/'.
- *
- * @param c an object or array class.
- * @return the internal name of the given class.
- */
- public static String getInternalName(final Class> c) {
- return c.getName().replace('.', '/');
- }
-
- /**
- * Returns the descriptor corresponding to the given Java type.
- *
- * @param c an object class, a primitive class or an array class.
- * @return the descriptor corresponding to the given class.
- */
- public static String getDescriptor(final Class> c) {
- StringBuilder buf = new StringBuilder();
- getDescriptor(buf, c);
- return buf.toString();
- }
-
- /**
- * Returns the descriptor corresponding to the given constructor.
- *
- * @param c a {@link Constructor Constructor} object.
- * @return the descriptor of the given constructor.
- */
- public static String getConstructorDescriptor(final Constructor> c) {
- Class>[] parameters = c.getParameterTypes();
- StringBuilder buf = new StringBuilder();
- buf.append('(');
- for (int i = 0; i < parameters.length; ++i) {
- getDescriptor(buf, parameters[i]);
- }
- return buf.append(")V").toString();
- }
-
- /**
- * Returns the descriptor corresponding to the given method.
- *
- * @param m a {@link Method Method} object.
- * @return the descriptor of the given method.
- */
- public static String getMethodDescriptor(final Method m) {
- Class>[] parameters = m.getParameterTypes();
- StringBuilder buf = new StringBuilder();
- buf.append('(');
- for (int i = 0; i < parameters.length; ++i) {
- getDescriptor(buf, parameters[i]);
- }
- buf.append(')');
- getDescriptor(buf, m.getReturnType());
- return buf.toString();
- }
-
- /**
- * Appends the descriptor of the given class to the given string buffer.
- *
- * @param buf the string buffer to which the descriptor must be appended.
- * @param c the class whose descriptor must be computed.
- */
- private static void getDescriptor(final StringBuilder buf, final Class> c) {
- Class> d = c;
- while (true) {
- if (d.isPrimitive()) {
- char car;
- if (d == Integer.TYPE) {
- car = 'I';
- } else if (d == Void.TYPE) {
- car = 'V';
- } else if (d == Boolean.TYPE) {
- car = 'Z';
- } else if (d == Byte.TYPE) {
- car = 'B';
- } else if (d == Character.TYPE) {
- car = 'C';
- } else if (d == Short.TYPE) {
- car = 'S';
- } else if (d == Double.TYPE) {
- car = 'D';
- } else if (d == Float.TYPE) {
- car = 'F';
- } else /* if (d == Long.TYPE) */ {
- car = 'J';
- }
- buf.append(car);
- return;
- } else if (d.isArray()) {
- buf.append('[');
- d = d.getComponentType();
- } else {
- buf.append('L');
- String name = d.getName();
- int len = name.length();
- for (int i = 0; i < len; ++i) {
- char car = name.charAt(i);
- buf.append(car == '.' ? '/' : car);
- }
- buf.append(';');
- return;
- }
- }
- }
-
- // ------------------------------------------------------------------------
- // Corresponding size and opcodes
- // ------------------------------------------------------------------------
-
- /**
- * Returns the size of values of this type. This method must not be used for method types.
- *
- * @return the size of values of this type, i.e., 2 for <tt>long</tt> and
- * <tt>double</tt>, 0 for <tt>void</tt> and 1 otherwise.
- */
- public int getSize() {
- // the size is in byte 0 of 'off' for primitive types (buf == null)
- return buf == null ? (off & 0xFF) : 1;
- }
-
- /**
- * Returns a JVM instruction opcode adapted to this Java type. This method must not be used for method types.
- *
- * @param opcode a JVM instruction opcode. This opcode must be one of ILOAD, ISTORE, IALOAD, IASTORE, IADD, ISUB,
- * IMUL, IDIV, IREM, INEG, ISHL, ISHR, IUSHR, IAND, IOR, IXOR and IRETURN.
- * @return an opcode that is similar to the given opcode, but adapted to this Java type. For example, if this type
- * is <tt>float</tt> and <tt>opcode</tt> is IRETURN, this method returns
- * FRETURN.
- */
- public int getOpcode(final int opcode) {
- if (opcode == Opcodes.IALOAD || opcode == Opcodes.IASTORE) {
- // the offset for IALOAD or IASTORE is in byte 1 of 'off' for
- // primitive types (buf == null)
- return opcode + (buf == null ? (off & 0xFF00) >> 8 : 4);
- } else {
- // the offset for other instructions is in byte 2 of 'off' for
- // primitive types (buf == null)
- return opcode + (buf == null ? (off & 0xFF0000) >> 16 : 4);
- }
- }
-
- // ------------------------------------------------------------------------
- // Equals, hashCode and toString
- // ------------------------------------------------------------------------
-
- /**
- * Tests if the given object is equal to this type.
- *
- * @param o the object to be compared to this type.
- * @return <tt>true</tt> if the given object is equal to this type.
- */
- @Override
- public boolean equals(final Object o) {
- if (this == o) {
- return true;
- }
- if (!(o instanceof Type)) {
- return false;
- }
- Type t = (Type) o;
- if (sort != t.sort) {
- return false;
- }
- if (sort >= ARRAY) {
- if (len != t.len) {
- return false;
- }
- for (int i = off, j = t.off, end = i + len; i < end; i++, j++) {
- if (buf[i] != t.buf[j]) {
- return false;
- }
- }
- }
- return true;
- }
-
- /**
- * Returns a hash code value for this type.
- *
- * @return a hash code value for this type.
- */
- @Override
- public int hashCode() {
- int hc = 13 * sort;
- if (sort >= ARRAY) {
- for (int i = off, end = i + len; i < end; i++) {
- hc = 17 * (hc + buf[i]);
- }
- }
- return hc;
- }
-
- /**
- * Returns a string representation of this type.
- *
- * @return the descriptor of this type.
- */
- @Override
- public String toString() {
- return getDescriptor();
- }
-}
+/*
+ * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ */
+
+/*
+ *
+ *
+ *
+ *
+ *
+ * ASM: a very small and fast Java bytecode manipulation framework
+ * Copyright (c) 2000-2011 INRIA, France Telecom
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.redkale.asm;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+
+/**
+ * A Java field or method type. This class can be used to make it easier to manipulate type and method descriptors.
+ *
+ * @author Eric Bruneton
+ * @author Chris Nokleberg
+ */
+public class Type {
+
+ /** The sort of the <tt>void</tt> type. See {@link #getSort getSort}. */
+ public static final int VOID = 0;
+
+ /** The sort of the <tt>boolean</tt> type. See {@link #getSort getSort}. */
+ public static final int BOOLEAN = 1;
+
+ /** The sort of the <tt>char</tt> type. See {@link #getSort getSort}. */
+ public static final int CHAR = 2;
+
+ /** The sort of the <tt>byte</tt> type. See {@link #getSort getSort}. */
+ public static final int BYTE = 3;
+
+ /** The sort of the <tt>short</tt> type. See {@link #getSort getSort}. */
+ public static final int SHORT = 4;
+
+ /** The sort of the <tt>int</tt> type. See {@link #getSort getSort}. */
+ public static final int INT = 5;
+
+ /** The sort of the <tt>float</tt> type. See {@link #getSort getSort}. */
+ public static final int FLOAT = 6;
+
+ /** The sort of the <tt>long</tt> type. See {@link #getSort getSort}. */
+ public static final int LONG = 7;
+
+ /** The sort of the <tt>double</tt> type. See {@link #getSort getSort}. */
+ public static final int DOUBLE = 8;
+
+ /** The sort of array reference types. See {@link #getSort getSort}. */
+ public static final int ARRAY = 9;
+
+ /** The sort of object reference types. See {@link #getSort getSort}. */
+ public static final int OBJECT = 10;
+
+ /** The sort of method types. See {@link #getSort getSort}. */
+ public static final int METHOD = 11;
+
+ /** The <tt>void</tt> type. */
+ public static final Type VOID_TYPE = new Type(VOID, null, ('V' << 24) | (5 << 16) | (0 << 8) | 0, 1);
+
+ /** The <tt>boolean</tt> type. */
+ public static final Type BOOLEAN_TYPE = new Type(BOOLEAN, null, ('Z' << 24) | (0 << 16) | (5 << 8) | 1, 1);
+
+ /** The <tt>char</tt> type. */
+ public static final Type CHAR_TYPE = new Type(CHAR, null, ('C' << 24) | (0 << 16) | (6 << 8) | 1, 1);
+
+ /** The <tt>byte</tt> type. */
+ public static final Type BYTE_TYPE = new Type(BYTE, null, ('B' << 24) | (0 << 16) | (5 << 8) | 1, 1);
+
+ /** The <tt>short</tt> type. */
+ public static final Type SHORT_TYPE = new Type(SHORT, null, ('S' << 24) | (0 << 16) | (7 << 8) | 1, 1);
+
+ /** The <tt>int</tt> type. */
+ public static final Type INT_TYPE = new Type(INT, null, ('I' << 24) | (0 << 16) | (0 << 8) | 1, 1);
+
+ /** The <tt>float</tt> type. */
+ public static final Type FLOAT_TYPE = new Type(FLOAT, null, ('F' << 24) | (2 << 16) | (2 << 8) | 1, 1);
+
+ /** The <tt>long</tt> type. */
+ public static final Type LONG_TYPE = new Type(LONG, null, ('J' << 24) | (1 << 16) | (1 << 8) | 2, 1);
+
+ /** The <tt>double</tt> type. */
+ public static final Type DOUBLE_TYPE = new Type(DOUBLE, null, ('D' << 24) | (3 << 16) | (3 << 8) | 2, 1);
+
+ // ------------------------------------------------------------------------
+ // Fields
+ // ------------------------------------------------------------------------
+
+ /** The sort of this Java type. */
+ private final int sort;
+
+ /** A buffer containing the internal name of this Java type. This field is only used for reference types. */
+ private final char[] buf;
+
+ /**
+ * The offset of the internal name of this Java type in {@link #buf buf} or, for primitive types, the size,
+ * descriptor and getOpcode offsets for this type (byte 0 contains the size, byte 1 the descriptor, byte 2 the
+ * offset for IALOAD or IASTORE, byte 3 the offset for all other instructions).
+ */
+ private final int off;
+
+ /** The length of the internal name of this Java type. */
+ private final int len;
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+
+ /**
+ * Constructs a reference type.
+ *
+ * @param sort the sort of the reference type to be constructed.
+ * @param buf a buffer containing the descriptor of the previous type.
+ * @param off the offset of this descriptor in the previous buffer.
+ * @param len the length of this descriptor.
+ */
+ private Type(final int sort, final char[] buf, final int off, final int len) {
+ this.sort = sort;
+ this.buf = buf;
+ this.off = off;
+ this.len = len;
+ }
+
+ /**
+ * Returns the Java type corresponding to the given type descriptor.
+ *
+ * @param typeDescriptor a field or method type descriptor.
+ * @return the Java type corresponding to the given type descriptor.
+ */
+ public static Type getType(final String typeDescriptor) {
+ return getType(typeDescriptor.toCharArray(), 0);
+ }
+
+ /**
+ * Returns the Java type corresponding to the given internal name.
+ *
+ * @param internalName an internal name.
+ * @return the Java type corresponding to the given internal name.
+ */
+ public static Type getObjectType(final String internalName) {
+ char[] buf = internalName.toCharArray();
+ return new Type(buf[0] == '[' ? ARRAY : OBJECT, buf, 0, buf.length);
+ }
+
+ /**
+ * Returns the Java type corresponding to the given method descriptor. Equivalent to
+ * Type.getType(methodDescriptor).
+ *
+ * @param methodDescriptor a method descriptor.
+ * @return the Java type corresponding to the given method descriptor.
+ */
+ public static Type getMethodType(final String methodDescriptor) {
+ return getType(methodDescriptor.toCharArray(), 0);
+ }
+
+ /**
+ * Returns the Java method type corresponding to the given argument and return types.
+ *
+ * @param returnType the return type of the method.
+ * @param argumentTypes the argument types of the method.
+ * @return the Java type corresponding to the given argument and return types.
+ */
+ public static Type getMethodType(final Type returnType, final Type... argumentTypes) {
+ return getType(getMethodDescriptor(returnType, argumentTypes));
+ }
+
+ /**
+ * Returns the Java type corresponding to the given class.
+ *
+ * @param c a class.
+ * @return the Java type corresponding to the given class.
+ */
+ public static Type getType(final Class> c) {
+ if (c.isPrimitive()) {
+ if (c == Integer.TYPE) {
+ return INT_TYPE;
+ } else if (c == Void.TYPE) {
+ return VOID_TYPE;
+ } else if (c == Boolean.TYPE) {
+ return BOOLEAN_TYPE;
+ } else if (c == Byte.TYPE) {
+ return BYTE_TYPE;
+ } else if (c == Character.TYPE) {
+ return CHAR_TYPE;
+ } else if (c == Short.TYPE) {
+ return SHORT_TYPE;
+ } else if (c == Double.TYPE) {
+ return DOUBLE_TYPE;
+ } else if (c == Float.TYPE) {
+ return FLOAT_TYPE;
+ } else /* if (c == Long.TYPE) */ {
+ return LONG_TYPE;
+ }
+ } else {
+ return getType(getDescriptor(c));
+ }
+ }
+
+ /**
+ * Returns the Java method type corresponding to the given constructor.
+ *
+ * @param c a {@link Constructor Constructor} object.
+ * @return the Java method type corresponding to the given constructor.
+ */
+ public static Type getType(final Constructor> c) {
+ return getType(getConstructorDescriptor(c));
+ }
+
+ /**
+ * Returns the Java method type corresponding to the given method.
+ *
+ * @param m a {@link Method Method} object.
+ * @return the Java method type corresponding to the given method.
+ */
+ public static Type getType(final Method m) {
+ return getType(getMethodDescriptor(m));
+ }
+
+ /**
+ * Returns the Java types corresponding to the argument types of the given method descriptor.
+ *
+ * @param methodDescriptor a method descriptor.
+ * @return the Java types corresponding to the argument types of the given method descriptor.
+ */
+ public static Type[] getArgumentTypes(final String methodDescriptor) {
+ char[] buf = methodDescriptor.toCharArray();
+ int off = 1;
+ int size = 0;
+ while (true) {
+ char car = buf[off++];
+ if (car == ')') {
+ break;
+ } else if (car == 'L') {
+ while (buf[off++] != ';') {
+ // do nothing
+ }
+ ++size;
+ } else if (car != '[') {
+ ++size;
+ }
+ }
+ Type[] args = new Type[size];
+ off = 1;
+ size = 0;
+ while (buf[off] != ')') {
+ args[size] = getType(buf, off);
+ off += args[size].len + (args[size].sort == OBJECT ? 2 : 0);
+ size += 1;
+ }
+ return args;
+ }
+
+ /**
+ * Returns the Java types corresponding to the argument types of the given method.
+ *
+ * @param method a method.
+ * @return the Java types corresponding to the argument types of the given method.
+ */
+ public static Type[] getArgumentTypes(final Method method) {
+ Class>[] classes = method.getParameterTypes();
+ Type[] types = new Type[classes.length];
+ for (int i = classes.length - 1; i >= 0; --i) {
+ types[i] = getType(classes[i]);
+ }
+ return types;
+ }
+
+ /**
+ * Returns the Java type corresponding to the return type of the given method descriptor.
+ *
+ * @param methodDescriptor a method descriptor.
+ * @return the Java type corresponding to the return type of the given method descriptor.
+ */
+ public static Type getReturnType(final String methodDescriptor) {
+ char[] buf = methodDescriptor.toCharArray();
+ int off = 1;
+ while (true) {
+ char car = buf[off++];
+ if (car == ')') {
+ return getType(buf, off);
+ } else if (car == 'L') {
+ while (buf[off++] != ';') {
+ // do nothing
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns the Java type corresponding to the return type of the given method.
+ *
+ * @param method a method.
+ * @return the Java type corresponding to the return type of the given method.
+ */
+ public static Type getReturnType(final Method method) {
+ return getType(method.getReturnType());
+ }
+
+ /**
+ * Computes the size of the arguments and of the return value of a method.
+ *
+ * @param desc the descriptor of a method.
+ * @return the size of the arguments of the method (plus one for the implicit this argument), argSize, and the size
+ * of its return value, retSize, packed into a single int i = <tt>(argSize << 2) |
+ * retSize</tt> (argSize is therefore equal to <tt>i >> 2</tt>, and retSize to
+ * <tt>i & 0x03</tt>).
+ */
+ public static int getArgumentsAndReturnSizes(final String desc) {
+ int n = 1;
+ int c = 1;
+ while (true) {
+ char car = desc.charAt(c++);
+ if (car == ')') {
+ car = desc.charAt(c);
+ return n << 2 | (car == 'V' ? 0 : (car == 'D' || car == 'J' ? 2 : 1));
+ } else if (car == 'L') {
+ while (desc.charAt(c++) != ';') {
+ // do nothing
+ }
+ n += 1;
+ } else if (car == '[') {
+ while ((car = desc.charAt(c)) == '[') {
+ ++c;
+ }
+ if (car == 'D' || car == 'J') {
+ n -= 1;
+ }
+ } else if (car == 'D' || car == 'J') {
+ n += 2;
+ } else {
+ n += 1;
+ }
+ }
+ }
+
+ /**
+ * Returns the Java type corresponding to the given type descriptor. For method descriptors, buf is supposed to
+ * contain nothing more than the descriptor itself.
+ *
+ * @param buf a buffer containing a type descriptor.
+ * @param off the offset of this descriptor in the previous buffer.
+ * @return the Java type corresponding to the given type descriptor.
+ */
+ private static Type getType(final char[] buf, final int off) {
+ int len;
+ switch (buf[off]) {
+ case 'V':
+ return VOID_TYPE;
+ case 'Z':
+ return BOOLEAN_TYPE;
+ case 'C':
+ return CHAR_TYPE;
+ case 'B':
+ return BYTE_TYPE;
+ case 'S':
+ return SHORT_TYPE;
+ case 'I':
+ return INT_TYPE;
+ case 'F':
+ return FLOAT_TYPE;
+ case 'J':
+ return LONG_TYPE;
+ case 'D':
+ return DOUBLE_TYPE;
+ case '[':
+ len = 1;
+ while (buf[off + len] == '[') {
+ ++len;
+ }
+ if (buf[off + len] == 'L') {
+ ++len;
+ while (buf[off + len] != ';') {
+ ++len;
+ }
+ }
+ return new Type(ARRAY, buf, off, len + 1);
+ case 'L':
+ len = 1;
+ while (buf[off + len] != ';') {
+ ++len;
+ }
+ return new Type(OBJECT, buf, off + 1, len - 1);
+ // case '(':
+ default:
+ return new Type(METHOD, buf, off, buf.length - off);
+ }
+ }
+
+ // ------------------------------------------------------------------------
+ // Accessors
+ // ------------------------------------------------------------------------
+
+ /**
+ * Returns the sort of this Java type.
+ *
+ * @return {@link #VOID VOID}, {@link #BOOLEAN BOOLEAN}, {@link #CHAR CHAR}, {@link #BYTE BYTE}, {@link #SHORT
+ * SHORT}, {@link #INT INT}, {@link #FLOAT FLOAT}, {@link #LONG LONG}, {@link #DOUBLE DOUBLE}, {@link #ARRAY
+ * ARRAY}, {@link #OBJECT OBJECT} or {@link #METHOD METHOD}.
+ */
+ public int getSort() {
+ return sort;
+ }
+
+ /**
+ * Returns the number of dimensions of this array type. This method should only be used for an array type.
+ *
+ * @return the number of dimensions of this array type.
+ */
+ public int getDimensions() {
+ int i = 1;
+ while (buf[off + i] == '[') {
+ ++i;
+ }
+ return i;
+ }
+
+ /**
+ * Returns the type of the elements of this array type. This method should only be used for an array type.
+ *
+ * @return Returns the type of the elements of this array type.
+ */
+ public Type getElementType() {
+ return getType(buf, off + getDimensions());
+ }
+
+ /**
+ * Returns the binary name of the class corresponding to this type. This method must not be used on method types.
+ *
+ * @return the binary name of the class corresponding to this type.
+ */
+ public String getClassName() {
+ switch (sort) {
+ case VOID:
+ return "void";
+ case BOOLEAN:
+ return "boolean";
+ case CHAR:
+ return "char";
+ case BYTE:
+ return "byte";
+ case SHORT:
+ return "short";
+ case INT:
+ return "int";
+ case FLOAT:
+ return "float";
+ case LONG:
+ return "long";
+ case DOUBLE:
+ return "double";
+ case ARRAY:
+ StringBuilder sb = new StringBuilder(getElementType().getClassName());
+ for (int i = getDimensions(); i > 0; --i) {
+ sb.append("[]");
+ }
+ return sb.toString();
+ case OBJECT:
+ return new String(buf, off, len).replace('/', '.');
+ default:
+ return null;
+ }
+ }
+
+ /**
+ * Returns the internal name of the class corresponding to this object or array type. The internal name of a class
+ * is its fully qualified name (as returned by Class.getName(), where '.' are replaced by '/'. This method should
+ * only be used for an object or array type.
+ *
+ * @return the internal name of the class corresponding to this object type.
+ */
+ public String getInternalName() {
+ return new String(buf, off, len);
+ }
+
+ /**
+ * Returns the argument types of methods of this type. This method should only be used for method types.
+ *
+ * @return the argument types of methods of this type.
+ */
+ public Type[] getArgumentTypes() {
+ return getArgumentTypes(getDescriptor());
+ }
+
+ /**
+ * Returns the return type of methods of this type. This method should only be used for method types.
+ *
+ * @return the return type of methods of this type.
+ */
+ public Type getReturnType() {
+ return getReturnType(getDescriptor());
+ }
+
+ /**
+ * Returns the size of the arguments and of the return value of methods of this type. This method should only be
+ * used for method types.
+ *
+ * @return the size of the arguments (plus one for the implicit this argument), argSize, and the size of the return
+ * value, retSize, packed into a single int i = <tt>(argSize << 2) | retSize</tt> (argSize
+ * is therefore equal to <tt>i >> 2</tt>, and retSize to <tt>i &
+ * 0x03</tt>).
+ */
+ public int getArgumentsAndReturnSizes() {
+ return getArgumentsAndReturnSizes(getDescriptor());
+ }
+
+ // ------------------------------------------------------------------------
+ // Conversion to type descriptors
+ // ------------------------------------------------------------------------
+
+ /**
+ * Returns the descriptor corresponding to this Java type.
+ *
+ * @return the descriptor corresponding to this Java type.
+ */
+ public String getDescriptor() {
+ StringBuilder buf = new StringBuilder();
+ getDescriptor(buf);
+ return buf.toString();
+ }
+
+ /**
+ * Returns the descriptor corresponding to the given argument and return types.
+ *
+ * @param returnType the return type of the method.
+ * @param argumentTypes the argument types of the method.
+ * @return the descriptor corresponding to the given argument and return types.
+ */
+ public static String getMethodDescriptor(final Type returnType, final Type... argumentTypes) {
+ StringBuilder buf = new StringBuilder();
+ buf.append('(');
+ for (int i = 0; i < argumentTypes.length; ++i) {
+ argumentTypes[i].getDescriptor(buf);
+ }
+ buf.append(')');
+ returnType.getDescriptor(buf);
+ return buf.toString();
+ }
+
+ /**
+ * Appends the descriptor corresponding to this Java type to the given string buffer.
+ *
+ * @param buf the string buffer to which the descriptor must be appended.
+ */
+ private void getDescriptor(final StringBuilder buf) {
+ if (this.buf == null) {
+ // descriptor is in byte 3 of 'off' for primitive types (buf ==
+ // null)
+ buf.append((char) ((off & 0xFF000000) >>> 24));
+ } else if (sort == OBJECT) {
+ buf.append('L');
+ buf.append(this.buf, off, len);
+ buf.append(';');
+ } else { // sort == ARRAY || sort == METHOD
+ buf.append(this.buf, off, len);
+ }
+ }
+
+ // ------------------------------------------------------------------------
+ // Direct conversion from classes to type descriptors,
+ // without intermediate Type objects
+ // ------------------------------------------------------------------------
+
+ /**
+ * Returns the internal name of the given class. The internal name of a class is its fully qualified name, as
+ * returned by Class.getName(), where '.' are replaced by '/'.
+ *
+ * @param c an object or array class.
+ * @return the internal name of the given class.
+ */
+ public static String getInternalName(final Class> c) {
+ return c.getName().replace('.', '/');
+ }
+
+ /**
+ * Returns the descriptor corresponding to the given Java type.
+ *
+ * @param c an object class, a primitive class or an array class.
+ * @return the descriptor corresponding to the given class.
+ */
+ public static String getDescriptor(final Class> c) {
+ StringBuilder buf = new StringBuilder();
+ getDescriptor(buf, c);
+ return buf.toString();
+ }
+
+ /**
+ * Returns the descriptor corresponding to the given constructor.
+ *
+ * @param c a {@link Constructor Constructor} object.
+ * @return the descriptor of the given constructor.
+ */
+ public static String getConstructorDescriptor(final Constructor> c) {
+ Class>[] parameters = c.getParameterTypes();
+ StringBuilder buf = new StringBuilder();
+ buf.append('(');
+ for (int i = 0; i < parameters.length; ++i) {
+ getDescriptor(buf, parameters[i]);
+ }
+ return buf.append(")V").toString();
+ }
+
+ /**
+ * Returns the descriptor corresponding to the given method.
+ *
+ * @param m a {@link Method Method} object.
+ * @return the descriptor of the given method.
+ */
+ public static String getMethodDescriptor(final Method m) {
+ Class>[] parameters = m.getParameterTypes();
+ StringBuilder buf = new StringBuilder();
+ buf.append('(');
+ for (int i = 0; i < parameters.length; ++i) {
+ getDescriptor(buf, parameters[i]);
+ }
+ buf.append(')');
+ getDescriptor(buf, m.getReturnType());
+ return buf.toString();
+ }
+
+ /**
+ * Appends the descriptor of the given class to the given string buffer.
+ *
+ * @param buf the string buffer to which the descriptor must be appended.
+ * @param c the class whose descriptor must be computed.
+ */
+ private static void getDescriptor(final StringBuilder buf, final Class> c) {
+ Class> d = c;
+ while (true) {
+ if (d.isPrimitive()) {
+ char car;
+ if (d == Integer.TYPE) {
+ car = 'I';
+ } else if (d == Void.TYPE) {
+ car = 'V';
+ } else if (d == Boolean.TYPE) {
+ car = 'Z';
+ } else if (d == Byte.TYPE) {
+ car = 'B';
+ } else if (d == Character.TYPE) {
+ car = 'C';
+ } else if (d == Short.TYPE) {
+ car = 'S';
+ } else if (d == Double.TYPE) {
+ car = 'D';
+ } else if (d == Float.TYPE) {
+ car = 'F';
+ } else /* if (d == Long.TYPE) */ {
+ car = 'J';
+ }
+ buf.append(car);
+ return;
+ } else if (d.isArray()) {
+ buf.append('[');
+ d = d.getComponentType();
+ } else {
+ buf.append('L');
+ String name = d.getName();
+ int len = name.length();
+ for (int i = 0; i < len; ++i) {
+ char car = name.charAt(i);
+ buf.append(car == '.' ? '/' : car);
+ }
+ buf.append(';');
+ return;
+ }
+ }
+ }
+
+ // ------------------------------------------------------------------------
+ // Corresponding size and opcodes
+ // ------------------------------------------------------------------------
+
+ /**
+ * Returns the size of values of this type. This method must not be used for method types.
+ *
+ * @return the size of values of this type, i.e., 2 for <tt>long</tt> and
+ * <tt>double</tt>, 0 for <tt>void</tt> and 1 otherwise.
+ */
+ public int getSize() {
+ // the size is in byte 0 of 'off' for primitive types (buf == null)
+ return buf == null ? (off & 0xFF) : 1;
+ }
+
+ /**
+ * Returns a JVM instruction opcode adapted to this Java type. This method must not be used for method types.
+ *
+ * @param opcode a JVM instruction opcode. This opcode must be one of ILOAD, ISTORE, IALOAD, IASTORE, IADD, ISUB,
+ * IMUL, IDIV, IREM, INEG, ISHL, ISHR, IUSHR, IAND, IOR, IXOR and IRETURN.
+ * @return an opcode that is similar to the given opcode, but adapted to this Java type. For example, if this type
+ * is <tt>float</tt> and <tt>opcode</tt> is IRETURN, this method returns
+ * FRETURN.
+ */
+ public int getOpcode(final int opcode) {
+ if (opcode == Opcodes.IALOAD || opcode == Opcodes.IASTORE) {
+ // the offset for IALOAD or IASTORE is in byte 1 of 'off' for
+ // primitive types (buf == null)
+ return opcode + (buf == null ? (off & 0xFF00) >> 8 : 4);
+ } else {
+ // the offset for other instructions is in byte 2 of 'off' for
+ // primitive types (buf == null)
+ return opcode + (buf == null ? (off & 0xFF0000) >> 16 : 4);
+ }
+ }
+
+ // ------------------------------------------------------------------------
+ // Equals, hashCode and toString
+ // ------------------------------------------------------------------------
+
+ /**
+ * Tests if the given object is equal to this type.
+ *
+ * @param o the object to be compared to this type.
+ * @return <tt>true</tt> if the given object is equal to this type.
+ */
+ @Override
+ public boolean equals(final Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof Type)) {
+ return false;
+ }
+ Type t = (Type) o;
+ if (sort != t.sort) {
+ return false;
+ }
+ if (sort >= ARRAY) {
+ if (len != t.len) {
+ return false;
+ }
+ for (int i = off, j = t.off, end = i + len; i < end; i++, j++) {
+ if (buf[i] != t.buf[j]) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Returns a hash code value for this type.
+ *
+ * @return a hash code value for this type.
+ */
+ @Override
+ public int hashCode() {
+ int hc = 13 * sort;
+ if (sort >= ARRAY) {
+ for (int i = off, end = i + len; i < end; i++) {
+ hc = 17 * (hc + buf[i]);
+ }
+ }
+ return hc;
+ }
+
+ /**
+ * Returns a string representation of this type.
+ *
+ * @return the descriptor of this type.
+ */
+ @Override
+ public String toString() {
+ return getDescriptor();
+ }
+}
diff --git a/src/main/java/org/redkale/asm/TypePath.java b/src/main/java/org/redkale/asm/TypePath.java
index 39964a78a..b32c0fa26 100644
--- a/src/main/java/org/redkale/asm/TypePath.java
+++ b/src/main/java/org/redkale/asm/TypePath.java
@@ -1,195 +1,195 @@
-/*
- * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- */
-
-/*
- *
- *
- *
- *
- *
- * ASM: a very small and fast Java bytecode manipulation framework
- * Copyright (c) 2000-2013 INRIA, France Telecom
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package org.redkale.asm;
-
-/**
- * The path to a type argument, wildcard bound, array element type, or static inner type within an enclosing type.
- *
- * @author Eric Bruneton
- */
-public class TypePath {
-
- /** A type path step that steps into the element type of an array type. See {@link #getStep getStep}. */
- public static final int ARRAY_ELEMENT = 0;
-
- /** A type path step that steps into the nested type of a class type. See {@link #getStep getStep}. */
- public static final int INNER_TYPE = 1;
-
- /** A type path step that steps into the bound of a wildcard type. See {@link #getStep getStep}. */
- public static final int WILDCARD_BOUND = 2;
-
- /** A type path step that steps into a type argument of a generic type. See {@link #getStep getStep}. */
- public static final int TYPE_ARGUMENT = 3;
-
- /** The byte array where the path is stored, in Java class file format. */
- byte[] b;
-
- /** The offset of the first byte of the type path in 'b'. */
- int offset;
-
- /**
- * Creates a new type path.
- *
- * @param b the byte array containing the type path in Java class file format.
- * @param offset the offset of the first byte of the type path in 'b'.
- */
- TypePath(byte[] b, int offset) {
- this.b = b;
- this.offset = offset;
- }
-
- /**
- * Returns the length of this path.
- *
- * @return the length of this path.
- */
- public int getLength() {
- return b[offset];
- }
-
- /**
- * Returns the value of the given step of this path.
- *
- * @param index an index between 0 and {@link #getLength()}, exclusive.
- * @return {@link #ARRAY_ELEMENT ARRAY_ELEMENT}, {@link #INNER_TYPE INNER_TYPE}, {@link #WILDCARD_BOUND
- * WILDCARD_BOUND}, or {@link #TYPE_ARGUMENT TYPE_ARGUMENT}.
- */
- public int getStep(int index) {
- return b[offset + 2 * index + 1];
- }
-
- /**
- * Returns the index of the type argument that the given step is stepping into. This method should only be used for
- * steps whose value is {@link #TYPE_ARGUMENT TYPE_ARGUMENT}.
- *
- * @param index an index between 0 and {@link #getLength()}, exclusive.
- * @return the index of the type argument that the given step is stepping into.
- */
- public int getStepArgument(int index) {
- return b[offset + 2 * index + 2];
- }
-
- /**
- * Converts a type path in string form, in the format used by {@link #toString()}, into a TypePath object.
- *
- * @param typePath a type path in string form, in the format used by {@link #toString()}. May be null or empty.
- * @return the corresponding TypePath object, or null if the path is empty.
- */
- public static TypePath fromString(final String typePath) {
- if (typePath == null || typePath.isEmpty()) {
- return null;
- }
- int n = typePath.length();
- ByteVector out = new ByteVector(n);
- out.putByte(0);
- for (int i = 0; i < n; ) {
- char c = typePath.charAt(i++);
- if (c == '[') {
- out.put11(ARRAY_ELEMENT, 0);
- } else if (c == '.') {
- out.put11(INNER_TYPE, 0);
- } else if (c == '*') {
- out.put11(WILDCARD_BOUND, 0);
- } else if (c >= '0' && c <= '9') {
- int typeArg = c - '0';
- while (i < n && (c = typePath.charAt(i)) >= '0' && c <= '9') {
- typeArg = typeArg * 10 + c - '0';
- i += 1;
- }
- if (i < n && typePath.charAt(i) == ';') {
- i += 1;
- }
- out.put11(TYPE_ARGUMENT, typeArg);
- }
- }
- out.data[0] = (byte) (out.length / 2);
- return new TypePath(out.data, 0);
- }
-
- /**
- * Returns a string representation of this type path. {@link #ARRAY_ELEMENT ARRAY_ELEMENT} steps are represented
- * with '[', {@link #INNER_TYPE INNER_TYPE} steps with '.', {@link #WILDCARD_BOUND WILDCARD_BOUND} steps with '*'
- * and {@link #TYPE_ARGUMENT TYPE_ARGUMENT} steps with their type argument index in decimal form followed by ';'.
- */
- @Override
- public String toString() {
- int length = getLength();
- StringBuilder result = new StringBuilder(length * 2);
- for (int i = 0; i < length; ++i) {
- switch (getStep(i)) {
- case ARRAY_ELEMENT:
- result.append('[');
- break;
- case INNER_TYPE:
- result.append('.');
- break;
- case WILDCARD_BOUND:
- result.append('*');
- break;
- case TYPE_ARGUMENT:
- result.append(getStepArgument(i)).append(';');
- break;
- default:
- result.append('_');
- }
- }
- return result.toString();
- }
-}
+/*
+ * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ */
+
+/*
+ *
+ *
+ *
+ *
+ *
+ * ASM: a very small and fast Java bytecode manipulation framework
+ * Copyright (c) 2000-2013 INRIA, France Telecom
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.redkale.asm;
+
+/**
+ * The path to a type argument, wildcard bound, array element type, or static inner type within an enclosing type.
+ *
+ * @author Eric Bruneton
+ */
+public class TypePath {
+
+ /** A type path step that steps into the element type of an array type. See {@link #getStep getStep}. */
+ public static final int ARRAY_ELEMENT = 0;
+
+ /** A type path step that steps into the nested type of a class type. See {@link #getStep getStep}. */
+ public static final int INNER_TYPE = 1;
+
+ /** A type path step that steps into the bound of a wildcard type. See {@link #getStep getStep}. */
+ public static final int WILDCARD_BOUND = 2;
+
+ /** A type path step that steps into a type argument of a generic type. See {@link #getStep getStep}. */
+ public static final int TYPE_ARGUMENT = 3;
+
+ /** The byte array where the path is stored, in Java class file format. */
+ byte[] b;
+
+ /** The offset of the first byte of the type path in 'b'. */
+ int offset;
+
+ /**
+ * Creates a new type path.
+ *
+ * @param b the byte array containing the type path in Java class file format.
+ * @param offset the offset of the first byte of the type path in 'b'.
+ */
+ TypePath(byte[] b, int offset) {
+ this.b = b;
+ this.offset = offset;
+ }
+
+ /**
+ * Returns the length of this path.
+ *
+ * @return the length of this path.
+ */
+ public int getLength() {
+ return b[offset];
+ }
+
+ /**
+ * Returns the value of the given step of this path.
+ *
+ * @param index an index between 0 and {@link #getLength()}, exclusive.
+ * @return {@link #ARRAY_ELEMENT ARRAY_ELEMENT}, {@link #INNER_TYPE INNER_TYPE}, {@link #WILDCARD_BOUND
+ * WILDCARD_BOUND}, or {@link #TYPE_ARGUMENT TYPE_ARGUMENT}.
+ */
+ public int getStep(int index) {
+ return b[offset + 2 * index + 1];
+ }
+
+ /**
+ * Returns the index of the type argument that the given step is stepping into. This method should only be used for
+ * steps whose value is {@link #TYPE_ARGUMENT TYPE_ARGUMENT}.
+ *
+ * @param index an index between 0 and {@link #getLength()}, exclusive.
+ * @return the index of the type argument that the given step is stepping into.
+ */
+ public int getStepArgument(int index) {
+ return b[offset + 2 * index + 2];
+ }
+
+ /**
+ * Converts a type path in string form, in the format used by {@link #toString()}, into a TypePath object.
+ *
+ * @param typePath a type path in string form, in the format used by {@link #toString()}. May be null or empty.
+ * @return the corresponding TypePath object, or null if the path is empty.
+ */
+ public static TypePath fromString(final String typePath) {
+ if (typePath == null || typePath.isEmpty()) {
+ return null;
+ }
+ int n = typePath.length();
+ ByteVector out = new ByteVector(n);
+ out.putByte(0);
+ for (int i = 0; i < n; ) {
+ char c = typePath.charAt(i++);
+ if (c == '[') {
+ out.put11(ARRAY_ELEMENT, 0);
+ } else if (c == '.') {
+ out.put11(INNER_TYPE, 0);
+ } else if (c == '*') {
+ out.put11(WILDCARD_BOUND, 0);
+ } else if (c >= '0' && c <= '9') {
+ int typeArg = c - '0';
+ while (i < n && (c = typePath.charAt(i)) >= '0' && c <= '9') {
+ typeArg = typeArg * 10 + c - '0';
+ i += 1;
+ }
+ if (i < n && typePath.charAt(i) == ';') {
+ i += 1;
+ }
+ out.put11(TYPE_ARGUMENT, typeArg);
+ }
+ }
+ out.data[0] = (byte) (out.length / 2);
+ return new TypePath(out.data, 0);
+ }
+
+ /**
+ * Returns a string representation of this type path. {@link #ARRAY_ELEMENT ARRAY_ELEMENT} steps are represented
+ * with '[', {@link #INNER_TYPE INNER_TYPE} steps with '.', {@link #WILDCARD_BOUND WILDCARD_BOUND} steps with '*'
+ * and {@link #TYPE_ARGUMENT TYPE_ARGUMENT} steps with their type argument index in decimal form followed by ';'.
+ */
+ @Override
+ public String toString() {
+ int length = getLength();
+ StringBuilder result = new StringBuilder(length * 2);
+ for (int i = 0; i < length; ++i) {
+ switch (getStep(i)) {
+ case ARRAY_ELEMENT:
+ result.append('[');
+ break;
+ case INNER_TYPE:
+ result.append('.');
+ break;
+ case WILDCARD_BOUND:
+ result.append('*');
+ break;
+ case TYPE_ARGUMENT:
+ result.append(getStepArgument(i)).append(';');
+ break;
+ default:
+ result.append('_');
+ }
+ }
+ return result.toString();
+ }
+}
diff --git a/src/main/java/org/redkale/asm/TypeReference.java b/src/main/java/org/redkale/asm/TypeReference.java
index 2ec9ae0f4..4dd59f9df 100644
--- a/src/main/java/org/redkale/asm/TypeReference.java
+++ b/src/main/java/org/redkale/asm/TypeReference.java
@@ -1,402 +1,402 @@
-/*
- * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- */
-
-/*
- *
- *
- *
- *
- *
- * ASM: a very small and fast Java bytecode manipulation framework
- * Copyright (c) 2000-2013 INRIA, France Telecom
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package org.redkale.asm;
-
-/**
- * A reference to a type appearing in a class, field or method declaration, or on an instruction. Such a reference
- * designates the part of the class where the referenced type is appearing (e.g. an 'extends', 'implements' or 'throws'
- * clause, a 'new' instruction, a 'catch' clause, a type cast, a local variable declaration, etc).
- *
- * @author Eric Bruneton
- */
-public class TypeReference {
-
- /** The sort of type references that target a type parameter of a generic class. See {@link #getSort getSort}. */
- public static final int CLASS_TYPE_PARAMETER = 0x00;
-
- /** The sort of type references that target a type parameter of a generic method. See {@link #getSort getSort}. */
- public static final int METHOD_TYPE_PARAMETER = 0x01;
-
- /**
- * The sort of type references that target the super class of a class or one of the interfaces it implements. See
- * {@link #getSort getSort}.
- */
- public static final int CLASS_EXTENDS = 0x10;
-
- /**
- * The sort of type references that target a bound of a type parameter of a generic class. See {@link #getSort
- * getSort}.
- */
- public static final int CLASS_TYPE_PARAMETER_BOUND = 0x11;
-
- /**
- * The sort of type references that target a bound of a type parameter of a generic method. See {@link #getSort
- * getSort}.
- */
- public static final int METHOD_TYPE_PARAMETER_BOUND = 0x12;
-
- /** The sort of type references that target the type of a field. See {@link #getSort getSort}. */
- public static final int FIELD = 0x13;
-
- /** The sort of type references that target the return type of a method. See {@link #getSort getSort}. */
- public static final int METHOD_RETURN = 0x14;
-
- /** The sort of type references that target the receiver type of a method. See {@link #getSort getSort}. */
- public static final int METHOD_RECEIVER = 0x15;
-
- /**
- * The sort of type references that target the type of a formal parameter of a method. See {@link #getSort getSort}.
- */
- public static final int METHOD_FORMAL_PARAMETER = 0x16;
-
- /**
- * The sort of type references that target the type of an exception declared in the throws clause of a method. See
- * {@link #getSort getSort}.
- */
- public static final int THROWS = 0x17;
-
- /**
- * The sort of type references that target the type of a local variable in a method. See {@link #getSort getSort}.
- */
- public static final int LOCAL_VARIABLE = 0x40;
-
- /**
- * The sort of type references that target the type of a resource variable in a method. See {@link #getSort
- * getSort}.
- */
- public static final int RESOURCE_VARIABLE = 0x41;
-
- /**
- * The sort of type references that target the type of the exception of a 'catch' clause in a method. See
- * {@link #getSort getSort}.
- */
- public static final int EXCEPTION_PARAMETER = 0x42;
-
- /**
- * The sort of type references that target the type declared in an 'instanceof' instruction. See {@link #getSort
- * getSort}.
- */
- public static final int INSTANCEOF = 0x43;
-
- /**
- * The sort of type references that target the type of the object created by a 'new' instruction. See
- * {@link #getSort getSort}.
- */
- public static final int NEW = 0x44;
-
- /**
- * The sort of type references that target the receiver type of a constructor reference. See {@link #getSort
- * getSort}.
- */
- public static final int CONSTRUCTOR_REFERENCE = 0x45;
-
- /**
- * The sort of type references that target the receiver type of a method reference. See {@link #getSort getSort}.
- */
- public static final int METHOD_REFERENCE = 0x46;
-
- /**
- * The sort of type references that target the type declared in an explicit or implicit cast instruction. See
- * {@link #getSort getSort}.
- */
- public static final int CAST = 0x47;
-
- /**
- * The sort of type references that target a type parameter of a generic constructor in a constructor call. See
- * {@link #getSort getSort}.
- */
- public static final int CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT = 0x48;
-
- /**
- * The sort of type references that target a type parameter of a generic method in a method call. See
- * {@link #getSort getSort}.
- */
- public static final int METHOD_INVOCATION_TYPE_ARGUMENT = 0x49;
-
- /**
- * The sort of type references that target a type parameter of a generic constructor in a constructor reference. See
- * {@link #getSort getSort}.
- */
- public static final int CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT = 0x4A;
-
- /**
- * The sort of type references that target a type parameter of a generic method in a method reference. See
- * {@link #getSort getSort}.
- */
- public static final int METHOD_REFERENCE_TYPE_ARGUMENT = 0x4B;
-
- /** The type reference value in Java class file format. */
- private int value;
-
- /**
- * Creates a new TypeReference.
- *
- * @param typeRef the int encoded value of the type reference, as received in a visit method related to type
- * annotations, like visitTypeAnnotation.
- */
- public TypeReference(int typeRef) {
- this.value = typeRef;
- }
-
- /**
- * Returns a type reference of the given sort.
- *
- * @param sort {@link #FIELD FIELD}, {@link #METHOD_RETURN METHOD_RETURN}, {@link #METHOD_RECEIVER METHOD_RECEIVER},
- * {@link #LOCAL_VARIABLE LOCAL_VARIABLE}, {@link #RESOURCE_VARIABLE RESOURCE_VARIABLE}, {@link #INSTANCEOF
- * INSTANCEOF}, {@link #NEW NEW}, {@link #CONSTRUCTOR_REFERENCE CONSTRUCTOR_REFERENCE}, or
- * {@link #METHOD_REFERENCE METHOD_REFERENCE}.
- * @return a type reference of the given sort.
- */
- public static TypeReference newTypeReference(int sort) {
- return new TypeReference(sort << 24);
- }
-
- /**
- * Returns a reference to a type parameter of a generic class or method.
- *
- * @param sort {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER} or {@link #METHOD_TYPE_PARAMETER
- * METHOD_TYPE_PARAMETER}.
- * @param paramIndex the type parameter index.
- * @return a reference to the given generic class or method type parameter.
- */
- public static TypeReference newTypeParameterReference(int sort, int paramIndex) {
- return new TypeReference((sort << 24) | (paramIndex << 16));
- }
-
- /**
- * Returns a reference to a type parameter bound of a generic class or method.
- *
- * @param sort {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER} or {@link #METHOD_TYPE_PARAMETER
- * METHOD_TYPE_PARAMETER}.
- * @param paramIndex the type parameter index.
- * @param boundIndex the type bound index within the above type parameters.
- * @return a reference to the given generic class or method type parameter bound.
- */
- public static TypeReference newTypeParameterBoundReference(int sort, int paramIndex, int boundIndex) {
- return new TypeReference((sort << 24) | (paramIndex << 16) | (boundIndex << 8));
- }
-
- /**
- * Returns a reference to the super class or to an interface of the 'implements' clause of a class.
- *
- * @param itfIndex the index of an interface in the 'implements' clause of a class, or -1 to reference the super
- * class of the class.
- * @return a reference to the given super type of a class.
- */
- public static TypeReference newSuperTypeReference(int itfIndex) {
- itfIndex &= 0xFFFF;
- return new TypeReference((CLASS_EXTENDS << 24) | (itfIndex << 8));
- }
-
- /**
- * Returns a reference to the type of a formal parameter of a method.
- *
- * @param paramIndex the formal parameter index.
- * @return a reference to the type of the given method formal parameter.
- */
- public static TypeReference newFormalParameterReference(int paramIndex) {
- return new TypeReference((METHOD_FORMAL_PARAMETER << 24) | (paramIndex << 16));
- }
-
- /**
- * Returns a reference to the type of an exception, in a 'throws' clause of a method.
- *
- * @param exceptionIndex the index of an exception in a 'throws' clause of a method.
- * @return a reference to the type of the given exception.
- */
- public static TypeReference newExceptionReference(int exceptionIndex) {
- return new TypeReference((THROWS << 24) | (exceptionIndex << 8));
- }
-
- /**
- * Returns a reference to the type of the exception declared in a 'catch' clause of a method.
- *
- * @param tryCatchBlockIndex the index of a try catch block (using the order in which they are visited with
- * visitTryCatchBlock).
- * @return a reference to the type of the given exception.
- */
- public static TypeReference newTryCatchReference(int tryCatchBlockIndex) {
- return new TypeReference((EXCEPTION_PARAMETER << 24) | (tryCatchBlockIndex << 8));
- }
-
- /**
- * Returns a reference to the type of a type argument in a constructor or method call or reference.
- *
- * @param sort {@link #CAST CAST}, {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
- * CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, {@link #METHOD_INVOCATION_TYPE_ARGUMENT
- * METHOD_INVOCATION_TYPE_ARGUMENT}, {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
- * CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or {@link #METHOD_REFERENCE_TYPE_ARGUMENT
- * METHOD_REFERENCE_TYPE_ARGUMENT}.
- * @param argIndex the type argument index.
- * @return a reference to the type of the given type argument.
- */
- public static TypeReference newTypeArgumentReference(int sort, int argIndex) {
- return new TypeReference((sort << 24) | argIndex);
- }
-
- /**
- * Returns the sort of this type reference.
- *
- * @return {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER}, {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER},
- * {@link #CLASS_EXTENDS CLASS_EXTENDS}, {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND},
- * {@link #METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND}, {@link #FIELD FIELD}, {@link #METHOD_RETURN
- * METHOD_RETURN}, {@link #METHOD_RECEIVER METHOD_RECEIVER}, {@link #METHOD_FORMAL_PARAMETER
- * METHOD_FORMAL_PARAMETER}, {@link #THROWS THROWS}, {@link #LOCAL_VARIABLE LOCAL_VARIABLE},
- * {@link #RESOURCE_VARIABLE RESOURCE_VARIABLE}, {@link #EXCEPTION_PARAMETER EXCEPTION_PARAMETER},
- * {@link #INSTANCEOF INSTANCEOF}, {@link #NEW NEW}, {@link #CONSTRUCTOR_REFERENCE CONSTRUCTOR_REFERENCE},
- * {@link #METHOD_REFERENCE METHOD_REFERENCE}, {@link #CAST CAST}, {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
- * CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, {@link #METHOD_INVOCATION_TYPE_ARGUMENT
- * METHOD_INVOCATION_TYPE_ARGUMENT}, {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
- * CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or {@link #METHOD_REFERENCE_TYPE_ARGUMENT
- * METHOD_REFERENCE_TYPE_ARGUMENT}.
- */
- public int getSort() {
- return value >>> 24;
- }
-
- /**
- * Returns the index of the type parameter referenced by this type reference. This method must only be used for type
- * references whose sort is {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER}, {@link #METHOD_TYPE_PARAMETER
- * METHOD_TYPE_PARAMETER}, {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND} or
- * {@link #METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND}.
- *
- * @return a type parameter index.
- */
- public int getTypeParameterIndex() {
- return (value & 0x00FF0000) >> 16;
- }
-
- /**
- * Returns the index of the type parameter bound, within the type parameter {@link #getTypeParameterIndex},
- * referenced by this type reference. This method must only be used for type references whose sort is
- * {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND} or {@link #METHOD_TYPE_PARAMETER_BOUND
- * METHOD_TYPE_PARAMETER_BOUND}.
- *
- * @return a type parameter bound index.
- */
- public int getTypeParameterBoundIndex() {
- return (value & 0x0000FF00) >> 8;
- }
-
- /**
- * Returns the index of the "super type" of a class that is referenced by this type reference. This method must only
- * be used for type references whose sort is {@link #CLASS_EXTENDS CLASS_EXTENDS}.
- *
- * @return the index of an interface in the 'implements' clause of a class, or -1 if this type reference references
- * the type of the super class.
- */
- public int getSuperTypeIndex() {
- return (short) ((value & 0x00FFFF00) >> 8);
- }
-
- /**
- * Returns the index of the formal parameter whose type is referenced by this type reference. This method must only
- * be used for type references whose sort is {@link #METHOD_FORMAL_PARAMETER METHOD_FORMAL_PARAMETER}.
- *
- * @return a formal parameter index.
- */
- public int getFormalParameterIndex() {
- return (value & 0x00FF0000) >> 16;
- }
-
- /**
- * Returns the index of the exception, in a 'throws' clause of a method, whose type is referenced by this type
- * reference. This method must only be used for type references whose sort is {@link #THROWS THROWS}.
- *
- * @return the index of an exception in the 'throws' clause of a method.
- */
- public int getExceptionIndex() {
- return (value & 0x00FFFF00) >> 8;
- }
-
- /**
- * Returns the index of the try catch block (using the order in which they are visited with visitTryCatchBlock),
- * whose 'catch' type is referenced by this type reference. This method must only be used for type references whose
- * sort is {@link #EXCEPTION_PARAMETER EXCEPTION_PARAMETER} .
- *
- * @return the index of an exception in the 'throws' clause of a method.
- */
- public int getTryCatchBlockIndex() {
- return (value & 0x00FFFF00) >> 8;
- }
-
- /**
- * Returns the index of the type argument referenced by this type reference. This method must only be used for type
- * references whose sort is {@link #CAST CAST}, {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
- * CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, {@link #METHOD_INVOCATION_TYPE_ARGUMENT METHOD_INVOCATION_TYPE_ARGUMENT},
- * {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or
- * {@link #METHOD_REFERENCE_TYPE_ARGUMENT METHOD_REFERENCE_TYPE_ARGUMENT}.
- *
- * @return a type parameter index.
- */
- public int getTypeArgumentIndex() {
- return value & 0xFF;
- }
-
- /**
- * Returns the int encoded value of this type reference, suitable for use in visit methods related to type
- * annotations, like visitTypeAnnotation.
- *
- * @return the int encoded value of this type reference.
- */
- public int getValue() {
- return value;
- }
-}
+/*
+ * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ */
+
+/*
+ *
+ *
+ *
+ *
+ *
+ * ASM: a very small and fast Java bytecode manipulation framework
+ * Copyright (c) 2000-2013 INRIA, France Telecom
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.redkale.asm;
+
+/**
+ * A reference to a type appearing in a class, field or method declaration, or on an instruction. Such a reference
+ * designates the part of the class where the referenced type is appearing (e.g. an 'extends', 'implements' or 'throws'
+ * clause, a 'new' instruction, a 'catch' clause, a type cast, a local variable declaration, etc).
+ *
+ * @author Eric Bruneton
+ */
+public class TypeReference {
+
+ /** The sort of type references that target a type parameter of a generic class. See {@link #getSort getSort}. */
+ public static final int CLASS_TYPE_PARAMETER = 0x00;
+
+ /** The sort of type references that target a type parameter of a generic method. See {@link #getSort getSort}. */
+ public static final int METHOD_TYPE_PARAMETER = 0x01;
+
+ /**
+ * The sort of type references that target the super class of a class or one of the interfaces it implements. See
+ * {@link #getSort getSort}.
+ */
+ public static final int CLASS_EXTENDS = 0x10;
+
+ /**
+ * The sort of type references that target a bound of a type parameter of a generic class. See {@link #getSort
+ * getSort}.
+ */
+ public static final int CLASS_TYPE_PARAMETER_BOUND = 0x11;
+
+ /**
+ * The sort of type references that target a bound of a type parameter of a generic method. See {@link #getSort
+ * getSort}.
+ */
+ public static final int METHOD_TYPE_PARAMETER_BOUND = 0x12;
+
+ /** The sort of type references that target the type of a field. See {@link #getSort getSort}. */
+ public static final int FIELD = 0x13;
+
+ /** The sort of type references that target the return type of a method. See {@link #getSort getSort}. */
+ public static final int METHOD_RETURN = 0x14;
+
+ /** The sort of type references that target the receiver type of a method. See {@link #getSort getSort}. */
+ public static final int METHOD_RECEIVER = 0x15;
+
+ /**
+ * The sort of type references that target the type of a formal parameter of a method. See {@link #getSort getSort}.
+ */
+ public static final int METHOD_FORMAL_PARAMETER = 0x16;
+
+ /**
+ * The sort of type references that target the type of an exception declared in the throws clause of a method. See
+ * {@link #getSort getSort}.
+ */
+ public static final int THROWS = 0x17;
+
+ /**
+ * The sort of type references that target the type of a local variable in a method. See {@link #getSort getSort}.
+ */
+ public static final int LOCAL_VARIABLE = 0x40;
+
+ /**
+ * The sort of type references that target the type of a resource variable in a method. See {@link #getSort
+ * getSort}.
+ */
+ public static final int RESOURCE_VARIABLE = 0x41;
+
+ /**
+ * The sort of type references that target the type of the exception of a 'catch' clause in a method. See
+ * {@link #getSort getSort}.
+ */
+ public static final int EXCEPTION_PARAMETER = 0x42;
+
+ /**
+ * The sort of type references that target the type declared in an 'instanceof' instruction. See {@link #getSort
+ * getSort}.
+ */
+ public static final int INSTANCEOF = 0x43;
+
+ /**
+ * The sort of type references that target the type of the object created by a 'new' instruction. See
+ * {@link #getSort getSort}.
+ */
+ public static final int NEW = 0x44;
+
+ /**
+ * The sort of type references that target the receiver type of a constructor reference. See {@link #getSort
+ * getSort}.
+ */
+ public static final int CONSTRUCTOR_REFERENCE = 0x45;
+
+ /**
+ * The sort of type references that target the receiver type of a method reference. See {@link #getSort getSort}.
+ */
+ public static final int METHOD_REFERENCE = 0x46;
+
+ /**
+ * The sort of type references that target the type declared in an explicit or implicit cast instruction. See
+ * {@link #getSort getSort}.
+ */
+ public static final int CAST = 0x47;
+
+ /**
+ * The sort of type references that target a type parameter of a generic constructor in a constructor call. See
+ * {@link #getSort getSort}.
+ */
+ public static final int CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT = 0x48;
+
+ /**
+ * The sort of type references that target a type parameter of a generic method in a method call. See
+ * {@link #getSort getSort}.
+ */
+ public static final int METHOD_INVOCATION_TYPE_ARGUMENT = 0x49;
+
+ /**
+ * The sort of type references that target a type parameter of a generic constructor in a constructor reference. See
+ * {@link #getSort getSort}.
+ */
+ public static final int CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT = 0x4A;
+
+ /**
+ * The sort of type references that target a type parameter of a generic method in a method reference. See
+ * {@link #getSort getSort}.
+ */
+ public static final int METHOD_REFERENCE_TYPE_ARGUMENT = 0x4B;
+
+ /** The type reference value in Java class file format. */
+ private int value;
+
+ /**
+ * Creates a new TypeReference.
+ *
+ * @param typeRef the int encoded value of the type reference, as received in a visit method related to type
+ * annotations, like visitTypeAnnotation.
+ */
+ public TypeReference(int typeRef) {
+ this.value = typeRef;
+ }
+
+ /**
+ * Returns a type reference of the given sort.
+ *
+ * @param sort {@link #FIELD FIELD}, {@link #METHOD_RETURN METHOD_RETURN}, {@link #METHOD_RECEIVER METHOD_RECEIVER},
+ * {@link #LOCAL_VARIABLE LOCAL_VARIABLE}, {@link #RESOURCE_VARIABLE RESOURCE_VARIABLE}, {@link #INSTANCEOF
+ * INSTANCEOF}, {@link #NEW NEW}, {@link #CONSTRUCTOR_REFERENCE CONSTRUCTOR_REFERENCE}, or
+ * {@link #METHOD_REFERENCE METHOD_REFERENCE}.
+ * @return a type reference of the given sort.
+ */
+ public static TypeReference newTypeReference(int sort) {
+ return new TypeReference(sort << 24);
+ }
+
+ /**
+ * Returns a reference to a type parameter of a generic class or method.
+ *
+ * @param sort {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER} or {@link #METHOD_TYPE_PARAMETER
+ * METHOD_TYPE_PARAMETER}.
+ * @param paramIndex the type parameter index.
+ * @return a reference to the given generic class or method type parameter.
+ */
+ public static TypeReference newTypeParameterReference(int sort, int paramIndex) {
+ return new TypeReference((sort << 24) | (paramIndex << 16));
+ }
+
+ /**
+ * Returns a reference to a type parameter bound of a generic class or method.
+ *
+ * @param sort {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER} or {@link #METHOD_TYPE_PARAMETER
+ * METHOD_TYPE_PARAMETER}.
+ * @param paramIndex the type parameter index.
+ * @param boundIndex the type bound index within the above type parameters.
+ * @return a reference to the given generic class or method type parameter bound.
+ */
+ public static TypeReference newTypeParameterBoundReference(int sort, int paramIndex, int boundIndex) {
+ return new TypeReference((sort << 24) | (paramIndex << 16) | (boundIndex << 8));
+ }
+
+ /**
+ * Returns a reference to the super class or to an interface of the 'implements' clause of a class.
+ *
+ * @param itfIndex the index of an interface in the 'implements' clause of a class, or -1 to reference the super
+ * class of the class.
+ * @return a reference to the given super type of a class.
+ */
+ public static TypeReference newSuperTypeReference(int itfIndex) {
+ itfIndex &= 0xFFFF;
+ return new TypeReference((CLASS_EXTENDS << 24) | (itfIndex << 8));
+ }
+
+ /**
+ * Returns a reference to the type of a formal parameter of a method.
+ *
+ * @param paramIndex the formal parameter index.
+ * @return a reference to the type of the given method formal parameter.
+ */
+ public static TypeReference newFormalParameterReference(int paramIndex) {
+ return new TypeReference((METHOD_FORMAL_PARAMETER << 24) | (paramIndex << 16));
+ }
+
+ /**
+ * Returns a reference to the type of an exception, in a 'throws' clause of a method.
+ *
+ * @param exceptionIndex the index of an exception in a 'throws' clause of a method.
+ * @return a reference to the type of the given exception.
+ */
+ public static TypeReference newExceptionReference(int exceptionIndex) {
+ return new TypeReference((THROWS << 24) | (exceptionIndex << 8));
+ }
+
+ /**
+ * Returns a reference to the type of the exception declared in a 'catch' clause of a method.
+ *
+ * @param tryCatchBlockIndex the index of a try catch block (using the order in which they are visited with
+ * visitTryCatchBlock).
+ * @return a reference to the type of the given exception.
+ */
+ public static TypeReference newTryCatchReference(int tryCatchBlockIndex) {
+ return new TypeReference((EXCEPTION_PARAMETER << 24) | (tryCatchBlockIndex << 8));
+ }
+
+ /**
+ * Returns a reference to the type of a type argument in a constructor or method call or reference.
+ *
+ * @param sort {@link #CAST CAST}, {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
+ * CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, {@link #METHOD_INVOCATION_TYPE_ARGUMENT
+ * METHOD_INVOCATION_TYPE_ARGUMENT}, {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
+ * CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or {@link #METHOD_REFERENCE_TYPE_ARGUMENT
+ * METHOD_REFERENCE_TYPE_ARGUMENT}.
+ * @param argIndex the type argument index.
+ * @return a reference to the type of the given type argument.
+ */
+ public static TypeReference newTypeArgumentReference(int sort, int argIndex) {
+ return new TypeReference((sort << 24) | argIndex);
+ }
+
+ /**
+ * Returns the sort of this type reference.
+ *
+ * @return {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER}, {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER},
+ * {@link #CLASS_EXTENDS CLASS_EXTENDS}, {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND},
+ * {@link #METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND}, {@link #FIELD FIELD}, {@link #METHOD_RETURN
+ * METHOD_RETURN}, {@link #METHOD_RECEIVER METHOD_RECEIVER}, {@link #METHOD_FORMAL_PARAMETER
+ * METHOD_FORMAL_PARAMETER}, {@link #THROWS THROWS}, {@link #LOCAL_VARIABLE LOCAL_VARIABLE},
+ * {@link #RESOURCE_VARIABLE RESOURCE_VARIABLE}, {@link #EXCEPTION_PARAMETER EXCEPTION_PARAMETER},
+ * {@link #INSTANCEOF INSTANCEOF}, {@link #NEW NEW}, {@link #CONSTRUCTOR_REFERENCE CONSTRUCTOR_REFERENCE},
+ * {@link #METHOD_REFERENCE METHOD_REFERENCE}, {@link #CAST CAST}, {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
+ * CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, {@link #METHOD_INVOCATION_TYPE_ARGUMENT
+ * METHOD_INVOCATION_TYPE_ARGUMENT}, {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
+ * CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or {@link #METHOD_REFERENCE_TYPE_ARGUMENT
+ * METHOD_REFERENCE_TYPE_ARGUMENT}.
+ */
+ public int getSort() {
+ return value >>> 24;
+ }
+
+ /**
+ * Returns the index of the type parameter referenced by this type reference. This method must only be used for type
+ * references whose sort is {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER}, {@link #METHOD_TYPE_PARAMETER
+ * METHOD_TYPE_PARAMETER}, {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND} or
+ * {@link #METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND}.
+ *
+ * @return a type parameter index.
+ */
+ public int getTypeParameterIndex() {
+ return (value & 0x00FF0000) >> 16;
+ }
+
+ /**
+ * Returns the index of the type parameter bound, within the type parameter {@link #getTypeParameterIndex},
+ * referenced by this type reference. This method must only be used for type references whose sort is
+ * {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND} or {@link #METHOD_TYPE_PARAMETER_BOUND
+ * METHOD_TYPE_PARAMETER_BOUND}.
+ *
+ * @return a type parameter bound index.
+ */
+ public int getTypeParameterBoundIndex() {
+ return (value & 0x0000FF00) >> 8;
+ }
+
+ /**
+ * Returns the index of the "super type" of a class that is referenced by this type reference. This method must only
+ * be used for type references whose sort is {@link #CLASS_EXTENDS CLASS_EXTENDS}.
+ *
+ * @return the index of an interface in the 'implements' clause of a class, or -1 if this type reference references
+ * the type of the super class.
+ */
+ public int getSuperTypeIndex() {
+ return (short) ((value & 0x00FFFF00) >> 8);
+ }
+
+ /**
+ * Returns the index of the formal parameter whose type is referenced by this type reference. This method must only
+ * be used for type references whose sort is {@link #METHOD_FORMAL_PARAMETER METHOD_FORMAL_PARAMETER}.
+ *
+ * @return a formal parameter index.
+ */
+ public int getFormalParameterIndex() {
+ return (value & 0x00FF0000) >> 16;
+ }
+
+ /**
+ * Returns the index of the exception, in a 'throws' clause of a method, whose type is referenced by this type
+ * reference. This method must only be used for type references whose sort is {@link #THROWS THROWS}.
+ *
+ * @return the index of an exception in the 'throws' clause of a method.
+ */
+ public int getExceptionIndex() {
+ return (value & 0x00FFFF00) >> 8;
+ }
+
+ /**
+ * Returns the index of the try catch block (using the order in which they are visited with visitTryCatchBlock),
+ * whose 'catch' type is referenced by this type reference. This method must only be used for type references whose
+ * sort is {@link #EXCEPTION_PARAMETER EXCEPTION_PARAMETER} .
+ *
+ * @return the index of an exception in the 'throws' clause of a method.
+ */
+ public int getTryCatchBlockIndex() {
+ return (value & 0x00FFFF00) >> 8;
+ }
+
+ /**
+ * Returns the index of the type argument referenced by this type reference. This method must only be used for type
+ * references whose sort is {@link #CAST CAST}, {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
+ * CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, {@link #METHOD_INVOCATION_TYPE_ARGUMENT METHOD_INVOCATION_TYPE_ARGUMENT},
+ * {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or
+ * {@link #METHOD_REFERENCE_TYPE_ARGUMENT METHOD_REFERENCE_TYPE_ARGUMENT}.
+ *
+ * @return a type parameter index.
+ */
+ public int getTypeArgumentIndex() {
+ return value & 0xFF;
+ }
+
+ /**
+ * Returns the int encoded value of this type reference, suitable for use in visit methods related to type
+ * annotations, like visitTypeAnnotation.
+ *
+ * @return the int encoded value of this type reference.
+ */
+ public int getValue() {
+ return value;
+ }
+}
diff --git a/src/main/java/org/redkale/boot/AppConfig.java b/src/main/java/org/redkale/boot/AppConfig.java
index bbe098afd..ef35b170e 100644
--- a/src/main/java/org/redkale/boot/AppConfig.java
+++ b/src/main/java/org/redkale/boot/AppConfig.java
@@ -1,494 +1,494 @@
-/*
- *
- */
-package org.redkale.boot;
-
-import static org.redkale.boot.Application.*;
-import static org.redkale.util.RedkaleClassLoader.putReflectionClass;
-import static org.redkale.util.RedkaleClassLoader.putReflectionPublicConstructors;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.URI;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Properties;
-import java.util.Set;
-import java.util.logging.SimpleFormatter;
-import org.redkale.source.DataSources;
-import org.redkale.util.AnyValue;
-import org.redkale.util.AnyValueWriter;
-import org.redkale.util.RedkaleClassLoader;
-import org.redkale.util.RedkaleException;
-import org.redkale.util.Utility;
-
-/**
- * 加载系统参数配置
- *
- * @author zhangjx
- */
-class AppConfig {
-
- /**
- * 当前进程的配置文件, 类型:String、URI、File、Path
- * 一般命名为: application.xml、application.onlyLogProps, 若配置文件不是本地文件, 则File、Path类型的值为null
- */
- static final String PARAM_APP_CONF_FILE = "APP_CONF_FILE";
-
- // 是否用于main方法运行
- final boolean singletonMode;
-
- // 是否用于编译模式运行
- final boolean compileMode;
-
- // application.xml原始配置信息
- AnyValue config;
-
- // 是否从/META-INF中读取配置
- boolean configFromCache;
-
- // 本进程节点ID
- String nodeid;
-
- // 本进程节点ID
- String name;
-
- // 本地IP地址
- InetSocketAddress localAddress;
-
- // 进程根目录
- File home;
-
- // 配置文件目录
- File confFile;
-
- // 配置文件目录
- URI confDir;
-
- // 根ClassLoader
- RedkaleClassLoader classLoader;
-
- // Server根ClassLoader
- RedkaleClassLoader serverClassLoader;
-
- // 本地文件日志配置项
- final Properties locaLogProperties = new Properties();
-
- // 本地文件除logging配置之外的所有的配置项, 包含system.property.、mimetype.property.开头的
- final Properties localEnvProperties = new Properties();
-
- public AppConfig(boolean singletonMode, boolean compileMode) {
- this.singletonMode = singletonMode;
- this.compileMode = compileMode;
- }
-
- public static AppConfig create(boolean singletonMode, boolean compileMode) throws IOException {
- AppConfig rs = new AppConfig(singletonMode, compileMode);
- rs.init(loadAppConfig());
- return rs;
- }
-
- private void init(AnyValue conf) {
- this.config = conf;
- this.name = checkName(config.getValue("name", ""));
- this.nodeid = checkNodeid(config.getValue("nodeid", String.valueOf(Math.abs(System.nanoTime()))));
- this.configFromCache = "true".equals(config.getValue("[config-from-cache]"));
- // 初始化classLoader、serverClassLoader
- this.initClassLoader();
- // 初始化home、confDir、localAddress等信息
- this.initAppHome();
- // 读取本地参数配置
- this.initLocalProperties();
- // 读取本地日志配置
- this.initLogProperties();
- // 读取本地数据库配置
- this.initSourceProperties();
- }
-
- /** 初始化classLoader、serverClassLoader */
- private void initClassLoader() {
- ClassLoader currClassLoader = Thread.currentThread().getContextClassLoader();
- if (currClassLoader instanceof RedkaleClassLoader) {
- this.classLoader = (RedkaleClassLoader) currClassLoader;
- } else {
- Set
+ * 一般命名为: application.xml、application.onlyLogProps, 若配置文件不是本地文件, 则File、Path类型的值为null
+ */
+ static final String PARAM_APP_CONF_FILE = "APP_CONF_FILE";
+
+ // 是否用于main方法运行
+ final boolean singletonMode;
+
+ // 是否用于编译模式运行
+ final boolean compileMode;
+
+ // application.xml原始配置信息
+ AnyValue config;
+
+ // 是否从/META-INF中读取配置
+ boolean configFromCache;
+
+ // 本进程节点ID
+ String nodeid;
+
+ // 本进程节点ID
+ String name;
+
+ // 本地IP地址
+ InetSocketAddress localAddress;
+
+ // 进程根目录
+ File home;
+
+ // 配置文件目录
+ File confFile;
+
+ // 配置文件目录
+ URI confDir;
+
+ // 根ClassLoader
+ RedkaleClassLoader classLoader;
+
+ // Server根ClassLoader
+ RedkaleClassLoader serverClassLoader;
+
+ // 本地文件日志配置项
+ final Properties locaLogProperties = new Properties();
+
+ // 本地文件除logging配置之外的所有的配置项, 包含system.property.、mimetype.property.开头的
+ final Properties localEnvProperties = new Properties();
+
+ public AppConfig(boolean singletonMode, boolean compileMode) {
+ this.singletonMode = singletonMode;
+ this.compileMode = compileMode;
+ }
+
+ public static AppConfig create(boolean singletonMode, boolean compileMode) throws IOException {
+ AppConfig rs = new AppConfig(singletonMode, compileMode);
+ rs.init(loadAppConfig());
+ return rs;
+ }
+
+ private void init(AnyValue conf) {
+ this.config = conf;
+ this.name = checkName(config.getValue("name", ""));
+ this.nodeid = checkNodeid(config.getValue("nodeid", String.valueOf(Math.abs(System.nanoTime()))));
+ this.configFromCache = "true".equals(config.getValue("[config-from-cache]"));
+ // 初始化classLoader、serverClassLoader
+ this.initClassLoader();
+ // 初始化home、confDir、localAddress等信息
+ this.initAppHome();
+ // 读取本地参数配置
+ this.initLocalProperties();
+ // 读取本地日志配置
+ this.initLogProperties();
+ // 读取本地数据库配置
+ this.initSourceProperties();
+ }
+
+ /** 初始化classLoader、serverClassLoader */
+ private void initClassLoader() {
+ ClassLoader currClassLoader = Thread.currentThread().getContextClassLoader();
+ if (currClassLoader instanceof RedkaleClassLoader) {
+ this.classLoader = (RedkaleClassLoader) currClassLoader;
+ } else {
+ Set
- *
- *
- * 程序启动执行步骤:
- * 1、读取application.xml
- * 2、进行classpath扫描动态加载Service、WebSocket与Servlet
- * 3、优先加载所有SNCP协议的服务,再加载其他协议服务, 最后加载WATCH协议的服务
- * 4、最后进行Service、Servlet与其他资源之间的依赖注入
- *
- *
- *
- * 若配置目录不是本地文件夹, 则File、Path类型的值为null
- */
- public static final String RESNAME_APP_CONF_DIR = "APP_CONF_DIR";
-
- /** 当前进程节点的nodeid, 类型:String */
- public static final String RESNAME_APP_NODEID = "APP_NODEID";
-
- /** 当前进程节点的IP地址, 类型:InetSocketAddress、InetAddress、String */
- public static final String RESNAME_APP_ADDR = "APP_ADDR";
-
- /**
- * 当前进程的work线程池, 类型:Executor、ExecutorService
- *
- * @since 2.3.0
- */
- public static final String RESNAME_APP_EXECUTOR = "APP_EXECUTOR";
-
- /**
- * 使用RESNAME_APP_CLIENT_IOGROUP代替
- *
- * @since 2.3.0
- */
- public static final String RESNAME_APP_CLIENT_ASYNCGROUP = "APP_CLIENT_ASYNCGROUP";
-
- /** 当前Service所属的SNCP Server的地址 类型: SocketAddress、InetSocketAddress、String
*/
- public static final String RESNAME_SNCP_ADDRESS = "SNCP_ADDRESS";
-
- /** 当前Service所属的SNCP Server所属的组 类型: String
*/
- public static final String RESNAME_SNCP_GROUP = "SNCP_GROUP";
-
- /** "SERVER_ROOT" 当前Server的ROOT目录类型:String、File、Path */
- public static final String RESNAME_SERVER_ROOT = Server.RESNAME_SERVER_ROOT;
-
- /** 当前Server的ResourceFactory */
- public static final String RESNAME_SERVER_RESFACTORY = "SERVER_RESFACTORY";
-
- public static final String SYSNAME_APP_NAME = "redkale.application.name";
-
- public static final String SYSNAME_APP_NODEID = "redkale.application.nodeid";
-
- public static final String SYSNAME_APP_HOME = "redkale.application.home";
-
- public static final String SYSNAME_APP_CONF_DIR = "redkale.application.confdir";
-
- public static final Set
- * 1、基本环境变量设置
- * 2、ClassLoader初始化
- * 3、日志配置初始化
- * 4、本地和远程配置文件读取
- * 5、ClusterAgent和MessageAgent实例化
- * 6、Work线程池初始化 7、原生sql解析器初始化
- *
- * @param singletonMode 是否测试模式
- * @param compileMode 是否编译模式
- * @param config 启动配置
- */
- @SuppressWarnings("UseSpecificCatch") // config: 不带redkale.前缀的配置项
- Application(final AppConfig appConfig) {
- this.singletonMode = appConfig.singletonMode;
- this.compileMode = appConfig.compileMode;
- this.config = appConfig.config;
- this.envProperties.putAll(appConfig.localEnvProperties);
- this.environment = new Environment(this.envProperties);
- this.name = appConfig.name;
- this.nodeid = appConfig.nodeid;
- this.home = appConfig.home;
- this.confDir = appConfig.confDir;
- this.localAddress = appConfig.localAddress;
- this.classLoader = appConfig.classLoader;
- this.serverClassLoader = appConfig.serverClassLoader;
-
- this.loggingModule = new LoggingModule(this);
- this.propertiesModule = new PropertiesModule(this);
- this.sourceModule = new SourceModuleEngine(this);
-
- // 设置基础信息资源
- this.resourceFactory.register(RESNAME_APP_NAME, String.class, this.name);
-
- this.resourceFactory.register(RESNAME_APP_NODEID, String.class, this.nodeid);
- if (Utility.isNumeric(this.nodeid)) { // 兼容旧类型
- this.resourceFactory.register(
- RESNAME_APP_NODEID, int.class, Math.abs(((Long) Long.parseLong(this.nodeid)).intValue()));
- }
-
- this.resourceFactory.register(RESNAME_APP_TIME, long.class, this.startTime);
- this.resourceFactory.register(RESNAME_APP_TIME, Long.class, this.startTime);
-
- this.resourceFactory.register(RESNAME_APP_HOME, String.class, this.home.getPath());
- this.resourceFactory.register(RESNAME_APP_HOME, Path.class, this.home.toPath());
- this.resourceFactory.register(RESNAME_APP_HOME, File.class, this.home);
- this.resourceFactory.register(RESNAME_APP_HOME, URI.class, this.home.toURI());
-
- this.resourceFactory.register(RESNAME_APP_ADDR, InetSocketAddress.class, this.localAddress);
- this.resourceFactory.register(RESNAME_APP_ADDR, InetAddress.class, this.localAddress.getAddress());
- this.resourceFactory.register(
- RESNAME_APP_ADDR, String.class, this.localAddress.getAddress().getHostAddress());
-
- this.resourceFactory.register(RESNAME_APP_CONF_DIR, URI.class, this.confDir);
- this.resourceFactory.register(RESNAME_APP_CONF_DIR, File.class, appConfig.confFile);
- this.resourceFactory.register(RESNAME_APP_CONF_DIR, String.class, this.confDir.toString());
-
- System.setProperty("redkale.version", Redkale.getDotedVersion());
- System.setProperty(SYSNAME_APP_NAME, this.name);
- System.setProperty(SYSNAME_APP_NODEID, String.valueOf(this.nodeid));
- System.setProperty(SYSNAME_APP_HOME, this.home.getPath());
- System.setProperty(SYSNAME_APP_CONF_DIR, this.confDir.toString());
-
- this.envProperties.put(RESNAME_APP_NAME, this.name);
- this.envProperties.put(RESNAME_APP_NODEID, String.valueOf(this.nodeid));
- this.envProperties.put(RESNAME_APP_TIME, String.valueOf(this.startTime));
- this.envProperties.put(RESNAME_APP_HOME, this.home.getPath());
- this.envProperties.put(RESNAME_APP_ADDR, this.localAddress.getAddress().getHostAddress());
- this.envProperties.put(RESNAME_APP_CONF_DIR, this.confDir.toString());
-
- // 初始化本地配置的System.properties、mimetypes
- this.registerResourceEnvs(true, appConfig.localEnvProperties);
-
- // 需要在加载properties初始化System.properties之后再注册
- this.resourceFactory.register(Environment.class, environment);
- this.resourceFactory.register(BsonFactory.root());
- this.resourceFactory.register(JsonFactory.root());
- this.resourceFactory.register(ProtobufFactory.root());
- this.resourceFactory.register(BsonFactory.root().getConvert());
- this.resourceFactory.register(JsonFactory.root().getConvert());
- this.resourceFactory.register(ProtobufFactory.root().getConvert());
- this.resourceFactory.register(
- "bsonconvert", Convert.class, BsonFactory.root().getConvert());
- this.resourceFactory.register(
- "jsonconvert", Convert.class, JsonFactory.root().getConvert());
- this.resourceFactory.register(
- "protobufconvert", Convert.class, ProtobufFactory.root().getConvert());
-
- // 系统内部模块组件
- moduleEngines.add(this.sourceModule); // 放第一,很多module依赖于source
- moduleEngines.add(new MessageModuleEngine(this));
- moduleEngines.add(new ClusterModuleEngine(this));
- moduleEngines.add(new ScheduleModuleEngine(this));
- moduleEngines.add(new CacheModuleEngine(this));
- moduleEngines.add(new LockModuleEngine(this));
-
- // 根据本地日志配置文件初始化日志
- loggingModule.reconfigLogging(true, appConfig.locaLogProperties);
-
- // 打印基础信息日志
- logger.log(
- Level.INFO,
- colorMessage(
- logger,
- 36,
- 1,
- "-------------------------------- Redkale " + Redkale.getDotedVersion()
- + " --------------------------------"));
-
- final String confDirStr = this.confDir.toString();
- logger.log(
- Level.INFO,
- "APP_OS = " + System.getProperty("os.name") + " "
- + System.getProperty("os.version") + " " + System.getProperty("os.arch") + "\r\n"
- + "APP_JAVA = "
- + System.getProperty(
- "java.runtime.name",
- System.getProperty("org.graalvm.nativeimage.kind") != null ? "Nativeimage" : "")
- + " "
- + System.getProperty(
- "java.runtime.version",
- System.getProperty("java.vendor.version", System.getProperty("java.vm.version")))
- + "\r\n" // graalvm.nativeimage 模式下无 java.runtime.xxx 属性
- + "APP_PID = " + ProcessHandle.current().pid() + "\r\n"
- + RESNAME_APP_NAME + " = " + this.name + "\r\n"
- + RESNAME_APP_NODEID + " = " + this.nodeid + "\r\n"
- + "APP_LOADER = " + this.classLoader.getClass().getSimpleName() + "\r\n"
- + RESNAME_APP_ADDR + " = " + this.localAddress.getHostString() + ":"
- + this.localAddress.getPort() + "\r\n"
- + RESNAME_APP_HOME + " = " + this.home.getPath().replace('\\', '/') + "\r\n"
- + RESNAME_APP_CONF_DIR + " = " + confDirStr.substring(confDirStr.indexOf('!') + 1));
-
- if (!compileMode && !(classLoader instanceof RedkaleClassLoader.RedkaleCacheClassLoader)) {
- String lib = environment.getPropertyValue(
- config.getValue("lib", "${APP_HOME}/libs/*").trim());
- lib = Utility.isEmpty(lib) ? confDirStr : (lib + ";" + confDirStr);
- Server.loadLib(classLoader, logger, lib.isEmpty() ? confDirStr : (lib + ";" + confDirStr));
- }
- this.shutdownLatch = new CountDownLatch(config.getAnyValues("server").length + 1);
- }
-
- public void init() throws Exception {
- // 注册ResourceType
- this.initResourceTypeLoader();
- // 读取远程配置,并合并app.config
- this.propertiesModule.initRemoteProperties();
- // 解析配置
- this.onEnvironmentLoaded();
- // init起始回调
- this.onAppPreInit();
- // 设置WorkExecutor
- this.initWorkExecutor();
- // 回调Listener
- initAppListeners();
- // init结束回调
- this.onAppPostInit();
- }
-
- private void initResourceTypeLoader() {
- final Application application = this;
- // 只有WatchService才能加载Application、WatchFactory
- this.resourceFactory.register(new ResourceTypeLoader() {
-
- @Override
- public Object load(
- ResourceFactory rf,
- String srcResourceName,
- Object srcObj,
- String resourceName,
- Field field,
- Object attachment) {
- try {
- field.set(srcObj, application);
- return application;
- } catch (Exception e) {
- logger.log(Level.SEVERE, "Resource inject error", e);
- throw e instanceof RuntimeException ? (RuntimeException) e : new RedkaleException(e);
- }
- }
-
- @Override
- public Type resourceType() {
- return Application.class;
- }
-
- @Override
- public boolean autoNone() {
- return false;
- }
- });
- this.resourceFactory.register(new ResourceTypeLoader() {
-
- @Override
- public Object load(
- ResourceFactory rf,
- String srcResourceName,
- Object srcObj,
- String resourceName,
- Field field,
- Object attachment) {
- try {
- boolean serv =
- RESNAME_SERVER_RESFACTORY.equals(resourceName) || resourceName.equalsIgnoreCase("server");
- ResourceFactory rs = serv ? rf : (resourceName.isEmpty() ? application.resourceFactory : null);
- field.set(srcObj, rs);
- return rs;
- } catch (Exception e) {
- logger.log(Level.SEVERE, "Resource inject error", e);
- throw e instanceof RuntimeException ? (RuntimeException) e : new RedkaleException(e);
- }
- }
-
- @Override
- public Type resourceType() {
- return ResourceFactory.class;
- }
-
- @Override
- public boolean autoNone() {
- return false;
- }
- });
- this.resourceFactory.register(new ResourceTypeLoader() {
-
- @Override
- public Object load(
- ResourceFactory rf,
- String srcResourceName,
- Object srcObj,
- String resourceName,
- Field field,
- Object attachment) {
- try {
- NodeServer server = null;
- for (NodeServer ns : application.getNodeServers()) {
- if (ns.getClass() != NodeSncpServer.class) {
- continue;
- }
- if (resourceName.equals(ns.server.getName())) {
- server = ns;
- break;
- }
- }
- field.set(srcObj, server);
- return server;
- } catch (Exception e) {
- logger.log(Level.SEVERE, "Resource inject error", e);
- throw e instanceof RuntimeException ? (RuntimeException) e : new RedkaleException(e);
- }
- }
-
- @Override
- public Type resourceType() {
- return NodeSncpServer.class;
- }
-
- @Override
- public boolean autoNone() {
- return false;
- }
- });
- this.resourceFactory.register(new ResourceTypeLoader() {
-
- @Override
- public Object load(
- ResourceFactory rf,
- String srcResourceName,
- Object srcObj,
- String resourceName,
- Field field,
- Object attachment) {
- try {
- NodeServer server = null;
- for (NodeServer ns : application.getNodeServers()) {
- if (ns.getClass() != NodeHttpServer.class) {
- continue;
- }
- if (resourceName.equals(ns.server.getName())) {
- server = ns;
- break;
- }
- }
- field.set(srcObj, server);
- return server;
- } catch (Exception e) {
- logger.log(Level.SEVERE, "Resource inject error", e);
- throw e instanceof RuntimeException ? (RuntimeException) e : new RedkaleException(e);
- }
- }
-
- @Override
- public Type resourceType() {
- return NodeHttpServer.class;
- }
-
- @Override
- public boolean autoNone() {
- return false;
- }
- });
- this.resourceFactory.register(new ResourceTypeLoader() {
-
- @Override
- public Object load(
- ResourceFactory rf,
- String srcResourceName,
- Object srcObj,
- String resourceName,
- Field field,
- Object attachment) {
- try {
- NodeServer server = null;
- for (NodeServer ns : application.getNodeServers()) {
- if (ns.getClass() != NodeWatchServer.class) {
- continue;
- }
- if (resourceName.equals(ns.server.getName())) {
- server = ns;
- break;
- }
- }
- field.set(srcObj, server);
- return server;
- } catch (Exception e) {
- logger.log(Level.SEVERE, "Resource inject error", e);
- throw e instanceof RuntimeException ? (RuntimeException) e : new RedkaleException(e);
- }
- }
-
- @Override
- public Type resourceType() {
- return NodeWatchServer.class;
- }
-
- @Override
- public boolean autoNone() {
- return false;
- }
- });
-
- // ------------------------------------ 注册 java.net.http.HttpClient ------------------------------------
- resourceFactory.register(new ResourceTypeLoader() {
-
- @Override
- public Object load(
- ResourceFactory rf,
- String srcResourceName,
- Object srcObj,
- String resourceName,
- Field field,
- Object attachment) {
- try {
- java.net.http.HttpClient.Builder builder = java.net.http.HttpClient.newBuilder();
- if (resourceName.endsWith(".1.1")) {
- builder.version(HttpClient.Version.HTTP_1_1);
- } else if (resourceName.endsWith(".2")) {
- builder.version(HttpClient.Version.HTTP_2);
- }
- java.net.http.HttpClient httpClient = builder.build();
- field.set(srcObj, httpClient);
- rf.inject(resourceName, httpClient, null); // 给其可能包含@Resource的字段赋值;
- rf.register(resourceName, java.net.http.HttpClient.class, httpClient);
- return httpClient;
- } catch (Exception e) {
- logger.log(Level.SEVERE, java.net.http.HttpClient.class.getSimpleName() + " inject error", e);
- return null;
- }
- }
-
- @Override
- public Type resourceType() {
- return java.net.http.HttpClient.class;
- }
- });
- // ------------------------------------ 注册 WebClient ------------------------------------
- resourceFactory.register(new ResourceTypeLoader() {
-
- @Override
- public Object load(
- ResourceFactory rf,
- String srcResourceName,
- Object srcObj,
- String resourceName,
- Field field,
- Object attachment) {
- try {
- WebClient httpClient = WebClient.create(workExecutor, clientAsyncGroup);
- field.set(srcObj, httpClient);
- rf.inject(resourceName, httpClient, null); // 给其可能包含@Resource的字段赋值;
- rf.register(resourceName, WebClient.class, httpClient);
- return httpClient;
- } catch (Exception e) {
- logger.log(Level.SEVERE, WebClient.class.getSimpleName() + " inject error", e);
- throw e instanceof RuntimeException ? (RuntimeException) e : new RedkaleException(e);
- }
- }
-
- @Override
- public Type resourceType() {
- return WebClient.class;
- }
- });
- // ------------------------------------ 注册 HttpRpcClient ------------------------------------
- resourceFactory.register(new ResourceTypeLoader() {
-
- @Override
- public Object load(
- ResourceFactory rf,
- String srcResourceName,
- Object srcObj,
- String resourceName,
- Field field,
- Object attachment) {
- try {
- ClusterAgent clusterAgent = resourceFactory.find("", ClusterAgent.class);
- MessageAgent messageAgent = resourceFactory.find(resourceName, MessageAgent.class);
- if (messageAgent != null) {
- if (clusterAgent == null
- || !Objects.equals(clusterAgent.getName(), resourceName)
- || messageAgent.isRpcFirst()) {
- HttpRpcClient rpcClient = messageAgent.getHttpRpcClient();
- field.set(srcObj, rpcClient);
- rf.inject(resourceName, rpcClient, null); // 给其可能包含@Resource的字段赋值;
- rf.register(resourceName, HttpRpcClient.class, rpcClient);
- return rpcClient;
- }
- }
- if (clusterAgent == null) {
- HttpRpcClient rpcClient = new HttpLocalRpcClient(application, resourceName);
- field.set(srcObj, rpcClient);
- rf.inject(resourceName, rpcClient, null); // 给其可能包含@Resource的字段赋值;
- rf.register(resourceName, HttpRpcClient.class, rpcClient);
- return rpcClient;
- }
- HttpRpcClient rpcClient = new HttpClusterRpcClient(application, resourceName, clusterAgent);
- field.set(srcObj, rpcClient);
- rf.inject(resourceName, rpcClient, null); // 给其可能包含@Resource的字段赋值;
- rf.register(resourceName, HttpRpcClient.class, rpcClient);
- return rpcClient;
- } catch (Exception e) {
- logger.log(Level.SEVERE, HttpRpcClient.class.getSimpleName() + " inject error", e);
- throw e instanceof RuntimeException ? (RuntimeException) e : new RedkaleException(e);
- }
- }
-
- @Override
- public Type resourceType() {
- return HttpRpcClient.class;
- }
- });
- }
-
- private void registerResourceEnvs(boolean first, Properties... envs) {
- for (Properties props : envs) {
- props.forEach((k, v) -> {
- String val = environment.getPropertyValue(v.toString(), envs);
- if (k.toString().startsWith("system.property.")) {
- String key = k.toString().substring("system.property.".length());
- if (System.getProperty(key) == null || !first) {
- System.setProperty(key, val);
- }
- resourceFactory.register(!first, k.toString(), val);
- } else if (k.toString().startsWith("mimetype.property.")) {
- MimeType.add(k.toString().substring("mimetype.property.".length()), val);
- } else {
- resourceFactory.register(!first, k.toString(), val);
- }
- });
- }
- }
-
- /** 设置WorkExecutor */
- private void initWorkExecutor() {
- int bufferCapacity = 32 * 1024;
- int bufferPoolSize = Utility.cpus() * 8;
- final AnyValue executorConf = config.getAnyValue("executor", true);
- StringBuilder executorLog = new StringBuilder();
-
- final int workThreads = Math.max(Utility.cpus(), executorConf.getIntValue("threads", Utility.cpus() * 10));
- // 指定threads则不使用虚拟线程池
- this.workExecutor = executorConf.getValue("threads") != null
- ? WorkThread.createExecutor(workThreads, "Redkale-WorkThread-%s")
- : WorkThread.createWorkExecutor(workThreads, "Redkale-WorkThread-%s");
- String executorName = this.workExecutor.getClass().getSimpleName();
- executorLog.append("defaultWorkExecutor: {type=").append(executorName);
- if (executorName.contains("VirtualExecutor") || executorName.contains("PerTaskExecutor")) {
- executorLog.append(", threads=[virtual]}");
- } else {
- executorLog.append(", threads=").append(workThreads).append("}");
- }
-
- ExecutorService clientWorkExecutor = this.workExecutor;
- if (executorName.contains("VirtualExecutor") || executorName.contains("PerTaskExecutor")) {
- executorLog.append(", clientWorkExecutor: [workExecutor]");
- } else {
- // 给所有client给一个新的默认ExecutorService
- int clientThreads = executorConf.getIntValue("clients", Utility.cpus() * 4);
- clientWorkExecutor = WorkThread.createWorkExecutor(clientThreads, "Redkale-DefaultClient-WorkThread-%s");
- executorLog.append(", threads=").append(clientThreads).append("}");
- }
- AsyncIOGroup ioGroup = new AsyncIOGroup(
- "Redkale-DefaultClient-IOThread-%s", clientWorkExecutor, bufferCapacity, bufferPoolSize)
- .skipClose(true);
- this.clientAsyncGroup = ioGroup.start();
-
- if (executorLog.length() > 0) {
- logger.log(Level.INFO, executorLog.toString());
- }
- this.resourceFactory.register(RESNAME_APP_EXECUTOR, Executor.class, this.workExecutor);
- this.resourceFactory.register(RESNAME_APP_EXECUTOR, ExecutorService.class, this.workExecutor);
- this.resourceFactory.register(RESNAME_APP_CLIENT_ASYNCGROUP, AsyncGroup.class, this.clientAsyncGroup);
- this.resourceFactory.register(RESNAME_APP_CLIENT_ASYNCGROUP, AsyncIOGroup.class, this.clientAsyncGroup);
- }
-
- private void initAppListeners() throws Exception {
- // ------------------------------------------------------------------------
- for (AnyValue conf : config.getAnyValues("group")) {
- final String group = conf.getValue("name", "");
- if (group.indexOf('$') >= 0 || group.indexOf('.') >= 0) {
- throw new RedkaleException("