Codebase list eclipselink / upstream/latest
New upstream version 2.6.9 Emmanuel Bourg 3 years ago
193 changed file(s) with 51634 addition(s) and 52318 deletion(s). Raw diff Collapse all Expand all
00 Manifest-Version: 1.0
1 Ant-Version: Apache Ant 1.9.6
2 Created-By: 1.7.0_80-b15 (Oracle Corporation)
1 Ant-Version: Apache Ant 1.10.7
2 Created-By: 1.8.0_222-b10 (Oracle Corporation)
33 Specification-Title: Eclipse Persistence Services Source
44 Specification-Vendor: Eclipse.org - EclipseLink Project
5 Specification-Version: 2.6.6
5 Specification-Version: 2.6.9
66 Implementation-Title: org.eclipse.persistence
77 Implementation-Vendor: Eclipse.org - EclipseLink Project
8 Implementation-Version: 2.6.6.v20181219-80f4920114
9 Release-Designation: EclipseLink 2.6.6
8 Implementation-Version: 2.6.9.v20200130-0143b822bc
9 Release-Designation: EclipseLink 2.6.9
1010
00 #Source Bundle Localization
1 #Wed Dec 19 08:26:19 EST 2018
1 #Thu Jan 30 14:07:19 UTC 2020
22 bundleVendor=Eclipse.org - EclipseLink Project
33 bundleName=EclipseLink Core Source
8181 </li>
8282 </ul>
8383 <hr />
84 <h3><a name="ASM" id="ASM"></a>ASM v5.0.1</h3>
84 <h3><a name="ASM" id="ASM"></a>ASM v6.2.0</h3>
8585 <blockquote>
86 <p>The EclipseLink Project includes ASM for the purpose of
87 byte code weaving. The AMS library is re-packaged within the source of the
88 project (org.persistence.eclipse.internal.libraries.asm.*) to avoid version
89 collisions with other usage of ASM.
90 </p>
91 <p>The source code is available within the project's subversion repository.
92 The binaries are distributed within the eclipselink.jar and in the org.eclipse.persistence.asm_*.jar
93 bundle. </p>
94 <p> <a href="http://asm.objectweb.org/license.html">http://asm.objectweb.org/license.html</a></p>
95 <p>Copyright (c) 2000-2005 INRIA, France Telecom, All rights reserved.</p>
96 <p>Redistribution and use in source and binary forms, with or without modification,
97 are permitted provided that the following conditions are met:</p>
98 <ol>
99 <li> Redistributions of source code must retain the above copyright notice,
100 this list of conditions and the following disclaimer.</li>
101 <li> Redistributions in binary form must reproduce the above copyright notice,
102 this list of conditions and the following disclaimer in the documentation
103 and/or other materials provided with the distribution.</li>
104 <li> Neither the name of the copyright holders nor the names of its contributors
105 may be used to endorse or promote products derived from this software without
106 specific prior written permission.</li>
107 </ol>
108 <p>THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS &quot;AS
109 IS&quot;AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
110 TO, THEIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
111 PURPOSEARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
112 BELIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, ORCONSEQUENTIAL
113 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OFSUBSTITUTE GOODS OR
114 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
115 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER INCONTRACT, STRICT LIABILITY,
116 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)ARISING IN ANY WAY OUT OF THE USE
117 OF THIS SOFTWARE, EVEN IF ADVISED OFTHE POSSIBILITY OF SUCH DAMAGE.</p>
86 <p>The EclipseLink Project includes ASM for the purpose of
87 byte code weaving. The AMS library is re-packaged within the source of the
88 project (org.persistence.eclipse.internal.libraries.asm.*) to avoid version
89 collisions with other usage of ASM.
90 </p>
91 <p>The source code is available within the project's git repository.
92 The binaries are distributed within the eclipselink.jar and in the org.eclipse.persistence.asm_*.jar
93 bundle. </p>
94 <p> <a href="https://asm.ow2.io/license.html">https://asm.ow2.io/license.html</a></p>
95 <p>Copyright (c) 2000-2011 INRIA, France Telecom, All rights reserved.</p>
96 <p>Redistribution and use in source and binary forms, with or without
97 modification, are permitted provided that the following conditions
98 are met:</p>
99 <ol>
100 <li>Redistributions of source code must retain the above copyright
101 notice, this list of conditions and the following disclaimer.</li>
102 <li>Redistributions in binary form must reproduce the above copyright
103 notice, this list of conditions and the following disclaimer in the
104 documentation and/or other materials provided with the distribution.</li>
105 <li>Neither the name of the copyright holders nor the names of its
106 contributors may be used to endorse or promote products derived from
107 this software without specific prior written permission.</li>
108 </ol>
109 <p>THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS &quot;AS IS&quot;
110 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
111 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
112 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
113 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
114 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
115 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
116 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
117 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
118 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
119 THE POSSIBILITY OF SUCH DAMAGE.</p>
118120 </blockquote>
119121 <h3><a name="ANTLR" id="ANTLR"></a>ANTLR v3.2</h3>
120122 <blockquote>
3131 // This will be used by all product components and included in exceptions.
3232 private static String product = "Eclipse Persistence Services";
3333 // A three part version number (major.minor.service)
34 private static final String version = "2.6.6";
34 private static final String version = "2.6.9";
3535 // A string that describes this build i.e.( vYYYYMMDD-HHMM, etc.)
36 private static final String qualifier = "v20181219-80f4920114";
36 private static final String qualifier = "v20200130-0143b822bc";
3737 // Should be in the format YYYYMMDD
38 private static final String buildDate = "20181219";
38 private static final String buildDate = "20200130";
3939 // Should be in the format HHMM
40 private static final String buildTime = "0826";
40 private static final String buildTime = "1407";
4141 // revision of source from the repository
4242 private static final String buildRevision = "NA";
4343 // Typically SNAPSHOT, Milestone name (M1,M2,etc), or RELEASE
00 /*******************************************************************************
1 * Copyright (c) 1998, 2015 Oracle and/or its affiliates, IBM Corporation. All rights reserved.
1 * Copyright (c) 1998, 2020 Oracle and/or its affiliates, IBM Corporation. All rights reserved.
22 * This program and the accompanying materials are made available under the
33 * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
44 * which accompanies this distribution.
3636 * - 458877 : Add national character support
3737 * 09/03/2015 - Will Dazey
3838 * - 456067 : Added support for defining query timeout units
39 * 09/28/2015 - Will Dazey
40 * - 478331 : Added support for defining local or server as the default locale for obtaining timestamps
41 * 12/06/2018 - Will Dazey
42 * - 542491: Add new 'eclipselink.jdbc.force-bind-parameters' property to force enable binding
3943 ******************************************************************************/
4044 package org.eclipse.persistence.config;
4145
10141018 public static final String JDBC_BIND_PARAMETERS = "eclipselink.jdbc.bind-parameters";
10151019
10161020 /**
1021 * Property "<code>eclipselink.jdbc.force-bind-parameters</code>" enables parameter binding
1022 * in the creation of JDBC prepared statements. Some database platforms disable parameter binding
1023 * on certain functions and relations. This property allows the user to force parameter binding
1024 * to be enabled regardless.
1025 * <p>
1026 * <b>Allowed Values:</b>
1027 * <ul>
1028 * <li>"<code>false</code>" (DEFAULT) - values will default to platform specific logic
1029 * <li>"<code>true</code>" - bindings will use platform default
1030 * </ul>
1031 *
1032 * @see #JDBC_BIND_PARAMETERS
1033 */
1034 public static final String JDBC_FORCE_BIND_PARAMETERS = "eclipselink.jdbc.force-bind-parameters";
1035
1036 /**
10171037 * The "<code>eclipselink.jdbc.exclusive-connection.mode</code>" property
10181038 * specifies when reads are performed through the write connection.<br>
10191039 * You can set this property while creating either an EntityManagerFactory (either
30323052 * <ul>
30333053 * <li>a string containing a zero or greater integer value
30343054 * </ul>
3035 * @see PersistenceUnitProperties.QUERY_TIMEOUT_UNIT
3055 * @see #QUERY_TIMEOUT_UNIT
30363056 */
30373057 public static final String QUERY_TIMEOUT = "javax.persistence.query.timeout";
30383058
30473067 * <li>"<code>java.util.concurrent.TimeUnit.SECONDS</code>" (DEFAULT),
30483068 * <li>"<code>java.util.concurrent.TimeUnit.MINUTES</code>".
30493069 * </ul>
3050 * @see PersistenceUnitProperties.QUERY_TIMEOUT
3070 * @see #QUERY_TIMEOUT
30513071 */
30523072 public static final String QUERY_TIMEOUT_UNIT = "eclipselink.query.timeout.unit";
30533073
37023722 public static final String JPQL_TOLERATE = "eclipselink.tolerate-invalid-jpql";
37033723
37043724 /**
3725 * The "<code>eclipselink.locking.timestamp.local</code>" property defines if locking policies
3726 * should default to local time(true) or server time(false).
3727 * <p>
3728 * <b>Allowed Values</b> (case sensitive String)<b>:</b>
3729 * <ul>
3730 * <li>"<code>false</code>" (DEFAULT)
3731 * <li>"<code>true</code>"
3732 * </ul>
3733 */
3734 public static final String USE_LOCAL_TIMESTAMP = "eclipselink.locking.timestamp.local." + PersistenceUnitProperties.DEFAULT;
3735
3736 /**
37053737 * INTERNAL: The following properties will not be displayed through logging
37063738 * but instead have an alternate value shown in the log.
37073739 */
6767 public static final String DO_NOT_PROCESS_XTOMANY_FOR_QBE = "eclipselink.query.query-by-example.ignore-xtomany";
6868
6969 /**
70 * This property can be set to <code>false</code> to enable UPDATE call to set
71 * foreign key value in the target row in unidirectional 1-Many mapping
72 * with not nullable FK. In previous versions of EclipseLink this was
73 * the default behaviour.
74 * Allowed values are: true/false.
75 */
76 public static final String ONETOMANY_DEFER_INSERTS = "eclipselink.mapping.onetomany.defer-inserts";
77
78 /**
7079 * This system property can be set to override target server platform set by the Java EE container
7180 * with the one either set in persistence.xml or auto detected.
7281 */
0 /*******************************************************************************
1 * Copyright (c) 1998, 2017 Oracle and/or its affiliates. All rights reserved.
2 * This program and the accompanying materials are made available under the
3 * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
4 * which accompanies this distribution.
0 /*******************************************************************************
1 * Copyright (c) 1998, 2019 Oracle and/or its affiliates. All rights reserved.
2 * This program and the accompanying materials are made available under the
3 * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
4 * which accompanies this distribution.
55 * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
66 * and the Eclipse Distribution License is available at
77 * http://www.eclipse.org/org/documents/edl-v10.php.
8 *
9 * Contributors:
10 * Oracle - initial API and implementation from Oracle TopLink
11 * 12/14/2017-2.6.6 Tomas Kraus
12 * - 291546: Performance degradation due to usage of Vector in DescriptorEventManager
13 ******************************************************************************/
14 package org.eclipse.persistence.descriptors;
15
16 import java.util.List;
17
18 /**
19 * <p><b>Purpose</b>: Provides an empty implementation of DescriptorEventListener.
8 *
9 * Contributors:
10 * Oracle - initial API and implementation from Oracle TopLink
11 ******************************************************************************/
12 package org.eclipse.persistence.descriptors;
13
14 import java.util.Vector;
15
16 /**
17 * <p><b>Purpose</b>: Provides an empty implementation of DescriptorEventListener.
2018 * Users who do not require the full DescritorEventListener API can subclass this class
2119 * and implement only the methods required.
2220 *
2725 public void aboutToInsert(DescriptorEvent event) {}
2826
2927 public void aboutToUpdate(DescriptorEvent event) {}
30
31 public void aboutToDelete(DescriptorEvent event) {}
32
33 @Override
34 public boolean isOverriddenEvent(DescriptorEvent event, List<DescriptorEventManager> eventManagers) {
35 return false;
36 }
37
28
29 public void aboutToDelete(DescriptorEvent event) {}
30
31 public boolean isOverriddenEvent(DescriptorEvent event, Vector eventManagers) {
32 return false;
33 }
34
3835 public void postBuild(DescriptorEvent event) {}
3936
4037 public void postClone(DescriptorEvent event) {}
0 /*******************************************************************************
1 * Copyright (c) 1998, 2017 Oracle and/or its affiliates. All rights reserved.
2 * This program and the accompanying materials are made available under the
3 * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
4 * which accompanies this distribution.
0 /*******************************************************************************
1 * Copyright (c) 1998, 2019 Oracle and/or its affiliates. All rights reserved.
2 * This program and the accompanying materials are made available under the
3 * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
4 * which accompanies this distribution.
55 * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
66 * and the Eclipse Distribution License is available at
77 * http://www.eclipse.org/org/documents/edl-v10.php.
8 *
9 * Contributors:
10 * Oracle - initial API and implementation from Oracle TopLink
11 * 12/14/2017-2.6.6 Tomas Kraus
12 * - 291546: Performance degradation due to usage of Vector in DescriptorEventManager
13 ******************************************************************************/
14 package org.eclipse.persistence.descriptors;
15
16 import java.util.EventListener;
17 import java.util.List;
18
19 /**
20 * <p><b>Purpose</b>: Used to support Java event listener event model on descriptors.
8 *
9 * Contributors:
10 * Oracle - initial API and implementation from Oracle TopLink
11 ******************************************************************************/
12 package org.eclipse.persistence.descriptors;
13
14 import java.util.*;
15
16 /**
17 * <p><b>Purpose</b>: Used to support Java event listener event model on descriptors.
2118 * Events can be registered for, through two methods, the first is by providing a method
2219 * to be called on the object that a particular operation is being performed on.
2320 * The second is by registering an event listener object to be notified when any event occurs
3330 /**
3431 * This event is raised before an object is deleted from the database.
3532 * The object's row has already been built and is accessible from the event.
36 * This event can be used to amend an object's delete row.
37 */
38 // CR#2660080 was missing aboutToDelete
39 void aboutToDelete(DescriptorEvent event);
40
41 /**
42 * This event is raised before a new object is inserted to the database.
43 * The object's row has already been built and is accessible from the event.
44 * This event can be used to amend an object's insert row.
45 */
46 void aboutToInsert(DescriptorEvent event);
47
48 /**
49 * This event is raised before an object is updated in the database.
33 * This event can be used to amend an object's delete row.
34 */
35 // CR#2660080 was missing aboutToDelete
36 public void aboutToDelete(DescriptorEvent event);
37
38 /**
39 * This event is raised before a new object is inserted to the database.
40 * The object's row has already been built and is accessible from the event.
41 * This event can be used to amend an object's insert row.
42 */
43 public void aboutToInsert(DescriptorEvent event);
44
45 /**
46 * This event is raised before an object is updated in the database.
5047 * This event is only raised for object's that have changes and will be updated.
51 * The object's row has already been built and is accessible from the event.
52 * This event can be used to amend an object's update row.
53 */
54 void aboutToUpdate(DescriptorEvent event);
55
56 /**
57 * Implementers should define this method if they need or want to restrict
58 * the calling of inherited events.
59 */
60 boolean isOverriddenEvent(DescriptorEvent event, List<DescriptorEventManager> eventManagers);
61
62 /**
63 * This event is raised after an object is built from its row on a read operation.
64 * This event can be used to initialize non-persistent or non-mapped state in the object.
65 */
66 void postBuild(DescriptorEvent event);
67
68 /**
69 * This event is raised after an object is cloned into a unit of work.
48 * The object's row has already been built and is accessible from the event.
49 * This event can be used to amend an object's update row.
50 */
51 public void aboutToUpdate(DescriptorEvent event);
52
53 /**
54 * Implementers should define this method if they need or want to restrict
55 * the calling of inherited events.
56 */
57 public boolean isOverriddenEvent(DescriptorEvent event, Vector eventManagers);
58
59 /**
60 * This event is raised after an object is built from its row on a read operation.
61 * This event can be used to initialize non-persistent or non-mapped state in the object.
62 */
63 public void postBuild(DescriptorEvent event);
64
65 /**
66 * This event is raised after an object is cloned into a unit of work.
7067 * This event can be used to initialize non-mapped state in the object.
71 * The event source/object is the unit of work clone,
72 * the event originalObject is the original object from the session cache.
73 */
74 void postClone(DescriptorEvent event);
75
76 /**
77 * This event is raised after an object is deleted from the database.
78 */
79 void postDelete(DescriptorEvent event);
80
81 /**
82 * This event is raised after an object is inserted to the database.
83 */
84 void postInsert(DescriptorEvent event);
85
86 /**
87 * This event is raised after an object is merged from a unit of work into its parent.
68 * The event source/object is the unit of work clone,
69 * the event originalObject is the original object from the session cache.
70 */
71 public void postClone(DescriptorEvent event);
72
73 /**
74 * This event is raised after an object is deleted from the database.
75 */
76 public void postDelete(DescriptorEvent event);
77
78 /**
79 * This event is raised after an object is inserted to the database.
80 */
81 public void postInsert(DescriptorEvent event);
82
83 /**
84 * This event is raised after an object is merged from a unit of work into its parent.
8885 * This event can be used to initialize non-mapped state in the parent object.
89 * The event source/object is the parent session object that was merged into,
90 * the event originalObject is the unit of work clone that was merged from.
91 */
92 void postMerge(DescriptorEvent event);
93
94 /**
95 * This event is raised after an object is refreshed from its row on a refresh operation.
96 * This event can be used to initialize non-persistent or non-mapped state in the object.
97 */
98 void postRefresh(DescriptorEvent event);
99
100 /**
101 * This event is raised after an object updated in the database.
102 * This event is only raised for objects that had changes and were updated.
103 */
104 void postUpdate(DescriptorEvent event);
105
106 /**
107 * This event is raised after an object is inserted or updated in the database.
108 * This event is only raised for new objects or objects that had changes and were updated.
109 */
110 void postWrite(DescriptorEvent event);
111
112 /**
113 * This event is raised before an object is deleted from the database.
114 */
115 void preDelete(DescriptorEvent event);
116
117 /**
118 * This event is raised before an object is inserted to the database.
119 */
120 void preInsert(DescriptorEvent event);
121
122 /**
123 * This event is only raised by the EntityManager. It is raised when the
124 * create operation is initiated on an object.
125 */
126 void prePersist(DescriptorEvent event);
127
128 /**
129 * This event is raised when the remove operation is initiated on an object.
130 */
131 void preRemove(DescriptorEvent event);
132
133 /**
134 * This event is raised for all existing objects written or committed in a unit of work.
86 * The event source/object is the parent session object that was merged into,
87 * the event originalObject is the unit of work clone that was merged from.
88 */
89 public void postMerge(DescriptorEvent event);
90
91 /**
92 * This event is raised after an object is refreshed from its row on a refresh operation.
93 * This event can be used to initialize non-persistent or non-mapped state in the object.
94 */
95 public void postRefresh(DescriptorEvent event);
96
97 /**
98 * This event is raised after an object updated in the database.
99 * This event is only raised for objects that had changes and were updated.
100 */
101 public void postUpdate(DescriptorEvent event);
102
103 /**
104 * This event is raised after an object is inserted or updated in the database.
105 * This event is only raised for new objects or objects that had changes and were updated.
106 */
107 public void postWrite(DescriptorEvent event);
108
109 /**
110 * This event is raised before an object is deleted from the database.
111 */
112 public void preDelete(DescriptorEvent event);
113
114 /**
115 * This event is raised before an object is inserted to the database.
116 */
117 public void preInsert(DescriptorEvent event);
118
119 /**
120 * This event is only raised by the EntityManager. It is raised when the
121 * create operation is initiated on an object.
122 */
123 public void prePersist(DescriptorEvent event);
124
125 /**
126 * This event is raised when the remove operation is initiated on an object.
127 */
128 public void preRemove(DescriptorEvent event);
129
130 /**
131 * This event is raised for all existing objects written or committed in a unit of work.
135132 * This event is raised before the object's changes are computed,
136 * so the object may still be modified by the event.
137 * If the object has no changes, it will not be updated in a unit of work.
138 */
139 void preUpdate(DescriptorEvent event);
140
141 /**
142 * This event is raised before an object is updated regardless if the object
133 * so the object may still be modified by the event.
134 * If the object has no changes, it will not be updated in a unit of work.
135 */
136 public void preUpdate(DescriptorEvent event);
137
138 /**
139 * This event is raised before an object is updated regardless if the object
143140 * has any database changes. This event was created to support EJB 3.0
144141 * events. The object in this case will not have a row accessible from the
145 * event. For objects that have database changes, an aboutToUpdate will also
146 * be triggered.
147 */
148 void preUpdateWithChanges(DescriptorEvent event);
149
150 /**
151 * This event is raised for all new or existing objects written or committed in a unit of work.
142 * event. For objects that have database changes, an aboutToUpdate will also
143 * be triggered.
144 */
145 public void preUpdateWithChanges(DescriptorEvent event);
146
147 /**
148 * This event is raised for all new or existing objects written or committed in a unit of work.
152149 * This event is raised before the object's changes are computed,
153 * so the object may still be modified by the event.
154 * If the object is existing and has no changes, it will not be updated in a unit of work.
155 */
156 void preWrite(DescriptorEvent event);
157 }
150 * so the object may still be modified by the event.
151 * If the object is existing and has no changes, it will not be updated in a unit of work.
152 */
153 public void preWrite(DescriptorEvent event);
154 }
0 /*******************************************************************************
1 * Copyright (c) 1998, 2017 Oracle and/or its affiliates. All rights reserved.
2 * This program and the accompanying materials are made available under the
3 * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
4 * which accompanies this distribution.
0 /*******************************************************************************
1 * Copyright (c) 1998, 2019 Oracle and/or its affiliates. All rights reserved.
2 * This program and the accompanying materials are made available under the
3 * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
4 * which accompanies this distribution.
55 * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
66 * and the Eclipse Distribution License is available at
77 * http://www.eclipse.org/org/documents/edl-v10.php.
8 *
9 * Contributors:
10 * Oracle - initial API and implementation from Oracle TopLink
11 * 12/14/2017-2.6.6 Tomas Kraus
12 * - 291546: Performance degradation due to usage of Vector in DescriptorEventManager
13 ******************************************************************************/
14 package org.eclipse.persistence.descriptors;
15
16 import java.io.Serializable;
17 import java.lang.reflect.InvocationTargetException;
18 import java.lang.reflect.Method;
19 import java.security.AccessController;
20 import java.security.PrivilegedActionException;
21 import java.util.ArrayList;
22 import java.util.List;
23 import java.util.concurrent.CopyOnWriteArrayList;
24 import java.util.concurrent.atomic.AtomicIntegerArray;
25 import java.util.concurrent.atomic.AtomicReferenceArray;
26
27 import org.eclipse.persistence.core.descriptors.CoreDescriptorEventManager;
28 import org.eclipse.persistence.exceptions.DescriptorException;
29 import org.eclipse.persistence.internal.helper.ClassConstants;
30 import org.eclipse.persistence.internal.helper.Helper;
31 import org.eclipse.persistence.internal.security.PrivilegedAccessHelper;
32 import org.eclipse.persistence.internal.security.PrivilegedMethodInvoker;
33 import org.eclipse.persistence.internal.sessions.AbstractSession;
34 import org.eclipse.persistence.sessions.SessionProfiler;
35
36 /**
37 * <p><b>Purpose</b>: The event manager allows for a descriptor to specify that
8 *
9 * Contributors:
10 * Oracle - initial API and implementation from Oracle TopLink
11 ******************************************************************************/
12 package org.eclipse.persistence.descriptors;
13
14 import java.lang.reflect.*;
15 import java.security.AccessController;
16 import java.security.PrivilegedActionException;
17 import java.util.*;
18 import java.io.*;
19
20 import org.eclipse.persistence.internal.helper.*;
21 import org.eclipse.persistence.core.descriptors.CoreDescriptorEventManager;
22 import org.eclipse.persistence.exceptions.*;
23 import org.eclipse.persistence.sessions.SessionProfiler;
24 import org.eclipse.persistence.internal.security.PrivilegedAccessHelper;
25 import org.eclipse.persistence.internal.security.PrivilegedMethodInvoker;
26 import org.eclipse.persistence.internal.sessions.AbstractSession;
27
28 /**
29 * <p><b>Purpose</b>: The event manager allows for a descriptor to specify that
3830 * an object should be notified when a EclipseLink event occurs. It also determines
3931 * how the object will be notified. To specify an event a method name can be
4032 * registered to be called on the object when the event occurs. Events can be
5345 * </ul>
5446 *
5547 * @see ClassDescriptor
56 */
57 public class DescriptorEventManager extends CoreDescriptorEventManager<DescriptorEvent> implements Cloneable, Serializable {
58 protected ClassDescriptor descriptor;
59 protected AtomicReferenceArray<String> eventSelectors;
60 protected transient AtomicReferenceArray<Method> eventMethods;
61 protected transient List<DescriptorEventListener> eventListeners;
62
63 // EJB 3.0 support for event listeners.
64 protected transient List<DescriptorEventListener> defaultEventListeners;
65 protected transient List<DescriptorEventListener> entityListenerEventListeners;
66 protected transient DescriptorEventListener entityEventListener;
67 /**
68 * Listeners that are fired after all other listeners are fired
69 */
70 protected transient List<DescriptorEventListener> internalListeners = new ArrayList<>();
71
72 // EJB 3.0 support - cache our parent event managers.
73 protected transient List<DescriptorEventManager> entityEventManagers;
74 protected transient List<DescriptorEventManager> entityListenerEventManagers;
75
76 // EJB 3.0 support for event listener configuration flags.
77 protected boolean excludeDefaultListeners;
78 protected boolean excludeSuperclassListeners;
79
80 //JPA project caching support. Holds DescriptorEventListener representations for serialization/storage.
81 protected List<SerializableDescriptorEventHolder> descriptorEventHolders;
82
83 /** PERF: Cache if any events listener exist. */
84 protected boolean hasAnyEventListeners;
48 */
49 public class DescriptorEventManager extends CoreDescriptorEventManager<DescriptorEvent> implements Cloneable, Serializable {
50 protected ClassDescriptor descriptor;
51 protected Vector eventSelectors;
52 protected transient Vector eventMethods;
53 protected transient Vector eventListeners;
54
55 // EJB 3.0 support for event listeners.
56 protected transient Vector defaultEventListeners;
57 protected transient Vector entityListenerEventListeners;
58 protected transient DescriptorEventListener entityEventListener;
59 /**
60 * Listeners that are fired after all other listeners are fired
61 */
62 protected transient List<DescriptorEventListener> internalListeners = new ArrayList<DescriptorEventListener>();
63
64 // EJB 3.0 support - cache our parent event managers.
65 protected transient Vector entityEventManagers;
66 protected transient Vector entityListenerEventManagers;
67
68 // EJB 3.0 support for event listener configuration flags.
69 protected boolean excludeDefaultListeners;
70 protected boolean excludeSuperclassListeners;
71
72 //JPA project caching support. Holds DescriptorEventListener representations for serialization/storage.
73 protected java.util.List<SerializableDescriptorEventHolder> descriptorEventHolders;
74
75 /** PERF: Cache if any events listener exist. */
76 protected boolean hasAnyEventListeners;
8577 public static final int PreWriteEvent = 0;
8678 public static final int PostWriteEvent = 1;
8779 public static final int PreDeleteEvent = 2;
10294
10395 // EJB 3.0 events
10496 public static final int PrePersistEvent = 15;
105 public static final int PreRemoveEvent = 16;
106 public static final int PreUpdateWithChangesEvent = 17;
107
108 protected static final int NumberOfEvents = 18;
109
110 /**
111 * INTERNAL:
112 * Returns a new DescriptorEventManager for the specified ClassDescriptor.
113 */
114 public DescriptorEventManager() {
115 this.eventSelectors = newAtomicReferenceArray(NumberOfEvents);
116 this.eventMethods = newAtomicReferenceArray(NumberOfEvents);
117 this.hasAnyEventListeners = false;
118 this.excludeDefaultListeners = false;
119 this.excludeSuperclassListeners = false;
120 }
121
122 /**
123 * PUBLIC:
124 * EJB 3.0 support for default listeners.
125 */
126 public void addDefaultEventListener(DescriptorEventListener listener) {
127 getDefaultEventListeners().add(listener);
128 }
129
130 /**
97 public static final int PreRemoveEvent = 16;
98 public static final int PreUpdateWithChangesEvent = 17;
99
100 protected static final int NumberOfEvents = 18;
101 /**
102 * INTERNAL:
103 * Returns a new DescriptorEventManager for the specified ClassDescriptor.
104 */
105 public DescriptorEventManager() {
106 this.eventSelectors = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(NumberOfEvents);
107 this.eventMethods = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(NumberOfEvents);
108 this.hasAnyEventListeners = false;
109 this.excludeDefaultListeners = false;
110 this.excludeSuperclassListeners = false;
111
112 for (int index = 0; index < NumberOfEvents; index++) {
113 this.eventSelectors.addElement(null);
114 this.eventMethods.addElement(null);
115 }
116 }
117
118 /**
119 * PUBLIC:
120 * EJB 3.0 support for default listeners.
121 */
122 public void addDefaultEventListener(DescriptorEventListener listener) {
123 getDefaultEventListeners().addElement(listener);
124 }
125
126 /**
131127 * PUBLIC:
132128 * EJB 3.0 support for lifecycle callback events defined on an entity
133 * listener class.
134 */
135 public void addEntityListenerEventListener(DescriptorEventListener listener) {
136 getEntityListenerEventListeners().add(listener);
137 }
138
139 /**
129 * listener class.
130 */
131 public void addEntityListenerEventListener(DescriptorEventListener listener) {
132 getEntityListenerEventListeners().addElement(listener);
133 }
134
135 /**
140136 * PUBLIC:
141137 * Listener objects can be registered with the event manager to be notified
142 * when an event occurs on any instance of the descriptor's class.
143 */
144 public void addListener(DescriptorEventListener listener) {
145 getEventListeners().add(listener);
146 setHasAnyEventListeners(true);
147 }
148
138 * when an event occurs on any instance of the descriptor's class.
139 */
140 public void addListener(DescriptorEventListener listener) {
141 getEventListeners().addElement(listener);
142 setHasAnyEventListeners(true);
143 }
144
149145 /**
150146 * INTERNAL:
151147 *
152 */
153 public void addInternalListener(DescriptorEventListener listener) {
154 if (internalListeners==null) {
155 internalListeners = new ArrayList<>();
156 }
157 internalListeners.add(listener);
158 setHasAnyEventListeners(true); // ensure that events are generated
148 */
149 public void addInternalListener(DescriptorEventListener listener) {
150 if (internalListeners==null) {
151 internalListeners = new ArrayList<DescriptorEventListener>();
152 }
153 internalListeners.add(listener);
154 setHasAnyEventListeners(true); // ensure that events are generated
159155 }
160156
161157 /**
167163 }
168164
169165 /**
170 * INTERNAL:
171 * Clone the manager and its private parts.
172 */
173 @Override
174 public Object clone() {
175 try {
176 DescriptorEventManager clone = (DescriptorEventManager)super.clone();
177 clone.setEventSelectors(newAtomicReferenceArray(getEventSelectors()));
178 clone.setEventMethods(newAtomicReferenceArray(getEventMethods()));
179 clone.setEventListeners(getEventListeners());
180 return clone;
181 } catch (Exception exception) {
182 throw new AssertionError(exception);
183 }
184 }
185 /**
186 * INTERNAL:
187 * This method was added to allow JPA project caching so that DescriptorEventListeners could be
166 * INTERNAL:
167 * Clone the manager and its private parts.
168 */
169 public Object clone() {
170 DescriptorEventManager clone = null;
171
172 try {
173 clone = (DescriptorEventManager)super.clone();
174 clone.setEventSelectors((Vector)getEventSelectors().clone());
175 clone.setEventMethods((Vector)getEventMethods().clone());
176 clone.setEventListeners(getEventListeners());
177 } catch (Exception exception) {
178 ;
179 }
180
181 return clone;
182 }
183
184 /**
185 * INTERNAL:
186 * This method was added to allow JPA project caching so that DescriptorEventListeners could be
188187 * serialized and re-added to the EventManager using a SerializableDescriptorEventHolder.
189188 * @param classLoader
190189 */
231230 if (event.getSource() instanceof DescriptorEventListener) {
232231 // Allow the object itself to implement the interface.
233232 notifyListener((DescriptorEventListener)event.getSource(), event);
234 return;
235 }
236
237 Method eventMethod = (Method)getEventMethods().get(event.getEventCode());
238 if (eventMethod == null) {
239 return;
240 }
233 return;
234 }
235
236 Method eventMethod = (Method)getEventMethods().elementAt(event.getEventCode());
237 if (eventMethod == null) {
238 return;
239 }
241240
242241 // Now that I have the method, I need to invoke it
243242 try {
274273 * DescriptorEvent as argument, Session is also supported as argument for
275274 * backward compatibility.
276275 */
277 protected Method findMethod(int selector) throws DescriptorException {
278 Class[] declarationParameters = new Class[1];
279 declarationParameters[0] = ClassConstants.DescriptorEvent_Class;
280 String methodName = getEventSelectors().get(selector);
281
282 try {
283 return Helper.getDeclaredMethod(getDescriptor().getJavaClass(), methodName, declarationParameters);
276 protected Method findMethod(int selector) throws DescriptorException {
277 Class[] declarationParameters = new Class[1];
278 declarationParameters[0] = ClassConstants.DescriptorEvent_Class;
279 String methodName = (String)getEventSelectors().elementAt(selector);
280
281 try {
282 return Helper.getDeclaredMethod(getDescriptor().getJavaClass(), methodName, declarationParameters);
284283 } catch (NoSuchMethodException exception) {
285284 throw DescriptorException.noSuchMethodOnFindObsoleteMethod(methodName, getDescriptor(), exception);
286285 } catch (SecurityException exception) {
290289
291290 /**
292291 * INTERNAL:
293 * bug 251180 - Missing method org.eclipse.persistence.descriptors.DescriptorEventManager#setAboutToDeleteSelector
294 */
295 public String getAboutToDeleteSelector() {
296 return (String)getEventSelectors().get(AboutToDeleteEvent);
297 }
298
299 /**
300 * INTERNAL:
301 */
302 public String getAboutToInsertSelector() {
303 return (String)getEventSelectors().get(AboutToInsertEvent);
304 }
305
306 /**
307 * INTERNAL:
308 */
309 public String getAboutToUpdateSelector() {
310 return (String)getEventSelectors().get(AboutToUpdateEvent);
311 }
312
313 /**
314 * INTERNAL:
315 * EJB 3.0 support. Returns the default listeners.
316 */
317 public List<DescriptorEventListener> getDefaultEventListeners() {
318 if (defaultEventListeners == null) {
319 defaultEventListeners = new CopyOnWriteArrayList<>();
320 }
321 return defaultEventListeners;
322 }
323
292 * bug 251180 - Missing method org.eclipse.persistence.descriptors.DescriptorEventManager#setAboutToDeleteSelector
293 */
294 public String getAboutToDeleteSelector() {
295 return (String)getEventSelectors().elementAt(AboutToDeleteEvent);
296 }
297
298 /**
299 * INTERNAL:
300 */
301 public String getAboutToInsertSelector() {
302 return (String)getEventSelectors().elementAt(AboutToInsertEvent);
303 }
304
305 /**
306 * INTERNAL:
307 */
308 public String getAboutToUpdateSelector() {
309 return (String)getEventSelectors().elementAt(AboutToUpdateEvent);
310 }
311
312 /**
313 * INTERNAL:
314 * EJB 3.0 support. Returns the default listeners.
315 */
316 public Vector getDefaultEventListeners() {
317 if (defaultEventListeners == null) {
318 defaultEventListeners = new NonSynchronizedVector();
319 }
320
321 return defaultEventListeners;
322 }
323
324324 /**
325325 * INTERNAL:
326326 */
330330
331331 /**
332332 * INTERNAL:
333 * used by JPA project caching to store DescriptorEventListener representations that can build the underlying
334 * DescriptorEventListener and add it to the EventManager.
335 */
336 public List<SerializableDescriptorEventHolder> getDescriptorEventHolders() {
337 if (descriptorEventHolders == null) {
338 descriptorEventHolders = new CopyOnWriteArrayList<>();
339 }
340 return descriptorEventHolders;
341 }
342
343 /**
344 * INTERNAL:
345 * used by JPA project caching to store DescriptorEventListener representations that can build the underlying
346 * DescriptorEventListener and add it to the EventManager.
347 */
348 public void setDescriptorEventHolders(List<SerializableDescriptorEventHolder> descriptorEventHolders) {
349 this.descriptorEventHolders = descriptorEventHolders;
350 }
351
333 * used by JPA project caching to store DescriptorEventListener representations that can build the underlying
334 * DescriptorEventListener and add it to the EventManager.
335 */
336 public java.util.List<SerializableDescriptorEventHolder> getDescriptorEventHolders() {
337 if (descriptorEventHolders == null) {
338 descriptorEventHolders = new java.util.ArrayList();
339 }
340 return descriptorEventHolders;
341 }
342
343 /**
344 * INTERNAL:
345 * used by JPA project caching to store DescriptorEventListener representations that can build the underlying
346 * DescriptorEventListener and add it to the EventManager.
347 */
348 public void setDescriptorEventHolders(java.util.List<SerializableDescriptorEventHolder> descriptorEventHolders) {
349 this.descriptorEventHolders = descriptorEventHolders;
350 }
351
352352 /**
353353 * INTERNAL:
354354 * EJB 3.0 support. Returns the entity event listener.
358358 }
359359
360360 /**
361 * INTERNAL:
362 * EJB 3.0 support. Returns the entity listener event listeners.
363 */
364 public List<DescriptorEventListener> getEntityListenerEventListeners() {
365 if (entityListenerEventListeners == null) {
366 entityListenerEventListeners = new CopyOnWriteArrayList<>();
367 }
368 return entityListenerEventListeners;
369 }
370
361 * INTERNAL:
362 * EJB 3.0 support. Returns the entity listener event listeners.
363 */
364 public Vector getEntityListenerEventListeners() {
365 if (entityListenerEventListeners == null) {
366 entityListenerEventListeners = new Vector();
367 }
368
369 return entityListenerEventListeners;
370 }
371
371372 /**
372373 * PUBLIC:
373374 * Returns the Listener objects that have been added.
374 *
375 * @see #addListener(DescriptorEventListener)
376 */
377 public List<DescriptorEventListener> getEventListeners() {
378 // Lazy initialize to avoid unnecessary enumerations.
379 if (eventListeners == null) {
380 eventListeners = new CopyOnWriteArrayList<>();
381 }
382 return eventListeners;
383 }
384
385 protected AtomicReferenceArray<Method> getEventMethods() {
386 //Lazy Initialized to prevent Null Pointer exception after serialization
387 if (this.eventMethods == null) {
388 this.eventMethods = newAtomicReferenceArray(NumberOfEvents);
389 }
390 return eventMethods;
391 }
392
393 protected AtomicReferenceArray<String> getEventSelectors() {
394 if (this.eventSelectors == null) {
395 this.eventSelectors = newAtomicReferenceArray(NumberOfEvents);
396 }
397 return eventSelectors;
398 }
399
400 /**
401 * PUBLIC:
402 * The name of the method called after an object is built
403 */
404 public String getPostBuildSelector() {
405 return (String)getEventSelectors().get(PostBuildEvent);
406 }
407
408 /**
409 * PUBLIC:
410 * The name of the method called after an object is cloned
411 */
412 public String getPostCloneSelector() {
413 return (String)getEventSelectors().get(PostCloneEvent);
414 }
415
416 /**
417 * PUBLIC:
418 * The name of the method called after an object is deleted
419 */
420 public String getPostDeleteSelector() {
421 return (String)getEventSelectors().get(PostDeleteEvent);
422 }
423
424 /**
425 * PUBLIC:
426 * The name of the method called after an object is inserted
427 */
428 public String getPostInsertSelector() {
429 return (String)getEventSelectors().get(PostInsertEvent);
430 }
431
432 /**
433 * PUBLIC:
434 * The name of the method called after an object is merged
435 */
436 public String getPostMergeSelector() {
437 return (String)getEventSelectors().get(PostMergeEvent);
438 }
439
440 /**
441 * PUBLIC:
442 * The name of the method called after an object is refreshed
443 */
444 public String getPostRefreshSelector() {
445 return (String)getEventSelectors().get(PostRefreshEvent);
446 }
447
448 /**
449 * PUBLIC:
450 * The name of the method called after an object is updated
451 */
452 public String getPostUpdateSelector() {
453 return (String)getEventSelectors().get(PostUpdateEvent);
454 }
455
456 /**
457 * PUBLIC:
458 * The name of the method called after an object is written
459 */
460 public String getPostWriteSelector() {
461 return (String)getEventSelectors().get(PostWriteEvent);
462 }
463
464 /**
465 * PUBLIC:
466 * The name of the method called before the create operation is applied to an object
467 */
468 public String getPrePersistSelector() {
469 return (String)getEventSelectors().get(PrePersistEvent);
470 }
471
472 /**
473 * PUBLIC:
474 * The name of the method called before an object is deleted
475 */
476 public String getPreDeleteSelector() {
477 return (String)getEventSelectors().get(PreDeleteEvent);
478 }
479
480 /**
481 * PUBLIC:
482 * The name of the method called before an object is inserted
483 */
484 public String getPreInsertSelector() {
485 return (String)getEventSelectors().get(PreInsertEvent);
486 }
487
488 /**
489 * PUBLIC:
490 * The name of the method called before the remove operation is applied to an object
491 */
492 public String getPreRemoveSelector() {
493 return (String)getEventSelectors().get(PreRemoveEvent);
494 }
495
496 /**
497 * PUBLIC:
498 * The name of the method called before an object is updated
499 */
500 public String getPreUpdateSelector() {
501 return (String)getEventSelectors().get(PreUpdateEvent);
502 }
503
504 /**
505 * PUBLIC:
506 * The name of the method called before an object is written
507 */
508 public String getPreWriteSelector() {
509 return (String)getEventSelectors().get(PreWriteEvent);
510 }
511
512 /**
375 *
376 * @see #addListener(DescriptorEventListener)
377 */
378 public Vector getEventListeners() {
379 // Lazy initialize to avoid unnecessary enumerations.
380 if (eventListeners == null) {
381 eventListeners = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(1);
382 }
383 return eventListeners;
384 }
385
386 protected Vector getEventMethods() {
387 //Lazy Initialized to prevent Null Pointer exception after serialization
388 if (this.eventMethods == null) {
389 this.eventMethods = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(NumberOfEvents);
390 for (int index = 0; index < NumberOfEvents; ++index) {
391 this.eventMethods.addElement(null);
392 }
393 }
394 return eventMethods;
395 }
396
397 protected Vector getEventSelectors() {
398 if (this.eventSelectors == null) {
399 this.eventSelectors = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(NumberOfEvents);
400 for (int index = 0; index < NumberOfEvents; ++index) {
401 this.eventSelectors.addElement(null);
402 }
403 }
404 return eventSelectors;
405 }
406
407 /**
408 * PUBLIC:
409 * The name of the method called after an object is built
410 */
411 public String getPostBuildSelector() {
412 return (String)getEventSelectors().elementAt(PostBuildEvent);
413 }
414
415 /**
416 * PUBLIC:
417 * The name of the method called after an object is cloned
418 */
419 public String getPostCloneSelector() {
420 return (String)getEventSelectors().elementAt(PostCloneEvent);
421 }
422
423 /**
424 * PUBLIC:
425 * The name of the method called after an object is deleted
426 */
427 public String getPostDeleteSelector() {
428 return (String)getEventSelectors().elementAt(PostDeleteEvent);
429 }
430
431 /**
432 * PUBLIC:
433 * The name of the method called after an object is inserted
434 */
435 public String getPostInsertSelector() {
436 return (String)getEventSelectors().elementAt(PostInsertEvent);
437 }
438
439 /**
440 * PUBLIC:
441 * The name of the method called after an object is merged
442 */
443 public String getPostMergeSelector() {
444 return (String)getEventSelectors().elementAt(PostMergeEvent);
445 }
446
447 /**
448 * PUBLIC:
449 * The name of the method called after an object is refreshed
450 */
451 public String getPostRefreshSelector() {
452 return (String)getEventSelectors().elementAt(PostRefreshEvent);
453 }
454
455 /**
456 * PUBLIC:
457 * The name of the method called after an object is updated
458 */
459 public String getPostUpdateSelector() {
460 return (String)getEventSelectors().elementAt(PostUpdateEvent);
461 }
462
463 /**
464 * PUBLIC:
465 * The name of the method called after an object is written
466 */
467 public String getPostWriteSelector() {
468 return (String)getEventSelectors().elementAt(PostWriteEvent);
469 }
470
471 /**
472 * PUBLIC:
473 * The name of the method called before the create operation is applied to an object
474 */
475 public String getPrePersistSelector() {
476 return (String)getEventSelectors().elementAt(PrePersistEvent);
477 }
478
479 /**
480 * PUBLIC:
481 * The name of the method called before an object is deleted
482 */
483 public String getPreDeleteSelector() {
484 return (String)getEventSelectors().elementAt(PreDeleteEvent);
485 }
486
487 /**
488 * PUBLIC:
489 * The name of the method called before an object is inserted
490 */
491 public String getPreInsertSelector() {
492 return (String)getEventSelectors().elementAt(PreInsertEvent);
493 }
494
495 /**
496 * PUBLIC:
497 * The name of the method called before the remove operation is applied to an object
498 */
499 public String getPreRemoveSelector() {
500 return (String)getEventSelectors().elementAt(PreRemoveEvent);
501 }
502
503 /**
504 * PUBLIC:
505 * The name of the method called before an object is updated
506 */
507 public String getPreUpdateSelector() {
508 return (String)getEventSelectors().elementAt(PreUpdateEvent);
509 }
510
511 /**
512 * PUBLIC:
513 * The name of the method called before an object is written
514 */
515 public String getPreWriteSelector() {
516 return (String)getEventSelectors().elementAt(PreWriteEvent);
517 }
518
519 /**
513520 * INTERNAL:
514521 * Return if the event manager has any event listeners, or event methods.
515522 * If nothing is listening to event they can be avoided.
547554 /**
548555 * INTERNAL:
549556 * Internal event support. Return true if this event manager has any internal
550 * listener event listeners.
551 */
552 public boolean hasInternalEventListeners() {
553 return internalListeners != null && !internalListeners.isEmpty();
554 }
555
556 /**
557 * listener event listeners.
558 */
559 public boolean hasInternalEventListeners() {
560 return internalListeners != null && internalListeners.size() > 0;
561 }
562
563 /**
557564 * INTERNAL:
558565 * EJB 3.0 support. Return true if this event manager has any entity
559 * listener event listeners.
560 */
561 public boolean hasEntityListenerEventListeners() {
562 return entityListenerEventListeners != null && !entityListenerEventListeners.isEmpty();
563 }
564
565 /**
566 * listener event listeners.
567 */
568 public boolean hasEntityListenerEventListeners() {
569 return entityListenerEventListeners != null && entityListenerEventListeners.size() > 0;
570 }
571
572 /**
566573 * INTERNAL:
567574 * Configure inherited selectors.
568575 */
576583
577584 // Initialize if events are required at all.
578585 if (hasAnyListeners() || DescriptorEventListener.class.isAssignableFrom(getDescriptor().getJavaClass())) {
579 setHasAnyEventListeners(true);
580 }
581
582 final AtomicReferenceArray<String> selectors = getEventSelectors();
583 for (int index = 0; index < NumberOfEvents; index++) {
584 if (selectors.get(index) != null) {
585 setHasAnyEventListeners(true);
586 getEventMethods().set(index, findMethod(index));
587 }
588 }
589
586 setHasAnyEventListeners(true);
587 }
588
589 for (int index = 0; index < NumberOfEvents; index++) {
590 if (getEventSelectors().elementAt(index) != null) {
591 setHasAnyEventListeners(true);
592 getEventMethods().setElementAt(findMethod(index), index);
593 }
594 }
595
590596 // Inherit all parent defined event method
591597 // Do NOT inherit the listener as the events are broadcast to the parent.
592598 if (getDescriptor().isChildDescriptor()) {
593599 DescriptorEventManager parentEventManager = getDescriptor().getInheritancePolicy().getParentDescriptor().getEventManager();
594600 if (parentEventManager.hasAnyEventListeners()) {
595601 setHasAnyEventListeners(true);
596 }
597
598 for (int index = 0; index < NumberOfEvents; index++) {
599 if ((selectors.get(index) == null) && (parentEventManager.getEventSelectors().get(index) != null)) {
600 setHasAnyEventListeners(true);
601 selectors.set(index, parentEventManager.getEventSelectors().get(index));
602 getEventMethods().set(index, parentEventManager.getEventMethods().get(index));
603 }
604 }
602 }
603
604 for (int index = 0; index < NumberOfEvents; index++) {
605 if ((getEventSelectors().get(index) == null) && (parentEventManager.getEventSelectors().get(index) != null)) {
606 setHasAnyEventListeners(true);
607 getEventSelectors().set(index, parentEventManager.getEventSelectors().get(index));
608 getEventMethods().set(index, parentEventManager.getEventMethods().get(index));
609 }
610 }
605611 }
606612 }
607613
609615 * INTERNAL:
610616 * EJB 3.0 support. Builds our chains of descriptor event managers that will
611617 * need to be notified. The chains are cache so we only need to build them
612 * once.
613 */
614 protected void initializeEJB30EventManagers() {
615 entityEventManagers = new CopyOnWriteArrayList<>();
616 entityListenerEventManagers = new CopyOnWriteArrayList<>();
617
618 if (hasEntityEventListener()) {
619 entityEventManagers.add(this);
618 * once.
619 */
620 protected void initializeEJB30EventManagers() {
621 entityEventManagers = new NonSynchronizedVector();
622 entityListenerEventManagers = new NonSynchronizedVector();
623
624 if (hasEntityEventListener()) {
625 entityEventManagers.add(this);
620626 }
621627
622628 if (hasEntityListenerEventListeners()) {
657663 notifyListener(listener, event);
658664 }
659665 }
660
661 // Step 2 - Notify the Entity Listener's first, top -> down.
662 for (int index = entityListenerEventManagers.size() - 1; index >= 0; index--) {
663 List entityListenerEventListeners = ((DescriptorEventManager) entityListenerEventManagers.get(index)).getEntityListenerEventListeners();
664
665 for (int i = 0; i < entityListenerEventListeners.size(); i++) {
666 DescriptorEventListener listener = (DescriptorEventListener) entityListenerEventListeners.get(i);
666
667 // Step 2 - Notify the Entity Listener's first, top -> down.
668 for (int index = entityListenerEventManagers.size() - 1; index >= 0; index--) {
669 Vector entityListenerEventListeners = ((DescriptorEventManager) entityListenerEventManagers.get(index)).getEntityListenerEventListeners();
670
671 for (int i = 0; i < entityListenerEventListeners.size(); i++) {
672 DescriptorEventListener listener = (DescriptorEventListener) entityListenerEventListeners.get(i);
667673 notifyListener(listener, event);
668674 }
669675 }
670676
671 // Step 3 - Notify the Entity event listeners. top -> down, unless
672 // they are overridden in a subclass.
673 for (int index = entityEventManagers.size() - 1; index >= 0; index--) {
674 DescriptorEventListener entityEventListener = entityEventManagers.get(index).getEntityEventListener();
675
676 if (! entityEventListener.isOverriddenEvent(event, entityEventManagers)) {
677 notifyListener(entityEventListener, event);
677 // Step 3 - Notify the Entity event listeners. top -> down, unless
678 // they are overridden in a subclass.
679 for (int index = entityEventManagers.size() - 1; index >= 0; index--) {
680 DescriptorEventListener entityEventListener = ((DescriptorEventManager) entityEventManagers.get(index)).getEntityEventListener();
681
682 if (! entityEventListener.isOverriddenEvent(event, entityEventManagers)) {
683 notifyListener(entityEventListener, event);
678684 }
679685 }
680686
771777
772778 /**
773779 * INTERNAL:
774 * Used to initialize a remote DescriptorEventManager.
775 */
776 public void remoteInitialization(AbstractSession session) {
777 this.eventMethods = newAtomicReferenceArray(NumberOfEvents);
778 initialize(session);
779 }
780
781 /**
782 * PUBLIC:
783 * Remove a event listener.
784 */
785 public void removeListener(DescriptorEventListener listener) {
786 getEventListeners().remove(listener);
787 }
788
789 /**
780 * Used to initialize a remote DescriptorEventManager.
781 */
782 public void remoteInitialization(AbstractSession session) {
783 this.eventMethods = new Vector(NumberOfEvents);
784
785 for (int index = 0; index < NumberOfEvents; index++) {
786 this.eventMethods.addElement(null);
787 }
788
789 initialize(session);
790 }
791
792 /**
793 * PUBLIC:
794 * Remove a event listener.
795 */
796 public void removeListener(DescriptorEventListener listener) {
797 getEventListeners().removeElement(listener);
798 }
799
800 /**
790801 * PUBLIC:
791802 * A method can be registered to be called when an object's row it about to
792803 * be inserted. This uses the optional event argument of the DatabaseRow.
793804 * This is different from pre/postInsert because it occurs after the row has
794805 * already been built. This event can be used to modify the row before
795806 * insert, such as adding a user inserted by.
796 */
797 //bug 251180: Missing method org.eclipse.persistence.descriptors.DescriptorEventManager#setAboutToDeleteSelector
798 public void setAboutToDeleteSelector(String aboutToDeleteSelector) {
799 getEventSelectors().set(AboutToDeleteEvent, aboutToDeleteSelector);
800 }
801
802 /**
807 */
808 //bug 251180: Missing method org.eclipse.persistence.descriptors.DescriptorEventManager#setAboutToDeleteSelector
809 public void setAboutToDeleteSelector(String aboutToDeleteSelector) {
810 getEventSelectors().setElementAt(aboutToDeleteSelector, AboutToDeleteEvent);
811 }
812
813 /**
803814 * PUBLIC:
804815 * A method can be registered to be called when an object's row it about to
805816 * be inserted. This uses the optional event argument of the DatabaseRow.
806817 * This is different from pre/postInsert because it occurs after the row has
807818 * already been built. This event can be used to modify the row before
808 * insert, such as adding a user inserted by.
809 */
810 public void setAboutToInsertSelector(String aboutToInsertSelector) {
811 getEventSelectors().set(AboutToInsertEvent, aboutToInsertSelector);
812 }
813
814 /**
819 * insert, such as adding a user inserted by.
820 */
821 public void setAboutToInsertSelector(String aboutToInsertSelector) {
822 getEventSelectors().setElementAt(aboutToInsertSelector, AboutToInsertEvent);
823 }
824
825 /**
815826 * PUBLIC:
816827 * A method can be registered to be called when an object's row it about to
817828 * be updated. This uses the optional event argument of the DatabaseRow.
818829 * This is different from pre/postUpdate because it occurs after the row has
819830 * already been built, and it ONLY called if the update is required (changed
820831 * within a unit of work), as the other occur ALWAYS. This event can be used
821 * to modify the row before insert, such as adding a user inserted by.
822 */
823 public void setAboutToUpdateSelector(String aboutToUpdateSelector) {
824 getEventSelectors().set(AboutToUpdateEvent, aboutToUpdateSelector);
825 }
826
827 /**
832 * to modify the row before insert, such as adding a user inserted by.
833 */
834 public void setAboutToUpdateSelector(String aboutToUpdateSelector) {
835 getEventSelectors().setElementAt(aboutToUpdateSelector, AboutToUpdateEvent);
836 }
837
838 /**
828839 * INTERNAL:
829840 * Set the descriptor.
830841 */
837848 * EJB 3.0 support for lifecycle callback events defined on an entity class.
838849 */
839850 public void setEntityEventListener(DescriptorEventListener listener) {
840 this.entityEventListener = listener;
841 }
842
843 protected void setEventListeners(List<DescriptorEventListener> eventListeners) {
844 if (eventListeners instanceof CopyOnWriteArrayList) {
845 this.eventListeners = eventListeners;
846 } else {
847 this.eventListeners = new CopyOnWriteArrayList(eventListeners);
848 }
849 }
850
851 protected void setEventMethods(AtomicReferenceArray<Method> eventMethods) {
852 this.eventMethods = eventMethods;
853 }
854
855 protected void setEventSelectors(AtomicReferenceArray<String> eventSelectors) {
856 this.eventSelectors = eventSelectors;
857 }
858
859 /**
860 * INTERNAL:
861 * EJB 3.0 support. Default listeners apply to all entities in a persistence
851 this.entityEventListener = listener;
852 }
853
854 protected void setEventListeners(Vector eventListeners) {
855 this.eventListeners = eventListeners;
856 }
857
858 protected void setEventMethods(Vector eventMethods) {
859 this.eventMethods = eventMethods;
860 }
861
862 protected void setEventSelectors(Vector eventSelectors) {
863 this.eventSelectors = eventSelectors;
864 }
865
866 /**
867 * INTERNAL:
868 * EJB 3.0 support. Default listeners apply to all entities in a persistence
862869 * unit. Set this flag to true to exclude the invocation of the default
863870 * listeners for this descriptor.
864871 */
893900 * built from the database. This uses the optional event argument for the
894901 * DatabaseRow. This event can be used to correctly initialize an object's
895902 * non-persistent attributes or to perform complex optimizations or
896 * mappings. This event is called whenever an object is built.
897 */
898 public void setPostBuildSelector(String postBuildSelector) {
899 getEventSelectors().set(PostBuildEvent, postBuildSelector);
900 }
901
902 /**
903 * mappings. This event is called whenever an object is built.
904 */
905 public void setPostBuildSelector(String postBuildSelector) {
906 getEventSelectors().setElementAt(postBuildSelector, PostBuildEvent);
907 }
908
909 /**
903910 * PUBLIC:
904911 * A method can be registered to be called on a object that has just been
905912 * cloned into a unit of work. This uses the optional event argument for the
906913 * original object (the source object is the clone). This event can be used
907 * to correctly initialize an object's non-persistent attributes.
908 */
909 public void setPostCloneSelector(String postCloneSelector) {
910 getEventSelectors().set(PostCloneEvent, postCloneSelector);
911 }
912
913 /**
914 * to correctly initialize an object's non-persistent attributes.
915 */
916 public void setPostCloneSelector(String postCloneSelector) {
917 getEventSelectors().setElementAt(postCloneSelector, PostCloneEvent);
918 }
919
920 /**
914921 * PUBLIC:
915922 * A method can be registered to be called on a object that has just been
916923 * deleted from the database. This event can notify/remove any dependents
917 * on the object.
918 */
919 public void setPostDeleteSelector(String postDeleteSelector) {
920 getEventSelectors().set(PostDeleteEvent, postDeleteSelector);
921 }
922
923 /**
924 * on the object.
925 */
926 public void setPostDeleteSelector(String postDeleteSelector) {
927 getEventSelectors().setElementAt(postDeleteSelector, PostDeleteEvent);
928 }
929
930 /**
924931 * PUBLIC:
925932 * A method can be registered to be called on a object that has just been
926933 * inserted into the database. This event can be used to notify any
927934 * dependent on the object, or to update information not accessible until
928 * the object has been inserted.
929 */
930 public void setPostInsertSelector(String postInsertSelector) {
931 getEventSelectors().set(PostInsertEvent, postInsertSelector);
932 }
933
934 /**
935 * the object has been inserted.
936 */
937 public void setPostInsertSelector(String postInsertSelector) {
938 getEventSelectors().setElementAt(postInsertSelector, PostInsertEvent);
939 }
940
941 /**
935942 * PUBLIC:
936943 * A method can be registered to be called on a object that has just been
937944 * merge from a unit of work. This uses the optional event argument of the
938945 * original object which is the object being merged from, the source object
939946 * is the object being merged into. This event can be used to correctly
940 * initialize an object's non-persistent attributes.
941 */
942 public void setPostMergeSelector(String postMergeSelector) {
943 getEventSelectors().set(PostMergeEvent, postMergeSelector);
944 }
945
946 /**
947 * initialize an object's non-persistent attributes.
948 */
949 public void setPostMergeSelector(String postMergeSelector) {
950 getEventSelectors().setElementAt(postMergeSelector, PostMergeEvent);
951 }
952
953 /**
947954 * PUBLIC:
948955 * A method can be registered to be called on a object that has just been
949956 * refreshed from the database. This uses the optional event argument of
950957 * the DatabaseRow. This event can be used to correctly initialize an
951958 * object's non-persistent attributes or to perform complex optimizations or
952 * mappings. This event is only called on refreshes of existing objects.
953 */
954 public void setPostRefreshSelector(String postRefreshSelector) {
955 getEventSelectors().set(PostRefreshEvent, postRefreshSelector);
956 }
957
958 /**
959 * mappings. This event is only called on refreshes of existing objects.
960 */
961 public void setPostRefreshSelector(String postRefreshSelector) {
962 getEventSelectors().setElementAt(postRefreshSelector, PostRefreshEvent);
963 }
964
965 /**
959966 * PUBLIC:
960967 * A method can be registered to be called on a object that has just been
961 * updated into the database.
962 */
963 public void setPostUpdateSelector(String postUpdateSelector) {
964 getEventSelectors().set(PostUpdateEvent, postUpdateSelector);
965 }
966
967 /**
968 * updated into the database.
969 */
970 public void setPostUpdateSelector(String postUpdateSelector) {
971 getEventSelectors().setElementAt(postUpdateSelector, PostUpdateEvent);
972 }
973
974 /**
968975 * PUBLIC:
969976 * A method can be registered to be called on a object that has just been
970977 * written to the database. This event is raised on any registered object
972979 * "aboutToUpdate" selector if it is required for the event to be raised
973980 * only when the object has been changed. This will be called on all inserts
974981 * and updates, after the "postInsert/Update" event has been raised. This
975 * event can be used to notify any dependent on the object.
976 */
977 public void setPostWriteSelector(String postWriteSelector) {
978 getEventSelectors().set(PostWriteEvent, postWriteSelector);
979 }
980
981 /**
982 * event can be used to notify any dependent on the object.
983 */
984 public void setPostWriteSelector(String postWriteSelector) {
985 getEventSelectors().setElementAt(postWriteSelector, PostWriteEvent);
986 }
987
988 /**
982989 * PUBLIC:
983990 * A method can be registered to be called on a object that is going to be
984991 * deleted from the database. This event can notify/remove any dependents
985 * on the object.
986 */
987 public void setPreDeleteSelector(String preDeleteSelector) {
988 getEventSelectors().set(PreDeleteEvent, preDeleteSelector);
989 }
990
991 /**
992 * on the object.
993 */
994 public void setPreDeleteSelector(String preDeleteSelector) {
995 getEventSelectors().setElementAt(preDeleteSelector, PreDeleteEvent);
996 }
997
998 /**
992999 * PUBLIC:
9931000 * A method can be registered to be called on a object that is going to be
9941001 * inserted into the database. This event can be used to notify any
9951002 * dependent on the object or acquire the object's id through a custom
996 * mechanism.
997 */
998 public void setPreInsertSelector(String preInsertSelector) {
999 getEventSelectors().set(PreInsertEvent, preInsertSelector);
1000 }
1001
1002 /**
1003 * mechanism.
1004 */
1005 public void setPreInsertSelector(String preInsertSelector) {
1006 getEventSelectors().setElementAt(preInsertSelector, PreInsertEvent);
1007 }
1008
1009 /**
10031010 * PUBLIC:
10041011 * A method can be registered to be called on a object when that object has
1005 * the create operation applied to it.
1006 */
1007 public void setPrePersistSelector(String prePersistSelector) {
1008 getEventSelectors().set(PrePersistEvent, prePersistSelector);
1009 }
1010
1011 /**
1012 * the create operation applied to it.
1013 */
1014 public void setPrePersistSelector(String prePersistSelector) {
1015 getEventSelectors().setElementAt(prePersistSelector, PrePersistEvent);
1016 }
1017
1018 /**
10121019 * PUBLIC:
10131020 * A method can be registered to be called on a object when that object has
1014 * the remove operation applied to it.
1015 */
1016 public void setPreRemoveSelector(String preRemoveSelector) {
1017 getEventSelectors().set(PreRemoveEvent, preRemoveSelector);
1018 }
1019
1020 /**
1021 * the remove operation applied to it.
1022 */
1023 public void setPreRemoveSelector(String preRemoveSelector) {
1024 getEventSelectors().setElementAt(preRemoveSelector, PreRemoveEvent);
1025 }
1026
1027 /**
10211028 * PUBLIC:
10221029 * A method can be registered to be called on a object that is going to be
10231030 * updated into the database. This event is raised on any registered object
10241031 * in a unit of work, even if it has not changed, refer to the
10251032 * "aboutToUpdate" selector if it is required for the event to be raised
10261033 * only when the object has been changed. This event can be used to notify
1027 * any dependent on the object.
1028 */
1029 public void setPreUpdateSelector(String preUpdateSelector) {
1030 getEventSelectors().set(PreUpdateEvent, preUpdateSelector);
1031 }
1032
1033 /**
1034 * any dependent on the object.
1035 */
1036 public void setPreUpdateSelector(String preUpdateSelector) {
1037 getEventSelectors().setElementAt(preUpdateSelector, PreUpdateEvent);
1038 }
1039
1040 /**
10341041 * PUBLIC:
10351042 * A method can be registered to be called on a object that is going to be
10361043 * written to the database. This event is raised on any registered object
10381045 * "aboutToUpdate" selector if it is required for the event to be raised
10391046 * only when the object has been changed. This will be called on all inserts
10401047 * and updates, before the "preInsert/Update" event has been raised. This
1041 * event can be used to notify any dependent on the object.
1042 */
1043 public void setPreWriteSelector(String preWriteSelector) {
1044 getEventSelectors().set(PreWriteEvent, preWriteSelector);
1045 }
1046
1047 /**
1048 * Create an instance of {@link AtomicIntegerArray} initialized with {@code NullEvent} values.
1049 *
1050 * @param length length of the array.
1051 * @return initialized instance of {@link AtomicIntegerArray}
1052 */
1053 private static <T> AtomicReferenceArray<T> newAtomicReferenceArray(final int length) {
1054 final AtomicReferenceArray array = new AtomicReferenceArray<>(length);
1055 for (int index = 0; index < length; array.set(index++, null));
1056 return (AtomicReferenceArray<T>)array;
1057 }
1058
1059 /**
1060 * Create an instance of {@link AtomicIntegerArray} initialized with content of provided array.
1061 *
1062 * @param src source array.
1063 * @return initialized instance of {@link AtomicIntegerArray}
1064 */
1065 private static <T> AtomicReferenceArray<T> newAtomicReferenceArray(final AtomicReferenceArray<T> src) {
1066 final int length = src.length();
1067 final AtomicReferenceArray array = new AtomicReferenceArray<>(length);
1068 for (int index = 0; index < length; array.set(index, src.get(index++)));
1069 return (AtomicReferenceArray<T>)array;
1070 }
1071
1072 }
1048 * event can be used to notify any dependent on the object.
1049 */
1050 public void setPreWriteSelector(String preWriteSelector) {
1051 getEventSelectors().setElementAt(preWriteSelector, PreWriteEvent);
1052 }
1053 }
0 /*******************************************************************************
1 * Copyright (c) 1998, 2014 Oracle and/or its affiliates. All rights reserved.
2 * This program and the accompanying materials are made available under the
3 * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
4 * which accompanies this distribution.
5 * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
6 * and the Eclipse Distribution License is available at
7 * http://www.eclipse.org/org/documents/edl-v10.php.
8 *
9 * Contributors:
10 * Oracle - initial API and implementation from Oracle TopLink
11 ******************************************************************************/
12 package org.eclipse.persistence.descriptors.changetracking;
13
14 import java.beans.PropertyChangeListener;
15
16 import java.util.*;
17 import org.eclipse.persistence.internal.sessions.ObjectChangeSet;
18 import org.eclipse.persistence.queries.*;
19 import org.eclipse.persistence.internal.descriptors.*;
20 import org.eclipse.persistence.internal.descriptors.changetracking.ObjectChangeListener;
21 import org.eclipse.persistence.internal.sessions.MergeManager;
22 import org.eclipse.persistence.descriptors.ClassDescriptor;
23 import org.eclipse.persistence.mappings.*;
24 import org.eclipse.persistence.descriptors.DescriptorEvent;
25 import org.eclipse.persistence.descriptors.DescriptorEventManager;
26 import org.eclipse.persistence.exceptions.ValidationException;
27 import org.eclipse.persistence.internal.sessions.AbstractSession;
28 import org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork;
29 import org.eclipse.persistence.internal.sessions.UnitOfWorkChangeSet;
30 import org.eclipse.persistence.internal.sessions.UnitOfWorkImpl;
31
32 /**
33 * PUBLIC:
34 * A DeferredChangeDetectionPolicy defers all change detection to the UnitOfWork's
35 * change detection process. Essentially, the calculateChanges() method will run
36 * for all objects in a UnitOfWork. This is the default ObjectChangePolicy unless weaving is used.
37 *
38 * @author Tom Ware
39 */
40 public class DeferredChangeDetectionPolicy implements ObjectChangePolicy, java.io.Serializable {
41
42 /**
43 * INTERNAL:
44 * PERF: Calculate change for the new object, avoids check for new since already know.
45 */
46 public ObjectChangeSet calculateChangesForNewObject(Object clone, UnitOfWorkChangeSet changeSet, UnitOfWorkImpl unitOfWork, ClassDescriptor descriptor, boolean shouldRaiseEvent) {
47 return calculateChanges(clone, null, true, changeSet, unitOfWork, descriptor, shouldRaiseEvent);
48 }
49
50 /**
51 * INTERNAL:
52 * PERF: Calculate change for the new object, avoids check for new since already know.
53 */
54 public ObjectChangeSet calculateChangesForExistingObject(Object clone, UnitOfWorkChangeSet changeSet, UnitOfWorkImpl unitOfWork, ClassDescriptor descriptor, boolean shouldRaiseEvent) {
55 return calculateChanges(clone, unitOfWork.getBackupClone(clone, descriptor), false, changeSet, unitOfWork, descriptor, shouldRaiseEvent);
56 }
57
58 /**
59 * INTERNAL:
60 * calculateChanges creates a change set for a particular object. In DeferredChangeDetectionPolicy
61 * all mappings will be compared against a backup copy of the object.
62 * @return an object change set describing
63 * the changes to this object
64 * @param clone the Object to compute a change set for
65 * @param backUp the old version of the object to use for comparison
66 * @param changeSet the change set to add changes to
0 /*******************************************************************************
1 * Copyright (c) 1998, 2019 Oracle and/or its affiliates. All rights reserved.
2 * This program and the accompanying materials are made available under the
3 * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
4 * which accompanies this distribution.
5 * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
6 * and the Eclipse Distribution License is available at
7 * http://www.eclipse.org/org/documents/edl-v10.php.
8 *
9 * Contributors:
10 * Oracle - initial API and implementation from Oracle TopLink
11 ******************************************************************************/
12 package org.eclipse.persistence.descriptors.changetracking;
13
14 import java.beans.PropertyChangeListener;
15 import java.util.List;
16 import java.util.Map;
17
18 import org.eclipse.persistence.descriptors.ClassDescriptor;
19 import org.eclipse.persistence.descriptors.DescriptorEvent;
20 import org.eclipse.persistence.descriptors.DescriptorEventManager;
21 import org.eclipse.persistence.exceptions.ValidationException;
22 import org.eclipse.persistence.internal.descriptors.ObjectBuilder;
23 import org.eclipse.persistence.internal.descriptors.changetracking.ObjectChangeListener;
24 import org.eclipse.persistence.internal.sessions.AbstractSession;
25 import org.eclipse.persistence.internal.sessions.MergeManager;
26 import org.eclipse.persistence.internal.sessions.ObjectChangeSet;
27 import org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork;
28 import org.eclipse.persistence.internal.sessions.UnitOfWorkChangeSet;
29 import org.eclipse.persistence.internal.sessions.UnitOfWorkImpl;
30 import org.eclipse.persistence.mappings.DatabaseMapping;
31 import org.eclipse.persistence.mappings.ForeignReferenceMapping;
32 import org.eclipse.persistence.queries.FetchGroup;
33 import org.eclipse.persistence.queries.WriteObjectQuery;
34
35 /**
36 * PUBLIC:
37 * A DeferredChangeDetectionPolicy defers all change detection to the UnitOfWork's
38 * change detection process. Essentially, the calculateChanges() method will run
39 * for all objects in a UnitOfWork. This is the default ObjectChangePolicy unless weaving is used.
40 *
41 * @author Tom Ware
42 */
43 public class DeferredChangeDetectionPolicy implements ObjectChangePolicy, java.io.Serializable {
44
45 /**
46 * INTERNAL:
47 * PERF: Calculate change for the new object, avoids check for new since already know.
48 */
49 @Override
50 public ObjectChangeSet calculateChangesForNewObject(Object clone, UnitOfWorkChangeSet changeSet, UnitOfWorkImpl unitOfWork, ClassDescriptor descriptor, boolean shouldRaiseEvent) {
51 return calculateChanges(clone, null, true, changeSet, unitOfWork, descriptor, shouldRaiseEvent);
52 }
53
54 /**
55 * INTERNAL:
56 * PERF: Calculate change for the new object, avoids check for new since already know.
57 */
58 @Override
59 public ObjectChangeSet calculateChangesForExistingObject(Object clone, UnitOfWorkChangeSet changeSet, UnitOfWorkImpl unitOfWork, ClassDescriptor descriptor, boolean shouldRaiseEvent) {
60 return calculateChanges(clone, unitOfWork.getBackupClone(clone, descriptor), false, changeSet, unitOfWork, descriptor, shouldRaiseEvent);
61 }
62
63 /**
64 * INTERNAL:
65 * calculateChanges creates a change set for a particular object. In DeferredChangeDetectionPolicy
66 * all mappings will be compared against a backup copy of the object.
67 * @return an object change set describing
68 * the changes to this object
69 * @param clone the Object to compute a change set for
70 * @param backUp the old version of the object to use for comparison
71 * @param changeSet the change set to add changes to
6772 * @param unitOfWork the current session
68 * @param descriptor the descriptor for this object
69 * @param shouldRaiseEvent indicates whether PreUpdate event should be risen (usually true)
70 */
71 public ObjectChangeSet calculateChanges(Object clone, Object backUp, boolean isNew, UnitOfWorkChangeSet changeSet, UnitOfWorkImpl unitOfWork, ClassDescriptor descriptor, boolean shouldRaiseEvent) {
72 // PERF: Avoid events if no listeners.
73 if (descriptor.getEventManager().hasAnyEventListeners() && shouldRaiseEvent) {
74 // The query is built for compatibility to old event mechanism.
75 WriteObjectQuery writeQuery = new WriteObjectQuery(clone.getClass());
76 writeQuery.setObject(clone);
77 writeQuery.setBackupClone(backUp);
78 writeQuery.setSession(unitOfWork);
79 writeQuery.setDescriptor(descriptor);
80
81 descriptor.getEventManager().executeEvent(new DescriptorEvent(DescriptorEventManager.PreWriteEvent, writeQuery));
82
83 if (isNew) {
84 descriptor.getEventManager().executeEvent(new DescriptorEvent(DescriptorEventManager.PreInsertEvent, writeQuery));
85 } else {
86 descriptor.getEventManager().executeEvent(new DescriptorEvent(DescriptorEventManager.PreUpdateEvent, writeQuery));
87 }
88 }
89
90 ObjectChangeSet changes = createObjectChangeSet(clone, backUp, changeSet, isNew, unitOfWork, descriptor);
91 if(changes.hasChanges() && descriptor.hasMappingsPostCalculateChanges() && ! changes.isNew() && ! unitOfWork.getCommitManager().isActive() && !unitOfWork.isNestedUnitOfWork()) {
92 // if we are in the commit because of an event skip this postCalculateChanges step as we have already executed it.
93 int size = descriptor.getMappingsPostCalculateChanges().size();
94 for(int i=0; i < size; i++) {
95 DatabaseMapping mapping = descriptor.getMappingsPostCalculateChanges().get(i);
96 org.eclipse.persistence.sessions.changesets.ChangeRecord record = changes.getChangesForAttributeNamed(mapping.getAttributeName());
97 if(record != null) {
98 // Deferred attributes will already have been acted on, therefore we need
99 // to post calculate changes to ensure orphaned objects are removed.
100 mapping.postCalculateChanges(record, unitOfWork);
101 }
102 }
103 }
104 //Check if the user set the PK to null and throw an exception (bug# 4569755)
105 if (changes.getId() == null && !isNew && !changes.isAggregate()) {
106 if(!(unitOfWork.isNestedUnitOfWork()) || (unitOfWork.isNestedUnitOfWork() && !(unitOfWork.isNewObjectInParent(clone)|| unitOfWork.isUnregisteredNewObjectInParent(unitOfWork.getCloneToOriginals().get(clone))))) {
107 Object id = descriptor.getObjectBuilder().extractPrimaryKeyFromObject(clone, unitOfWork, false);
108 throw ValidationException.nullPrimaryKeyInUnitOfWorkClone(clone, id);
109 }
110 }
111
112 // if forceUpdate or optimistic read locking is on, mark changeSet. This is to force it
113 // to be stored and used for writing out SQL later on
114 if ((descriptor.getCMPPolicy() != null) && (descriptor.getCMPPolicy().getForceUpdate())) {
115 changes.setHasCmpPolicyForcedUpdate(true);
116 }
117 if (!changes.hasForcedChangesFromCascadeLocking() && unitOfWork.hasOptimisticReadLockObjects()) {
118 Boolean modifyVersionField = (Boolean)unitOfWork.getOptimisticReadLockObjects().get(clone);
119 if ((modifyVersionField != null) && (unitOfWork instanceof RepeatableWriteUnitOfWork) && (((RepeatableWriteUnitOfWork)unitOfWork).getCumulativeUOWChangeSet() != null)) {
120 // modify the version field if the UOW cumulative change set does not contain a changeset for this clone
121 if (((RepeatableWriteUnitOfWork)unitOfWork).getCumulativeUOWChangeSet().getObjectChangeSetForClone(clone) == null) {
122 modifyVersionField = Boolean.TRUE;
123 }
124 }
125 changes.setShouldModifyVersionField(modifyVersionField);
126 }
127 if (changes.hasChanges() || changes.hasForcedChanges()) {
128 return changes;
129 }
130 return null;
131 }
132
133 /**
134 * INTERNAL:
135 * This is a place holder for reseting the listener on one of the subclasses
136 */
137 public void clearChanges(Object object, UnitOfWorkImpl uow, ClassDescriptor descriptor, boolean forRefresh) {
138 }
139
140 /**
141 * INTERNAL:
142 * Create ObjectChangeSet
143 */
144 public ObjectChangeSet createObjectChangeSet(Object clone, Object backUp, org.eclipse.persistence.internal.sessions.UnitOfWorkChangeSet changeSet, boolean isNew, AbstractSession session, ClassDescriptor descriptor) {
145 return this.createObjectChangeSetThroughComparison(clone, backUp, changeSet, isNew, session, descriptor);
146 }
147
148 /**
149 * INTERNAL:
150 * Create ObjectChangeSet
151 */
152 public ObjectChangeSet createObjectChangeSetThroughComparison(Object clone, Object backUp, org.eclipse.persistence.internal.sessions.UnitOfWorkChangeSet changeSet, boolean isNew, AbstractSession session, ClassDescriptor descriptor) {
153 ObjectBuilder builder = descriptor.getObjectBuilder();
154 ObjectChangeSet changes = builder.createObjectChangeSet(clone, changeSet, isNew, true, session);
155
156 // The following code deals with reads that force changes to the flag associated with optimistic locking.
157 FetchGroup fetchGroup = null;
158 // The flag indicates whether should get fetch group - to avoid doing
159 // that twice. Useful because fetchGroup may be null.
160 boolean shouldGetFetchGroup = true;
161 if ((descriptor.usesOptimisticLocking()) && (changes.getId() != null)) {
162 if (descriptor.hasFetchGroupManager()) {
163 fetchGroup = descriptor.getFetchGroupManager().getObjectFetchGroup(clone);
164 }
165
166 if (fetchGroup == null || fetchGroup != descriptor.getFetchGroupManager().getIdEntityFetchGroup()) {
167 changes.setOptimisticLockingPolicyAndInitialWriteLockValue(descriptor.getOptimisticLockingPolicy(), session);
168 }
169
170 // already tried to get the fetch group - no need to do that again.
171 shouldGetFetchGroup = false;
172 }
173
174 // PERF: Do not create change records for new objects.
175 if (!isNew || descriptor.shouldUseFullChangeSetsForNewObjects() || descriptor.isDescriptorTypeAggregate()) {
176 // PERF: Avoid synchronized enumerator as is concurrency bottleneck.
177 List mappings = descriptor.getMappings();
178 int mappingsSize = mappings.size();
179 if(shouldGetFetchGroup && descriptor.hasFetchGroupManager()) {
180 fetchGroup = descriptor.getFetchGroupManager().getObjectFetchGroup(clone);
181 }
182 for (int index = 0; index < mappingsSize; index++) {
183 DatabaseMapping mapping = (DatabaseMapping)mappings.get(index);
184 if ((fetchGroup == null) || fetchGroup.containsAttributeInternal(mapping.getAttributeName())) {
185 changes.addChange(mapping.compareForChange(clone, backUp, changes, session));
186 }
187 }
188 }
189
190 return changes;
191 }
192
193 /**
194 * INTERNAL:
195 * This method is used to disable changetracking temporarily
196 */
197 public void dissableEventProcessing(Object changeTracker){
198 //no-op
199 }
200
201 /**
202 * INTERNAL:
203 * This method is used to enable changetracking temporarily
204 */
205 public void enableEventProcessing(Object changeTracker){
206 //no-op
207 }
208
209 /**
210 * INTERNAL:
211 * Return true if the Object should be compared, false otherwise. In DeferredChangeDetectionPolicy,
212 * true is always returned since always allow the UnitOfWork to calculate changes.
213 * @param object the object that will be compared
214 * @param unitOfWork the active unitOfWork
215 * @param descriptor the descriptor for the current object
216 */
217 public boolean shouldCompareExistingObjectForChange(Object object, UnitOfWorkImpl unitOfWork, ClassDescriptor descriptor) {
218 return true;
219 }
220
221 /**
222 * INTERNAL:
223 * Build back up clone. Used if clone is new because listener should not be set.
224 */
225 public Object buildBackupClone(Object clone, ObjectBuilder builder, UnitOfWorkImpl uow) {
226 return builder.buildBackupClone(clone, uow);
227 }
228
229 /**
230 * INTERNAL:
231 * Assign ChangeListener to an aggregate object
232 */
233 public void setAggregateChangeListener(Object parent, Object aggregate, UnitOfWorkImpl uow, ClassDescriptor descriptor, String mappingAttribute){
234 //no-op
235 }
236
237 /**
238 * INTERNAL:
239 * Set ChangeListener for the clone
240 */
241 public PropertyChangeListener setChangeListener(Object clone, UnitOfWorkImpl uow, ClassDescriptor descriptor) {
242 return null;
243 }
244
245 /**
246 * INTERNAL:
247 * Set the ObjectChangeSet on the Listener, initially used for aggregate support
248 */
249 public void setChangeSetOnListener(ObjectChangeSet objectChangeSet, Object clone){
250 //no-op
251 }
252
253 /**
254 * INTERNAL:
255 * Clear changes in the ChangeListener of the clone
256 */
257 public void updateWithChanges(Object clone, ObjectChangeSet objectChangeSet, UnitOfWorkImpl uow, ClassDescriptor descriptor) {
258 if (objectChangeSet == null) {
259 return;
260 }
261 Object backupClone = uow.getCloneMapping().get(clone);
262 if (backupClone != null) {
263 // If new just re-build the backup clone, otherwise use MergeManager (should be a special merge though, not the default constructor like it is...)
264 if (objectChangeSet.isNew()) {
265 uow.getCloneMapping().put(clone, descriptor.getObjectBuilder().buildBackupClone(clone, uow));
266 } else {
267 MergeManager mergeManager = new MergeManager(uow);
268 mergeManager.setCascadePolicy(MergeManager.NO_CASCADE);
269 descriptor.getObjectBuilder().mergeChangesIntoObject(backupClone, objectChangeSet, clone, mergeManager, mergeManager.getSession());
270 }
271 }
272 clearChanges(clone, uow, descriptor, false);
273 }
274
275 /**
276 * INTERNAL:
277 * This may cause a property change event to be raised to a listener in the case that a listener exists.
278 * If there is no listener then this call is a no-op
279 */
280 public void raiseInternalPropertyChangeEvent(Object source, String propertyName, Object oldValue, Object newValue){
281 //no-op
282 }
283
284 /**
285 * INTERNAL:
286 * This method is used to revert an object within the unit of work
287 * @param cloneMapping may not be the same as what is in the uow
288 */
289 public void revertChanges(Object clone, ClassDescriptor descriptor, UnitOfWorkImpl uow, Map cloneMapping, boolean forRefresh) {
290 cloneMapping.put(clone, buildBackupClone(clone, descriptor.getObjectBuilder(), uow));
291 clearChanges(clone, uow, descriptor, forRefresh);
292 }
293
294 /**
295 * INTERNAL:
296 * initialize the Policy
297 */
298 public void initialize(AbstractSession session, ClassDescriptor descriptor) {
299 //do nothing
300 }
301
302 /**
303 * Used to track instances of the change policies without doing an instance of check
304 */
305 public boolean isDeferredChangeDetectionPolicy(){
306 return true;
307 }
308
309 /**
310 * Used to track instances of the change policies without doing an instance of check
311 */
312 public boolean isObjectChangeTrackingPolicy(){
313 return false;
314 }
315
316 /**
317 * Used to track instances of the change policies without doing an instance of check
318 */
319 public boolean isAttributeChangeTrackingPolicy(){
320 return false;
321 }
322
323 /**
324 * INTERNAL:
325 * In cases where a relationship with detached or new entities is merged into itself previous changes may have been recorded for
326 * the detached/new entity that need to be updated.
327 */
328 public void updateListenerForSelfMerge(ObjectChangeListener listener, ForeignReferenceMapping mapping, Object source, Object target, UnitOfWorkImpl unitOfWork) {
329 //not applicable for this change detection type.
330 }
331 }
73 * @param descriptor the descriptor for this object
74 * @param shouldRaiseEvent indicates whether PreUpdate event should be risen (usually true)
75 */
76 @Override
77 public ObjectChangeSet calculateChanges(Object clone, Object backUp, boolean isNew, UnitOfWorkChangeSet changeSet, UnitOfWorkImpl unitOfWork, ClassDescriptor descriptor, boolean shouldRaiseEvent) {
78 // PERF: Avoid events if no listeners.
79 if (descriptor.getEventManager().hasAnyEventListeners() && shouldRaiseEvent) {
80 // The query is built for compatibility to old event mechanism.
81 WriteObjectQuery writeQuery = new WriteObjectQuery(clone.getClass());
82 writeQuery.setObject(clone);
83 writeQuery.setBackupClone(backUp);
84 writeQuery.setSession(unitOfWork);
85 writeQuery.setDescriptor(descriptor);
86
87 descriptor.getEventManager().executeEvent(new DescriptorEvent(DescriptorEventManager.PreWriteEvent, writeQuery));
88
89 if (isNew) {
90 descriptor.getEventManager().executeEvent(new DescriptorEvent(DescriptorEventManager.PreInsertEvent, writeQuery));
91 } else {
92 descriptor.getEventManager().executeEvent(new DescriptorEvent(DescriptorEventManager.PreUpdateEvent, writeQuery));
93 }
94 }
95
96 ObjectChangeSet changes = createObjectChangeSet(clone, backUp, changeSet, isNew, unitOfWork, descriptor);
97 if(changes.hasChanges() && descriptor.hasMappingsPostCalculateChanges() && ! changes.isNew() && ! unitOfWork.getCommitManager().isActive() && !unitOfWork.isNestedUnitOfWork()) {
98 // if we are in the commit because of an event skip this postCalculateChanges step as we have already executed it.
99 int size = descriptor.getMappingsPostCalculateChanges().size();
100 for(int i=0; i < size; i++) {
101 DatabaseMapping mapping = descriptor.getMappingsPostCalculateChanges().get(i);
102 org.eclipse.persistence.sessions.changesets.ChangeRecord record = changes.getChangesForAttributeNamed(mapping.getAttributeName());
103 if(record != null) {
104 // Deferred attributes will already have been acted on, therefore we need
105 // to post calculate changes to ensure orphaned objects are removed.
106 mapping.postCalculateChanges(record, unitOfWork);
107 }
108 }
109 }
110 //Check if the user set the PK to null and throw an exception (bug# 4569755)
111 if (changes.getId() == null && !isNew && !changes.isAggregate()) {
112 if(!(unitOfWork.isNestedUnitOfWork()) || (unitOfWork.isNestedUnitOfWork() && !(unitOfWork.isNewObjectInParent(clone)|| unitOfWork.isUnregisteredNewObjectInParent(unitOfWork.getCloneToOriginals().get(clone))))) {
113 Object id = descriptor.getObjectBuilder().extractPrimaryKeyFromObject(clone, unitOfWork, false);
114 throw ValidationException.nullPrimaryKeyInUnitOfWorkClone(clone, id);
115 }
116 }
117
118 // if forceUpdate or optimistic read locking is on, mark changeSet. This is to force it
119 // to be stored and used for writing out SQL later on
120 if ((descriptor.getCMPPolicy() != null) && (descriptor.getCMPPolicy().getForceUpdate())) {
121 changes.setHasCmpPolicyForcedUpdate(true);
122 }
123 if (!changes.hasForcedChangesFromCascadeLocking() && unitOfWork.hasOptimisticReadLockObjects()) {
124 Boolean modifyVersionField = (Boolean)unitOfWork.getOptimisticReadLockObjects().get(clone);
125 if ((modifyVersionField != null) && (unitOfWork instanceof RepeatableWriteUnitOfWork) && (((RepeatableWriteUnitOfWork)unitOfWork).getCumulativeUOWChangeSet() != null)) {
126 // modify the version field if the UOW cumulative change set does not contain a changeset for this clone
127 if (((RepeatableWriteUnitOfWork)unitOfWork).getCumulativeUOWChangeSet().getObjectChangeSetForClone(clone) == null) {
128 modifyVersionField = Boolean.TRUE;
129 }
130 }
131 changes.setShouldModifyVersionField(modifyVersionField);
132 }
133 if (changes.hasChanges() || changes.hasForcedChanges()) {
134 return changes;
135 }
136 return null;
137 }
138
139 /**
140 * INTERNAL:
141 * This is a place holder for reseting the listener on one of the subclasses
142 */
143 @Override
144 public void clearChanges(Object object, UnitOfWorkImpl uow, ClassDescriptor descriptor, boolean forRefresh) {
145 }
146
147 /**
148 * INTERNAL:
149 * Create ObjectChangeSet
150 */
151 public ObjectChangeSet createObjectChangeSet(Object clone, Object backUp, org.eclipse.persistence.internal.sessions.UnitOfWorkChangeSet changeSet, boolean isNew, AbstractSession session, ClassDescriptor descriptor) {
152 return this.createObjectChangeSetThroughComparison(clone, backUp, changeSet, isNew, session, descriptor);
153 }
154
155 /**
156 * INTERNAL:
157 * Create ObjectChangeSet
158 */
159 @Override
160 public ObjectChangeSet createObjectChangeSetThroughComparison(Object clone, Object backUp, org.eclipse.persistence.internal.sessions.UnitOfWorkChangeSet changeSet, boolean isNew, AbstractSession session, ClassDescriptor descriptor) {
161 ObjectBuilder builder = descriptor.getObjectBuilder();
162 ObjectChangeSet changes = builder.createObjectChangeSet(clone, changeSet, isNew, true, session);
163
164 // The following code deals with reads that force changes to the flag associated with optimistic locking.
165 FetchGroup fetchGroup = null;
166 // The flag indicates whether should get fetch group - to avoid doing
167 // that twice. Useful because fetchGroup may be null.
168 boolean shouldGetFetchGroup = true;
169 if ((descriptor.usesOptimisticLocking()) && (changes.getId() != null)) {
170 if (descriptor.hasFetchGroupManager()) {
171 fetchGroup = descriptor.getFetchGroupManager().getObjectFetchGroup(clone);
172 }
173
174 if (fetchGroup == null || fetchGroup != descriptor.getFetchGroupManager().getIdEntityFetchGroup()) {
175 changes.setOptimisticLockingPolicyAndInitialWriteLockValue(descriptor.getOptimisticLockingPolicy(), session);
176 }
177
178 // already tried to get the fetch group - no need to do that again.
179 shouldGetFetchGroup = false;
180 }
181
182 // PERF: Do not create change records for new objects.
183 if (!isNew || descriptor.shouldUseFullChangeSetsForNewObjects() || descriptor.isDescriptorTypeAggregate()) {
184 // PERF: Avoid synchronized enumerator as is concurrency bottleneck.
185 List mappings = descriptor.getMappings();
186 int mappingsSize = mappings.size();
187 if(shouldGetFetchGroup && descriptor.hasFetchGroupManager()) {
188 fetchGroup = descriptor.getFetchGroupManager().getObjectFetchGroup(clone);
189 }
190 for (int index = 0; index < mappingsSize; index++) {
191 DatabaseMapping mapping = (DatabaseMapping)mappings.get(index);
192 if ((fetchGroup == null) || fetchGroup.containsAttributeInternal(mapping.getAttributeName())) {
193 changes.addChange(mapping.compareForChange(clone, backUp, changes, session));
194 }
195 }
196 }
197
198 return changes;
199 }
200
201 /**
202 * INTERNAL:
203 * This method is used to disable changetracking temporarily
204 */
205 @Override
206 public void dissableEventProcessing(Object changeTracker){
207 //no-op
208 }
209
210 /**
211 * INTERNAL:
212 * This method is used to enable changetracking temporarily
213 */
214 @Override
215 public void enableEventProcessing(Object changeTracker){
216 //no-op
217 }
218
219 /**
220 * INTERNAL:
221 * Return true if the Object should be compared, false otherwise. In DeferredChangeDetectionPolicy,
222 * true is always returned since always allow the UnitOfWork to calculate changes.
223 * @param object the object that will be compared
224 * @param unitOfWork the active unitOfWork
225 * @param descriptor the descriptor for the current object
226 */
227 @Override
228 public boolean shouldCompareExistingObjectForChange(Object object, UnitOfWorkImpl unitOfWork, ClassDescriptor descriptor) {
229 return true;
230 }
231
232 /**
233 * INTERNAL:
234 * Build back up clone. Used if clone is new because listener should not be set.
235 */
236 @Override
237 public Object buildBackupClone(Object clone, ObjectBuilder builder, UnitOfWorkImpl uow) {
238 return builder.buildBackupClone(clone, uow);
239 }
240
241 /**
242 * INTERNAL:
243 * Assign ChangeListener to an aggregate object
244 */
245 @Override
246 public void setAggregateChangeListener(Object parent, Object aggregate, UnitOfWorkImpl uow, ClassDescriptor descriptor, String mappingAttribute){
247 //no-op
248 }
249
250 /**
251 * INTERNAL:
252 * Set ChangeListener for the clone
253 */
254 @Override
255 public PropertyChangeListener setChangeListener(Object clone, UnitOfWorkImpl uow, ClassDescriptor descriptor) {
256 return null;
257 }
258
259 /**
260 * INTERNAL:
261 * Set the ObjectChangeSet on the Listener, initially used for aggregate support
262 */
263 @Override
264 public void setChangeSetOnListener(ObjectChangeSet objectChangeSet, Object clone){
265 //no-op
266 }
267
268 /**
269 * INTERNAL:
270 * Clear changes in the ChangeListener of the clone
271 */
272 @Override
273 public void updateWithChanges(Object clone, ObjectChangeSet objectChangeSet, UnitOfWorkImpl uow, ClassDescriptor descriptor) {
274 if (objectChangeSet == null) {
275 return;
276 }
277 Object backupClone = uow.getCloneMapping().get(clone);
278 if (backupClone != null) {
279 // If new just re-build the backup clone, otherwise use MergeManager (should be a special merge though, not the default constructor like it is...)
280 if (objectChangeSet.isNew()) {
281 uow.getCloneMapping().put(clone, descriptor.getObjectBuilder().buildBackupClone(clone, uow));
282 } else {
283 MergeManager mergeManager = new MergeManager(uow);
284 mergeManager.setCascadePolicy(MergeManager.NO_CASCADE);
285 descriptor.getObjectBuilder().mergeChangesIntoObject(backupClone, objectChangeSet, clone, mergeManager, mergeManager.getSession());
286 }
287 }
288 clearChanges(clone, uow, descriptor, false);
289 }
290
291 /**
292 * INTERNAL:
293 * This may cause a property change event to be raised to a listener in the case that a listener exists.
294 * If there is no listener then this call is a no-op
295 */
296 @Override
297 public void raiseInternalPropertyChangeEvent(Object source, String propertyName, Object oldValue, Object newValue){
298 //no-op
299 }
300
301 /**
302 * INTERNAL:
303 * This method is used to revert an object within the unit of work
304 * @param cloneMapping may not be the same as what is in the uow
305 */
306 @Override
307 public void revertChanges(Object clone, ClassDescriptor descriptor, UnitOfWorkImpl uow, Map cloneMapping, boolean forRefresh) {
308 cloneMapping.put(clone, buildBackupClone(clone, descriptor.getObjectBuilder(), uow));
309 clearChanges(clone, uow, descriptor, forRefresh);
310 }
311
312 /**
313 * INTERNAL:
314 * initialize the Policy
315 */
316 @Override
317 public void initialize(AbstractSession session, ClassDescriptor descriptor) {
318 //do nothing
319 }
320
321 /**
322 * Used to track instances of the change policies without doing an instance of check
323 */
324 @Override
325 public boolean isDeferredChangeDetectionPolicy(){
326 return true;
327 }
328
329 /**
330 * Used to track instances of the change policies without doing an instance of check
331 */
332 @Override
333 public boolean isObjectChangeTrackingPolicy(){
334 return false;
335 }
336
337 /**
338 * Used to track instances of the change policies without doing an instance of check
339 */
340 @Override
341 public boolean isAttributeChangeTrackingPolicy(){
342 return false;
343 }
344
345 /**
346 * INTERNAL:
347 * In cases where a relationship with detached or new entities is merged into itself previous changes may have been recorded for
348 * the detached/new entity that need to be updated.
349 */
350 @Override
351 public void updateListenerForSelfMerge(ObjectChangeListener listener, ForeignReferenceMapping mapping, Object source, Object target, UnitOfWorkImpl unitOfWork) {
352 //not applicable for this change detection type.
353 }
354 }
2323 * - 458877 : Add national character support
2424 * 02/23/2015-2.6 Dalia Abo Sheasha
2525 * - 460607: Change DatabasePlatform StoredProcedureTerminationToken to be configurable
26 * 12/06/2018 - Will Dazey
27 * - 542491: Add new 'eclipselink.jdbc.force-bind-parameters' property to force enable binding
2628 ******************************************************************************/
2729 package org.eclipse.persistence.internal.databaseaccess;
2830
128130 /** Bind all arguments to any SQL statement. */
129131 protected boolean shouldBindAllParameters;
130132
133 /** Bind all arguments to any SQL statement. */
134 protected boolean shouldForceBindAllParameters;
135
131136 /** Cache all prepared statements, this requires full parameter binding as well. */
132137 protected boolean shouldCacheAllStatements;
133138
271276 this.stringBindingSize = 255;
272277 this.shouldTrimStrings = true;
273278 this.shouldBindAllParameters = true;
279 this.shouldForceBindAllParameters = false;
274280 this.shouldCacheAllStatements = false;
275281 this.shouldOptimizeDataConversion = true;
276282 this.statementCacheSize = 50;
956962 databasePlatform.setUsesByteArrayBinding(usesByteArrayBinding());
957963 databasePlatform.setUsesStringBinding(usesStringBinding());
958964 databasePlatform.setShouldBindAllParameters(shouldBindAllParameters());
965 databasePlatform.setShouldForceBindAllParameters(shouldForceBindAllParameters());
959966 databasePlatform.setShouldCacheAllStatements(shouldCacheAllStatements());
960967 databasePlatform.setStatementCacheSize(getStatementCacheSize());
961968 databasePlatform.setTransactionIsolation(getTransactionIsolation());
19161923 }
19171924
19181925 /**
1926 * Used to enable parameter binding and override the platform default
1927 */
1928 public void setShouldForceBindAllParameters(boolean shouldForceBindAllParameters) {
1929 this.shouldForceBindAllParameters = shouldForceBindAllParameters;
1930 }
1931
1932 /**
19191933 * Can be used if the app expects upper case but the database is not return consistent case, i.e. different databases.
19201934 */
19211935 public void setShouldForceFieldNamesToUpperCase(boolean shouldForceFieldNamesToUpperCase) {
21292143 */
21302144 public void setShouldCreateIndicesOnForeignKeys(boolean shouldCreateIndicesOnForeignKeys) {
21312145 this.shouldCreateIndicesOnForeignKeys = shouldCreateIndicesOnForeignKeys;
2146 }
2147
2148 /**
2149 * Used to enable parameter binding and override platform default
2150 */
2151 public boolean shouldForceBindAllParameters() {
2152 return this.shouldForceBindAllParameters;
21322153 }
21332154
21342155 /**
1111 ******************************************************************************/
1212 package org.eclipse.persistence.internal.descriptors;
1313
14 import java.security.AccessController;
15 import java.security.PrivilegedActionException;
16
1417 import org.eclipse.persistence.exceptions.DescriptorException;
18 import org.eclipse.persistence.internal.logging.StdErrLogger;
19 import org.eclipse.persistence.internal.security.PrivilegedAccessHelper;
20 import org.eclipse.persistence.internal.security.PrivilegedGetClassLoaderForClass;
21 import org.eclipse.persistence.internal.security.PrivilegedGetClassLoaderFromCurrentThread;
22 import org.eclipse.persistence.logging.SessionLog;
1523
1624 /**
1725 * Used with weaving to access attributes without using reflection.
1826 */
1927 public class PersistenceObjectAttributeAccessor extends InstanceVariableAttributeAccessor {
2028
29 /** Cache weaver logger finest level settings. */
30 private final boolean shouldLogFinest;
31
2132 public PersistenceObjectAttributeAccessor(String attributeName) {
2233 this.attributeName = attributeName.intern();
34 // PERF: Cache weaver logger finest level settings. It won't allow to change logger settings on the fly
35 // but it's less evil than evaluating it with every single getter/setter call.
36 shouldLogFinest = StdErrLogger.shouldLog(SessionLog.FINEST, SessionLog.WEAVER);
2337 }
2438
2539 /**
2640 * Returns the value of the attribute on the specified object.
2741 */
2842 public Object getAttributeValueFromObject(Object object) {
43 if (shouldLogFinest) {
44 ClassLoader contextClassLoader;
45 ClassLoader objectClassLoader;
46 if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()) {
47 try {
48 contextClassLoader = AccessController.doPrivileged(
49 new PrivilegedGetClassLoaderFromCurrentThread());
50 objectClassLoader = AccessController.doPrivileged(
51 new PrivilegedGetClassLoaderForClass(object.getClass()));
52 } catch (PrivilegedActionException ex) {
53 throw (RuntimeException) ex.getCause();
54 }
55 } else {
56 contextClassLoader = Thread.currentThread().getContextClassLoader();
57 objectClassLoader = object.getClass().getClassLoader();
58 }
59 StdErrLogger.log(SessionLog.FINEST, SessionLog.WEAVER, "weaving_call_persistence_get",
60 object.getClass().getName(),
61 Integer.toHexString(System.identityHashCode(contextClassLoader)),
62 Integer.toHexString(System.identityHashCode(objectClassLoader)));
63 }
2964 return ((PersistenceObject)object)._persistence_get(this.attributeName);
3065 }
3166
4277 * Sets the value of the instance variable in the object to the value.
4378 */
4479 public void setAttributeValueInObject(Object object, Object value) {
80 if (shouldLogFinest) {
81 ClassLoader contextClassLoader;
82 ClassLoader objectClassLoader;
83 if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()) {
84 try {
85 contextClassLoader = AccessController.doPrivileged(
86 new PrivilegedGetClassLoaderFromCurrentThread());
87 objectClassLoader = AccessController.doPrivileged(
88 new PrivilegedGetClassLoaderForClass(object.getClass()));
89 } catch (PrivilegedActionException ex) {
90 throw (RuntimeException) ex.getCause();
91 }
92 } else {
93 contextClassLoader = Thread.currentThread().getContextClassLoader();
94 objectClassLoader = object.getClass().getClassLoader();
95 }
96 StdErrLogger.log(SessionLog.FINEST, SessionLog.WEAVER, "weaving_call_persistence_set",
97 object.getClass().getName(),
98 Integer.toHexString(System.identityHashCode(contextClassLoader)),
99 Integer.toHexString(System.identityHashCode(objectClassLoader)));
100 }
45101 ((PersistenceObject)object)._persistence_set(this.attributeName, value);
46102 }
47103 }
7777 /** Used to store null values in hashtables, is helper because need to be serializable. */
7878 public static final Object NULL_VALUE = new Helper();
7979
80 /** Used to convert {@code null} value to {@link String}. */
81 private static final String NULL_STRING = "null";
82
8083 /** PERF: Used to cache a set of calendars for conversion/printing purposes. */
8184 protected static Queue<Calendar> calendarCache = initCalendarCache();
8285
244247 }
245248
246249 /**
250 * Convert {@link Integer} to hexadecimal {@link String}.
251 * @param i An {@link Integer} to be converted to a hexadecimal string.
252 * @return The {@link String} representation of the unsigned integer value represented by the argument
253 * in hexadecimal or {@code "null"} if provided {@link Integer} argument is {@code null}.
254 */
255 public static String integerToHexString(final Integer i) {
256 return i != null ? Integer.toHexString(i) : NULL_STRING;
257 }
258
259 /**
247260 * Convert the HEX string to a byte array.
248261 * HEX allows for binary data to be printed.
249262 */
796809 public static String cr() {
797810 // bug 2756643
798811 if (CR == null) {
799 CR = System.getProperty("line.separator");
812 CR = PrivilegedAccessHelper.getLineSeparator();
800813 }
801814 return CR;
802815 }
4545 /** Java SE 18.9. */
4646 v18_9(18,9);
4747
48 /** Lowest supported Java SE platform. Currently it's Java SE 1.7. */
49 public static final JavaSEPlatform MIN_SUPPORTED = v1_7;
50
51 /** Latest Java SE platform. This value is used when Java SE platform detection fails. */
52 static final JavaSEPlatform LATEST = JavaSEPlatform.v18_9;
53
4854 public static final class Version {
4955 /**
5056 * Creates an instance of Java SE version numbers.
126132 /** Current Java SE platform. */
127133 public static final JavaSEPlatform CURRENT
128134 = JavaVersion.vmVersion().toPlatform();
129
130 /** Lowest supported Java SE platform. Currently it's Java SE 1.7. */
131 public static final JavaSEPlatform MIN_SUPPORTED = v1_7;
132
133 /** Latest Java SE platform. This value is used when Java SE platform detection fails. */
134 static final JavaSEPlatform LATEST = JavaSEPlatform.v18_9;
135135
136136 /**
137137 * Check whether current Java SE is exactly matching provided platform.
3636 import org.eclipse.persistence.config.PersistenceUnitProperties;
3737 import org.eclipse.persistence.config.TargetDatabase;
3838 import org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.TableCreationType;
39 import org.eclipse.persistence.internal.localization.ExceptionLocalization;
4039 import org.eclipse.persistence.internal.security.PrivilegedAccessHelper;
4140 import org.eclipse.persistence.internal.security.PrivilegedGetSystemProperty;
4241 import org.eclipse.persistence.internal.sessions.AbstractSession;
115114 }
116115 }
117116
118 public static String getConfigPropertyAsString(String propertyKey, Map overrides){
119 String value = null;
120 if (overrides != null){
121 value = (String)overrides.get(propertyKey);
122 }
123 if (value == null){
124 if (propertyKey == null || !(propertyKey.startsWith("eclipselink.")
125 || propertyKey.startsWith("javax.persistence.")
126 || propertyKey.startsWith("persistence.")
127 || PersistenceUnitProperties.JAVASE_DB_INTERACTION.equals(propertyKey))) {
128 throw new IllegalArgumentException(
129 ExceptionLocalization.buildMessage("unexpect_argument", new Object[] {propertyKey}));
130 }
131 if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()) {
132 value = AccessController.doPrivileged(new PrivilegedGetSystemProperty(propertyKey));
133 } else {
134 value = System.getProperty(propertyKey);
135 }
136 }
137
138 return value;
117 /**
118 * Get configuration {@link System} property indicated by the specified {@code propertyKey}.
119 * Property value may be overridden by {@code overrides} {@link Map}.
120 * @param propertyKey The name of the configuration {@link System} property.
121 * @param overrides {@link Map} with property overrides.
122 * @return The {@link String} value of the property from {@code overrides} {@link Map} or value of configuration
123 * {@link System} property or {@code null} if property identified by {@code propertyKey} does not exist.
124 */
125 public static String getConfigPropertyAsString(final String propertyKey, final Map overrides) {
126 final String value = overrides != null ? (String)overrides.get(propertyKey) : null;
127 return value != null ? value : PrivilegedAccessHelper.getSystemProperty(propertyKey);
139128 }
140129
141130 /**
6161 * - 460862 : Added support for JTA schema generation without JTA-DS
6262 * 09/03/2015 - Will Dazey
6363 * - 456067 : Added support for defining query timeout units
64 * 09/28/2015 - Will Dazey
65 * - 478331 : Added support for defining local or server as the default locale for obtaining timestamps
66 * 11/05/2015 - Dalia Abo Sheasha
67 * - 480787 : Wrap several privileged method calls with a doPrivileged block
68 * 12/06/2018 - Will Dazey
69 * - 542491: Add new 'eclipselink.jdbc.force-bind-parameters' property to force enable binding
6470 *****************************************************************************/
6571 package org.eclipse.persistence.internal.jpa;
6672
114120 import java.rmi.Naming;
115121 import java.rmi.RemoteException;
116122 import java.security.AccessController;
123 import java.security.PrivilegedAction;
117124 import java.security.PrivilegedActionException;
118125 import java.util.ArrayList;
119126 import java.util.Collection;
158165 import org.eclipse.persistence.descriptors.ClassDescriptor;
159166 import org.eclipse.persistence.descriptors.MultitenantPolicy;
160167 import org.eclipse.persistence.descriptors.SchemaPerMultitenantPolicy;
168 import org.eclipse.persistence.descriptors.TimestampLockingPolicy;
161169 import org.eclipse.persistence.descriptors.partitioning.PartitioningPolicy;
162170 import org.eclipse.persistence.dynamic.DynamicClassLoader;
163171 import org.eclipse.persistence.eis.EISConnectionSpec;
201209 import org.eclipse.persistence.internal.jpa.metamodel.proxy.MapAttributeProxyImpl;
202210 import org.eclipse.persistence.internal.jpa.metamodel.proxy.SetAttributeProxyImpl;
203211 import org.eclipse.persistence.internal.jpa.metamodel.proxy.SingularAttributeProxyImpl;
212 import org.eclipse.persistence.internal.jpa.weaving.ClassDetails;
204213 import org.eclipse.persistence.internal.jpa.weaving.PersistenceWeaver;
205214 import org.eclipse.persistence.internal.jpa.weaving.TransformerFactory;
206215 import org.eclipse.persistence.internal.localization.ExceptionLocalization;
19491958 }
19501959
19511960 // Process the Object/relational metadata from XML and annotations.
1952 PersistenceUnitProcessor.processORMetadata(processor, throwExceptionOnFail, mode);
1961 // If Java Security is enabled, surround this call with a doPrivileged block.
1962 if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()) {
1963 AccessController.doPrivileged(new PrivilegedAction<Void>() {
1964 @Override
1965 public Void run() {
1966 PersistenceUnitProcessor.processORMetadata(processor, throwExceptionOnFail, mode);
1967 return null;
1968 }
1969 });
1970 } else {
1971 PersistenceUnitProcessor.processORMetadata(processor, throwExceptionOnFail, mode);
1972 }
19531973
19541974 if (mode == PersistenceUnitProcessor.Mode.COMPOSITE_MEMBER_INITIAL) {
19551975 mode = PersistenceUnitProcessor.Mode.COMPOSITE_MEMBER_MIDDLE;
27322752 if (shouldBindString != null) {
27332753 session.getPlatform().setShouldBindAllParameters(Boolean.parseBoolean(shouldBindString));
27342754 }
2755
2756 String shouldForceBindString = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.JDBC_FORCE_BIND_PARAMETERS, m, session);
2757 if(shouldForceBindString != null) {
2758 session.getPlatform().setShouldForceBindAllParameters(Boolean.parseBoolean(shouldForceBindString));
2759 }
2760
27352761 updateLogins(m);
27362762 }
27372763 if (!session.getDatasourceLogin().shouldUseExternalTransactionController()) {
27892815 updatePessimisticLockTimeout(m);
27902816 updateQueryTimeout(m);
27912817 updateQueryTimeoutUnit(m);
2818 updateLockingTimestampDefault(m);
27922819 if (!session.hasBroker()) {
27932820 updateCacheCoordination(m, loader);
27942821 }
35363563 }
35373564 }
35383565
3566 private void updateLockingTimestampDefault(Map persistenceProperties) {
3567 String local = EntityManagerFactoryProvider.getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.USE_LOCAL_TIMESTAMP, persistenceProperties, session);
3568 try {
3569 if (local != null) {
3570 for (ClassDescriptor descriptor: session.getProject().getDescriptors().values()) {
3571 OptimisticLockingPolicy policy = descriptor.getOptimisticLockingPolicy();
3572 if (policy instanceof TimestampLockingPolicy) {
3573 ((TimestampLockingPolicy)policy).setUsesServerTime(!Boolean.parseBoolean(local));
3574 }
3575 }
3576 }
3577 } catch (NumberFormatException exception) {
3578 this.session.handleException(ValidationException.invalidValueForProperty(local, PersistenceUnitProperties.USE_LOCAL_TIMESTAMP, exception));
3579 }
3580 }
3581
35393582 /**
35403583 * If Bean Validation is enabled, bootstraps Bean Validation on descriptors.
35413584 * @param puProperties merged properties for this persistence unit
37313774 this.compositeMemberEmSetupImpls = new HashSet(compositeMemberPuInfos.size());
37323775 this.processor = new MetadataProcessor();
37333776 if (enableWeaving) {
3734 this.weaver = new PersistenceWeaver(this.session, new HashMap());
3777 this.weaver = new PersistenceWeaver(new HashMap<String, ClassDetails>());
37353778 }
37363779
37373780 // create containedEmSetupImpls and predeploy them for the first time.
00 /*******************************************************************************
1 * Copyright (c) 1998, 2014 Oracle, Hans Harz, Andrew Rustleund. All rights reserved.
1 * Copyright (c) 1998, 2015 Oracle, Hans Harz, Andrew Rustleund, IBM Corporation. All rights reserved.
22 * This program and the accompanying materials are made available under the
33 * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
44 * which accompanies this distribution.
1818 * - 373092: Exceptions using generics, embedded key and entity inheritance
1919 * 19/04/2014-2.6 Lukas Jungmann
2020 * - 429992: JavaSE 8/ASM 5.0.1 support (EclipseLink silently ignores Entity classes with lambda expressions)
21 * 11/05/2015-2.6 Dalia Abo Sheasha
22 * - 480787 : Wrap several privileged method calls with a doPrivileged block
2123 ******************************************************************************/
2224 package org.eclipse.persistence.internal.jpa.metadata.accessors.objects;
2325
2426 import java.io.IOException;
2527 import java.io.InputStream;
28 import java.security.AccessController;
29 import java.security.PrivilegedAction;
2630 import java.util.ArrayList;
2731 import java.util.List;
2832
3741 import org.eclipse.persistence.internal.libraries.asm.MethodVisitor;
3842 import org.eclipse.persistence.internal.libraries.asm.Opcodes;
3943 import org.eclipse.persistence.internal.libraries.asm.Type;
44 import org.eclipse.persistence.internal.security.PrivilegedAccessHelper;
4045
4146 /**
4247 * INTERNAL: A metadata factory that uses ASM technology and no reflection
7681 InputStream stream = null;
7782 try {
7883 String resourceString = className.replace('.', '/') + ".class";
79 stream = m_loader.getResourceAsStream(resourceString);
84 if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()) {
85 final String f_resourceString = resourceString;
86 stream = AccessController.doPrivileged(new PrivilegedAction<InputStream>() {
87 @Override
88 public InputStream run() {
89 return m_loader.getResourceAsStream(f_resourceString);
90 }
91 });
92 } else {
93 stream = m_loader.getResourceAsStream(resourceString);
94 }
8095
8196 ClassReader reader = new ClassReader(stream);
8297 Attribute[] attributes = new Attribute[0];
0 /*******************************************************************************
1 * Copyright (c) 2009, 2015 Sun Microsystems, Inc, IBM Corporation. All rights reserved.
2 * This program and the accompanying materials are made available under the
3 * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
4 * which accompanies this distribution.
5 * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
6 * and the Eclipse Distribution License is available at
7 * http://www.eclipse.org/org/documents/edl-v10.php.
8 *
9 * Contributors:
10 * 08/20/2014-2.5 Rick Curtis
11 * - 441890: Cache Validator instances.
12 * Marcel Valovy - 2.6 - skip validation of objects that are not constrained.
13 ******************************************************************************/
14
15 package org.eclipse.persistence.internal.jpa.metadata.listeners;
16
17 import javax.validation.ConstraintViolation;
18 import javax.validation.ConstraintViolationException;
19 import javax.validation.Path;
20 import javax.validation.TraversableResolver;
21 import javax.validation.Validator;
22 import javax.validation.ValidatorFactory;
23 import javax.validation.groups.Default;
24
0 /*******************************************************************************
1 * Copyright (c) 2009, 2019 Sun Microsystems, Inc, IBM Corporation. All rights reserved.
2 * This program and the accompanying materials are made available under the
3 * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
4 * which accompanies this distribution.
5 * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
6 * and the Eclipse Distribution License is available at
7 * http://www.eclipse.org/org/documents/edl-v10.php.
8 *
9 * Contributors:
10 * 08/20/2014-2.5 Rick Curtis
11 * - 441890: Cache Validator instances.
12 * Marcel Valovy - 2.6 - skip validation of objects that are not constrained.
13 ******************************************************************************/
14
15 package org.eclipse.persistence.internal.jpa.metadata.listeners;
16
17 import java.lang.annotation.ElementType;
18 import java.util.Map;
19 import java.util.Set;
20 import java.util.concurrent.ConcurrentHashMap;
21
22 import javax.validation.ConstraintViolation;
23 import javax.validation.ConstraintViolationException;
24 import javax.validation.Path;
25 import javax.validation.TraversableResolver;
26 import javax.validation.Validator;
27 import javax.validation.ValidatorFactory;
28 import javax.validation.groups.Default;
29
2530 import org.eclipse.persistence.config.PersistenceUnitProperties;
26 import org.eclipse.persistence.descriptors.DescriptorEventAdapter;
27 import org.eclipse.persistence.descriptors.DescriptorEvent;
28 import org.eclipse.persistence.descriptors.ClassDescriptor;
29 import org.eclipse.persistence.descriptors.FetchGroupManager;
31 import org.eclipse.persistence.descriptors.ClassDescriptor;
32 import org.eclipse.persistence.descriptors.DescriptorEvent;
33 import org.eclipse.persistence.descriptors.DescriptorEventAdapter;
34 import org.eclipse.persistence.descriptors.FetchGroupManager;
3035 import org.eclipse.persistence.internal.jpa.metadata.beanvalidation.BeanValidationHelper;
31 import org.eclipse.persistence.internal.sessions.UnitOfWorkImpl;
32 import org.eclipse.persistence.mappings.DatabaseMapping;
33 import org.eclipse.persistence.mappings.ForeignReferenceMapping;
34
35 import java.util.Map;
36 import java.util.Set;
37 import java.util.concurrent.ConcurrentHashMap;
38 import java.lang.annotation.ElementType;
39
40 /**
41 * Responsible for performing automatic bean validation on call back events.
42 * @author Mitesh Meswani
43 */
44 public class BeanValidationListener extends DescriptorEventAdapter {
45 private final ValidatorFactory validatorFactory;
46 private final Class[] groupPrePersit;
47 private final Class[] groupPreUpdate;
48 private final Class[] groupPreRemove;
49 private static final Class[] groupDefault = new Class[]{Default.class};
50 private final Map<ClassDescriptor, Validator> validatorMap;
36 import org.eclipse.persistence.internal.sessions.UnitOfWorkImpl;
37 import org.eclipse.persistence.mappings.DatabaseMapping;
38 import org.eclipse.persistence.mappings.ForeignReferenceMapping;
39
40 /**
41 * Responsible for performing automatic bean validation on call back events.
42 * @author Mitesh Meswani
43 */
44 public class BeanValidationListener extends DescriptorEventAdapter {
45 private final ValidatorFactory validatorFactory;
46 private final Class[] groupPrePersit;
47 private final Class[] groupPreUpdate;
48 private final Class[] groupPreRemove;
49 private static final Class[] groupDefault = new Class[]{Default.class};
50 private final Map<ClassDescriptor, Validator> validatorMap;
5151 private final BeanValidationHelper beanValidationHelper = new BeanValidationHelper();
52
53 public BeanValidationListener(ValidatorFactory validatorFactory, Class[] groupPrePersit, Class[] groupPreUpdate, Class[] groupPreRemove) {
54 this.validatorFactory = validatorFactory;
55 //For prePersit and preUpdate, default the group to validation group Default if user has not specified one
56 this.groupPrePersit = groupPrePersit != null ? groupPrePersit : groupDefault;
57 this.groupPreUpdate = groupPreUpdate != null ? groupPreUpdate : groupDefault;
58 //No validation performed on preRemove if user has not explicitly specified a validation group
59 this.groupPreRemove = groupPreRemove;
60
61 validatorMap = new ConcurrentHashMap<>();
62 }
63
64 @Override
65 public void prePersist (DescriptorEvent event) {
66 // since we are using prePersist to perform validation, invlid data may get inserted into database as shown by
67 // following example
68 // tx.begin()
69 // e = new MyEntity(...);
70 // em.perist(e); // prePersist validation happens here
71 // em.setXXX("invalid data");
72 // tx.commit();
73 // "invalid data" would get inserted into database.
74 //
75 // preInsert can be used to work around above issue. Howerver, the JPA spec does not itent it.
76 // This might be corrected in next iteration of spec
77 validateOnCallbackEvent(event, "prePersist", groupPrePersit);
78 }
79
80 @Override
81 public void preUpdate (DescriptorEvent event) {
82 Object source = event.getSource();
83 UnitOfWorkImpl unitOfWork = (UnitOfWorkImpl )event.getSession();
84 // preUpdate is also generated for deleted objects that were modified in this UOW.
85 // Do not perform preUpdate validation for such objects as preRemove would have already been called.
86 if(!unitOfWork.isObjectDeleted(source)) {
87 validateOnCallbackEvent(event, "preUpdate", groupPreUpdate);
88 }
89 }
90
91 @Override
92 public void preRemove (DescriptorEvent event) {
93 if(groupPreRemove != null) { //No validation performed on preRemove if user has not explicitly specified a validation group
94 validateOnCallbackEvent(event, "preRemove", groupPreRemove);
95 }
96 }
97
98 private void validateOnCallbackEvent(DescriptorEvent event, String callbackEventName, Class[] validationGroup) {
99 Object source = event.getSource();
52
53 public BeanValidationListener(ValidatorFactory validatorFactory, Class[] groupPrePersit, Class[] groupPreUpdate, Class[] groupPreRemove) {
54 this.validatorFactory = validatorFactory;
55 //For prePersit and preUpdate, default the group to validation group Default if user has not specified one
56 this.groupPrePersit = groupPrePersit != null ? groupPrePersit : groupDefault;
57 this.groupPreUpdate = groupPreUpdate != null ? groupPreUpdate : groupDefault;
58 //No validation performed on preRemove if user has not explicitly specified a validation group
59 this.groupPreRemove = groupPreRemove;
60
61 validatorMap = new ConcurrentHashMap<>();
62 }
63
64 @Override
65 public void prePersist (DescriptorEvent event) {
66 // since we are using prePersist to perform validation, invlid data may get inserted into database as shown by
67 // following example
68 // tx.begin()
69 // e = new MyEntity(...);
70 // em.perist(e); // prePersist validation happens here
71 // em.setXXX("invalid data");
72 // tx.commit();
73 // "invalid data" would get inserted into database.
74 //
75 // preInsert can be used to work around above issue. Howerver, the JPA spec does not itent it.
76 // This might be corrected in next iteration of spec
77 validateOnCallbackEvent(event, "prePersist", groupPrePersit);
78 }
79
80 @Override
81 public void preUpdate (DescriptorEvent event) {
82 Object source = event.getSource();
83 UnitOfWorkImpl unitOfWork = (UnitOfWorkImpl )event.getSession();
84 // preUpdate is also generated for deleted objects that were modified in this UOW.
85 // Do not perform preUpdate validation for such objects as preRemove would have already been called.
86 if(!unitOfWork.isObjectDeleted(source)) {
87 validateOnCallbackEvent(event, "preUpdate", groupPreUpdate);
88 }
89 }
90
91 @Override
92 public void preRemove (DescriptorEvent event) {
93 if(groupPreRemove != null) { //No validation performed on preRemove if user has not explicitly specified a validation group
94 validateOnCallbackEvent(event, "preRemove", groupPreRemove);
95 }
96 }
97
98 private void validateOnCallbackEvent(DescriptorEvent event, String callbackEventName, Class[] validationGroup) {
99 Object source = event.getSource();
100100 boolean noOptimization = "true".equalsIgnoreCase((String) event.getSession().getProperty(PersistenceUnitProperties.BEAN_VALIDATION_NO_OPTIMISATION));
101101 boolean shouldValidate = noOptimization || beanValidationHelper.isConstrained(source.getClass());
102 if (shouldValidate) {
102 if (shouldValidate) {
103103 Set<ConstraintViolation<Object>> constraintViolations = getValidator(event).validate(source, validationGroup);
104 if (constraintViolations.size() > 0) {
105 // There were errors while call to validate above.
106 // Throw a ConstrainViolationException as required by the spec.
107 // The transaction would be rolled back automatically
108 // TODO need to I18N this.
109 throw new ConstraintViolationException(
110 "Bean Validation constraint(s) violated while executing Automatic Bean Validation on callback event:'" +
111 callbackEventName + "'. Please refer to embedded ConstraintViolations for details.",
112 (Set<ConstraintViolation<?>>) (Object) constraintViolations); /* Do not remove the explicit
113 cast. This issue is related to capture#a not being instance of capture#b. */
114 }
115 }
116 }
117
118 private Validator getValidator(DescriptorEvent event) {
119 ClassDescriptor descriptor = event.getDescriptor();
120 Validator res = validatorMap.get(descriptor);
121 if (res == null) {
122 TraversableResolver traversableResolver = new AutomaticLifeCycleValidationTraversableResolver(descriptor);
123 res = validatorFactory.usingContext().traversableResolver(traversableResolver).getValidator();
124
125 Validator t = validatorMap.put(descriptor, res);
126 if (t != null) {
127 // Threading collision, use existing
128 res = t;
129 }
130 }
131
132 return res;
133 }
134
135
136 /**
137 * This traversable resolver ensures that validation is not cascaded to any associations and no lazily loaded
138 * attribute is loaded as a side effect of validation
139 */
140 private static class AutomaticLifeCycleValidationTraversableResolver implements TraversableResolver {
141
142 private final ClassDescriptor descriptor;
143
144 AutomaticLifeCycleValidationTraversableResolver(ClassDescriptor eventDescriptor) {
145 descriptor = eventDescriptor;
146 }
147
148
149 /**
150 * @return false for any lazily loaded property of root object being validated
151 */
152 public boolean isReachable(Object traversableObject, Path.Node traversableProperty, Class<?> rootBeanType, Path pathToTraversableObject, ElementType elementType) {
153 boolean reachable = true;
154 String attributeName = null;
155 if (isRootObjectPath(pathToTraversableObject)) {
156 attributeName = traversableProperty.getName(); //Refer to section 4.2 of Bean Validation spec for more details about Path.Node
157 DatabaseMapping mapping = getMappingForAttributeName(attributeName);
158 if(mapping != null) {
159 if(mapping.isForeignReferenceMapping()) {
160 // For lazy relationships check whether it is instantiated
161 if(mapping.isLazy()) {
162 Object attributeValue = mapping.getAttributeAccessor().getAttributeValueFromObject(traversableObject);
163 reachable = ((ForeignReferenceMapping)mapping).getIndirectionPolicy().objectIsInstantiatedOrChanged(attributeValue);
164 }
165 } else {
166 // For lazy non relationship attributes, check whether it is fetched
167 FetchGroupManager fetchGroupManager = descriptor.getFetchGroupManager();
168 if (fetchGroupManager != null) {
169 reachable = fetchGroupManager.isAttributeFetched(traversableObject, attributeName);
170 }
171 }
172 }
173 }
174 return reachable;
175
176 }
177
178 /**
179 * Called only if isReachable returns true
180 * @return false for any associatons of root object being validated true otherwise
181 */
182 public boolean isCascadable(Object traversableObject, Path.Node traversableProperty, Class<?> rootBeanType, Path pathToTraversableObject, ElementType elementType) {
183 boolean cascadable = true;
184 if (isRootObjectPath(pathToTraversableObject)) {
185 String attributeName = traversableProperty.getName(); //Refer to section 4.2 of Bean Validation spec for more details about Path
186 DatabaseMapping mapping = getMappingForAttributeName(attributeName);
187 if(mapping != null && mapping.isForeignReferenceMapping()) {
188 cascadable = false;
189 }
190 }
191
192 return cascadable;
193 }
194
195 /**
196 * @return DatabaseMapping for given attribute name
197 */
198 private DatabaseMapping getMappingForAttributeName(String attributeName) {
199 return descriptor.getObjectBuilder().getMappingForAttributeName(attributeName);
200 }
201
202 /**
203 * @return true if given path corresponds to Root Object else false.
204 */
205 private boolean isRootObjectPath(Path pathToTraversableObject) {
206 // From Bean Validation spec section 3.5.2
207 // <quote>
208 // pathToTraversableObject is the Path from the rootBeanType down to the traversableObject (it is composed of
209 // a single Node whose name is null if the root object is traversableObject). The path is described following the
210 // conventions described in Section 4.2 (getPropertyPath).
211 // </quote>
212 return pathToTraversableObject.iterator().next().getName() == null;
213 }
214 }
215
216 }
104 if (constraintViolations.size() > 0) {
105 // There were errors while call to validate above.
106 // Throw a ConstrainViolationException as required by the spec.
107 // The transaction would be rolled back automatically
108 // TODO need to I18N this.
109 throw new ConstraintViolationException(
110 "Bean Validation constraint(s) violated while executing Automatic Bean Validation on callback event:'" +
111 callbackEventName + "'. Please refer to embedded ConstraintViolations for details.",
112 (Set<ConstraintViolation<?>>) (Object) constraintViolations); /* Do not remove the explicit
113 cast. This issue is related to capture#a not being instance of capture#b. */
114 }
115 }
116 }
117
118 private Validator getValidator(DescriptorEvent event) {
119 ClassDescriptor descriptor = event.getDescriptor();
120 Validator res = validatorMap.get(descriptor);
121 if (res == null) {
122 TraversableResolver traversableResolver = new AutomaticLifeCycleValidationTraversableResolver(descriptor);
123 res = validatorFactory.usingContext().traversableResolver(traversableResolver).getValidator();
124
125 Validator t = validatorMap.put(descriptor, res);
126 if (t != null) {
127 // Threading collision, use existing
128 res = t;
129 }
130 }
131
132 return res;
133 }
134
135
136 /**
137 * This traversable resolver ensures that validation is not cascaded to any associations and no lazily loaded
138 * attribute is loaded as a side effect of validation
139 */
140 private static class AutomaticLifeCycleValidationTraversableResolver implements TraversableResolver {
141
142 private final ClassDescriptor descriptor;
143
144 AutomaticLifeCycleValidationTraversableResolver(ClassDescriptor eventDescriptor) {
145 descriptor = eventDescriptor;
146 }
147
148
149 /**
150 * @return false for any lazily loaded property of root object being validated
151 */
152 @Override
153 public boolean isReachable(Object traversableObject, Path.Node traversableProperty, Class<?> rootBeanType, Path pathToTraversableObject, ElementType elementType) {
154 boolean reachable = true;
155 String attributeName = null;
156 if (isRootObjectPath(pathToTraversableObject)) {
157 attributeName = traversableProperty.getName(); //Refer to section 4.2 of Bean Validation spec for more details about Path.Node
158 DatabaseMapping mapping = getMappingForAttributeName(attributeName);
159 if(mapping != null) {
160 if(mapping.isForeignReferenceMapping()) {
161 // For lazy relationships check whether it is instantiated
162 if(mapping.isLazy()) {
163 Object attributeValue = mapping.getAttributeAccessor().getAttributeValueFromObject(traversableObject);
164 reachable = ((ForeignReferenceMapping)mapping).getIndirectionPolicy().objectIsInstantiatedOrChanged(attributeValue);
165 }
166 } else {
167 // For lazy non relationship attributes, check whether it is fetched
168 FetchGroupManager fetchGroupManager = descriptor.getFetchGroupManager();
169 if (fetchGroupManager != null) {
170 reachable = fetchGroupManager.isAttributeFetched(traversableObject, attributeName);
171 }
172 }
173 }
174 }
175 return reachable;
176
177 }
178
179 /**
180 * Called only if isReachable returns true
181 * @return false for any associatons of root object being validated true otherwise
182 */
183 @Override
184 public boolean isCascadable(Object traversableObject, Path.Node traversableProperty, Class<?> rootBeanType, Path pathToTraversableObject, ElementType elementType) {
185 boolean cascadable = true;
186 if (isRootObjectPath(pathToTraversableObject)) {
187 String attributeName = traversableProperty.getName(); //Refer to section 4.2 of Bean Validation spec for more details about Path
188 DatabaseMapping mapping = getMappingForAttributeName(attributeName);
189 if(mapping != null && mapping.isForeignReferenceMapping()) {
190 cascadable = false;
191 }
192 }
193
194 return cascadable;
195 }
196
197 /**
198 * @return DatabaseMapping for given attribute name
199 */
200 private DatabaseMapping getMappingForAttributeName(String attributeName) {
201 return descriptor.getObjectBuilder().getMappingForAttributeName(attributeName);
202 }
203
204 /**
205 * @return true if given path corresponds to Root Object else false.
206 */
207 private boolean isRootObjectPath(Path pathToTraversableObject) {
208 // From Bean Validation spec section 3.5.2
209 // <quote>
210 // pathToTraversableObject is the Path from the rootBeanType down to the traversableObject (it is composed of
211 // a single Node whose name is null if the root object is traversableObject). The path is described following the
212 // conventions described in Section 4.2 (getPropertyPath).
213 // </quote>
214 return pathToTraversableObject.iterator().next().getName() == null;
215 }
216 }
217
218 }
00 /*******************************************************************************
1 * Copyright (c) 1998, 2013 Oracle and/or its affiliates. All rights reserved.
1 * Copyright (c) 1998, 2019 Oracle and/or its affiliates. All rights reserved.
22 * This program and the accompanying materials are made available under the
33 * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
44 * which accompanies this distribution.
0 /*******************************************************************************
1 * Copyright (c) 1998, 2017 Oracle and/or its affiliates. All rights reserved.
2 * This program and the accompanying materials are made available under the
3 * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
4 * which accompanies this distribution.
0 /*******************************************************************************
1 * Copyright (c) 1998, 2013 Oracle and/or its affiliates. All rights reserved.
2 * This program and the accompanying materials are made available under the
3 * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
4 * which accompanies this distribution.
55 * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
66 * and the Eclipse Distribution License is available at
77 * http://www.eclipse.org/org/documents/edl-v10.php.
1010 * 05/16/2008-1.0M8 Guy Pelletier
1111 * - 218084: Implement metadata merging functionality between mapping files
1212 * 01/05/2010-2.1 Guy Pelletier
13 * - 211324: Add additional event(s) support to the EclipseLink-ORM.XML Schema
14 * 07/15/2010-2.2 Guy Pelletier
15 * -311395 : Multiple lifecycle callback methods for the same lifecycle event
16 * 12/14/2017-2.6.6 Tomas Kraus
17 * - 291546: Performance degradation due to usage of Vector in DescriptorEventManager
18 ******************************************************************************/
19 package org.eclipse.persistence.internal.jpa.metadata.listeners;
20
21 import java.lang.reflect.InvocationTargetException;
22 import java.lang.reflect.Method;
23 import java.lang.reflect.Modifier;
24 import java.security.AccessController;
25 import java.security.PrivilegedActionException;
26 import java.util.ArrayList;
27 import java.util.Collections;
28 import java.util.HashMap;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.concurrent.ConcurrentHashMap;
32
33 import org.eclipse.persistence.descriptors.DescriptorEvent;
34 import org.eclipse.persistence.descriptors.DescriptorEventAdapter;
35 import org.eclipse.persistence.descriptors.DescriptorEventManager;
36 import org.eclipse.persistence.exceptions.ValidationException;
37 import org.eclipse.persistence.internal.security.PrivilegedAccessHelper;
38 import org.eclipse.persistence.internal.security.PrivilegedMethodInvoker;
39 import org.eclipse.persistence.internal.security.PrivilegedNewInstanceFromClass;
13 * - 211324: Add additional event(s) support to the EclipseLink-ORM.XML Schema
14 * 07/15/2010-2.2 Guy Pelletier
15 * -311395 : Multiple lifecycle callback methods for the same lifecycle event
16 ******************************************************************************/
17 package org.eclipse.persistence.internal.jpa.metadata.listeners;
18
19 import java.lang.reflect.InvocationTargetException;
20 import java.lang.reflect.Method;
21 import java.lang.reflect.Modifier;
22
23 import java.security.AccessController;
24 import java.security.PrivilegedActionException;
25
26 import java.util.ArrayList;
27 import java.util.Hashtable;
28 import java.util.List;
29 import java.util.Vector;
30
31 import org.eclipse.persistence.descriptors.DescriptorEvent;
32 import org.eclipse.persistence.descriptors.DescriptorEventAdapter;
33 import org.eclipse.persistence.descriptors.DescriptorEventManager;
34
35 import org.eclipse.persistence.exceptions.ValidationException;
36
37 import org.eclipse.persistence.internal.security.PrivilegedAccessHelper;
38 import org.eclipse.persistence.internal.security.PrivilegedMethodInvoker;
39 import org.eclipse.persistence.internal.security.PrivilegedNewInstanceFromClass;
4040 import org.eclipse.persistence.internal.sessions.AbstractSession;
4141 import org.eclipse.persistence.logging.SessionLog;
4242
5959 public final static String PRE_REMOVE = "preRemove";
6060 public final static String PRE_UPDATE_WITH_CHANGES = "preUpdateWithChanges";
6161
62 private Object m_listener;
63 private Class m_listenerClass;
64 private Class m_entityClass;
65 private Map<String, List<Method>> m_methods;
66 private final Map<String, Map<Integer, Boolean>> m_overriddenEvents;
67 private static final Map<Integer, String> m_eventStrings;
68 private AbstractSession owningSession;
69
70 static {
71 // For quick look up of equivalent event strings from event codes.
72 Map<Integer, String> mappings = new HashMap<>(9);
73 mappings.put(DescriptorEventManager.PostBuildEvent, POST_BUILD);
74 mappings.put(DescriptorEventManager.PostCloneEvent, POST_CLONE);
75 mappings.put(DescriptorEventManager.PostDeleteEvent, POST_DELETE);
76 mappings.put(DescriptorEventManager.PostInsertEvent, POST_INSERT);
77 mappings.put(DescriptorEventManager.PostRefreshEvent, POST_REFRESH);
78 mappings.put(DescriptorEventManager.PostUpdateEvent, POST_UPDATE);
79 mappings.put(DescriptorEventManager.PrePersistEvent, PRE_PERSIST);
80 mappings.put(DescriptorEventManager.PreRemoveEvent, PRE_REMOVE);
81 mappings.put(DescriptorEventManager.PreUpdateWithChangesEvent, PRE_UPDATE_WITH_CHANGES);
82 m_eventStrings = Collections.unmodifiableMap(mappings);
83 }
84
85 /**
86 * INTERNAL:
87 */
88 protected EntityListener(Class entityClass) {
89 m_entityClass = entityClass;
90 m_methods = new ConcurrentHashMap<>();
91
92 // Remember which events are overridden in subclasses. Overriden events
93 // must be built for each subclass chain.
94 m_overriddenEvents = new ConcurrentHashMap<>();
95 }
96
97 public EntityListener(Class listenerClass, Class entityClass){
62 private Object m_listener;
63 private Class m_listenerClass;
64 private Class m_entityClass;
65 private Hashtable<String, List<Method>> m_methods;
66 private Hashtable<String, Hashtable<Integer, Boolean>> m_overriddenEvents;
67 private static Hashtable<Integer, String> m_eventStrings;
68 private AbstractSession owningSession;
69
70 /**
71 * INTERNAL:
72 */
73 protected EntityListener(Class entityClass) {
74 m_entityClass = entityClass;
75 m_methods = new Hashtable<String, List<Method>>();
76
77 // Remember which events are overridden in subclasses. Overriden events
78 // must be built for each subclass chain.
79 m_overriddenEvents = new Hashtable<String, Hashtable<Integer, Boolean>>();
80
81 // For quick look up of equivalent event strings from event codes.
82 if (m_eventStrings == null) {
83 m_eventStrings = new Hashtable<Integer, String>();
84 m_eventStrings.put(Integer.valueOf(DescriptorEventManager.PostBuildEvent), POST_BUILD);
85 m_eventStrings.put(Integer.valueOf(DescriptorEventManager.PostCloneEvent), POST_CLONE);
86 m_eventStrings.put(Integer.valueOf(DescriptorEventManager.PostDeleteEvent), POST_DELETE);
87 m_eventStrings.put(Integer.valueOf(DescriptorEventManager.PostInsertEvent), POST_INSERT);
88 m_eventStrings.put(Integer.valueOf(DescriptorEventManager.PostRefreshEvent), POST_REFRESH);
89 m_eventStrings.put(Integer.valueOf(DescriptorEventManager.PostUpdateEvent), POST_UPDATE);
90 m_eventStrings.put(Integer.valueOf(DescriptorEventManager.PrePersistEvent), PRE_PERSIST);
91 m_eventStrings.put(Integer.valueOf(DescriptorEventManager.PreRemoveEvent), PRE_REMOVE);
92 m_eventStrings.put(Integer.valueOf(DescriptorEventManager.PreUpdateWithChangesEvent), PRE_UPDATE_WITH_CHANGES);
93 }
94 }
95
96 public EntityListener(Class listenerClass, Class entityClass){
9897 this(entityClass);
9998 this.m_listenerClass = listenerClass;
10099 }
178177 return m_entityClass;
179178 }
180179
181 /**
182 * INTERNAL:
183 */
184 public Map<String, List<Method>> getAllEventMethods() {
185 return m_methods;
186 }
187
188 /**
189 * INTERNAL:
190 */
191 public void setAllEventMethods(Map<String, List<Method>> methods) {
192 m_methods = methods;
193 }
194
180 /**
181 * INTERNAL:
182 */
183 public Hashtable<String, List<Method>> getAllEventMethods() {
184 return m_methods;
185 }
186
187 /**
188 * INTERNAL:
189 */
190 public void setAllEventMethods(Hashtable<String, List<Method>> methods) {
191 m_methods = methods;
192 }
193
195194 /**
196195 * INTERNAL:
197196 */
201200
202201 /**
203202 * INTERNAL:
204 */
205 protected List<Method> getEventMethods(int eventCode) {
206 String eventString = m_eventStrings.get(eventCode);
207 return eventString != null ? getEventMethods(eventString) : null;
208 }
209
210 /**
203 */
204 protected List<Method> getEventMethods(int eventCode) {
205 String eventString = m_eventStrings.get(eventCode);
206
207 if (eventString != null) {
208 return getEventMethods(eventString);
209 } else {
210 return null;
211 }
212 }
213
214 /**
211215 * INTERNAL:
212216 */
213217 protected List<Method> getEventMethods(String event) {
349353
350354 /**
351355 * INTERNAL:
352 * Return true if listener has a lifecycle callback method that is
353 * overridden in a subclass.
354 */
355 public boolean isOverriddenEvent(DescriptorEvent event, List<DescriptorEventManager> eventManagers) {
356 int eventCode = event.getEventCode();
357 String forSubclass = event.getDescriptor().getJavaClassName();
358 Map<Integer, Boolean> subClassMap = m_overriddenEvents.get(forSubclass);
359
360 // If we haven't built an overridden events map for this subclass, do so now.
361 if (subClassMap == null) {
362 subClassMap = new ConcurrentHashMap<>();
363 }
364
365 // Now check the individual events for this subclass.
356 * Return true if listener has a lifecycle callback method that is
357 * overridden in a subclass.
358 */
359 public boolean isOverriddenEvent(DescriptorEvent event, Vector eventManagers) {
360 int eventCode = event.getEventCode();
361 String forSubclass = event.getDescriptor().getJavaClassName();
362 Hashtable<Integer, Boolean> subClassMap = m_overriddenEvents.get(forSubclass);
363
364 // If we haven't built an overridden events map for this subclass, do so now.
365 if (subClassMap == null) {
366 subClassMap = new Hashtable<Integer, Boolean>();
367 }
368
369 // Now check the individual events for this subclass.
366370 if (! subClassMap.containsKey(eventCode)) {
367371 boolean hasOverrides = false;
368 if (hasEventMethods(eventCode)) {
369 List<Method> eventMethods = getEventMethods(eventCode);
370 for (Method eventMethod : eventMethods) {
371 for (DescriptorEventManager eventManager : eventManagers) {
372 EntityListener childListener = (EntityListener) eventManager.getEntityEventListener();
373
374 // We can't override ourself ...
372 if (hasEventMethods(eventCode)) {
373 List<Method> eventMethods = getEventMethods(eventCode);
374 for (Method eventMethod : eventMethods) {
375 for (DescriptorEventManager eventManager : (Vector<DescriptorEventManager>) eventManagers) {
376 EntityListener childListener = (EntityListener) eventManager.getEntityEventListener();
377
378 // We can't override ourself ...
375379 if (childListener == this) {
376380 break;
377381 } else {
00 /*******************************************************************************
1 * Copyright (c) 2012, 2017 Oracle and/or its affiliates. All rights reserved.
1 * Copyright (c) 2012, 2019 Oracle and/or its affiliates. All rights reserved.
22 * This program and the accompanying materials are made available under the
33 * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
44 * which accompanies this distribution.
1010 * Oracle - initial API and implementation
1111 * 08/01/2012-2.5 Chris Delahunt
1212 * - 371950: Metadata caching
13 * 12/14/2017-2.6.6 Tomas Kraus
14 * - 291546: Performance degradation due to usage of Vector in DescriptorEventManager
1513 ******************************************************************************/
1614 package org.eclipse.persistence.internal.jpa.metadata.listeners;
1715
1917 import java.security.AccessController;
2018 import java.security.PrivilegedActionException;
2119 import java.util.ArrayList;
20 import java.util.Hashtable;
2221 import java.util.List;
23 import java.util.Map;
24 import java.util.concurrent.ConcurrentHashMap;
2522
2623 import org.eclipse.persistence.descriptors.ClassDescriptor;
2724 import org.eclipse.persistence.descriptors.DescriptorEventListener;
3936
4037 public transient DescriptorEventListener listener;
4138
42 public Map<String,java.util.List<MethodSerialImpl>> serializableMethods;
39 public java.util.Hashtable<String,java.util.List<MethodSerialImpl>> serializableMethods;
4340
4441 public void setIsDefaultListener(Boolean isDefaultListener) {
4542 this.isDefaultListener = isDefaultListener;
105102 return entityListenerClassInstance;
106103 }
107104
108 public void convertToSerializableMethods(Map<String, List<Method>> methods) {
109 this.serializableMethods = new ConcurrentHashMap<>();
105 public void convertToSerializableMethods(java.util.Hashtable<String,java.util.List<Method>> methods) {
106 this.serializableMethods = new java.util.Hashtable();
110107 for (String event: methods.keySet()){
111108 java.util.List<Method> methodList = methods.get(event);
112109 java.util.List<MethodSerialImpl> newMethodList = new java.util.ArrayList();
165162 * @param loader
166163 * @return
167164 */
168 public Map<String,java.util.List<Method>> convertToMethods(ClassLoader loader) {
169 Map<String,java.util.List<Method>> table = new ConcurrentHashMap<>();
165 public java.util.Hashtable<String,java.util.List<Method>> convertToMethods(ClassLoader loader) {
166 java.util.Hashtable<String,java.util.List<Method>> table = new java.util.Hashtable();
170167 for (String event: serializableMethods.keySet()){
171168 java.util.List<MethodSerialImpl> methodList = serializableMethods.get(event);
172169 java.util.List<Method> newMethodList = new java.util.ArrayList();
183180 return table;
184181 }
185182
186 public Map<String,java.util.List<MethodSerialImpl>> getMethods() {
183 public java.util.Hashtable<String,java.util.List<MethodSerialImpl>> getMethods() {
187184 if (serializableMethods == null) {
188 serializableMethods = new ConcurrentHashMap<String, List<MethodSerialImpl>>();
185 serializableMethods = new Hashtable<String, List<MethodSerialImpl>>();
189186 }
190187 return serializableMethods;
191188 }
2727 import org.eclipse.persistence.internal.libraries.asm.MethodVisitor;
2828 import org.eclipse.persistence.internal.libraries.asm.Opcodes;
2929 import org.eclipse.persistence.internal.libraries.asm.Type;
30 import org.eclipse.persistence.internal.logging.StdErrLogger;
31 import org.eclipse.persistence.logging.SessionLog;
3032
3133 /**
3234 * INTERNAL: Weaves classes to allow them to support EclipseLink indirection.
917919 * "city") { this.city = (String)city; } }
918920 */
919921 public void addPersistenceGetSet(ClassDetails classDetails) {
922 // PERF: Is finest logging turned on?
923 final boolean shouldLogFinest = StdErrLogger.shouldLog(SessionLog.FINEST, SessionLog.WEAVER);
920924 // create the _persistence_get() method
925 if (shouldLogFinest) {
926 StdErrLogger.log(SessionLog.FINEST, SessionLog.WEAVER, "class_weaver_add_get_set_add_get", classDetails.getClassName());
927 }
921928 MethodVisitor cv_get = cv.visitMethod(ACC_PUBLIC, "_persistence_get", "(Ljava/lang/String;)Ljava/lang/Object;", null, null);
922929
923930 Label label = null;
962969 cv_get.visitMaxs(0, 0);
963970
964971 // create the _persistence_set() method
972 if (shouldLogFinest) {
973 StdErrLogger.log(SessionLog.FINEST, SessionLog.WEAVER, "class_weaver_add_get_set_add_set", classDetails.getClassName());
974 }
965975 MethodVisitor cv_set = cv.visitMethod(ACC_PUBLIC, "_persistence_set", "(Ljava/lang/String;Ljava/lang/Object;)V", null, null);
966976
967977 label = null;
13581368 }
13591369
13601370 /**
1361 * Visit the end of the class byte codes. Add any new methods or variables
1362 * to the end.
1371 * Visit the end of the class byte codes. Add any new methods or variables to the end.
13631372 */
13641373 public void visitEnd() {
1374 // PERF: Is finest logging turned on?
1375 final boolean shouldLogFinest = StdErrLogger.shouldLog(SessionLog.FINEST, SessionLog.WEAVER);
13651376 if (!alreadyWeaved) {
1377 if (shouldLogFinest) {
1378 StdErrLogger.log(
1379 SessionLog.FINEST, SessionLog.WEAVER, "class_weaver_visit_end_do", classDetails.getClassName());
1380 }
13661381 if (this.classDetails.shouldWeaveInternal()) {
13671382
13681383 // Add a persistence and shallow clone method.
14411456 addFetchGroupMethods(this.classDetails);
14421457 }
14431458 }
1459 } else if (shouldLogFinest) {
1460 StdErrLogger.log(SessionLog.FINEST, SessionLog.WEAVER, "class_weaver_visit_end_skip", classDetails.getClassName());
14441461 }
14451462 if (classDetails.shouldWeaveREST() && classDetails.getSuperClassDetails() == null) {
14461463 weavedRest = true;
2828 import org.eclipse.persistence.internal.libraries.asm.ClassVisitor;
2929 import org.eclipse.persistence.internal.libraries.asm.ClassWriter;
3030 import org.eclipse.persistence.internal.libraries.asm.commons.SerialVersionUIDAdder;
31 import org.eclipse.persistence.internal.logging.StdErrLogger;
3132 import org.eclipse.persistence.internal.security.PrivilegedAccessHelper;
3233 import org.eclipse.persistence.internal.security.PrivilegedGetClassLoaderFromCurrentThread;
3334 import org.eclipse.persistence.internal.sessions.AbstractSession;
4243 */
4344 public class PersistenceWeaver implements ClassTransformer {
4445
45 protected Session session; // for logging
4646 /** Class name in JVM '/' format to {@link ClassDetails} map. */
47 protected Map classDetailsMap;
47 protected Map<String, ClassDetails> classDetailsMap;
4848
4949 /**
5050 * INTERNAL:
5151 * Creates an instance of dynamic byte code weaver.
52 * @param session EclipseLink session.
52 * @param session EclipseLink session (not used so {@code null} value is OK).
5353 * @param classDetailsMap Class name to {@link ClassDetails} map.
54 */
55 public PersistenceWeaver(final Session session, final Map classDetailsMap) {
56 this.session = session;
54 * @deprecated Session instance is no longer needed for logging. Will be removed in 2.8.
55 */
56 public PersistenceWeaver(final Session session, final Map<String, ClassDetails> classDetailsMap) {
5757 this.classDetailsMap = classDetailsMap;
5858 }
5959
6060 /**
6161 * INTERNAL:
62 * Creates an instance of dynamic byte code weaver.
63 * @param classDetailsMap Class name to {@link ClassDetails} map.
64 * @since 2.7
65 */
66 public PersistenceWeaver(final Map<String, ClassDetails> classDetailsMap) {
67 this.classDetailsMap = classDetailsMap;
68 }
69
70 /**
71 * INTERNAL:
6272 * Allow the weaver to be clear to release its referenced memory.
63 * This is require because the class loader reference to the transformer will never gc.
73 * This is required because the class loader reference to the transformer will never gc.
6474 */
6575 public void clear() {
66 this.session = null;
6776 this.classDetailsMap = null;
6877 }
6978
7281 * Get Class name in JVM '/' format to {@link ClassDetails} map.
7382 * @return Class name in JVM '/' format to {@link ClassDetails} map.
7483 */
75 public Map getClassDetailsMap() {
84 public Map<String, ClassDetails> getClassDetailsMap() {
7685 return classDetailsMap;
7786 }
7887
79 // @Override: well, not precisely. I wanted the code to be 1.4 compatible,
80 // so the method is written without any Generic type <T>'s in the signature
8188 /**
8289 * INTERNAL:
8390 * Perform dynamic byte code weaving of class.
8491 * @param loader The defining loader of the class to be transformed, may be {@code null}
8592 * if the bootstrap loader.
86 * @param className The name of the class in the internal form of fully qualified class and interface names.
93 * @param className The name of the class in the internal form of fully qualified class and interface
94 * names.
8795 * @param classBeingRedefined If this is a redefine, the class being redefined, otherwise {@code null}.
8896 * @param protectionDomain The protection domain of the class being defined or redefined.
8997 * @param classfileBuffer The input byte buffer in class file format (must not be modified).
90 * @return A well-formed class file buffer (the result of the transform), or {@code null} if no transform is performed
98 * @return A well-formed class file buffer (the result of the transform), or {@code null} if no transform
99 * is performed.
91100 */
92101 @Override
93102 public byte[] transform(final ClassLoader loader, final String className,
94103 final Class classBeingRedefined, final ProtectionDomain protectionDomain,
95104 final byte[] classfileBuffer) throws IllegalClassFormatException {
96105 // PERF: Is finest logging on weaving turned on?
97 final boolean shouldLogFinest = ((AbstractSession)session).shouldLog(SessionLog.FINEST, SessionLog.WEAVER);
106 final boolean shouldLogFinest = StdErrLogger.shouldLog(SessionLog.FINEST, SessionLog.WEAVER);
98107 final Map classDetailsMap = this.classDetailsMap;
99 final Session session = this.session;
100108 // Check if cleared already.
101 if ((classDetailsMap == null) || (session == null)) {
109 if (classDetailsMap == null) {
102110 return null;
103111 }
104112 try {
112120
113121 if (classDetails != null) {
114122 if (shouldLogFinest) {
115 ((AbstractSession)session).log(SessionLog.FINEST, SessionLog.WEAVER, "begin_weaving_class", className);
123 StdErrLogger.log(SessionLog.FINEST, SessionLog.WEAVER, "begin_weaving_class", className);
116124 }
117125 final ClassReader classReader = new ClassReader(classfileBuffer);
118 ClassWriter classWriter = null;
119 final String introspectForHierarchy = System.getProperty(SystemProperties.WEAVING_REFLECTIVE_INTROSPECTION, null);
120 if (introspectForHierarchy != null) {
121 classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
122 } else {
123 classWriter = new ComputeClassWriter(loader, ClassWriter.COMPUTE_FRAMES);
126 final String reflectiveIntrospectionProperty =
127 PrivilegedAccessHelper.getSystemProperty(SystemProperties.WEAVING_REFLECTIVE_INTROSPECTION);
128 final ClassWriter classWriter = reflectiveIntrospectionProperty != null
129 ? new ClassWriter(ClassWriter.COMPUTE_FRAMES)
130 : new ComputeClassWriter(loader, ClassWriter.COMPUTE_FRAMES);
131 if (shouldLogFinest) {
132 ClassLoader contextClassLoader;
133 if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()) {
134 try {
135 contextClassLoader = AccessController.doPrivileged(
136 new PrivilegedGetClassLoaderFromCurrentThread());
137 } catch (PrivilegedActionException ex) {
138 throw (RuntimeException) ex.getCause();
139 }
140 } else {
141 contextClassLoader = Thread.currentThread().getContextClassLoader();
142 }
143 if (reflectiveIntrospectionProperty != null) {
144 StdErrLogger.log(SessionLog.FINEST, SessionLog.WEAVER, "weaving_init_class_writer",
145 className, Integer.toHexString(System.identityHashCode(contextClassLoader)));
146 } else {
147 StdErrLogger.log(SessionLog.FINEST, SessionLog.WEAVER, "weaving_init_compute_class_writer",
148 className, Integer.toHexString(System.identityHashCode(contextClassLoader)),
149 loader != null ? Integer.toHexString(System.identityHashCode(loader)) : "null");
150 }
124151 }
125152 final ClassWeaver classWeaver = new ClassWeaver(classWriter, classDetails);
126153 final ClassVisitor sv = new SerialVersionUIDAdder(classWeaver);
127154 classReader.accept(sv, 0);
128155 if (classWeaver.alreadyWeaved) {
129156 if (shouldLogFinest) {
130 ((AbstractSession)session).log(SessionLog.FINEST, SessionLog.WEAVER, "end_weaving_class", className);
157 StdErrLogger.log(SessionLog.FINEST, SessionLog.WEAVER, "end_weaving_class", className);
131158 }
132159 return null;
133160 }
134161 if (classWeaver.weaved) {
135162 final byte[] bytes = classWriter.toByteArray();
136 final String outputPath = System.getProperty(SystemProperties.WEAVING_OUTPUT_PATH, "");
163 final String outputPath =
164 PrivilegedAccessHelper.getSystemProperty(SystemProperties.WEAVING_OUTPUT_PATH, "");
137165
138166 if (!outputPath.equals("")) {
139167 Helper.outputClassFile(className, bytes, outputPath);
141169 // PERF: Don't execute this set of if statements with logging turned off.
142170 if (shouldLogFinest) {
143171 if (classWeaver.weavedPersistenceEntity) {
144 ((AbstractSession)session).log(SessionLog.FINEST, SessionLog.WEAVER, "weaved_persistenceentity", className);
172 StdErrLogger.log(
173 SessionLog.FINEST, SessionLog.WEAVER, "weaved_persistenceentity", className);
145174 }
146175 if (classWeaver.weavedChangeTracker) {
147 ((AbstractSession)session).log(SessionLog.FINEST, SessionLog.WEAVER, "weaved_changetracker", className);
176 StdErrLogger.log(SessionLog.FINEST, SessionLog.WEAVER, "weaved_changetracker", className);
148177 }
149178 if (classWeaver.weavedLazy) {
150 ((AbstractSession)session).log(SessionLog.FINEST, SessionLog.WEAVER, "weaved_lazy", className);
179 StdErrLogger.log(SessionLog.FINEST, SessionLog.WEAVER, "weaved_lazy", className);
151180 }
152181 if (classWeaver.weavedFetchGroups) {
153 ((AbstractSession)session).log(SessionLog.FINEST, SessionLog.WEAVER, "weaved_fetchgroups", className);
182 StdErrLogger.log(SessionLog.FINEST, SessionLog.WEAVER, "weaved_fetchgroups", className);
154183 }
155184 if (classWeaver.weavedRest) {
156 ((AbstractSession)session).log(SessionLog.FINEST, SessionLog.WEAVER, "weaved_rest", className);
157 }
158 ((AbstractSession)session).log(SessionLog.FINEST, SessionLog.WEAVER, "end_weaving_class", className);
185 StdErrLogger.log(SessionLog.FINEST, SessionLog.WEAVER, "weaved_rest", className);
186 }
187 StdErrLogger.log(SessionLog.FINEST, SessionLog.WEAVER, "end_weaving_class", className);
159188 }
160189 return bytes;
161190 }
162191 if (shouldLogFinest) {
163 ((AbstractSession)session).log(SessionLog.FINEST, SessionLog.WEAVER, "end_weaving_class", className);
192 StdErrLogger.log(SessionLog.FINEST, SessionLog.WEAVER, "end_weaving_class", className);
164193 }
165194 } else {
166195 if (shouldLogFinest) {
167 ((AbstractSession)session).log(SessionLog.FINEST, SessionLog.WEAVER, "transform_missing_class_details", className);
196 StdErrLogger.log(
197 SessionLog.FINEST, SessionLog.WEAVER, "transform_missing_class_details", className);
168198 }
169199 }
170200 } catch (Throwable exception) {
171 ((AbstractSession)session).log(SessionLog.WARNING, SessionLog.WEAVER, "exception_while_weaving", new Object[] {className, exception.getLocalizedMessage()});
172 if (shouldLogFinest) {
173 ((AbstractSession)session).logThrowable(SessionLog.FINEST, SessionLog.WEAVER, exception);
201 if (StdErrLogger.shouldLog(SessionLog.WARNING, SessionLog.WEAVER)) {
202 StdErrLogger.log(SessionLog.WARNING, SessionLog.WEAVER,
203 "exception_while_weaving", new Object[] {exception, className});
204 if (shouldLogFinest) {
205 StdErrLogger.logThrowable(SessionLog.FINEST, SessionLog.WEAVER, exception);
206 }
174207 }
175208 }
176209 if (shouldLogFinest) {
177 ((AbstractSession)session).log(SessionLog.FINEST, SessionLog.WEAVER, "transform_existing_class_bytes", className);
178 }
179 return null; // returning null means 'use existing class bytes'
180 }
181
182 // same as in org.eclipse.persistence.internal.helper.Helper, but uses
183 // '/' slash as delimiter, not '.'
210 StdErrLogger.log(SessionLog.FINEST, SessionLog.WEAVER, "transform_existing_class_bytes", className);
211 }
212 // Returning null means 'use existing class bytes'.
213 return null;
214 }
215
184216 /**
185217 * INTERNAL:
186218 * Returns an unqualified class name from the specified class name.
198230 }
199231 return "";
200232 }
233
201234 }
137137 }
138138
139139 public PersistenceWeaver buildPersistenceWeaver() {
140 return new PersistenceWeaver(session, classDetailsMap);
140 return new PersistenceWeaver(classDetailsMap);
141141 }
142142
143143 /**
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm;
3028
3129 /**
32 * A visitor to visit a Java annotation. The methods of this class must be
33 * called in the following order: ( <tt>visit</tt> | <tt>visitEnum</tt> |
34 * <tt>visitAnnotation</tt> | <tt>visitArray</tt> )* <tt>visitEnd</tt>.
35 *
30 * A visitor to visit a Java annotation. The methods of this class must be called in the following
31 * order: ( <tt>visit</tt> | <tt>visitEnum</tt> | <tt>visitAnnotation</tt> | <tt>visitArray</tt> )*
32 * <tt>visitEnd</tt>.
33 *
3634 * @author Eric Bruneton
3735 * @author Eugene Kuleshov
3836 */
3937 public abstract class AnnotationVisitor {
4038
41 /**
42 * The ASM API version implemented by this visitor. The value of this field
43 * must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
44 */
45 protected final int api;
39 /**
40 * The ASM API version implemented by this visitor. The value of this field must be one of {@link
41 * Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7_EXPERIMENTAL}.
42 */
43 protected final int api;
4644
47 /**
48 * The annotation visitor to which this visitor must delegate method calls.
49 * May be null.
50 */
51 protected AnnotationVisitor av;
45 /** The annotation visitor to which this visitor must delegate method calls. May be null. */
46 protected AnnotationVisitor av;
5247
53 /**
54 * Constructs a new {@link AnnotationVisitor}.
55 *
56 * @param api
57 * the ASM API version implemented by this visitor. Must be one
58 * of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
59 */
60 public AnnotationVisitor(final int api) {
61 this(api, null);
48 /**
49 * Constructs a new {@link AnnotationVisitor}.
50 *
51 * @param api the ASM API version implemented by this visitor. Must be one of {@link
52 * Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link
53 * Opcodes#ASM7_EXPERIMENTAL}.
54 */
55 public AnnotationVisitor(final int api) {
56 this(api, null);
57 }
58
59 /**
60 * Constructs a new {@link AnnotationVisitor}.
61 *
62 * @param api the ASM API version implemented by this visitor. Must be one of {@link
63 * Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link
64 * Opcodes#ASM7_EXPERIMENTAL}.
65 * @param annotationVisitor the annotation visitor to which this visitor must delegate method
66 * calls. May be null.
67 */
68 public AnnotationVisitor(final int api, final AnnotationVisitor annotationVisitor) {
69 if (api != Opcodes.ASM6
70 && api != Opcodes.ASM5
71 && api != Opcodes.ASM4
72 && api != Opcodes.ASM7_EXPERIMENTAL) {
73 throw new IllegalArgumentException();
6274 }
75 this.api = api;
76 this.av = annotationVisitor;
77 }
6378
64 /**
65 * Constructs a new {@link AnnotationVisitor}.
66 *
67 * @param api
68 * the ASM API version implemented by this visitor. Must be one
69 * of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
70 * @param av
71 * the annotation visitor to which this visitor must delegate
72 * method calls. May be null.
73 */
74 public AnnotationVisitor(final int api, final AnnotationVisitor av) {
75 if (api < Opcodes.ASM4 || api > Opcodes.ASM6) {
76 throw new IllegalArgumentException();
77 }
78 this.api = api;
79 this.av = av;
79 /**
80 * Visits a primitive value of the annotation.
81 *
82 * @param name the value name.
83 * @param value the actual value, whose type must be {@link Byte}, {@link Boolean}, {@link
84 * Character}, {@link Short}, {@link Integer} , {@link Long}, {@link Float}, {@link Double},
85 * {@link String} or {@link Type} of {@link Type#OBJECT} or {@link Type#ARRAY} sort. This
86 * value can also be an array of byte, boolean, short, char, int, long, float or double values
87 * (this is equivalent to using {@link #visitArray} and visiting each array element in turn,
88 * but is more convenient).
89 */
90 public void visit(final String name, final Object value) {
91 if (av != null) {
92 av.visit(name, value);
8093 }
94 }
8195
82 /**
83 * Visits a primitive value of the annotation.
84 *
85 * @param name
86 * the value name.
87 * @param value
88 * the actual value, whose type must be {@link Byte},
89 * {@link Boolean}, {@link Character}, {@link Short},
90 * {@link Integer} , {@link Long}, {@link Float}, {@link Double},
91 * {@link String} or {@link Type} or OBJECT or ARRAY sort. This
92 * value can also be an array of byte, boolean, short, char, int,
93 * long, float or double values (this is equivalent to using
94 * {@link #visitArray visitArray} and visiting each array element
95 * in turn, but is more convenient).
96 */
97 public void visit(String name, Object value) {
98 if (av != null) {
99 av.visit(name, value);
100 }
96 /**
97 * Visits an enumeration value of the annotation.
98 *
99 * @param name the value name.
100 * @param descriptor the class descriptor of the enumeration class.
101 * @param value the actual enumeration value.
102 */
103 public void visitEnum(final String name, final String descriptor, final String value) {
104 if (av != null) {
105 av.visitEnum(name, descriptor, value);
101106 }
107 }
102108
103 /**
104 * Visits an enumeration value of the annotation.
105 *
106 * @param name
107 * the value name.
108 * @param desc
109 * the class descriptor of the enumeration class.
110 * @param value
111 * the actual enumeration value.
112 */
113 public void visitEnum(String name, String desc, String value) {
114 if (av != null) {
115 av.visitEnum(name, desc, value);
116 }
109 /**
110 * Visits a nested annotation value of the annotation.
111 *
112 * @param name the value name.
113 * @param descriptor the class descriptor of the nested annotation class.
114 * @return a visitor to visit the actual nested annotation value, or <tt>null</tt> if this visitor
115 * is not interested in visiting this nested annotation. <i>The nested annotation value must
116 * be fully visited before calling other methods on this annotation visitor</i>.
117 */
118 public AnnotationVisitor visitAnnotation(final String name, final String descriptor) {
119 if (av != null) {
120 return av.visitAnnotation(name, descriptor);
117121 }
122 return null;
123 }
118124
119 /**
120 * Visits a nested annotation value of the annotation.
121 *
122 * @param name
123 * the value name.
124 * @param desc
125 * the class descriptor of the nested annotation class.
126 * @return a visitor to visit the actual nested annotation value, or
127 * <tt>null</tt> if this visitor is not interested in visiting this
128 * nested annotation. <i>The nested annotation value must be fully
129 * visited before calling other methods on this annotation
130 * visitor</i>.
131 */
132 public AnnotationVisitor visitAnnotation(String name, String desc) {
133 if (av != null) {
134 return av.visitAnnotation(name, desc);
135 }
136 return null;
125 /**
126 * Visits an array value of the annotation. Note that arrays of primitive types (such as byte,
127 * boolean, short, char, int, long, float or double) can be passed as value to {@link #visit
128 * visit}. This is what {@link ClassReader} does.
129 *
130 * @param name the value name.
131 * @return a visitor to visit the actual array value elements, or <tt>null</tt> if this visitor is
132 * not interested in visiting these values. The 'name' parameters passed to the methods of
133 * this visitor are ignored. <i>All the array values must be visited before calling other
134 * methods on this annotation visitor</i>.
135 */
136 public AnnotationVisitor visitArray(final String name) {
137 if (av != null) {
138 return av.visitArray(name);
137139 }
140 return null;
141 }
138142
139 /**
140 * Visits an array value of the annotation. Note that arrays of primitive
141 * types (such as byte, boolean, short, char, int, long, float or double)
142 * can be passed as value to {@link #visit visit}. This is what
143 * {@link ClassReader} does.
144 *
145 * @param name
146 * the value name.
147 * @return a visitor to visit the actual array value elements, or
148 * <tt>null</tt> if this visitor is not interested in visiting these
149 * values. The 'name' parameters passed to the methods of this
150 * visitor are ignored. <i>All the array values must be visited
151 * before calling other methods on this annotation visitor</i>.
152 */
153 public AnnotationVisitor visitArray(String name) {
154 if (av != null) {
155 return av.visitArray(name);
156 }
157 return null;
143 /** Visits the end of the annotation. */
144 public void visitEnd() {
145 if (av != null) {
146 av.visitEnd();
158147 }
159
160 /**
161 * Visits the end of the annotation.
162 */
163 public void visitEnd() {
164 if (av != null) {
165 av.visitEnd();
166 }
167 }
148 }
168149 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
27 package org.eclipse.persistence.internal.libraries.asm;
28
29 /**
30 * An {@link AnnotationVisitor} that generates a corresponding 'annotation' or 'type_annotation'
31 * structure, as defined in the Java Virtual Machine Specification (JVMS). AnnotationWriter
32 * instances can be chained in a doubly linked list, from which Runtime[In]Visible[Type]Annotations
33 * attributes can be generated with the {@link #putAnnotations} method. Similarly, arrays of such
34 * lists can be used to generate Runtime[In]VisibleParameterAnnotations attributes.
435 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 package org.eclipse.persistence.internal.libraries.asm;
30
31 /**
32 * An {@link AnnotationVisitor} that generates annotations in bytecode form.
33 *
36 * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16">JVMS
37 * 4.7.16</a>
38 * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20">JVMS
39 * 4.7.20</a>
3440 * @author Eric Bruneton
3541 * @author Eugene Kuleshov
3642 */
3743 final class AnnotationWriter extends AnnotationVisitor {
3844
39 /**
40 * The class writer to which this annotation must be added.
41 */
42 private final ClassWriter cw;
43
44 /**
45 * The number of values in this annotation.
46 */
47 private int size;
48
49 /**
50 * <tt>true<tt> if values are named, <tt>false</tt> otherwise. Annotation
51 * writers used for annotation default and annotation arrays use unnamed
52 * values.
53 */
54 private final boolean named;
55
56 /**
57 * The annotation values in bytecode form. This byte vector only contains
58 * the values themselves, i.e. the number of values must be stored as a
59 * unsigned short just before these bytes.
60 */
61 private final ByteVector bv;
62
63 /**
64 * The byte vector to be used to store the number of values of this
65 * annotation. See {@link #bv}.
66 */
67 private final ByteVector parent;
68
69 /**
70 * Where the number of values of this annotation must be stored in
71 * {@link #parent}.
72 */
73 private final int offset;
74
75 /**
76 * Next annotation writer. This field is used to store annotation lists.
77 */
78 AnnotationWriter next;
79
80 /**
81 * Previous annotation writer. This field is used to store annotation lists.
82 */
83 AnnotationWriter prev;
84
85 // ------------------------------------------------------------------------
86 // Constructor
87 // ------------------------------------------------------------------------
88
89 /**
90 * Constructs a new {@link AnnotationWriter}.
91 *
92 * @param cw
93 * the class writer to which this annotation must be added.
94 * @param named
95 * <tt>true<tt> if values are named, <tt>false</tt> otherwise.
96 * @param bv
97 * where the annotation values must be stored.
98 * @param parent
99 * where the number of annotation values must be stored.
100 * @param offset
101 * where in <tt>parent</tt> the number of annotation values must
102 * be stored.
103 */
104 AnnotationWriter(final ClassWriter cw, final boolean named,
105 final ByteVector bv, final ByteVector parent, final int offset) {
106 super(Opcodes.ASM6);
107 this.cw = cw;
108 this.named = named;
109 this.bv = bv;
110 this.parent = parent;
111 this.offset = offset;
112 }
113
114 // ------------------------------------------------------------------------
115 // Implementation of the AnnotationVisitor abstract class
116 // ------------------------------------------------------------------------
117
118 @Override
119 public void visit(final String name, final Object value) {
120 ++size;
121 if (named) {
122 bv.putShort(cw.newUTF8(name));
123 }
124 if (value instanceof String) {
125 bv.put12('s', cw.newUTF8((String) value));
126 } else if (value instanceof Byte) {
127 bv.put12('B', cw.newInteger(((Byte) value).byteValue()).index);
128 } else if (value instanceof Boolean) {
129 int v = ((Boolean) value).booleanValue() ? 1 : 0;
130 bv.put12('Z', cw.newInteger(v).index);
131 } else if (value instanceof Character) {
132 bv.put12('C', cw.newInteger(((Character) value).charValue()).index);
133 } else if (value instanceof Short) {
134 bv.put12('S', cw.newInteger(((Short) value).shortValue()).index);
135 } else if (value instanceof Type) {
136 bv.put12('c', cw.newUTF8(((Type) value).getDescriptor()));
137 } else if (value instanceof byte[]) {
138 byte[] v = (byte[]) value;
139 bv.put12('[', v.length);
140 for (int i = 0; i < v.length; i++) {
141 bv.put12('B', cw.newInteger(v[i]).index);
142 }
143 } else if (value instanceof boolean[]) {
144 boolean[] v = (boolean[]) value;
145 bv.put12('[', v.length);
146 for (int i = 0; i < v.length; i++) {
147 bv.put12('Z', cw.newInteger(v[i] ? 1 : 0).index);
148 }
149 } else if (value instanceof short[]) {
150 short[] v = (short[]) value;
151 bv.put12('[', v.length);
152 for (int i = 0; i < v.length; i++) {
153 bv.put12('S', cw.newInteger(v[i]).index);
154 }
155 } else if (value instanceof char[]) {
156 char[] v = (char[]) value;
157 bv.put12('[', v.length);
158 for (int i = 0; i < v.length; i++) {
159 bv.put12('C', cw.newInteger(v[i]).index);
160 }
161 } else if (value instanceof int[]) {
162 int[] v = (int[]) value;
163 bv.put12('[', v.length);
164 for (int i = 0; i < v.length; i++) {
165 bv.put12('I', cw.newInteger(v[i]).index);
166 }
167 } else if (value instanceof long[]) {
168 long[] v = (long[]) value;
169 bv.put12('[', v.length);
170 for (int i = 0; i < v.length; i++) {
171 bv.put12('J', cw.newLong(v[i]).index);
172 }
173 } else if (value instanceof float[]) {
174 float[] v = (float[]) value;
175 bv.put12('[', v.length);
176 for (int i = 0; i < v.length; i++) {
177 bv.put12('F', cw.newFloat(v[i]).index);
178 }
179 } else if (value instanceof double[]) {
180 double[] v = (double[]) value;
181 bv.put12('[', v.length);
182 for (int i = 0; i < v.length; i++) {
183 bv.put12('D', cw.newDouble(v[i]).index);
184 }
185 } else {
186 Item i = cw.newConstItem(value);
187 bv.put12(".s.IFJDCS".charAt(i.type), i.index);
188 }
189 }
190
191 @Override
192 public void visitEnum(final String name, final String desc,
193 final String value) {
194 ++size;
195 if (named) {
196 bv.putShort(cw.newUTF8(name));
197 }
198 bv.put12('e', cw.newUTF8(desc)).putShort(cw.newUTF8(value));
199 }
200
201 @Override
202 public AnnotationVisitor visitAnnotation(final String name,
203 final String desc) {
204 ++size;
205 if (named) {
206 bv.putShort(cw.newUTF8(name));
207 }
208 // write tag and type, and reserve space for values count
209 bv.put12('@', cw.newUTF8(desc)).putShort(0);
210 return new AnnotationWriter(cw, true, bv, bv, bv.length - 2);
211 }
212
213 @Override
214 public AnnotationVisitor visitArray(final String name) {
215 ++size;
216 if (named) {
217 bv.putShort(cw.newUTF8(name));
218 }
219 // write tag, and reserve space for array size
220 bv.put12('[', 0);
221 return new AnnotationWriter(cw, false, bv, bv, bv.length - 2);
222 }
223
224 @Override
225 public void visitEnd() {
226 if (parent != null) {
227 byte[] data = parent.data;
228 data[offset] = (byte) (size >>> 8);
229 data[offset + 1] = (byte) size;
230 }
231 }
232
233 // ------------------------------------------------------------------------
234 // Utility methods
235 // ------------------------------------------------------------------------
236
237 /**
238 * Returns the size of this annotation writer list.
239 *
240 * @return the size of this annotation writer list.
241 */
242 int getSize() {
243 int size = 0;
244 AnnotationWriter aw = this;
245 while (aw != null) {
246 size += aw.bv.length;
247 aw = aw.next;
248 }
249 return size;
250 }
251
252 /**
253 * Puts the annotations of this annotation writer list into the given byte
254 * vector.
255 *
256 * @param out
257 * where the annotations must be put.
258 */
259 void put(final ByteVector out) {
260 int n = 0;
261 int size = 2;
262 AnnotationWriter aw = this;
263 AnnotationWriter last = null;
264 while (aw != null) {
265 ++n;
266 size += aw.bv.length;
267 aw.visitEnd(); // in case user forgot to call visitEnd
268 aw.prev = last;
269 last = aw;
270 aw = aw.next;
271 }
272 out.putInt(size);
273 out.putShort(n);
274 aw = last;
275 while (aw != null) {
276 out.putByteArray(aw.bv.data, 0, aw.bv.length);
277 aw = aw.prev;
278 }
279 }
280
281 /**
282 * Puts the given annotation lists into the given byte vector.
283 *
284 * @param panns
285 * an array of annotation writer lists.
286 * @param off
287 * index of the first annotation to be written.
288 * @param out
289 * where the annotations must be put.
290 */
291 static void put(final AnnotationWriter[] panns, final int off,
292 final ByteVector out) {
293 int size = 1 + 2 * (panns.length - off);
294 for (int i = off; i < panns.length; ++i) {
295 size += panns[i] == null ? 0 : panns[i].getSize();
296 }
297 out.putInt(size).putByte(panns.length - off);
298 for (int i = off; i < panns.length; ++i) {
299 AnnotationWriter aw = panns[i];
300 AnnotationWriter last = null;
301 int n = 0;
302 while (aw != null) {
303 ++n;
304 aw.visitEnd(); // in case user forgot to call visitEnd
305 aw.prev = last;
306 last = aw;
307 aw = aw.next;
308 }
309 out.putShort(n);
310 aw = last;
311 while (aw != null) {
312 out.putByteArray(aw.bv.data, 0, aw.bv.length);
313 aw = aw.prev;
314 }
315 }
316 }
317
318 /**
319 * Puts the given type reference and type path into the given bytevector.
320 * LOCAL_VARIABLE and RESOURCE_VARIABLE target types are not supported.
321 *
322 * @param typeRef
323 * a reference to the annotated type. See {@link TypeReference}.
324 * @param typePath
325 * the path to the annotated type argument, wildcard bound, array
326 * element type, or static inner type within 'typeRef'. May be
327 * <tt>null</tt> if the annotation targets 'typeRef' as a whole.
328 * @param out
329 * where the type reference and type path must be put.
330 */
331 static void putTarget(int typeRef, TypePath typePath, ByteVector out) {
332 switch (typeRef >>> 24) {
333 case 0x00: // CLASS_TYPE_PARAMETER
334 case 0x01: // METHOD_TYPE_PARAMETER
335 case 0x16: // METHOD_FORMAL_PARAMETER
336 out.putShort(typeRef >>> 16);
337 break;
338 case 0x13: // FIELD
339 case 0x14: // METHOD_RETURN
340 case 0x15: // METHOD_RECEIVER
341 out.putByte(typeRef >>> 24);
342 break;
343 case 0x47: // CAST
344 case 0x48: // CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
345 case 0x49: // METHOD_INVOCATION_TYPE_ARGUMENT
346 case 0x4A: // CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
347 case 0x4B: // METHOD_REFERENCE_TYPE_ARGUMENT
348 out.putInt(typeRef);
349 break;
350 // case 0x10: // CLASS_EXTENDS
351 // case 0x11: // CLASS_TYPE_PARAMETER_BOUND
352 // case 0x12: // METHOD_TYPE_PARAMETER_BOUND
353 // case 0x17: // THROWS
354 // case 0x42: // EXCEPTION_PARAMETER
355 // case 0x43: // INSTANCEOF
356 // case 0x44: // NEW
357 // case 0x45: // CONSTRUCTOR_REFERENCE
358 // case 0x46: // METHOD_REFERENCE
359 default:
360 out.put12(typeRef >>> 24, (typeRef & 0xFFFF00) >> 8);
361 break;
362 }
363 if (typePath == null) {
364 out.putByte(0);
365 } else {
366 int length = typePath.b[typePath.offset] * 2 + 1;
367 out.putByteArray(typePath.b, typePath.offset, length);
368 }
369 }
45 /** Where the constants used in this AnnotationWriter must be stored. */
46 private final SymbolTable symbolTable;
47
48 /**
49 * Whether values are named or not. AnnotationWriter instances used for annotation default and
50 * annotation arrays use unnamed values (i.e. they generate an 'element_value' structure for each
51 * value, instead of an element_name_index followed by an element_value).
52 */
53 private final boolean useNamedValues;
54
55 /**
56 * The 'annotation' or 'type_annotation' JVMS structure corresponding to the annotation values
57 * visited so far. All the fields of these structures, except the last one - the
58 * element_value_pairs array, must be set before this ByteVector is passed to the constructor
59 * (num_element_value_pairs can be set to 0, it is reset to the correct value in {@link
60 * #visitEnd()}). The element_value_pairs array is filled incrementally in the various visit()
61 * methods.
62 *
63 * <p>Note: as an exception to the above rules, for AnnotationDefault attributes (which contain a
64 * single element_value by definition), this ByteVector is initially empty when passed to the
65 * constructor, and {@link #numElementValuePairsOffset} is set to -1.
66 */
67 private final ByteVector annotation;
68
69 /**
70 * The offset in {@link #annotation} where {@link #numElementValuePairs} must be stored (or -1 for
71 * the case of AnnotationDefault attributes).
72 */
73 private final int numElementValuePairsOffset;
74
75 /** The number of element value pairs visited so far. */
76 private int numElementValuePairs;
77
78 /**
79 * The previous AnnotationWriter. This field is used to store the list of annotations of a
80 * Runtime[In]Visible[Type]Annotations attribute. It is unused for nested or array annotations
81 * (annotation values of annotation type), or for AnnotationDefault attributes.
82 */
83 private final AnnotationWriter previousAnnotation;
84
85 /**
86 * The next AnnotationWriter. This field is used to store the list of annotations of a
87 * Runtime[In]Visible[Type]Annotations attribute. It is unused for nested or array annotations
88 * (annotation values of annotation type), or for AnnotationDefault attributes.
89 */
90 private AnnotationWriter nextAnnotation;
91
92 // -----------------------------------------------------------------------------------------------
93 // Constructors
94 // -----------------------------------------------------------------------------------------------
95
96 /**
97 * Constructs a new {@link AnnotationWriter}.
98 *
99 * @param symbolTable where the constants used in this AnnotationWriter must be stored.
100 * @param useNamedValues whether values are named or not. AnnotationDefault and annotation arrays
101 * use unnamed values.
102 * @param annotation where the 'annotation' or 'type_annotation' JVMS structure corresponding to
103 * the visited content must be stored. This ByteVector must already contain all the fields of
104 * the structure except the last one (the element_value_pairs array).
105 * @param previousAnnotation the previously visited annotation of the
106 * Runtime[In]Visible[Type]Annotations attribute to which this annotation belongs, or null in
107 * other cases (e.g. nested or array annotations).
108 */
109 AnnotationWriter(
110 final SymbolTable symbolTable,
111 final boolean useNamedValues,
112 final ByteVector annotation,
113 final AnnotationWriter previousAnnotation) {
114 super(Opcodes.ASM6);
115 this.symbolTable = symbolTable;
116 this.useNamedValues = useNamedValues;
117 this.annotation = annotation;
118 // By hypothesis, num_element_value_pairs is stored in the last unsigned short of 'annotation'.
119 this.numElementValuePairsOffset = annotation.length == 0 ? -1 : annotation.length - 2;
120 this.previousAnnotation = previousAnnotation;
121 if (previousAnnotation != null) {
122 previousAnnotation.nextAnnotation = this;
123 }
124 }
125
126 /**
127 * Constructs a new {@link AnnotationWriter} using named values.
128 *
129 * @param symbolTable where the constants used in this AnnotationWriter must be stored.
130 * @param annotation where the 'annotation' or 'type_annotation' JVMS structure corresponding to
131 * the visited content must be stored. This ByteVector must already contain all the fields of
132 * the structure except the last one (the element_value_pairs array).
133 * @param previousAnnotation the previously visited annotation of the
134 * Runtime[In]Visible[Type]Annotations attribute to which this annotation belongs, or null in
135 * other cases (e.g. nested or array annotations).
136 */
137 AnnotationWriter(
138 final SymbolTable symbolTable,
139 final ByteVector annotation,
140 final AnnotationWriter previousAnnotation) {
141 this(symbolTable, /* useNamedValues = */ true, annotation, previousAnnotation);
142 }
143
144 // -----------------------------------------------------------------------------------------------
145 // Implementation of the AnnotationVisitor abstract class
146 // -----------------------------------------------------------------------------------------------
147
148 @Override
149 public void visit(final String name, final Object value) {
150 // Case of an element_value with a const_value_index, class_info_index or array_index field.
151 // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.1.
152 ++numElementValuePairs;
153 if (useNamedValues) {
154 annotation.putShort(symbolTable.addConstantUtf8(name));
155 }
156 if (value instanceof String) {
157 annotation.put12('s', symbolTable.addConstantUtf8((String) value));
158 } else if (value instanceof Byte) {
159 annotation.put12('B', symbolTable.addConstantInteger(((Byte) value).byteValue()).index);
160 } else if (value instanceof Boolean) {
161 int booleanValue = ((Boolean) value).booleanValue() ? 1 : 0;
162 annotation.put12('Z', symbolTable.addConstantInteger(booleanValue).index);
163 } else if (value instanceof Character) {
164 annotation.put12('C', symbolTable.addConstantInteger(((Character) value).charValue()).index);
165 } else if (value instanceof Short) {
166 annotation.put12('S', symbolTable.addConstantInteger(((Short) value).shortValue()).index);
167 } else if (value instanceof Type) {
168 annotation.put12('c', symbolTable.addConstantUtf8(((Type) value).getDescriptor()));
169 } else if (value instanceof byte[]) {
170 byte[] byteArray = (byte[]) value;
171 annotation.put12('[', byteArray.length);
172 for (byte byteValue : byteArray) {
173 annotation.put12('B', symbolTable.addConstantInteger(byteValue).index);
174 }
175 } else if (value instanceof boolean[]) {
176 boolean[] booleanArray = (boolean[]) value;
177 annotation.put12('[', booleanArray.length);
178 for (boolean booleanValue : booleanArray) {
179 annotation.put12('Z', symbolTable.addConstantInteger(booleanValue ? 1 : 0).index);
180 }
181 } else if (value instanceof short[]) {
182 short[] shortArray = (short[]) value;
183 annotation.put12('[', shortArray.length);
184 for (short shortValue : shortArray) {
185 annotation.put12('S', symbolTable.addConstantInteger(shortValue).index);
186 }
187 } else if (value instanceof char[]) {
188 char[] charArray = (char[]) value;
189 annotation.put12('[', charArray.length);
190 for (char charValue : charArray) {
191 annotation.put12('C', symbolTable.addConstantInteger(charValue).index);
192 }
193 } else if (value instanceof int[]) {
194 int[] intArray = (int[]) value;
195 annotation.put12('[', intArray.length);
196 for (int intValue : intArray) {
197 annotation.put12('I', symbolTable.addConstantInteger(intValue).index);
198 }
199 } else if (value instanceof long[]) {
200 long[] longArray = (long[]) value;
201 annotation.put12('[', longArray.length);
202 for (long longValue : longArray) {
203 annotation.put12('J', symbolTable.addConstantLong(longValue).index);
204 }
205 } else if (value instanceof float[]) {
206 float[] floatArray = (float[]) value;
207 annotation.put12('[', floatArray.length);
208 for (float floatValue : floatArray) {
209 annotation.put12('F', symbolTable.addConstantFloat(floatValue).index);
210 }
211 } else if (value instanceof double[]) {
212 double[] doubleArray = (double[]) value;
213 annotation.put12('[', doubleArray.length);
214 for (double doubleValue : doubleArray) {
215 annotation.put12('D', symbolTable.addConstantDouble(doubleValue).index);
216 }
217 } else {
218 Symbol symbol = symbolTable.addConstant(value);
219 annotation.put12(".s.IFJDCS".charAt(symbol.tag), symbol.index);
220 }
221 }
222
223 @Override
224 public void visitEnum(final String name, final String descriptor, final String value) {
225 // Case of an element_value with an enum_const_value field.
226 // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.1.
227 ++numElementValuePairs;
228 if (useNamedValues) {
229 annotation.putShort(symbolTable.addConstantUtf8(name));
230 }
231 annotation
232 .put12('e', symbolTable.addConstantUtf8(descriptor))
233 .putShort(symbolTable.addConstantUtf8(value));
234 }
235
236 @Override
237 public AnnotationVisitor visitAnnotation(final String name, final String descriptor) {
238 // Case of an element_value with an annotation_value field.
239 // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.1.
240 ++numElementValuePairs;
241 if (useNamedValues) {
242 annotation.putShort(symbolTable.addConstantUtf8(name));
243 }
244 // Write tag and type_index, and reserve 2 bytes for num_element_value_pairs.
245 annotation.put12('@', symbolTable.addConstantUtf8(descriptor)).putShort(0);
246 return new AnnotationWriter(symbolTable, annotation, null);
247 }
248
249 @Override
250 public AnnotationVisitor visitArray(final String name) {
251 // Case of an element_value with an array_value field.
252 // https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.1
253 ++numElementValuePairs;
254 if (useNamedValues) {
255 annotation.putShort(symbolTable.addConstantUtf8(name));
256 }
257 // Write tag, and reserve 2 bytes for num_values. Here we take advantage of the fact that the
258 // end of an element_value of array type is similar to the end of an 'annotation' structure: an
259 // unsigned short num_values followed by num_values element_value, versus an unsigned short
260 // num_element_value_pairs, followed by num_element_value_pairs { element_name_index,
261 // element_value } tuples. This allows us to use an AnnotationWriter with unnamed values to
262 // visit the array elements. Its num_element_value_pairs will correspond to the number of array
263 // elements and will be stored in what is in fact num_values.
264 annotation.put12('[', 0);
265 return new AnnotationWriter(symbolTable, /* useNamedValues = */ false, annotation, null);
266 }
267
268 @Override
269 public void visitEnd() {
270 if (numElementValuePairsOffset != -1) {
271 byte[] data = annotation.data;
272 data[numElementValuePairsOffset] = (byte) (numElementValuePairs >>> 8);
273 data[numElementValuePairsOffset + 1] = (byte) numElementValuePairs;
274 }
275 }
276
277 // -----------------------------------------------------------------------------------------------
278 // Utility methods
279 // -----------------------------------------------------------------------------------------------
280
281 /**
282 * Returns the size of a Runtime[In]Visible[Type]Annotations attribute containing this annotation
283 * and all its <i>predecessors</i> (see {@link #previousAnnotation}. Also adds the attribute name
284 * to the constant pool of the class (if not null).
285 *
286 * @param attributeName one of "Runtime[In]Visible[Type]Annotations", or null.
287 * @return the size in bytes of a Runtime[In]Visible[Type]Annotations attribute containing this
288 * annotation and all its predecessors. This includes the size of the attribute_name_index and
289 * attribute_length fields.
290 */
291 int computeAnnotationsSize(final String attributeName) {
292 if (attributeName != null) {
293 symbolTable.addConstantUtf8(attributeName);
294 }
295 // The attribute_name_index, attribute_length and num_annotations fields use 8 bytes.
296 int attributeSize = 8;
297 AnnotationWriter annotationWriter = this;
298 while (annotationWriter != null) {
299 attributeSize += annotationWriter.annotation.length;
300 annotationWriter = annotationWriter.previousAnnotation;
301 }
302 return attributeSize;
303 }
304
305 /**
306 * Puts a Runtime[In]Visible[Type]Annotations attribute containing this annotations and all its
307 * <i>predecessors</i> (see {@link #previousAnnotation} in the given ByteVector. Annotations are
308 * put in the same order they have been visited.
309 *
310 * @param attributeNameIndex the constant pool index of the attribute name (one of
311 * "Runtime[In]Visible[Type]Annotations").
312 * @param output where the attribute must be put.
313 */
314 void putAnnotations(final int attributeNameIndex, final ByteVector output) {
315 int attributeLength = 2; // For num_annotations.
316 int numAnnotations = 0;
317 AnnotationWriter annotationWriter = this;
318 AnnotationWriter firstAnnotation = null;
319 while (annotationWriter != null) {
320 // In case the user forgot to call visitEnd().
321 annotationWriter.visitEnd();
322 attributeLength += annotationWriter.annotation.length;
323 numAnnotations++;
324 firstAnnotation = annotationWriter;
325 annotationWriter = annotationWriter.previousAnnotation;
326 }
327 output.putShort(attributeNameIndex);
328 output.putInt(attributeLength);
329 output.putShort(numAnnotations);
330 annotationWriter = firstAnnotation;
331 while (annotationWriter != null) {
332 output.putByteArray(annotationWriter.annotation.data, 0, annotationWriter.annotation.length);
333 annotationWriter = annotationWriter.nextAnnotation;
334 }
335 }
336
337 /**
338 * Returns the size of a Runtime[In]VisibleParameterAnnotations attribute containing all the
339 * annotation lists from the given AnnotationWriter sub-array. Also adds the attribute name to the
340 * constant pool of the class.
341 *
342 * @param attributeName one of "Runtime[In]VisibleParameterAnnotations".
343 * @param annotationWriters an array of AnnotationWriter lists (designated by their <i>last</i>
344 * element).
345 * @param annotableParameterCount the number of elements in annotationWriters to take into account
346 * (elements [0..annotableParameterCount[ are taken into account).
347 * @return the size in bytes of a Runtime[In]VisibleParameterAnnotations attribute corresponding
348 * to the given sub-array of AnnotationWriter lists. This includes the size of the
349 * attribute_name_index and attribute_length fields.
350 */
351 static int computeParameterAnnotationsSize(
352 final String attributeName,
353 final AnnotationWriter[] annotationWriters,
354 final int annotableParameterCount) {
355 // Note: attributeName is added to the constant pool by the call to computeAnnotationsSize
356 // below. This assumes that there is at least one non-null element in the annotationWriters
357 // sub-array (which is ensured by the lazy instantiation of this array in MethodWriter).
358 // The attribute_name_index, attribute_length and num_parameters fields use 7 bytes, and each
359 // element of the parameter_annotations array uses 2 bytes for its num_annotations field.
360 int attributeSize = 7 + 2 * annotableParameterCount;
361 for (int i = 0; i < annotableParameterCount; ++i) {
362 AnnotationWriter annotationWriter = annotationWriters[i];
363 attributeSize +=
364 annotationWriter == null ? 0 : annotationWriter.computeAnnotationsSize(attributeName) - 8;
365 }
366 return attributeSize;
367 }
368
369 /**
370 * Puts a Runtime[In]VisibleParameterAnnotations attribute containing all the annotation lists
371 * from the given AnnotationWriter sub-array in the given ByteVector.
372 *
373 * @param attributeNameIndex constant pool index of the attribute name (one of
374 * Runtime[In]VisibleParameterAnnotations).
375 * @param annotationWriters an array of AnnotationWriter lists (designated by their <i>last</i>
376 * element).
377 * @param annotableParameterCount the number of elements in annotationWriters to put (elements
378 * [0..annotableParameterCount[ are put).
379 * @param output where the attribute must be put.
380 */
381 static void putParameterAnnotations(
382 final int attributeNameIndex,
383 final AnnotationWriter[] annotationWriters,
384 final int annotableParameterCount,
385 final ByteVector output) {
386 // The num_parameters field uses 1 byte, and each element of the parameter_annotations array
387 // uses 2 bytes for its num_annotations field.
388 int attributeLength = 1 + 2 * annotableParameterCount;
389 for (int i = 0; i < annotableParameterCount; ++i) {
390 AnnotationWriter annotationWriter = annotationWriters[i];
391 attributeLength +=
392 annotationWriter == null ? 0 : annotationWriter.computeAnnotationsSize(null) - 8;
393 }
394 output.putShort(attributeNameIndex);
395 output.putInt(attributeLength);
396 output.putByte(annotableParameterCount);
397 for (int i = 0; i < annotableParameterCount; ++i) {
398 AnnotationWriter annotationWriter = annotationWriters[i];
399 AnnotationWriter firstAnnotation = null;
400 int numAnnotations = 0;
401 while (annotationWriter != null) {
402 // In case user the forgot to call visitEnd().
403 annotationWriter.visitEnd();
404 numAnnotations++;
405 firstAnnotation = annotationWriter;
406 annotationWriter = annotationWriter.previousAnnotation;
407 }
408 output.putShort(numAnnotations);
409 annotationWriter = firstAnnotation;
410 while (annotationWriter != null) {
411 output.putByteArray(
412 annotationWriter.annotation.data, 0, annotationWriter.annotation.length);
413 annotationWriter = annotationWriter.nextAnnotation;
414 }
415 }
416 }
370417 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
27 package org.eclipse.persistence.internal.libraries.asm;
28
29 /**
30 * A non standard class, field, method or code attribute, as defined in the Java Virtual Machine
31 * Specification (JVMS).
432 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 package org.eclipse.persistence.internal.libraries.asm;
30
31 /**
32 * A non standard class, field, method or code attribute.
33 *
33 * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7">JVMS
34 * 4.7</a>
35 * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.3">JVMS
36 * 4.7.3</a>
3437 * @author Eric Bruneton
3538 * @author Eugene Kuleshov
3639 */
3740 public class Attribute {
3841
39 /**
40 * The type of this attribute.
41 */
42 public final String type;
43
44 /**
45 * The raw value of this attribute, used only for unknown attributes.
46 */
47 byte[] value;
48
49 /**
50 * The next attribute in this attribute list. May be <tt>null</tt>.
51 */
52 Attribute next;
53
54 /**
55 * Constructs a new empty attribute.
56 *
57 * @param type
58 * the type of the attribute.
59 */
60 protected Attribute(final String type) {
61 this.type = type;
62 }
63
64 /**
65 * Returns <tt>true</tt> if this type of attribute is unknown. The default
66 * implementation of this method always returns <tt>true</tt>.
67 *
68 * @return <tt>true</tt> if this type of attribute is unknown.
69 */
70 public boolean isUnknown() {
71 return true;
72 }
73
74 /**
75 * Returns <tt>true</tt> if this type of attribute is a code attribute.
76 *
77 * @return <tt>true</tt> if this type of attribute is a code attribute.
78 */
79 public boolean isCodeAttribute() {
80 return false;
81 }
82
83 /**
84 * Returns the labels corresponding to this attribute.
85 *
86 * @return the labels corresponding to this attribute, or <tt>null</tt> if
87 * this attribute is not a code attribute that contains labels.
88 */
89 protected Label[] getLabels() {
90 return null;
91 }
92
93 /**
94 * Reads a {@link #type type} attribute. This method must return a
95 * <i>new</i> {@link Attribute} object, of type {@link #type type},
96 * corresponding to the <tt>len</tt> bytes starting at the given offset, in
97 * the given class reader.
98 *
99 * @param cr
100 * the class that contains the attribute to be read.
101 * @param off
102 * index of the first byte of the attribute's content in
103 * {@link ClassReader#b cr.b}. The 6 attribute header bytes,
104 * containing the type and the length of the attribute, are not
105 * taken into account here.
106 * @param len
107 * the length of the attribute's content.
108 * @param buf
109 * buffer to be used to call {@link ClassReader#readUTF8
110 * readUTF8}, {@link ClassReader#readClass(int,char[]) readClass}
111 * or {@link ClassReader#readConst readConst}.
112 * @param codeOff
113 * index of the first byte of code's attribute content in
114 * {@link ClassReader#b cr.b}, or -1 if the attribute to be read
115 * is not a code attribute. The 6 attribute header bytes,
116 * containing the type and the length of the attribute, are not
117 * taken into account here.
118 * @param labels
119 * the labels of the method's code, or <tt>null</tt> if the
120 * attribute to be read is not a code attribute.
121 * @return a <i>new</i> {@link Attribute} object corresponding to the given
122 * bytes.
123 */
124 protected Attribute read(final ClassReader cr, final int off,
125 final int len, final char[] buf, final int codeOff,
126 final Label[] labels) {
127 Attribute attr = new Attribute(type);
128 attr.value = new byte[len];
129 System.arraycopy(cr.b, off, attr.value, 0, len);
130 return attr;
131 }
132
133 /**
134 * Returns the byte array form of this attribute.
135 *
136 * @param cw
137 * the class to which this attribute must be added. This
138 * parameter can be used to add to the constant pool of this
139 * class the items that corresponds to this attribute.
140 * @param code
141 * the bytecode of the method corresponding to this code
142 * attribute, or <tt>null</tt> if this attribute is not a code
143 * attributes.
144 * @param len
145 * the length of the bytecode of the method corresponding to this
146 * code attribute, or <tt>null</tt> if this attribute is not a
147 * code attribute.
148 * @param maxStack
149 * the maximum stack size of the method corresponding to this
150 * code attribute, or -1 if this attribute is not a code
151 * attribute.
152 * @param maxLocals
153 * the maximum number of local variables of the method
154 * corresponding to this code attribute, or -1 if this attribute
155 * is not a code attribute.
156 * @return the byte array form of this attribute.
157 */
158 protected ByteVector write(final ClassWriter cw, final byte[] code,
159 final int len, final int maxStack, final int maxLocals) {
160 ByteVector v = new ByteVector();
161 v.data = value;
162 v.length = value.length;
163 return v;
164 }
165
166 /**
167 * Returns the length of the attribute list that begins with this attribute.
168 *
169 * @return the length of the attribute list that begins with this attribute.
170 */
171 final int getCount() {
172 int count = 0;
173 Attribute attr = this;
174 while (attr != null) {
175 count += 1;
176 attr = attr.next;
42 /** The type of this attribute, also called its name in the JVMS. */
43 public final String type;
44
45 /**
46 * The raw content of this attribute, only used for unknown attributes (see {@link #isUnknown()}).
47 * The 6 header bytes of the attribute (attribute_name_index and attribute_length) are <i>not</i>
48 * included.
49 */
50 private byte[] content;
51
52 /**
53 * The next attribute in this attribute list (Attribute instances can be linked via this field to
54 * store a list of class, field, method or code attributes). May be <tt>null</tt>.
55 */
56 Attribute nextAttribute;
57
58 /**
59 * Constructs a new empty attribute.
60 *
61 * @param type the type of the attribute.
62 */
63 protected Attribute(final String type) {
64 this.type = type;
65 }
66
67 /**
68 * Returns <tt>true</tt> if this type of attribute is unknown. This means that the attribute
69 * content can't be parsed to extract constant pool references, labels, etc. Instead, the
70 * attribute content is read as an opaque byte array, and written back as is. This can lead to
71 * invalid attributes, if the content actually contains constant pool references, labels, or other
72 * symbolic references that need to be updated when there are changes to the constant pool, the
73 * method bytecode, etc. The default implementation of this method always returns <tt>true</tt>.
74 *
75 * @return <tt>true</tt> if this type of attribute is unknown.
76 */
77 public boolean isUnknown() {
78 return true;
79 }
80
81 /**
82 * Returns <tt>true</tt> if this type of attribute is a code attribute.
83 *
84 * @return <tt>true</tt> if this type of attribute is a code attribute.
85 */
86 public boolean isCodeAttribute() {
87 return false;
88 }
89
90 /**
91 * Returns the labels corresponding to this attribute.
92 *
93 * @return the labels corresponding to this attribute, or <tt>null</tt> if this attribute is not a
94 * code attribute that contains labels.
95 */
96 protected Label[] getLabels() {
97 return new Label[0];
98 }
99
100 /**
101 * Reads a {@link #type} attribute. This method must return a <i>new</i> {@link Attribute} object,
102 * of type {@link #type}, corresponding to the 'length' bytes starting at 'offset', in the given
103 * ClassReader.
104 *
105 * @param classReader the class that contains the attribute to be read.
106 * @param offset index of the first byte of the attribute's content in {@link ClassReader#b}. The
107 * 6 attribute header bytes (attribute_name_index and attribute_length) are not taken into
108 * account here.
109 * @param length the length of the attribute's content (excluding the 6 attribute header bytes).
110 * @param charBuffer the buffer to be used to call the ClassReader methods requiring a
111 * 'charBuffer' parameter.
112 * @param codeAttributeOffset index of the first byte of content of the enclosing Code attribute
113 * in {@link ClassReader#b}, or -1 if the attribute to be read is not a code attribute. The 6
114 * attribute header bytes (attribute_name_index and attribute_length) are not taken into
115 * account here.
116 * @param labels the labels of the method's code, or <tt>null</tt> if the attribute to be read is
117 * not a code attribute.
118 * @return a <i>new</i> {@link Attribute} object corresponding to the specified bytes.
119 */
120 protected Attribute read(
121 final ClassReader classReader,
122 final int offset,
123 final int length,
124 final char[] charBuffer,
125 final int codeAttributeOffset,
126 final Label[] labels) {
127 Attribute attribute = new Attribute(type);
128 attribute.content = new byte[length];
129 System.arraycopy(classReader.b, offset, attribute.content, 0, length);
130 return attribute;
131 }
132
133 /**
134 * Returns the byte array form of the content of this attribute. The 6 header bytes
135 * (attribute_name_index and attribute_length) must <i>not</i> be added in the returned
136 * ByteVector.
137 *
138 * @param classWriter the class to which this attribute must be added. This parameter can be used
139 * to add the items that corresponds to this attribute to the constant pool of this class.
140 * @param code the bytecode of the method corresponding to this code attribute, or <tt>null</tt>
141 * if this attribute is not a code attribute. Corresponds to the 'code' field of the Code
142 * attribute.
143 * @param codeLength the length of the bytecode of the method corresponding to this code
144 * attribute, or 0 if this attribute is not a code attribute. Corresponds to the 'code_length'
145 * field of the Code attribute.
146 * @param maxStack the maximum stack size of the method corresponding to this code attribute, or
147 * -1 if this attribute is not a code attribute.
148 * @param maxLocals the maximum number of local variables of the method corresponding to this code
149 * attribute, or -1 if this attribute is not a code attribute.
150 * @return the byte array form of this attribute.
151 */
152 protected ByteVector write(
153 final ClassWriter classWriter,
154 final byte[] code,
155 final int codeLength,
156 final int maxStack,
157 final int maxLocals) {
158 return new ByteVector(content);
159 }
160
161 /**
162 * Returns the number of attributes of the attribute list that begins with this attribute.
163 *
164 * @return the number of attributes of the attribute list that begins with this attribute.
165 */
166 final int getAttributeCount() {
167 int count = 0;
168 Attribute attribute = this;
169 while (attribute != null) {
170 count += 1;
171 attribute = attribute.nextAttribute;
172 }
173 return count;
174 }
175
176 /**
177 * Returns the total size in bytes of all the attributes in the attribute list that begins with
178 * this attribute. This size includes the 6 header bytes (attribute_name_index and
179 * attribute_length) per attribute. Also adds the attribute type names to the constant pool.
180 *
181 * @param symbolTable where the constants used in the attributes must be stored.
182 * @return the size of all the attributes in this attribute list. This size includes the size of
183 * the attribute headers.
184 */
185 final int computeAttributesSize(final SymbolTable symbolTable) {
186 final byte[] code = null;
187 final int codeLength = 0;
188 final int maxStack = -1;
189 final int maxLocals = -1;
190 return computeAttributesSize(symbolTable, code, codeLength, maxStack, maxLocals);
191 }
192
193 /**
194 * Returns the total size in bytes of all the attributes in the attribute list that begins with
195 * this attribute. This size includes the 6 header bytes (attribute_name_index and
196 * attribute_length) per attribute. Also adds the attribute type names to the constant pool.
197 *
198 * @param symbolTable where the constants used in the attributes must be stored.
199 * @param code the bytecode of the method corresponding to these code attributes, or <tt>null</tt>
200 * if they are not code attributes. Corresponds to the 'code' field of the Code attribute.
201 * @param codeLength the length of the bytecode of the method corresponding to these code
202 * attributes, or 0 if they are not code attributes. Corresponds to the 'code_length' field of
203 * the Code attribute.
204 * @param maxStack the maximum stack size of the method corresponding to these code attributes, or
205 * -1 if they are not code attributes.
206 * @param maxLocals the maximum number of local variables of the method corresponding to these
207 * code attributes, or -1 if they are not code attribute.
208 * @return the size of all the attributes in this attribute list. This size includes the size of
209 * the attribute headers.
210 */
211 final int computeAttributesSize(
212 final SymbolTable symbolTable,
213 final byte[] code,
214 final int codeLength,
215 final int maxStack,
216 final int maxLocals) {
217 final ClassWriter classWriter = symbolTable.classWriter;
218 int size = 0;
219 Attribute attribute = this;
220 while (attribute != null) {
221 symbolTable.addConstantUtf8(attribute.type);
222 size += 6 + attribute.write(classWriter, code, codeLength, maxStack, maxLocals).length;
223 attribute = attribute.nextAttribute;
224 }
225 return size;
226 }
227
228 /**
229 * Puts all the attributes of the attribute list that begins with this attribute, in the given
230 * byte vector. This includes the 6 header bytes (attribute_name_index and attribute_length) per
231 * attribute.
232 *
233 * @param symbolTable where the constants used in the attributes must be stored.
234 * @param output where the attributes must be written.
235 */
236 final void putAttributes(final SymbolTable symbolTable, final ByteVector output) {
237 final byte[] code = null;
238 final int codeLength = 0;
239 final int maxStack = -1;
240 final int maxLocals = -1;
241 putAttributes(symbolTable, code, codeLength, maxStack, maxLocals, output);
242 }
243
244 /**
245 * Puts all the attributes of the attribute list that begins with this attribute, in the given
246 * byte vector. This includes the 6 header bytes (attribute_name_index and attribute_length) per
247 * attribute.
248 *
249 * @param symbolTable where the constants used in the attributes must be stored.
250 * @param code the bytecode of the method corresponding to these code attributes, or <tt>null</tt>
251 * if they are not code attributes. Corresponds to the 'code' field of the Code attribute.
252 * @param codeLength the length of the bytecode of the method corresponding to these code
253 * attributes, or 0 if they are not code attributes. Corresponds to the 'code_length' field of
254 * the Code attribute.
255 * @param maxStack the maximum stack size of the method corresponding to these code attributes, or
256 * -1 if they are not code attributes.
257 * @param maxLocals the maximum number of local variables of the method corresponding to these
258 * code attributes, or -1 if they are not code attribute.
259 * @param output where the attributes must be written.
260 */
261 final void putAttributes(
262 final SymbolTable symbolTable,
263 final byte[] code,
264 final int codeLength,
265 final int maxStack,
266 final int maxLocals,
267 final ByteVector output) {
268 final ClassWriter classWriter = symbolTable.classWriter;
269 Attribute attribute = this;
270 while (attribute != null) {
271 ByteVector attributeContent =
272 attribute.write(classWriter, code, codeLength, maxStack, maxLocals);
273 // Put attribute_name_index and attribute_length.
274 output.putShort(symbolTable.addConstantUtf8(attribute.type)).putInt(attributeContent.length);
275 output.putByteArray(attributeContent.data, 0, attributeContent.length);
276 attribute = attribute.nextAttribute;
277 }
278 }
279
280 /** A set of attribute prototypes (attributes with the same type are considered equal). */
281 static final class Set {
282
283 private static final int SIZE_INCREMENT = 6;
284
285 private int size;
286 private Attribute[] data = new Attribute[SIZE_INCREMENT];
287
288 void addAttributes(final Attribute attributeList) {
289 Attribute attribute = attributeList;
290 while (attribute != null) {
291 if (!contains(attribute)) {
292 add(attribute);
177293 }
178 return count;
179 }
180
181 /**
182 * Returns the size of all the attributes in this attribute list.
183 *
184 * @param cw
185 * the class writer to be used to convert the attributes into
186 * byte arrays, with the {@link #write write} method.
187 * @param code
188 * the bytecode of the method corresponding to these code
189 * attributes, or <tt>null</tt> if these attributes are not code
190 * attributes.
191 * @param len
192 * the length of the bytecode of the method corresponding to
193 * these code attributes, or <tt>null</tt> if these attributes
194 * are not code attributes.
195 * @param maxStack
196 * the maximum stack size of the method corresponding to these
197 * code attributes, or -1 if these attributes are not code
198 * attributes.
199 * @param maxLocals
200 * the maximum number of local variables of the method
201 * corresponding to these code attributes, or -1 if these
202 * attributes are not code attributes.
203 * @return the size of all the attributes in this attribute list. This size
204 * includes the size of the attribute headers.
205 */
206 final int getSize(final ClassWriter cw, final byte[] code, final int len,
207 final int maxStack, final int maxLocals) {
208 Attribute attr = this;
209 int size = 0;
210 while (attr != null) {
211 cw.newUTF8(attr.type);
212 size += attr.write(cw, code, len, maxStack, maxLocals).length + 6;
213 attr = attr.next;
294 attribute = attribute.nextAttribute;
295 }
296 }
297
298 Attribute[] toArray() {
299 Attribute[] result = new Attribute[size];
300 System.arraycopy(data, 0, result, 0, size);
301 return result;
302 }
303
304 private boolean contains(final Attribute attribute) {
305 for (int i = 0; i < size; ++i) {
306 if (data[i].type.equals(attribute.type)) {
307 return true;
214308 }
215 return size;
216 }
217
218 /**
219 * Writes all the attributes of this attribute list in the given byte
220 * vector.
221 *
222 * @param cw
223 * the class writer to be used to convert the attributes into
224 * byte arrays, with the {@link #write write} method.
225 * @param code
226 * the bytecode of the method corresponding to these code
227 * attributes, or <tt>null</tt> if these attributes are not code
228 * attributes.
229 * @param len
230 * the length of the bytecode of the method corresponding to
231 * these code attributes, or <tt>null</tt> if these attributes
232 * are not code attributes.
233 * @param maxStack
234 * the maximum stack size of the method corresponding to these
235 * code attributes, or -1 if these attributes are not code
236 * attributes.
237 * @param maxLocals
238 * the maximum number of local variables of the method
239 * corresponding to these code attributes, or -1 if these
240 * attributes are not code attributes.
241 * @param out
242 * where the attributes must be written.
243 */
244 final void put(final ClassWriter cw, final byte[] code, final int len,
245 final int maxStack, final int maxLocals, final ByteVector out) {
246 Attribute attr = this;
247 while (attr != null) {
248 ByteVector b = attr.write(cw, code, len, maxStack, maxLocals);
249 out.putShort(cw.newUTF8(attr.type)).putInt(b.length);
250 out.putByteArray(b.data, 0, b.length);
251 attr = attr.next;
252 }
253 }
309 }
310 return false;
311 }
312
313 private void add(final Attribute attribute) {
314 if (size >= data.length) {
315 Attribute[] newData = new Attribute[data.length + SIZE_INCREMENT];
316 System.arraycopy(data, 0, newData, 0, size);
317 data = newData;
318 }
319 data[size++] = attribute;
320 }
321 }
254322 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
27 package org.eclipse.persistence.internal.libraries.asm;
28
29 /**
30 * A dynamically extensible vector of bytes. This class is roughly equivalent to a DataOutputStream
31 * on top of a ByteArrayOutputStream, but is more efficient.
432 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 package org.eclipse.persistence.internal.libraries.asm;
30
31 /**
32 * A dynamically extensible vector of bytes. This class is roughly equivalent to
33 * a DataOutputStream on top of a ByteArrayOutputStream, but is more efficient.
34 *
3533 * @author Eric Bruneton
3634 */
3735 public class ByteVector {
3836
39 /**
40 * The content of this vector.
41 */
42 byte[] data;
43
44 /**
45 * Actual number of bytes in this vector.
46 */
47 int length;
48
49 /**
50 * Constructs a new {@link ByteVector ByteVector} with a default initial
51 * size.
52 */
53 public ByteVector() {
54 data = new byte[64];
55 }
56
57 /**
58 * Constructs a new {@link ByteVector ByteVector} with the given initial
59 * size.
60 *
61 * @param initialSize
62 * the initial size of the byte vector to be constructed.
63 */
64 public ByteVector(final int initialSize) {
65 data = new byte[initialSize];
66 }
67
68 /**
69 * Puts a byte into this byte vector. The byte vector is automatically
70 * enlarged if necessary.
71 *
72 * @param b
73 * a byte.
74 * @return this byte vector.
75 */
76 public ByteVector putByte(final int b) {
77 int length = this.length;
78 if (length + 1 > data.length) {
79 enlarge(1);
80 }
81 data[length++] = (byte) b;
82 this.length = length;
83 return this;
84 }
85
86 /**
87 * Puts two bytes into this byte vector. The byte vector is automatically
88 * enlarged if necessary.
89 *
90 * @param b1
91 * a byte.
92 * @param b2
93 * another byte.
94 * @return this byte vector.
95 */
96 ByteVector put11(final int b1, final int b2) {
97 int length = this.length;
98 if (length + 2 > data.length) {
99 enlarge(2);
100 }
101 byte[] data = this.data;
102 data[length++] = (byte) b1;
103 data[length++] = (byte) b2;
104 this.length = length;
105 return this;
106 }
107
108 /**
109 * Puts a short into this byte vector. The byte vector is automatically
110 * enlarged if necessary.
111 *
112 * @param s
113 * a short.
114 * @return this byte vector.
115 */
116 public ByteVector putShort(final int s) {
117 int length = this.length;
118 if (length + 2 > data.length) {
119 enlarge(2);
120 }
121 byte[] data = this.data;
122 data[length++] = (byte) (s >>> 8);
123 data[length++] = (byte) s;
124 this.length = length;
125 return this;
126 }
127
128 /**
129 * Puts a byte and a short into this byte vector. The byte vector is
130 * automatically enlarged if necessary.
131 *
132 * @param b
133 * a byte.
134 * @param s
135 * a short.
136 * @return this byte vector.
137 */
138 ByteVector put12(final int b, final int s) {
139 int length = this.length;
140 if (length + 3 > data.length) {
141 enlarge(3);
142 }
143 byte[] data = this.data;
144 data[length++] = (byte) b;
145 data[length++] = (byte) (s >>> 8);
146 data[length++] = (byte) s;
147 this.length = length;
148 return this;
149 }
150
151 /**
152 * Puts an int into this byte vector. The byte vector is automatically
153 * enlarged if necessary.
154 *
155 * @param i
156 * an int.
157 * @return this byte vector.
158 */
159 public ByteVector putInt(final int i) {
160 int length = this.length;
161 if (length + 4 > data.length) {
162 enlarge(4);
163 }
164 byte[] data = this.data;
165 data[length++] = (byte) (i >>> 24);
166 data[length++] = (byte) (i >>> 16);
167 data[length++] = (byte) (i >>> 8);
168 data[length++] = (byte) i;
169 this.length = length;
170 return this;
171 }
172
173 /**
174 * Puts a long into this byte vector. The byte vector is automatically
175 * enlarged if necessary.
176 *
177 * @param l
178 * a long.
179 * @return this byte vector.
180 */
181 public ByteVector putLong(final long l) {
182 int length = this.length;
183 if (length + 8 > data.length) {
184 enlarge(8);
185 }
186 byte[] data = this.data;
187 int i = (int) (l >>> 32);
188 data[length++] = (byte) (i >>> 24);
189 data[length++] = (byte) (i >>> 16);
190 data[length++] = (byte) (i >>> 8);
191 data[length++] = (byte) i;
192 i = (int) l;
193 data[length++] = (byte) (i >>> 24);
194 data[length++] = (byte) (i >>> 16);
195 data[length++] = (byte) (i >>> 8);
196 data[length++] = (byte) i;
197 this.length = length;
198 return this;
199 }
200
201 /**
202 * Puts an UTF8 string into this byte vector. The byte vector is
203 * automatically enlarged if necessary.
204 *
205 * @param s
206 * a String whose UTF8 encoded length must be less than 65536.
207 * @return this byte vector.
208 */
209 public ByteVector putUTF8(final String s) {
210 int charLength = s.length();
211 if (charLength > 65535) {
212 throw new IllegalArgumentException();
213 }
214 int len = length;
215 if (len + 2 + charLength > data.length) {
216 enlarge(2 + charLength);
217 }
218 byte[] data = this.data;
219 // optimistic algorithm: instead of computing the byte length and then
220 // serializing the string (which requires two loops), we assume the byte
221 // length is equal to char length (which is the most frequent case), and
222 // we start serializing the string right away. During the serialization,
223 // if we find that this assumption is wrong, we continue with the
224 // general method.
225 data[len++] = (byte) (charLength >>> 8);
226 data[len++] = (byte) charLength;
227 for (int i = 0; i < charLength; ++i) {
228 char c = s.charAt(i);
229 if (c >= '\001' && c <= '\177') {
230 data[len++] = (byte) c;
231 } else {
232 length = len;
233 return encodeUTF8(s, i, 65535);
234 }
235 }
236 length = len;
237 return this;
238 }
239
240 /**
241 * Puts an UTF8 string into this byte vector. The byte vector is
242 * automatically enlarged if necessary. The string length is encoded in two
243 * bytes before the encoded characters, if there is space for that (i.e. if
244 * this.length - i - 2 >= 0).
245 *
246 * @param s
247 * the String to encode.
248 * @param i
249 * the index of the first character to encode. The previous
250 * characters are supposed to have already been encoded, using
251 * only one byte per character.
252 * @param maxByteLength
253 * the maximum byte length of the encoded string, including the
254 * already encoded characters.
255 * @return this byte vector.
256 */
257 ByteVector encodeUTF8(final String s, int i, int maxByteLength) {
258 int charLength = s.length();
259 int byteLength = i;
260 char c;
261 for (int j = i; j < charLength; ++j) {
262 c = s.charAt(j);
263 if (c >= '\001' && c <= '\177') {
264 byteLength++;
265 } else if (c > '\u07FF') {
266 byteLength += 3;
267 } else {
268 byteLength += 2;
269 }
270 }
271 if (byteLength > maxByteLength) {
272 throw new IllegalArgumentException();
273 }
274 int start = length - i - 2;
275 if (start >= 0) {
276 data[start] = (byte) (byteLength >>> 8);
277 data[start + 1] = (byte) byteLength;
278 }
279 if (length + byteLength - i > data.length) {
280 enlarge(byteLength - i);
281 }
282 int len = length;
283 for (int j = i; j < charLength; ++j) {
284 c = s.charAt(j);
285 if (c >= '\001' && c <= '\177') {
286 data[len++] = (byte) c;
287 } else if (c > '\u07FF') {
288 data[len++] = (byte) (0xE0 | c >> 12 & 0xF);
289 data[len++] = (byte) (0x80 | c >> 6 & 0x3F);
290 data[len++] = (byte) (0x80 | c & 0x3F);
291 } else {
292 data[len++] = (byte) (0xC0 | c >> 6 & 0x1F);
293 data[len++] = (byte) (0x80 | c & 0x3F);
294 }
295 }
296 length = len;
297 return this;
298 }
299
300 /**
301 * Puts an array of bytes into this byte vector. The byte vector is
302 * automatically enlarged if necessary.
303 *
304 * @param b
305 * an array of bytes. May be <tt>null</tt> to put <tt>len</tt>
306 * null bytes into this byte vector.
307 * @param off
308 * index of the fist byte of b that must be copied.
309 * @param len
310 * number of bytes of b that must be copied.
311 * @return this byte vector.
312 */
313 public ByteVector putByteArray(final byte[] b, final int off, final int len) {
314 if (length + len > data.length) {
315 enlarge(len);
316 }
317 if (b != null) {
318 System.arraycopy(b, off, data, length, len);
319 }
320 length += len;
321 return this;
322 }
323
324 /**
325 * Enlarge this byte vector so that it can receive n more bytes.
326 *
327 * @param size
328 * number of additional bytes that this byte vector should be
329 * able to receive.
330 */
331 private void enlarge(final int size) {
332 int length1 = 2 * data.length;
333 int length2 = length + size;
334 byte[] newData = new byte[length1 > length2 ? length1 : length2];
335 System.arraycopy(data, 0, newData, 0, length);
336 data = newData;
337 }
37 /** The content of this vector. Only the first {@link #length} bytes contain real data. */
38 byte[] data;
39
40 /** The actual number of bytes in this vector. */
41 int length;
42
43 /** Constructs a new {@link ByteVector} with a default initial capacity. */
44 public ByteVector() {
45 data = new byte[64];
46 }
47
48 /**
49 * Constructs a new {@link ByteVector} with the given initial capacity.
50 *
51 * @param initialCapacity the initial capacity of the byte vector to be constructed.
52 */
53 public ByteVector(final int initialCapacity) {
54 data = new byte[initialCapacity];
55 }
56
57 /**
58 * Constructs a new {@link ByteVector} from the given initial data.
59 *
60 * @param data the initial data of the new byte vector.
61 */
62 ByteVector(final byte[] data) {
63 this.data = data;
64 this.length = data.length;
65 }
66
67 /**
68 * Puts a byte into this byte vector. The byte vector is automatically enlarged if necessary.
69 *
70 * @param byteValue a byte.
71 * @return this byte vector.
72 */
73 public ByteVector putByte(final int byteValue) {
74 int currentLength = length;
75 if (currentLength + 1 > data.length) {
76 enlarge(1);
77 }
78 data[currentLength++] = (byte) byteValue;
79 length = currentLength;
80 return this;
81 }
82
83 /**
84 * Puts two bytes into this byte vector. The byte vector is automatically enlarged if necessary.
85 *
86 * @param byteValue1 a byte.
87 * @param byteValue2 another byte.
88 * @return this byte vector.
89 */
90 final ByteVector put11(final int byteValue1, final int byteValue2) {
91 int currentLength = length;
92 if (currentLength + 2 > data.length) {
93 enlarge(2);
94 }
95 byte[] currentData = data;
96 currentData[currentLength++] = (byte) byteValue1;
97 currentData[currentLength++] = (byte) byteValue2;
98 length = currentLength;
99 return this;
100 }
101
102 /**
103 * Puts a short into this byte vector. The byte vector is automatically enlarged if necessary.
104 *
105 * @param shortValue a short.
106 * @return this byte vector.
107 */
108 public ByteVector putShort(final int shortValue) {
109 int currentLength = length;
110 if (currentLength + 2 > data.length) {
111 enlarge(2);
112 }
113 byte[] currentData = data;
114 currentData[currentLength++] = (byte) (shortValue >>> 8);
115 currentData[currentLength++] = (byte) shortValue;
116 length = currentLength;
117 return this;
118 }
119
120 /**
121 * Puts a byte and a short into this byte vector. The byte vector is automatically enlarged if
122 * necessary.
123 *
124 * @param byteValue a byte.
125 * @param shortValue a short.
126 * @return this byte vector.
127 */
128 final ByteVector put12(final int byteValue, final int shortValue) {
129 int currentLength = length;
130 if (currentLength + 3 > data.length) {
131 enlarge(3);
132 }
133 byte[] currentData = data;
134 currentData[currentLength++] = (byte) byteValue;
135 currentData[currentLength++] = (byte) (shortValue >>> 8);
136 currentData[currentLength++] = (byte) shortValue;
137 length = currentLength;
138 return this;
139 }
140
141 /**
142 * Puts two bytes and a short into this byte vector. The byte vector is automatically enlarged if
143 * necessary.
144 *
145 * @param byteValue1 a byte.
146 * @param byteValue2 another byte.
147 * @param shortValue a short.
148 * @return this byte vector.
149 */
150 final ByteVector put112(final int byteValue1, final int byteValue2, final int shortValue) {
151 int currentLength = length;
152 if (currentLength + 4 > data.length) {
153 enlarge(4);
154 }
155 byte[] currentData = data;
156 currentData[currentLength++] = (byte) byteValue1;
157 currentData[currentLength++] = (byte) byteValue2;
158 currentData[currentLength++] = (byte) (shortValue >>> 8);
159 currentData[currentLength++] = (byte) shortValue;
160 length = currentLength;
161 return this;
162 }
163
164 /**
165 * Puts an int into this byte vector. The byte vector is automatically enlarged if necessary.
166 *
167 * @param intValue an int.
168 * @return this byte vector.
169 */
170 public ByteVector putInt(final int intValue) {
171 int currentLength = length;
172 if (currentLength + 4 > data.length) {
173 enlarge(4);
174 }
175 byte[] currentData = data;
176 currentData[currentLength++] = (byte) (intValue >>> 24);
177 currentData[currentLength++] = (byte) (intValue >>> 16);
178 currentData[currentLength++] = (byte) (intValue >>> 8);
179 currentData[currentLength++] = (byte) intValue;
180 length = currentLength;
181 return this;
182 }
183
184 /**
185 * Puts one byte and two shorts into this byte vector. The byte vector is automatically enlarged
186 * if necessary.
187 *
188 * @param byteValue a byte.
189 * @param shortValue1 a short.
190 * @param shortValue2 another short.
191 * @return this byte vector.
192 */
193 final ByteVector put122(final int byteValue, final int shortValue1, final int shortValue2) {
194 int currentLength = length;
195 if (currentLength + 5 > data.length) {
196 enlarge(5);
197 }
198 byte[] currentData = data;
199 currentData[currentLength++] = (byte) byteValue;
200 currentData[currentLength++] = (byte) (shortValue1 >>> 8);
201 currentData[currentLength++] = (byte) shortValue1;
202 currentData[currentLength++] = (byte) (shortValue2 >>> 8);
203 currentData[currentLength++] = (byte) shortValue2;
204 length = currentLength;
205 return this;
206 }
207
208 /**
209 * Puts a long into this byte vector. The byte vector is automatically enlarged if necessary.
210 *
211 * @param longValue a long.
212 * @return this byte vector.
213 */
214 public ByteVector putLong(final long longValue) {
215 int currentLength = length;
216 if (currentLength + 8 > data.length) {
217 enlarge(8);
218 }
219 byte[] currentData = data;
220 int intValue = (int) (longValue >>> 32);
221 currentData[currentLength++] = (byte) (intValue >>> 24);
222 currentData[currentLength++] = (byte) (intValue >>> 16);
223 currentData[currentLength++] = (byte) (intValue >>> 8);
224 currentData[currentLength++] = (byte) intValue;
225 intValue = (int) longValue;
226 currentData[currentLength++] = (byte) (intValue >>> 24);
227 currentData[currentLength++] = (byte) (intValue >>> 16);
228 currentData[currentLength++] = (byte) (intValue >>> 8);
229 currentData[currentLength++] = (byte) intValue;
230 length = currentLength;
231 return this;
232 }
233
234 /**
235 * Puts an UTF8 string into this byte vector. The byte vector is automatically enlarged if
236 * necessary.
237 *
238 * @param stringValue a String whose UTF8 encoded length must be less than 65536.
239 * @return this byte vector.
240 */
241 public ByteVector putUTF8(final String stringValue) {
242 int charLength = stringValue.length();
243 if (charLength > 65535) {
244 throw new IllegalArgumentException();
245 }
246 int currentLength = length;
247 if (currentLength + 2 + charLength > data.length) {
248 enlarge(2 + charLength);
249 }
250 byte[] currentData = data;
251 // Optimistic algorithm: instead of computing the byte length and then serializing the string
252 // (which requires two loops), we assume the byte length is equal to char length (which is the
253 // most frequent case), and we start serializing the string right away. During the
254 // serialization, if we find that this assumption is wrong, we continue with the general method.
255 currentData[currentLength++] = (byte) (charLength >>> 8);
256 currentData[currentLength++] = (byte) charLength;
257 for (int i = 0; i < charLength; ++i) {
258 char charValue = stringValue.charAt(i);
259 if (charValue >= '\u0001' && charValue <= '\u007F') {
260 currentData[currentLength++] = (byte) charValue;
261 } else {
262 length = currentLength;
263 return encodeUTF8(stringValue, i, 65535);
264 }
265 }
266 length = currentLength;
267 return this;
268 }
269
270 /**
271 * Puts an UTF8 string into this byte vector. The byte vector is automatically enlarged if
272 * necessary. The string length is encoded in two bytes before the encoded characters, if there is
273 * space for that (i.e. if this.length - offset - 2 &gt;= 0).
274 *
275 * @param stringValue the String to encode.
276 * @param offset the index of the first character to encode. The previous characters are supposed
277 * to have already been encoded, using only one byte per character.
278 * @param maxByteLength the maximum byte length of the encoded string, including the already
279 * encoded characters.
280 * @return this byte vector.
281 */
282 final ByteVector encodeUTF8(final String stringValue, final int offset, final int maxByteLength) {
283 int charLength = stringValue.length();
284 int byteLength = offset;
285 for (int i = offset; i < charLength; ++i) {
286 char charValue = stringValue.charAt(i);
287 if (charValue >= '\u0001' && charValue <= '\u007F') {
288 byteLength++;
289 } else if (charValue <= '\u07FF') {
290 byteLength += 2;
291 } else {
292 byteLength += 3;
293 }
294 }
295 if (byteLength > maxByteLength) {
296 throw new IllegalArgumentException();
297 }
298 // Compute where 'byteLength' must be stored in 'data', and store it at this location.
299 int byteLengthOffset = length - offset - 2;
300 if (byteLengthOffset >= 0) {
301 data[byteLengthOffset] = (byte) (byteLength >>> 8);
302 data[byteLengthOffset + 1] = (byte) byteLength;
303 }
304 if (length + byteLength - offset > data.length) {
305 enlarge(byteLength - offset);
306 }
307 int currentLength = length;
308 for (int i = offset; i < charLength; ++i) {
309 char charValue = stringValue.charAt(i);
310 if (charValue >= '\u0001' && charValue <= '\u007F') {
311 data[currentLength++] = (byte) charValue;
312 } else if (charValue <= '\u07FF') {
313 data[currentLength++] = (byte) (0xC0 | charValue >> 6 & 0x1F);
314 data[currentLength++] = (byte) (0x80 | charValue & 0x3F);
315 } else {
316 data[currentLength++] = (byte) (0xE0 | charValue >> 12 & 0xF);
317 data[currentLength++] = (byte) (0x80 | charValue >> 6 & 0x3F);
318 data[currentLength++] = (byte) (0x80 | charValue & 0x3F);
319 }
320 }
321 length = currentLength;
322 return this;
323 }
324
325 /**
326 * Puts an array of bytes into this byte vector. The byte vector is automatically enlarged if
327 * necessary.
328 *
329 * @param byteArrayValue an array of bytes. May be <tt>null</tt> to put <tt>byteLength</tt> null
330 * bytes into this byte vector.
331 * @param byteOffset index of the first byte of byteArrayValue that must be copied.
332 * @param byteLength number of bytes of byteArrayValue that must be copied.
333 * @return this byte vector.
334 */
335 public ByteVector putByteArray(
336 final byte[] byteArrayValue, final int byteOffset, final int byteLength) {
337 if (length + byteLength > data.length) {
338 enlarge(byteLength);
339 }
340 if (byteArrayValue != null) {
341 System.arraycopy(byteArrayValue, byteOffset, data, length, byteLength);
342 }
343 length += byteLength;
344 return this;
345 }
346
347 /**
348 * Enlarges this byte vector so that it can receive 'size' more bytes.
349 *
350 * @param size number of additional bytes that this byte vector should be able to receive.
351 */
352 private void enlarge(final int size) {
353 int doubleCapacity = 2 * data.length;
354 int minimalCapacity = length + size;
355 byte[] newData = new byte[doubleCapacity > minimalCapacity ? doubleCapacity : minimalCapacity];
356 System.arraycopy(data, 0, newData, 0, length);
357 data = newData;
358 }
338359 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm;
3028
29 import java.io.ByteArrayOutputStream;
3130 import java.io.IOException;
3231 import java.io.InputStream;
3332
3433 /**
35 * A Java class parser to make a {@link ClassVisitor} visit an existing class.
36 * This class parses a byte array conforming to the Java class file format and
37 * calls the appropriate visit methods of a given class visitor for each field,
38 * method and bytecode instruction encountered.
39 *
34 * A parser to make a {@link ClassVisitor} visit a ClassFile structure, as defined in the Java
35 * Virtual Machine Specification (JVMS). This class parses the ClassFile content and calls the
36 * appropriate visit methods of a given {@link ClassVisitor} for each field, method and bytecode
37 * instruction encountered.
38 *
39 * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html">JVMS 4</a>
4040 * @author Eric Bruneton
4141 * @author Eugene Kuleshov
4242 */
4343 public class ClassReader {
44 /**
45 * True to enable signatures support.
46 */
47 static final boolean SIGNATURES = true;
48
49 /**
50 * True to enable annotations support.
51 */
52 static final boolean ANNOTATIONS = true;
53
54 /**
55 * True to enable stack map frames support.
56 */
57 static final boolean FRAMES = true;
58
59 /**
60 * True to enable bytecode writing support.
61 */
62 static final boolean WRITER = true;
63
64 /**
65 * True to enable JSR_W and GOTO_W support.
66 */
67 static final boolean RESIZE = true;
68
69 /**
70 * Flag to skip method code. If this class is set <code>CODE</code>
71 * attribute won't be visited. This can be used, for example, to retrieve
72 * annotations for methods and method parameters.
73 */
74 public static final int SKIP_CODE = 1;
75
76 /**
77 * Flag to skip the debug information in the class. If this flag is set the
78 * debug information of the class is not visited, i.e. the
79 * {@link MethodVisitor#visitLocalVariable visitLocalVariable} and
80 * {@link MethodVisitor#visitLineNumber visitLineNumber} methods will not be
81 * called.
82 */
83 public static final int SKIP_DEBUG = 2;
84
85 /**
86 * Flag to skip the stack map frames in the class. If this flag is set the
87 * stack map frames of the class is not visited, i.e. the
88 * {@link MethodVisitor#visitFrame visitFrame} method will not be called.
89 * This flag is useful when the {@link ClassWriter#COMPUTE_FRAMES} option is
90 * used: it avoids visiting frames that will be ignored and recomputed from
91 * scratch in the class writer.
92 */
93 public static final int SKIP_FRAMES = 4;
94
95 /**
96 * Flag to expand the stack map frames. By default stack map frames are
97 * visited in their original format (i.e. "expanded" for classes whose
98 * version is less than V1_6, and "compressed" for the other classes). If
99 * this flag is set, stack map frames are always visited in expanded format
100 * (this option adds a decompression/recompression step in ClassReader and
101 * ClassWriter which degrades performances quite a lot).
102 */
103 public static final int EXPAND_FRAMES = 8;
104
105 /**
106 * The class to be parsed. <i>The content of this array must not be
107 * modified. This field is intended for {@link Attribute} sub classes, and
108 * is normally not needed by class generators or adapters.</i>
109 */
110 public final byte[] b;
111
112 /**
113 * The start index of each constant pool item in {@link #b b}, plus one. The
114 * one byte offset skips the constant pool item tag that indicates its type.
115 */
116 private final int[] items;
117
118 /**
119 * The String objects corresponding to the CONSTANT_Utf8 items. This cache
120 * avoids multiple parsing of a given CONSTANT_Utf8 constant pool item,
121 * which GREATLY improves performances (by a factor 2 to 3). This caching
122 * strategy could be extended to all constant pool items, but its benefit
123 * would not be so great for these items (because they are much less
124 * expensive to parse than CONSTANT_Utf8 items).
125 */
126 private final String[] strings;
127
128 /**
129 * Maximum length of the strings contained in the constant pool of the
130 * class.
131 */
132 private final int maxStringLength;
133
134 /**
135 * Start index of the class header information (access, name...) in
136 * {@link #b b}.
137 */
138 public final int header;
139
140 // ------------------------------------------------------------------------
141 // Constructors
142 // ------------------------------------------------------------------------
143
144 /**
145 * Constructs a new {@link ClassReader} object.
146 *
147 * @param b
148 * the bytecode of the class to be read.
149 */
150 public ClassReader(final byte[] b) {
151 this(b, 0, b.length);
152 }
153
154 /**
155 * Constructs a new {@link ClassReader} object.
156 *
157 * @param b
158 * the bytecode of the class to be read.
159 * @param off
160 * the start offset of the class data.
161 * @param len
162 * the length of the class data.
163 */
164 public ClassReader(final byte[] b, final int off, final int len) {
165 this.b = b;
166 // checks the class version
167 if (readShort(off + 6) > Opcodes.V1_9) {
168 throw new IllegalArgumentException();
44
45 /**
46 * A flag to skip the Code attributes. If this flag is set the Code attributes are neither parsed
47 * nor visited.
48 */
49 public static final int SKIP_CODE = 1;
50
51 /**
52 * A flag to skip the SourceFile, SourceDebugExtension, LocalVariableTable, LocalVariableTypeTable
53 * and LineNumberTable attributes. If this flag is set these attributes are neither parsed nor
54 * visited (i.e. {@link ClassVisitor#visitSource}, {@link MethodVisitor#visitLocalVariable} and
55 * {@link MethodVisitor#visitLineNumber} are not called).
56 */
57 public static final int SKIP_DEBUG = 2;
58
59 /**
60 * A flag to skip the StackMap and StackMapTable attributes. If this flag is set these attributes
61 * are neither parsed nor visited (i.e. {@link MethodVisitor#visitFrame} is not called). This flag
62 * is useful when the {@link ClassWriter#COMPUTE_FRAMES} option is used: it avoids visiting frames
63 * that will be ignored and recomputed from scratch.
64 */
65 public static final int SKIP_FRAMES = 4;
66
67 /**
68 * A flag to expand the stack map frames. By default stack map frames are visited in their
69 * original format (i.e. "expanded" for classes whose version is less than V1_6, and "compressed"
70 * for the other classes). If this flag is set, stack map frames are always visited in expanded
71 * format (this option adds a decompression/compression step in ClassReader and ClassWriter which
72 * degrades performance quite a lot).
73 */
74 public static final int EXPAND_FRAMES = 8;
75
76 /**
77 * A flag to expand the ASM specific instructions into an equivalent sequence of standard bytecode
78 * instructions. When resolving a forward jump it may happen that the signed 2 bytes offset
79 * reserved for it is not sufficient to store the bytecode offset. In this case the jump
80 * instruction is replaced with a temporary ASM specific instruction using an unsigned 2 bytes
81 * offset (see {@link Label#resolve}). This internal flag is used to re-read classes containing
82 * such instructions, in order to replace them with standard instructions. In addition, when this
83 * flag is used, goto_w and jsr_w are <i>not</i> converted into goto and jsr, to make sure that
84 * infinite loops where a goto_w is replaced with a goto in ClassReader and converted back to a
85 * goto_w in ClassWriter cannot occur.
86 */
87 static final int EXPAND_ASM_INSNS = 256;
88
89 /** The size of the temporary byte array used to read class input streams chunk by chunk. */
90 private static final int INPUT_STREAM_DATA_CHUNK_SIZE = 4096;
91
92 /**
93 * A byte array containing the JVMS ClassFile structure to be parsed. <i>The content of this array
94 * must not be modified. This field is intended for {@link Attribute} sub classes, and is normally
95 * not needed by class visitors.</i>
96 *
97 * <p>NOTE: the ClassFile structure can start at any offset within this array, i.e. it does not
98 * necessarily start at offset 0. Use {@link #getItem} and {@link #header} to get correct
99 * ClassFile element offsets within this byte array.
100 */
101 public final byte[] b;
102
103 /**
104 * The offset in bytes, in {@link #b}, of each cp_info entry of the ClassFile's constant_pool
105 * array, <i>plus one</i>. In other words, the offset of constant pool entry i is given by
106 * cpInfoOffsets[i] - 1, i.e. its cp_info's tag field is given by b[cpInfoOffsets[i] - 1].
107 */
108 private final int[] cpInfoOffsets;
109
110 /**
111 * The value of each cp_info entry of the ClassFile's constant_pool array, <i>for Constant_Utf8
112 * and Constant_Dynamic constants only</i>. The value of constant pool entry i is given by
113 * cpInfoValues[i]. This cache avoids multiple parsing of those constant pool items.
114 */
115 private final Object[] cpInfoValues;
116
117 /**
118 * The start offsets in {@link #b} of each element of the bootstrap_methods array (in the
119 * BootstrapMethods attribute).
120 *
121 * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.23">JVMS
122 * 4.7.23</a>
123 */
124 private final int[] bootstrapMethodOffsets;
125
126 /**
127 * A conservative estimate of the maximum length of the strings contained in the constant pool of
128 * the class.
129 */
130 private final int maxStringLength;
131
132 /** The offset in bytes, in {@link #b}, of the ClassFile's access_flags field. */
133 public final int header;
134
135 // -----------------------------------------------------------------------------------------------
136 // Constructors
137 // -----------------------------------------------------------------------------------------------
138
139 /**
140 * Constructs a new {@link ClassReader} object.
141 *
142 * @param classFile the JVMS ClassFile structure to be read.
143 */
144 public ClassReader(final byte[] classFile) {
145 this(classFile, 0, classFile.length);
146 }
147
148 /**
149 * Constructs a new {@link ClassReader} object.
150 *
151 * @param classFileBuffer a byte array containing the JVMS ClassFile structure to be read.
152 * @param classFileOffset the offset in byteBuffer of the first byte of the ClassFile to be read.
153 * @param classFileLength the length in bytes of the ClassFile to be read.
154 */
155 public ClassReader(
156 final byte[] classFileBuffer, final int classFileOffset, final int classFileLength) {
157 this(classFileBuffer, classFileOffset, /* checkClassVersion = */ true);
158 }
159
160 /**
161 * Constructs a new {@link ClassReader} object. <i>This internal constructor must not be exposed
162 * as a public API</i>.
163 *
164 * @param classFileBuffer a byte array containing the JVMS ClassFile structure to be read.
165 * @param classFileOffset the offset in byteBuffer of the first byte of the ClassFile to be read.
166 * @param checkClassVersion whether to check the class version or not.
167 */
168 ClassReader(
169 final byte[] classFileBuffer, final int classFileOffset, final boolean checkClassVersion) {
170 this.b = classFileBuffer;
171 // Check the class' major_version. This field is after the magic and minor_version fields, which
172 // use 4 and 2 bytes respectively.
173 if (checkClassVersion && readShort(classFileOffset + 6) > Opcodes.V11) {
174 throw new IllegalArgumentException(
175 "Unsupported class file major version " + readShort(classFileOffset + 6));
176 }
177 // Create the constant pool arrays. The constant_pool_count field is after the magic,
178 // minor_version and major_version fields, which use 4, 2 and 2 bytes respectively.
179 int constantPoolCount = readUnsignedShort(classFileOffset + 8);
180 cpInfoOffsets = new int[constantPoolCount];
181 cpInfoValues = new Object[constantPoolCount];
182 // Compute the offset of each constant pool entry, as well as a conservative estimate of the
183 // maximum length of the constant pool strings. The first constant pool entry is after the
184 // magic, minor_version, major_version and constant_pool_count fields, which use 4, 2, 2 and 2
185 // bytes respectively.
186 int currentCpInfoIndex = 1;
187 int currentCpInfoOffset = classFileOffset + 10;
188 int currentMaxStringLength = 0;
189 // The offset of the other entries depend on the total size of all the previous entries.
190 while (currentCpInfoIndex < constantPoolCount) {
191 cpInfoOffsets[currentCpInfoIndex++] = currentCpInfoOffset + 1;
192 int cpInfoSize;
193 switch (classFileBuffer[currentCpInfoOffset]) {
194 case Symbol.CONSTANT_FIELDREF_TAG:
195 case Symbol.CONSTANT_METHODREF_TAG:
196 case Symbol.CONSTANT_INTERFACE_METHODREF_TAG:
197 case Symbol.CONSTANT_INTEGER_TAG:
198 case Symbol.CONSTANT_FLOAT_TAG:
199 case Symbol.CONSTANT_NAME_AND_TYPE_TAG:
200 case Symbol.CONSTANT_INVOKE_DYNAMIC_TAG:
201 case Symbol.CONSTANT_DYNAMIC_TAG:
202 cpInfoSize = 5;
203 break;
204 case Symbol.CONSTANT_LONG_TAG:
205 case Symbol.CONSTANT_DOUBLE_TAG:
206 cpInfoSize = 9;
207 currentCpInfoIndex++;
208 break;
209 case Symbol.CONSTANT_UTF8_TAG:
210 cpInfoSize = 3 + readUnsignedShort(currentCpInfoOffset + 1);
211 if (cpInfoSize > currentMaxStringLength) {
212 // The size in bytes of this CONSTANT_Utf8 structure provides a conservative estimate
213 // of the length in characters of the corresponding string, and is much cheaper to
214 // compute than this exact length.
215 currentMaxStringLength = cpInfoSize;
216 }
217 break;
218 case Symbol.CONSTANT_METHOD_HANDLE_TAG:
219 cpInfoSize = 4;
220 break;
221 case Symbol.CONSTANT_CLASS_TAG:
222 case Symbol.CONSTANT_STRING_TAG:
223 case Symbol.CONSTANT_METHOD_TYPE_TAG:
224 case Symbol.CONSTANT_PACKAGE_TAG:
225 case Symbol.CONSTANT_MODULE_TAG:
226 cpInfoSize = 3;
227 break;
228 default:
229 throw new IllegalArgumentException();
230 }
231 currentCpInfoOffset += cpInfoSize;
232 }
233 this.maxStringLength = currentMaxStringLength;
234 // The Classfile's access_flags field is just after the last constant pool entry.
235 this.header = currentCpInfoOffset;
236
237 // Read the BootstrapMethods attribute, if any (only get the offset of each method).
238 int currentAttributeOffset = getFirstAttributeOffset();
239 int[] currentBootstrapMethodOffsets = null;
240 for (int i = readUnsignedShort(currentAttributeOffset - 2); i > 0; --i) {
241 // Read the attribute_info's attribute_name and attribute_length fields.
242 String attributeName = readUTF8(currentAttributeOffset, new char[maxStringLength]);
243 int attributeLength = readInt(currentAttributeOffset + 2);
244 currentAttributeOffset += 6;
245 if (Constants.BOOTSTRAP_METHODS.equals(attributeName)) {
246 // Read the num_bootstrap_methods field and create an array of this size.
247 currentBootstrapMethodOffsets = new int[readUnsignedShort(currentAttributeOffset)];
248 // Compute and store the offset of each 'bootstrap_methods' array field entry.
249 int currentBootstrapMethodOffset = currentAttributeOffset + 2;
250 for (int j = 0; j < currentBootstrapMethodOffsets.length; ++j) {
251 currentBootstrapMethodOffsets[j] = currentBootstrapMethodOffset;
252 // Skip the bootstrap_method_ref and num_bootstrap_arguments fields (2 bytes each),
253 // as well as the bootstrap_arguments array field (of size num_bootstrap_arguments * 2).
254 currentBootstrapMethodOffset +=
255 4 + readUnsignedShort(currentBootstrapMethodOffset + 2) * 2;
169256 }
170 // parses the constant pool
171 items = new int[readUnsignedShort(off + 8)];
172 int n = items.length;
173 strings = new String[n];
174 int max = 0;
175 int index = off + 10;
176 for (int i = 1; i < n; ++i) {
177 items[i] = index + 1;
178 int size;
179 switch (b[index]) {
180 case ClassWriter.FIELD:
181 case ClassWriter.METH:
182 case ClassWriter.IMETH:
183 case ClassWriter.INT:
184 case ClassWriter.FLOAT:
185 case ClassWriter.NAME_TYPE:
186 case ClassWriter.INDY:
187 size = 5;
188 break;
189 case ClassWriter.LONG:
190 case ClassWriter.DOUBLE:
191 size = 9;
192 ++i;
193 break;
194 case ClassWriter.UTF8:
195 size = 3 + readUnsignedShort(index + 1);
196 if (size > max) {
197 max = size;
198 }
199 break;
200 case ClassWriter.HANDLE:
201 size = 4;
202 break;
203 // case ClassWriter.CLASS:
204 // case ClassWriter.STR:
205 // case ClassWriter.MTYPE
257 }
258 currentAttributeOffset += attributeLength;
259 }
260 this.bootstrapMethodOffsets = currentBootstrapMethodOffsets;
261 }
262
263 /**
264 * Constructs a new {@link ClassReader} object.
265 *
266 * @param inputStream an input stream of the JVMS ClassFile structure to be read. This input
267 * stream must contain nothing more than the ClassFile structure itself. It is read from its
268 * current position to its end.
269 * @throws IOException if a problem occurs during reading.
270 */
271 public ClassReader(final InputStream inputStream) throws IOException {
272 this(readStream(inputStream, false));
273 }
274
275 /**
276 * Constructs a new {@link ClassReader} object.
277 *
278 * @param className the fully qualified name of the class to be read. The ClassFile structure is
279 * retrieved with the current class loader's {@link ClassLoader#getSystemResourceAsStream}.
280 * @throws IOException if an exception occurs during reading.
281 */
282 public ClassReader(final String className) throws IOException {
283 this(
284 readStream(
285 ClassLoader.getSystemResourceAsStream(className.replace('.', '/') + ".class"), true));
286 }
287
288 /**
289 * Reads the given input stream and returns its content as a byte array.
290 *
291 * @param inputStream an input stream.
292 * @param close true to close the input stream after reading.
293 * @return the content of the given input stream.
294 * @throws IOException if a problem occurs during reading.
295 */
296 private static byte[] readStream(final InputStream inputStream, final boolean close)
297 throws IOException {
298 if (inputStream == null) {
299 throw new IOException("Class not found");
300 }
301 try {
302 ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
303 byte[] data = new byte[INPUT_STREAM_DATA_CHUNK_SIZE];
304 int bytesRead;
305 while ((bytesRead = inputStream.read(data, 0, data.length)) != -1) {
306 outputStream.write(data, 0, bytesRead);
307 }
308 outputStream.flush();
309 return outputStream.toByteArray();
310 } finally {
311 if (close) {
312 inputStream.close();
313 }
314 }
315 }
316
317 // -----------------------------------------------------------------------------------------------
318 // Accessors
319 // -----------------------------------------------------------------------------------------------
320
321 /**
322 * Returns the class's access flags (see {@link Opcodes}). This value may not reflect Deprecated
323 * and Synthetic flags when bytecode is before 1.5 and those flags are represented by attributes.
324 *
325 * @return the class access flags.
326 * @see ClassVisitor#visit(int, int, String, String, String, String[])
327 */
328 public int getAccess() {
329 return readUnsignedShort(header);
330 }
331
332 /**
333 * Returns the internal name of the class (see {@link Type#getInternalName()}).
334 *
335 * @return the internal class name.
336 * @see ClassVisitor#visit(int, int, String, String, String, String[])
337 */
338 public String getClassName() {
339 // this_class is just after the access_flags field (using 2 bytes).
340 return readClass(header + 2, new char[maxStringLength]);
341 }
342
343 /**
344 * Returns the internal of name of the super class (see {@link Type#getInternalName()}). For
345 * interfaces, the super class is {@link Object}.
346 *
347 * @return the internal name of the super class, or <tt>null</tt> for {@link Object} class.
348 * @see ClassVisitor#visit(int, int, String, String, String, String[])
349 */
350 public String getSuperName() {
351 // super_class is after the access_flags and this_class fields (2 bytes each).
352 return readClass(header + 4, new char[maxStringLength]);
353 }
354
355 /**
356 * Returns the internal names of the implemented interfaces (see {@link Type#getInternalName()}).
357 *
358 * @return the internal names of the directly implemented interfaces. Inherited implemented
359 * interfaces are not returned.
360 * @see ClassVisitor#visit(int, int, String, String, String, String[])
361 */
362 public String[] getInterfaces() {
363 // interfaces_count is after the access_flags, this_class and super_class fields (2 bytes each).
364 int currentOffset = header + 6;
365 int interfacesCount = readUnsignedShort(currentOffset);
366 String[] interfaces = new String[interfacesCount];
367 if (interfacesCount > 0) {
368 char[] charBuffer = new char[maxStringLength];
369 for (int i = 0; i < interfacesCount; ++i) {
370 currentOffset += 2;
371 interfaces[i] = readClass(currentOffset, charBuffer);
372 }
373 }
374 return interfaces;
375 }
376
377 // -----------------------------------------------------------------------------------------------
378 // Public methods
379 // -----------------------------------------------------------------------------------------------
380
381 /**
382 * Makes the given visitor visit the JVMS ClassFile structure passed to the constructor of this
383 * {@link ClassReader}.
384 *
385 * @param classVisitor the visitor that must visit this class.
386 * @param parsingOptions the options to use to parse this class. One or more of {@link
387 * #SKIP_CODE}, {@link #SKIP_DEBUG}, {@link #SKIP_FRAMES} or {@link #EXPAND_FRAMES}.
388 */
389 public void accept(final ClassVisitor classVisitor, final int parsingOptions) {
390 accept(classVisitor, new Attribute[0], parsingOptions);
391 }
392
393 /**
394 * Makes the given visitor visit the JVMS ClassFile structure passed to the constructor of this
395 * {@link ClassReader}.
396 *
397 * @param classVisitor the visitor that must visit this class.
398 * @param attributePrototypes prototypes of the attributes that must be parsed during the visit of
399 * the class. Any attribute whose type is not equal to the type of one the prototypes will not
400 * be parsed: its byte array value will be passed unchanged to the ClassWriter. <i>This may
401 * corrupt it if this value contains references to the constant pool, or has syntactic or
402 * semantic links with a class element that has been transformed by a class adapter between
403 * the reader and the writer</i>.
404 * @param parsingOptions the options to use to parse this class. One or more of {@link
405 * #SKIP_CODE}, {@link #SKIP_DEBUG}, {@link #SKIP_FRAMES} or {@link #EXPAND_FRAMES}.
406 */
407 public void accept(
408 final ClassVisitor classVisitor,
409 final Attribute[] attributePrototypes,
410 final int parsingOptions) {
411 Context context = new Context();
412 context.attributePrototypes = attributePrototypes;
413 context.parsingOptions = parsingOptions;
414 context.charBuffer = new char[maxStringLength];
415
416 // Read the access_flags, this_class, super_class, interface_count and interfaces fields.
417 char[] charBuffer = context.charBuffer;
418 int currentOffset = header;
419 int accessFlags = readUnsignedShort(currentOffset);
420 String thisClass = readClass(currentOffset + 2, charBuffer);
421 String superClass = readClass(currentOffset + 4, charBuffer);
422 String[] interfaces = new String[readUnsignedShort(currentOffset + 6)];
423 currentOffset += 8;
424 for (int i = 0; i < interfaces.length; ++i) {
425 interfaces[i] = readClass(currentOffset, charBuffer);
426 currentOffset += 2;
427 }
428
429 // Read the class attributes (the variables are ordered as in Section 4.7 of the JVMS).
430 // Attribute offsets exclude the attribute_name_index and attribute_length fields.
431 // - The offset of the InnerClasses attribute, or 0.
432 int innerClassesOffset = 0;
433 // - The offset of the EnclosingMethod attribute, or 0.
434 int enclosingMethodOffset = 0;
435 // - The string corresponding to the Signature attribute, or null.
436 String signature = null;
437 // - The string corresponding to the SourceFile attribute, or null.
438 String sourceFile = null;
439 // - The string corresponding to the SourceDebugExtension attribute, or null.
440 String sourceDebugExtension = null;
441 // - The offset of the RuntimeVisibleAnnotations attribute, or 0.
442 int runtimeVisibleAnnotationsOffset = 0;
443 // - The offset of the RuntimeInvisibleAnnotations attribute, or 0.
444 int runtimeInvisibleAnnotationsOffset = 0;
445 // - The offset of the RuntimeVisibleTypeAnnotations attribute, or 0.
446 int runtimeVisibleTypeAnnotationsOffset = 0;
447 // - The offset of the RuntimeInvisibleTypeAnnotations attribute, or 0.
448 int runtimeInvisibleTypeAnnotationsOffset = 0;
449 // - The offset of the Module attribute, or 0.
450 int moduleOffset = 0;
451 // - The offset of the ModulePackages attribute, or 0.
452 int modulePackagesOffset = 0;
453 // - The string corresponding to the ModuleMainClass attribute, or null.
454 String moduleMainClass = null;
455 // - The string corresponding to the NestHost attribute, or null.
456 String nestHostClass = null;
457 // - The offset of the NestMembers attribute, or 0.
458 int nestMembersOffset = 0;
459 // - The non standard attributes (linked with their {@link Attribute#nextAttribute} field).
460 // This list in the <i>reverse order</i> or their order in the ClassFile structure.
461 Attribute attributes = null;
462
463 int currentAttributeOffset = getFirstAttributeOffset();
464 for (int i = readUnsignedShort(currentAttributeOffset - 2); i > 0; --i) {
465 // Read the attribute_info's attribute_name and attribute_length fields.
466 String attributeName = readUTF8(currentAttributeOffset, charBuffer);
467 int attributeLength = readInt(currentAttributeOffset + 2);
468 currentAttributeOffset += 6;
469 // The tests are sorted in decreasing frequency order (based on frequencies observed on
470 // typical classes).
471 if (Constants.SOURCE_FILE.equals(attributeName)) {
472 sourceFile = readUTF8(currentAttributeOffset, charBuffer);
473 } else if (Constants.INNER_CLASSES.equals(attributeName)) {
474 innerClassesOffset = currentAttributeOffset;
475 } else if (Constants.ENCLOSING_METHOD.equals(attributeName)) {
476 enclosingMethodOffset = currentAttributeOffset;
477 } else if (Constants.NEST_HOST.equals(attributeName)) {
478 nestHostClass = readClass(currentAttributeOffset, charBuffer);
479 } else if (Constants.NEST_MEMBERS.equals(attributeName)) {
480 nestMembersOffset = currentAttributeOffset;
481 } else if (Constants.SIGNATURE.equals(attributeName)) {
482 signature = readUTF8(currentAttributeOffset, charBuffer);
483 } else if (Constants.RUNTIME_VISIBLE_ANNOTATIONS.equals(attributeName)) {
484 runtimeVisibleAnnotationsOffset = currentAttributeOffset;
485 } else if (Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) {
486 runtimeVisibleTypeAnnotationsOffset = currentAttributeOffset;
487 } else if (Constants.DEPRECATED.equals(attributeName)) {
488 accessFlags |= Opcodes.ACC_DEPRECATED;
489 } else if (Constants.SYNTHETIC.equals(attributeName)) {
490 accessFlags |= Opcodes.ACC_SYNTHETIC;
491 } else if (Constants.SOURCE_DEBUG_EXTENSION.equals(attributeName)) {
492 sourceDebugExtension =
493 readUTF(currentAttributeOffset, attributeLength, new char[attributeLength]);
494 } else if (Constants.RUNTIME_INVISIBLE_ANNOTATIONS.equals(attributeName)) {
495 runtimeInvisibleAnnotationsOffset = currentAttributeOffset;
496 } else if (Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) {
497 runtimeInvisibleTypeAnnotationsOffset = currentAttributeOffset;
498 } else if (Constants.MODULE.equals(attributeName)) {
499 moduleOffset = currentAttributeOffset;
500 } else if (Constants.MODULE_MAIN_CLASS.equals(attributeName)) {
501 moduleMainClass = readClass(currentAttributeOffset, charBuffer);
502 } else if (Constants.MODULE_PACKAGES.equals(attributeName)) {
503 modulePackagesOffset = currentAttributeOffset;
504 } else if (Constants.BOOTSTRAP_METHODS.equals(attributeName)) {
505 // This attribute is read in the constructor.
506 } else {
507 Attribute attribute =
508 readAttribute(
509 attributePrototypes,
510 attributeName,
511 currentAttributeOffset,
512 attributeLength,
513 charBuffer,
514 -1,
515 null);
516 attribute.nextAttribute = attributes;
517 attributes = attribute;
518 }
519 currentAttributeOffset += attributeLength;
520 }
521
522 // Visit the class declaration. The minor_version and major_version fields start 6 bytes before
523 // the first constant pool entry, which itself starts at cpInfoOffsets[1] - 1 (by definition).
524 classVisitor.visit(
525 readInt(cpInfoOffsets[1] - 7), accessFlags, thisClass, signature, superClass, interfaces);
526
527 // Visit the SourceFile and SourceDebugExtenstion attributes.
528 if ((parsingOptions & SKIP_DEBUG) == 0
529 && (sourceFile != null || sourceDebugExtension != null)) {
530 classVisitor.visitSource(sourceFile, sourceDebugExtension);
531 }
532
533 // Visit the Module, ModulePackages and ModuleMainClass attributes.
534 if (moduleOffset != 0) {
535 readModule(classVisitor, context, moduleOffset, modulePackagesOffset, moduleMainClass);
536 }
537
538 // Visit the NestHost attribute.
539 if (nestHostClass != null) {
540 classVisitor.visitNestHostExperimental(nestHostClass);
541 }
542
543 // Visit the EnclosingMethod attribute.
544 if (enclosingMethodOffset != 0) {
545 String className = readClass(enclosingMethodOffset, charBuffer);
546 int methodIndex = readUnsignedShort(enclosingMethodOffset + 2);
547 String name = methodIndex == 0 ? null : readUTF8(cpInfoOffsets[methodIndex], charBuffer);
548 String type = methodIndex == 0 ? null : readUTF8(cpInfoOffsets[methodIndex] + 2, charBuffer);
549 classVisitor.visitOuterClass(className, name, type);
550 }
551
552 // Visit the RuntimeVisibleAnnotations attribute.
553 if (runtimeVisibleAnnotationsOffset != 0) {
554 int numAnnotations = readUnsignedShort(runtimeVisibleAnnotationsOffset);
555 int currentAnnotationOffset = runtimeVisibleAnnotationsOffset + 2;
556 while (numAnnotations-- > 0) {
557 // Parse the type_index field.
558 String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
559 currentAnnotationOffset += 2;
560 // Parse num_element_value_pairs and element_value_pairs and visit these values.
561 currentAnnotationOffset =
562 readElementValues(
563 classVisitor.visitAnnotation(annotationDescriptor, /* visible = */ true),
564 currentAnnotationOffset,
565 /* named = */ true,
566 charBuffer);
567 }
568 }
569
570 // Visit the RuntimeInvisibleAnnotations attribute.
571 if (runtimeInvisibleAnnotationsOffset != 0) {
572 int numAnnotations = readUnsignedShort(runtimeInvisibleAnnotationsOffset);
573 int currentAnnotationOffset = runtimeInvisibleAnnotationsOffset + 2;
574 while (numAnnotations-- > 0) {
575 // Parse the type_index field.
576 String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
577 currentAnnotationOffset += 2;
578 // Parse num_element_value_pairs and element_value_pairs and visit these values.
579 currentAnnotationOffset =
580 readElementValues(
581 classVisitor.visitAnnotation(annotationDescriptor, /* visible = */ false),
582 currentAnnotationOffset,
583 /* named = */ true,
584 charBuffer);
585 }
586 }
587
588 // Visit the RuntimeVisibleTypeAnnotations attribute.
589 if (runtimeVisibleTypeAnnotationsOffset != 0) {
590 int numAnnotations = readUnsignedShort(runtimeVisibleTypeAnnotationsOffset);
591 int currentAnnotationOffset = runtimeVisibleTypeAnnotationsOffset + 2;
592 while (numAnnotations-- > 0) {
593 // Parse the target_type, target_info and target_path fields.
594 currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset);
595 // Parse the type_index field.
596 String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
597 currentAnnotationOffset += 2;
598 // Parse num_element_value_pairs and element_value_pairs and visit these values.
599 currentAnnotationOffset =
600 readElementValues(
601 classVisitor.visitTypeAnnotation(
602 context.currentTypeAnnotationTarget,
603 context.currentTypeAnnotationTargetPath,
604 annotationDescriptor,
605 /* visible = */ true),
606 currentAnnotationOffset,
607 /* named = */ true,
608 charBuffer);
609 }
610 }
611
612 // Visit the RuntimeInvisibleTypeAnnotations attribute.
613 if (runtimeInvisibleTypeAnnotationsOffset != 0) {
614 int numAnnotations = readUnsignedShort(runtimeInvisibleTypeAnnotationsOffset);
615 int currentAnnotationOffset = runtimeInvisibleTypeAnnotationsOffset + 2;
616 while (numAnnotations-- > 0) {
617 // Parse the target_type, target_info and target_path fields.
618 currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset);
619 // Parse the type_index field.
620 String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
621 currentAnnotationOffset += 2;
622 // Parse num_element_value_pairs and element_value_pairs and visit these values.
623 currentAnnotationOffset =
624 readElementValues(
625 classVisitor.visitTypeAnnotation(
626 context.currentTypeAnnotationTarget,
627 context.currentTypeAnnotationTargetPath,
628 annotationDescriptor,
629 /* visible = */ false),
630 currentAnnotationOffset,
631 /* named = */ true,
632 charBuffer);
633 }
634 }
635
636 // Visit the non standard attributes.
637 while (attributes != null) {
638 // Copy and reset the nextAttribute field so that it can also be used in ClassWriter.
639 Attribute nextAttribute = attributes.nextAttribute;
640 attributes.nextAttribute = null;
641 classVisitor.visitAttribute(attributes);
642 attributes = nextAttribute;
643 }
644
645 // Visit the NestedMembers attribute.
646 if (nestMembersOffset != 0) {
647 int numberOfNestMembers = readUnsignedShort(nestMembersOffset);
648 int currentNestMemberOffset = nestMembersOffset + 2;
649 while (numberOfNestMembers-- > 0) {
650 classVisitor.visitNestMemberExperimental(readClass(currentNestMemberOffset, charBuffer));
651 currentNestMemberOffset += 2;
652 }
653 }
654
655 // Visit the InnerClasses attribute.
656 if (innerClassesOffset != 0) {
657 int numberOfClasses = readUnsignedShort(innerClassesOffset);
658 int currentClassesOffset = innerClassesOffset + 2;
659 while (numberOfClasses-- > 0) {
660 classVisitor.visitInnerClass(
661 readClass(currentClassesOffset, charBuffer),
662 readClass(currentClassesOffset + 2, charBuffer),
663 readUTF8(currentClassesOffset + 4, charBuffer),
664 readUnsignedShort(currentClassesOffset + 6));
665 currentClassesOffset += 8;
666 }
667 }
668
669 // Visit the fields and methods.
670 int fieldsCount = readUnsignedShort(currentOffset);
671 currentOffset += 2;
672 while (fieldsCount-- > 0) {
673 currentOffset = readField(classVisitor, context, currentOffset);
674 }
675 int methodsCount = readUnsignedShort(currentOffset);
676 currentOffset += 2;
677 while (methodsCount-- > 0) {
678 currentOffset = readMethod(classVisitor, context, currentOffset);
679 }
680
681 // Visit the end of the class.
682 classVisitor.visitEnd();
683 }
684
685 // ----------------------------------------------------------------------------------------------
686 // Methods to parse modules, fields and methods
687 // ----------------------------------------------------------------------------------------------
688
689 /**
690 * Reads the module attribute and visit it.
691 *
692 * @param classVisitor the current class visitor
693 * @param context information about the class being parsed.
694 * @param moduleOffset the offset of the Module attribute (excluding the attribute_info's
695 * attribute_name_index and attribute_length fields).
696 * @param modulePackagesOffset the offset of the ModulePackages attribute (excluding the
697 * attribute_info's attribute_name_index and attribute_length fields), or 0.
698 * @param moduleMainClass the string corresponding to the ModuleMainClass attribute, or null.
699 */
700 private void readModule(
701 final ClassVisitor classVisitor,
702 final Context context,
703 final int moduleOffset,
704 final int modulePackagesOffset,
705 final String moduleMainClass) {
706 char[] buffer = context.charBuffer;
707
708 // Read the module_name_index, module_flags and module_version_index fields and visit them.
709 int currentOffset = moduleOffset;
710 String moduleName = readModule(currentOffset, buffer);
711 int moduleFlags = readUnsignedShort(currentOffset + 2);
712 String moduleVersion = readUTF8(currentOffset + 4, buffer);
713 currentOffset += 6;
714 ModuleVisitor moduleVisitor = classVisitor.visitModule(moduleName, moduleFlags, moduleVersion);
715 if (moduleVisitor == null) {
716 return;
717 }
718
719 // Visit the ModuleMainClass attribute.
720 if (moduleMainClass != null) {
721 moduleVisitor.visitMainClass(moduleMainClass);
722 }
723
724 // Visit the ModulePackages attribute.
725 if (modulePackagesOffset != 0) {
726 int packageCount = readUnsignedShort(modulePackagesOffset);
727 int currentPackageOffset = modulePackagesOffset + 2;
728 while (packageCount-- > 0) {
729 moduleVisitor.visitPackage(readPackage(currentPackageOffset, buffer));
730 currentPackageOffset += 2;
731 }
732 }
733
734 // Read the 'requires_count' and 'requires' fields.
735 int requiresCount = readUnsignedShort(currentOffset);
736 currentOffset += 2;
737 while (requiresCount-- > 0) {
738 // Read the requires_index, requires_flags and requires_version fields and visit them.
739 String requires = readModule(currentOffset, buffer);
740 int requiresFlags = readUnsignedShort(currentOffset + 2);
741 String requiresVersion = readUTF8(currentOffset + 4, buffer);
742 currentOffset += 6;
743 moduleVisitor.visitRequire(requires, requiresFlags, requiresVersion);
744 }
745
746 // Read the 'exports_count' and 'exports' fields.
747 int exportsCount = readUnsignedShort(currentOffset);
748 currentOffset += 2;
749 while (exportsCount-- > 0) {
750 // Read the exports_index, exports_flags, exports_to_count and exports_to_index fields
751 // and visit them.
752 String exports = readPackage(currentOffset, buffer);
753 int exportsFlags = readUnsignedShort(currentOffset + 2);
754 int exportsToCount = readUnsignedShort(currentOffset + 4);
755 currentOffset += 6;
756 String[] exportsTo = null;
757 if (exportsToCount != 0) {
758 exportsTo = new String[exportsToCount];
759 for (int i = 0; i < exportsToCount; ++i) {
760 exportsTo[i] = readModule(currentOffset, buffer);
761 currentOffset += 2;
762 }
763 }
764 moduleVisitor.visitExport(exports, exportsFlags, exportsTo);
765 }
766
767 // Reads the 'opens_count' and 'opens' fields.
768 int opensCount = readUnsignedShort(currentOffset);
769 currentOffset += 2;
770 while (opensCount-- > 0) {
771 // Read the opens_index, opens_flags, opens_to_count and opens_to_index fields and visit them.
772 String opens = readPackage(currentOffset, buffer);
773 int opensFlags = readUnsignedShort(currentOffset + 2);
774 int opensToCount = readUnsignedShort(currentOffset + 4);
775 currentOffset += 6;
776 String[] opensTo = null;
777 if (opensToCount != 0) {
778 opensTo = new String[opensToCount];
779 for (int i = 0; i < opensToCount; ++i) {
780 opensTo[i] = readModule(currentOffset, buffer);
781 currentOffset += 2;
782 }
783 }
784 moduleVisitor.visitOpen(opens, opensFlags, opensTo);
785 }
786
787 // Read the 'uses_count' and 'uses' fields.
788 int usesCount = readUnsignedShort(currentOffset);
789 currentOffset += 2;
790 while (usesCount-- > 0) {
791 moduleVisitor.visitUse(readClass(currentOffset, buffer));
792 currentOffset += 2;
793 }
794
795 // Read the 'provides_count' and 'provides' fields.
796 int providesCount = readUnsignedShort(currentOffset);
797 currentOffset += 2;
798 while (providesCount-- > 0) {
799 // Read the provides_index, provides_with_count and provides_with_index fields and visit them.
800 String provides = readClass(currentOffset, buffer);
801 int providesWithCount = readUnsignedShort(currentOffset + 2);
802 currentOffset += 4;
803 String[] providesWith = new String[providesWithCount];
804 for (int i = 0; i < providesWithCount; ++i) {
805 providesWith[i] = readClass(currentOffset, buffer);
806 currentOffset += 2;
807 }
808 moduleVisitor.visitProvide(provides, providesWith);
809 }
810
811 // Visit the end of the module attributes.
812 moduleVisitor.visitEnd();
813 }
814
815 /**
816 * Reads a JVMS field_info structure and makes the given visitor visit it.
817 *
818 * @param classVisitor the visitor that must visit the field.
819 * @param context information about the class being parsed.
820 * @param fieldInfoOffset the start offset of the field_info structure.
821 * @return the offset of the first byte following the field_info structure.
822 */
823 private int readField(
824 final ClassVisitor classVisitor, final Context context, final int fieldInfoOffset) {
825 char[] charBuffer = context.charBuffer;
826
827 // Read the access_flags, name_index and descriptor_index fields.
828 int currentOffset = fieldInfoOffset;
829 int accessFlags = readUnsignedShort(currentOffset);
830 String name = readUTF8(currentOffset + 2, charBuffer);
831 String descriptor = readUTF8(currentOffset + 4, charBuffer);
832 currentOffset += 6;
833
834 // Read the field attributes (the variables are ordered as in Section 4.7 of the JVMS).
835 // Attribute offsets exclude the attribute_name_index and attribute_length fields.
836 // - The value corresponding to the ConstantValue attribute, or null.
837 Object constantValue = null;
838 // - The string corresponding to the Signature attribute, or null.
839 String signature = null;
840 // - The offset of the RuntimeVisibleAnnotations attribute, or 0.
841 int runtimeVisibleAnnotationsOffset = 0;
842 // - The offset of the RuntimeInvisibleAnnotations attribute, or 0.
843 int runtimeInvisibleAnnotationsOffset = 0;
844 // - The offset of the RuntimeVisibleTypeAnnotations attribute, or 0.
845 int runtimeVisibleTypeAnnotationsOffset = 0;
846 // - The offset of the RuntimeInvisibleTypeAnnotations attribute, or 0.
847 int runtimeInvisibleTypeAnnotationsOffset = 0;
848 // - The non standard attributes (linked with their {@link Attribute#nextAttribute} field).
849 // This list in the <i>reverse order</i> or their order in the ClassFile structure.
850 Attribute attributes = null;
851
852 int attributesCount = readUnsignedShort(currentOffset);
853 currentOffset += 2;
854 while (attributesCount-- > 0) {
855 // Read the attribute_info's attribute_name and attribute_length fields.
856 String attributeName = readUTF8(currentOffset, charBuffer);
857 int attributeLength = readInt(currentOffset + 2);
858 currentOffset += 6;
859 // The tests are sorted in decreasing frequency order (based on frequencies observed on
860 // typical classes).
861 if (Constants.CONSTANT_VALUE.equals(attributeName)) {
862 int constantvalueIndex = readUnsignedShort(currentOffset);
863 constantValue = constantvalueIndex == 0 ? null : readConst(constantvalueIndex, charBuffer);
864 } else if (Constants.SIGNATURE.equals(attributeName)) {
865 signature = readUTF8(currentOffset, charBuffer);
866 } else if (Constants.DEPRECATED.equals(attributeName)) {
867 accessFlags |= Opcodes.ACC_DEPRECATED;
868 } else if (Constants.SYNTHETIC.equals(attributeName)) {
869 accessFlags |= Opcodes.ACC_SYNTHETIC;
870 } else if (Constants.RUNTIME_VISIBLE_ANNOTATIONS.equals(attributeName)) {
871 runtimeVisibleAnnotationsOffset = currentOffset;
872 } else if (Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) {
873 runtimeVisibleTypeAnnotationsOffset = currentOffset;
874 } else if (Constants.RUNTIME_INVISIBLE_ANNOTATIONS.equals(attributeName)) {
875 runtimeInvisibleAnnotationsOffset = currentOffset;
876 } else if (Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) {
877 runtimeInvisibleTypeAnnotationsOffset = currentOffset;
878 } else {
879 Attribute attribute =
880 readAttribute(
881 context.attributePrototypes,
882 attributeName,
883 currentOffset,
884 attributeLength,
885 charBuffer,
886 -1,
887 null);
888 attribute.nextAttribute = attributes;
889 attributes = attribute;
890 }
891 currentOffset += attributeLength;
892 }
893
894 // Visit the field declaration.
895 FieldVisitor fieldVisitor =
896 classVisitor.visitField(accessFlags, name, descriptor, signature, constantValue);
897 if (fieldVisitor == null) {
898 return currentOffset;
899 }
900
901 // Visit the RuntimeVisibleAnnotations attribute.
902 if (runtimeVisibleAnnotationsOffset != 0) {
903 int numAnnotations = readUnsignedShort(runtimeVisibleAnnotationsOffset);
904 int currentAnnotationOffset = runtimeVisibleAnnotationsOffset + 2;
905 while (numAnnotations-- > 0) {
906 // Parse the type_index field.
907 String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
908 currentAnnotationOffset += 2;
909 // Parse num_element_value_pairs and element_value_pairs and visit these values.
910 currentAnnotationOffset =
911 readElementValues(
912 fieldVisitor.visitAnnotation(annotationDescriptor, /* visible = */ true),
913 currentAnnotationOffset,
914 /* named = */ true,
915 charBuffer);
916 }
917 }
918
919 // Visit the RuntimeInvisibleAnnotations attribute.
920 if (runtimeInvisibleAnnotationsOffset != 0) {
921 int numAnnotations = readUnsignedShort(runtimeInvisibleAnnotationsOffset);
922 int currentAnnotationOffset = runtimeInvisibleAnnotationsOffset + 2;
923 while (numAnnotations-- > 0) {
924 // Parse the type_index field.
925 String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
926 currentAnnotationOffset += 2;
927 // Parse num_element_value_pairs and element_value_pairs and visit these values.
928 currentAnnotationOffset =
929 readElementValues(
930 fieldVisitor.visitAnnotation(annotationDescriptor, /* visible = */ false),
931 currentAnnotationOffset,
932 /* named = */ true,
933 charBuffer);
934 }
935 }
936
937 // Visit the RuntimeVisibleTypeAnnotations attribute.
938 if (runtimeVisibleTypeAnnotationsOffset != 0) {
939 int numAnnotations = readUnsignedShort(runtimeVisibleTypeAnnotationsOffset);
940 int currentAnnotationOffset = runtimeVisibleTypeAnnotationsOffset + 2;
941 while (numAnnotations-- > 0) {
942 // Parse the target_type, target_info and target_path fields.
943 currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset);
944 // Parse the type_index field.
945 String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
946 currentAnnotationOffset += 2;
947 // Parse num_element_value_pairs and element_value_pairs and visit these values.
948 currentAnnotationOffset =
949 readElementValues(
950 fieldVisitor.visitTypeAnnotation(
951 context.currentTypeAnnotationTarget,
952 context.currentTypeAnnotationTargetPath,
953 annotationDescriptor,
954 /* visible = */ true),
955 currentAnnotationOffset,
956 /* named = */ true,
957 charBuffer);
958 }
959 }
960
961 // Visit the RuntimeInvisibleTypeAnnotations attribute.
962 if (runtimeInvisibleTypeAnnotationsOffset != 0) {
963 int numAnnotations = readUnsignedShort(runtimeInvisibleTypeAnnotationsOffset);
964 int currentAnnotationOffset = runtimeInvisibleTypeAnnotationsOffset + 2;
965 while (numAnnotations-- > 0) {
966 // Parse the target_type, target_info and target_path fields.
967 currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset);
968 // Parse the type_index field.
969 String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
970 currentAnnotationOffset += 2;
971 // Parse num_element_value_pairs and element_value_pairs and visit these values.
972 currentAnnotationOffset =
973 readElementValues(
974 fieldVisitor.visitTypeAnnotation(
975 context.currentTypeAnnotationTarget,
976 context.currentTypeAnnotationTargetPath,
977 annotationDescriptor,
978 /* visible = */ false),
979 currentAnnotationOffset,
980 /* named = */ true,
981 charBuffer);
982 }
983 }
984
985 // Visit the non standard attributes.
986 while (attributes != null) {
987 // Copy and reset the nextAttribute field so that it can also be used in FieldWriter.
988 Attribute nextAttribute = attributes.nextAttribute;
989 attributes.nextAttribute = null;
990 fieldVisitor.visitAttribute(attributes);
991 attributes = nextAttribute;
992 }
993
994 // Visit the end of the field.
995 fieldVisitor.visitEnd();
996 return currentOffset;
997 }
998
999 /**
1000 * Reads a JVMS method_info structure and makes the given visitor visit it.
1001 *
1002 * @param classVisitor the visitor that must visit the method.
1003 * @param context information about the class being parsed.
1004 * @param methodInfoOffset the start offset of the method_info structure.
1005 * @return the offset of the first byte following the method_info structure.
1006 */
1007 private int readMethod(
1008 final ClassVisitor classVisitor, final Context context, final int methodInfoOffset) {
1009 char[] charBuffer = context.charBuffer;
1010
1011 // Read the access_flags, name_index and descriptor_index fields.
1012 int currentOffset = methodInfoOffset;
1013 context.currentMethodAccessFlags = readUnsignedShort(currentOffset);
1014 context.currentMethodName = readUTF8(currentOffset + 2, charBuffer);
1015 context.currentMethodDescriptor = readUTF8(currentOffset + 4, charBuffer);
1016 currentOffset += 6;
1017
1018 // Read the method attributes (the variables are ordered as in Section 4.7 of the JVMS).
1019 // Attribute offsets exclude the attribute_name_index and attribute_length fields.
1020 // - The offset of the Code attribute, or 0.
1021 int codeOffset = 0;
1022 // - The offset of the Exceptions attribute, or 0.
1023 int exceptionsOffset = 0;
1024 // - The strings corresponding to the Exceptions attribute, or null.
1025 String[] exceptions = null;
1026 // - Whether the method has a Synthetic attribute.
1027 boolean synthetic = false;
1028 // - The constant pool index contained in the Signature attribute, or 0.
1029 int signatureIndex = 0;
1030 // - The offset of the RuntimeVisibleAnnotations attribute, or 0.
1031 int runtimeVisibleAnnotationsOffset = 0;
1032 // - The offset of the RuntimeInvisibleAnnotations attribute, or 0.
1033 int runtimeInvisibleAnnotationsOffset = 0;
1034 // - The offset of the RuntimeVisibleParameterAnnotations attribute, or 0.
1035 int runtimeVisibleParameterAnnotationsOffset = 0;
1036 // - The offset of the RuntimeInvisibleParameterAnnotations attribute, or 0.
1037 int runtimeInvisibleParameterAnnotationsOffset = 0;
1038 // - The offset of the RuntimeVisibleTypeAnnotations attribute, or 0.
1039 int runtimeVisibleTypeAnnotationsOffset = 0;
1040 // - The offset of the RuntimeInvisibleTypeAnnotations attribute, or 0.
1041 int runtimeInvisibleTypeAnnotationsOffset = 0;
1042 // - The offset of the AnnotationDefault attribute, or 0.
1043 int annotationDefaultOffset = 0;
1044 // - The offset of the MethodParameters attribute, or 0.
1045 int methodParametersOffset = 0;
1046 // - The non standard attributes (linked with their {@link Attribute#nextAttribute} field).
1047 // This list in the <i>reverse order</i> or their order in the ClassFile structure.
1048 Attribute attributes = null;
1049
1050 int attributesCount = readUnsignedShort(currentOffset);
1051 currentOffset += 2;
1052 while (attributesCount-- > 0) {
1053 // Read the attribute_info's attribute_name and attribute_length fields.
1054 String attributeName = readUTF8(currentOffset, charBuffer);
1055 int attributeLength = readInt(currentOffset + 2);
1056 currentOffset += 6;
1057 // The tests are sorted in decreasing frequency order (based on frequencies observed on
1058 // typical classes).
1059 if (Constants.CODE.equals(attributeName)) {
1060 if ((context.parsingOptions & SKIP_CODE) == 0) {
1061 codeOffset = currentOffset;
1062 }
1063 } else if (Constants.EXCEPTIONS.equals(attributeName)) {
1064 exceptionsOffset = currentOffset;
1065 exceptions = new String[readUnsignedShort(exceptionsOffset)];
1066 int currentExceptionOffset = exceptionsOffset + 2;
1067 for (int i = 0; i < exceptions.length; ++i) {
1068 exceptions[i] = readClass(currentExceptionOffset, charBuffer);
1069 currentExceptionOffset += 2;
1070 }
1071 } else if (Constants.SIGNATURE.equals(attributeName)) {
1072 signatureIndex = readUnsignedShort(currentOffset);
1073 } else if (Constants.DEPRECATED.equals(attributeName)) {
1074 context.currentMethodAccessFlags |= Opcodes.ACC_DEPRECATED;
1075 } else if (Constants.RUNTIME_VISIBLE_ANNOTATIONS.equals(attributeName)) {
1076 runtimeVisibleAnnotationsOffset = currentOffset;
1077 } else if (Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) {
1078 runtimeVisibleTypeAnnotationsOffset = currentOffset;
1079 } else if (Constants.ANNOTATION_DEFAULT.equals(attributeName)) {
1080 annotationDefaultOffset = currentOffset;
1081 } else if (Constants.SYNTHETIC.equals(attributeName)) {
1082 synthetic = true;
1083 context.currentMethodAccessFlags |= Opcodes.ACC_SYNTHETIC;
1084 } else if (Constants.RUNTIME_INVISIBLE_ANNOTATIONS.equals(attributeName)) {
1085 runtimeInvisibleAnnotationsOffset = currentOffset;
1086 } else if (Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) {
1087 runtimeInvisibleTypeAnnotationsOffset = currentOffset;
1088 } else if (Constants.RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS.equals(attributeName)) {
1089 runtimeVisibleParameterAnnotationsOffset = currentOffset;
1090 } else if (Constants.RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS.equals(attributeName)) {
1091 runtimeInvisibleParameterAnnotationsOffset = currentOffset;
1092 } else if (Constants.METHOD_PARAMETERS.equals(attributeName)) {
1093 methodParametersOffset = currentOffset;
1094 } else {
1095 Attribute attribute =
1096 readAttribute(
1097 context.attributePrototypes,
1098 attributeName,
1099 currentOffset,
1100 attributeLength,
1101 charBuffer,
1102 -1,
1103 null);
1104 attribute.nextAttribute = attributes;
1105 attributes = attribute;
1106 }
1107 currentOffset += attributeLength;
1108 }
1109
1110 // Visit the method declaration.
1111 MethodVisitor methodVisitor =
1112 classVisitor.visitMethod(
1113 context.currentMethodAccessFlags,
1114 context.currentMethodName,
1115 context.currentMethodDescriptor,
1116 signatureIndex == 0 ? null : readUTF(signatureIndex, charBuffer),
1117 exceptions);
1118 if (methodVisitor == null) {
1119 return currentOffset;
1120 }
1121
1122 // If the returned MethodVisitor is in fact a MethodWriter, it means there is no method
1123 // adapter between the reader and the writer. In this case, it might be possible to copy
1124 // the method attributes directly into the writer. If so, return early without visiting
1125 // the content of these attributes.
1126 if (methodVisitor instanceof MethodWriter) {
1127 MethodWriter methodWriter = (MethodWriter) methodVisitor;
1128 if (methodWriter.canCopyMethodAttributes(
1129 this,
1130 methodInfoOffset,
1131 currentOffset - methodInfoOffset,
1132 synthetic,
1133 (context.currentMethodAccessFlags & Opcodes.ACC_DEPRECATED) != 0,
1134 signatureIndex,
1135 exceptionsOffset)) {
1136 return currentOffset;
1137 }
1138 }
1139
1140 // Visit the MethodParameters attribute.
1141 if (methodParametersOffset != 0) {
1142 int parametersCount = readByte(methodParametersOffset);
1143 int currentParameterOffset = methodParametersOffset + 1;
1144 while (parametersCount-- > 0) {
1145 // Read the name_index and access_flags fields and visit them.
1146 methodVisitor.visitParameter(
1147 readUTF8(currentParameterOffset, charBuffer),
1148 readUnsignedShort(currentParameterOffset + 2));
1149 currentParameterOffset += 4;
1150 }
1151 }
1152
1153 // Visit the AnnotationDefault attribute.
1154 if (annotationDefaultOffset != 0) {
1155 AnnotationVisitor annotationVisitor = methodVisitor.visitAnnotationDefault();
1156 readElementValue(annotationVisitor, annotationDefaultOffset, null, charBuffer);
1157 if (annotationVisitor != null) {
1158 annotationVisitor.visitEnd();
1159 }
1160 }
1161
1162 // Visit the RuntimeVisibleAnnotations attribute.
1163 if (runtimeVisibleAnnotationsOffset != 0) {
1164 int numAnnotations = readUnsignedShort(runtimeVisibleAnnotationsOffset);
1165 int currentAnnotationOffset = runtimeVisibleAnnotationsOffset + 2;
1166 while (numAnnotations-- > 0) {
1167 // Parse the type_index field.
1168 String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
1169 currentAnnotationOffset += 2;
1170 // Parse num_element_value_pairs and element_value_pairs and visit these values.
1171 currentAnnotationOffset =
1172 readElementValues(
1173 methodVisitor.visitAnnotation(annotationDescriptor, /* visible = */ true),
1174 currentAnnotationOffset,
1175 /* named = */ true,
1176 charBuffer);
1177 }
1178 }
1179
1180 // Visit the RuntimeInvisibleAnnotations attribute.
1181 if (runtimeInvisibleAnnotationsOffset != 0) {
1182 int numAnnotations = readUnsignedShort(runtimeInvisibleAnnotationsOffset);
1183 int currentAnnotationOffset = runtimeInvisibleAnnotationsOffset + 2;
1184 while (numAnnotations-- > 0) {
1185 // Parse the type_index field.
1186 String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
1187 currentAnnotationOffset += 2;
1188 // Parse num_element_value_pairs and element_value_pairs and visit these values.
1189 currentAnnotationOffset =
1190 readElementValues(
1191 methodVisitor.visitAnnotation(annotationDescriptor, /* visible = */ false),
1192 currentAnnotationOffset,
1193 /* named = */ true,
1194 charBuffer);
1195 }
1196 }
1197
1198 // Visit the RuntimeVisibleTypeAnnotations attribute.
1199 if (runtimeVisibleTypeAnnotationsOffset != 0) {
1200 int numAnnotations = readUnsignedShort(runtimeVisibleTypeAnnotationsOffset);
1201 int currentAnnotationOffset = runtimeVisibleTypeAnnotationsOffset + 2;
1202 while (numAnnotations-- > 0) {
1203 // Parse the target_type, target_info and target_path fields.
1204 currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset);
1205 // Parse the type_index field.
1206 String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
1207 currentAnnotationOffset += 2;
1208 // Parse num_element_value_pairs and element_value_pairs and visit these values.
1209 currentAnnotationOffset =
1210 readElementValues(
1211 methodVisitor.visitTypeAnnotation(
1212 context.currentTypeAnnotationTarget,
1213 context.currentTypeAnnotationTargetPath,
1214 annotationDescriptor,
1215 /* visible = */ true),
1216 currentAnnotationOffset,
1217 /* named = */ true,
1218 charBuffer);
1219 }
1220 }
1221
1222 // Visit the RuntimeInvisibleTypeAnnotations attribute.
1223 if (runtimeInvisibleTypeAnnotationsOffset != 0) {
1224 int numAnnotations = readUnsignedShort(runtimeInvisibleTypeAnnotationsOffset);
1225 int currentAnnotationOffset = runtimeInvisibleTypeAnnotationsOffset + 2;
1226 while (numAnnotations-- > 0) {
1227 // Parse the target_type, target_info and target_path fields.
1228 currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset);
1229 // Parse the type_index field.
1230 String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
1231 currentAnnotationOffset += 2;
1232 // Parse num_element_value_pairs and element_value_pairs and visit these values.
1233 currentAnnotationOffset =
1234 readElementValues(
1235 methodVisitor.visitTypeAnnotation(
1236 context.currentTypeAnnotationTarget,
1237 context.currentTypeAnnotationTargetPath,
1238 annotationDescriptor,
1239 /* visible = */ false),
1240 currentAnnotationOffset,
1241 /* named = */ true,
1242 charBuffer);
1243 }
1244 }
1245
1246 // Visit the RuntimeVisibleParameterAnnotations attribute.
1247 if (runtimeVisibleParameterAnnotationsOffset != 0) {
1248 readParameterAnnotations(
1249 methodVisitor, context, runtimeVisibleParameterAnnotationsOffset, /* visible = */ true);
1250 }
1251
1252 // Visit the RuntimeInvisibleParameterAnnotations attribute.
1253 if (runtimeInvisibleParameterAnnotationsOffset != 0) {
1254 readParameterAnnotations(
1255 methodVisitor,
1256 context,
1257 runtimeInvisibleParameterAnnotationsOffset,
1258 /* visible = */ false);
1259 }
1260
1261 // Visit the non standard attributes.
1262 while (attributes != null) {
1263 // Copy and reset the nextAttribute field so that it can also be used in MethodWriter.
1264 Attribute nextAttribute = attributes.nextAttribute;
1265 attributes.nextAttribute = null;
1266 methodVisitor.visitAttribute(attributes);
1267 attributes = nextAttribute;
1268 }
1269
1270 // Visit the Code attribute.
1271 if (codeOffset != 0) {
1272 methodVisitor.visitCode();
1273 readCode(methodVisitor, context, codeOffset);
1274 }
1275
1276 // Visit the end of the method.
1277 methodVisitor.visitEnd();
1278 return currentOffset;
1279 }
1280
1281 // ----------------------------------------------------------------------------------------------
1282 // Methods to parse a Code attribute
1283 // ----------------------------------------------------------------------------------------------
1284
1285 /**
1286 * Reads a JVMS 'Code' attribute and makes the given visitor visit it.
1287 *
1288 * @param methodVisitor the visitor that must visit the Code attribute.
1289 * @param context information about the class being parsed.
1290 * @param codeOffset the start offset in {@link #b} of the Code attribute, excluding its
1291 * attribute_name_index and attribute_length fields.
1292 */
1293 private void readCode(
1294 final MethodVisitor methodVisitor, final Context context, final int codeOffset) {
1295 int currentOffset = codeOffset;
1296
1297 // Read the max_stack, max_locals and code_length fields.
1298 final byte[] classFileBuffer = b;
1299 final char[] charBuffer = context.charBuffer;
1300 final int maxStack = readUnsignedShort(currentOffset);
1301 final int maxLocals = readUnsignedShort(currentOffset + 2);
1302 final int codeLength = readInt(currentOffset + 4);
1303 currentOffset += 8;
1304
1305 // Read the bytecode 'code' array to create a label for each referenced instruction.
1306 final int bytecodeStartOffset = currentOffset;
1307 final int bytecodeEndOffset = currentOffset + codeLength;
1308 final Label[] labels = context.currentMethodLabels = new Label[codeLength + 1];
1309 while (currentOffset < bytecodeEndOffset) {
1310 final int bytecodeOffset = currentOffset - bytecodeStartOffset;
1311 final int opcode = classFileBuffer[currentOffset] & 0xFF;
1312 switch (opcode) {
1313 case Constants.NOP:
1314 case Constants.ACONST_NULL:
1315 case Constants.ICONST_M1:
1316 case Constants.ICONST_0:
1317 case Constants.ICONST_1:
1318 case Constants.ICONST_2:
1319 case Constants.ICONST_3:
1320 case Constants.ICONST_4:
1321 case Constants.ICONST_5:
1322 case Constants.LCONST_0:
1323 case Constants.LCONST_1:
1324 case Constants.FCONST_0:
1325 case Constants.FCONST_1:
1326 case Constants.FCONST_2:
1327 case Constants.DCONST_0:
1328 case Constants.DCONST_1:
1329 case Constants.IALOAD:
1330 case Constants.LALOAD:
1331 case Constants.FALOAD:
1332 case Constants.DALOAD:
1333 case Constants.AALOAD:
1334 case Constants.BALOAD:
1335 case Constants.CALOAD:
1336 case Constants.SALOAD:
1337 case Constants.IASTORE:
1338 case Constants.LASTORE:
1339 case Constants.FASTORE:
1340 case Constants.DASTORE:
1341 case Constants.AASTORE:
1342 case Constants.BASTORE:
1343 case Constants.CASTORE:
1344 case Constants.SASTORE:
1345 case Constants.POP:
1346 case Constants.POP2:
1347 case Constants.DUP:
1348 case Constants.DUP_X1:
1349 case Constants.DUP_X2:
1350 case Constants.DUP2:
1351 case Constants.DUP2_X1:
1352 case Constants.DUP2_X2:
1353 case Constants.SWAP:
1354 case Constants.IADD:
1355 case Constants.LADD:
1356 case Constants.FADD:
1357 case Constants.DADD:
1358 case Constants.ISUB:
1359 case Constants.LSUB:
1360 case Constants.FSUB:
1361 case Constants.DSUB:
1362 case Constants.IMUL:
1363 case Constants.LMUL:
1364 case Constants.FMUL:
1365 case Constants.DMUL:
1366 case Constants.IDIV:
1367 case Constants.LDIV:
1368 case Constants.FDIV:
1369 case Constants.DDIV:
1370 case Constants.IREM:
1371 case Constants.LREM:
1372 case Constants.FREM:
1373 case Constants.DREM:
1374 case Constants.INEG:
1375 case Constants.LNEG:
1376 case Constants.FNEG:
1377 case Constants.DNEG:
1378 case Constants.ISHL:
1379 case Constants.LSHL:
1380 case Constants.ISHR:
1381 case Constants.LSHR:
1382 case Constants.IUSHR:
1383 case Constants.LUSHR:
1384 case Constants.IAND:
1385 case Constants.LAND:
1386 case Constants.IOR:
1387 case Constants.LOR:
1388 case Constants.IXOR:
1389 case Constants.LXOR:
1390 case Constants.I2L:
1391 case Constants.I2F:
1392 case Constants.I2D:
1393 case Constants.L2I:
1394 case Constants.L2F:
1395 case Constants.L2D:
1396 case Constants.F2I:
1397 case Constants.F2L:
1398 case Constants.F2D:
1399 case Constants.D2I:
1400 case Constants.D2L:
1401 case Constants.D2F:
1402 case Constants.I2B:
1403 case Constants.I2C:
1404 case Constants.I2S:
1405 case Constants.LCMP:
1406 case Constants.FCMPL:
1407 case Constants.FCMPG:
1408 case Constants.DCMPL:
1409 case Constants.DCMPG:
1410 case Constants.IRETURN:
1411 case Constants.LRETURN:
1412 case Constants.FRETURN:
1413 case Constants.DRETURN:
1414 case Constants.ARETURN:
1415 case Constants.RETURN:
1416 case Constants.ARRAYLENGTH:
1417 case Constants.ATHROW:
1418 case Constants.MONITORENTER:
1419 case Constants.MONITOREXIT:
1420 case Constants.ILOAD_0:
1421 case Constants.ILOAD_1:
1422 case Constants.ILOAD_2:
1423 case Constants.ILOAD_3:
1424 case Constants.LLOAD_0:
1425 case Constants.LLOAD_1:
1426 case Constants.LLOAD_2:
1427 case Constants.LLOAD_3:
1428 case Constants.FLOAD_0:
1429 case Constants.FLOAD_1:
1430 case Constants.FLOAD_2:
1431 case Constants.FLOAD_3:
1432 case Constants.DLOAD_0:
1433 case Constants.DLOAD_1:
1434 case Constants.DLOAD_2:
1435 case Constants.DLOAD_3:
1436 case Constants.ALOAD_0:
1437 case Constants.ALOAD_1:
1438 case Constants.ALOAD_2:
1439 case Constants.ALOAD_3:
1440 case Constants.ISTORE_0:
1441 case Constants.ISTORE_1:
1442 case Constants.ISTORE_2:
1443 case Constants.ISTORE_3:
1444 case Constants.LSTORE_0:
1445 case Constants.LSTORE_1:
1446 case Constants.LSTORE_2:
1447 case Constants.LSTORE_3:
1448 case Constants.FSTORE_0:
1449 case Constants.FSTORE_1:
1450 case Constants.FSTORE_2:
1451 case Constants.FSTORE_3:
1452 case Constants.DSTORE_0:
1453 case Constants.DSTORE_1:
1454 case Constants.DSTORE_2:
1455 case Constants.DSTORE_3:
1456 case Constants.ASTORE_0:
1457 case Constants.ASTORE_1:
1458 case Constants.ASTORE_2:
1459 case Constants.ASTORE_3:
1460 currentOffset += 1;
1461 break;
1462 case Constants.IFEQ:
1463 case Constants.IFNE:
1464 case Constants.IFLT:
1465 case Constants.IFGE:
1466 case Constants.IFGT:
1467 case Constants.IFLE:
1468 case Constants.IF_ICMPEQ:
1469 case Constants.IF_ICMPNE:
1470 case Constants.IF_ICMPLT:
1471 case Constants.IF_ICMPGE:
1472 case Constants.IF_ICMPGT:
1473 case Constants.IF_ICMPLE:
1474 case Constants.IF_ACMPEQ:
1475 case Constants.IF_ACMPNE:
1476 case Constants.GOTO:
1477 case Constants.JSR:
1478 case Constants.IFNULL:
1479 case Constants.IFNONNULL:
1480 createLabel(bytecodeOffset + readShort(currentOffset + 1), labels);
1481 currentOffset += 3;
1482 break;
1483 case Constants.ASM_IFEQ:
1484 case Constants.ASM_IFNE:
1485 case Constants.ASM_IFLT:
1486 case Constants.ASM_IFGE:
1487 case Constants.ASM_IFGT:
1488 case Constants.ASM_IFLE:
1489 case Constants.ASM_IF_ICMPEQ:
1490 case Constants.ASM_IF_ICMPNE:
1491 case Constants.ASM_IF_ICMPLT:
1492 case Constants.ASM_IF_ICMPGE:
1493 case Constants.ASM_IF_ICMPGT:
1494 case Constants.ASM_IF_ICMPLE:
1495 case Constants.ASM_IF_ACMPEQ:
1496 case Constants.ASM_IF_ACMPNE:
1497 case Constants.ASM_GOTO:
1498 case Constants.ASM_JSR:
1499 case Constants.ASM_IFNULL:
1500 case Constants.ASM_IFNONNULL:
1501 createLabel(bytecodeOffset + readUnsignedShort(currentOffset + 1), labels);
1502 currentOffset += 3;
1503 break;
1504 case Constants.GOTO_W:
1505 case Constants.JSR_W:
1506 case Constants.ASM_GOTO_W:
1507 createLabel(bytecodeOffset + readInt(currentOffset + 1), labels);
1508 currentOffset += 5;
1509 break;
1510 case Constants.WIDE:
1511 switch (classFileBuffer[currentOffset + 1] & 0xFF) {
1512 case Constants.ILOAD:
1513 case Constants.FLOAD:
1514 case Constants.ALOAD:
1515 case Constants.LLOAD:
1516 case Constants.DLOAD:
1517 case Constants.ISTORE:
1518 case Constants.FSTORE:
1519 case Constants.ASTORE:
1520 case Constants.LSTORE:
1521 case Constants.DSTORE:
1522 case Constants.RET:
1523 currentOffset += 4;
1524 break;
1525 case Constants.IINC:
1526 currentOffset += 6;
1527 break;
2061528 default:
207 size = 3;
208 break;
1529 throw new IllegalArgumentException();
1530 }
1531 break;
1532 case Constants.TABLESWITCH:
1533 // Skip 0 to 3 padding bytes.
1534 currentOffset += 4 - (bytecodeOffset & 3);
1535 // Read the default label and the number of table entries.
1536 createLabel(bytecodeOffset + readInt(currentOffset), labels);
1537 int numTableEntries = readInt(currentOffset + 8) - readInt(currentOffset + 4) + 1;
1538 currentOffset += 12;
1539 // Read the table labels.
1540 while (numTableEntries-- > 0) {
1541 createLabel(bytecodeOffset + readInt(currentOffset), labels);
1542 currentOffset += 4;
1543 }
1544 break;
1545 case Constants.LOOKUPSWITCH:
1546 // Skip 0 to 3 padding bytes.
1547 currentOffset += 4 - (bytecodeOffset & 3);
1548 // Read the default label and the number of switch cases.
1549 createLabel(bytecodeOffset + readInt(currentOffset), labels);
1550 int numSwitchCases = readInt(currentOffset + 4);
1551 currentOffset += 8;
1552 // Read the switch labels.
1553 while (numSwitchCases-- > 0) {
1554 createLabel(bytecodeOffset + readInt(currentOffset + 4), labels);
1555 currentOffset += 8;
1556 }
1557 break;
1558 case Constants.ILOAD:
1559 case Constants.LLOAD:
1560 case Constants.FLOAD:
1561 case Constants.DLOAD:
1562 case Constants.ALOAD:
1563 case Constants.ISTORE:
1564 case Constants.LSTORE:
1565 case Constants.FSTORE:
1566 case Constants.DSTORE:
1567 case Constants.ASTORE:
1568 case Constants.RET:
1569 case Constants.BIPUSH:
1570 case Constants.NEWARRAY:
1571 case Constants.LDC:
1572 currentOffset += 2;
1573 break;
1574 case Constants.SIPUSH:
1575 case Constants.LDC_W:
1576 case Constants.LDC2_W:
1577 case Constants.GETSTATIC:
1578 case Constants.PUTSTATIC:
1579 case Constants.GETFIELD:
1580 case Constants.PUTFIELD:
1581 case Constants.INVOKEVIRTUAL:
1582 case Constants.INVOKESPECIAL:
1583 case Constants.INVOKESTATIC:
1584 case Constants.NEW:
1585 case Constants.ANEWARRAY:
1586 case Constants.CHECKCAST:
1587 case Constants.INSTANCEOF:
1588 case Constants.IINC:
1589 currentOffset += 3;
1590 break;
1591 case Constants.INVOKEINTERFACE:
1592 case Constants.INVOKEDYNAMIC:
1593 currentOffset += 5;
1594 break;
1595 case Constants.MULTIANEWARRAY:
1596 currentOffset += 4;
1597 break;
1598 default:
1599 throw new IllegalArgumentException();
1600 }
1601 }
1602
1603 // Read the 'exception_table_length' and 'exception_table' field to create a label for each
1604 // referenced instruction, and to make methodVisitor visit the corresponding try catch blocks.
1605 {
1606 int exceptionTableLength = readUnsignedShort(currentOffset);
1607 currentOffset += 2;
1608 while (exceptionTableLength-- > 0) {
1609 Label start = createLabel(readUnsignedShort(currentOffset), labels);
1610 Label end = createLabel(readUnsignedShort(currentOffset + 2), labels);
1611 Label handler = createLabel(readUnsignedShort(currentOffset + 4), labels);
1612 String catchType =
1613 readUTF8(cpInfoOffsets[readUnsignedShort(currentOffset + 6)], charBuffer);
1614 currentOffset += 8;
1615 methodVisitor.visitTryCatchBlock(start, end, handler, catchType);
1616 }
1617 }
1618
1619 // Read the Code attributes to create a label for each referenced instruction (the variables
1620 // are ordered as in Section 4.7 of the JVMS). Attribute offsets exclude the
1621 // attribute_name_index and attribute_length fields.
1622 // - The offset of the current 'stack_map_frame' in the StackMap[Table] attribute, or 0.
1623 // Initially, this is the offset of the first 'stack_map_frame' entry. Then this offset is
1624 // updated after each stack_map_frame is read.
1625 int stackMapFrameOffset = 0;
1626 // - The end offset of the StackMap[Table] attribute, or 0.
1627 int stackMapTableEndOffset = 0;
1628 // - Whether the stack map frames are compressed (i.e. in a StackMapTable) or not.
1629 boolean compressedFrames = true;
1630 // - The offset of the LocalVariableTable attribute, or 0.
1631 int localVariableTableOffset = 0;
1632 // - The offset of the LocalVariableTypeTable attribute, or 0.
1633 int localVariableTypeTableOffset = 0;
1634 // - The offset of each 'type_annotation' entry in the RuntimeVisibleTypeAnnotations
1635 // attribute, or null.
1636 int[] visibleTypeAnnotationOffsets = null;
1637 // - The offset of each 'type_annotation' entry in the RuntimeInvisibleTypeAnnotations
1638 // attribute, or null.
1639 int[] invisibleTypeAnnotationOffsets = null;
1640 // - The non standard attributes (linked with their {@link Attribute#nextAttribute} field).
1641 // This list in the <i>reverse order</i> or their order in the ClassFile structure.
1642 Attribute attributes = null;
1643
1644 int attributesCount = readUnsignedShort(currentOffset);
1645 currentOffset += 2;
1646 while (attributesCount-- > 0) {
1647 // Read the attribute_info's attribute_name and attribute_length fields.
1648 String attributeName = readUTF8(currentOffset, charBuffer);
1649 int attributeLength = readInt(currentOffset + 2);
1650 currentOffset += 6;
1651 if (Constants.LOCAL_VARIABLE_TABLE.equals(attributeName)) {
1652 if ((context.parsingOptions & SKIP_DEBUG) == 0) {
1653 localVariableTableOffset = currentOffset;
1654 // Parse the attribute to find the corresponding (debug only) labels.
1655 int currentLocalVariableTableOffset = currentOffset;
1656 int localVariableTableLength = readUnsignedShort(currentLocalVariableTableOffset);
1657 currentLocalVariableTableOffset += 2;
1658 while (localVariableTableLength-- > 0) {
1659 int startPc = readUnsignedShort(currentLocalVariableTableOffset);
1660 createDebugLabel(startPc, labels);
1661 int length = readUnsignedShort(currentLocalVariableTableOffset + 2);
1662 createDebugLabel(startPc + length, labels);
1663 // Skip the name_index, descriptor_index and index fields (2 bytes each).
1664 currentLocalVariableTableOffset += 10;
1665 }
1666 }
1667 } else if (Constants.LOCAL_VARIABLE_TYPE_TABLE.equals(attributeName)) {
1668 localVariableTypeTableOffset = currentOffset;
1669 // Here we do not extract the labels corresponding to the attribute content. We assume they
1670 // are the same or a subset of those of the LocalVariableTable attribute.
1671 } else if (Constants.LINE_NUMBER_TABLE.equals(attributeName)) {
1672 if ((context.parsingOptions & SKIP_DEBUG) == 0) {
1673 // Parse the attribute to find the corresponding (debug only) labels.
1674 int currentLineNumberTableOffset = currentOffset;
1675 int lineNumberTableLength = readUnsignedShort(currentLineNumberTableOffset);
1676 currentLineNumberTableOffset += 2;
1677 while (lineNumberTableLength-- > 0) {
1678 int startPc = readUnsignedShort(currentLineNumberTableOffset);
1679 int lineNumber = readUnsignedShort(currentLineNumberTableOffset + 2);
1680 currentLineNumberTableOffset += 4;
1681 createDebugLabel(startPc, labels);
1682 labels[startPc].addLineNumber(lineNumber);
1683 }
1684 }
1685 } else if (Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) {
1686 visibleTypeAnnotationOffsets =
1687 readTypeAnnotations(methodVisitor, context, currentOffset, /* visible = */ true);
1688 // Here we do not extract the labels corresponding to the attribute content. This would
1689 // require a full parsing of the attribute, which would need to be repeated when parsing
1690 // the bytecode instructions (see below). Instead, the content of the attribute is read one
1691 // type annotation at a time (i.e. after a type annotation has been visited, the next type
1692 // annotation is read), and the labels it contains are also extracted one annotation at a
1693 // time. This assumes that type annotations are ordered by increasing bytecode offset.
1694 } else if (Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) {
1695 invisibleTypeAnnotationOffsets =
1696 readTypeAnnotations(methodVisitor, context, currentOffset, /* visible = */ false);
1697 // Same comment as above for the RuntimeVisibleTypeAnnotations attribute.
1698 } else if (Constants.STACK_MAP_TABLE.equals(attributeName)) {
1699 if ((context.parsingOptions & SKIP_FRAMES) == 0) {
1700 stackMapFrameOffset = currentOffset + 2;
1701 stackMapTableEndOffset = currentOffset + attributeLength;
1702 }
1703 // Here we do not extract the labels corresponding to the attribute content. This would
1704 // require a full parsing of the attribute, which would need to be repeated when parsing
1705 // the bytecode instructions (see below). Instead, the content of the attribute is read one
1706 // frame at a time (i.e. after a frame has been visited, the next frame is read), and the
1707 // labels it contains are also extracted one frame at a time. Thanks to the ordering of
1708 // frames, having only a "one frame lookahead" is not a problem, i.e. it is not possible to
1709 // see an offset smaller than the offset of the current instruction and for which no Label
1710 // exist. Except for UNINITIALIZED type offsets. We solve this by parsing the stack map
1711 // table without a full decoding (see below).
1712 } else if ("StackMap".equals(attributeName)) {
1713 if ((context.parsingOptions & SKIP_FRAMES) == 0) {
1714 stackMapFrameOffset = currentOffset + 2;
1715 stackMapTableEndOffset = currentOffset + attributeLength;
1716 compressedFrames = false;
1717 }
1718 // IMPORTANT! Here we assume that the frames are ordered, as in the StackMapTable attribute,
1719 // although this is not guaranteed by the attribute format. This allows an incremental
1720 // extraction of the labels corresponding to this attribute (see the comment above for the
1721 // StackMapTable attribute).
1722 } else {
1723 Attribute attribute =
1724 readAttribute(
1725 context.attributePrototypes,
1726 attributeName,
1727 currentOffset,
1728 attributeLength,
1729 charBuffer,
1730 codeOffset,
1731 labels);
1732 attribute.nextAttribute = attributes;
1733 attributes = attribute;
1734 }
1735 currentOffset += attributeLength;
1736 }
1737
1738 // Initialize the context fields related to stack map frames, and generate the first
1739 // (implicit) stack map frame, if needed.
1740 final boolean expandFrames = (context.parsingOptions & EXPAND_FRAMES) != 0;
1741 if (stackMapFrameOffset != 0) {
1742 // The bytecode offset of the first explicit frame is not offset_delta + 1 but only
1743 // offset_delta. Setting the implicit frame offset to -1 allows us to use of the
1744 // "offset_delta + 1" rule in all cases.
1745 context.currentFrameOffset = -1;
1746 context.currentFrameType = 0;
1747 context.currentFrameLocalCount = 0;
1748 context.currentFrameLocalCountDelta = 0;
1749 context.currentFrameLocalTypes = new Object[maxLocals];
1750 context.currentFrameStackCount = 0;
1751 context.currentFrameStackTypes = new Object[maxStack];
1752 if (expandFrames) {
1753 computeImplicitFrame(context);
1754 }
1755 // Find the labels for UNINITIALIZED frame types. Instead of decoding each element of the
1756 // stack map table, we look for 3 consecutive bytes that "look like" an UNINITIALIZED type
1757 // (tag ITEM_Uninitialized, offset within bytecode bounds, NEW instruction at this offset).
1758 // We may find false positives (i.e. not real UNINITIALIZED types), but this should be rare,
1759 // and the only consequence will be the creation of an unneeded label. This is better than
1760 // creating a label for each NEW instruction, and faster than fully decoding the whole stack
1761 // map table.
1762 for (int offset = stackMapFrameOffset; offset < stackMapTableEndOffset - 2; ++offset) {
1763 if (classFileBuffer[offset] == Frame.ITEM_UNINITIALIZED) {
1764 int potentialBytecodeOffset = readUnsignedShort(offset + 1);
1765 if (potentialBytecodeOffset >= 0
1766 && potentialBytecodeOffset < codeLength
1767 && (classFileBuffer[bytecodeStartOffset + potentialBytecodeOffset] & 0xFF)
1768 == Opcodes.NEW) {
1769 createLabel(potentialBytecodeOffset, labels);
1770 }
1771 }
1772 }
1773 }
1774 if (expandFrames && (context.parsingOptions & EXPAND_ASM_INSNS) != 0) {
1775 // Expanding the ASM specific instructions can introduce F_INSERT frames, even if the method
1776 // does not currently have any frame. These inserted frames must be computed by simulating the
1777 // effect of the bytecode instructions, one by one, starting from the implicit first frame.
1778 // For this, MethodWriter needs to know maxLocals before the first instruction is visited. To
1779 // ensure this, we visit the implicit first frame here (passing only maxLocals - the rest is
1780 // computed in MethodWriter).
1781 methodVisitor.visitFrame(Opcodes.F_NEW, maxLocals, null, 0, null);
1782 }
1783
1784 // Visit the bytecode instructions. First, introduce state variables for the incremental parsing
1785 // of the type annotations.
1786
1787 // Index of the next runtime visible type annotation to read (in the
1788 // visibleTypeAnnotationOffsets array).
1789 int currentVisibleTypeAnnotationIndex = 0;
1790 // The bytecode offset of the next runtime visible type annotation to read, or -1.
1791 int currentVisibleTypeAnnotationBytecodeOffset =
1792 getTypeAnnotationBytecodeOffset(visibleTypeAnnotationOffsets, 0);
1793 // Index of the next runtime invisible type annotation to read (in the
1794 // invisibleTypeAnnotationOffsets array).
1795 int currentInvisibleTypeAnnotationIndex = 0;
1796 // The bytecode offset of the next runtime invisible type annotation to read, or -1.
1797 int currentInvisibleTypeAnnotationBytecodeOffset =
1798 getTypeAnnotationBytecodeOffset(invisibleTypeAnnotationOffsets, 0);
1799
1800 // Whether a F_INSERT stack map frame must be inserted before the current instruction.
1801 boolean insertFrame = false;
1802
1803 // The delta to subtract from a goto_w or jsr_w opcode to get the corresponding goto or jsr
1804 // opcode, or 0 if goto_w and jsr_w must be left unchanged (i.e. when expanding ASM specific
1805 // instructions).
1806 final int wideJumpOpcodeDelta =
1807 (context.parsingOptions & EXPAND_ASM_INSNS) == 0 ? Constants.WIDE_JUMP_OPCODE_DELTA : 0;
1808
1809 currentOffset = bytecodeStartOffset;
1810 while (currentOffset < bytecodeEndOffset) {
1811 final int currentBytecodeOffset = currentOffset - bytecodeStartOffset;
1812
1813 // Visit the label and the line number(s) for this bytecode offset, if any.
1814 Label currentLabel = labels[currentBytecodeOffset];
1815 if (currentLabel != null) {
1816 currentLabel.accept(methodVisitor, (context.parsingOptions & SKIP_DEBUG) == 0);
1817 }
1818
1819 // Visit the stack map frame for this bytecode offset, if any.
1820 while (stackMapFrameOffset != 0
1821 && (context.currentFrameOffset == currentBytecodeOffset
1822 || context.currentFrameOffset == -1)) {
1823 // If there is a stack map frame for this offset, make methodVisitor visit it, and read the
1824 // next stack map frame if there is one.
1825 if (context.currentFrameOffset != -1) {
1826 if (!compressedFrames || expandFrames) {
1827 methodVisitor.visitFrame(
1828 Opcodes.F_NEW,
1829 context.currentFrameLocalCount,
1830 context.currentFrameLocalTypes,
1831 context.currentFrameStackCount,
1832 context.currentFrameStackTypes);
1833 } else {
1834 methodVisitor.visitFrame(
1835 context.currentFrameType,
1836 context.currentFrameLocalCountDelta,
1837 context.currentFrameLocalTypes,
1838 context.currentFrameStackCount,
1839 context.currentFrameStackTypes);
1840 }
1841 // Since there is already a stack map frame for this bytecode offset, there is no need to
1842 // insert a new one.
1843 insertFrame = false;
1844 }
1845 if (stackMapFrameOffset < stackMapTableEndOffset) {
1846 stackMapFrameOffset =
1847 readStackMapFrame(stackMapFrameOffset, compressedFrames, expandFrames, context);
1848 } else {
1849 stackMapFrameOffset = 0;
1850 }
1851 }
1852
1853 // Insert a stack map frame for this bytecode offset, if requested by setting insertFrame to
1854 // true during the previous iteration. The actual frame content is computed in MethodWriter.
1855 if (insertFrame) {
1856 if ((context.parsingOptions & EXPAND_FRAMES) != 0) {
1857 methodVisitor.visitFrame(Constants.F_INSERT, 0, null, 0, null);
1858 }
1859 insertFrame = false;
1860 }
1861
1862 // Visit the instruction at this bytecode offset.
1863 int opcode = classFileBuffer[currentOffset] & 0xFF;
1864 switch (opcode) {
1865 case Constants.NOP:
1866 case Constants.ACONST_NULL:
1867 case Constants.ICONST_M1:
1868 case Constants.ICONST_0:
1869 case Constants.ICONST_1:
1870 case Constants.ICONST_2:
1871 case Constants.ICONST_3:
1872 case Constants.ICONST_4:
1873 case Constants.ICONST_5:
1874 case Constants.LCONST_0:
1875 case Constants.LCONST_1:
1876 case Constants.FCONST_0:
1877 case Constants.FCONST_1:
1878 case Constants.FCONST_2:
1879 case Constants.DCONST_0:
1880 case Constants.DCONST_1:
1881 case Constants.IALOAD:
1882 case Constants.LALOAD:
1883 case Constants.FALOAD:
1884 case Constants.DALOAD:
1885 case Constants.AALOAD:
1886 case Constants.BALOAD:
1887 case Constants.CALOAD:
1888 case Constants.SALOAD:
1889 case Constants.IASTORE:
1890 case Constants.LASTORE:
1891 case Constants.FASTORE:
1892 case Constants.DASTORE:
1893 case Constants.AASTORE:
1894 case Constants.BASTORE:
1895 case Constants.CASTORE:
1896 case Constants.SASTORE:
1897 case Constants.POP:
1898 case Constants.POP2:
1899 case Constants.DUP:
1900 case Constants.DUP_X1:
1901 case Constants.DUP_X2:
1902 case Constants.DUP2:
1903 case Constants.DUP2_X1:
1904 case Constants.DUP2_X2:
1905 case Constants.SWAP:
1906 case Constants.IADD:
1907 case Constants.LADD:
1908 case Constants.FADD:
1909 case Constants.DADD:
1910 case Constants.ISUB:
1911 case Constants.LSUB:
1912 case Constants.FSUB:
1913 case Constants.DSUB:
1914 case Constants.IMUL:
1915 case Constants.LMUL:
1916 case Constants.FMUL:
1917 case Constants.DMUL:
1918 case Constants.IDIV:
1919 case Constants.LDIV:
1920 case Constants.FDIV:
1921 case Constants.DDIV:
1922 case Constants.IREM:
1923 case Constants.LREM:
1924 case Constants.FREM:
1925 case Constants.DREM:
1926 case Constants.INEG:
1927 case Constants.LNEG:
1928 case Constants.FNEG:
1929 case Constants.DNEG:
1930 case Constants.ISHL:
1931 case Constants.LSHL:
1932 case Constants.ISHR:
1933 case Constants.LSHR:
1934 case Constants.IUSHR:
1935 case Constants.LUSHR:
1936 case Constants.IAND:
1937 case Constants.LAND:
1938 case Constants.IOR:
1939 case Constants.LOR:
1940 case Constants.IXOR:
1941 case Constants.LXOR:
1942 case Constants.I2L:
1943 case Constants.I2F:
1944 case Constants.I2D:
1945 case Constants.L2I:
1946 case Constants.L2F:
1947 case Constants.L2D:
1948 case Constants.F2I:
1949 case Constants.F2L:
1950 case Constants.F2D:
1951 case Constants.D2I:
1952 case Constants.D2L:
1953 case Constants.D2F:
1954 case Constants.I2B:
1955 case Constants.I2C:
1956 case Constants.I2S:
1957 case Constants.LCMP:
1958 case Constants.FCMPL:
1959 case Constants.FCMPG:
1960 case Constants.DCMPL:
1961 case Constants.DCMPG:
1962 case Constants.IRETURN:
1963 case Constants.LRETURN:
1964 case Constants.FRETURN:
1965 case Constants.DRETURN:
1966 case Constants.ARETURN:
1967 case Constants.RETURN:
1968 case Constants.ARRAYLENGTH:
1969 case Constants.ATHROW:
1970 case Constants.MONITORENTER:
1971 case Constants.MONITOREXIT:
1972 methodVisitor.visitInsn(opcode);
1973 currentOffset += 1;
1974 break;
1975 case Constants.ILOAD_0:
1976 case Constants.ILOAD_1:
1977 case Constants.ILOAD_2:
1978 case Constants.ILOAD_3:
1979 case Constants.LLOAD_0:
1980 case Constants.LLOAD_1:
1981 case Constants.LLOAD_2:
1982 case Constants.LLOAD_3:
1983 case Constants.FLOAD_0:
1984 case Constants.FLOAD_1:
1985 case Constants.FLOAD_2:
1986 case Constants.FLOAD_3:
1987 case Constants.DLOAD_0:
1988 case Constants.DLOAD_1:
1989 case Constants.DLOAD_2:
1990 case Constants.DLOAD_3:
1991 case Constants.ALOAD_0:
1992 case Constants.ALOAD_1:
1993 case Constants.ALOAD_2:
1994 case Constants.ALOAD_3:
1995 opcode -= Constants.ILOAD_0;
1996 methodVisitor.visitVarInsn(Opcodes.ILOAD + (opcode >> 2), opcode & 0x3);
1997 currentOffset += 1;
1998 break;
1999 case Constants.ISTORE_0:
2000 case Constants.ISTORE_1:
2001 case Constants.ISTORE_2:
2002 case Constants.ISTORE_3:
2003 case Constants.LSTORE_0:
2004 case Constants.LSTORE_1:
2005 case Constants.LSTORE_2:
2006 case Constants.LSTORE_3:
2007 case Constants.FSTORE_0:
2008 case Constants.FSTORE_1:
2009 case Constants.FSTORE_2:
2010 case Constants.FSTORE_3:
2011 case Constants.DSTORE_0:
2012 case Constants.DSTORE_1:
2013 case Constants.DSTORE_2:
2014 case Constants.DSTORE_3:
2015 case Constants.ASTORE_0:
2016 case Constants.ASTORE_1:
2017 case Constants.ASTORE_2:
2018 case Constants.ASTORE_3:
2019 opcode -= Constants.ISTORE_0;
2020 methodVisitor.visitVarInsn(Opcodes.ISTORE + (opcode >> 2), opcode & 0x3);
2021 currentOffset += 1;
2022 break;
2023 case Constants.IFEQ:
2024 case Constants.IFNE:
2025 case Constants.IFLT:
2026 case Constants.IFGE:
2027 case Constants.IFGT:
2028 case Constants.IFLE:
2029 case Constants.IF_ICMPEQ:
2030 case Constants.IF_ICMPNE:
2031 case Constants.IF_ICMPLT:
2032 case Constants.IF_ICMPGE:
2033 case Constants.IF_ICMPGT:
2034 case Constants.IF_ICMPLE:
2035 case Constants.IF_ACMPEQ:
2036 case Constants.IF_ACMPNE:
2037 case Constants.GOTO:
2038 case Constants.JSR:
2039 case Constants.IFNULL:
2040 case Constants.IFNONNULL:
2041 methodVisitor.visitJumpInsn(
2042 opcode, labels[currentBytecodeOffset + readShort(currentOffset + 1)]);
2043 currentOffset += 3;
2044 break;
2045 case Constants.GOTO_W:
2046 case Constants.JSR_W:
2047 methodVisitor.visitJumpInsn(
2048 opcode - wideJumpOpcodeDelta,
2049 labels[currentBytecodeOffset + readInt(currentOffset + 1)]);
2050 currentOffset += 5;
2051 break;
2052 case Constants.ASM_IFEQ:
2053 case Constants.ASM_IFNE:
2054 case Constants.ASM_IFLT:
2055 case Constants.ASM_IFGE:
2056 case Constants.ASM_IFGT:
2057 case Constants.ASM_IFLE:
2058 case Constants.ASM_IF_ICMPEQ:
2059 case Constants.ASM_IF_ICMPNE:
2060 case Constants.ASM_IF_ICMPLT:
2061 case Constants.ASM_IF_ICMPGE:
2062 case Constants.ASM_IF_ICMPGT:
2063 case Constants.ASM_IF_ICMPLE:
2064 case Constants.ASM_IF_ACMPEQ:
2065 case Constants.ASM_IF_ACMPNE:
2066 case Constants.ASM_GOTO:
2067 case Constants.ASM_JSR:
2068 case Constants.ASM_IFNULL:
2069 case Constants.ASM_IFNONNULL:
2070 {
2071 // A forward jump with an offset > 32767. In this case we automatically replace ASM_GOTO
2072 // with GOTO_W, ASM_JSR with JSR_W and ASM_IFxxx <l> with IFNOTxxx <L> GOTO_W <l> L:...,
2073 // where IFNOTxxx is the "opposite" opcode of ASMS_IFxxx (e.g. IFNE for ASM_IFEQ) and
2074 // where <L> designates the instruction just after the GOTO_W.
2075 // First, change the ASM specific opcodes ASM_IFEQ ... ASM_JSR, ASM_IFNULL and
2076 // ASM_IFNONNULL to IFEQ ... JSR, IFNULL and IFNONNULL.
2077 opcode =
2078 opcode < Constants.ASM_IFNULL
2079 ? opcode - Constants.ASM_OPCODE_DELTA
2080 : opcode - Constants.ASM_IFNULL_OPCODE_DELTA;
2081 Label target = labels[currentBytecodeOffset + readUnsignedShort(currentOffset + 1)];
2082 if (opcode == Opcodes.GOTO || opcode == Opcodes.JSR) {
2083 // Replace GOTO with GOTO_W and JSR with JSR_W.
2084 methodVisitor.visitJumpInsn(opcode + Constants.WIDE_JUMP_OPCODE_DELTA, target);
2085 } else {
2086 // Compute the "opposite" of opcode. This can be done by flipping the least
2087 // significant bit for IFNULL and IFNONNULL, and similarly for IFEQ ... IF_ACMPEQ
2088 // (with a pre and post offset by 1).
2089 opcode = opcode < Opcodes.GOTO ? ((opcode + 1) ^ 1) - 1 : opcode ^ 1;
2090 Label endif = createLabel(currentBytecodeOffset + 3, labels);
2091 methodVisitor.visitJumpInsn(opcode, endif);
2092 methodVisitor.visitJumpInsn(Constants.GOTO_W, target);
2093 // endif designates the instruction just after GOTO_W, and is visited as part of the
2094 // next instruction. Since it is a jump target, we need to insert a frame here.
2095 insertFrame = true;
2092096 }
210 index += size;
211 }
212 maxStringLength = max;
213 // the class header information starts just after the constant pool
214 header = index;
215 }
216
217 /**
218 * Returns the class's access flags (see {@link Opcodes}). This value may
219 * not reflect Deprecated and Synthetic flags when bytecode is before 1.5
220 * and those flags are represented by attributes.
221 *
222 * @return the class access flags
223 *
224 * @see ClassVisitor#visit(int, int, String, String, String, String[])
225 */
226 public int getAccess() {
227 return readUnsignedShort(header);
228 }
229
230 /**
231 * Returns the internal name of the class (see
232 * {@link Type#getInternalName() getInternalName}).
233 *
234 * @return the internal class name
235 *
236 * @see ClassVisitor#visit(int, int, String, String, String, String[])
237 */
238 public String getClassName() {
239 return readClass(header + 2, new char[maxStringLength]);
240 }
241
242 /**
243 * Returns the internal of name of the super class (see
244 * {@link Type#getInternalName() getInternalName}). For interfaces, the
245 * super class is {@link Object}.
246 *
247 * @return the internal name of super class, or <tt>null</tt> for
248 * {@link Object} class.
249 *
250 * @see ClassVisitor#visit(int, int, String, String, String, String[])
251 */
252 public String getSuperName() {
253 return readClass(header + 4, new char[maxStringLength]);
254 }
255
256 /**
257 * Returns the internal names of the class's interfaces (see
258 * {@link Type#getInternalName() getInternalName}).
259 *
260 * @return the array of internal names for all implemented interfaces or
261 * <tt>null</tt>.
262 *
263 * @see ClassVisitor#visit(int, int, String, String, String, String[])
264 */
265 public String[] getInterfaces() {
266 int index = header + 6;
267 int n = readUnsignedShort(index);
268 String[] interfaces = new String[n];
269 if (n > 0) {
270 char[] buf = new char[maxStringLength];
271 for (int i = 0; i < n; ++i) {
272 index += 2;
273 interfaces[i] = readClass(index, buf);
2097 currentOffset += 3;
2098 break;
2099 }
2100 case Constants.ASM_GOTO_W:
2101 {
2102 // Replace ASM_GOTO_W with GOTO_W.
2103 methodVisitor.visitJumpInsn(
2104 Constants.GOTO_W, labels[currentBytecodeOffset + readInt(currentOffset + 1)]);
2105 // The instruction just after is a jump target (because ASM_GOTO_W is used in patterns
2106 // IFNOTxxx <L> ASM_GOTO_W <l> L:..., see MethodWriter), so we need to insert a frame
2107 // here.
2108 insertFrame = true;
2109 currentOffset += 5;
2110 break;
2111 }
2112 case Constants.WIDE:
2113 opcode = classFileBuffer[currentOffset + 1] & 0xFF;
2114 if (opcode == Opcodes.IINC) {
2115 methodVisitor.visitIincInsn(
2116 readUnsignedShort(currentOffset + 2), readShort(currentOffset + 4));
2117 currentOffset += 6;
2118 } else {
2119 methodVisitor.visitVarInsn(opcode, readUnsignedShort(currentOffset + 2));
2120 currentOffset += 4;
2121 }
2122 break;
2123 case Constants.TABLESWITCH:
2124 {
2125 // Skip 0 to 3 padding bytes.
2126 currentOffset += 4 - (currentBytecodeOffset & 3);
2127 // Read the instruction.
2128 Label defaultLabel = labels[currentBytecodeOffset + readInt(currentOffset)];
2129 int low = readInt(currentOffset + 4);
2130 int high = readInt(currentOffset + 8);
2131 currentOffset += 12;
2132 Label[] table = new Label[high - low + 1];
2133 for (int i = 0; i < table.length; ++i) {
2134 table[i] = labels[currentBytecodeOffset + readInt(currentOffset)];
2135 currentOffset += 4;
2742136 }
275 }
276 return interfaces;
277 }
278
279 /**
280 * Copies the constant pool data into the given {@link ClassWriter}. Should
281 * be called before the {@link #accept(ClassVisitor,int)} method.
282 *
283 * @param classWriter
284 * the {@link ClassWriter} to copy constant pool into.
285 */
286 void copyPool(final ClassWriter classWriter) {
287 char[] buf = new char[maxStringLength];
288 int ll = items.length;
289 Item[] items2 = new Item[ll];
290 for (int i = 1; i < ll; i++) {
291 int index = items[i];
292 int tag = b[index - 1];
293 Item item = new Item(i);
294 int nameType;
295 switch (tag) {
296 case ClassWriter.FIELD:
297 case ClassWriter.METH:
298 case ClassWriter.IMETH:
299 nameType = items[readUnsignedShort(index + 2)];
300 item.set(tag, readClass(index, buf), readUTF8(nameType, buf),
301 readUTF8(nameType + 2, buf));
302 break;
303 case ClassWriter.INT:
304 item.set(readInt(index));
305 break;
306 case ClassWriter.FLOAT:
307 item.set(Float.intBitsToFloat(readInt(index)));
308 break;
309 case ClassWriter.NAME_TYPE:
310 item.set(tag, readUTF8(index, buf), readUTF8(index + 2, buf),
311 null);
312 break;
313 case ClassWriter.LONG:
314 item.set(readLong(index));
315 ++i;
316 break;
317 case ClassWriter.DOUBLE:
318 item.set(Double.longBitsToDouble(readLong(index)));
319 ++i;
320 break;
321 case ClassWriter.UTF8: {
322 String s = strings[i];
323 if (s == null) {
324 index = items[i];
325 s = strings[i] = readUTF(index + 2,
326 readUnsignedShort(index), buf);
327 }
328 item.set(tag, s, null, null);
329 break;
2137 methodVisitor.visitTableSwitchInsn(low, high, defaultLabel, table);
2138 break;
2139 }
2140 case Constants.LOOKUPSWITCH:
2141 {
2142 // Skip 0 to 3 padding bytes.
2143 currentOffset += 4 - (currentBytecodeOffset & 3);
2144 // Read the instruction.
2145 Label defaultLabel = labels[currentBytecodeOffset + readInt(currentOffset)];
2146 int nPairs = readInt(currentOffset + 4);
2147 currentOffset += 8;
2148 int[] keys = new int[nPairs];
2149 Label[] values = new Label[nPairs];
2150 for (int i = 0; i < nPairs; ++i) {
2151 keys[i] = readInt(currentOffset);
2152 values[i] = labels[currentBytecodeOffset + readInt(currentOffset + 4)];
2153 currentOffset += 8;
3302154 }
331 case ClassWriter.HANDLE: {
332 int fieldOrMethodRef = items[readUnsignedShort(index + 1)];
333 nameType = items[readUnsignedShort(fieldOrMethodRef + 2)];
334 item.set(ClassWriter.HANDLE_BASE + readByte(index),
335 readClass(fieldOrMethodRef, buf),
336 readUTF8(nameType, buf), readUTF8(nameType + 2, buf));
337 break;
2155 methodVisitor.visitLookupSwitchInsn(defaultLabel, keys, values);
2156 break;
2157 }
2158 case Constants.ILOAD:
2159 case Constants.LLOAD:
2160 case Constants.FLOAD:
2161 case Constants.DLOAD:
2162 case Constants.ALOAD:
2163 case Constants.ISTORE:
2164 case Constants.LSTORE:
2165 case Constants.FSTORE:
2166 case Constants.DSTORE:
2167 case Constants.ASTORE:
2168 case Constants.RET:
2169 methodVisitor.visitVarInsn(opcode, classFileBuffer[currentOffset + 1] & 0xFF);
2170 currentOffset += 2;
2171 break;
2172 case Constants.BIPUSH:
2173 case Constants.NEWARRAY:
2174 methodVisitor.visitIntInsn(opcode, classFileBuffer[currentOffset + 1]);
2175 currentOffset += 2;
2176 break;
2177 case Constants.SIPUSH:
2178 methodVisitor.visitIntInsn(opcode, readShort(currentOffset + 1));
2179 currentOffset += 3;
2180 break;
2181 case Constants.LDC:
2182 methodVisitor.visitLdcInsn(
2183 readConst(classFileBuffer[currentOffset + 1] & 0xFF, charBuffer));
2184 currentOffset += 2;
2185 break;
2186 case Constants.LDC_W:
2187 case Constants.LDC2_W:
2188 methodVisitor.visitLdcInsn(readConst(readUnsignedShort(currentOffset + 1), charBuffer));
2189 currentOffset += 3;
2190 break;
2191 case Constants.GETSTATIC:
2192 case Constants.PUTSTATIC:
2193 case Constants.GETFIELD:
2194 case Constants.PUTFIELD:
2195 case Constants.INVOKEVIRTUAL:
2196 case Constants.INVOKESPECIAL:
2197 case Constants.INVOKESTATIC:
2198 case Constants.INVOKEINTERFACE:
2199 {
2200 int cpInfoOffset = cpInfoOffsets[readUnsignedShort(currentOffset + 1)];
2201 int nameAndTypeCpInfoOffset = cpInfoOffsets[readUnsignedShort(cpInfoOffset + 2)];
2202 String owner = readClass(cpInfoOffset, charBuffer);
2203 String name = readUTF8(nameAndTypeCpInfoOffset, charBuffer);
2204 String descriptor = readUTF8(nameAndTypeCpInfoOffset + 2, charBuffer);
2205 if (opcode < Opcodes.INVOKEVIRTUAL) {
2206 methodVisitor.visitFieldInsn(opcode, owner, name, descriptor);
2207 } else {
2208 boolean isInterface =
2209 classFileBuffer[cpInfoOffset - 1] == Symbol.CONSTANT_INTERFACE_METHODREF_TAG;
2210 methodVisitor.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
3382211 }
339 case ClassWriter.INDY:
340 if (classWriter.bootstrapMethods == null) {
341 copyBootstrapMethods(classWriter, items2, buf);
342 }
343 nameType = items[readUnsignedShort(index + 2)];
344 item.set(readUTF8(nameType, buf), readUTF8(nameType + 2, buf),
345 readUnsignedShort(index));
346 break;
347 // case ClassWriter.STR:
348 // case ClassWriter.CLASS:
349 // case ClassWriter.MTYPE
350 default:
351 item.set(tag, readUTF8(index, buf), null, null);
352 break;
353 }
354
355 int index2 = item.hashCode % items2.length;
356 item.next = items2[index2];
357 items2[index2] = item;
358 }
359
360 int off = items[1] - 1;
361 classWriter.pool.putByteArray(b, off, header - off);
362 classWriter.items = items2;
363 classWriter.threshold = (int) (0.75d * ll);
364 classWriter.index = ll;
365 }
366
367 /**
368 * Copies the bootstrap method data into the given {@link ClassWriter}.
369 * Should be called before the {@link #accept(ClassVisitor,int)} method.
370 *
371 * @param classWriter
372 * the {@link ClassWriter} to copy bootstrap methods into.
373 */
374 private void copyBootstrapMethods(final ClassWriter classWriter,
375 final Item[] items, final char[] c) {
376 // finds the "BootstrapMethods" attribute
377 int u = getAttributes();
378 boolean found = false;
379 for (int i = readUnsignedShort(u); i > 0; --i) {
380 String attrName = readUTF8(u + 2, c);
381 if ("BootstrapMethods".equals(attrName)) {
382 found = true;
383 break;
384 }
385 u += 6 + readInt(u + 4);
386 }
387 if (!found) {
388 return;
389 }
390 // copies the bootstrap methods in the class writer
391 int boostrapMethodCount = readUnsignedShort(u + 8);
392 for (int j = 0, v = u + 10; j < boostrapMethodCount; j++) {
393 int position = v - u - 10;
394 int hashCode = readConst(readUnsignedShort(v), c).hashCode();
395 for (int k = readUnsignedShort(v + 2); k > 0; --k) {
396 hashCode ^= readConst(readUnsignedShort(v + 4), c).hashCode();
397 v += 2;
398 }
399 v += 4;
400 Item item = new Item(j);
401 item.set(position, hashCode & 0x7FFFFFFF);
402 int index = item.hashCode % items.length;
403 item.next = items[index];
404 items[index] = item;
405 }
406 int attrSize = readInt(u + 4);
407 ByteVector bootstrapMethods = new ByteVector(attrSize + 62);
408 bootstrapMethods.putByteArray(b, u + 10, attrSize - 2);
409 classWriter.bootstrapMethodsCount = boostrapMethodCount;
410 classWriter.bootstrapMethods = bootstrapMethods;
411 }
412
413 /**
414 * Constructs a new {@link ClassReader} object.
415 *
416 * @param is
417 * an input stream from which to read the class.
418 * @throws IOException
419 * if a problem occurs during reading.
420 */
421 public ClassReader(final InputStream is) throws IOException {
422 this(readClass(is, false));
423 }
424
425 /**
426 * Constructs a new {@link ClassReader} object.
427 *
428 * @param name
429 * the binary qualified name of the class to be read.
430 * @throws IOException
431 * if an exception occurs during reading.
432 */
433 public ClassReader(final String name) throws IOException {
434 this(readClass(
435 ClassLoader.getSystemResourceAsStream(name.replace('.', '/')
436 + ".class"), true));
437 }
438
439 /**
440 * Reads the bytecode of a class.
441 *
442 * @param is
443 * an input stream from which to read the class.
444 * @param close
445 * true to close the input stream after reading.
446 * @return the bytecode read from the given input stream.
447 * @throws IOException
448 * if a problem occurs during reading.
449 */
450 private static byte[] readClass(final InputStream is, boolean close)
451 throws IOException {
452 if (is == null) {
453 throw new IOException("Class not found");
454 }
455 try {
456 byte[] b = new byte[is.available()];
457 int len = 0;
458 while (true) {
459 int n = is.read(b, len, b.length - len);
460 if (n == -1) {
461 if (len < b.length) {
462 byte[] c = new byte[len];
463 System.arraycopy(b, 0, c, 0, len);
464 b = c;
465 }
466 return b;
467 }
468 len += n;
469 if (len == b.length) {
470 int last = is.read();
471 if (last < 0) {
472 return b;
473 }
474 byte[] c = new byte[b.length + 1000];
475 System.arraycopy(b, 0, c, 0, len);
476 c[len++] = (byte) last;
477 b = c;
478 }
479 }
480 } finally {
481 if (close) {
482 is.close();
483 }
484 }
485 }
486
487 // ------------------------------------------------------------------------
488 // Public methods
489 // ------------------------------------------------------------------------
490
491 /**
492 * Makes the given visitor visit the Java class of this {@link ClassReader}
493 * . This class is the one specified in the constructor (see
494 * {@link #ClassReader(byte[]) ClassReader}).
495 *
496 * @param classVisitor
497 * the visitor that must visit this class.
498 * @param flags
499 * option flags that can be used to modify the default behavior
500 * of this class. See {@link #SKIP_DEBUG}, {@link #EXPAND_FRAMES}
501 * , {@link #SKIP_FRAMES}, {@link #SKIP_CODE}.
502 */
503 public void accept(final ClassVisitor classVisitor, final int flags) {
504 accept(classVisitor, new Attribute[0], flags);
505 }
506
507 /**
508 * Makes the given visitor visit the Java class of this {@link ClassReader}.
509 * This class is the one specified in the constructor (see
510 * {@link #ClassReader(byte[]) ClassReader}).
511 *
512 * @param classVisitor
513 * the visitor that must visit this class.
514 * @param attrs
515 * prototypes of the attributes that must be parsed during the
516 * visit of the class. Any attribute whose type is not equal to
517 * the type of one the prototypes will not be parsed: its byte
518 * array value will be passed unchanged to the ClassWriter.
519 * <i>This may corrupt it if this value contains references to
520 * the constant pool, or has syntactic or semantic links with a
521 * class element that has been transformed by a class adapter
522 * between the reader and the writer</i>.
523 * @param flags
524 * option flags that can be used to modify the default behavior
525 * of this class. See {@link #SKIP_DEBUG}, {@link #EXPAND_FRAMES}
526 * , {@link #SKIP_FRAMES}, {@link #SKIP_CODE}.
527 */
528 public void accept(final ClassVisitor classVisitor,
529 final Attribute[] attrs, final int flags) {
530 int u = header; // current offset in the class file
531 char[] c = new char[maxStringLength]; // buffer used to read strings
532
533 Context context = new Context();
534 context.attrs = attrs;
535 context.flags = flags;
536 context.buffer = c;
537
538 // reads the class declaration
539 int access = readUnsignedShort(u);
540 String name = readClass(u + 2, c);
541 String superClass = readClass(u + 4, c);
542 String[] interfaces = new String[readUnsignedShort(u + 6)];
543 u += 8;
544 for (int i = 0; i < interfaces.length; ++i) {
545 interfaces[i] = readClass(u, c);
546 u += 2;
547 }
548
549 // reads the class attributes
550 String signature = null;
551 String sourceFile = null;
552 String sourceDebug = null;
553 String enclosingOwner = null;
554 String enclosingName = null;
555 String enclosingDesc = null;
556 int anns = 0;
557 int ianns = 0;
558 int tanns = 0;
559 int itanns = 0;
560 int innerClasses = 0;
561 int module = 0;
562 Attribute attributes = null;
563
564 u = getAttributes();
565 for (int i = readUnsignedShort(u); i > 0; --i) {
566 String attrName = readUTF8(u + 2, c);
567 // tests are sorted in decreasing frequency order
568 // (based on frequencies observed on typical classes)
569 if ("SourceFile".equals(attrName)) {
570 sourceFile = readUTF8(u + 8, c);
571 } else if ("InnerClasses".equals(attrName)) {
572 innerClasses = u + 8;
573 } else if ("EnclosingMethod".equals(attrName)) {
574 enclosingOwner = readClass(u + 8, c);
575 int item = readUnsignedShort(u + 10);
576 if (item != 0) {
577 enclosingName = readUTF8(items[item], c);
578 enclosingDesc = readUTF8(items[item] + 2, c);
579 }
580 } else if (SIGNATURES && "Signature".equals(attrName)) {
581 signature = readUTF8(u + 8, c);
582 } else if (ANNOTATIONS
583 && "RuntimeVisibleAnnotations".equals(attrName)) {
584 anns = u + 8;
585 } else if (ANNOTATIONS
586 && "RuntimeVisibleTypeAnnotations".equals(attrName)) {
587 tanns = u + 8;
588 } else if ("Deprecated".equals(attrName)) {
589 access |= Opcodes.ACC_DEPRECATED;
590 } else if ("Synthetic".equals(attrName)) {
591 access |= Opcodes.ACC_SYNTHETIC
592 | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE;
593 } else if ("SourceDebugExtension".equals(attrName)) {
594 int len = readInt(u + 4);
595 sourceDebug = readUTF(u + 8, len, new char[len]);
596 } else if (ANNOTATIONS
597 && "RuntimeInvisibleAnnotations".equals(attrName)) {
598 ianns = u + 8;
599 } else if (ANNOTATIONS
600 && "RuntimeInvisibleTypeAnnotations".equals(attrName)) {
601 itanns = u + 8;
602 } else if ("Module".equals(attrName)) {
603 module = u + 8;
604 } else if ("BootstrapMethods".equals(attrName)) {
605 int[] bootstrapMethods = new int[readUnsignedShort(u + 8)];
606 for (int j = 0, v = u + 10; j < bootstrapMethods.length; j++) {
607 bootstrapMethods[j] = v;
608 v += 2 + readUnsignedShort(v + 2) << 1;
609 }
610 context.bootstrapMethods = bootstrapMethods;
2212 if (opcode == Opcodes.INVOKEINTERFACE) {
2213 currentOffset += 5;
6112214 } else {
612 Attribute attr = readAttribute(attrs, attrName, u + 8,
613 readInt(u + 4), c, -1, null);
614 if (attr != null) {
615 attr.next = attributes;
616 attributes = attr;
617 }
618 }
619 u += 6 + readInt(u + 4);
620 }
621
622 // visits the class declaration
623 classVisitor.visit(readInt(items[1] - 7), access, name, signature,
624 superClass, interfaces);
625
626 // visits the source and debug info
627 if ((flags & SKIP_DEBUG) == 0
628 && (sourceFile != null || sourceDebug != null)) {
629 classVisitor.visitSource(sourceFile, sourceDebug);
630 }
631
632 // visits the module info
633 if (module != 0) {
634 readModule(classVisitor, context, module);
635 }
636
637 // visits the outer class
638 if (enclosingOwner != null) {
639 classVisitor.visitOuterClass(enclosingOwner, enclosingName,
640 enclosingDesc);
641 }
642
643 // visits the class annotations and type annotations
644 if (ANNOTATIONS && anns != 0) {
645 for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) {
646 v = readAnnotationValues(v + 2, c, true,
647 classVisitor.visitAnnotation(readUTF8(v, c), true));
648 }
649 }
650 if (ANNOTATIONS && ianns != 0) {
651 for (int i = readUnsignedShort(ianns), v = ianns + 2; i > 0; --i) {
652 v = readAnnotationValues(v + 2, c, true,
653 classVisitor.visitAnnotation(readUTF8(v, c), false));
654 }
655 }
656 if (ANNOTATIONS && tanns != 0) {
657 for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) {
658 v = readAnnotationTarget(context, v);
659 v = readAnnotationValues(v + 2, c, true,
660 classVisitor.visitTypeAnnotation(context.typeRef,
661 context.typePath, readUTF8(v, c), true));
662 }
663 }
664 if (ANNOTATIONS && itanns != 0) {
665 for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) {
666 v = readAnnotationTarget(context, v);
667 v = readAnnotationValues(v + 2, c, true,
668 classVisitor.visitTypeAnnotation(context.typeRef,
669 context.typePath, readUTF8(v, c), false));
670 }
671 }
672
673 // visits the attributes
674 while (attributes != null) {
675 Attribute attr = attributes.next;
676 attributes.next = null;
677 classVisitor.visitAttribute(attributes);
678 attributes = attr;
679 }
680
681 // visits the inner classes
682 if (innerClasses != 0) {
683 int v = innerClasses + 2;
684 for (int i = readUnsignedShort(innerClasses); i > 0; --i) {
685 classVisitor.visitInnerClass(readClass(v, c),
686 readClass(v + 2, c), readUTF8(v + 4, c),
687 readUnsignedShort(v + 6));
688 v += 8;
689 }
690 }
691
692 // visits the fields and methods
693 u = header + 10 + 2 * interfaces.length;
694 for (int i = readUnsignedShort(u - 2); i > 0; --i) {
695 u = readField(classVisitor, context, u);
696 }
697 u += 2;
698 for (int i = readUnsignedShort(u - 2); i > 0; --i) {
699 u = readMethod(classVisitor, context, u);
700 }
701
702 // visits the end of the class
703 classVisitor.visitEnd();
704 }
705
706 /**
707 * Reads the module attribute and visit it.
708 *
709 * @param classVisitor
710 * the current class visitor
711 * @param context
712 * information about the class being parsed.
713 * @param moduleOffset
714 * the start offset of the module attribute in the class file.
715 * @return
716 */
717 private void readModule(final ClassVisitor classVisitor,
718 final Context context, int u) {
719 ModuleVisitor mv = classVisitor.visitModule();
720 if (mv == null) {
721 return;
722 }
723 char[] buffer = context.buffer;
724
725 // reads requires
726 u += 2;
727 for (int i = readUnsignedShort(u - 2); i > 0; --i) {
728 //FIXME emulate ACC_PUBLIC wrong value (0x0020)
729 String module = readUTF8(u, buffer);
730 int access = readUnsignedShort(u + 2);
731 if ((access & 0x0020) != 0) {
732 access = access & ~ 0x0020 | Opcodes.ACC_PUBLIC;
733 }
734 mv.visitRequire(module, access);
735 u += 4;
736 }
737
738 // reads exports
739 u += 2;
740 for (int i = readUnsignedShort(u - 2); i > 0; --i) {
741 String export = readUTF8(u, buffer);
742 int exportToCount = readUnsignedShort(u + 2);
743 u += 4;
744 String[] tos = null;
745 if (exportToCount != 0) {
746 tos = new String[exportToCount];
747 for (int j = 0; j < tos.length; ++j) {
748 tos[j] = readUTF8(u, buffer);
749 u += 2;
750 }
751 }
752 mv.visitExport(export, tos);
753 }
754
755 // read uses
756 u += 2;
757 for (int i = readUnsignedShort(u - 2); i > 0; --i) {
758 mv.visitUse(readClass(u, buffer));
759 u += 2;
760 }
761
762 // read provides
763 u += 2;
764 for (int i = readUnsignedShort(u - 2); i > 0; --i) {
765 mv.visitProvide(readClass(u, buffer), readClass(u + 2, buffer));
766 u += 4;
767 }
768
769 mv.visitEnd();
770 }
771
772 /**
773 * Reads a field and makes the given visitor visit it.
774 *
775 * @param classVisitor
776 * the visitor that must visit the field.
777 * @param context
778 * information about the class being parsed.
779 * @param u
780 * the start offset of the field in the class file.
781 * @return the offset of the first byte following the field in the class.
782 */
783 private int readField(final ClassVisitor classVisitor,
784 final Context context, int u) {
785 // reads the field declaration
786 char[] c = context.buffer;
787 int access = readUnsignedShort(u);
788 String name = readUTF8(u + 2, c);
789 String desc = readUTF8(u + 4, c);
790 u += 6;
791
792 // reads the field attributes
793 String signature = null;
794 int anns = 0;
795 int ianns = 0;
796 int tanns = 0;
797 int itanns = 0;
798 Object value = null;
799 Attribute attributes = null;
800
801 for (int i = readUnsignedShort(u); i > 0; --i) {
802 String attrName = readUTF8(u + 2, c);
803 // tests are sorted in decreasing frequency order
804 // (based on frequencies observed on typical classes)
805 if ("ConstantValue".equals(attrName)) {
806 int item = readUnsignedShort(u + 8);
807 value = item == 0 ? null : readConst(item, c);
808 } else if (SIGNATURES && "Signature".equals(attrName)) {
809 signature = readUTF8(u + 8, c);
810 } else if ("Deprecated".equals(attrName)) {
811 access |= Opcodes.ACC_DEPRECATED;
812 } else if ("Synthetic".equals(attrName)) {
813 access |= Opcodes.ACC_SYNTHETIC
814 | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE;
815 } else if (ANNOTATIONS
816 && "RuntimeVisibleAnnotations".equals(attrName)) {
817 anns = u + 8;
818 } else if (ANNOTATIONS
819 && "RuntimeVisibleTypeAnnotations".equals(attrName)) {
820 tanns = u + 8;
821 } else if (ANNOTATIONS
822 && "RuntimeInvisibleAnnotations".equals(attrName)) {
823 ianns = u + 8;
824 } else if (ANNOTATIONS
825 && "RuntimeInvisibleTypeAnnotations".equals(attrName)) {
826 itanns = u + 8;
827 } else {
828 Attribute attr = readAttribute(context.attrs, attrName, u + 8,
829 readInt(u + 4), c, -1, null);
830 if (attr != null) {
831 attr.next = attributes;
832 attributes = attr;
833 }
834 }
835 u += 6 + readInt(u + 4);
836 }
837 u += 2;
838
839 // visits the field declaration
840 FieldVisitor fv = classVisitor.visitField(access, name, desc,
841 signature, value);
842 if (fv == null) {
843 return u;
844 }
845
846 // visits the field annotations and type annotations
847 if (ANNOTATIONS && anns != 0) {
848 for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) {
849 v = readAnnotationValues(v + 2, c, true,
850 fv.visitAnnotation(readUTF8(v, c), true));
851 }
852 }
853 if (ANNOTATIONS && ianns != 0) {
854 for (int i = readUnsignedShort(ianns), v = ianns + 2; i > 0; --i) {
855 v = readAnnotationValues(v + 2, c, true,
856 fv.visitAnnotation(readUTF8(v, c), false));
857 }
858 }
859 if (ANNOTATIONS && tanns != 0) {
860 for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) {
861 v = readAnnotationTarget(context, v);
862 v = readAnnotationValues(v + 2, c, true,
863 fv.visitTypeAnnotation(context.typeRef,
864 context.typePath, readUTF8(v, c), true));
865 }
866 }
867 if (ANNOTATIONS && itanns != 0) {
868 for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) {
869 v = readAnnotationTarget(context, v);
870 v = readAnnotationValues(v + 2, c, true,
871 fv.visitTypeAnnotation(context.typeRef,
872 context.typePath, readUTF8(v, c), false));
873 }
874 }
875
876 // visits the field attributes
877 while (attributes != null) {
878 Attribute attr = attributes.next;
879 attributes.next = null;
880 fv.visitAttribute(attributes);
881 attributes = attr;
882 }
883
884 // visits the end of the field
885 fv.visitEnd();
886
887 return u;
888 }
889
890 /**
891 * Reads a method and makes the given visitor visit it.
892 *
893 * @param classVisitor
894 * the visitor that must visit the method.
895 * @param context
896 * information about the class being parsed.
897 * @param u
898 * the start offset of the method in the class file.
899 * @return the offset of the first byte following the method in the class.
900 */
901 private int readMethod(final ClassVisitor classVisitor,
902 final Context context, int u) {
903 // reads the method declaration
904 char[] c = context.buffer;
905 context.access = readUnsignedShort(u);
906 context.name = readUTF8(u + 2, c);
907 context.desc = readUTF8(u + 4, c);
908 u += 6;
909
910 // reads the method attributes
911 int code = 0;
912 int exception = 0;
913 String[] exceptions = null;
914 String signature = null;
915 int methodParameters = 0;
916 int anns = 0;
917 int ianns = 0;
918 int tanns = 0;
919 int itanns = 0;
920 int dann = 0;
921 int mpanns = 0;
922 int impanns = 0;
923 int firstAttribute = u;
924 Attribute attributes = null;
925
926 for (int i = readUnsignedShort(u); i > 0; --i) {
927 String attrName = readUTF8(u + 2, c);
928 // tests are sorted in decreasing frequency order
929 // (based on frequencies observed on typical classes)
930 if ("Code".equals(attrName)) {
931 if ((context.flags & SKIP_CODE) == 0) {
932 code = u + 8;
933 }
934 } else if ("Exceptions".equals(attrName)) {
935 exceptions = new String[readUnsignedShort(u + 8)];
936 exception = u + 10;
937 for (int j = 0; j < exceptions.length; ++j) {
938 exceptions[j] = readClass(exception, c);
939 exception += 2;
940 }
941 } else if (SIGNATURES && "Signature".equals(attrName)) {
942 signature = readUTF8(u + 8, c);
943 } else if ("Deprecated".equals(attrName)) {
944 context.access |= Opcodes.ACC_DEPRECATED;
945 } else if (ANNOTATIONS
946 && "RuntimeVisibleAnnotations".equals(attrName)) {
947 anns = u + 8;
948 } else if (ANNOTATIONS
949 && "RuntimeVisibleTypeAnnotations".equals(attrName)) {
950 tanns = u + 8;
951 } else if (ANNOTATIONS && "AnnotationDefault".equals(attrName)) {
952 dann = u + 8;
953 } else if ("Synthetic".equals(attrName)) {
954 context.access |= Opcodes.ACC_SYNTHETIC
955 | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE;
956 } else if (ANNOTATIONS
957 && "RuntimeInvisibleAnnotations".equals(attrName)) {
958 ianns = u + 8;
959 } else if (ANNOTATIONS
960 && "RuntimeInvisibleTypeAnnotations".equals(attrName)) {
961 itanns = u + 8;
962 } else if (ANNOTATIONS
963 && "RuntimeVisibleParameterAnnotations".equals(attrName)) {
964 mpanns = u + 8;
965 } else if (ANNOTATIONS
966 && "RuntimeInvisibleParameterAnnotations".equals(attrName)) {
967 impanns = u + 8;
968 } else if ("MethodParameters".equals(attrName)) {
969 methodParameters = u + 8;
970 } else {
971 Attribute attr = readAttribute(context.attrs, attrName, u + 8,
972 readInt(u + 4), c, -1, null);
973 if (attr != null) {
974 attr.next = attributes;
975 attributes = attr;
976 }
977 }
978 u += 6 + readInt(u + 4);
979 }
980 u += 2;
981
982 // visits the method declaration
983 MethodVisitor mv = classVisitor.visitMethod(context.access,
984 context.name, context.desc, signature, exceptions);
985 if (mv == null) {
986 return u;
987 }
988
989 /*
990 * if the returned MethodVisitor is in fact a MethodWriter, it means
991 * there is no method adapter between the reader and the writer. If, in
992 * addition, the writer's constant pool was copied from this reader
993 * (mw.cw.cr == this), and the signature and exceptions of the method
994 * have not been changed, then it is possible to skip all visit events
995 * and just copy the original code of the method to the writer (the
996 * access, name and descriptor can have been changed, this is not
997 * important since they are not copied as is from the reader).
998 */
999 if (WRITER && mv instanceof MethodWriter) {
1000 MethodWriter mw = (MethodWriter) mv;
1001 if (mw.cw.cr == this && signature == mw.signature) {
1002 boolean sameExceptions = false;
1003 if (exceptions == null) {
1004 sameExceptions = mw.exceptionCount == 0;
1005 } else if (exceptions.length == mw.exceptionCount) {
1006 sameExceptions = true;
1007 for (int j = exceptions.length - 1; j >= 0; --j) {
1008 exception -= 2;
1009 if (mw.exceptions[j] != readUnsignedShort(exception)) {
1010 sameExceptions = false;
1011 break;
1012 }
1013 }
1014 }
1015 if (sameExceptions) {
1016 /*
1017 * we do not copy directly the code into MethodWriter to
1018 * save a byte array copy operation. The real copy will be
1019 * done in ClassWriter.toByteArray().
1020 */
1021 mw.classReaderOffset = firstAttribute;
1022 mw.classReaderLength = u - firstAttribute;
1023 return u;
1024 }
1025 }
1026 }
1027
1028 // visit the method parameters
1029 if (methodParameters != 0) {
1030 for (int i = b[methodParameters] & 0xFF, v = methodParameters + 1; i > 0; --i, v = v + 4) {
1031 mv.visitParameter(readUTF8(v, c), readUnsignedShort(v + 2));
1032 }
1033 }
1034
1035 // visits the method annotations
1036 if (ANNOTATIONS && dann != 0) {
1037 AnnotationVisitor dv = mv.visitAnnotationDefault();
1038 readAnnotationValue(dann, c, null, dv);
1039 if (dv != null) {
1040 dv.visitEnd();
1041 }
1042 }
1043 if (ANNOTATIONS && anns != 0) {
1044 for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) {
1045 v = readAnnotationValues(v + 2, c, true,
1046 mv.visitAnnotation(readUTF8(v, c), true));
1047 }
1048 }
1049 if (ANNOTATIONS && ianns != 0) {
1050 for (int i = readUnsignedShort(ianns), v = ianns + 2; i > 0; --i) {
1051 v = readAnnotationValues(v + 2, c, true,
1052 mv.visitAnnotation(readUTF8(v, c), false));
1053 }
1054 }
1055 if (ANNOTATIONS && tanns != 0) {
1056 for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) {
1057 v = readAnnotationTarget(context, v);
1058 v = readAnnotationValues(v + 2, c, true,
1059 mv.visitTypeAnnotation(context.typeRef,
1060 context.typePath, readUTF8(v, c), true));
1061 }
1062 }
1063 if (ANNOTATIONS && itanns != 0) {
1064 for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) {
1065 v = readAnnotationTarget(context, v);
1066 v = readAnnotationValues(v + 2, c, true,
1067 mv.visitTypeAnnotation(context.typeRef,
1068 context.typePath, readUTF8(v, c), false));
1069 }
1070 }
1071 if (ANNOTATIONS && mpanns != 0) {
1072 readParameterAnnotations(mv, context, mpanns, true);
1073 }
1074 if (ANNOTATIONS && impanns != 0) {
1075 readParameterAnnotations(mv, context, impanns, false);
1076 }
1077
1078 // visits the method attributes
1079 while (attributes != null) {
1080 Attribute attr = attributes.next;
1081 attributes.next = null;
1082 mv.visitAttribute(attributes);
1083 attributes = attr;
1084 }
1085
1086 // visits the method code
1087 if (code != 0) {
1088 mv.visitCode();
1089 readCode(mv, context, code);
1090 }
1091
1092 // visits the end of the method
1093 mv.visitEnd();
1094
1095 return u;
1096 }
1097
1098 /**
1099 * Reads the bytecode of a method and makes the given visitor visit it.
1100 *
1101 * @param mv
1102 * the visitor that must visit the method's code.
1103 * @param context
1104 * information about the class being parsed.
1105 * @param u
1106 * the start offset of the code attribute in the class file.
1107 */
1108 private void readCode(final MethodVisitor mv, final Context context, int u) {
1109 // reads the header
1110 byte[] b = this.b;
1111 char[] c = context.buffer;
1112 int maxStack = readUnsignedShort(u);
1113 int maxLocals = readUnsignedShort(u + 2);
1114 int codeLength = readInt(u + 4);
1115 u += 8;
1116
1117 // reads the bytecode to find the labels
1118 int codeStart = u;
1119 int codeEnd = u + codeLength;
1120 Label[] labels = context.labels = new Label[codeLength + 2];
1121 readLabel(codeLength + 1, labels);
1122 while (u < codeEnd) {
1123 int offset = u - codeStart;
1124 int opcode = b[u] & 0xFF;
1125 switch (ClassWriter.TYPE[opcode]) {
1126 case ClassWriter.NOARG_INSN:
1127 case ClassWriter.IMPLVAR_INSN:
1128 u += 1;
1129 break;
1130 case ClassWriter.LABEL_INSN:
1131 readLabel(offset + readShort(u + 1), labels);
1132 u += 3;
1133 break;
1134 case ClassWriter.LABELW_INSN:
1135 readLabel(offset + readInt(u + 1), labels);
1136 u += 5;
1137 break;
1138 case ClassWriter.WIDE_INSN:
1139 opcode = b[u + 1] & 0xFF;
1140 if (opcode == Opcodes.IINC) {
1141 u += 6;
1142 } else {
1143 u += 4;
1144 }
1145 break;
1146 case ClassWriter.TABL_INSN:
1147 // skips 0 to 3 padding bytes
1148 u = u + 4 - (offset & 3);
1149 // reads instruction
1150 readLabel(offset + readInt(u), labels);
1151 for (int i = readInt(u + 8) - readInt(u + 4) + 1; i > 0; --i) {
1152 readLabel(offset + readInt(u + 12), labels);
1153 u += 4;
1154 }
1155 u += 12;
1156 break;
1157 case ClassWriter.LOOK_INSN:
1158 // skips 0 to 3 padding bytes
1159 u = u + 4 - (offset & 3);
1160 // reads instruction
1161 readLabel(offset + readInt(u), labels);
1162 for (int i = readInt(u + 4); i > 0; --i) {
1163 readLabel(offset + readInt(u + 12), labels);
1164 u += 8;
1165 }
1166 u += 8;
1167 break;
1168 case ClassWriter.VAR_INSN:
1169 case ClassWriter.SBYTE_INSN:
1170 case ClassWriter.LDC_INSN:
1171 u += 2;
1172 break;
1173 case ClassWriter.SHORT_INSN:
1174 case ClassWriter.LDCW_INSN:
1175 case ClassWriter.FIELDORMETH_INSN:
1176 case ClassWriter.TYPE_INSN:
1177 case ClassWriter.IINC_INSN:
1178 u += 3;
1179 break;
1180 case ClassWriter.ITFMETH_INSN:
1181 case ClassWriter.INDYMETH_INSN:
1182 u += 5;
1183 break;
1184 // case MANA_INSN:
1185 default:
1186 u += 4;
1187 break;
1188 }
1189 }
1190
1191 // reads the try catch entries to find the labels, and also visits them
1192 for (int i = readUnsignedShort(u); i > 0; --i) {
1193 Label start = readLabel(readUnsignedShort(u + 2), labels);
1194 Label end = readLabel(readUnsignedShort(u + 4), labels);
1195 Label handler = readLabel(readUnsignedShort(u + 6), labels);
1196 String type = readUTF8(items[readUnsignedShort(u + 8)], c);
1197 mv.visitTryCatchBlock(start, end, handler, type);
1198 u += 8;
1199 }
1200 u += 2;
1201
1202 // reads the code attributes
1203 int[] tanns = null; // start index of each visible type annotation
1204 int[] itanns = null; // start index of each invisible type annotation
1205 int tann = 0; // current index in tanns array
1206 int itann = 0; // current index in itanns array
1207 int ntoff = -1; // next visible type annotation code offset
1208 int nitoff = -1; // next invisible type annotation code offset
1209 int varTable = 0;
1210 int varTypeTable = 0;
1211 boolean zip = true;
1212 boolean unzip = (context.flags & EXPAND_FRAMES) != 0;
1213 int stackMap = 0;
1214 int stackMapSize = 0;
1215 int frameCount = 0;
1216 Context frame = null;
1217 Attribute attributes = null;
1218
1219 for (int i = readUnsignedShort(u); i > 0; --i) {
1220 String attrName = readUTF8(u + 2, c);
1221 if ("LocalVariableTable".equals(attrName)) {
1222 if ((context.flags & SKIP_DEBUG) == 0) {
1223 varTable = u + 8;
1224 for (int j = readUnsignedShort(u + 8), v = u; j > 0; --j) {
1225 int label = readUnsignedShort(v + 10);
1226 if (labels[label] == null) {
1227 readLabel(label, labels).status |= Label.DEBUG;
1228 }
1229 label += readUnsignedShort(v + 12);
1230 if (labels[label] == null) {
1231 readLabel(label, labels).status |= Label.DEBUG;
1232 }
1233 v += 10;
1234 }
1235 }
1236 } else if ("LocalVariableTypeTable".equals(attrName)) {
1237 varTypeTable = u + 8;
1238 } else if ("LineNumberTable".equals(attrName)) {
1239 if ((context.flags & SKIP_DEBUG) == 0) {
1240 for (int j = readUnsignedShort(u + 8), v = u; j > 0; --j) {
1241 int label = readUnsignedShort(v + 10);
1242 if (labels[label] == null) {
1243 readLabel(label, labels).status |= Label.DEBUG;
1244 }
1245 Label l = labels[label];
1246 while (l.line > 0) {
1247 if (l.next == null) {
1248 l.next = new Label();
1249 }
1250 l = l.next;
1251 }
1252 l.line = readUnsignedShort(v + 12);
1253 v += 4;
1254 }
1255 }
1256 } else if (ANNOTATIONS
1257 && "RuntimeVisibleTypeAnnotations".equals(attrName)) {
1258 tanns = readTypeAnnotations(mv, context, u + 8, true);
1259 ntoff = tanns.length == 0 || readByte(tanns[0]) < 0x43 ? -1
1260 : readUnsignedShort(tanns[0] + 1);
1261 } else if (ANNOTATIONS
1262 && "RuntimeInvisibleTypeAnnotations".equals(attrName)) {
1263 itanns = readTypeAnnotations(mv, context, u + 8, false);
1264 nitoff = itanns.length == 0 || readByte(itanns[0]) < 0x43 ? -1
1265 : readUnsignedShort(itanns[0] + 1);
1266 } else if (FRAMES && "StackMapTable".equals(attrName)) {
1267 if ((context.flags & SKIP_FRAMES) == 0) {
1268 stackMap = u + 10;
1269 stackMapSize = readInt(u + 4);
1270 frameCount = readUnsignedShort(u + 8);
1271 }
1272 /*
1273 * here we do not extract the labels corresponding to the
1274 * attribute content. This would require a full parsing of the
1275 * attribute, which would need to be repeated in the second
1276 * phase (see below). Instead the content of the attribute is
1277 * read one frame at a time (i.e. after a frame has been
1278 * visited, the next frame is read), and the labels it contains
1279 * are also extracted one frame at a time. Thanks to the
1280 * ordering of frames, having only a "one frame lookahead" is
1281 * not a problem, i.e. it is not possible to see an offset
1282 * smaller than the offset of the current insn and for which no
1283 * Label exist.
1284 */
1285 /*
1286 * This is not true for UNINITIALIZED type offsets. We solve
1287 * this by parsing the stack map table without a full decoding
1288 * (see below).
1289 */
1290 } else if (FRAMES && "StackMap".equals(attrName)) {
1291 if ((context.flags & SKIP_FRAMES) == 0) {
1292 zip = false;
1293 stackMap = u + 10;
1294 stackMapSize = readInt(u + 4);
1295 frameCount = readUnsignedShort(u + 8);
1296 }
1297 /*
1298 * IMPORTANT! here we assume that the frames are ordered, as in
1299 * the StackMapTable attribute, although this is not guaranteed
1300 * by the attribute format.
1301 */
1302 } else {
1303 for (int j = 0; j < context.attrs.length; ++j) {
1304 if (context.attrs[j].type.equals(attrName)) {
1305 Attribute attr = context.attrs[j].read(this, u + 8,
1306 readInt(u + 4), c, codeStart - 8, labels);
1307 if (attr != null) {
1308 attr.next = attributes;
1309 attributes = attr;
1310 }
1311 }
1312 }
1313 }
1314 u += 6 + readInt(u + 4);
1315 }
1316 u += 2;
1317
1318 // generates the first (implicit) stack map frame
1319 if (FRAMES && stackMap != 0) {
1320 /*
1321 * for the first explicit frame the offset is not offset_delta + 1
1322 * but only offset_delta; setting the implicit frame offset to -1
1323 * allow the use of the "offset_delta + 1" rule in all cases
1324 */
1325 frame = context;
1326 frame.offset = -1;
1327 frame.mode = 0;
1328 frame.localCount = 0;
1329 frame.localDiff = 0;
1330 frame.stackCount = 0;
1331 frame.local = new Object[maxLocals];
1332 frame.stack = new Object[maxStack];
1333 if (unzip) {
1334 getImplicitFrame(context);
1335 }
1336 /*
1337 * Finds labels for UNINITIALIZED frame types. Instead of decoding
1338 * each element of the stack map table, we look for 3 consecutive
1339 * bytes that "look like" an UNINITIALIZED type (tag 8, offset
1340 * within code bounds, NEW instruction at this offset). We may find
1341 * false positives (i.e. not real UNINITIALIZED types), but this
1342 * should be rare, and the only consequence will be the creation of
1343 * an unneeded label. This is better than creating a label for each
1344 * NEW instruction, and faster than fully decoding the whole stack
1345 * map table.
1346 */
1347 for (int i = stackMap; i < stackMap + stackMapSize - 2; ++i) {
1348 if (b[i] == 8) { // UNINITIALIZED FRAME TYPE
1349 int v = readUnsignedShort(i + 1);
1350 if (v >= 0 && v < codeLength) {
1351 if ((b[codeStart + v] & 0xFF) == Opcodes.NEW) {
1352 readLabel(v, labels);
1353 }
1354 }
1355 }
1356 }
1357 }
1358
1359 // visits the instructions
1360 u = codeStart;
1361 while (u < codeEnd) {
1362 int offset = u - codeStart;
1363
1364 // visits the label and line number for this offset, if any
1365 Label l = labels[offset];
1366 if (l != null) {
1367 Label next = l.next;
1368 l.next = null;
1369 mv.visitLabel(l);
1370 if ((context.flags & SKIP_DEBUG) == 0 && l.line > 0) {
1371 mv.visitLineNumber(l.line, l);
1372 while (next != null) {
1373 mv.visitLineNumber(next.line, l);
1374 next = next.next;
1375 }
1376 }
1377 }
1378
1379 // visits the frame for this offset, if any
1380 while (FRAMES && frame != null
1381 && (frame.offset == offset || frame.offset == -1)) {
1382 // if there is a frame for this offset, makes the visitor visit
1383 // it, and reads the next frame if there is one.
1384 if (frame.offset != -1) {
1385 if (!zip || unzip) {
1386 mv.visitFrame(Opcodes.F_NEW, frame.localCount,
1387 frame.local, frame.stackCount, frame.stack);
1388 } else {
1389 mv.visitFrame(frame.mode, frame.localDiff, frame.local,
1390 frame.stackCount, frame.stack);
1391 }
1392 }
1393 if (frameCount > 0) {
1394 stackMap = readFrame(stackMap, zip, unzip, frame);
1395 --frameCount;
1396 } else {
1397 frame = null;
1398 }
1399 }
1400
1401 // visits the instruction at this offset
1402 int opcode = b[u] & 0xFF;
1403 switch (ClassWriter.TYPE[opcode]) {
1404 case ClassWriter.NOARG_INSN:
1405 mv.visitInsn(opcode);
1406 u += 1;
1407 break;
1408 case ClassWriter.IMPLVAR_INSN:
1409 if (opcode > Opcodes.ISTORE) {
1410 opcode -= 59; // ISTORE_0
1411 mv.visitVarInsn(Opcodes.ISTORE + (opcode >> 2),
1412 opcode & 0x3);
1413 } else {
1414 opcode -= 26; // ILOAD_0
1415 mv.visitVarInsn(Opcodes.ILOAD + (opcode >> 2), opcode & 0x3);
1416 }
1417 u += 1;
1418 break;
1419 case ClassWriter.LABEL_INSN:
1420 mv.visitJumpInsn(opcode, labels[offset + readShort(u + 1)]);
1421 u += 3;
1422 break;
1423 case ClassWriter.LABELW_INSN:
1424 mv.visitJumpInsn(opcode - 33, labels[offset + readInt(u + 1)]);
1425 u += 5;
1426 break;
1427 case ClassWriter.WIDE_INSN:
1428 opcode = b[u + 1] & 0xFF;
1429 if (opcode == Opcodes.IINC) {
1430 mv.visitIincInsn(readUnsignedShort(u + 2), readShort(u + 4));
1431 u += 6;
1432 } else {
1433 mv.visitVarInsn(opcode, readUnsignedShort(u + 2));
1434 u += 4;
1435 }
1436 break;
1437 case ClassWriter.TABL_INSN: {
1438 // skips 0 to 3 padding bytes
1439 u = u + 4 - (offset & 3);
1440 // reads instruction
1441 int label = offset + readInt(u);
1442 int min = readInt(u + 4);
1443 int max = readInt(u + 8);
1444 Label[] table = new Label[max - min + 1];
1445 u += 12;
1446 for (int i = 0; i < table.length; ++i) {
1447 table[i] = labels[offset + readInt(u)];
1448 u += 4;
1449 }
1450 mv.visitTableSwitchInsn(min, max, labels[label], table);
1451 break;
1452 }
1453 case ClassWriter.LOOK_INSN: {
1454 // skips 0 to 3 padding bytes
1455 u = u + 4 - (offset & 3);
1456 // reads instruction
1457 int label = offset + readInt(u);
1458 int len = readInt(u + 4);
1459 int[] keys = new int[len];
1460 Label[] values = new Label[len];
1461 u += 8;
1462 for (int i = 0; i < len; ++i) {
1463 keys[i] = readInt(u);
1464 values[i] = labels[offset + readInt(u + 4)];
1465 u += 8;
1466 }
1467 mv.visitLookupSwitchInsn(labels[label], keys, values);
1468 break;
1469 }
1470 case ClassWriter.VAR_INSN:
1471 mv.visitVarInsn(opcode, b[u + 1] & 0xFF);
1472 u += 2;
1473 break;
1474 case ClassWriter.SBYTE_INSN:
1475 mv.visitIntInsn(opcode, b[u + 1]);
1476 u += 2;
1477 break;
1478 case ClassWriter.SHORT_INSN:
1479 mv.visitIntInsn(opcode, readShort(u + 1));
1480 u += 3;
1481 break;
1482 case ClassWriter.LDC_INSN:
1483 mv.visitLdcInsn(readConst(b[u + 1] & 0xFF, c));
1484 u += 2;
1485 break;
1486 case ClassWriter.LDCW_INSN:
1487 mv.visitLdcInsn(readConst(readUnsignedShort(u + 1), c));
1488 u += 3;
1489 break;
1490 case ClassWriter.FIELDORMETH_INSN:
1491 case ClassWriter.ITFMETH_INSN: {
1492 int cpIndex = items[readUnsignedShort(u + 1)];
1493 boolean itf = b[cpIndex - 1] == ClassWriter.IMETH;
1494 String iowner = readClass(cpIndex, c);
1495 cpIndex = items[readUnsignedShort(cpIndex + 2)];
1496 String iname = readUTF8(cpIndex, c);
1497 String idesc = readUTF8(cpIndex + 2, c);
1498 if (opcode < Opcodes.INVOKEVIRTUAL) {
1499 mv.visitFieldInsn(opcode, iowner, iname, idesc);
1500 } else {
1501 mv.visitMethodInsn(opcode, iowner, iname, idesc, itf);
1502 }
1503 if (opcode == Opcodes.INVOKEINTERFACE) {
1504 u += 5;
1505 } else {
1506 u += 3;
1507 }
1508 break;
1509 }
1510 case ClassWriter.INDYMETH_INSN: {
1511 int cpIndex = items[readUnsignedShort(u + 1)];
1512 int bsmIndex = context.bootstrapMethods[readUnsignedShort(cpIndex)];
1513 Handle bsm = (Handle) readConst(readUnsignedShort(bsmIndex), c);
1514 int bsmArgCount = readUnsignedShort(bsmIndex + 2);
1515 Object[] bsmArgs = new Object[bsmArgCount];
1516 bsmIndex += 4;
1517 for (int i = 0; i < bsmArgCount; i++) {
1518 bsmArgs[i] = readConst(readUnsignedShort(bsmIndex), c);
1519 bsmIndex += 2;
1520 }
1521 cpIndex = items[readUnsignedShort(cpIndex + 2)];
1522 String iname = readUTF8(cpIndex, c);
1523 String idesc = readUTF8(cpIndex + 2, c);
1524 mv.visitInvokeDynamicInsn(iname, idesc, bsm, bsmArgs);
1525 u += 5;
1526 break;
1527 }
1528 case ClassWriter.TYPE_INSN:
1529 mv.visitTypeInsn(opcode, readClass(u + 1, c));
1530 u += 3;
1531 break;
1532 case ClassWriter.IINC_INSN:
1533 mv.visitIincInsn(b[u + 1] & 0xFF, b[u + 2]);
1534 u += 3;
1535 break;
1536 // case MANA_INSN:
1537 default:
1538 mv.visitMultiANewArrayInsn(readClass(u + 1, c), b[u + 3] & 0xFF);
1539 u += 4;
1540 break;
1541 }
1542
1543 // visit the instruction annotations, if any
1544 while (tanns != null && tann < tanns.length && ntoff <= offset) {
1545 if (ntoff == offset) {
1546 int v = readAnnotationTarget(context, tanns[tann]);
1547 readAnnotationValues(v + 2, c, true,
1548 mv.visitInsnAnnotation(context.typeRef,
1549 context.typePath, readUTF8(v, c), true));
1550 }
1551 ntoff = ++tann >= tanns.length || readByte(tanns[tann]) < 0x43 ? -1
1552 : readUnsignedShort(tanns[tann] + 1);
1553 }
1554 while (itanns != null && itann < itanns.length && nitoff <= offset) {
1555 if (nitoff == offset) {
1556 int v = readAnnotationTarget(context, itanns[itann]);
1557 readAnnotationValues(v + 2, c, true,
1558 mv.visitInsnAnnotation(context.typeRef,
1559 context.typePath, readUTF8(v, c), false));
1560 }
1561 nitoff = ++itann >= itanns.length
1562 || readByte(itanns[itann]) < 0x43 ? -1
1563 : readUnsignedShort(itanns[itann] + 1);
1564 }
1565 }
1566 if (labels[codeLength] != null) {
1567 mv.visitLabel(labels[codeLength]);
1568 }
1569
1570 // visits the local variable tables
1571 if ((context.flags & SKIP_DEBUG) == 0 && varTable != 0) {
1572 int[] typeTable = null;
1573 if (varTypeTable != 0) {
1574 u = varTypeTable + 2;
1575 typeTable = new int[readUnsignedShort(varTypeTable) * 3];
1576 for (int i = typeTable.length; i > 0;) {
1577 typeTable[--i] = u + 6; // signature
1578 typeTable[--i] = readUnsignedShort(u + 8); // index
1579 typeTable[--i] = readUnsignedShort(u); // start
1580 u += 10;
1581 }
1582 }
1583 u = varTable + 2;
1584 for (int i = readUnsignedShort(varTable); i > 0; --i) {
1585 int start = readUnsignedShort(u);
1586 int length = readUnsignedShort(u + 2);
1587 int index = readUnsignedShort(u + 8);
1588 String vsignature = null;
1589 if (typeTable != null) {
1590 for (int j = 0; j < typeTable.length; j += 3) {
1591 if (typeTable[j] == start && typeTable[j + 1] == index) {
1592 vsignature = readUTF8(typeTable[j + 2], c);
1593 break;
1594 }
1595 }
1596 }
1597 mv.visitLocalVariable(readUTF8(u + 4, c), readUTF8(u + 6, c),
1598 vsignature, labels[start], labels[start + length],
1599 index);
1600 u += 10;
1601 }
1602 }
1603
1604 // visits the local variables type annotations
1605 if (tanns != null) {
1606 for (int i = 0; i < tanns.length; ++i) {
1607 if ((readByte(tanns[i]) >> 1) == (0x40 >> 1)) {
1608 int v = readAnnotationTarget(context, tanns[i]);
1609 v = readAnnotationValues(v + 2, c, true,
1610 mv.visitLocalVariableAnnotation(context.typeRef,
1611 context.typePath, context.start,
1612 context.end, context.index, readUTF8(v, c),
1613 true));
1614 }
1615 }
1616 }
1617 if (itanns != null) {
1618 for (int i = 0; i < itanns.length; ++i) {
1619 if ((readByte(itanns[i]) >> 1) == (0x40 >> 1)) {
1620 int v = readAnnotationTarget(context, itanns[i]);
1621 v = readAnnotationValues(v + 2, c, true,
1622 mv.visitLocalVariableAnnotation(context.typeRef,
1623 context.typePath, context.start,
1624 context.end, context.index, readUTF8(v, c),
1625 false));
1626 }
1627 }
1628 }
1629
1630 // visits the code attributes
1631 while (attributes != null) {
1632 Attribute attr = attributes.next;
1633 attributes.next = null;
1634 mv.visitAttribute(attributes);
1635 attributes = attr;
1636 }
1637
1638 // visits the max stack and max locals values
1639 mv.visitMaxs(maxStack, maxLocals);
1640 }
1641
1642 /**
1643 * Parses a type annotation table to find the labels, and to visit the try
1644 * catch block annotations.
1645 *
1646 * @param u
1647 * the start offset of a type annotation table.
1648 * @param mv
1649 * the method visitor to be used to visit the try catch block
1650 * annotations.
1651 * @param context
1652 * information about the class being parsed.
1653 * @param visible
1654 * if the type annotation table to parse contains runtime visible
1655 * annotations.
1656 * @return the start offset of each type annotation in the parsed table.
1657 */
1658 private int[] readTypeAnnotations(final MethodVisitor mv,
1659 final Context context, int u, boolean visible) {
1660 char[] c = context.buffer;
1661 int[] offsets = new int[readUnsignedShort(u)];
1662 u += 2;
1663 for (int i = 0; i < offsets.length; ++i) {
1664 offsets[i] = u;
1665 int target = readInt(u);
1666 switch (target >>> 24) {
1667 case 0x00: // CLASS_TYPE_PARAMETER
1668 case 0x01: // METHOD_TYPE_PARAMETER
1669 case 0x16: // METHOD_FORMAL_PARAMETER
1670 u += 2;
1671 break;
1672 case 0x13: // FIELD
1673 case 0x14: // METHOD_RETURN
1674 case 0x15: // METHOD_RECEIVER
1675 u += 1;
1676 break;
1677 case 0x40: // LOCAL_VARIABLE
1678 case 0x41: // RESOURCE_VARIABLE
1679 for (int j = readUnsignedShort(u + 1); j > 0; --j) {
1680 int start = readUnsignedShort(u + 3);
1681 int length = readUnsignedShort(u + 5);
1682 readLabel(start, context.labels);
1683 readLabel(start + length, context.labels);
1684 u += 6;
1685 }
1686 u += 3;
1687 break;
1688 case 0x47: // CAST
1689 case 0x48: // CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
1690 case 0x49: // METHOD_INVOCATION_TYPE_ARGUMENT
1691 case 0x4A: // CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
1692 case 0x4B: // METHOD_REFERENCE_TYPE_ARGUMENT
1693 u += 4;
1694 break;
1695 // case 0x10: // CLASS_EXTENDS
1696 // case 0x11: // CLASS_TYPE_PARAMETER_BOUND
1697 // case 0x12: // METHOD_TYPE_PARAMETER_BOUND
1698 // case 0x17: // THROWS
1699 // case 0x42: // EXCEPTION_PARAMETER
1700 // case 0x43: // INSTANCEOF
1701 // case 0x44: // NEW
1702 // case 0x45: // CONSTRUCTOR_REFERENCE
1703 // case 0x46: // METHOD_REFERENCE
1704 default:
1705 u += 3;
1706 break;
1707 }
1708 int pathLength = readByte(u);
1709 if ((target >>> 24) == 0x42) {
1710 TypePath path = pathLength == 0 ? null : new TypePath(b, u);
1711 u += 1 + 2 * pathLength;
1712 u = readAnnotationValues(u + 2, c, true,
1713 mv.visitTryCatchAnnotation(target, path,
1714 readUTF8(u, c), visible));
1715 } else {
1716 u = readAnnotationValues(u + 3 + 2 * pathLength, c, true, null);
1717 }
1718 }
1719 return offsets;
1720 }
1721
1722 /**
1723 * Parses the header of a type annotation to extract its target_type and
1724 * target_path (the result is stored in the given context), and returns the
1725 * start offset of the rest of the type_annotation structure (i.e. the
1726 * offset to the type_index field, which is followed by
1727 * num_element_value_pairs and then the name,value pairs).
1728 *
1729 * @param context
1730 * information about the class being parsed. This is where the
1731 * extracted target_type and target_path must be stored.
1732 * @param u
1733 * the start offset of a type_annotation structure.
1734 * @return the start offset of the rest of the type_annotation structure.
1735 */
1736 private int readAnnotationTarget(final Context context, int u) {
1737 int target = readInt(u);
1738 switch (target >>> 24) {
1739 case 0x00: // CLASS_TYPE_PARAMETER
1740 case 0x01: // METHOD_TYPE_PARAMETER
1741 case 0x16: // METHOD_FORMAL_PARAMETER
1742 target &= 0xFFFF0000;
1743 u += 2;
1744 break;
1745 case 0x13: // FIELD
1746 case 0x14: // METHOD_RETURN
1747 case 0x15: // METHOD_RECEIVER
1748 target &= 0xFF000000;
1749 u += 1;
1750 break;
1751 case 0x40: // LOCAL_VARIABLE
1752 case 0x41: { // RESOURCE_VARIABLE
1753 target &= 0xFF000000;
1754 int n = readUnsignedShort(u + 1);
1755 context.start = new Label[n];
1756 context.end = new Label[n];
1757 context.index = new int[n];
1758 u += 3;
1759 for (int i = 0; i < n; ++i) {
1760 int start = readUnsignedShort(u);
1761 int length = readUnsignedShort(u + 2);
1762 context.start[i] = readLabel(start, context.labels);
1763 context.end[i] = readLabel(start + length, context.labels);
1764 context.index[i] = readUnsignedShort(u + 4);
1765 u += 6;
2215 currentOffset += 3;
17662216 }
17672217 break;
2218 }
2219 case Constants.INVOKEDYNAMIC:
2220 {
2221 int cpInfoOffset = cpInfoOffsets[readUnsignedShort(currentOffset + 1)];
2222 int nameAndTypeCpInfoOffset = cpInfoOffsets[readUnsignedShort(cpInfoOffset + 2)];
2223 String name = readUTF8(nameAndTypeCpInfoOffset, charBuffer);
2224 String descriptor = readUTF8(nameAndTypeCpInfoOffset + 2, charBuffer);
2225 int bootstrapMethodOffset = bootstrapMethodOffsets[readUnsignedShort(cpInfoOffset)];
2226 Handle handle =
2227 (Handle) readConst(readUnsignedShort(bootstrapMethodOffset), charBuffer);
2228 Object[] bootstrapMethodArguments =
2229 new Object[readUnsignedShort(bootstrapMethodOffset + 2)];
2230 bootstrapMethodOffset += 4;
2231 for (int i = 0; i < bootstrapMethodArguments.length; i++) {
2232 bootstrapMethodArguments[i] =
2233 readConst(readUnsignedShort(bootstrapMethodOffset), charBuffer);
2234 bootstrapMethodOffset += 2;
2235 }
2236 methodVisitor.visitInvokeDynamicInsn(
2237 name, descriptor, handle, bootstrapMethodArguments);
2238 currentOffset += 5;
2239 break;
2240 }
2241 case Constants.NEW:
2242 case Constants.ANEWARRAY:
2243 case Constants.CHECKCAST:
2244 case Constants.INSTANCEOF:
2245 methodVisitor.visitTypeInsn(opcode, readClass(currentOffset + 1, charBuffer));
2246 currentOffset += 3;
2247 break;
2248 case Constants.IINC:
2249 methodVisitor.visitIincInsn(
2250 classFileBuffer[currentOffset + 1] & 0xFF, classFileBuffer[currentOffset + 2]);
2251 currentOffset += 3;
2252 break;
2253 case Constants.MULTIANEWARRAY:
2254 methodVisitor.visitMultiANewArrayInsn(
2255 readClass(currentOffset + 1, charBuffer), classFileBuffer[currentOffset + 3] & 0xFF);
2256 currentOffset += 4;
2257 break;
2258 default:
2259 throw new AssertionError();
2260 }
2261
2262 // Visit the runtime visible instruction annotations, if any.
2263 while (visibleTypeAnnotationOffsets != null
2264 && currentVisibleTypeAnnotationIndex < visibleTypeAnnotationOffsets.length
2265 && currentVisibleTypeAnnotationBytecodeOffset <= currentBytecodeOffset) {
2266 if (currentVisibleTypeAnnotationBytecodeOffset == currentBytecodeOffset) {
2267 // Parse the target_type, target_info and target_path fields.
2268 int currentAnnotationOffset =
2269 readTypeAnnotationTarget(
2270 context, visibleTypeAnnotationOffsets[currentVisibleTypeAnnotationIndex]);
2271 // Parse the type_index field.
2272 String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
2273 currentAnnotationOffset += 2;
2274 // Parse num_element_value_pairs and element_value_pairs and visit these values.
2275 readElementValues(
2276 methodVisitor.visitInsnAnnotation(
2277 context.currentTypeAnnotationTarget,
2278 context.currentTypeAnnotationTargetPath,
2279 annotationDescriptor,
2280 /* visible = */ true),
2281 currentAnnotationOffset,
2282 /* named = */ true,
2283 charBuffer);
17682284 }
1769 case 0x47: // CAST
1770 case 0x48: // CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
1771 case 0x49: // METHOD_INVOCATION_TYPE_ARGUMENT
1772 case 0x4A: // CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
1773 case 0x4B: // METHOD_REFERENCE_TYPE_ARGUMENT
1774 target &= 0xFF0000FF;
1775 u += 4;
2285 currentVisibleTypeAnnotationBytecodeOffset =
2286 getTypeAnnotationBytecodeOffset(
2287 visibleTypeAnnotationOffsets, ++currentVisibleTypeAnnotationIndex);
2288 }
2289
2290 // Visit the runtime invisible instruction annotations, if any.
2291 while (invisibleTypeAnnotationOffsets != null
2292 && currentInvisibleTypeAnnotationIndex < invisibleTypeAnnotationOffsets.length
2293 && currentInvisibleTypeAnnotationBytecodeOffset <= currentBytecodeOffset) {
2294 if (currentInvisibleTypeAnnotationBytecodeOffset == currentBytecodeOffset) {
2295 // Parse the target_type, target_info and target_path fields.
2296 int currentAnnotationOffset =
2297 readTypeAnnotationTarget(
2298 context, invisibleTypeAnnotationOffsets[currentInvisibleTypeAnnotationIndex]);
2299 // Parse the type_index field.
2300 String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
2301 currentAnnotationOffset += 2;
2302 // Parse num_element_value_pairs and element_value_pairs and visit these values.
2303 readElementValues(
2304 methodVisitor.visitInsnAnnotation(
2305 context.currentTypeAnnotationTarget,
2306 context.currentTypeAnnotationTargetPath,
2307 annotationDescriptor,
2308 /* visible = */ false),
2309 currentAnnotationOffset,
2310 /* named = */ true,
2311 charBuffer);
2312 }
2313 currentInvisibleTypeAnnotationBytecodeOffset =
2314 getTypeAnnotationBytecodeOffset(
2315 invisibleTypeAnnotationOffsets, ++currentInvisibleTypeAnnotationIndex);
2316 }
2317 }
2318 if (labels[codeLength] != null) {
2319 methodVisitor.visitLabel(labels[codeLength]);
2320 }
2321
2322 // Visit LocalVariableTable and LocalVariableTypeTable attributes.
2323 if (localVariableTableOffset != 0 && (context.parsingOptions & SKIP_DEBUG) == 0) {
2324 // The (start_pc, index, signature_index) fields of each entry of the LocalVariableTypeTable.
2325 int[] typeTable = null;
2326 if (localVariableTypeTableOffset != 0) {
2327 typeTable = new int[readUnsignedShort(localVariableTypeTableOffset) * 3];
2328 currentOffset = localVariableTypeTableOffset + 2;
2329 int typeTableIndex = typeTable.length;
2330 while (typeTableIndex > 0) {
2331 // Store the offset of 'signature_index', and the value of 'index' and 'start_pc'.
2332 typeTable[--typeTableIndex] = currentOffset + 6;
2333 typeTable[--typeTableIndex] = readUnsignedShort(currentOffset + 8);
2334 typeTable[--typeTableIndex] = readUnsignedShort(currentOffset);
2335 currentOffset += 10;
2336 }
2337 }
2338 int localVariableTableLength = readUnsignedShort(localVariableTableOffset);
2339 currentOffset = localVariableTableOffset + 2;
2340 while (localVariableTableLength-- > 0) {
2341 int startPc = readUnsignedShort(currentOffset);
2342 int length = readUnsignedShort(currentOffset + 2);
2343 String name = readUTF8(currentOffset + 4, charBuffer);
2344 String descriptor = readUTF8(currentOffset + 6, charBuffer);
2345 int index = readUnsignedShort(currentOffset + 8);
2346 currentOffset += 10;
2347 String signature = null;
2348 if (typeTable != null) {
2349 for (int i = 0; i < typeTable.length; i += 3) {
2350 if (typeTable[i] == startPc && typeTable[i + 1] == index) {
2351 signature = readUTF8(typeTable[i + 2], charBuffer);
2352 break;
2353 }
2354 }
2355 }
2356 methodVisitor.visitLocalVariable(
2357 name, descriptor, signature, labels[startPc], labels[startPc + length], index);
2358 }
2359 }
2360
2361 // Visit the local variable type annotations of the RuntimeVisibleTypeAnnotations attribute.
2362 if (visibleTypeAnnotationOffsets != null) {
2363 for (int i = 0; i < visibleTypeAnnotationOffsets.length; ++i) {
2364 int targetType = readByte(visibleTypeAnnotationOffsets[i]);
2365 if (targetType == TypeReference.LOCAL_VARIABLE
2366 || targetType == TypeReference.RESOURCE_VARIABLE) {
2367 // Parse the target_type, target_info and target_path fields.
2368 currentOffset = readTypeAnnotationTarget(context, visibleTypeAnnotationOffsets[i]);
2369 // Parse the type_index field.
2370 String annotationDescriptor = readUTF8(currentOffset, charBuffer);
2371 currentOffset += 2;
2372 // Parse num_element_value_pairs and element_value_pairs and visit these values.
2373 readElementValues(
2374 methodVisitor.visitLocalVariableAnnotation(
2375 context.currentTypeAnnotationTarget,
2376 context.currentTypeAnnotationTargetPath,
2377 context.currentLocalVariableAnnotationRangeStarts,
2378 context.currentLocalVariableAnnotationRangeEnds,
2379 context.currentLocalVariableAnnotationRangeIndices,
2380 annotationDescriptor,
2381 /* visible = */ true),
2382 currentOffset,
2383 /* named = */ true,
2384 charBuffer);
2385 }
2386 }
2387 }
2388
2389 // Visit the local variable type annotations of the RuntimeInvisibleTypeAnnotations attribute.
2390 if (invisibleTypeAnnotationOffsets != null) {
2391 for (int i = 0; i < invisibleTypeAnnotationOffsets.length; ++i) {
2392 int targetType = readByte(invisibleTypeAnnotationOffsets[i]);
2393 if (targetType == TypeReference.LOCAL_VARIABLE
2394 || targetType == TypeReference.RESOURCE_VARIABLE) {
2395 // Parse the target_type, target_info and target_path fields.
2396 currentOffset = readTypeAnnotationTarget(context, invisibleTypeAnnotationOffsets[i]);
2397 // Parse the type_index field.
2398 String annotationDescriptor = readUTF8(currentOffset, charBuffer);
2399 currentOffset += 2;
2400 // Parse num_element_value_pairs and element_value_pairs and visit these values.
2401 readElementValues(
2402 methodVisitor.visitLocalVariableAnnotation(
2403 context.currentTypeAnnotationTarget,
2404 context.currentTypeAnnotationTargetPath,
2405 context.currentLocalVariableAnnotationRangeStarts,
2406 context.currentLocalVariableAnnotationRangeEnds,
2407 context.currentLocalVariableAnnotationRangeIndices,
2408 annotationDescriptor,
2409 /* visible = */ false),
2410 currentOffset,
2411 /* named = */ true,
2412 charBuffer);
2413 }
2414 }
2415 }
2416
2417 // Visit the non standard attributes.
2418 while (attributes != null) {
2419 // Copy and reset the nextAttribute field so that it can also be used in MethodWriter.
2420 Attribute nextAttribute = attributes.nextAttribute;
2421 attributes.nextAttribute = null;
2422 methodVisitor.visitAttribute(attributes);
2423 attributes = nextAttribute;
2424 }
2425
2426 // Visit the max stack and max locals values.
2427 methodVisitor.visitMaxs(maxStack, maxLocals);
2428 }
2429
2430 /**
2431 * Returns the label corresponding to the given bytecode offset. The default implementation of
2432 * this method creates a label for the given offset if it has not been already created.
2433 *
2434 * @param bytecodeOffset a bytecode offset in a method.
2435 * @param labels the already created labels, indexed by their offset. If a label already exists
2436 * for bytecodeOffset this method must not create a new one. Otherwise it must store the new
2437 * label in this array.
2438 * @return a non null Label, which must be equal to labels[bytecodeOffset].
2439 */
2440 protected Label readLabel(final int bytecodeOffset, final Label[] labels) {
2441 if (labels[bytecodeOffset] == null) {
2442 labels[bytecodeOffset] = new Label();
2443 }
2444 return labels[bytecodeOffset];
2445 }
2446
2447 /**
2448 * Creates a label without the {@link Label#FLAG_DEBUG_ONLY} flag set, for the given bytecode
2449 * offset. The label is created with a call to {@link #readLabel} and its {@link
2450 * Label#FLAG_DEBUG_ONLY} flag is cleared.
2451 *
2452 * @param bytecodeOffset a bytecode offset in a method.
2453 * @param labels the already created labels, indexed by their offset.
2454 * @return a Label without the {@link Label#FLAG_DEBUG_ONLY} flag set.
2455 */
2456 private Label createLabel(final int bytecodeOffset, final Label[] labels) {
2457 Label label = readLabel(bytecodeOffset, labels);
2458 label.flags &= ~Label.FLAG_DEBUG_ONLY;
2459 return label;
2460 }
2461
2462 /**
2463 * Creates a label with the {@link Label#FLAG_DEBUG_ONLY} flag set, if there is no already
2464 * existing label for the given bytecode offset (otherwise does nothing). The label is created
2465 * with a call to {@link #readLabel}.
2466 *
2467 * @param bytecodeOffset a bytecode offset in a method.
2468 * @param labels the already created labels, indexed by their offset.
2469 */
2470 private void createDebugLabel(final int bytecodeOffset, final Label[] labels) {
2471 if (labels[bytecodeOffset] == null) {
2472 readLabel(bytecodeOffset, labels).flags |= Label.FLAG_DEBUG_ONLY;
2473 }
2474 }
2475
2476 // ----------------------------------------------------------------------------------------------
2477 // Methods to parse annotations, type annotations and parameter annotations
2478 // ----------------------------------------------------------------------------------------------
2479
2480 /**
2481 * Parses a Runtime[In]VisibleTypeAnnotations attribute to find the offset of each type_annotation
2482 * entry it contains, to find the corresponding labels, and to visit the try catch block
2483 * annotations.
2484 *
2485 * @param methodVisitor the method visitor to be used to visit the try catch block annotations.
2486 * @param context information about the class being parsed.
2487 * @param runtimeTypeAnnotationsOffset the start offset of a Runtime[In]VisibleTypeAnnotations
2488 * attribute, excluding the attribute_info's attribute_name_index and attribute_length fields.
2489 * @param visible true if the attribute to parse is a RuntimeVisibleTypeAnnotations attribute,
2490 * false it is a RuntimeInvisibleTypeAnnotations attribute.
2491 * @return the start offset of each entry of the Runtime[In]VisibleTypeAnnotations_attribute's
2492 * 'annotations' array field.
2493 */
2494 private int[] readTypeAnnotations(
2495 final MethodVisitor methodVisitor,
2496 final Context context,
2497 final int runtimeTypeAnnotationsOffset,
2498 final boolean visible) {
2499 char[] charBuffer = context.charBuffer;
2500 int currentOffset = runtimeTypeAnnotationsOffset;
2501 // Read the num_annotations field and create an array to store the type_annotation offsets.
2502 int[] typeAnnotationsOffsets = new int[readUnsignedShort(currentOffset)];
2503 currentOffset += 2;
2504 // Parse the 'annotations' array field.
2505 for (int i = 0; i < typeAnnotationsOffsets.length; ++i) {
2506 typeAnnotationsOffsets[i] = currentOffset;
2507 // Parse the type_annotation's target_type and the target_info fields. The size of the
2508 // target_info field depends on the value of target_type.
2509 int targetType = readInt(currentOffset);
2510 switch (targetType >>> 24) {
2511 case TypeReference.LOCAL_VARIABLE:
2512 case TypeReference.RESOURCE_VARIABLE:
2513 // A localvar_target has a variable size, which depends on the value of their table_length
2514 // field. It also references bytecode offsets, for which we need labels.
2515 int tableLength = readUnsignedShort(currentOffset + 1);
2516 currentOffset += 3;
2517 while (tableLength-- > 0) {
2518 int startPc = readUnsignedShort(currentOffset);
2519 int length = readUnsignedShort(currentOffset + 2);
2520 // Skip the index field (2 bytes).
2521 currentOffset += 6;
2522 createLabel(startPc, context.currentMethodLabels);
2523 createLabel(startPc + length, context.currentMethodLabels);
2524 }
2525 break;
2526 case TypeReference.CAST:
2527 case TypeReference.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
2528 case TypeReference.METHOD_INVOCATION_TYPE_ARGUMENT:
2529 case TypeReference.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT:
2530 case TypeReference.METHOD_REFERENCE_TYPE_ARGUMENT:
2531 currentOffset += 4;
2532 break;
2533 case TypeReference.CLASS_EXTENDS:
2534 case TypeReference.CLASS_TYPE_PARAMETER_BOUND:
2535 case TypeReference.METHOD_TYPE_PARAMETER_BOUND:
2536 case TypeReference.THROWS:
2537 case TypeReference.EXCEPTION_PARAMETER:
2538 case TypeReference.INSTANCEOF:
2539 case TypeReference.NEW:
2540 case TypeReference.CONSTRUCTOR_REFERENCE:
2541 case TypeReference.METHOD_REFERENCE:
2542 currentOffset += 3;
2543 break;
2544 case TypeReference.CLASS_TYPE_PARAMETER:
2545 case TypeReference.METHOD_TYPE_PARAMETER:
2546 case TypeReference.METHOD_FORMAL_PARAMETER:
2547 case TypeReference.FIELD:
2548 case TypeReference.METHOD_RETURN:
2549 case TypeReference.METHOD_RECEIVER:
2550 default:
2551 // TypeReference type which can't be used in Code attribute, or which is unknown.
2552 throw new IllegalArgumentException();
2553 }
2554 // Parse the rest of the type_annotation structure, starting with the target_path structure
2555 // (whose size depends on its path_length field).
2556 int pathLength = readByte(currentOffset);
2557 if ((targetType >>> 24) == TypeReference.EXCEPTION_PARAMETER) {
2558 // Parse the target_path structure and create a corresponding TypePath.
2559 TypePath path = pathLength == 0 ? null : new TypePath(b, currentOffset);
2560 currentOffset += 1 + 2 * pathLength;
2561 // Parse the type_index field.
2562 String annotationDescriptor = readUTF8(currentOffset, charBuffer);
2563 currentOffset += 2;
2564 // Parse num_element_value_pairs and element_value_pairs and visit these values.
2565 currentOffset =
2566 readElementValues(
2567 methodVisitor.visitTryCatchAnnotation(
2568 targetType & 0xFFFFFF00, path, annotationDescriptor, visible),
2569 currentOffset,
2570 /* named = */ true,
2571 charBuffer);
2572 } else {
2573 // We don't want to visit the other target_type annotations, so we just skip them (which
2574 // requires some parsing because the element_value_pairs array has a variable size). First,
2575 // skip the target_path structure:
2576 currentOffset += 3 + 2 * pathLength;
2577 // Then skip the num_element_value_pairs and element_value_pairs fields (by reading them
2578 // with a null AnnotationVisitor).
2579 currentOffset =
2580 readElementValues(
2581 /* annotationVisitor = */ null, currentOffset, /* named = */ true, charBuffer);
2582 }
2583 }
2584 return typeAnnotationsOffsets;
2585 }
2586
2587 /**
2588 * Returns the bytecode offset corresponding to the specified JVMS 'type_annotation' structure, or
2589 * -1 if there is no such type_annotation of if it does not have a bytecode offset.
2590 *
2591 * @param typeAnnotationOffsets the offset of each 'type_annotation' entry in a
2592 * Runtime[In]VisibleTypeAnnotations attribute, or null.
2593 * @param typeAnnotationIndex the index a 'type_annotation' entry in typeAnnotationOffsets.
2594 * @return bytecode offset corresponding to the specified JVMS 'type_annotation' structure, or -1
2595 * if there is no such type_annotation of if it does not have a bytecode offset.
2596 */
2597 private int getTypeAnnotationBytecodeOffset(
2598 final int[] typeAnnotationOffsets, final int typeAnnotationIndex) {
2599 if (typeAnnotationOffsets == null
2600 || typeAnnotationIndex >= typeAnnotationOffsets.length
2601 || readByte(typeAnnotationOffsets[typeAnnotationIndex]) < TypeReference.INSTANCEOF) {
2602 return -1;
2603 }
2604 return readUnsignedShort(typeAnnotationOffsets[typeAnnotationIndex] + 1);
2605 }
2606
2607 /**
2608 * Parses the header of a JVMS type_annotation structure to extract its target_type, target_info
2609 * and target_path (the result is stored in the given context), and returns the start offset of
2610 * the rest of the type_annotation structure.
2611 *
2612 * @param context information about the class being parsed. This is where the extracted
2613 * target_type and target_path must be stored.
2614 * @param typeAnnotationOffset the start offset of a type_annotation structure.
2615 * @return the start offset of the rest of the type_annotation structure.
2616 */
2617 private int readTypeAnnotationTarget(final Context context, final int typeAnnotationOffset) {
2618 int currentOffset = typeAnnotationOffset;
2619 // Parse and store the target_type structure.
2620 int targetType = readInt(typeAnnotationOffset);
2621 switch (targetType >>> 24) {
2622 case TypeReference.CLASS_TYPE_PARAMETER:
2623 case TypeReference.METHOD_TYPE_PARAMETER:
2624 case TypeReference.METHOD_FORMAL_PARAMETER:
2625 targetType &= 0xFFFF0000;
2626 currentOffset += 2;
2627 break;
2628 case TypeReference.FIELD:
2629 case TypeReference.METHOD_RETURN:
2630 case TypeReference.METHOD_RECEIVER:
2631 targetType &= 0xFF000000;
2632 currentOffset += 1;
2633 break;
2634 case TypeReference.LOCAL_VARIABLE:
2635 case TypeReference.RESOURCE_VARIABLE:
2636 targetType &= 0xFF000000;
2637 int tableLength = readUnsignedShort(currentOffset + 1);
2638 currentOffset += 3;
2639 context.currentLocalVariableAnnotationRangeStarts = new Label[tableLength];
2640 context.currentLocalVariableAnnotationRangeEnds = new Label[tableLength];
2641 context.currentLocalVariableAnnotationRangeIndices = new int[tableLength];
2642 for (int i = 0; i < tableLength; ++i) {
2643 int startPc = readUnsignedShort(currentOffset);
2644 int length = readUnsignedShort(currentOffset + 2);
2645 int index = readUnsignedShort(currentOffset + 4);
2646 currentOffset += 6;
2647 context.currentLocalVariableAnnotationRangeStarts[i] =
2648 createLabel(startPc, context.currentMethodLabels);
2649 context.currentLocalVariableAnnotationRangeEnds[i] =
2650 createLabel(startPc + length, context.currentMethodLabels);
2651 context.currentLocalVariableAnnotationRangeIndices[i] = index;
2652 }
2653 break;
2654 case TypeReference.CAST:
2655 case TypeReference.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
2656 case TypeReference.METHOD_INVOCATION_TYPE_ARGUMENT:
2657 case TypeReference.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT:
2658 case TypeReference.METHOD_REFERENCE_TYPE_ARGUMENT:
2659 targetType &= 0xFF0000FF;
2660 currentOffset += 4;
2661 break;
2662 case TypeReference.CLASS_EXTENDS:
2663 case TypeReference.CLASS_TYPE_PARAMETER_BOUND:
2664 case TypeReference.METHOD_TYPE_PARAMETER_BOUND:
2665 case TypeReference.THROWS:
2666 case TypeReference.EXCEPTION_PARAMETER:
2667 targetType &= 0xFFFFFF00;
2668 currentOffset += 3;
2669 break;
2670 case TypeReference.INSTANCEOF:
2671 case TypeReference.NEW:
2672 case TypeReference.CONSTRUCTOR_REFERENCE:
2673 case TypeReference.METHOD_REFERENCE:
2674 targetType &= 0xFF000000;
2675 currentOffset += 3;
2676 break;
2677 default:
2678 throw new IllegalArgumentException();
2679 }
2680 context.currentTypeAnnotationTarget = targetType;
2681 // Parse and store the target_path structure.
2682 int pathLength = readByte(currentOffset);
2683 context.currentTypeAnnotationTargetPath =
2684 pathLength == 0 ? null : new TypePath(b, currentOffset);
2685 // Return the start offset of the rest of the type_annotation structure.
2686 return currentOffset + 1 + 2 * pathLength;
2687 }
2688
2689 /**
2690 * Reads a Runtime[In]VisibleParameterAnnotations attribute and makes the given visitor visit it.
2691 *
2692 * @param methodVisitor the visitor that must visit the parameter annotations.
2693 * @param context information about the class being parsed.
2694 * @param runtimeParameterAnnotationsOffset the start offset of a
2695 * Runtime[In]VisibleParameterAnnotations attribute, excluding the attribute_info's
2696 * attribute_name_index and attribute_length fields.
2697 * @param visible true if the attribute to parse is a RuntimeVisibleParameterAnnotations
2698 * attribute, false it is a RuntimeInvisibleParameterAnnotations attribute.
2699 */
2700 private void readParameterAnnotations(
2701 final MethodVisitor methodVisitor,
2702 final Context context,
2703 final int runtimeParameterAnnotationsOffset,
2704 final boolean visible) {
2705 int currentOffset = runtimeParameterAnnotationsOffset;
2706 int numParameters = b[currentOffset++] & 0xFF;
2707 methodVisitor.visitAnnotableParameterCount(numParameters, visible);
2708 char[] charBuffer = context.charBuffer;
2709 for (int i = 0; i < numParameters; ++i) {
2710 int numAnnotations = readUnsignedShort(currentOffset);
2711 currentOffset += 2;
2712 while (numAnnotations-- > 0) {
2713 // Parse the type_index field.
2714 String annotationDescriptor = readUTF8(currentOffset, charBuffer);
2715 currentOffset += 2;
2716 // Parse num_element_value_pairs and element_value_pairs and visit these values.
2717 currentOffset =
2718 readElementValues(
2719 methodVisitor.visitParameterAnnotation(i, annotationDescriptor, visible),
2720 currentOffset,
2721 /* named = */ true,
2722 charBuffer);
2723 }
2724 }
2725 }
2726
2727 /**
2728 * Reads the element values of a JVMS 'annotation' structure and makes the given visitor visit
2729 * them. This method can also be used to read the values of the JVMS 'array_value' field of an
2730 * annotation's 'element_value'.
2731 *
2732 * @param annotationVisitor the visitor that must visit the values.
2733 * @param annotationOffset the start offset of an 'annotation' structure (excluding its type_index
2734 * field) or of an 'array_value' structure.
2735 * @param named if the annotation values are named or not. This should be true to parse the values
2736 * of a JVMS 'annotation' structure, and false to parse the JVMS 'array_value' of an
2737 * annotation's element_value.
2738 * @param charBuffer the buffer used to read strings in the constant pool.
2739 * @return the end offset of the JVMS 'annotation' or 'array_value' structure.
2740 */
2741 private int readElementValues(
2742 final AnnotationVisitor annotationVisitor,
2743 final int annotationOffset,
2744 final boolean named,
2745 final char[] charBuffer) {
2746 int currentOffset = annotationOffset;
2747 // Read the num_element_value_pairs field (or num_values field for an array_value).
2748 int numElementValuePairs = readUnsignedShort(currentOffset);
2749 currentOffset += 2;
2750 if (named) {
2751 // Parse the element_value_pairs array.
2752 while (numElementValuePairs-- > 0) {
2753 String elementName = readUTF8(currentOffset, charBuffer);
2754 currentOffset =
2755 readElementValue(annotationVisitor, currentOffset + 2, elementName, charBuffer);
2756 }
2757 } else {
2758 // Parse the array_value array.
2759 while (numElementValuePairs-- > 0) {
2760 currentOffset =
2761 readElementValue(annotationVisitor, currentOffset, /* named = */ null, charBuffer);
2762 }
2763 }
2764 if (annotationVisitor != null) {
2765 annotationVisitor.visitEnd();
2766 }
2767 return currentOffset;
2768 }
2769
2770 /**
2771 * Reads a JVMS 'element_value' structure and makes the given visitor visit it.
2772 *
2773 * @param annotationVisitor the visitor that must visit the element_value structure.
2774 * @param elementValueOffset the start offset in {@link #b} of the element_value structure to be
2775 * read.
2776 * @param elementName the name of the element_value structure to be read, or <tt>null</tt>.
2777 * @param charBuffer the buffer used to read strings in the constant pool.
2778 * @return the end offset of the JVMS 'element_value' structure.
2779 */
2780 private int readElementValue(
2781 final AnnotationVisitor annotationVisitor,
2782 final int elementValueOffset,
2783 final String elementName,
2784 final char[] charBuffer) {
2785 int currentOffset = elementValueOffset;
2786 if (annotationVisitor == null) {
2787 switch (b[currentOffset] & 0xFF) {
2788 case 'e': // enum_const_value
2789 return currentOffset + 5;
2790 case '@': // annotation_value
2791 return readElementValues(null, currentOffset + 3, /* named = */ true, charBuffer);
2792 case '[': // array_value
2793 return readElementValues(null, currentOffset + 1, /* named = */ false, charBuffer);
2794 default:
2795 return currentOffset + 3;
2796 }
2797 }
2798 switch (b[currentOffset++] & 0xFF) {
2799 case 'B': // const_value_index, CONSTANT_Integer
2800 annotationVisitor.visit(
2801 elementName, (byte) readInt(cpInfoOffsets[readUnsignedShort(currentOffset)]));
2802 currentOffset += 2;
2803 break;
2804 case 'C': // const_value_index, CONSTANT_Integer
2805 annotationVisitor.visit(
2806 elementName, (char) readInt(cpInfoOffsets[readUnsignedShort(currentOffset)]));
2807 currentOffset += 2;
2808 break;
2809 case 'D': // const_value_index, CONSTANT_Double
2810 case 'F': // const_value_index, CONSTANT_Float
2811 case 'I': // const_value_index, CONSTANT_Integer
2812 case 'J': // const_value_index, CONSTANT_Long
2813 annotationVisitor.visit(
2814 elementName, readConst(readUnsignedShort(currentOffset), charBuffer));
2815 currentOffset += 2;
2816 break;
2817 case 'S': // const_value_index, CONSTANT_Integer
2818 annotationVisitor.visit(
2819 elementName, (short) readInt(cpInfoOffsets[readUnsignedShort(currentOffset)]));
2820 currentOffset += 2;
2821 break;
2822
2823 case 'Z': // const_value_index, CONSTANT_Integer
2824 annotationVisitor.visit(
2825 elementName,
2826 readInt(cpInfoOffsets[readUnsignedShort(currentOffset)]) == 0
2827 ? Boolean.FALSE
2828 : Boolean.TRUE);
2829 currentOffset += 2;
2830 break;
2831 case 's': // const_value_index, CONSTANT_Utf8
2832 annotationVisitor.visit(elementName, readUTF8(currentOffset, charBuffer));
2833 currentOffset += 2;
2834 break;
2835 case 'e': // enum_const_value
2836 annotationVisitor.visitEnum(
2837 elementName,
2838 readUTF8(currentOffset, charBuffer),
2839 readUTF8(currentOffset + 2, charBuffer));
2840 currentOffset += 4;
2841 break;
2842 case 'c': // class_info
2843 annotationVisitor.visit(elementName, Type.getType(readUTF8(currentOffset, charBuffer)));
2844 currentOffset += 2;
2845 break;
2846 case '@': // annotation_value
2847 currentOffset =
2848 readElementValues(
2849 annotationVisitor.visitAnnotation(elementName, readUTF8(currentOffset, charBuffer)),
2850 currentOffset + 2,
2851 true,
2852 charBuffer);
2853 break;
2854 case '[': // array_value
2855 int numValues = readUnsignedShort(currentOffset);
2856 currentOffset += 2;
2857 if (numValues == 0) {
2858 return readElementValues(
2859 annotationVisitor.visitArray(elementName),
2860 currentOffset - 2,
2861 /* named = */ false,
2862 charBuffer);
2863 }
2864 switch (b[currentOffset] & 0xFF) {
2865 case 'B':
2866 byte[] byteValues = new byte[numValues];
2867 for (int i = 0; i < numValues; i++) {
2868 byteValues[i] = (byte) readInt(cpInfoOffsets[readUnsignedShort(currentOffset + 1)]);
2869 currentOffset += 3;
2870 }
2871 annotationVisitor.visit(elementName, byteValues);
17762872 break;
1777 // case 0x10: // CLASS_EXTENDS
1778 // case 0x11: // CLASS_TYPE_PARAMETER_BOUND
1779 // case 0x12: // METHOD_TYPE_PARAMETER_BOUND
1780 // case 0x17: // THROWS
1781 // case 0x42: // EXCEPTION_PARAMETER
1782 // case 0x43: // INSTANCEOF
1783 // case 0x44: // NEW
1784 // case 0x45: // CONSTRUCTOR_REFERENCE
1785 // case 0x46: // METHOD_REFERENCE
1786 default:
1787 target &= (target >>> 24) < 0x43 ? 0xFFFFFF00 : 0xFF000000;
1788 u += 3;
2873 case 'Z':
2874 boolean[] booleanValues = new boolean[numValues];
2875 for (int i = 0; i < numValues; i++) {
2876 booleanValues[i] = readInt(cpInfoOffsets[readUnsignedShort(currentOffset + 1)]) != 0;
2877 currentOffset += 3;
2878 }
2879 annotationVisitor.visit(elementName, booleanValues);
2880 break;
2881 case 'S':
2882 short[] shortValues = new short[numValues];
2883 for (int i = 0; i < numValues; i++) {
2884 shortValues[i] = (short) readInt(cpInfoOffsets[readUnsignedShort(currentOffset + 1)]);
2885 currentOffset += 3;
2886 }
2887 annotationVisitor.visit(elementName, shortValues);
2888 break;
2889 case 'C':
2890 char[] charValues = new char[numValues];
2891 for (int i = 0; i < numValues; i++) {
2892 charValues[i] = (char) readInt(cpInfoOffsets[readUnsignedShort(currentOffset + 1)]);
2893 currentOffset += 3;
2894 }
2895 annotationVisitor.visit(elementName, charValues);
2896 break;
2897 case 'I':
2898 int[] intValues = new int[numValues];
2899 for (int i = 0; i < numValues; i++) {
2900 intValues[i] = readInt(cpInfoOffsets[readUnsignedShort(currentOffset + 1)]);
2901 currentOffset += 3;
2902 }
2903 annotationVisitor.visit(elementName, intValues);
2904 break;
2905 case 'J':
2906 long[] longValues = new long[numValues];
2907 for (int i = 0; i < numValues; i++) {
2908 longValues[i] = readLong(cpInfoOffsets[readUnsignedShort(currentOffset + 1)]);
2909 currentOffset += 3;
2910 }
2911 annotationVisitor.visit(elementName, longValues);
2912 break;
2913 case 'F':
2914 float[] floatValues = new float[numValues];
2915 for (int i = 0; i < numValues; i++) {
2916 floatValues[i] =
2917 Float.intBitsToFloat(
2918 readInt(cpInfoOffsets[readUnsignedShort(currentOffset + 1)]));
2919 currentOffset += 3;
2920 }
2921 annotationVisitor.visit(elementName, floatValues);
2922 break;
2923 case 'D':
2924 double[] doubleValues = new double[numValues];
2925 for (int i = 0; i < numValues; i++) {
2926 doubleValues[i] =
2927 Double.longBitsToDouble(
2928 readLong(cpInfoOffsets[readUnsignedShort(currentOffset + 1)]));
2929 currentOffset += 3;
2930 }
2931 annotationVisitor.visit(elementName, doubleValues);
2932 break;
2933 default:
2934 currentOffset =
2935 readElementValues(
2936 annotationVisitor.visitArray(elementName),
2937 currentOffset - 2,
2938 /* named = */ false,
2939 charBuffer);
17892940 break;
17902941 }
1791 int pathLength = readByte(u);
1792 context.typeRef = target;
1793 context.typePath = pathLength == 0 ? null : new TypePath(b, u);
1794 return u + 1 + 2 * pathLength;
1795 }
1796
1797 /**
1798 * Reads parameter annotations and makes the given visitor visit them.
1799 *
1800 * @param mv
1801 * the visitor that must visit the annotations.
1802 * @param context
1803 * information about the class being parsed.
1804 * @param v
1805 * start offset in {@link #b b} of the annotations to be read.
1806 * @param visible
1807 * <tt>true</tt> if the annotations to be read are visible at
1808 * runtime.
1809 */
1810 private void readParameterAnnotations(final MethodVisitor mv,
1811 final Context context, int v, final boolean visible) {
1812 int i;
1813 int n = b[v++] & 0xFF;
1814 // workaround for a bug in javac (javac compiler generates a parameter
1815 // annotation array whose size is equal to the number of parameters in
1816 // the Java source file, while it should generate an array whose size is
1817 // equal to the number of parameters in the method descriptor - which
1818 // includes the synthetic parameters added by the compiler). This work-
1819 // around supposes that the synthetic parameters are the first ones.
1820 int synthetics = Type.getArgumentTypes(context.desc).length - n;
1821 AnnotationVisitor av;
1822 for (i = 0; i < synthetics; ++i) {
1823 // virtual annotation to detect synthetic parameters in MethodWriter
1824 av = mv.visitParameterAnnotation(i, "Ljava/lang/Synthetic;", false);
1825 if (av != null) {
1826 av.visitEnd();
2942 break;
2943 default:
2944 throw new IllegalArgumentException();
2945 }
2946 return currentOffset;
2947 }
2948
2949 // ----------------------------------------------------------------------------------------------
2950 // Methods to parse stack map frames
2951 // ----------------------------------------------------------------------------------------------
2952
2953 /**
2954 * Computes the implicit frame of the method currently being parsed (as defined in the given
2955 * {@link Context}) and stores it in the given context.
2956 *
2957 * @param context information about the class being parsed.
2958 */
2959 private void computeImplicitFrame(final Context context) {
2960 String methodDescriptor = context.currentMethodDescriptor;
2961 Object[] locals = context.currentFrameLocalTypes;
2962 int nLocal = 0;
2963 if ((context.currentMethodAccessFlags & Opcodes.ACC_STATIC) == 0) {
2964 if ("<init>".equals(context.currentMethodName)) {
2965 locals[nLocal++] = Opcodes.UNINITIALIZED_THIS;
2966 } else {
2967 locals[nLocal++] = readClass(header + 2, context.charBuffer);
2968 }
2969 }
2970 // Parse the method descriptor, one argument type descriptor at each iteration. Start by
2971 // skipping the first method descriptor character, which is always '('.
2972 int currentMethodDescritorOffset = 1;
2973 while (true) {
2974 int currentArgumentDescriptorStartOffset = currentMethodDescritorOffset;
2975 switch (methodDescriptor.charAt(currentMethodDescritorOffset++)) {
2976 case 'Z':
2977 case 'C':
2978 case 'B':
2979 case 'S':
2980 case 'I':
2981 locals[nLocal++] = Opcodes.INTEGER;
2982 break;
2983 case 'F':
2984 locals[nLocal++] = Opcodes.FLOAT;
2985 break;
2986 case 'J':
2987 locals[nLocal++] = Opcodes.LONG;
2988 break;
2989 case 'D':
2990 locals[nLocal++] = Opcodes.DOUBLE;
2991 break;
2992 case '[':
2993 while (methodDescriptor.charAt(currentMethodDescritorOffset) == '[') {
2994 ++currentMethodDescritorOffset;
2995 }
2996 if (methodDescriptor.charAt(currentMethodDescritorOffset) == 'L') {
2997 ++currentMethodDescritorOffset;
2998 while (methodDescriptor.charAt(currentMethodDescritorOffset) != ';') {
2999 ++currentMethodDescritorOffset;
18273000 }
3001 }
3002 locals[nLocal++] =
3003 methodDescriptor.substring(
3004 currentArgumentDescriptorStartOffset, ++currentMethodDescritorOffset);
3005 break;
3006 case 'L':
3007 while (methodDescriptor.charAt(currentMethodDescritorOffset) != ';') {
3008 ++currentMethodDescritorOffset;
3009 }
3010 locals[nLocal++] =
3011 methodDescriptor.substring(
3012 currentArgumentDescriptorStartOffset + 1, currentMethodDescritorOffset++);
3013 break;
3014 default:
3015 context.currentFrameLocalCount = nLocal;
3016 return;
3017 }
3018 }
3019 }
3020
3021 /**
3022 * Reads a JVMS 'stack_map_frame' structure and stores the result in the given {@link Context}
3023 * object. This method can also be used to read a full_frame structure, excluding its frame_type
3024 * field (this is used to parse the legacy StackMap attributes).
3025 *
3026 * @param stackMapFrameOffset the start offset in {@link #b} of the stack_map_frame_value
3027 * structure to be read, or the start offset of a full_frame structure (excluding its
3028 * frame_type field).
3029 * @param compressed true to read a 'stack_map_frame' structure, false to read a 'full_frame'
3030 * structure without its frame_type field.
3031 * @param expand if the stack map frame must be expanded. See {@link #EXPAND_FRAMES}.
3032 * @param context where the parsed stack map frame must be stored.
3033 * @return the end offset of the JVMS 'stack_map_frame' or 'full_frame' structure.
3034 */
3035 private int readStackMapFrame(
3036 final int stackMapFrameOffset,
3037 final boolean compressed,
3038 final boolean expand,
3039 final Context context) {
3040 int currentOffset = stackMapFrameOffset;
3041 final char[] charBuffer = context.charBuffer;
3042 final Label[] labels = context.currentMethodLabels;
3043 int frameType;
3044 if (compressed) {
3045 // Read the frame_type field.
3046 frameType = b[currentOffset++] & 0xFF;
3047 } else {
3048 frameType = Frame.FULL_FRAME;
3049 context.currentFrameOffset = -1;
3050 }
3051 int offsetDelta;
3052 context.currentFrameLocalCountDelta = 0;
3053 if (frameType < Frame.SAME_LOCALS_1_STACK_ITEM_FRAME) {
3054 offsetDelta = frameType;
3055 context.currentFrameType = Opcodes.F_SAME;
3056 context.currentFrameStackCount = 0;
3057 } else if (frameType < Frame.RESERVED) {
3058 offsetDelta = frameType - Frame.SAME_LOCALS_1_STACK_ITEM_FRAME;
3059 currentOffset =
3060 readVerificationTypeInfo(
3061 currentOffset, context.currentFrameStackTypes, 0, charBuffer, labels);
3062 context.currentFrameType = Opcodes.F_SAME1;
3063 context.currentFrameStackCount = 1;
3064 } else if (frameType >= Frame.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) {
3065 offsetDelta = readUnsignedShort(currentOffset);
3066 currentOffset += 2;
3067 if (frameType == Frame.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) {
3068 currentOffset =
3069 readVerificationTypeInfo(
3070 currentOffset, context.currentFrameStackTypes, 0, charBuffer, labels);
3071 context.currentFrameType = Opcodes.F_SAME1;
3072 context.currentFrameStackCount = 1;
3073 } else if (frameType >= Frame.CHOP_FRAME && frameType < Frame.SAME_FRAME_EXTENDED) {
3074 context.currentFrameType = Opcodes.F_CHOP;
3075 context.currentFrameLocalCountDelta = Frame.SAME_FRAME_EXTENDED - frameType;
3076 context.currentFrameLocalCount -= context.currentFrameLocalCountDelta;
3077 context.currentFrameStackCount = 0;
3078 } else if (frameType == Frame.SAME_FRAME_EXTENDED) {
3079 context.currentFrameType = Opcodes.F_SAME;
3080 context.currentFrameStackCount = 0;
3081 } else if (frameType < Frame.FULL_FRAME) {
3082 int local = expand ? context.currentFrameLocalCount : 0;
3083 for (int k = frameType - Frame.SAME_FRAME_EXTENDED; k > 0; k--) {
3084 currentOffset =
3085 readVerificationTypeInfo(
3086 currentOffset, context.currentFrameLocalTypes, local++, charBuffer, labels);
18283087 }
1829 char[] c = context.buffer;
1830 for (; i < n + synthetics; ++i) {
1831 int j = readUnsignedShort(v);
1832 v += 2;
1833 for (; j > 0; --j) {
1834 av = mv.visitParameterAnnotation(i, readUTF8(v, c), visible);
1835 v = readAnnotationValues(v + 2, c, true, av);
1836 }
3088 context.currentFrameType = Opcodes.F_APPEND;
3089 context.currentFrameLocalCountDelta = frameType - Frame.SAME_FRAME_EXTENDED;
3090 context.currentFrameLocalCount += context.currentFrameLocalCountDelta;
3091 context.currentFrameStackCount = 0;
3092 } else {
3093 final int numberOfLocals = readUnsignedShort(currentOffset);
3094 currentOffset += 2;
3095 context.currentFrameType = Opcodes.F_FULL;
3096 context.currentFrameLocalCountDelta = numberOfLocals;
3097 context.currentFrameLocalCount = numberOfLocals;
3098 for (int local = 0; local < numberOfLocals; ++local) {
3099 currentOffset =
3100 readVerificationTypeInfo(
3101 currentOffset, context.currentFrameLocalTypes, local, charBuffer, labels);
18373102 }
1838 }
1839
1840 /**
1841 * Reads the values of an annotation and makes the given visitor visit them.
1842 *
1843 * @param v
1844 * the start offset in {@link #b b} of the values to be read
1845 * (including the unsigned short that gives the number of
1846 * values).
1847 * @param buf
1848 * buffer to be used to call {@link #readUTF8 readUTF8},
1849 * {@link #readClass(int,char[]) readClass} or {@link #readConst
1850 * readConst}.
1851 * @param named
1852 * if the annotation values are named or not.
1853 * @param av
1854 * the visitor that must visit the values.
1855 * @return the end offset of the annotation values.
1856 */
1857 private int readAnnotationValues(int v, final char[] buf,
1858 final boolean named, final AnnotationVisitor av) {
1859 int i = readUnsignedShort(v);
1860 v += 2;
1861 if (named) {
1862 for (; i > 0; --i) {
1863 v = readAnnotationValue(v + 2, buf, readUTF8(v, buf), av);
1864 }
1865 } else {
1866 for (; i > 0; --i) {
1867 v = readAnnotationValue(v, buf, null, av);
1868 }
3103 final int numberOfStackItems = readUnsignedShort(currentOffset);
3104 currentOffset += 2;
3105 context.currentFrameStackCount = numberOfStackItems;
3106 for (int stack = 0; stack < numberOfStackItems; ++stack) {
3107 currentOffset =
3108 readVerificationTypeInfo(
3109 currentOffset, context.currentFrameStackTypes, stack, charBuffer, labels);
18693110 }
1870 if (av != null) {
1871 av.visitEnd();
1872 }
1873 return v;
1874 }
1875
1876 /**
1877 * Reads a value of an annotation and makes the given visitor visit it.
1878 *
1879 * @param v
1880 * the start offset in {@link #b b} of the value to be read
1881 * (<i>not including the value name constant pool index</i>).
1882 * @param buf
1883 * buffer to be used to call {@link #readUTF8 readUTF8},
1884 * {@link #readClass(int,char[]) readClass} or {@link #readConst
1885 * readConst}.
1886 * @param name
1887 * the name of the value to be read.
1888 * @param av
1889 * the visitor that must visit the value.
1890 * @return the end offset of the annotation value.
1891 */
1892 private int readAnnotationValue(int v, final char[] buf, final String name,
1893 final AnnotationVisitor av) {
1894 int i;
1895 if (av == null) {
1896 switch (b[v] & 0xFF) {
1897 case 'e': // enum_const_value
1898 return v + 5;
1899 case '@': // annotation_value
1900 return readAnnotationValues(v + 3, buf, true, null);
1901 case '[': // array_value
1902 return readAnnotationValues(v + 1, buf, false, null);
1903 default:
1904 return v + 3;
1905 }
1906 }
1907 switch (b[v++] & 0xFF) {
1908 case 'I': // pointer to CONSTANT_Integer
1909 case 'J': // pointer to CONSTANT_Long
1910 case 'F': // pointer to CONSTANT_Float
1911 case 'D': // pointer to CONSTANT_Double
1912 av.visit(name, readConst(readUnsignedShort(v), buf));
1913 v += 2;
1914 break;
1915 case 'B': // pointer to CONSTANT_Byte
1916 av.visit(name, (byte) readInt(items[readUnsignedShort(v)]));
1917 v += 2;
1918 break;
1919 case 'Z': // pointer to CONSTANT_Boolean
1920 av.visit(name,
1921 readInt(items[readUnsignedShort(v)]) == 0 ? Boolean.FALSE
1922 : Boolean.TRUE);
1923 v += 2;
1924 break;
1925 case 'S': // pointer to CONSTANT_Short
1926 av.visit(name, (short) readInt(items[readUnsignedShort(v)]));
1927 v += 2;
1928 break;
1929 case 'C': // pointer to CONSTANT_Char
1930 av.visit(name, (char) readInt(items[readUnsignedShort(v)]));
1931 v += 2;
1932 break;
1933 case 's': // pointer to CONSTANT_Utf8
1934 av.visit(name, readUTF8(v, buf));
1935 v += 2;
1936 break;
1937 case 'e': // enum_const_value
1938 av.visitEnum(name, readUTF8(v, buf), readUTF8(v + 2, buf));
1939 v += 4;
1940 break;
1941 case 'c': // class_info
1942 av.visit(name, Type.getType(readUTF8(v, buf)));
1943 v += 2;
1944 break;
1945 case '@': // annotation_value
1946 v = readAnnotationValues(v + 2, buf, true,
1947 av.visitAnnotation(name, readUTF8(v, buf)));
1948 break;
1949 case '[': // array_value
1950 int size = readUnsignedShort(v);
1951 v += 2;
1952 if (size == 0) {
1953 return readAnnotationValues(v - 2, buf, false,
1954 av.visitArray(name));
1955 }
1956 switch (this.b[v++] & 0xFF) {
1957 case 'B':
1958 byte[] bv = new byte[size];
1959 for (i = 0; i < size; i++) {
1960 bv[i] = (byte) readInt(items[readUnsignedShort(v)]);
1961 v += 3;
1962 }
1963 av.visit(name, bv);
1964 --v;
1965 break;
1966 case 'Z':
1967 boolean[] zv = new boolean[size];
1968 for (i = 0; i < size; i++) {
1969 zv[i] = readInt(items[readUnsignedShort(v)]) != 0;
1970 v += 3;
1971 }
1972 av.visit(name, zv);
1973 --v;
1974 break;
1975 case 'S':
1976 short[] sv = new short[size];
1977 for (i = 0; i < size; i++) {
1978 sv[i] = (short) readInt(items[readUnsignedShort(v)]);
1979 v += 3;
1980 }
1981 av.visit(name, sv);
1982 --v;
1983 break;
1984 case 'C':
1985 char[] cv = new char[size];
1986 for (i = 0; i < size; i++) {
1987 cv[i] = (char) readInt(items[readUnsignedShort(v)]);
1988 v += 3;
1989 }
1990 av.visit(name, cv);
1991 --v;
1992 break;
1993 case 'I':
1994 int[] iv = new int[size];
1995 for (i = 0; i < size; i++) {
1996 iv[i] = readInt(items[readUnsignedShort(v)]);
1997 v += 3;
1998 }
1999 av.visit(name, iv);
2000 --v;
2001 break;
2002 case 'J':
2003 long[] lv = new long[size];
2004 for (i = 0; i < size; i++) {
2005 lv[i] = readLong(items[readUnsignedShort(v)]);
2006 v += 3;
2007 }
2008 av.visit(name, lv);
2009 --v;
2010 break;
2011 case 'F':
2012 float[] fv = new float[size];
2013 for (i = 0; i < size; i++) {
2014 fv[i] = Float
2015 .intBitsToFloat(readInt(items[readUnsignedShort(v)]));
2016 v += 3;
2017 }
2018 av.visit(name, fv);
2019 --v;
2020 break;
2021 case 'D':
2022 double[] dv = new double[size];
2023 for (i = 0; i < size; i++) {
2024 dv[i] = Double
2025 .longBitsToDouble(readLong(items[readUnsignedShort(v)]));
2026 v += 3;
2027 }
2028 av.visit(name, dv);
2029 --v;
2030 break;
2031 default:
2032 v = readAnnotationValues(v - 3, buf, false, av.visitArray(name));
2033 }
2034 }
2035 return v;
2036 }
2037
2038 /**
2039 * Computes the implicit frame of the method currently being parsed (as
2040 * defined in the given {@link Context}) and stores it in the given context.
2041 *
2042 * @param frame
2043 * information about the class being parsed.
2044 */
2045 private void getImplicitFrame(final Context frame) {
2046 String desc = frame.desc;
2047 Object[] locals = frame.local;
2048 int local = 0;
2049 if ((frame.access & Opcodes.ACC_STATIC) == 0) {
2050 if ("<init>".equals(frame.name)) {
2051 locals[local++] = Opcodes.UNINITIALIZED_THIS;
2052 } else {
2053 locals[local++] = readClass(header + 2, frame.buffer);
2054 }
2055 }
2056 int i = 1;
2057 loop: while (true) {
2058 int j = i;
2059 switch (desc.charAt(i++)) {
2060 case 'Z':
2061 case 'C':
2062 case 'B':
2063 case 'S':
2064 case 'I':
2065 locals[local++] = Opcodes.INTEGER;
2066 break;
2067 case 'F':
2068 locals[local++] = Opcodes.FLOAT;
2069 break;
2070 case 'J':
2071 locals[local++] = Opcodes.LONG;
2072 break;
2073 case 'D':
2074 locals[local++] = Opcodes.DOUBLE;
2075 break;
2076 case '[':
2077 while (desc.charAt(i) == '[') {
2078 ++i;
2079 }
2080 if (desc.charAt(i) == 'L') {
2081 ++i;
2082 while (desc.charAt(i) != ';') {
2083 ++i;
2084 }
2085 }
2086 locals[local++] = desc.substring(j, ++i);
2087 break;
2088 case 'L':
2089 while (desc.charAt(i) != ';') {
2090 ++i;
2091 }
2092 locals[local++] = desc.substring(j + 1, i++);
2093 break;
2094 default:
2095 break loop;
2096 }
2097 }
2098 frame.localCount = local;
2099 }
2100
2101 /**
2102 * Reads a stack map frame and stores the result in the given
2103 * {@link Context} object.
2104 *
2105 * @param stackMap
2106 * the start offset of a stack map frame in the class file.
2107 * @param zip
2108 * if the stack map frame at stackMap is compressed or not.
2109 * @param unzip
2110 * if the stack map frame must be uncompressed.
2111 * @param frame
2112 * where the parsed stack map frame must be stored.
2113 * @return the offset of the first byte following the parsed frame.
2114 */
2115 private int readFrame(int stackMap, boolean zip, boolean unzip,
2116 Context frame) {
2117 char[] c = frame.buffer;
2118 Label[] labels = frame.labels;
2119 int tag;
2120 int delta;
2121 if (zip) {
2122 tag = b[stackMap++] & 0xFF;
2123 } else {
2124 tag = MethodWriter.FULL_FRAME;
2125 frame.offset = -1;
2126 }
2127 frame.localDiff = 0;
2128 if (tag < MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME) {
2129 delta = tag;
2130 frame.mode = Opcodes.F_SAME;
2131 frame.stackCount = 0;
2132 } else if (tag < MethodWriter.RESERVED) {
2133 delta = tag - MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME;
2134 stackMap = readFrameType(frame.stack, 0, stackMap, c, labels);
2135 frame.mode = Opcodes.F_SAME1;
2136 frame.stackCount = 1;
2137 } else {
2138 delta = readUnsignedShort(stackMap);
2139 stackMap += 2;
2140 if (tag == MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) {
2141 stackMap = readFrameType(frame.stack, 0, stackMap, c, labels);
2142 frame.mode = Opcodes.F_SAME1;
2143 frame.stackCount = 1;
2144 } else if (tag >= MethodWriter.CHOP_FRAME
2145 && tag < MethodWriter.SAME_FRAME_EXTENDED) {
2146 frame.mode = Opcodes.F_CHOP;
2147 frame.localDiff = MethodWriter.SAME_FRAME_EXTENDED - tag;
2148 frame.localCount -= frame.localDiff;
2149 frame.stackCount = 0;
2150 } else if (tag == MethodWriter.SAME_FRAME_EXTENDED) {
2151 frame.mode = Opcodes.F_SAME;
2152 frame.stackCount = 0;
2153 } else if (tag < MethodWriter.FULL_FRAME) {
2154 int local = unzip ? frame.localCount : 0;
2155 for (int i = tag - MethodWriter.SAME_FRAME_EXTENDED; i > 0; i--) {
2156 stackMap = readFrameType(frame.local, local++, stackMap, c,
2157 labels);
2158 }
2159 frame.mode = Opcodes.F_APPEND;
2160 frame.localDiff = tag - MethodWriter.SAME_FRAME_EXTENDED;
2161 frame.localCount += frame.localDiff;
2162 frame.stackCount = 0;
2163 } else { // if (tag == FULL_FRAME) {
2164 frame.mode = Opcodes.F_FULL;
2165 int n = readUnsignedShort(stackMap);
2166 stackMap += 2;
2167 frame.localDiff = n;
2168 frame.localCount = n;
2169 for (int local = 0; n > 0; n--) {
2170 stackMap = readFrameType(frame.local, local++, stackMap, c,
2171 labels);
2172 }
2173 n = readUnsignedShort(stackMap);
2174 stackMap += 2;
2175 frame.stackCount = n;
2176 for (int stack = 0; n > 0; n--) {
2177 stackMap = readFrameType(frame.stack, stack++, stackMap, c,
2178 labels);
2179 }
2180 }
2181 }
2182 frame.offset += delta + 1;
2183 readLabel(frame.offset, labels);
2184 return stackMap;
2185 }
2186
2187 /**
2188 * Reads a stack map frame type and stores it at the given index in the
2189 * given array.
2190 *
2191 * @param frame
2192 * the array where the parsed type must be stored.
2193 * @param index
2194 * the index in 'frame' where the parsed type must be stored.
2195 * @param v
2196 * the start offset of the stack map frame type to read.
2197 * @param buf
2198 * a buffer to read strings.
2199 * @param labels
2200 * the labels of the method currently being parsed, indexed by
2201 * their offset. If the parsed type is an Uninitialized type, a
2202 * new label for the corresponding NEW instruction is stored in
2203 * this array if it does not already exist.
2204 * @return the offset of the first byte after the parsed type.
2205 */
2206 private int readFrameType(final Object[] frame, final int index, int v,
2207 final char[] buf, final Label[] labels) {
2208 int type = b[v++] & 0xFF;
2209 switch (type) {
2210 case 0:
2211 frame[index] = Opcodes.TOP;
2212 break;
2213 case 1:
2214 frame[index] = Opcodes.INTEGER;
2215 break;
2216 case 2:
2217 frame[index] = Opcodes.FLOAT;
2218 break;
2219 case 3:
2220 frame[index] = Opcodes.DOUBLE;
2221 break;
2222 case 4:
2223 frame[index] = Opcodes.LONG;
2224 break;
2225 case 5:
2226 frame[index] = Opcodes.NULL;
2227 break;
2228 case 6:
2229 frame[index] = Opcodes.UNINITIALIZED_THIS;
2230 break;
2231 case 7: // Object
2232 frame[index] = readClass(v, buf);
2233 v += 2;
2234 break;
2235 default: // Uninitialized
2236 frame[index] = readLabel(readUnsignedShort(v), labels);
2237 v += 2;
2238 }
2239 return v;
2240 }
2241
2242 /**
2243 * Returns the label corresponding to the given offset. The default
2244 * implementation of this method creates a label for the given offset if it
2245 * has not been already created.
2246 *
2247 * @param offset
2248 * a bytecode offset in a method.
2249 * @param labels
2250 * the already created labels, indexed by their offset. If a
2251 * label already exists for offset this method must not create a
2252 * new one. Otherwise it must store the new label in this array.
2253 * @return a non null Label, which must be equal to labels[offset].
2254 */
2255 protected Label readLabel(int offset, Label[] labels) {
2256 if (labels[offset] == null) {
2257 labels[offset] = new Label();
2258 }
2259 return labels[offset];
2260 }
2261
2262 /**
2263 * Returns the start index of the attribute_info structure of this class.
2264 *
2265 * @return the start index of the attribute_info structure of this class.
2266 */
2267 private int getAttributes() {
2268 // skips the header
2269 int u = header + 8 + readUnsignedShort(header + 6) * 2;
2270 // skips fields and methods
2271 for (int i = readUnsignedShort(u); i > 0; --i) {
2272 for (int j = readUnsignedShort(u + 8); j > 0; --j) {
2273 u += 6 + readInt(u + 12);
2274 }
2275 u += 8;
2276 }
2277 u += 2;
2278 for (int i = readUnsignedShort(u); i > 0; --i) {
2279 for (int j = readUnsignedShort(u + 8); j > 0; --j) {
2280 u += 6 + readInt(u + 12);
2281 }
2282 u += 8;
2283 }
2284 // the attribute_info structure starts just after the methods
2285 return u + 2;
2286 }
2287
2288 /**
2289 * Reads an attribute in {@link #b b}.
2290 *
2291 * @param attrs
2292 * prototypes of the attributes that must be parsed during the
2293 * visit of the class. Any attribute whose type is not equal to
2294 * the type of one the prototypes is ignored (i.e. an empty
2295 * {@link Attribute} instance is returned).
2296 * @param type
2297 * the type of the attribute.
2298 * @param off
2299 * index of the first byte of the attribute's content in
2300 * {@link #b b}. The 6 attribute header bytes, containing the
2301 * type and the length of the attribute, are not taken into
2302 * account here (they have already been read).
2303 * @param len
2304 * the length of the attribute's content.
2305 * @param buf
2306 * buffer to be used to call {@link #readUTF8 readUTF8},
2307 * {@link #readClass(int,char[]) readClass} or {@link #readConst
2308 * readConst}.
2309 * @param codeOff
2310 * index of the first byte of code's attribute content in
2311 * {@link #b b}, or -1 if the attribute to be read is not a code
2312 * attribute. The 6 attribute header bytes, containing the type
2313 * and the length of the attribute, are not taken into account
2314 * here.
2315 * @param labels
2316 * the labels of the method's code, or <tt>null</tt> if the
2317 * attribute to be read is not a code attribute.
2318 * @return the attribute that has been read, or <tt>null</tt> to skip this
2319 * attribute.
2320 */
2321 private Attribute readAttribute(final Attribute[] attrs, final String type,
2322 final int off, final int len, final char[] buf, final int codeOff,
2323 final Label[] labels) {
2324 for (int i = 0; i < attrs.length; ++i) {
2325 if (attrs[i].type.equals(type)) {
2326 return attrs[i].read(this, off, len, buf, codeOff, labels);
2327 }
2328 }
2329 return new Attribute(type).read(this, off, len, null, -1, null);
2330 }
2331
2332 // ------------------------------------------------------------------------
2333 // Utility methods: low level parsing
2334 // ------------------------------------------------------------------------
2335
2336 /**
2337 * Returns the number of constant pool items in {@link #b b}.
2338 *
2339 * @return the number of constant pool items in {@link #b b}.
2340 */
2341 public int getItemCount() {
2342 return items.length;
2343 }
2344
2345 /**
2346 * Returns the start index of the constant pool item in {@link #b b}, plus
2347 * one. <i>This method is intended for {@link Attribute} sub classes, and is
2348 * normally not needed by class generators or adapters.</i>
2349 *
2350 * @param item
2351 * the index a constant pool item.
2352 * @return the start index of the constant pool item in {@link #b b}, plus
2353 * one.
2354 */
2355 public int getItem(final int item) {
2356 return items[item];
2357 }
2358
2359 /**
2360 * Returns the maximum length of the strings contained in the constant pool
2361 * of the class.
2362 *
2363 * @return the maximum length of the strings contained in the constant pool
2364 * of the class.
2365 */
2366 public int getMaxStringLength() {
2367 return maxStringLength;
2368 }
2369
2370 /**
2371 * Reads a byte value in {@link #b b}. <i>This method is intended for
2372 * {@link Attribute} sub classes, and is normally not needed by class
2373 * generators or adapters.</i>
2374 *
2375 * @param index
2376 * the start index of the value to be read in {@link #b b}.
2377 * @return the read value.
2378 */
2379 public int readByte(final int index) {
2380 return b[index] & 0xFF;
2381 }
2382
2383 /**
2384 * Reads an unsigned short value in {@link #b b}. <i>This method is intended
2385 * for {@link Attribute} sub classes, and is normally not needed by class
2386 * generators or adapters.</i>
2387 *
2388 * @param index
2389 * the start index of the value to be read in {@link #b b}.
2390 * @return the read value.
2391 */
2392 public int readUnsignedShort(final int index) {
2393 byte[] b = this.b;
2394 return ((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF);
2395 }
2396
2397 /**
2398 * Reads a signed short value in {@link #b b}. <i>This method is intended
2399 * for {@link Attribute} sub classes, and is normally not needed by class
2400 * generators or adapters.</i>
2401 *
2402 * @param index
2403 * the start index of the value to be read in {@link #b b}.
2404 * @return the read value.
2405 */
2406 public short readShort(final int index) {
2407 byte[] b = this.b;
2408 return (short) (((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF));
2409 }
2410
2411 /**
2412 * Reads a signed int value in {@link #b b}. <i>This method is intended for
2413 * {@link Attribute} sub classes, and is normally not needed by class
2414 * generators or adapters.</i>
2415 *
2416 * @param index
2417 * the start index of the value to be read in {@link #b b}.
2418 * @return the read value.
2419 */
2420 public int readInt(final int index) {
2421 byte[] b = this.b;
2422 return ((b[index] & 0xFF) << 24) | ((b[index + 1] & 0xFF) << 16)
2423 | ((b[index + 2] & 0xFF) << 8) | (b[index + 3] & 0xFF);
2424 }
2425
2426 /**
2427 * Reads a signed long value in {@link #b b}. <i>This method is intended for
2428 * {@link Attribute} sub classes, and is normally not needed by class
2429 * generators or adapters.</i>
2430 *
2431 * @param index
2432 * the start index of the value to be read in {@link #b b}.
2433 * @return the read value.
2434 */
2435 public long readLong(final int index) {
2436 long l1 = readInt(index);
2437 long l0 = readInt(index + 4) & 0xFFFFFFFFL;
2438 return (l1 << 32) | l0;
2439 }
2440
2441 /**
2442 * Reads an UTF8 string constant pool item in {@link #b b}. <i>This method
2443 * is intended for {@link Attribute} sub classes, and is normally not needed
2444 * by class generators or adapters.</i>
2445 *
2446 * @param index
2447 * the start index of an unsigned short value in {@link #b b},
2448 * whose value is the index of an UTF8 constant pool item.
2449 * @param buf
2450 * buffer to be used to read the item. This buffer must be
2451 * sufficiently large. It is not automatically resized.
2452 * @return the String corresponding to the specified UTF8 item.
2453 */
2454 public String readUTF8(int index, final char[] buf) {
2455 int item = readUnsignedShort(index);
2456 if (index == 0 || item == 0) {
2457 return null;
2458 }
2459 String s = strings[item];
2460 if (s != null) {
2461 return s;
2462 }
2463 index = items[item];
2464 return strings[item] = readUTF(index + 2, readUnsignedShort(index), buf);
2465 }
2466
2467 /**
2468 * Reads UTF8 string in {@link #b b}.
2469 *
2470 * @param index
2471 * start offset of the UTF8 string to be read.
2472 * @param utfLen
2473 * length of the UTF8 string to be read.
2474 * @param buf
2475 * buffer to be used to read the string. This buffer must be
2476 * sufficiently large. It is not automatically resized.
2477 * @return the String corresponding to the specified UTF8 string.
2478 */
2479 private String readUTF(int index, final int utfLen, final char[] buf) {
2480 int endIndex = index + utfLen;
2481 byte[] b = this.b;
2482 int strLen = 0;
2483 int c;
2484 int st = 0;
2485 char cc = 0;
2486 while (index < endIndex) {
2487 c = b[index++];
2488 switch (st) {
2489 case 0:
2490 c = c & 0xFF;
2491 if (c < 0x80) { // 0xxxxxxx
2492 buf[strLen++] = (char) c;
2493 } else if (c < 0xE0 && c > 0xBF) { // 110x xxxx 10xx xxxx
2494 cc = (char) (c & 0x1F);
2495 st = 1;
2496 } else { // 1110 xxxx 10xx xxxx 10xx xxxx
2497 cc = (char) (c & 0x0F);
2498 st = 2;
2499 }
2500 break;
2501
2502 case 1: // byte 2 of 2-byte char or byte 3 of 3-byte char
2503 buf[strLen++] = (char) ((cc << 6) | (c & 0x3F));
2504 st = 0;
2505 break;
2506
2507 case 2: // byte 2 of 3-byte char
2508 cc = (char) ((cc << 6) | (c & 0x3F));
2509 st = 1;
2510 break;
2511 }
2512 }
2513 return new String(buf, 0, strLen);
2514 }
2515
2516 /**
2517 * Reads a class constant pool item in {@link #b b}. <i>This method is
2518 * intended for {@link Attribute} sub classes, and is normally not needed by
2519 * class generators or adapters.</i>
2520 *
2521 * @param index
2522 * the start index of an unsigned short value in {@link #b b},
2523 * whose value is the index of a class constant pool item.
2524 * @param buf
2525 * buffer to be used to read the item. This buffer must be
2526 * sufficiently large. It is not automatically resized.
2527 * @return the String corresponding to the specified class item.
2528 */
2529 public String readClass(final int index, final char[] buf) {
2530 // computes the start index of the CONSTANT_Class item in b
2531 // and reads the CONSTANT_Utf8 item designated by
2532 // the first two bytes of this CONSTANT_Class item
2533 return readUTF8(items[readUnsignedShort(index)], buf);
2534 }
2535
2536 /**
2537 * Reads a numeric or string constant pool item in {@link #b b}. <i>This
2538 * method is intended for {@link Attribute} sub classes, and is normally not
2539 * needed by class generators or adapters.</i>
2540 *
2541 * @param item
2542 * the index of a constant pool item.
2543 * @param buf
2544 * buffer to be used to read the item. This buffer must be
2545 * sufficiently large. It is not automatically resized.
2546 * @return the {@link Integer}, {@link Float}, {@link Long}, {@link Double},
2547 * {@link String}, {@link Type} or {@link Handle} corresponding to
2548 * the given constant pool item.
2549 */
2550 public Object readConst(final int item, final char[] buf) {
2551 int index = items[item];
2552 switch (b[index - 1]) {
2553 case ClassWriter.INT:
2554 return readInt(index);
2555 case ClassWriter.FLOAT:
2556 return Float.intBitsToFloat(readInt(index));
2557 case ClassWriter.LONG:
2558 return readLong(index);
2559 case ClassWriter.DOUBLE:
2560 return Double.longBitsToDouble(readLong(index));
2561 case ClassWriter.CLASS:
2562 return Type.getObjectType(readUTF8(index, buf));
2563 case ClassWriter.STR:
2564 return readUTF8(index, buf);
2565 case ClassWriter.MTYPE:
2566 return Type.getMethodType(readUTF8(index, buf));
2567 default: // case ClassWriter.HANDLE_BASE + [1..9]:
2568 int tag = readByte(index);
2569 int[] items = this.items;
2570 int cpIndex = items[readUnsignedShort(index + 1)];
2571 boolean itf = b[cpIndex - 1] == ClassWriter.IMETH;
2572 String owner = readClass(cpIndex, buf);
2573 cpIndex = items[readUnsignedShort(cpIndex + 2)];
2574 String name = readUTF8(cpIndex, buf);
2575 String desc = readUTF8(cpIndex + 2, buf);
2576 return new Handle(tag, owner, name, desc, itf);
2577 }
2578 }
3111 }
3112 } else {
3113 throw new IllegalArgumentException();
3114 }
3115 context.currentFrameOffset += offsetDelta + 1;
3116 createLabel(context.currentFrameOffset, labels);
3117 return currentOffset;
3118 }
3119
3120 /**
3121 * Reads a JVMS 'verification_type_info' structure and stores it at the given index in the given
3122 * array.
3123 *
3124 * @param verificationTypeInfoOffset the start offset of the 'verification_type_info' structure to
3125 * read.
3126 * @param frame the array where the parsed type must be stored.
3127 * @param index the index in 'frame' where the parsed type must be stored.
3128 * @param charBuffer the buffer used to read strings in the constant pool.
3129 * @param labels the labels of the method currently being parsed, indexed by their offset. If the
3130 * parsed type is an ITEM_Uninitialized, a new label for the corresponding NEW instruction is
3131 * stored in this array if it does not already exist.
3132 * @return the end offset of the JVMS 'verification_type_info' structure.
3133 */
3134 private int readVerificationTypeInfo(
3135 final int verificationTypeInfoOffset,
3136 final Object[] frame,
3137 final int index,
3138 final char[] charBuffer,
3139 final Label[] labels) {
3140 int currentOffset = verificationTypeInfoOffset;
3141 int tag = b[currentOffset++] & 0xFF;
3142 switch (tag) {
3143 case Frame.ITEM_TOP:
3144 frame[index] = Opcodes.TOP;
3145 break;
3146 case Frame.ITEM_INTEGER:
3147 frame[index] = Opcodes.INTEGER;
3148 break;
3149 case Frame.ITEM_FLOAT:
3150 frame[index] = Opcodes.FLOAT;
3151 break;
3152 case Frame.ITEM_DOUBLE:
3153 frame[index] = Opcodes.DOUBLE;
3154 break;
3155 case Frame.ITEM_LONG:
3156 frame[index] = Opcodes.LONG;
3157 break;
3158 case Frame.ITEM_NULL:
3159 frame[index] = Opcodes.NULL;
3160 break;
3161 case Frame.ITEM_UNINITIALIZED_THIS:
3162 frame[index] = Opcodes.UNINITIALIZED_THIS;
3163 break;
3164 case Frame.ITEM_OBJECT:
3165 frame[index] = readClass(currentOffset, charBuffer);
3166 currentOffset += 2;
3167 break;
3168 case Frame.ITEM_UNINITIALIZED:
3169 frame[index] = createLabel(readUnsignedShort(currentOffset), labels);
3170 currentOffset += 2;
3171 break;
3172 default:
3173 throw new IllegalArgumentException();
3174 }
3175 return currentOffset;
3176 }
3177
3178 // ----------------------------------------------------------------------------------------------
3179 // Methods to parse attributes
3180 // ----------------------------------------------------------------------------------------------
3181
3182 /** @return the offset in {@link #b} of the first ClassFile's 'attributes' array field entry. */
3183 final int getFirstAttributeOffset() {
3184 // Skip the access_flags, this_class, super_class, and interfaces_count fields (using 2 bytes
3185 // each), as well as the interfaces array field (2 bytes per interface).
3186 int currentOffset = header + 8 + readUnsignedShort(header + 6) * 2;
3187
3188 // Read the fields_count field.
3189 int fieldsCount = readUnsignedShort(currentOffset);
3190 currentOffset += 2;
3191 // Skip the 'fields' array field.
3192 while (fieldsCount-- > 0) {
3193 // Invariant: currentOffset is the offset of a field_info structure.
3194 // Skip the access_flags, name_index and descriptor_index fields (2 bytes each), and read the
3195 // attributes_count field.
3196 int attributesCount = readUnsignedShort(currentOffset + 6);
3197 currentOffset += 8;
3198 // Skip the 'attributes' array field.
3199 while (attributesCount-- > 0) {
3200 // Invariant: currentOffset is the offset of an attribute_info structure.
3201 // Read the attribute_length field (2 bytes after the start of the attribute_info) and skip
3202 // this many bytes, plus 6 for the attribute_name_index and attribute_length fields
3203 // (yielding the total size of the attribute_info structure).
3204 currentOffset += 6 + readInt(currentOffset + 2);
3205 }
3206 }
3207
3208 // Skip the methods_count and 'methods' fields, using the same method as above.
3209 int methodsCount = readUnsignedShort(currentOffset);
3210 currentOffset += 2;
3211 while (methodsCount-- > 0) {
3212 int attributesCount = readUnsignedShort(currentOffset + 6);
3213 currentOffset += 8;
3214 while (attributesCount-- > 0) {
3215 currentOffset += 6 + readInt(currentOffset + 2);
3216 }
3217 }
3218
3219 // Skip the ClassFile's attributes_count field.
3220 return currentOffset + 2;
3221 }
3222
3223 /**
3224 * Reads a non standard JVMS 'attribute' structure in {@link #b}.
3225 *
3226 * @param attributePrototypes prototypes of the attributes that must be parsed during the visit of
3227 * the class. Any attribute whose type is not equal to the type of one the prototypes will not
3228 * be parsed: its byte array value will be passed unchanged to the ClassWriter.
3229 * @param type the type of the attribute.
3230 * @param offset the start offset of the JVMS 'attribute' structure in {@link #b}. The 6 attribute
3231 * header bytes (attribute_name_index and attribute_length) are not taken into account here.
3232 * @param length the length of the attribute's content (excluding the 6 attribute header bytes).
3233 * @param charBuffer the buffer to be used to read strings in the constant pool.
3234 * @param codeAttributeOffset the start offset of the enclosing Code attribute in {@link #b}, or
3235 * -1 if the attribute to be read is not a code attribute. The 6 attribute header bytes
3236 * (attribute_name_index and attribute_length) are not taken into account here.
3237 * @param labels the labels of the method's code, or <tt>null</tt> if the attribute to be read is
3238 * not a code attribute.
3239 * @return the attribute that has been read.
3240 */
3241 private Attribute readAttribute(
3242 final Attribute[] attributePrototypes,
3243 final String type,
3244 final int offset,
3245 final int length,
3246 final char[] charBuffer,
3247 final int codeAttributeOffset,
3248 final Label[] labels) {
3249 for (int i = 0; i < attributePrototypes.length; ++i) {
3250 if (attributePrototypes[i].type.equals(type)) {
3251 return attributePrototypes[i].read(
3252 this, offset, length, charBuffer, codeAttributeOffset, labels);
3253 }
3254 }
3255 return new Attribute(type).read(this, offset, length, null, -1, null);
3256 }
3257
3258 // -----------------------------------------------------------------------------------------------
3259 // Utility methods: low level parsing
3260 // -----------------------------------------------------------------------------------------------
3261
3262 /**
3263 * Returns the number of entries in the class's constant pool table.
3264 *
3265 * @return the number of entries in the class's constant pool table.
3266 */
3267 public int getItemCount() {
3268 return cpInfoOffsets.length;
3269 }
3270
3271 /**
3272 * Returns the start offset in {@link #b} of a JVMS 'cp_info' structure (i.e. a constant pool
3273 * entry), plus one. <i>This method is intended for {@link Attribute} sub classes, and is normally
3274 * not needed by class generators or adapters.</i>
3275 *
3276 * @param constantPoolEntryIndex the index a constant pool entry in the class's constant pool
3277 * table.
3278 * @return the start offset in {@link #b} of the corresponding JVMS 'cp_info' structure, plus one.
3279 */
3280 public int getItem(final int constantPoolEntryIndex) {
3281 return cpInfoOffsets[constantPoolEntryIndex];
3282 }
3283
3284 /**
3285 * Returns a conservative estimate of the maximum length of the strings contained in the class's
3286 * constant pool table.
3287 *
3288 * @return a conservative estimate of the maximum length of the strings contained in the class's
3289 * constant pool table.
3290 */
3291 public int getMaxStringLength() {
3292 return maxStringLength;
3293 }
3294
3295 /**
3296 * Reads a byte value in {@link #b}. <i>This method is intended for {@link Attribute} sub classes,
3297 * and is normally not needed by class generators or adapters.</i>
3298 *
3299 * @param offset the start offset of the value to be read in {@link #b}.
3300 * @return the read value.
3301 */
3302 public int readByte(final int offset) {
3303 return b[offset] & 0xFF;
3304 }
3305
3306 /**
3307 * Reads an unsigned short value in {@link #b}. <i>This method is intended for {@link Attribute}
3308 * sub classes, and is normally not needed by class generators or adapters.</i>
3309 *
3310 * @param offset the start index of the value to be read in {@link #b}.
3311 * @return the read value.
3312 */
3313 public int readUnsignedShort(final int offset) {
3314 byte[] classFileBuffer = b;
3315 return ((classFileBuffer[offset] & 0xFF) << 8) | (classFileBuffer[offset + 1] & 0xFF);
3316 }
3317
3318 /**
3319 * Reads a signed short value in {@link #b}. <i>This method is intended for {@link Attribute} sub
3320 * classes, and is normally not needed by class generators or adapters.</i>
3321 *
3322 * @param offset the start offset of the value to be read in {@link #b}.
3323 * @return the read value.
3324 */
3325 public short readShort(final int offset) {
3326 byte[] classFileBuffer = b;
3327 return (short) (((classFileBuffer[offset] & 0xFF) << 8) | (classFileBuffer[offset + 1] & 0xFF));
3328 }
3329
3330 /**
3331 * Reads a signed int value in {@link #b}. <i>This method is intended for {@link Attribute} sub
3332 * classes, and is normally not needed by class generators or adapters.</i>
3333 *
3334 * @param offset the start offset of the value to be read in {@link #b}.
3335 * @return the read value.
3336 */
3337 public int readInt(final int offset) {
3338 byte[] classFileBuffer = b;
3339 return ((classFileBuffer[offset] & 0xFF) << 24)
3340 | ((classFileBuffer[offset + 1] & 0xFF) << 16)
3341 | ((classFileBuffer[offset + 2] & 0xFF) << 8)
3342 | (classFileBuffer[offset + 3] & 0xFF);
3343 }
3344
3345 /**
3346 * Reads a signed long value in {@link #b}. <i>This method is intended for {@link Attribute} sub
3347 * classes, and is normally not needed by class generators or adapters.</i>
3348 *
3349 * @param offset the start offset of the value to be read in {@link #b}.
3350 * @return the read value.
3351 */
3352 public long readLong(final int offset) {
3353 long l1 = readInt(offset);
3354 long l0 = readInt(offset + 4) & 0xFFFFFFFFL;
3355 return (l1 << 32) | l0;
3356 }
3357
3358 /**
3359 * Reads a CONSTANT_Utf8 constant pool entry in {@link #b}. <i>This method is intended for {@link
3360 * Attribute} sub classes, and is normally not needed by class generators or adapters.</i>
3361 *
3362 * @param offset the start offset of an unsigned short value in {@link #b}, whose value is the
3363 * index of a CONSTANT_Utf8 entry in the class's constant pool table.
3364 * @param charBuffer the buffer to be used to read the string. This buffer must be sufficiently
3365 * large. It is not automatically resized.
3366 * @return the String corresponding to the specified CONSTANT_Utf8 entry.
3367 */
3368 public String readUTF8(final int offset, final char[] charBuffer) {
3369 int constantPoolEntryIndex = readUnsignedShort(offset);
3370 if (offset == 0 || constantPoolEntryIndex == 0) {
3371 return null;
3372 }
3373 return readUTF(constantPoolEntryIndex, charBuffer);
3374 }
3375
3376 /**
3377 * Reads a CONSTANT_Utf8 constant pool entry in {@link #b}.
3378 *
3379 * @param constantPoolEntryIndex the index of a CONSTANT_Utf8 entry in the class's constant pool
3380 * table.
3381 * @param charBuffer the buffer to be used to read the string. This buffer must be sufficiently
3382 * large. It is not automatically resized.
3383 * @return the String corresponding to the specified CONSTANT_Utf8 entry.
3384 */
3385 final String readUTF(final int constantPoolEntryIndex, final char[] charBuffer) {
3386 String value = (String) cpInfoValues[constantPoolEntryIndex];
3387 if (value != null) {
3388 return value;
3389 }
3390 int cpInfoOffset = cpInfoOffsets[constantPoolEntryIndex];
3391 value = readUTF(cpInfoOffset + 2, readUnsignedShort(cpInfoOffset), charBuffer);
3392 cpInfoValues[constantPoolEntryIndex] = value;
3393 return value;
3394 }
3395
3396 /**
3397 * Reads an UTF8 string in {@link #b}.
3398 *
3399 * @param utfOffset the start offset of the UTF8 string to be read.
3400 * @param utfLength the length of the UTF8 string to be read.
3401 * @param charBuffer the buffer to be used to read the string. This buffer must be sufficiently
3402 * large. It is not automatically resized.
3403 * @return the String corresponding to the specified UTF8 string.
3404 */
3405 private String readUTF(final int utfOffset, final int utfLength, final char[] charBuffer) {
3406 int currentOffset = utfOffset;
3407 int endOffset = currentOffset + utfLength;
3408 int strLength = 0;
3409 byte[] classFileBuffer = b;
3410 while (currentOffset < endOffset) {
3411 int currentByte = classFileBuffer[currentOffset++];
3412 if ((currentByte & 0x80) == 0) {
3413 charBuffer[strLength++] = (char) (currentByte & 0x7F);
3414 } else if ((currentByte & 0xE0) == 0xC0) {
3415 charBuffer[strLength++] =
3416 (char) (((currentByte & 0x1F) << 6) + (classFileBuffer[currentOffset++] & 0x3F));
3417 } else {
3418 charBuffer[strLength++] =
3419 (char)
3420 (((currentByte & 0xF) << 12)
3421 + ((classFileBuffer[currentOffset++] & 0x3F) << 6)
3422 + (classFileBuffer[currentOffset++] & 0x3F));
3423 }
3424 }
3425 return new String(charBuffer, 0, strLength);
3426 }
3427
3428 /**
3429 * Reads a CONSTANT_Class, CONSTANT_String, CONSTANT_MethodType, CONSTANT_Module or
3430 * CONSTANT_Package constant pool entry in {@link #b}. <i>This method is intended for {@link
3431 * Attribute} sub classes, and is normally not needed by class generators or adapters.</i>
3432 *
3433 * @param offset the start offset of an unsigned short value in {@link #b}, whose value is the
3434 * index of a CONSTANT_Class, CONSTANT_String, CONSTANT_MethodType, CONSTANT_Module or
3435 * CONSTANT_Package entry in class's constant pool table.
3436 * @param charBuffer the buffer to be used to read the item. This buffer must be sufficiently
3437 * large. It is not automatically resized.
3438 * @return the String corresponding to the specified constant pool entry.
3439 */
3440 private String readStringish(final int offset, final char[] charBuffer) {
3441 // Get the start offset of the cp_info structure (plus one), and read the CONSTANT_Utf8 entry
3442 // designated by the first two bytes of this cp_info.
3443 return readUTF8(cpInfoOffsets[readUnsignedShort(offset)], charBuffer);
3444 }
3445
3446 /**
3447 * Reads a CONSTANT_Class constant pool entry in {@link #b}. <i>This method is intended for {@link
3448 * Attribute} sub classes, and is normally not needed by class generators or adapters.</i>
3449 *
3450 * @param offset the start offset of an unsigned short value in {@link #b}, whose value is the
3451 * index of a CONSTANT_Class entry in class's constant pool table.
3452 * @param charBuffer the buffer to be used to read the item. This buffer must be sufficiently
3453 * large. It is not automatically resized.
3454 * @return the String corresponding to the specified CONSTANT_Class entry.
3455 */
3456 public String readClass(final int offset, final char[] charBuffer) {
3457 return readStringish(offset, charBuffer);
3458 }
3459
3460 /**
3461 * Reads a CONSTANT_Module constant pool entry in {@link #b}. <i>This method is intended for
3462 * {@link Attribute} sub classes, and is normally not needed by class generators or adapters.</i>
3463 *
3464 * @param offset the start offset of an unsigned short value in {@link #b}, whose value is the
3465 * index of a CONSTANT_Module entry in class's constant pool table.
3466 * @param charBuffer the buffer to be used to read the item. This buffer must be sufficiently
3467 * large. It is not automatically resized.
3468 * @return the String corresponding to the specified CONSTANT_Module entry.
3469 */
3470 public String readModule(final int offset, final char[] charBuffer) {
3471 return readStringish(offset, charBuffer);
3472 }
3473
3474 /**
3475 * Reads a CONSTANT_Package constant pool entry in {@link #b}. <i>This method is intended for
3476 * {@link Attribute} sub classes, and is normally not needed by class generators or adapters.</i>
3477 *
3478 * @param offset the start offset of an unsigned short value in {@link #b}, whose value is the
3479 * index of a CONSTANT_Package entry in class's constant pool table.
3480 * @param charBuffer the buffer to be used to read the item. This buffer must be sufficiently
3481 * large. It is not automatically resized.
3482 * @return the String corresponding to the specified CONSTANT_Package entry.
3483 */
3484 public String readPackage(final int offset, final char[] charBuffer) {
3485 return readStringish(offset, charBuffer);
3486 }
3487
3488 /**
3489 * Reads a CONSTANT_Dynamic constant pool entry in {@link #b}.
3490 *
3491 * @param constantPoolEntryIndex the index of a CONSTANT_Dynamic entry in the class's constant
3492 * pool table.
3493 * @param charBuffer the buffer to be used to read the string. This buffer must be sufficiently
3494 * large. It is not automatically resized.
3495 * @return the ConstantDynamic corresponding to the specified CONSTANT_Dynamic entry.
3496 */
3497 private ConstantDynamic readConstantDynamic(
3498 final int constantPoolEntryIndex, final char[] charBuffer) {
3499 ConstantDynamic constantDynamic = (ConstantDynamic) cpInfoValues[constantPoolEntryIndex];
3500 if (constantDynamic != null) {
3501 return constantDynamic;
3502 }
3503 int cpInfoOffset = cpInfoOffsets[constantPoolEntryIndex];
3504 int nameAndTypeCpInfoOffset = cpInfoOffsets[readUnsignedShort(cpInfoOffset + 2)];
3505 String name = readUTF8(nameAndTypeCpInfoOffset, charBuffer);
3506 String descriptor = readUTF8(nameAndTypeCpInfoOffset + 2, charBuffer);
3507 int bootstrapMethodOffset = bootstrapMethodOffsets[readUnsignedShort(cpInfoOffset)];
3508 Handle handle = (Handle) readConst(readUnsignedShort(bootstrapMethodOffset), charBuffer);
3509 Object[] bootstrapMethodArguments = new Object[readUnsignedShort(bootstrapMethodOffset + 2)];
3510 bootstrapMethodOffset += 4;
3511 for (int i = 0; i < bootstrapMethodArguments.length; i++) {
3512 bootstrapMethodArguments[i] = readConst(readUnsignedShort(bootstrapMethodOffset), charBuffer);
3513 bootstrapMethodOffset += 2;
3514 }
3515 constantDynamic = new ConstantDynamic(name, descriptor, handle, bootstrapMethodArguments);
3516 cpInfoValues[constantPoolEntryIndex] = constantDynamic;
3517 return constantDynamic;
3518 }
3519
3520 /**
3521 * Reads a numeric or string constant pool entry in {@link #b}. <i>This method is intended for
3522 * {@link Attribute} sub classes, and is normally not needed by class generators or adapters.</i>
3523 *
3524 * @param constantPoolEntryIndex the index of a CONSTANT_Integer, CONSTANT_Float, CONSTANT_Long,
3525 * CONSTANT_Double, CONSTANT_Class, CONSTANT_String, CONSTANT_MethodType,
3526 * CONSTANT_MethodHandle or CONSTANT_Dynamic entry in the class's constant pool.
3527 * @param charBuffer the buffer to be used to read strings. This buffer must be sufficiently
3528 * large. It is not automatically resized.
3529 * @return the {@link Integer}, {@link Float}, {@link Long}, {@link Double}, {@link String},
3530 * {@link Type}, {@link Handle} or {@link ConstantDynamic} corresponding to the specified
3531 * constant pool entry.
3532 */
3533 public Object readConst(final int constantPoolEntryIndex, final char[] charBuffer) {
3534 int cpInfoOffset = cpInfoOffsets[constantPoolEntryIndex];
3535 switch (b[cpInfoOffset - 1]) {
3536 case Symbol.CONSTANT_INTEGER_TAG:
3537 return readInt(cpInfoOffset);
3538 case Symbol.CONSTANT_FLOAT_TAG:
3539 return Float.intBitsToFloat(readInt(cpInfoOffset));
3540 case Symbol.CONSTANT_LONG_TAG:
3541 return readLong(cpInfoOffset);
3542 case Symbol.CONSTANT_DOUBLE_TAG:
3543 return Double.longBitsToDouble(readLong(cpInfoOffset));
3544 case Symbol.CONSTANT_CLASS_TAG:
3545 return Type.getObjectType(readUTF8(cpInfoOffset, charBuffer));
3546 case Symbol.CONSTANT_STRING_TAG:
3547 return readUTF8(cpInfoOffset, charBuffer);
3548 case Symbol.CONSTANT_METHOD_TYPE_TAG:
3549 return Type.getMethodType(readUTF8(cpInfoOffset, charBuffer));
3550 case Symbol.CONSTANT_METHOD_HANDLE_TAG:
3551 int referenceKind = readByte(cpInfoOffset);
3552 int referenceCpInfoOffset = cpInfoOffsets[readUnsignedShort(cpInfoOffset + 1)];
3553 int nameAndTypeCpInfoOffset = cpInfoOffsets[readUnsignedShort(referenceCpInfoOffset + 2)];
3554 String owner = readClass(referenceCpInfoOffset, charBuffer);
3555 String name = readUTF8(nameAndTypeCpInfoOffset, charBuffer);
3556 String descriptor = readUTF8(nameAndTypeCpInfoOffset + 2, charBuffer);
3557 boolean isInterface =
3558 b[referenceCpInfoOffset - 1] == Symbol.CONSTANT_INTERFACE_METHODREF_TAG;
3559 return new Handle(referenceKind, owner, name, descriptor, isInterface);
3560 case Symbol.CONSTANT_DYNAMIC_TAG:
3561 return readConstantDynamic(constantPoolEntryIndex, charBuffer);
3562 default:
3563 throw new IllegalArgumentException();
3564 }
3565 }
25793566 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
27 package org.eclipse.persistence.internal.libraries.asm;
28
29 /**
30 * A visitor to visit a Java class. The methods of this class must be called in the following order:
31 * <tt>visit</tt> [ <tt>visitSource</tt> ] [ <tt>visitModule</tt> ][ <tt>visitNestHost</tt> ][
32 * <tt>visitOuterClass</tt> ] ( <tt>visitAnnotation</tt> | <tt>visitTypeAnnotation</tt> |
33 * <tt>visitAttribute</tt> )* ( <tt>visitNestMember</tt> | <tt>visitInnerClass</tt> |
34 * <tt>visitField</tt> | <tt>visitMethod</tt> )* <tt>visitEnd</tt>.
435 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 package org.eclipse.persistence.internal.libraries.asm;
30
31 /**
32 * A visitor to visit a Java class. The methods of this class must be called in
33 * the following order: <tt>visit</tt> [ <tt>visitSource</tt> ] [
34 * <tt>visitOuterClass</tt> ] ( <tt>visitAnnotation</tt> |
35 * <tt>visitTypeAnnotation</tt> | <tt>visitAttribute</tt> )* (
36 * <tt>visitInnerClass</tt> | <tt>visitField</tt> | <tt>visitMethod</tt> )*
37 * <tt>visitEnd</tt>.
38 *
3936 * @author Eric Bruneton
4037 */
4138 public abstract class ClassVisitor {
4239
43 /**
44 * The ASM API version implemented by this visitor. The value of this field
45 * must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
46 */
47 protected final int api;
48
49 /**
50 * The class visitor to which this visitor must delegate method calls. May
51 * be null.
52 */
53 protected ClassVisitor cv;
54
55 /**
56 * Constructs a new {@link ClassVisitor}.
57 *
58 * @param api
59 * the ASM API version implemented by this visitor. Must be one
60 * of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
61 */
62 public ClassVisitor(final int api) {
63 this(api, null);
64 }
65
66 /**
67 * Constructs a new {@link ClassVisitor}.
68 *
69 * @param api
70 * the ASM API version implemented by this visitor. Must be one
71 * of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
72 * @param cv
73 * the class visitor to which this visitor must delegate method
74 * calls. May be null.
75 */
76 public ClassVisitor(final int api, final ClassVisitor cv) {
77 if (api < Opcodes.ASM4 || api > Opcodes.ASM6) {
78 throw new IllegalArgumentException();
79 }
80 this.api = api;
81 this.cv = cv;
82 }
83
84 /**
85 * Visits the header of the class.
86 *
87 * @param version
88 * the class version.
89 * @param access
90 * the class's access flags (see {@link Opcodes}). This parameter
91 * also indicates if the class is deprecated.
92 * @param name
93 * the internal name of the class (see
94 * {@link Type#getInternalName() getInternalName}).
95 * @param signature
96 * the signature of this class. May be <tt>null</tt> if the class
97 * is not a generic one, and does not extend or implement generic
98 * classes or interfaces.
99 * @param superName
100 * the internal of name of the super class (see
101 * {@link Type#getInternalName() getInternalName}). For
102 * interfaces, the super class is {@link Object}. May be
103 * <tt>null</tt>, but only for the {@link Object} class.
104 * @param interfaces
105 * the internal names of the class's interfaces (see
106 * {@link Type#getInternalName() getInternalName}). May be
107 * <tt>null</tt>.
108 */
109 public void visit(int version, int access, String name, String signature,
110 String superName, String[] interfaces) {
111 if (cv != null) {
112 cv.visit(version, access, name, signature, superName, interfaces);
113 }
114 }
115
116 /**
117 * Visits the source of the class.
118 *
119 * @param source
120 * the name of the source file from which the class was compiled.
121 * May be <tt>null</tt>.
122 * @param debug
123 * additional debug information to compute the correspondance
124 * between source and compiled elements of the class. May be
125 * <tt>null</tt>.
126 */
127 public void visitSource(String source, String debug) {
128 if (cv != null) {
129 cv.visitSource(source, debug);
130 }
131 }
132
133 /**
134 * Visit the module corresponding to the class.
135 * @return a visitor to visit the module values, or <tt>null</tt> if
136 * this visitor is not interested in visiting this module.
137 */
138 public ModuleVisitor visitModule() {
139 if (api < Opcodes.ASM6) {
140 throw new RuntimeException();
141 }
142 if (cv != null) {
143 return cv.visitModule();
144 }
145 return null;
146 }
147
148 /**
149 * Visits the enclosing class of the class. This method must be called only
150 * if the class has an enclosing class.
151 *
152 * @param owner
153 * internal name of the enclosing class of the class.
154 * @param name
155 * the name of the method that contains the class, or
156 * <tt>null</tt> if the class is not enclosed in a method of its
157 * enclosing class.
158 * @param desc
159 * the descriptor of the method that contains the class, or
160 * <tt>null</tt> if the class is not enclosed in a method of its
161 * enclosing class.
162 */
163 public void visitOuterClass(String owner, String name, String desc) {
164 if (cv != null) {
165 cv.visitOuterClass(owner, name, desc);
166 }
167 }
168
169 /**
170 * Visits an annotation of the class.
171 *
172 * @param desc
173 * the class descriptor of the annotation class.
174 * @param visible
175 * <tt>true</tt> if the annotation is visible at runtime.
176 * @return a visitor to visit the annotation values, or <tt>null</tt> if
177 * this visitor is not interested in visiting this annotation.
178 */
179 public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
180 if (cv != null) {
181 return cv.visitAnnotation(desc, visible);
182 }
183 return null;
184 }
185
186 /**
187 * Visits an annotation on a type in the class signature.
188 *
189 * @param typeRef
190 * a reference to the annotated type. The sort of this type
191 * reference must be {@link TypeReference#CLASS_TYPE_PARAMETER
192 * CLASS_TYPE_PARAMETER},
193 * {@link TypeReference#CLASS_TYPE_PARAMETER_BOUND
194 * CLASS_TYPE_PARAMETER_BOUND} or
195 * {@link TypeReference#CLASS_EXTENDS CLASS_EXTENDS}. See
196 * {@link TypeReference}.
197 * @param typePath
198 * the path to the annotated type argument, wildcard bound, array
199 * element type, or static inner type within 'typeRef'. May be
200 * <tt>null</tt> if the annotation targets 'typeRef' as a whole.
201 * @param desc
202 * the class descriptor of the annotation class.
203 * @param visible
204 * <tt>true</tt> if the annotation is visible at runtime.
205 * @return a visitor to visit the annotation values, or <tt>null</tt> if
206 * this visitor is not interested in visiting this annotation.
207 */
208 public AnnotationVisitor visitTypeAnnotation(int typeRef,
209 TypePath typePath, String desc, boolean visible) {
210 if (api < Opcodes.ASM5) {
211 throw new RuntimeException();
212 }
213 if (cv != null) {
214 return cv.visitTypeAnnotation(typeRef, typePath, desc, visible);
215 }
216 return null;
217 }
218
219 /**
220 * Visits a non standard attribute of the class.
221 *
222 * @param attr
223 * an attribute.
224 */
225 public void visitAttribute(Attribute attr) {
226 if (cv != null) {
227 cv.visitAttribute(attr);
228 }
229 }
230
231 /**
232 * Visits information about an inner class. This inner class is not
233 * necessarily a member of the class being visited.
234 *
235 * @param name
236 * the internal name of an inner class (see
237 * {@link Type#getInternalName() getInternalName}).
238 * @param outerName
239 * the internal name of the class to which the inner class
240 * belongs (see {@link Type#getInternalName() getInternalName}).
241 * May be <tt>null</tt> for not member classes.
242 * @param innerName
243 * the (simple) name of the inner class inside its enclosing
244 * class. May be <tt>null</tt> for anonymous inner classes.
245 * @param access
246 * the access flags of the inner class as originally declared in
247 * the enclosing class.
248 */
249 public void visitInnerClass(String name, String outerName,
250 String innerName, int access) {
251 if (cv != null) {
252 cv.visitInnerClass(name, outerName, innerName, access);
253 }
254 }
255
256 /**
257 * Visits a field of the class.
258 *
259 * @param access
260 * the field's access flags (see {@link Opcodes}). This parameter
261 * also indicates if the field is synthetic and/or deprecated.
262 * @param name
263 * the field's name.
264 * @param desc
265 * the field's descriptor (see {@link Type Type}).
266 * @param signature
267 * the field's signature. May be <tt>null</tt> if the field's
268 * type does not use generic types.
269 * @param value
270 * the field's initial value. This parameter, which may be
271 * <tt>null</tt> if the field does not have an initial value,
272 * must be an {@link Integer}, a {@link Float}, a {@link Long}, a
273 * {@link Double} or a {@link String} (for <tt>int</tt>,
274 * <tt>float</tt>, <tt>long</tt> or <tt>String</tt> fields
275 * respectively). <i>This parameter is only used for static
276 * fields</i>. Its value is ignored for non static fields, which
277 * must be initialized through bytecode instructions in
278 * constructors or methods.
279 * @return a visitor to visit field annotations and attributes, or
280 * <tt>null</tt> if this class visitor is not interested in visiting
281 * these annotations and attributes.
282 */
283 public FieldVisitor visitField(int access, String name, String desc,
284 String signature, Object value) {
285 if (cv != null) {
286 return cv.visitField(access, name, desc, signature, value);
287 }
288 return null;
289 }
290
291 /**
292 * Visits a method of the class. This method <i>must</i> return a new
293 * {@link MethodVisitor} instance (or <tt>null</tt>) each time it is called,
294 * i.e., it should not return a previously returned visitor.
295 *
296 * @param access
297 * the method's access flags (see {@link Opcodes}). This
298 * parameter also indicates if the method is synthetic and/or
299 * deprecated.
300 * @param name
301 * the method's name.
302 * @param desc
303 * the method's descriptor (see {@link Type Type}).
304 * @param signature
305 * the method's signature. May be <tt>null</tt> if the method
306 * parameters, return type and exceptions do not use generic
307 * types.
308 * @param exceptions
309 * the internal names of the method's exception classes (see
310 * {@link Type#getInternalName() getInternalName}). May be
311 * <tt>null</tt>.
312 * @return an object to visit the byte code of the method, or <tt>null</tt>
313 * if this class visitor is not interested in visiting the code of
314 * this method.
315 */
316 public MethodVisitor visitMethod(int access, String name, String desc,
317 String signature, String[] exceptions) {
318 if (cv != null) {
319 return cv.visitMethod(access, name, desc, signature, exceptions);
320 }
321 return null;
322 }
323
324 /**
325 * Visits the end of the class. This method, which is the last one to be
326 * called, is used to inform the visitor that all the fields and methods of
327 * the class have been visited.
328 */
329 public void visitEnd() {
330 if (cv != null) {
331 cv.visitEnd();
332 }
333 }
40 /**
41 * The ASM API version implemented by this visitor. The value of this field must be one of {@link
42 * Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7_EXPERIMENTAL}.
43 */
44 protected final int api;
45
46 /** The class visitor to which this visitor must delegate method calls. May be null. */
47 protected ClassVisitor cv;
48
49 /**
50 * Constructs a new {@link ClassVisitor}.
51 *
52 * @param api the ASM API version implemented by this visitor. Must be one of {@link
53 * Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link
54 * Opcodes#ASM7_EXPERIMENTAL}.
55 */
56 public ClassVisitor(final int api) {
57 this(api, null);
58 }
59
60 /**
61 * Constructs a new {@link ClassVisitor}.
62 *
63 * @param api the ASM API version implemented by this visitor. Must be one of {@link
64 * Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link
65 * Opcodes#ASM7_EXPERIMENTAL}.
66 * @param classVisitor the class visitor to which this visitor must delegate method calls. May be
67 * null.
68 */
69 public ClassVisitor(final int api, final ClassVisitor classVisitor) {
70 if (api != Opcodes.ASM6
71 && api != Opcodes.ASM5
72 && api != Opcodes.ASM4
73 && api != Opcodes.ASM7_EXPERIMENTAL) {
74 throw new IllegalArgumentException();
75 }
76 this.api = api;
77 this.cv = classVisitor;
78 }
79
80 /**
81 * Visits the header of the class.
82 *
83 * @param version the class version. The minor version is stored in the 16 most significant bits,
84 * and the major version in the 16 least significant bits.
85 * @param access the class's access flags (see {@link Opcodes}). This parameter also indicates if
86 * the class is deprecated.
87 * @param name the internal name of the class (see {@link Type#getInternalName()}).
88 * @param signature the signature of this class. May be <tt>null</tt> if the class is not a
89 * generic one, and does not extend or implement generic classes or interfaces.
90 * @param superName the internal of name of the super class (see {@link Type#getInternalName()}).
91 * For interfaces, the super class is {@link Object}. May be <tt>null</tt>, but only for the
92 * {@link Object} class.
93 * @param interfaces the internal names of the class's interfaces (see {@link
94 * Type#getInternalName()}). May be <tt>null</tt>.
95 */
96 public void visit(
97 final int version,
98 final int access,
99 final String name,
100 final String signature,
101 final String superName,
102 final String[] interfaces) {
103 if (cv != null) {
104 cv.visit(version, access, name, signature, superName, interfaces);
105 }
106 }
107
108 /**
109 * Visits the source of the class.
110 *
111 * @param source the name of the source file from which the class was compiled. May be
112 * <tt>null</tt>.
113 * @param debug additional debug information to compute the correspondence between source and
114 * compiled elements of the class. May be <tt>null</tt>.
115 */
116 public void visitSource(final String source, final String debug) {
117 if (cv != null) {
118 cv.visitSource(source, debug);
119 }
120 }
121
122 /**
123 * Visit the module corresponding to the class.
124 *
125 * @param name the fully qualified name (using dots) of the module.
126 * @param access the module access flags, among {@code ACC_OPEN}, {@code ACC_SYNTHETIC} and {@code
127 * ACC_MANDATED}.
128 * @param version the module version, or <tt>null</tt>.
129 * @return a visitor to visit the module values, or <tt>null</tt> if this visitor is not
130 * interested in visiting this module.
131 */
132 public ModuleVisitor visitModule(final String name, final int access, final String version) {
133 if (api < Opcodes.ASM6) {
134 throw new UnsupportedOperationException();
135 }
136 if (cv != null) {
137 return cv.visitModule(name, access, version);
138 }
139 return null;
140 }
141
142 /**
143 * <b>Experimental, use at your own risk. This method will be renamed when it becomes stable, this
144 * will break existing code using it</b>. Visits the nest host class of the class. A nest is a set
145 * of classes of the same package that share access to their private members. One of these
146 * classes, called the host, lists the other members of the nest, which in turn should link to the
147 * host of their nest. This method must be called only once and only if the visited class is a
148 * non-host member of a nest. A class is implicitly its own nest, so it's invalid to call this
149 * method with the visited class name as argument.
150 *
151 * @param nestHost the internal name of the host class of the nest.
152 * @deprecated This API is experimental.
153 */
154 @Deprecated
155 public void visitNestHostExperimental(final String nestHost) {
156 if (api < Opcodes.ASM7_EXPERIMENTAL) {
157 throw new UnsupportedOperationException();
158 }
159 if (cv != null) {
160 cv.visitNestHostExperimental(nestHost);
161 }
162 }
163
164 /**
165 * Visits the enclosing class of the class. This method must be called only if the class has an
166 * enclosing class.
167 *
168 * @param owner internal name of the enclosing class of the class.
169 * @param name the name of the method that contains the class, or <tt>null</tt> if the class is
170 * not enclosed in a method of its enclosing class.
171 * @param descriptor the descriptor of the method that contains the class, or <tt>null</tt> if the
172 * class is not enclosed in a method of its enclosing class.
173 */
174 public void visitOuterClass(final String owner, final String name, final String descriptor) {
175 if (cv != null) {
176 cv.visitOuterClass(owner, name, descriptor);
177 }
178 }
179
180 /**
181 * Visits an annotation of the class.
182 *
183 * @param descriptor the class descriptor of the annotation class.
184 * @param visible <tt>true</tt> if the annotation is visible at runtime.
185 * @return a visitor to visit the annotation values, or <tt>null</tt> if this visitor is not
186 * interested in visiting this annotation.
187 */
188 public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
189 if (cv != null) {
190 return cv.visitAnnotation(descriptor, visible);
191 }
192 return null;
193 }
194
195 /**
196 * Visits an annotation on a type in the class signature.
197 *
198 * @param typeRef a reference to the annotated type. The sort of this type reference must be
199 * {@link TypeReference#CLASS_TYPE_PARAMETER}, {@link
200 * TypeReference#CLASS_TYPE_PARAMETER_BOUND} or {@link TypeReference#CLASS_EXTENDS}. See
201 * {@link TypeReference}.
202 * @param typePath the path to the annotated type argument, wildcard bound, array element type, or
203 * static inner type within 'typeRef'. May be <tt>null</tt> if the annotation targets
204 * 'typeRef' as a whole.
205 * @param descriptor the class descriptor of the annotation class.
206 * @param visible <tt>true</tt> if the annotation is visible at runtime.
207 * @return a visitor to visit the annotation values, or <tt>null</tt> if this visitor is not
208 * interested in visiting this annotation.
209 */
210 public AnnotationVisitor visitTypeAnnotation(
211 final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
212 if (api < Opcodes.ASM5) {
213 throw new UnsupportedOperationException();
214 }
215 if (cv != null) {
216 return cv.visitTypeAnnotation(typeRef, typePath, descriptor, visible);
217 }
218 return null;
219 }
220
221 /**
222 * Visits a non standard attribute of the class.
223 *
224 * @param attribute an attribute.
225 */
226 public void visitAttribute(final Attribute attribute) {
227 if (cv != null) {
228 cv.visitAttribute(attribute);
229 }
230 }
231
232 /**
233 * <b>Experimental, use at your own risk. This method will be renamed when it becomes stable, this
234 * will break existing code using it</b>. Visits a member of the nest. A nest is a set of classes
235 * of the same package that share access to their private members. One of these classes, called
236 * the host, lists the other members of the nest, which in turn should link to the host of their
237 * nest. This method must be called only if the visited class is the host of a nest. A nest host
238 * is implicitly a member of its own nest, so it's invalid to call this method with the visited
239 * class name as argument.
240 *
241 * @param nestMember the internal name of a nest member.
242 * @deprecated This API is experimental.
243 */
244 @Deprecated
245 public void visitNestMemberExperimental(final String nestMember) {
246 if (api < Opcodes.ASM7_EXPERIMENTAL) {
247 throw new UnsupportedOperationException();
248 }
249 if (cv != null) {
250 cv.visitNestMemberExperimental(nestMember);
251 }
252 }
253
254 /**
255 * Visits information about an inner class. This inner class is not necessarily a member of the
256 * class being visited.
257 *
258 * @param name the internal name of an inner class (see {@link Type#getInternalName()}).
259 * @param outerName the internal name of the class to which the inner class belongs (see {@link
260 * Type#getInternalName()}). May be <tt>null</tt> for not member classes.
261 * @param innerName the (simple) name of the inner class inside its enclosing class. May be
262 * <tt>null</tt> for anonymous inner classes.
263 * @param access the access flags of the inner class as originally declared in the enclosing
264 * class.
265 */
266 public void visitInnerClass(
267 final String name, final String outerName, final String innerName, final int access) {
268 if (cv != null) {
269 cv.visitInnerClass(name, outerName, innerName, access);
270 }
271 }
272
273 /**
274 * Visits a field of the class.
275 *
276 * @param access the field's access flags (see {@link Opcodes}). This parameter also indicates if
277 * the field is synthetic and/or deprecated.
278 * @param name the field's name.
279 * @param descriptor the field's descriptor (see {@link Type}).
280 * @param signature the field's signature. May be <tt>null</tt> if the field's type does not use
281 * generic types.
282 * @param value the field's initial value. This parameter, which may be <tt>null</tt> if the field
283 * does not have an initial value, must be an {@link Integer}, a {@link Float}, a {@link
284 * Long}, a {@link Double} or a {@link String} (for <tt>int</tt>, <tt>float</tt>,
285 * <tt>long</tt> or <tt>String</tt> fields respectively). <i>This parameter is only used for
286 * static fields</i>. Its value is ignored for non static fields, which must be initialized
287 * through bytecode instructions in constructors or methods.
288 * @return a visitor to visit field annotations and attributes, or <tt>null</tt> if this class
289 * visitor is not interested in visiting these annotations and attributes.
290 */
291 public FieldVisitor visitField(
292 final int access,
293 final String name,
294 final String descriptor,
295 final String signature,
296 final Object value) {
297 if (cv != null) {
298 return cv.visitField(access, name, descriptor, signature, value);
299 }
300 return null;
301 }
302
303 /**
304 * Visits a method of the class. This method <i>must</i> return a new {@link MethodVisitor}
305 * instance (or <tt>null</tt>) each time it is called, i.e., it should not return a previously
306 * returned visitor.
307 *
308 * @param access the method's access flags (see {@link Opcodes}). This parameter also indicates if
309 * the method is synthetic and/or deprecated.
310 * @param name the method's name.
311 * @param descriptor the method's descriptor (see {@link Type}).
312 * @param signature the method's signature. May be <tt>null</tt> if the method parameters, return
313 * type and exceptions do not use generic types.
314 * @param exceptions the internal names of the method's exception classes (see {@link
315 * Type#getInternalName()}). May be <tt>null</tt>.
316 * @return an object to visit the byte code of the method, or <tt>null</tt> if this class visitor
317 * is not interested in visiting the code of this method.
318 */
319 public MethodVisitor visitMethod(
320 final int access,
321 final String name,
322 final String descriptor,
323 final String signature,
324 final String[] exceptions) {
325 if (cv != null) {
326 return cv.visitMethod(access, name, descriptor, signature, exceptions);
327 }
328 return null;
329 }
330
331 /**
332 * Visits the end of the class. This method, which is the last one to be called, is used to inform
333 * the visitor that all the fields and methods of the class have been visited.
334 */
335 public void visitEnd() {
336 if (cv != null) {
337 cv.visitEnd();
338 }
339 }
334340 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
27 package org.eclipse.persistence.internal.libraries.asm;
28
29 /**
30 * A {@link ClassVisitor} that generates a corresponding ClassFile structure, as defined in the Java
31 * Virtual Machine Specification (JVMS). It can be used alone, to generate a Java class "from
32 * scratch", or with one or more {@link ClassReader} and adapter {@link ClassVisitor} to generate a
33 * modified class from one or more existing Java classes.
434 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 package org.eclipse.persistence.internal.libraries.asm;
30
31 /**
32 * A {@link ClassVisitor} that generates classes in bytecode form. More
33 * precisely this visitor generates a byte array conforming to the Java class
34 * file format. It can be used alone, to generate a Java class "from scratch",
35 * or with one or more {@link ClassReader ClassReader} and adapter class visitor
36 * to generate a modified class from one or more existing Java classes.
37 *
35 * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html">JVMS 4</a>
3836 * @author Eric Bruneton
3937 */
4038 public class ClassWriter extends ClassVisitor {
4139
42 /**
43 * Flag to automatically compute the maximum stack size and the maximum
44 * number of local variables of methods. If this flag is set, then the
45 * arguments of the {@link MethodVisitor#visitMaxs visitMaxs} method of the
46 * {@link MethodVisitor} returned by the {@link #visitMethod visitMethod}
47 * method will be ignored, and computed automatically from the signature and
48 * the bytecode of each method.
49 *
50 * @see #ClassWriter(int)
51 */
52 public static final int COMPUTE_MAXS = 1;
53
54 /**
55 * Flag to automatically compute the stack map frames of methods from
56 * scratch. If this flag is set, then the calls to the
57 * {@link MethodVisitor#visitFrame} method are ignored, and the stack map
58 * frames are recomputed from the methods bytecode. The arguments of the
59 * {@link MethodVisitor#visitMaxs visitMaxs} method are also ignored and
60 * recomputed from the bytecode. In other words, computeFrames implies
61 * computeMaxs.
62 *
63 * @see #ClassWriter(int)
64 */
65 public static final int COMPUTE_FRAMES = 2;
66
67 /**
68 * Pseudo access flag to distinguish between the synthetic attribute and the
69 * synthetic access flag.
70 */
71 static final int ACC_SYNTHETIC_ATTRIBUTE = 0x40000;
72
73 /**
74 * Factor to convert from ACC_SYNTHETIC_ATTRIBUTE to Opcode.ACC_SYNTHETIC.
75 */
76 static final int TO_ACC_SYNTHETIC = ACC_SYNTHETIC_ATTRIBUTE
77 / Opcodes.ACC_SYNTHETIC;
78
79 /**
80 * The type of instructions without any argument.
81 */
82 static final int NOARG_INSN = 0;
83
84 /**
85 * The type of instructions with an signed byte argument.
86 */
87 static final int SBYTE_INSN = 1;
88
89 /**
90 * The type of instructions with an signed short argument.
91 */
92 static final int SHORT_INSN = 2;
93
94 /**
95 * The type of instructions with a local variable index argument.
96 */
97 static final int VAR_INSN = 3;
98
99 /**
100 * The type of instructions with an implicit local variable index argument.
101 */
102 static final int IMPLVAR_INSN = 4;
103
104 /**
105 * The type of instructions with a type descriptor argument.
106 */
107 static final int TYPE_INSN = 5;
108
109 /**
110 * The type of field and method invocations instructions.
111 */
112 static final int FIELDORMETH_INSN = 6;
113
114 /**
115 * The type of the INVOKEINTERFACE/INVOKEDYNAMIC instruction.
116 */
117 static final int ITFMETH_INSN = 7;
118
119 /**
120 * The type of the INVOKEDYNAMIC instruction.
121 */
122 static final int INDYMETH_INSN = 8;
123
124 /**
125 * The type of instructions with a 2 bytes bytecode offset label.
126 */
127 static final int LABEL_INSN = 9;
128
129 /**
130 * The type of instructions with a 4 bytes bytecode offset label.
131 */
132 static final int LABELW_INSN = 10;
133
134 /**
135 * The type of the LDC instruction.
136 */
137 static final int LDC_INSN = 11;
138
139 /**
140 * The type of the LDC_W and LDC2_W instructions.
141 */
142 static final int LDCW_INSN = 12;
143
144 /**
145 * The type of the IINC instruction.
146 */
147 static final int IINC_INSN = 13;
148
149 /**
150 * The type of the TABLESWITCH instruction.
151 */
152 static final int TABL_INSN = 14;
153
154 /**
155 * The type of the LOOKUPSWITCH instruction.
156 */
157 static final int LOOK_INSN = 15;
158
159 /**
160 * The type of the MULTIANEWARRAY instruction.
161 */
162 static final int MANA_INSN = 16;
163
164 /**
165 * The type of the WIDE instruction.
166 */
167 static final int WIDE_INSN = 17;
168
169 /**
170 * The instruction types of all JVM opcodes.
171 */
172 static final byte[] TYPE;
173
174 /**
175 * The type of CONSTANT_Class constant pool items.
176 */
177 static final int CLASS = 7;
178
179 /**
180 * The type of CONSTANT_Fieldref constant pool items.
181 */
182 static final int FIELD = 9;
183
184 /**
185 * The type of CONSTANT_Methodref constant pool items.
186 */
187 static final int METH = 10;
188
189 /**
190 * The type of CONSTANT_InterfaceMethodref constant pool items.
191 */
192 static final int IMETH = 11;
193
194 /**
195 * The type of CONSTANT_String constant pool items.
196 */
197 static final int STR = 8;
198
199 /**
200 * The type of CONSTANT_Integer constant pool items.
201 */
202 static final int INT = 3;
203
204 /**
205 * The type of CONSTANT_Float constant pool items.
206 */
207 static final int FLOAT = 4;
208
209 /**
210 * The type of CONSTANT_Long constant pool items.
211 */
212 static final int LONG = 5;
213
214 /**
215 * The type of CONSTANT_Double constant pool items.
216 */
217 static final int DOUBLE = 6;
218
219 /**
220 * The type of CONSTANT_NameAndType constant pool items.
221 */
222 static final int NAME_TYPE = 12;
223
224 /**
225 * The type of CONSTANT_Utf8 constant pool items.
226 */
227 static final int UTF8 = 1;
228
229 /**
230 * The type of CONSTANT_MethodType constant pool items.
231 */
232 static final int MTYPE = 16;
233
234 /**
235 * The type of CONSTANT_MethodHandle constant pool items.
236 */
237 static final int HANDLE = 15;
238
239 /**
240 * The type of CONSTANT_InvokeDynamic constant pool items.
241 */
242 static final int INDY = 18;
243
244 /**
245 * The base value for all CONSTANT_MethodHandle constant pool items.
246 * Internally, ASM store the 9 variations of CONSTANT_MethodHandle into 9
247 * different items.
248 */
249 static final int HANDLE_BASE = 20;
250
251 /**
252 * Normal type Item stored in the ClassWriter {@link ClassWriter#typeTable},
253 * instead of the constant pool, in order to avoid clashes with normal
254 * constant pool items in the ClassWriter constant pool's hash table.
255 */
256 static final int TYPE_NORMAL = 30;
257
258 /**
259 * Uninitialized type Item stored in the ClassWriter
260 * {@link ClassWriter#typeTable}, instead of the constant pool, in order to
261 * avoid clashes with normal constant pool items in the ClassWriter constant
262 * pool's hash table.
263 */
264 static final int TYPE_UNINIT = 31;
265
266 /**
267 * Merged type Item stored in the ClassWriter {@link ClassWriter#typeTable},
268 * instead of the constant pool, in order to avoid clashes with normal
269 * constant pool items in the ClassWriter constant pool's hash table.
270 */
271 static final int TYPE_MERGED = 32;
272
273 /**
274 * The type of BootstrapMethods items. These items are stored in a special
275 * class attribute named BootstrapMethods and not in the constant pool.
276 */
277 static final int BSM = 33;
278
279 /**
280 * The class reader from which this class writer was constructed, if any.
281 */
282 ClassReader cr;
283
284 /**
285 * Minor and major version numbers of the class to be generated.
286 */
287 int version;
288
289 /**
290 * Index of the next item to be added in the constant pool.
291 */
292 int index;
293
294 /**
295 * The constant pool of this class.
296 */
297 final ByteVector pool;
298
299 /**
300 * The constant pool's hash table data.
301 */
302 Item[] items;
303
304 /**
305 * The threshold of the constant pool's hash table.
306 */
307 int threshold;
308
309 /**
310 * A reusable key used to look for items in the {@link #items} hash table.
311 */
312 final Item key;
313
314 /**
315 * A reusable key used to look for items in the {@link #items} hash table.
316 */
317 final Item key2;
318
319 /**
320 * A reusable key used to look for items in the {@link #items} hash table.
321 */
322 final Item key3;
323
324 /**
325 * A reusable key used to look for items in the {@link #items} hash table.
326 */
327 final Item key4;
328
329 /**
330 * A type table used to temporarily store internal names that will not
331 * necessarily be stored in the constant pool. This type table is used by
332 * the control flow and data flow analysis algorithm used to compute stack
333 * map frames from scratch. This array associates to each index <tt>i</tt>
334 * the Item whose index is <tt>i</tt>. All Item objects stored in this array
335 * are also stored in the {@link #items} hash table. These two arrays allow
336 * to retrieve an Item from its index or, conversely, to get the index of an
337 * Item from its value. Each Item stores an internal name in its
338 * {@link Item#strVal1} field.
339 */
340 Item[] typeTable;
341
342 /**
343 * Number of elements in the {@link #typeTable} array.
344 */
345 private short typeCount;
346
347 /**
348 * The access flags of this class.
349 */
350 private int access;
351
352 /**
353 * The constant pool item that contains the internal name of this class.
354 */
355 private int name;
356
357 /**
358 * The internal name of this class.
359 */
360 String thisName;
361
362 /**
363 * The constant pool item that contains the signature of this class.
364 */
365 private int signature;
366
367 /**
368 * The constant pool item that contains the internal name of the super class
369 * of this class.
370 */
371 private int superName;
372
373 /**
374 * Number of interfaces implemented or extended by this class or interface.
375 */
376 private int interfaceCount;
377
378 /**
379 * The interfaces implemented or extended by this class or interface. More
380 * precisely, this array contains the indexes of the constant pool items
381 * that contain the internal names of these interfaces.
382 */
383 private int[] interfaces;
384
385 /**
386 * The index of the constant pool item that contains the name of the source
387 * file from which this class was compiled.
388 */
389 private int sourceFile;
390
391 /**
392 * The SourceDebug attribute of this class.
393 */
394 private ByteVector sourceDebug;
395
396 /**
397 * The module attribute of this class.
398 */
399 private ModuleWriter moduleWriter;
400
401 /**
402 * The constant pool item that contains the name of the enclosing class of
403 * this class.
404 */
405 private int enclosingMethodOwner;
406
407 /**
408 * The constant pool item that contains the name and descriptor of the
409 * enclosing method of this class.
410 */
411 private int enclosingMethod;
412
413 /**
414 * The runtime visible annotations of this class.
415 */
416 private AnnotationWriter anns;
417
418 /**
419 * The runtime invisible annotations of this class.
420 */
421 private AnnotationWriter ianns;
422
423 /**
424 * The runtime visible type annotations of this class.
425 */
426 private AnnotationWriter tanns;
427
428 /**
429 * The runtime invisible type annotations of this class.
430 */
431 private AnnotationWriter itanns;
432
433 /**
434 * The non standard attributes of this class.
435 */
436 private Attribute attrs;
437
438 /**
439 * The number of entries in the InnerClasses attribute.
440 */
441 private int innerClassesCount;
442
443 /**
444 * The InnerClasses attribute.
445 */
446 private ByteVector innerClasses;
447
448 /**
449 * The number of entries in the BootstrapMethods attribute.
450 */
451 int bootstrapMethodsCount;
452
453 /**
454 * The BootstrapMethods attribute.
455 */
456 ByteVector bootstrapMethods;
457
458 /**
459 * The fields of this class. These fields are stored in a linked list of
460 * {@link FieldWriter} objects, linked to each other by their
461 * {@link FieldWriter#fv} field. This field stores the first element of this
462 * list.
463 */
464 FieldWriter firstField;
465
466 /**
467 * The fields of this class. These fields are stored in a linked list of
468 * {@link FieldWriter} objects, linked to each other by their
469 * {@link FieldWriter#fv} field. This field stores the last element of this
470 * list.
471 */
472 FieldWriter lastField;
473
474 /**
475 * The methods of this class. These methods are stored in a linked list of
476 * {@link MethodWriter} objects, linked to each other by their
477 * {@link MethodWriter#mv} field. This field stores the first element of
478 * this list.
479 */
480 MethodWriter firstMethod;
481
482 /**
483 * The methods of this class. These methods are stored in a linked list of
484 * {@link MethodWriter} objects, linked to each other by their
485 * {@link MethodWriter#mv} field. This field stores the last element of this
486 * list.
487 */
488 MethodWriter lastMethod;
489
490 /**
491 * <tt>true</tt> if the maximum stack size and number of local variables
492 * must be automatically computed.
493 */
494 private boolean computeMaxs;
495
496 /**
497 * <tt>true</tt> if the stack map frames must be recomputed from scratch.
498 */
499 private boolean computeFrames;
500
501 /**
502 * <tt>true</tt> if the stack map tables of this class are invalid. The
503 * {@link MethodWriter#resizeInstructions} method cannot transform existing
504 * stack map tables, and so produces potentially invalid classes when it is
505 * executed. In this case the class is reread and rewritten with the
506 * {@link #COMPUTE_FRAMES} option (the resizeInstructions method can resize
507 * stack map tables when this option is used).
508 */
509 boolean invalidFrames;
510
511 // ------------------------------------------------------------------------
512 // Static initializer
513 // ------------------------------------------------------------------------
514
515 /**
516 * Computes the instruction types of JVM opcodes.
517 */
518 static {
519 int i;
520 byte[] b = new byte[220];
521 String s = "AAAAAAAAAAAAAAAABCLMMDDDDDEEEEEEEEEEEEEEEEEEEEAAAAAAAADD"
522 + "DDDEEEEEEEEEEEEEEEEEEEEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
523 + "AAAAAAAAAAAAAAAAANAAAAAAAAAAAAAAAAAAAAJJJJJJJJJJJJJJJJDOPAA"
524 + "AAAAGGGGGGGHIFBFAAFFAARQJJKKJJJJJJJJJJJJJJJJJJ";
525 for (i = 0; i < b.length; ++i) {
526 b[i] = (byte) (s.charAt(i) - 'A');
527 }
528 TYPE = b;
529
530 // code to generate the above string
531 //
532 // // SBYTE_INSN instructions
533 // b[Constants.NEWARRAY] = SBYTE_INSN;
534 // b[Constants.BIPUSH] = SBYTE_INSN;
535 //
536 // // SHORT_INSN instructions
537 // b[Constants.SIPUSH] = SHORT_INSN;
538 //
539 // // (IMPL)VAR_INSN instructions
540 // b[Constants.RET] = VAR_INSN;
541 // for (i = Constants.ILOAD; i <= Constants.ALOAD; ++i) {
542 // b[i] = VAR_INSN;
543 // }
544 // for (i = Constants.ISTORE; i <= Constants.ASTORE; ++i) {
545 // b[i] = VAR_INSN;
546 // }
547 // for (i = 26; i <= 45; ++i) { // ILOAD_0 to ALOAD_3
548 // b[i] = IMPLVAR_INSN;
549 // }
550 // for (i = 59; i <= 78; ++i) { // ISTORE_0 to ASTORE_3
551 // b[i] = IMPLVAR_INSN;
552 // }
553 //
554 // // TYPE_INSN instructions
555 // b[Constants.NEW] = TYPE_INSN;
556 // b[Constants.ANEWARRAY] = TYPE_INSN;
557 // b[Constants.CHECKCAST] = TYPE_INSN;
558 // b[Constants.INSTANCEOF] = TYPE_INSN;
559 //
560 // // (Set)FIELDORMETH_INSN instructions
561 // for (i = Constants.GETSTATIC; i <= Constants.INVOKESTATIC; ++i) {
562 // b[i] = FIELDORMETH_INSN;
563 // }
564 // b[Constants.INVOKEINTERFACE] = ITFMETH_INSN;
565 // b[Constants.INVOKEDYNAMIC] = INDYMETH_INSN;
566 //
567 // // LABEL(W)_INSN instructions
568 // for (i = Constants.IFEQ; i <= Constants.JSR; ++i) {
569 // b[i] = LABEL_INSN;
570 // }
571 // b[Constants.IFNULL] = LABEL_INSN;
572 // b[Constants.IFNONNULL] = LABEL_INSN;
573 // b[200] = LABELW_INSN; // GOTO_W
574 // b[201] = LABELW_INSN; // JSR_W
575 // // temporary opcodes used internally by ASM - see Label and
576 // MethodWriter
577 // for (i = 202; i < 220; ++i) {
578 // b[i] = LABEL_INSN;
579 // }
580 //
581 // // LDC(_W) instructions
582 // b[Constants.LDC] = LDC_INSN;
583 // b[19] = LDCW_INSN; // LDC_W
584 // b[20] = LDCW_INSN; // LDC2_W
585 //
586 // // special instructions
587 // b[Constants.IINC] = IINC_INSN;
588 // b[Constants.TABLESWITCH] = TABL_INSN;
589 // b[Constants.LOOKUPSWITCH] = LOOK_INSN;
590 // b[Constants.MULTIANEWARRAY] = MANA_INSN;
591 // b[196] = WIDE_INSN; // WIDE
592 //
593 // for (i = 0; i < b.length; ++i) {
594 // System.err.print((char)('A' + b[i]));
595 // }
596 // System.err.println();
597 }
598
599 // ------------------------------------------------------------------------
600 // Constructor
601 // ------------------------------------------------------------------------
602
603 /**
604 * Constructs a new {@link ClassWriter} object.
605 *
606 * @param flags
607 * option flags that can be used to modify the default behavior
608 * of this class. See {@link #COMPUTE_MAXS},
609 * {@link #COMPUTE_FRAMES}.
610 */
611 public ClassWriter(final int flags) {
612 super(Opcodes.ASM6);
613 index = 1;
614 pool = new ByteVector();
615 items = new Item[256];
616 threshold = (int) (0.75d * items.length);
617 key = new Item();
618 key2 = new Item();
619 key3 = new Item();
620 key4 = new Item();
621 this.computeMaxs = (flags & COMPUTE_MAXS) != 0;
622 this.computeFrames = (flags & COMPUTE_FRAMES) != 0;
623 }
624
625 /**
626 * Constructs a new {@link ClassWriter} object and enables optimizations for
627 * "mostly add" bytecode transformations. These optimizations are the
628 * following:
629 *
630 * <ul>
631 * <li>The constant pool from the original class is copied as is in the new
632 * class, which saves time. New constant pool entries will be added at the
633 * end if necessary, but unused constant pool entries <i>won't be
634 * removed</i>.</li>
635 * <li>Methods that are not transformed are copied as is in the new class,
636 * directly from the original class bytecode (i.e. without emitting visit
637 * events for all the method instructions), which saves a <i>lot</i> of
638 * time. Untransformed methods are detected by the fact that the
639 * {@link ClassReader} receives {@link MethodVisitor} objects that come from
640 * a {@link ClassWriter} (and not from any other {@link ClassVisitor}
641 * instance).</li>
642 * </ul>
643 *
644 * @param classReader
645 * the {@link ClassReader} used to read the original class. It
646 * will be used to copy the entire constant pool from the
647 * original class and also to copy other fragments of original
648 * bytecode where applicable.
649 * @param flags
650 * option flags that can be used to modify the default behavior
651 * of this class. <i>These option flags do not affect methods
652 * that are copied as is in the new class. This means that
653 * neither the maximum stack size nor the stack frames will be
654 * computed for these methods</i>. See {@link #COMPUTE_MAXS},
655 * {@link #COMPUTE_FRAMES}.
656 */
657 public ClassWriter(final ClassReader classReader, final int flags) {
658 this(flags);
659 classReader.copyPool(this);
660 this.cr = classReader;
661 }
662
663 // ------------------------------------------------------------------------
664 // Implementation of the ClassVisitor abstract class
665 // ------------------------------------------------------------------------
666
667 @Override
668 public final void visit(final int version, final int access,
669 final String name, final String signature, final String superName,
670 final String[] interfaces) {
671 this.version = version;
672 this.access = access;
673 this.name = newClass(name);
674 thisName = name;
675 if (ClassReader.SIGNATURES && signature != null) {
676 this.signature = newUTF8(signature);
677 }
678 this.superName = superName == null ? 0 : newClass(superName);
679 if (interfaces != null && interfaces.length > 0) {
680 interfaceCount = interfaces.length;
681 this.interfaces = new int[interfaceCount];
682 for (int i = 0; i < interfaceCount; ++i) {
683 this.interfaces[i] = newClass(interfaces[i]);
684 }
685 }
686 }
687
688 @Override
689 public final void visitSource(final String file, final String debug) {
690 if (file != null) {
691 sourceFile = newUTF8(file);
692 }
693 if (debug != null) {
694 sourceDebug = new ByteVector().encodeUTF8(debug, 0,
695 Integer.MAX_VALUE);
696 }
697 }
698
699 @Override
700 public final ModuleVisitor visitModule() {
701 return moduleWriter = new ModuleWriter(this);
702 }
703
704 @Override
705 public final void visitOuterClass(final String owner, final String name,
706 final String desc) {
707 enclosingMethodOwner = newClass(owner);
708 if (name != null && desc != null) {
709 enclosingMethod = newNameType(name, desc);
710 }
711 }
712
713 @Override
714 public final AnnotationVisitor visitAnnotation(final String desc,
715 final boolean visible) {
716 if (!ClassReader.ANNOTATIONS) {
717 return null;
718 }
719 ByteVector bv = new ByteVector();
720 // write type, and reserve space for values count
721 bv.putShort(newUTF8(desc)).putShort(0);
722 AnnotationWriter aw = new AnnotationWriter(this, true, bv, bv, 2);
723 if (visible) {
724 aw.next = anns;
725 anns = aw;
726 } else {
727 aw.next = ianns;
728 ianns = aw;
729 }
730 return aw;
731 }
732
733 @Override
734 public final AnnotationVisitor visitTypeAnnotation(int typeRef,
735 TypePath typePath, final String desc, final boolean visible) {
736 if (!ClassReader.ANNOTATIONS) {
737 return null;
738 }
739 ByteVector bv = new ByteVector();
740 // write target_type and target_info
741 AnnotationWriter.putTarget(typeRef, typePath, bv);
742 // write type, and reserve space for values count
743 bv.putShort(newUTF8(desc)).putShort(0);
744 AnnotationWriter aw = new AnnotationWriter(this, true, bv, bv,
745 bv.length - 2);
746 if (visible) {
747 aw.next = tanns;
748 tanns = aw;
749 } else {
750 aw.next = itanns;
751 itanns = aw;
752 }
753 return aw;
754 }
755
756 @Override
757 public final void visitAttribute(final Attribute attr) {
758 attr.next = attrs;
759 attrs = attr;
760 }
761
762 @Override
763 public final void visitInnerClass(final String name,
764 final String outerName, final String innerName, final int access) {
765 if (innerClasses == null) {
766 innerClasses = new ByteVector();
767 }
768 // Sec. 4.7.6 of the JVMS states "Every CONSTANT_Class_info entry in the
769 // constant_pool table which represents a class or interface C that is
770 // not a package member must have exactly one corresponding entry in the
771 // classes array". To avoid duplicates we keep track in the intVal field
772 // of the Item of each CONSTANT_Class_info entry C whether an inner
773 // class entry has already been added for C (this field is unused for
774 // class entries, and changing its value does not change the hashcode
775 // and equality tests). If so we store the index of this inner class
776 // entry (plus one) in intVal. This hack allows duplicate detection in
777 // O(1) time.
778 Item nameItem = newClassItem(name);
779 if (nameItem.intVal == 0) {
780 ++innerClassesCount;
781 innerClasses.putShort(nameItem.index);
782 innerClasses.putShort(outerName == null ? 0 : newClass(outerName));
783 innerClasses.putShort(innerName == null ? 0 : newUTF8(innerName));
784 innerClasses.putShort(access);
785 nameItem.intVal = innerClassesCount;
786 } else {
787 // Compare the inner classes entry nameItem.intVal - 1 with the
788 // arguments of this method and throw an exception if there is a
789 // difference?
790 }
791 }
792
793 @Override
794 public final FieldVisitor visitField(final int access, final String name,
795 final String desc, final String signature, final Object value) {
796 return new FieldWriter(this, access, name, desc, signature, value);
797 }
798
799 @Override
800 public final MethodVisitor visitMethod(final int access, final String name,
801 final String desc, final String signature, final String[] exceptions) {
802 return new MethodWriter(this, access, name, desc, signature,
803 exceptions, computeMaxs, computeFrames);
804 }
805
806 @Override
807 public final void visitEnd() {
808 }
809
810 // ------------------------------------------------------------------------
811 // Other public methods
812 // ------------------------------------------------------------------------
813
814 /**
815 * Returns the bytecode of the class that was build with this class writer.
816 *
817 * @return the bytecode of the class that was build with this class writer.
818 */
819 public byte[] toByteArray() {
820 if (index > 0xFFFF) {
821 throw new RuntimeException("Class file too large!");
822 }
823 // computes the real size of the bytecode of this class
824 int size = 24 + 2 * interfaceCount;
825 int nbFields = 0;
826 FieldWriter fb = firstField;
827 while (fb != null) {
828 ++nbFields;
829 size += fb.getSize();
830 fb = (FieldWriter) fb.fv;
831 }
832 int nbMethods = 0;
833 MethodWriter mb = firstMethod;
834 while (mb != null) {
835 ++nbMethods;
836 size += mb.getSize();
837 mb = (MethodWriter) mb.mv;
838 }
839 int attributeCount = 0;
840 if (bootstrapMethods != null) {
841 // we put it as first attribute in order to improve a bit
842 // ClassReader.copyBootstrapMethods
843 ++attributeCount;
844 size += 8 + bootstrapMethods.length;
845 newUTF8("BootstrapMethods");
846 }
847 if (ClassReader.SIGNATURES && signature != 0) {
848 ++attributeCount;
849 size += 8;
850 newUTF8("Signature");
851 }
852 if (sourceFile != 0) {
853 ++attributeCount;
854 size += 8;
855 newUTF8("SourceFile");
856 }
857 if (sourceDebug != null) {
858 ++attributeCount;
859 size += sourceDebug.length + 6;
860 newUTF8("SourceDebugExtension");
861 }
862 if (enclosingMethodOwner != 0) {
863 ++attributeCount;
864 size += 10;
865 newUTF8("EnclosingMethod");
866 }
867 if ((access & Opcodes.ACC_DEPRECATED) != 0) {
868 ++attributeCount;
869 size += 6;
870 newUTF8("Deprecated");
871 }
872 if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
873 if ((version & 0xFFFF) < Opcodes.V1_5
874 || (access & ACC_SYNTHETIC_ATTRIBUTE) != 0) {
875 ++attributeCount;
876 size += 6;
877 newUTF8("Synthetic");
878 }
879 }
880 if (innerClasses != null) {
881 ++attributeCount;
882 size += 8 + innerClasses.length;
883 newUTF8("InnerClasses");
884 }
885 if (ClassReader.ANNOTATIONS && anns != null) {
886 ++attributeCount;
887 size += 8 + anns.getSize();
888 newUTF8("RuntimeVisibleAnnotations");
889 }
890 if (ClassReader.ANNOTATIONS && ianns != null) {
891 ++attributeCount;
892 size += 8 + ianns.getSize();
893 newUTF8("RuntimeInvisibleAnnotations");
894 }
895 if (ClassReader.ANNOTATIONS && tanns != null) {
896 ++attributeCount;
897 size += 8 + tanns.getSize();
898 newUTF8("RuntimeVisibleTypeAnnotations");
899 }
900 if (ClassReader.ANNOTATIONS && itanns != null) {
901 ++attributeCount;
902 size += 8 + itanns.getSize();
903 newUTF8("RuntimeInvisibleTypeAnnotations");
904 }
905 if (moduleWriter != null) {
906 ++attributeCount;
907 size += 6 + moduleWriter.getSize();
908 newUTF8("Module");
909 }
910 if (attrs != null) {
911 attributeCount += attrs.getCount();
912 size += attrs.getSize(this, null, 0, -1, -1);
913 }
914 size += pool.length;
915 // allocates a byte vector of this size, in order to avoid unnecessary
916 // arraycopy operations in the ByteVector.enlarge() method
917 ByteVector out = new ByteVector(size);
918 out.putInt(0xCAFEBABE).putInt(version);
919 out.putShort(index).putByteArray(pool.data, 0, pool.length);
920 int mask = Opcodes.ACC_DEPRECATED | ACC_SYNTHETIC_ATTRIBUTE
921 | ((access & ACC_SYNTHETIC_ATTRIBUTE) / TO_ACC_SYNTHETIC);
922 out.putShort(access & ~mask).putShort(name).putShort(superName);
923 out.putShort(interfaceCount);
924 for (int i = 0; i < interfaceCount; ++i) {
925 out.putShort(interfaces[i]);
926 }
927 out.putShort(nbFields);
928 fb = firstField;
929 while (fb != null) {
930 fb.put(out);
931 fb = (FieldWriter) fb.fv;
932 }
933 out.putShort(nbMethods);
934 mb = firstMethod;
935 while (mb != null) {
936 mb.put(out);
937 mb = (MethodWriter) mb.mv;
938 }
939 out.putShort(attributeCount);
940 if (bootstrapMethods != null) {
941 out.putShort(newUTF8("BootstrapMethods"));
942 out.putInt(bootstrapMethods.length + 2).putShort(
943 bootstrapMethodsCount);
944 out.putByteArray(bootstrapMethods.data, 0, bootstrapMethods.length);
945 }
946 if (ClassReader.SIGNATURES && signature != 0) {
947 out.putShort(newUTF8("Signature")).putInt(2).putShort(signature);
948 }
949 if (sourceFile != 0) {
950 out.putShort(newUTF8("SourceFile")).putInt(2).putShort(sourceFile);
951 }
952 if (sourceDebug != null) {
953 int len = sourceDebug.length;
954 out.putShort(newUTF8("SourceDebugExtension")).putInt(len);
955 out.putByteArray(sourceDebug.data, 0, len);
956 }
957 if (moduleWriter != null) {
958 out.putShort(newUTF8("Module"));
959 moduleWriter.put(out);
960 }
961 if (enclosingMethodOwner != 0) {
962 out.putShort(newUTF8("EnclosingMethod")).putInt(4);
963 out.putShort(enclosingMethodOwner).putShort(enclosingMethod);
964 }
965 if ((access & Opcodes.ACC_DEPRECATED) != 0) {
966 out.putShort(newUTF8("Deprecated")).putInt(0);
967 }
968 if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
969 if ((version & 0xFFFF) < Opcodes.V1_5
970 || (access & ACC_SYNTHETIC_ATTRIBUTE) != 0) {
971 out.putShort(newUTF8("Synthetic")).putInt(0);
972 }
973 }
974 if (innerClasses != null) {
975 out.putShort(newUTF8("InnerClasses"));
976 out.putInt(innerClasses.length + 2).putShort(innerClassesCount);
977 out.putByteArray(innerClasses.data, 0, innerClasses.length);
978 }
979 if (ClassReader.ANNOTATIONS && anns != null) {
980 out.putShort(newUTF8("RuntimeVisibleAnnotations"));
981 anns.put(out);
982 }
983 if (ClassReader.ANNOTATIONS && ianns != null) {
984 out.putShort(newUTF8("RuntimeInvisibleAnnotations"));
985 ianns.put(out);
986 }
987 if (ClassReader.ANNOTATIONS && tanns != null) {
988 out.putShort(newUTF8("RuntimeVisibleTypeAnnotations"));
989 tanns.put(out);
990 }
991 if (ClassReader.ANNOTATIONS && itanns != null) {
992 out.putShort(newUTF8("RuntimeInvisibleTypeAnnotations"));
993 itanns.put(out);
994 }
995 if (attrs != null) {
996 attrs.put(this, null, 0, -1, -1, out);
997 }
998 if (invalidFrames) {
999 anns = null;
1000 ianns = null;
1001 attrs = null;
1002 moduleWriter = null;
1003 innerClassesCount = 0;
1004 innerClasses = null;
1005 bootstrapMethodsCount = 0;
1006 bootstrapMethods = null;
1007 firstField = null;
1008 lastField = null;
1009 firstMethod = null;
1010 lastMethod = null;
1011 computeMaxs = false;
1012 computeFrames = true;
1013 invalidFrames = false;
1014 new ClassReader(out.data).accept(this, ClassReader.SKIP_FRAMES);
1015 return toByteArray();
1016 }
1017 return out.data;
1018 }
1019
1020 // ------------------------------------------------------------------------
1021 // Utility methods: constant pool management
1022 // ------------------------------------------------------------------------
1023
1024 /**
1025 * Adds a number or string constant to the constant pool of the class being
1026 * build. Does nothing if the constant pool already contains a similar item.
1027 *
1028 * @param cst
1029 * the value of the constant to be added to the constant pool.
1030 * This parameter must be an {@link Integer}, a {@link Float}, a
1031 * {@link Long}, a {@link Double}, a {@link String} or a
1032 * {@link Type}.
1033 * @return a new or already existing constant item with the given value.
1034 */
1035 Item newConstItem(final Object cst) {
1036 if (cst instanceof Integer) {
1037 int val = ((Integer) cst).intValue();
1038 return newInteger(val);
1039 } else if (cst instanceof Byte) {
1040 int val = ((Byte) cst).intValue();
1041 return newInteger(val);
1042 } else if (cst instanceof Character) {
1043 int val = ((Character) cst).charValue();
1044 return newInteger(val);
1045 } else if (cst instanceof Short) {
1046 int val = ((Short) cst).intValue();
1047 return newInteger(val);
1048 } else if (cst instanceof Boolean) {
1049 int val = ((Boolean) cst).booleanValue() ? 1 : 0;
1050 return newInteger(val);
1051 } else if (cst instanceof Float) {
1052 float val = ((Float) cst).floatValue();
1053 return newFloat(val);
1054 } else if (cst instanceof Long) {
1055 long val = ((Long) cst).longValue();
1056 return newLong(val);
1057 } else if (cst instanceof Double) {
1058 double val = ((Double) cst).doubleValue();
1059 return newDouble(val);
1060 } else if (cst instanceof String) {
1061 return newString((String) cst);
1062 } else if (cst instanceof Type) {
1063 Type t = (Type) cst;
1064 int s = t.getSort();
1065 if (s == Type.OBJECT) {
1066 return newClassItem(t.getInternalName());
1067 } else if (s == Type.METHOD) {
1068 return newMethodTypeItem(t.getDescriptor());
1069 } else { // s == primitive type or array
1070 return newClassItem(t.getDescriptor());
1071 }
1072 } else if (cst instanceof Handle) {
1073 Handle h = (Handle) cst;
1074 return newHandleItem(h.tag, h.owner, h.name, h.desc, h.itf);
1075 } else {
1076 throw new IllegalArgumentException("value " + cst);
1077 }
1078 }
1079
1080 /**
1081 * Adds a number or string constant to the constant pool of the class being
1082 * build. Does nothing if the constant pool already contains a similar item.
1083 * <i>This method is intended for {@link Attribute} sub classes, and is
1084 * normally not needed by class generators or adapters.</i>
1085 *
1086 * @param cst
1087 * the value of the constant to be added to the constant pool.
1088 * This parameter must be an {@link Integer}, a {@link Float}, a
1089 * {@link Long}, a {@link Double} or a {@link String}.
1090 * @return the index of a new or already existing constant item with the
1091 * given value.
1092 */
1093 public int newConst(final Object cst) {
1094 return newConstItem(cst).index;
1095 }
1096
1097 /**
1098 * Adds an UTF8 string to the constant pool of the class being build. Does
1099 * nothing if the constant pool already contains a similar item. <i>This
1100 * method is intended for {@link Attribute} sub classes, and is normally not
1101 * needed by class generators or adapters.</i>
1102 *
1103 * @param value
1104 * the String value.
1105 * @return the index of a new or already existing UTF8 item.
1106 */
1107 public int newUTF8(final String value) {
1108 key.set(UTF8, value, null, null);
1109 Item result = get(key);
1110 if (result == null) {
1111 pool.putByte(UTF8).putUTF8(value);
1112 result = new Item(index++, key);
1113 put(result);
1114 }
1115 return result.index;
1116 }
1117
1118 /**
1119 * Adds a class reference to the constant pool of the class being build.
1120 * Does nothing if the constant pool already contains a similar item.
1121 * <i>This method is intended for {@link Attribute} sub classes, and is
1122 * normally not needed by class generators or adapters.</i>
1123 *
1124 * @param value
1125 * the internal name of the class.
1126 * @return a new or already existing class reference item.
1127 */
1128 Item newClassItem(final String value) {
1129 key2.set(CLASS, value, null, null);
1130 Item result = get(key2);
1131 if (result == null) {
1132 pool.put12(CLASS, newUTF8(value));
1133 result = new Item(index++, key2);
1134 put(result);
1135 }
1136 return result;
1137 }
1138
1139 /**
1140 * Adds a class reference to the constant pool of the class being build.
1141 * Does nothing if the constant pool already contains a similar item.
1142 * <i>This method is intended for {@link Attribute} sub classes, and is
1143 * normally not needed by class generators or adapters.</i>
1144 *
1145 * @param value
1146 * the internal name of the class.
1147 * @return the index of a new or already existing class reference item.
1148 */
1149 public int newClass(final String value) {
1150 return newClassItem(value).index;
1151 }
1152
1153 /**
1154 * Adds a method type reference to the constant pool of the class being
1155 * build. Does nothing if the constant pool already contains a similar item.
1156 * <i>This method is intended for {@link Attribute} sub classes, and is
1157 * normally not needed by class generators or adapters.</i>
1158 *
1159 * @param methodDesc
1160 * method descriptor of the method type.
1161 * @return a new or already existing method type reference item.
1162 */
1163 Item newMethodTypeItem(final String methodDesc) {
1164 key2.set(MTYPE, methodDesc, null, null);
1165 Item result = get(key2);
1166 if (result == null) {
1167 pool.put12(MTYPE, newUTF8(methodDesc));
1168 result = new Item(index++, key2);
1169 put(result);
1170 }
1171 return result;
1172 }
1173
1174 /**
1175 * Adds a method type reference to the constant pool of the class being
1176 * build. Does nothing if the constant pool already contains a similar item.
1177 * <i>This method is intended for {@link Attribute} sub classes, and is
1178 * normally not needed by class generators or adapters.</i>
1179 *
1180 * @param methodDesc
1181 * method descriptor of the method type.
1182 * @return the index of a new or already existing method type reference
1183 * item.
1184 */
1185 public int newMethodType(final String methodDesc) {
1186 return newMethodTypeItem(methodDesc).index;
1187 }
1188
1189 /**
1190 * Adds a handle to the constant pool of the class being build. Does nothing
1191 * if the constant pool already contains a similar item. <i>This method is
1192 * intended for {@link Attribute} sub classes, and is normally not needed by
1193 * class generators or adapters.</i>
1194 *
1195 * @param tag
1196 * the kind of this handle. Must be {@link Opcodes#H_GETFIELD},
1197 * {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD},
1198 * {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL},
1199 * {@link Opcodes#H_INVOKESTATIC},
1200 * {@link Opcodes#H_INVOKESPECIAL},
1201 * {@link Opcodes#H_NEWINVOKESPECIAL} or
1202 * {@link Opcodes#H_INVOKEINTERFACE}.
1203 * @param owner
1204 * the internal name of the field or method owner class.
1205 * @param name
1206 * the name of the field or method.
1207 * @param desc
1208 * the descriptor of the field or method.
1209 * @param itf
1210 * true if the owner is an interface.
1211 * @return a new or an already existing method type reference item.
1212 */
1213 Item newHandleItem(final int tag, final String owner, final String name,
1214 final String desc, final boolean itf) {
1215 key4.set(HANDLE_BASE + tag, owner, name, desc);
1216 Item result = get(key4);
1217 if (result == null) {
1218 if (tag <= Opcodes.H_PUTSTATIC) {
1219 put112(HANDLE, tag, newField(owner, name, desc));
1220 } else {
1221 put112(HANDLE,
1222 tag,
1223 newMethod(owner, name, desc, itf));
1224 }
1225 result = new Item(index++, key4);
1226 put(result);
1227 }
1228 return result;
1229 }
1230
1231 /**
1232 * Adds a handle to the constant pool of the class being build. Does nothing
1233 * if the constant pool already contains a similar item. <i>This method is
1234 * intended for {@link Attribute} sub classes, and is normally not needed by
1235 * class generators or adapters.</i>
1236 *
1237 * @param tag
1238 * the kind of this handle. Must be {@link Opcodes#H_GETFIELD},
1239 * {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD},
1240 * {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL},
1241 * {@link Opcodes#H_INVOKESTATIC},
1242 * {@link Opcodes#H_INVOKESPECIAL},
1243 * {@link Opcodes#H_NEWINVOKESPECIAL} or
1244 * {@link Opcodes#H_INVOKEINTERFACE}.
1245 * @param owner
1246 * the internal name of the field or method owner class.
1247 * @param name
1248 * the name of the field or method.
1249 * @param desc
1250 * the descriptor of the field or method.
1251 * @return the index of a new or already existing method type reference
1252 * item.
1253 *
1254 * @deprecated this method is superseded by
1255 * {@link #newHandle(int, String, String, String, boolean)}.
1256 */
1257 @Deprecated
1258 public int newHandle(final int tag, final String owner, final String name,
1259 final String desc) {
1260 return newHandle(tag, owner, name, desc, tag == Opcodes.H_INVOKEINTERFACE);
1261 }
1262
1263 /**
1264 * Adds a handle to the constant pool of the class being build. Does nothing
1265 * if the constant pool already contains a similar item. <i>This method is
1266 * intended for {@link Attribute} sub classes, and is normally not needed by
1267 * class generators or adapters.</i>
1268 *
1269 * @param tag
1270 * the kind of this handle. Must be {@link Opcodes#H_GETFIELD},
1271 * {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD},
1272 * {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL},
1273 * {@link Opcodes#H_INVOKESTATIC},
1274 * {@link Opcodes#H_INVOKESPECIAL},
1275 * {@link Opcodes#H_NEWINVOKESPECIAL} or
1276 * {@link Opcodes#H_INVOKEINTERFACE}.
1277 * @param owner
1278 * the internal name of the field or method owner class.
1279 * @param name
1280 * the name of the field or method.
1281 * @param desc
1282 * the descriptor of the field or method.
1283 * @param itf
1284 * true if the owner is an interface.
1285 * @return the index of a new or already existing method type reference
1286 * item.
1287 */
1288 public int newHandle(final int tag, final String owner, final String name,
1289 final String desc, final boolean itf) {
1290 return newHandleItem(tag, owner, name, desc, itf).index;
1291 }
1292
1293 /**
1294 * Adds an invokedynamic reference to the constant pool of the class being
1295 * build. Does nothing if the constant pool already contains a similar item.
1296 * <i>This method is intended for {@link Attribute} sub classes, and is
1297 * normally not needed by class generators or adapters.</i>
1298 *
1299 * @param name
1300 * name of the invoked method.
1301 * @param desc
1302 * descriptor of the invoke method.
1303 * @param bsm
1304 * the bootstrap method.
1305 * @param bsmArgs
1306 * the bootstrap method constant arguments.
1307 *
1308 * @return a new or an already existing invokedynamic type reference item.
1309 */
1310 Item newInvokeDynamicItem(final String name, final String desc,
1311 final Handle bsm, final Object... bsmArgs) {
1312 // cache for performance
1313 ByteVector bootstrapMethods = this.bootstrapMethods;
1314 if (bootstrapMethods == null) {
1315 bootstrapMethods = this.bootstrapMethods = new ByteVector();
1316 }
1317
1318 int position = bootstrapMethods.length; // record current position
1319
1320 int hashCode = bsm.hashCode();
1321 bootstrapMethods.putShort(newHandle(bsm.tag, bsm.owner, bsm.name,
1322 bsm.desc, bsm.isInterface()));
1323
1324 int argsLength = bsmArgs.length;
1325 bootstrapMethods.putShort(argsLength);
1326
1327 for (int i = 0; i < argsLength; i++) {
1328 Object bsmArg = bsmArgs[i];
1329 hashCode ^= bsmArg.hashCode();
1330 bootstrapMethods.putShort(newConst(bsmArg));
1331 }
1332
1333 byte[] data = bootstrapMethods.data;
1334 int length = (1 + 1 + argsLength) << 1; // (bsm + argCount + arguments)
1335 hashCode &= 0x7FFFFFFF;
1336 Item result = items[hashCode % items.length];
1337 loop: while (result != null) {
1338 if (result.type != BSM || result.hashCode != hashCode) {
1339 result = result.next;
1340 continue;
1341 }
1342
1343 // because the data encode the size of the argument
1344 // we don't need to test if these size are equals
1345 int resultPosition = result.intVal;
1346 for (int p = 0; p < length; p++) {
1347 if (data[position + p] != data[resultPosition + p]) {
1348 result = result.next;
1349 continue loop;
1350 }
1351 }
1352 break;
1353 }
1354
1355 int bootstrapMethodIndex;
1356 if (result != null) {
1357 bootstrapMethodIndex = result.index;
1358 bootstrapMethods.length = position; // revert to old position
1359 } else {
1360 bootstrapMethodIndex = bootstrapMethodsCount++;
1361 result = new Item(bootstrapMethodIndex);
1362 result.set(position, hashCode);
1363 put(result);
1364 }
1365
1366 // now, create the InvokeDynamic constant
1367 key3.set(name, desc, bootstrapMethodIndex);
1368 result = get(key3);
1369 if (result == null) {
1370 put122(INDY, bootstrapMethodIndex, newNameType(name, desc));
1371 result = new Item(index++, key3);
1372 put(result);
1373 }
1374 return result;
1375 }
1376
1377 /**
1378 * Adds an invokedynamic reference to the constant pool of the class being
1379 * build. Does nothing if the constant pool already contains a similar item.
1380 * <i>This method is intended for {@link Attribute} sub classes, and is
1381 * normally not needed by class generators or adapters.</i>
1382 *
1383 * @param name
1384 * name of the invoked method.
1385 * @param desc
1386 * descriptor of the invoke method.
1387 * @param bsm
1388 * the bootstrap method.
1389 * @param bsmArgs
1390 * the bootstrap method constant arguments.
1391 *
1392 * @return the index of a new or already existing invokedynamic reference
1393 * item.
1394 */
1395 public int newInvokeDynamic(final String name, final String desc,
1396 final Handle bsm, final Object... bsmArgs) {
1397 return newInvokeDynamicItem(name, desc, bsm, bsmArgs).index;
1398 }
1399
1400 /**
1401 * Adds a field reference to the constant pool of the class being build.
1402 * Does nothing if the constant pool already contains a similar item.
1403 *
1404 * @param owner
1405 * the internal name of the field's owner class.
1406 * @param name
1407 * the field's name.
1408 * @param desc
1409 * the field's descriptor.
1410 * @return a new or already existing field reference item.
1411 */
1412 Item newFieldItem(final String owner, final String name, final String desc) {
1413 key3.set(FIELD, owner, name, desc);
1414 Item result = get(key3);
1415 if (result == null) {
1416 put122(FIELD, newClass(owner), newNameType(name, desc));
1417 result = new Item(index++, key3);
1418 put(result);
1419 }
1420 return result;
1421 }
1422
1423 /**
1424 * Adds a field reference to the constant pool of the class being build.
1425 * Does nothing if the constant pool already contains a similar item.
1426 * <i>This method is intended for {@link Attribute} sub classes, and is
1427 * normally not needed by class generators or adapters.</i>
1428 *
1429 * @param owner
1430 * the internal name of the field's owner class.
1431 * @param name
1432 * the field's name.
1433 * @param desc
1434 * the field's descriptor.
1435 * @return the index of a new or already existing field reference item.
1436 */
1437 public int newField(final String owner, final String name, final String desc) {
1438 return newFieldItem(owner, name, desc).index;
1439 }
1440
1441 /**
1442 * Adds a method reference to the constant pool of the class being build.
1443 * Does nothing if the constant pool already contains a similar item.
1444 *
1445 * @param owner
1446 * the internal name of the method's owner class.
1447 * @param name
1448 * the method's name.
1449 * @param desc
1450 * the method's descriptor.
1451 * @param itf
1452 * <tt>true</tt> if <tt>owner</tt> is an interface.
1453 * @return a new or already existing method reference item.
1454 */
1455 Item newMethodItem(final String owner, final String name,
1456 final String desc, final boolean itf) {
1457 int type = itf ? IMETH : METH;
1458 key3.set(type, owner, name, desc);
1459 Item result = get(key3);
1460 if (result == null) {
1461 put122(type, newClass(owner), newNameType(name, desc));
1462 result = new Item(index++, key3);
1463 put(result);
1464 }
1465 return result;
1466 }
1467
1468 /**
1469 * Adds a method reference to the constant pool of the class being build.
1470 * Does nothing if the constant pool already contains a similar item.
1471 * <i>This method is intended for {@link Attribute} sub classes, and is
1472 * normally not needed by class generators or adapters.</i>
1473 *
1474 * @param owner
1475 * the internal name of the method's owner class.
1476 * @param name
1477 * the method's name.
1478 * @param desc
1479 * the method's descriptor.
1480 * @param itf
1481 * <tt>true</tt> if <tt>owner</tt> is an interface.
1482 * @return the index of a new or already existing method reference item.
1483 */
1484 public int newMethod(final String owner, final String name,
1485 final String desc, final boolean itf) {
1486 return newMethodItem(owner, name, desc, itf).index;
1487 }
1488
1489 /**
1490 * Adds an integer to the constant pool of the class being build. Does
1491 * nothing if the constant pool already contains a similar item.
1492 *
1493 * @param value
1494 * the int value.
1495 * @return a new or already existing int item.
1496 */
1497 Item newInteger(final int value) {
1498 key.set(value);
1499 Item result = get(key);
1500 if (result == null) {
1501 pool.putByte(INT).putInt(value);
1502 result = new Item(index++, key);
1503 put(result);
1504 }
1505 return result;
1506 }
1507
1508 /**
1509 * Adds a float to the constant pool of the class being build. Does nothing
1510 * if the constant pool already contains a similar item.
1511 *
1512 * @param value
1513 * the float value.
1514 * @return a new or already existing float item.
1515 */
1516 Item newFloat(final float value) {
1517 key.set(value);
1518 Item result = get(key);
1519 if (result == null) {
1520 pool.putByte(FLOAT).putInt(key.intVal);
1521 result = new Item(index++, key);
1522 put(result);
1523 }
1524 return result;
1525 }
1526
1527 /**
1528 * Adds a long to the constant pool of the class being build. Does nothing
1529 * if the constant pool already contains a similar item.
1530 *
1531 * @param value
1532 * the long value.
1533 * @return a new or already existing long item.
1534 */
1535 Item newLong(final long value) {
1536 key.set(value);
1537 Item result = get(key);
1538 if (result == null) {
1539 pool.putByte(LONG).putLong(value);
1540 result = new Item(index, key);
1541 index += 2;
1542 put(result);
1543 }
1544 return result;
1545 }
1546
1547 /**
1548 * Adds a double to the constant pool of the class being build. Does nothing
1549 * if the constant pool already contains a similar item.
1550 *
1551 * @param value
1552 * the double value.
1553 * @return a new or already existing double item.
1554 */
1555 Item newDouble(final double value) {
1556 key.set(value);
1557 Item result = get(key);
1558 if (result == null) {
1559 pool.putByte(DOUBLE).putLong(key.longVal);
1560 result = new Item(index, key);
1561 index += 2;
1562 put(result);
1563 }
1564 return result;
1565 }
1566
1567 /**
1568 * Adds a string to the constant pool of the class being build. Does nothing
1569 * if the constant pool already contains a similar item.
1570 *
1571 * @param value
1572 * the String value.
1573 * @return a new or already existing string item.
1574 */
1575 private Item newString(final String value) {
1576 key2.set(STR, value, null, null);
1577 Item result = get(key2);
1578 if (result == null) {
1579 pool.put12(STR, newUTF8(value));
1580 result = new Item(index++, key2);
1581 put(result);
1582 }
1583 return result;
1584 }
1585
1586 /**
1587 * Adds a name and type to the constant pool of the class being build. Does
1588 * nothing if the constant pool already contains a similar item. <i>This
1589 * method is intended for {@link Attribute} sub classes, and is normally not
1590 * needed by class generators or adapters.</i>
1591 *
1592 * @param name
1593 * a name.
1594 * @param desc
1595 * a type descriptor.
1596 * @return the index of a new or already existing name and type item.
1597 */
1598 public int newNameType(final String name, final String desc) {
1599 return newNameTypeItem(name, desc).index;
1600 }
1601
1602 /**
1603 * Adds a name and type to the constant pool of the class being build. Does
1604 * nothing if the constant pool already contains a similar item.
1605 *
1606 * @param name
1607 * a name.
1608 * @param desc
1609 * a type descriptor.
1610 * @return a new or already existing name and type item.
1611 */
1612 Item newNameTypeItem(final String name, final String desc) {
1613 key2.set(NAME_TYPE, name, desc, null);
1614 Item result = get(key2);
1615 if (result == null) {
1616 put122(NAME_TYPE, newUTF8(name), newUTF8(desc));
1617 result = new Item(index++, key2);
1618 put(result);
1619 }
1620 return result;
1621 }
1622
1623 /**
1624 * Adds the given internal name to {@link #typeTable} and returns its index.
1625 * Does nothing if the type table already contains this internal name.
1626 *
1627 * @param type
1628 * the internal name to be added to the type table.
1629 * @return the index of this internal name in the type table.
1630 */
1631 int addType(final String type) {
1632 key.set(TYPE_NORMAL, type, null, null);
1633 Item result = get(key);
1634 if (result == null) {
1635 result = addType(key);
1636 }
1637 return result.index;
1638 }
1639
1640 /**
1641 * Adds the given "uninitialized" type to {@link #typeTable} and returns its
1642 * index. This method is used for UNINITIALIZED types, made of an internal
1643 * name and a bytecode offset.
1644 *
1645 * @param type
1646 * the internal name to be added to the type table.
1647 * @param offset
1648 * the bytecode offset of the NEW instruction that created this
1649 * UNINITIALIZED type value.
1650 * @return the index of this internal name in the type table.
1651 */
1652 int addUninitializedType(final String type, final int offset) {
1653 key.type = TYPE_UNINIT;
1654 key.intVal = offset;
1655 key.strVal1 = type;
1656 key.hashCode = 0x7FFFFFFF & (TYPE_UNINIT + type.hashCode() + offset);
1657 Item result = get(key);
1658 if (result == null) {
1659 result = addType(key);
1660 }
1661 return result.index;
1662 }
1663
1664 /**
1665 * Adds the given Item to {@link #typeTable}.
1666 *
1667 * @param item
1668 * the value to be added to the type table.
1669 * @return the added Item, which a new Item instance with the same value as
1670 * the given Item.
1671 */
1672 private Item addType(final Item item) {
1673 ++typeCount;
1674 Item result = new Item(typeCount, key);
1675 put(result);
1676 if (typeTable == null) {
1677 typeTable = new Item[16];
1678 }
1679 if (typeCount == typeTable.length) {
1680 Item[] newTable = new Item[2 * typeTable.length];
1681 System.arraycopy(typeTable, 0, newTable, 0, typeTable.length);
1682 typeTable = newTable;
1683 }
1684 typeTable[typeCount] = result;
1685 return result;
1686 }
1687
1688 /**
1689 * Returns the index of the common super type of the two given types. This
1690 * method calls {@link #getCommonSuperClass} and caches the result in the
1691 * {@link #items} hash table to speedup future calls with the same
1692 * parameters.
1693 *
1694 * @param type1
1695 * index of an internal name in {@link #typeTable}.
1696 * @param type2
1697 * index of an internal name in {@link #typeTable}.
1698 * @return the index of the common super type of the two given types.
1699 */
1700 int getMergedType(final int type1, final int type2) {
1701 key2.type = TYPE_MERGED;
1702 key2.longVal = type1 | (((long) type2) << 32);
1703 key2.hashCode = 0x7FFFFFFF & (TYPE_MERGED + type1 + type2);
1704 Item result = get(key2);
1705 if (result == null) {
1706 String t = typeTable[type1].strVal1;
1707 String u = typeTable[type2].strVal1;
1708 key2.intVal = addType(getCommonSuperClass(t, u));
1709 result = new Item((short) 0, key2);
1710 put(result);
1711 }
1712 return result.intVal;
1713 }
1714
1715 /**
1716 * Returns the common super type of the two given types. The default
1717 * implementation of this method <i>loads</i> the two given classes and uses
1718 * the java.lang.Class methods to find the common super class. It can be
1719 * overridden to compute this common super type in other ways, in particular
1720 * without actually loading any class, or to take into account the class
1721 * that is currently being generated by this ClassWriter, which can of
1722 * course not be loaded since it is under construction.
1723 *
1724 * @param type1
1725 * the internal name of a class.
1726 * @param type2
1727 * the internal name of another class.
1728 * @return the internal name of the common super class of the two given
1729 * classes.
1730 */
1731 protected String getCommonSuperClass(final String type1, final String type2) {
1732 Class<?> c, d;
1733 ClassLoader classLoader = getClass().getClassLoader();
1734 try {
1735 c = Class.forName(type1.replace('/', '.'), false, classLoader);
1736 d = Class.forName(type2.replace('/', '.'), false, classLoader);
1737 } catch (Exception e) {
1738 throw new RuntimeException(e.toString());
1739 }
1740 if (c.isAssignableFrom(d)) {
1741 return type1;
1742 }
1743 if (d.isAssignableFrom(c)) {
1744 return type2;
1745 }
1746 if (c.isInterface() || d.isInterface()) {
1747 return "java/lang/Object";
1748 } else {
1749 do {
1750 c = c.getSuperclass();
1751 } while (!c.isAssignableFrom(d));
1752 return c.getName().replace('.', '/');
1753 }
1754 }
1755
1756 /**
1757 * Returns the constant pool's hash table item which is equal to the given
1758 * item.
1759 *
1760 * @param key
1761 * a constant pool item.
1762 * @return the constant pool's hash table item which is equal to the given
1763 * item, or <tt>null</tt> if there is no such item.
1764 */
1765 private Item get(final Item key) {
1766 Item i = items[key.hashCode % items.length];
1767 while (i != null && (i.type != key.type || !key.isEqualTo(i))) {
1768 i = i.next;
1769 }
1770 return i;
1771 }
1772
1773 /**
1774 * Puts the given item in the constant pool's hash table. The hash table
1775 * <i>must</i> not already contains this item.
1776 *
1777 * @param i
1778 * the item to be added to the constant pool's hash table.
1779 */
1780 private void put(final Item i) {
1781 if (index + typeCount > threshold) {
1782 int ll = items.length;
1783 int nl = ll * 2 + 1;
1784 Item[] newItems = new Item[nl];
1785 for (int l = ll - 1; l >= 0; --l) {
1786 Item j = items[l];
1787 while (j != null) {
1788 int index = j.hashCode % newItems.length;
1789 Item k = j.next;
1790 j.next = newItems[index];
1791 newItems[index] = j;
1792 j = k;
1793 }
1794 }
1795 items = newItems;
1796 threshold = (int) (nl * 0.75);
1797 }
1798 int index = i.hashCode % items.length;
1799 i.next = items[index];
1800 items[index] = i;
1801 }
1802
1803 /**
1804 * Puts one byte and two shorts into the constant pool.
1805 *
1806 * @param b
1807 * a byte.
1808 * @param s1
1809 * a short.
1810 * @param s2
1811 * another short.
1812 */
1813 private void put122(final int b, final int s1, final int s2) {
1814 pool.put12(b, s1).putShort(s2);
1815 }
1816
1817 /**
1818 * Puts two bytes and one short into the constant pool.
1819 *
1820 * @param b1
1821 * a byte.
1822 * @param b2
1823 * another byte.
1824 * @param s
1825 * a short.
1826 */
1827 private void put112(final int b1, final int b2, final int s) {
1828 pool.put11(b1, b2).putShort(s);
1829 }
40 /**
41 * A flag to automatically compute the maximum stack size and the maximum number of local
42 * variables of methods. If this flag is set, then the arguments of the {@link
43 * MethodVisitor#visitMaxs} method of the {@link MethodVisitor} returned by the {@link
44 * #visitMethod} method will be ignored, and computed automatically from the signature and the
45 * bytecode of each method.
46 *
47 * <p><b>Note:</b> for classes whose version is {@link Opcodes#V1_7} of more, this option requires
48 * valid stack map frames. The maximum stack size is then computed from these frames, and from the
49 * bytecode instructions in between. If stack map frames are not present or must be recomputed,
50 * used {@link #COMPUTE_FRAMES} instead.
51 *
52 * @see #ClassWriter(int)
53 */
54 public static final int COMPUTE_MAXS = 1;
55
56 /**
57 * A flag to automatically compute the stack map frames of methods from scratch. If this flag is
58 * set, then the calls to the {@link MethodVisitor#visitFrame} method are ignored, and the stack
59 * map frames are recomputed from the methods bytecode. The arguments of the {@link
60 * MethodVisitor#visitMaxs} method are also ignored and recomputed from the bytecode. In other
61 * words, {@link #COMPUTE_FRAMES} implies {@link #COMPUTE_MAXS}.
62 *
63 * @see #ClassWriter(int)
64 */
65 public static final int COMPUTE_FRAMES = 2;
66
67 // Note: fields are ordered as in the ClassFile structure, and those related to attributes are
68 // ordered as in Section 4.7 of the JVMS.
69
70 /**
71 * The minor_version and major_version fields of the JVMS ClassFile structure. minor_version is
72 * stored in the 16 most significant bits, and major_version in the 16 least significant bits.
73 */
74 private int version;
75
76 /** The symbol table for this class (contains the constant_pool and the BootstrapMethods). */
77 private final SymbolTable symbolTable;
78
79 /**
80 * The access_flags field of the JVMS ClassFile structure. This field can contain ASM specific
81 * access flags, such as {@link Opcodes#ACC_DEPRECATED}, which are removed when generating the
82 * ClassFile structure.
83 */
84 private int accessFlags;
85
86 /** The this_class field of the JVMS ClassFile structure. */
87 private int thisClass;
88
89 /** The super_class field of the JVMS ClassFile structure. */
90 private int superClass;
91
92 /** The interface_count field of the JVMS ClassFile structure. */
93 private int interfaceCount;
94
95 /** The 'interfaces' array of the JVMS ClassFile structure. */
96 private int[] interfaces;
97
98 /**
99 * The fields of this class, stored in a linked list of {@link FieldWriter} linked via their
100 * {@link FieldWriter#fv} field. This field stores the first element of this list.
101 */
102 private FieldWriter firstField;
103
104 /**
105 * The fields of this class, stored in a linked list of {@link FieldWriter} linked via their
106 * {@link FieldWriter#fv} field. This field stores the last element of this list.
107 */
108 private FieldWriter lastField;
109
110 /**
111 * The methods of this class, stored in a linked list of {@link MethodWriter} linked via their
112 * {@link MethodWriter#mv} field. This field stores the first element of this list.
113 */
114 private MethodWriter firstMethod;
115
116 /**
117 * The methods of this class, stored in a linked list of {@link MethodWriter} linked via their
118 * {@link MethodWriter#mv} field. This field stores the last element of this list.
119 */
120 private MethodWriter lastMethod;
121
122 /** The number_of_classes field of the InnerClasses attribute, or 0. */
123 private int numberOfInnerClasses;
124
125 /** The 'classes' array of the InnerClasses attribute, or <tt>null</tt>. */
126 private ByteVector innerClasses;
127
128 /** The class_index field of the EnclosingMethod attribute, or 0. */
129 private int enclosingClassIndex;
130
131 /** The method_index field of the EnclosingMethod attribute. */
132 private int enclosingMethodIndex;
133
134 /** The signature_index field of the Signature attribute, or 0. */
135 private int signatureIndex;
136
137 /** The source_file_index field of the SourceFile attribute, or 0. */
138 private int sourceFileIndex;
139
140 /** The debug_extension field of the SourceDebugExtension attribute, or <tt>null</tt>. */
141 private ByteVector debugExtension;
142
143 /**
144 * The last runtime visible annotation of this class. The previous ones can be accessed with the
145 * {@link AnnotationWriter#previousAnnotation} field. May be <tt>null</tt>.
146 */
147 private AnnotationWriter lastRuntimeVisibleAnnotation;
148
149 /**
150 * The last runtime invisible annotation of this class. The previous ones can be accessed with the
151 * {@link AnnotationWriter#previousAnnotation} field. May be <tt>null</tt>.
152 */
153 private AnnotationWriter lastRuntimeInvisibleAnnotation;
154
155 /**
156 * The last runtime visible type annotation of this class. The previous ones can be accessed with
157 * the {@link AnnotationWriter#previousAnnotation} field. May be <tt>null</tt>.
158 */
159 private AnnotationWriter lastRuntimeVisibleTypeAnnotation;
160
161 /**
162 * The last runtime invisible type annotation of this class. The previous ones can be accessed
163 * with the {@link AnnotationWriter#previousAnnotation} field. May be <tt>null</tt>.
164 */
165 private AnnotationWriter lastRuntimeInvisibleTypeAnnotation;
166
167 /** The Module attribute of this class, or <tt>null</tt>. */
168 private ModuleWriter moduleWriter;
169
170 /** The host_class_index field of the NestHost attribute, or 0. */
171 private int nestHostClassIndex;
172
173 /** The number_of_classes field of the NestMembers attribute, or 0. */
174 private int numberOfNestMemberClasses;
175
176 /** The 'classes' array of the NestMembers attribute, or <tt>null</tt>. */
177 private ByteVector nestMemberClasses;
178
179 /**
180 * The first non standard attribute of this class. The next ones can be accessed with the {@link
181 * Attribute#nextAttribute} field. May be <tt>null</tt>.
182 *
183 * <p><b>WARNING</b>: this list stores the attributes in the <i>reverse</i> order of their visit.
184 * firstAttribute is actually the last attribute visited in {@link #visitAttribute}. The {@link
185 * #toByteArray} method writes the attributes in the order defined by this list, i.e. in the
186 * reverse order specified by the user.
187 */
188 private Attribute firstAttribute;
189
190 /**
191 * Indicates what must be automatically computed in {@link MethodWriter}. Must be one of {@link
192 * MethodWriter#COMPUTE_NOTHING}, {@link MethodWriter#COMPUTE_MAX_STACK_AND_LOCAL}, {@link
193 * MethodWriter#COMPUTE_INSERTED_FRAMES}, or {@link MethodWriter#COMPUTE_ALL_FRAMES}.
194 */
195 private int compute;
196
197 // -----------------------------------------------------------------------------------------------
198 // Constructor
199 // -----------------------------------------------------------------------------------------------
200
201 /**
202 * Constructs a new {@link ClassWriter} object.
203 *
204 * @param flags option flags that can be used to modify the default behavior of this class. Must
205 * be zero or more of {@link #COMPUTE_MAXS} and {@link #COMPUTE_FRAMES}.
206 */
207 public ClassWriter(final int flags) {
208 this(null, flags);
209 }
210
211 /**
212 * Constructs a new {@link ClassWriter} object and enables optimizations for "mostly add" bytecode
213 * transformations. These optimizations are the following:
214 *
215 * <ul>
216 * <li>The constant pool and bootstrap methods from the original class are copied as is in the
217 * new class, which saves time. New constant pool entries and new bootstrap methods will be
218 * added at the end if necessary, but unused constant pool entries or bootstrap methods
219 * <i>won't be removed</i>.
220 * <li>Methods that are not transformed are copied as is in the new class, directly from the
221 * original class bytecode (i.e. without emitting visit events for all the method
222 * instructions), which saves a <i>lot</i> of time. Untransformed methods are detected by
223 * the fact that the {@link ClassReader} receives {@link MethodVisitor} objects that come
224 * from a {@link ClassWriter} (and not from any other {@link ClassVisitor} instance).
225 * </ul>
226 *
227 * @param classReader the {@link ClassReader} used to read the original class. It will be used to
228 * copy the entire constant pool and bootstrap methods from the original class and also to
229 * copy other fragments of original bytecode where applicable.
230 * @param flags option flags that can be used to modify the default behavior of this class.Must be
231 * zero or more of {@link #COMPUTE_MAXS} and {@link #COMPUTE_FRAMES}. <i>These option flags do
232 * not affect methods that are copied as is in the new class. This means that neither the
233 * maximum stack size nor the stack frames will be computed for these methods</i>.
234 */
235 public ClassWriter(final ClassReader classReader, final int flags) {
236 super(Opcodes.ASM6);
237 symbolTable = classReader == null ? new SymbolTable(this) : new SymbolTable(this, classReader);
238 if ((flags & COMPUTE_FRAMES) != 0) {
239 this.compute = MethodWriter.COMPUTE_ALL_FRAMES;
240 } else if ((flags & COMPUTE_MAXS) != 0) {
241 this.compute = MethodWriter.COMPUTE_MAX_STACK_AND_LOCAL;
242 } else {
243 this.compute = MethodWriter.COMPUTE_NOTHING;
244 }
245 }
246
247 // -----------------------------------------------------------------------------------------------
248 // Implementation of the ClassVisitor abstract class
249 // -----------------------------------------------------------------------------------------------
250
251 @Override
252 public final void visit(
253 final int version,
254 final int access,
255 final String name,
256 final String signature,
257 final String superName,
258 final String[] interfaces) {
259 this.version = version;
260 this.accessFlags = access;
261 this.thisClass = symbolTable.setMajorVersionAndClassName(version & 0xFFFF, name);
262 if (signature != null) {
263 this.signatureIndex = symbolTable.addConstantUtf8(signature);
264 }
265 this.superClass = superName == null ? 0 : symbolTable.addConstantClass(superName).index;
266 if (interfaces != null && interfaces.length > 0) {
267 interfaceCount = interfaces.length;
268 this.interfaces = new int[interfaceCount];
269 for (int i = 0; i < interfaceCount; ++i) {
270 this.interfaces[i] = symbolTable.addConstantClass(interfaces[i]).index;
271 }
272 }
273 if (compute == MethodWriter.COMPUTE_MAX_STACK_AND_LOCAL && (version & 0xFFFF) >= Opcodes.V1_7) {
274 compute = MethodWriter.COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES;
275 }
276 }
277
278 @Override
279 public final void visitSource(final String file, final String debug) {
280 if (file != null) {
281 sourceFileIndex = symbolTable.addConstantUtf8(file);
282 }
283 if (debug != null) {
284 debugExtension = new ByteVector().encodeUTF8(debug, 0, Integer.MAX_VALUE);
285 }
286 }
287
288 @Override
289 public final ModuleVisitor visitModule(
290 final String name, final int access, final String version) {
291 return moduleWriter =
292 new ModuleWriter(
293 symbolTable,
294 symbolTable.addConstantModule(name).index,
295 access,
296 version == null ? 0 : symbolTable.addConstantUtf8(version));
297 }
298
299 @Override
300 public void visitNestHostExperimental(final String nestHost) {
301 nestHostClassIndex = symbolTable.addConstantClass(nestHost).index;
302 }
303
304 @Override
305 public final void visitOuterClass(
306 final String owner, final String name, final String descriptor) {
307 enclosingClassIndex = symbolTable.addConstantClass(owner).index;
308 if (name != null && descriptor != null) {
309 enclosingMethodIndex = symbolTable.addConstantNameAndType(name, descriptor);
310 }
311 }
312
313 @Override
314 public final AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
315 // Create a ByteVector to hold an 'annotation' JVMS structure.
316 // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.
317 ByteVector annotation = new ByteVector();
318 // Write type_index and reserve space for num_element_value_pairs.
319 annotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0);
320 if (visible) {
321 return lastRuntimeVisibleAnnotation =
322 new AnnotationWriter(symbolTable, annotation, lastRuntimeVisibleAnnotation);
323 } else {
324 return lastRuntimeInvisibleAnnotation =
325 new AnnotationWriter(symbolTable, annotation, lastRuntimeInvisibleAnnotation);
326 }
327 }
328
329 @Override
330 public final AnnotationVisitor visitTypeAnnotation(
331 final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
332 // Create a ByteVector to hold a 'type_annotation' JVMS structure.
333 // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20.
334 ByteVector typeAnnotation = new ByteVector();
335 // Write target_type, target_info, and target_path.
336 TypeReference.putTarget(typeRef, typeAnnotation);
337 TypePath.put(typePath, typeAnnotation);
338 // Write type_index and reserve space for num_element_value_pairs.
339 typeAnnotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0);
340 if (visible) {
341 return lastRuntimeVisibleTypeAnnotation =
342 new AnnotationWriter(symbolTable, typeAnnotation, lastRuntimeVisibleTypeAnnotation);
343 } else {
344 return lastRuntimeInvisibleTypeAnnotation =
345 new AnnotationWriter(symbolTable, typeAnnotation, lastRuntimeInvisibleTypeAnnotation);
346 }
347 }
348
349 @Override
350 public final void visitAttribute(final Attribute attribute) {
351 // Store the attributes in the <i>reverse</i> order of their visit by this method.
352 attribute.nextAttribute = firstAttribute;
353 firstAttribute = attribute;
354 }
355
356 @Override
357 public void visitNestMemberExperimental(final String nestMember) {
358 if (nestMemberClasses == null) {
359 nestMemberClasses = new ByteVector();
360 }
361 ++numberOfNestMemberClasses;
362 nestMemberClasses.putShort(symbolTable.addConstantClass(nestMember).index);
363 }
364
365 @Override
366 public final void visitInnerClass(
367 final String name, final String outerName, final String innerName, final int access) {
368 if (innerClasses == null) {
369 innerClasses = new ByteVector();
370 }
371 // Section 4.7.6 of the JVMS states "Every CONSTANT_Class_info entry in the constant_pool table
372 // which represents a class or interface C that is not a package member must have exactly one
373 // corresponding entry in the classes array". To avoid duplicates we keep track in the info
374 // field of the Symbol of each CONSTANT_Class_info entry C whether an inner class entry has
375 // already been added for C. If so, we store the index of this inner class entry (plus one) in
376 // the info field. This trick allows duplicate detection in O(1) time.
377 Symbol nameSymbol = symbolTable.addConstantClass(name);
378 if (nameSymbol.info == 0) {
379 ++numberOfInnerClasses;
380 innerClasses.putShort(nameSymbol.index);
381 innerClasses.putShort(outerName == null ? 0 : symbolTable.addConstantClass(outerName).index);
382 innerClasses.putShort(innerName == null ? 0 : symbolTable.addConstantUtf8(innerName));
383 innerClasses.putShort(access);
384 nameSymbol.info = numberOfInnerClasses;
385 } else {
386 // Compare the inner classes entry nameSymbol.info - 1 with the arguments of this method and
387 // throw an exception if there is a difference?
388 }
389 }
390
391 @Override
392 public final FieldVisitor visitField(
393 final int access,
394 final String name,
395 final String descriptor,
396 final String signature,
397 final Object value) {
398 FieldWriter fieldWriter =
399 new FieldWriter(symbolTable, access, name, descriptor, signature, value);
400 if (firstField == null) {
401 firstField = fieldWriter;
402 } else {
403 lastField.fv = fieldWriter;
404 }
405 return lastField = fieldWriter;
406 }
407
408 @Override
409 public final MethodVisitor visitMethod(
410 final int access,
411 final String name,
412 final String descriptor,
413 final String signature,
414 final String[] exceptions) {
415 MethodWriter methodWriter =
416 new MethodWriter(symbolTable, access, name, descriptor, signature, exceptions, compute);
417 if (firstMethod == null) {
418 firstMethod = methodWriter;
419 } else {
420 lastMethod.mv = methodWriter;
421 }
422 return lastMethod = methodWriter;
423 }
424
425 @Override
426 public final void visitEnd() {
427 // Nothing to do.
428 }
429
430 // -----------------------------------------------------------------------------------------------
431 // Other public methods
432 // -----------------------------------------------------------------------------------------------
433
434 /**
435 * Returns the content of the class file that was built by this ClassWriter.
436 *
437 * @return the binary content of the JVMS ClassFile structure that was built by this ClassWriter.
438 */
439 public byte[] toByteArray() {
440 // First step: compute the size in bytes of the ClassFile structure.
441 // The magic field uses 4 bytes, 10 mandatory fields (minor_version, major_version,
442 // constant_pool_count, access_flags, this_class, super_class, interfaces_count, fields_count,
443 // methods_count and attributes_count) use 2 bytes each, and each interface uses 2 bytes too.
444 int size = 24 + 2 * interfaceCount;
445 int fieldsCount = 0;
446 FieldWriter fieldWriter = firstField;
447 while (fieldWriter != null) {
448 ++fieldsCount;
449 size += fieldWriter.computeFieldInfoSize();
450 fieldWriter = (FieldWriter) fieldWriter.fv;
451 }
452 int methodsCount = 0;
453 MethodWriter methodWriter = firstMethod;
454 while (methodWriter != null) {
455 ++methodsCount;
456 size += methodWriter.computeMethodInfoSize();
457 methodWriter = (MethodWriter) methodWriter.mv;
458 }
459 // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS.
460 int attributesCount = 0;
461 if (innerClasses != null) {
462 ++attributesCount;
463 size += 8 + innerClasses.length;
464 symbolTable.addConstantUtf8(Constants.INNER_CLASSES);
465 }
466 if (enclosingClassIndex != 0) {
467 ++attributesCount;
468 size += 10;
469 symbolTable.addConstantUtf8(Constants.ENCLOSING_METHOD);
470 }
471 if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 && (version & 0xFFFF) < Opcodes.V1_5) {
472 ++attributesCount;
473 size += 6;
474 symbolTable.addConstantUtf8(Constants.SYNTHETIC);
475 }
476 if (signatureIndex != 0) {
477 ++attributesCount;
478 size += 8;
479 symbolTable.addConstantUtf8(Constants.SIGNATURE);
480 }
481 if (sourceFileIndex != 0) {
482 ++attributesCount;
483 size += 8;
484 symbolTable.addConstantUtf8(Constants.SOURCE_FILE);
485 }
486 if (debugExtension != null) {
487 ++attributesCount;
488 size += 6 + debugExtension.length;
489 symbolTable.addConstantUtf8(Constants.SOURCE_DEBUG_EXTENSION);
490 }
491 if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) {
492 ++attributesCount;
493 size += 6;
494 symbolTable.addConstantUtf8(Constants.DEPRECATED);
495 }
496 if (lastRuntimeVisibleAnnotation != null) {
497 ++attributesCount;
498 size +=
499 lastRuntimeVisibleAnnotation.computeAnnotationsSize(
500 Constants.RUNTIME_VISIBLE_ANNOTATIONS);
501 }
502 if (lastRuntimeInvisibleAnnotation != null) {
503 ++attributesCount;
504 size +=
505 lastRuntimeInvisibleAnnotation.computeAnnotationsSize(
506 Constants.RUNTIME_INVISIBLE_ANNOTATIONS);
507 }
508 if (lastRuntimeVisibleTypeAnnotation != null) {
509 ++attributesCount;
510 size +=
511 lastRuntimeVisibleTypeAnnotation.computeAnnotationsSize(
512 Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS);
513 }
514 if (lastRuntimeInvisibleTypeAnnotation != null) {
515 ++attributesCount;
516 size +=
517 lastRuntimeInvisibleTypeAnnotation.computeAnnotationsSize(
518 Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS);
519 }
520 if (symbolTable.computeBootstrapMethodsSize() > 0) {
521 ++attributesCount;
522 size += symbolTable.computeBootstrapMethodsSize();
523 }
524 if (moduleWriter != null) {
525 attributesCount += moduleWriter.getAttributeCount();
526 size += moduleWriter.computeAttributesSize();
527 }
528 if (nestHostClassIndex != 0) {
529 ++attributesCount;
530 size += 8;
531 symbolTable.addConstantUtf8(Constants.NEST_HOST);
532 }
533 if (nestMemberClasses != null) {
534 ++attributesCount;
535 size += 8 + nestMemberClasses.length;
536 symbolTable.addConstantUtf8(Constants.NEST_MEMBERS);
537 }
538 if (firstAttribute != null) {
539 attributesCount += firstAttribute.getAttributeCount();
540 size += firstAttribute.computeAttributesSize(symbolTable);
541 }
542 // IMPORTANT: this must be the last part of the ClassFile size computation, because the previous
543 // statements can add attribute names to the constant pool, thereby changing its size!
544 size += symbolTable.getConstantPoolLength();
545 if (symbolTable.getConstantPoolCount() > 0xFFFF) {
546 throw new IndexOutOfBoundsException("Class file too large!");
547 }
548
549 // Second step: allocate a ByteVector of the correct size (in order to avoid any array copy in
550 // dynamic resizes) and fill it with the ClassFile content.
551 ByteVector result = new ByteVector(size);
552 result.putInt(0xCAFEBABE).putInt(version);
553 symbolTable.putConstantPool(result);
554 int mask = (version & 0xFFFF) < Opcodes.V1_5 ? Opcodes.ACC_SYNTHETIC : 0;
555 result.putShort(accessFlags & ~mask).putShort(thisClass).putShort(superClass);
556 result.putShort(interfaceCount);
557 for (int i = 0; i < interfaceCount; ++i) {
558 result.putShort(interfaces[i]);
559 }
560 result.putShort(fieldsCount);
561 fieldWriter = firstField;
562 while (fieldWriter != null) {
563 fieldWriter.putFieldInfo(result);
564 fieldWriter = (FieldWriter) fieldWriter.fv;
565 }
566 result.putShort(methodsCount);
567 boolean hasFrames = false;
568 boolean hasAsmInstructions = false;
569 methodWriter = firstMethod;
570 while (methodWriter != null) {
571 hasFrames |= methodWriter.hasFrames();
572 hasAsmInstructions |= methodWriter.hasAsmInstructions();
573 methodWriter.putMethodInfo(result);
574 methodWriter = (MethodWriter) methodWriter.mv;
575 }
576 // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS.
577 result.putShort(attributesCount);
578 if (innerClasses != null) {
579 result
580 .putShort(symbolTable.addConstantUtf8(Constants.INNER_CLASSES))
581 .putInt(innerClasses.length + 2)
582 .putShort(numberOfInnerClasses)
583 .putByteArray(innerClasses.data, 0, innerClasses.length);
584 }
585 if (enclosingClassIndex != 0) {
586 result
587 .putShort(symbolTable.addConstantUtf8(Constants.ENCLOSING_METHOD))
588 .putInt(4)
589 .putShort(enclosingClassIndex)
590 .putShort(enclosingMethodIndex);
591 }
592 if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 && (version & 0xFFFF) < Opcodes.V1_5) {
593 result.putShort(symbolTable.addConstantUtf8(Constants.SYNTHETIC)).putInt(0);
594 }
595 if (signatureIndex != 0) {
596 result
597 .putShort(symbolTable.addConstantUtf8(Constants.SIGNATURE))
598 .putInt(2)
599 .putShort(signatureIndex);
600 }
601 if (sourceFileIndex != 0) {
602 result
603 .putShort(symbolTable.addConstantUtf8(Constants.SOURCE_FILE))
604 .putInt(2)
605 .putShort(sourceFileIndex);
606 }
607 if (debugExtension != null) {
608 int length = debugExtension.length;
609 result
610 .putShort(symbolTable.addConstantUtf8(Constants.SOURCE_DEBUG_EXTENSION))
611 .putInt(length)
612 .putByteArray(debugExtension.data, 0, length);
613 }
614 if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) {
615 result.putShort(symbolTable.addConstantUtf8(Constants.DEPRECATED)).putInt(0);
616 }
617 if (lastRuntimeVisibleAnnotation != null) {
618 lastRuntimeVisibleAnnotation.putAnnotations(
619 symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_ANNOTATIONS), result);
620 }
621 if (lastRuntimeInvisibleAnnotation != null) {
622 lastRuntimeInvisibleAnnotation.putAnnotations(
623 symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_ANNOTATIONS), result);
624 }
625 if (lastRuntimeVisibleTypeAnnotation != null) {
626 lastRuntimeVisibleTypeAnnotation.putAnnotations(
627 symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS), result);
628 }
629 if (lastRuntimeInvisibleTypeAnnotation != null) {
630 lastRuntimeInvisibleTypeAnnotation.putAnnotations(
631 symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS), result);
632 }
633 symbolTable.putBootstrapMethods(result);
634 if (moduleWriter != null) {
635 moduleWriter.putAttributes(result);
636 }
637 if (nestHostClassIndex != 0) {
638 result
639 .putShort(symbolTable.addConstantUtf8(Constants.NEST_HOST))
640 .putInt(2)
641 .putShort(nestHostClassIndex);
642 }
643 if (nestMemberClasses != null) {
644 result
645 .putShort(symbolTable.addConstantUtf8(Constants.NEST_MEMBERS))
646 .putInt(nestMemberClasses.length + 2)
647 .putShort(numberOfNestMemberClasses)
648 .putByteArray(nestMemberClasses.data, 0, nestMemberClasses.length);
649 }
650 if (firstAttribute != null) {
651 firstAttribute.putAttributes(symbolTable, result);
652 }
653
654 // Third step: replace the ASM specific instructions, if any.
655 if (hasAsmInstructions) {
656 return replaceAsmInstructions(result.data, hasFrames);
657 } else {
658 return result.data;
659 }
660 }
661
662 /**
663 * Returns the equivalent of the given class file, with the ASM specific instructions replaced
664 * with standard ones. This is done with a ClassReader -&gt; ClassWriter round trip.
665 *
666 * @param classFile a class file containing ASM specific instructions, generated by this
667 * ClassWriter.
668 * @param hasFrames whether there is at least one stack map frames in 'classFile'.
669 * @return an equivalent of 'classFile', with the ASM specific instructions replaced with standard
670 * ones.
671 */
672 private byte[] replaceAsmInstructions(final byte[] classFile, final boolean hasFrames) {
673 Attribute[] attributes = getAttributePrototypes();
674 firstField = null;
675 lastField = null;
676 firstMethod = null;
677 lastMethod = null;
678 lastRuntimeVisibleAnnotation = null;
679 lastRuntimeInvisibleAnnotation = null;
680 lastRuntimeVisibleTypeAnnotation = null;
681 lastRuntimeInvisibleTypeAnnotation = null;
682 moduleWriter = null;
683 nestHostClassIndex = 0;
684 numberOfNestMemberClasses = 0;
685 nestMemberClasses = null;
686 firstAttribute = null;
687 compute = hasFrames ? MethodWriter.COMPUTE_INSERTED_FRAMES : MethodWriter.COMPUTE_NOTHING;
688 new ClassReader(classFile, 0, /* checkClassVersion = */ false)
689 .accept(
690 this,
691 attributes,
692 (hasFrames ? ClassReader.EXPAND_FRAMES : 0) | ClassReader.EXPAND_ASM_INSNS);
693 return toByteArray();
694 }
695
696 /**
697 * Returns the prototypes of the attributes used by this class, its fields and its methods.
698 *
699 * @return the prototypes of the attributes used by this class, its fields and its methods.
700 */
701 private Attribute[] getAttributePrototypes() {
702 Attribute.Set attributePrototypes = new Attribute.Set();
703 attributePrototypes.addAttributes(firstAttribute);
704 FieldWriter fieldWriter = firstField;
705 while (fieldWriter != null) {
706 fieldWriter.collectAttributePrototypes(attributePrototypes);
707 fieldWriter = (FieldWriter) fieldWriter.fv;
708 }
709 MethodWriter methodWriter = firstMethod;
710 while (methodWriter != null) {
711 methodWriter.collectAttributePrototypes(attributePrototypes);
712 methodWriter = (MethodWriter) methodWriter.mv;
713 }
714 return attributePrototypes.toArray();
715 }
716
717 // -----------------------------------------------------------------------------------------------
718 // Utility methods: constant pool management for Attribute sub classes
719 // -----------------------------------------------------------------------------------------------
720
721 /**
722 * Adds a number or string constant to the constant pool of the class being build. Does nothing if
723 * the constant pool already contains a similar item. <i>This method is intended for {@link
724 * Attribute} sub classes, and is normally not needed by class generators or adapters.</i>
725 *
726 * @param value the value of the constant to be added to the constant pool. This parameter must be
727 * an {@link Integer}, a {@link Float}, a {@link Long}, a {@link Double} or a {@link String}.
728 * @return the index of a new or already existing constant item with the given value.
729 */
730 public int newConst(final Object value) {
731 return symbolTable.addConstant(value).index;
732 }
733
734 /**
735 * Adds an UTF8 string to the constant pool of the class being build. Does nothing if the constant
736 * pool already contains a similar item. <i>This method is intended for {@link Attribute} sub
737 * classes, and is normally not needed by class generators or adapters.</i>
738 *
739 * @param value the String value.
740 * @return the index of a new or already existing UTF8 item.
741 */
742 public int newUTF8(final String value) {
743 return symbolTable.addConstantUtf8(value);
744 }
745
746 /**
747 * Adds a class reference to the constant pool of the class being build. Does nothing if the
748 * constant pool already contains a similar item. <i>This method is intended for {@link Attribute}
749 * sub classes, and is normally not needed by class generators or adapters.</i>
750 *
751 * @param value the internal name of the class.
752 * @return the index of a new or already existing class reference item.
753 */
754 public int newClass(final String value) {
755 return symbolTable.addConstantClass(value).index;
756 }
757
758 /**
759 * Adds a method type reference to the constant pool of the class being build. Does nothing if the
760 * constant pool already contains a similar item. <i>This method is intended for {@link Attribute}
761 * sub classes, and is normally not needed by class generators or adapters.</i>
762 *
763 * @param methodDescriptor method descriptor of the method type.
764 * @return the index of a new or already existing method type reference item.
765 */
766 public int newMethodType(final String methodDescriptor) {
767 return symbolTable.addConstantMethodType(methodDescriptor).index;
768 }
769
770 /**
771 * Adds a module reference to the constant pool of the class being build. Does nothing if the
772 * constant pool already contains a similar item. <i>This method is intended for {@link Attribute}
773 * sub classes, and is normally not needed by class generators or adapters.</i>
774 *
775 * @param moduleName name of the module.
776 * @return the index of a new or already existing module reference item.
777 */
778 public int newModule(final String moduleName) {
779 return symbolTable.addConstantModule(moduleName).index;
780 }
781
782 /**
783 * Adds a package reference to the constant pool of the class being build. Does nothing if the
784 * constant pool already contains a similar item. <i>This method is intended for {@link Attribute}
785 * sub classes, and is normally not needed by class generators or adapters.</i>
786 *
787 * @param packageName name of the package in its internal form.
788 * @return the index of a new or already existing module reference item.
789 */
790 public int newPackage(final String packageName) {
791 return symbolTable.addConstantPackage(packageName).index;
792 }
793
794 /**
795 * Adds a handle to the constant pool of the class being build. Does nothing if the constant pool
796 * already contains a similar item. <i>This method is intended for {@link Attribute} sub classes,
797 * and is normally not needed by class generators or adapters.</i>
798 *
799 * @param tag the kind of this handle. Must be {@link Opcodes#H_GETFIELD}, {@link
800 * Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, {@link
801 * Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL},
802 * {@link Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}.
803 * @param owner the internal name of the field or method owner class.
804 * @param name the name of the field or method.
805 * @param descriptor the descriptor of the field or method.
806 * @return the index of a new or already existing method type reference item.
807 * @deprecated this method is superseded by {@link #newHandle(int, String, String, String,
808 * boolean)}.
809 */
810 @Deprecated
811 public int newHandle(
812 final int tag, final String owner, final String name, final String descriptor) {
813 return newHandle(tag, owner, name, descriptor, tag == Opcodes.H_INVOKEINTERFACE);
814 }
815
816 /**
817 * Adds a handle to the constant pool of the class being build. Does nothing if the constant pool
818 * already contains a similar item. <i>This method is intended for {@link Attribute} sub classes,
819 * and is normally not needed by class generators or adapters.</i>
820 *
821 * @param tag the kind of this handle. Must be {@link Opcodes#H_GETFIELD}, {@link
822 * Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, {@link
823 * Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL},
824 * {@link Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}.
825 * @param owner the internal name of the field or method owner class.
826 * @param name the name of the field or method.
827 * @param descriptor the descriptor of the field or method.
828 * @param isInterface true if the owner is an interface.
829 * @return the index of a new or already existing method type reference item.
830 */
831 public int newHandle(
832 final int tag,
833 final String owner,
834 final String name,
835 final String descriptor,
836 final boolean isInterface) {
837 return symbolTable.addConstantMethodHandle(tag, owner, name, descriptor, isInterface).index;
838 }
839
840 /**
841 * Adds a dynamic constant reference to the constant pool of the class being build. Does nothing
842 * if the constant pool already contains a similar item. <i>This method is intended for {@link
843 * Attribute} sub classes, and is normally not needed by class generators or adapters.</i>
844 *
845 * @param name name of the invoked method.
846 * @param descriptor field descriptor of the constant type.
847 * @param bootstrapMethodHandle the bootstrap method.
848 * @param bootstrapMethodArguments the bootstrap method constant arguments.
849 * @return the index of a new or already existing dynamic constant reference item.
850 */
851 public int newConstantDynamic(
852 final String name,
853 final String descriptor,
854 final Handle bootstrapMethodHandle,
855 final Object... bootstrapMethodArguments) {
856 return symbolTable.addConstantDynamic(
857 name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments)
858 .index;
859 }
860
861 /**
862 * Adds an invokedynamic reference to the constant pool of the class being build. Does nothing if
863 * the constant pool already contains a similar item. <i>This method is intended for {@link
864 * Attribute} sub classes, and is normally not needed by class generators or adapters.</i>
865 *
866 * @param name name of the invoked method.
867 * @param descriptor descriptor of the invoke method.
868 * @param bootstrapMethodHandle the bootstrap method.
869 * @param bootstrapMethodArguments the bootstrap method constant arguments.
870 * @return the index of a new or already existing invokedynamic reference item.
871 */
872 public int newInvokeDynamic(
873 final String name,
874 final String descriptor,
875 final Handle bootstrapMethodHandle,
876 final Object... bootstrapMethodArguments) {
877 return symbolTable.addConstantInvokeDynamic(
878 name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments)
879 .index;
880 }
881
882 /**
883 * Adds a field reference to the constant pool of the class being build. Does nothing if the
884 * constant pool already contains a similar item. <i>This method is intended for {@link Attribute}
885 * sub classes, and is normally not needed by class generators or adapters.</i>
886 *
887 * @param owner the internal name of the field's owner class.
888 * @param name the field's name.
889 * @param descriptor the field's descriptor.
890 * @return the index of a new or already existing field reference item.
891 */
892 public int newField(final String owner, final String name, final String descriptor) {
893 return symbolTable.addConstantFieldref(owner, name, descriptor).index;
894 }
895
896 /**
897 * Adds a method reference to the constant pool of the class being build. Does nothing if the
898 * constant pool already contains a similar item. <i>This method is intended for {@link Attribute}
899 * sub classes, and is normally not needed by class generators or adapters.</i>
900 *
901 * @param owner the internal name of the method's owner class.
902 * @param name the method's name.
903 * @param descriptor the method's descriptor.
904 * @param isInterface <tt>true</tt> if <tt>owner</tt> is an interface.
905 * @return the index of a new or already existing method reference item.
906 */
907 public int newMethod(
908 final String owner, final String name, final String descriptor, final boolean isInterface) {
909 return symbolTable.addConstantMethodref(owner, name, descriptor, isInterface).index;
910 }
911
912 /**
913 * Adds a name and type to the constant pool of the class being build. Does nothing if the
914 * constant pool already contains a similar item. <i>This method is intended for {@link Attribute}
915 * sub classes, and is normally not needed by class generators or adapters.</i>
916 *
917 * @param name a name.
918 * @param descriptor a type descriptor.
919 * @return the index of a new or already existing name and type item.
920 */
921 public int newNameType(final String name, final String descriptor) {
922 return symbolTable.addConstantNameAndType(name, descriptor);
923 }
924
925 // -----------------------------------------------------------------------------------------------
926 // Default method to compute common super classes when computing stack map frames
927 // -----------------------------------------------------------------------------------------------
928
929 /**
930 * Returns the common super type of the two given types. The default implementation of this method
931 * <i>loads</i> the two given classes and uses the java.lang.Class methods to find the common
932 * super class. It can be overridden to compute this common super type in other ways, in
933 * particular without actually loading any class, or to take into account the class that is
934 * currently being generated by this ClassWriter, which can of course not be loaded since it is
935 * under construction.
936 *
937 * @param type1 the internal name of a class.
938 * @param type2 the internal name of another class.
939 * @return the internal name of the common super class of the two given classes.
940 */
941 protected String getCommonSuperClass(final String type1, final String type2) {
942 ClassLoader classLoader = getClass().getClassLoader();
943 Class<?> class1;
944 try {
945 class1 = Class.forName(type1.replace('/', '.'), false, classLoader);
946 } catch (Exception e) {
947 throw new TypeNotPresentException(type1, e);
948 }
949 Class<?> class2;
950 try {
951 class2 = Class.forName(type2.replace('/', '.'), false, classLoader);
952 } catch (Exception e) {
953 throw new TypeNotPresentException(type2, e);
954 }
955 if (class1.isAssignableFrom(class2)) {
956 return type1;
957 }
958 if (class2.isAssignableFrom(class1)) {
959 return type2;
960 }
961 if (class1.isInterface() || class2.isInterface()) {
962 return "java/lang/Object";
963 } else {
964 do {
965 class1 = class1.getSuperclass();
966 } while (!class1.isAssignableFrom(class2));
967 return class1.getName().replace('.', '/');
968 }
969 }
1830970 }
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
27 package org.eclipse.persistence.internal.libraries.asm;
28
29 import java.util.Arrays;
30
31 /**
32 * A constant whose value is computed at runtime, with a bootstrap method.
33 *
34 * @author Remi Forax
35 * @deprecated This API is experimental.
36 */
37 @Deprecated
38 public final class ConstantDynamic {
39
40 /** The constant name (can be arbitrary). */
41 private final String name;
42
43 /** The constant type (must be a field descriptor). */
44 private final String descriptor;
45
46 /** The bootstrap method to use to compute the constant value at runtime. */
47 private final Handle bootstrapMethod;
48
49 /**
50 * The arguments to pass to the bootstrap method, in order to compute the constant value at
51 * runtime.
52 */
53 private final Object[] bootstrapMethodArguments;
54
55 /**
56 * Constructs a new {@link ConstantDynamic}.
57 *
58 * @param name the constant name (can be arbitrary).
59 * @param descriptor the constant type (must be a field descriptor).
60 * @param bootstrapMethod the bootstrap method to use to compute the constant value at runtime.
61 * @param bootstrapMethodArguments the arguments to pass to the bootstrap method, in order to
62 * compute the constant value at runtime.
63 */
64 public ConstantDynamic(
65 final String name,
66 final String descriptor,
67 final Handle bootstrapMethod,
68 final Object... bootstrapMethodArguments) {
69 this.name = name;
70 this.descriptor = descriptor;
71 this.bootstrapMethod = bootstrapMethod;
72 this.bootstrapMethodArguments = bootstrapMethodArguments;
73 }
74
75 /**
76 * Returns the name of this constant.
77 *
78 * @return the name of this constant.
79 */
80 public String getName() {
81 return name;
82 }
83
84 /**
85 * Returns the type of this constant.
86 *
87 * @return the type of this constant, as a field descriptor.
88 */
89 public String getDescriptor() {
90 return descriptor;
91 }
92
93 /**
94 * Returns the bootstrap method used to compute the value of this constant.
95 *
96 * @return the bootstrap method used to compute the value of this constant.
97 */
98 public Handle getBootstrapMethod() {
99 return bootstrapMethod;
100 }
101
102 /**
103 * Returns the arguments to pass to the bootstrap method, in order to compute the value of this
104 * constant.
105 *
106 * @return the arguments to pass to the bootstrap method, in order to compute the value of this
107 * constant.
108 */
109 public Object[] getBootstrapMethodArguments() {
110 return bootstrapMethodArguments;
111 }
112
113 @Override
114 public boolean equals(final Object object) {
115 if (object == this) {
116 return true;
117 }
118 if (!(object instanceof ConstantDynamic)) {
119 return false;
120 }
121 ConstantDynamic constantDynamic = (ConstantDynamic) object;
122 return name.equals(constantDynamic.name)
123 && descriptor.equals(constantDynamic.descriptor)
124 && bootstrapMethod.equals(constantDynamic.bootstrapMethod)
125 && Arrays.equals(bootstrapMethodArguments, constantDynamic.bootstrapMethodArguments);
126 }
127
128 @Override
129 public int hashCode() {
130 return name.hashCode()
131 ^ Integer.rotateLeft(descriptor.hashCode(), 8)
132 ^ Integer.rotateLeft(bootstrapMethod.hashCode(), 16)
133 ^ Integer.rotateLeft(Arrays.hashCode(bootstrapMethodArguments), 24);
134 }
135
136 @Override
137 public String toString() {
138 return name
139 + " : "
140 + descriptor
141 + ' '
142 + bootstrapMethod
143 + ' '
144 + Arrays.toString(bootstrapMethodArguments);
145 }
146 }
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
27 package org.eclipse.persistence.internal.libraries.asm;
28
29 /**
30 * Defines additional JVM opcodes, access flags and constants which are not part of the ASM public
31 * API.
32 *
33 * @see <a href="https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-6.html">JVMS 6</a>
34 * @author Eric Bruneton
35 */
36 final class Constants implements Opcodes {
37
38 private Constants() {}
39
40 // The ClassFile attribute names, in the order they are defined in
41 // https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-4.html#jvms-4.7-300.
42
43 static final String CONSTANT_VALUE = "ConstantValue";
44 static final String CODE = "Code";
45 static final String STACK_MAP_TABLE = "StackMapTable";
46 static final String EXCEPTIONS = "Exceptions";
47 static final String INNER_CLASSES = "InnerClasses";
48 static final String ENCLOSING_METHOD = "EnclosingMethod";
49 static final String SYNTHETIC = "Synthetic";
50 static final String SIGNATURE = "Signature";
51 static final String SOURCE_FILE = "SourceFile";
52 static final String SOURCE_DEBUG_EXTENSION = "SourceDebugExtension";
53 static final String LINE_NUMBER_TABLE = "LineNumberTable";
54 static final String LOCAL_VARIABLE_TABLE = "LocalVariableTable";
55 static final String LOCAL_VARIABLE_TYPE_TABLE = "LocalVariableTypeTable";
56 static final String DEPRECATED = "Deprecated";
57 static final String RUNTIME_VISIBLE_ANNOTATIONS = "RuntimeVisibleAnnotations";
58 static final String RUNTIME_INVISIBLE_ANNOTATIONS = "RuntimeInvisibleAnnotations";
59 static final String RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS = "RuntimeVisibleParameterAnnotations";
60 static final String RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS =
61 "RuntimeInvisibleParameterAnnotations";
62 static final String RUNTIME_VISIBLE_TYPE_ANNOTATIONS = "RuntimeVisibleTypeAnnotations";
63 static final String RUNTIME_INVISIBLE_TYPE_ANNOTATIONS = "RuntimeInvisibleTypeAnnotations";
64 static final String ANNOTATION_DEFAULT = "AnnotationDefault";
65 static final String BOOTSTRAP_METHODS = "BootstrapMethods";
66 static final String METHOD_PARAMETERS = "MethodParameters";
67 static final String MODULE = "Module";
68 static final String MODULE_PACKAGES = "ModulePackages";
69 static final String MODULE_MAIN_CLASS = "ModuleMainClass";
70 static final String NEST_HOST = "NestHost";
71 static final String NEST_MEMBERS = "NestMembers";
72
73 // ASM specific access flags.
74 // WARNING: the 16 least significant bits must NOT be used, to avoid conflicts with standard
75 // access flags, and also to make sure that these flags are automatically filtered out when
76 // written in class files (because access flags are stored using 16 bits only).
77
78 static final int ACC_CONSTRUCTOR = 0x40000; // method access flag.
79
80 // ASM specific stack map frame types, used in {@link ClassVisitor#visitFrame}.
81
82 /**
83 * A frame inserted between already existing frames. This internal stack map frame type (in
84 * addition to the ones declared in {@link Opcodes}) can only be used if the frame content can be
85 * computed from the previous existing frame and from the instructions between this existing frame
86 * and the inserted one, without any knowledge of the type hierarchy. This kind of frame is only
87 * used when an unconditional jump is inserted in a method while expanding an ASM specific
88 * instruction. Keep in sync with Opcodes.java.
89 */
90 static final int F_INSERT = 256;
91
92 // The JVM opcode values which are not part of the ASM public API.
93 // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-6.html.
94
95 static final int LDC_W = 19;
96 static final int LDC2_W = 20;
97 static final int ILOAD_0 = 26;
98 static final int ILOAD_1 = 27;
99 static final int ILOAD_2 = 28;
100 static final int ILOAD_3 = 29;
101 static final int LLOAD_0 = 30;
102 static final int LLOAD_1 = 31;
103 static final int LLOAD_2 = 32;
104 static final int LLOAD_3 = 33;
105 static final int FLOAD_0 = 34;
106 static final int FLOAD_1 = 35;
107 static final int FLOAD_2 = 36;
108 static final int FLOAD_3 = 37;
109 static final int DLOAD_0 = 38;
110 static final int DLOAD_1 = 39;
111 static final int DLOAD_2 = 40;
112 static final int DLOAD_3 = 41;
113 static final int ALOAD_0 = 42;
114 static final int ALOAD_1 = 43;
115 static final int ALOAD_2 = 44;
116 static final int ALOAD_3 = 45;
117 static final int ISTORE_0 = 59;
118 static final int ISTORE_1 = 60;
119 static final int ISTORE_2 = 61;
120 static final int ISTORE_3 = 62;
121 static final int LSTORE_0 = 63;
122 static final int LSTORE_1 = 64;
123 static final int LSTORE_2 = 65;
124 static final int LSTORE_3 = 66;
125 static final int FSTORE_0 = 67;
126 static final int FSTORE_1 = 68;
127 static final int FSTORE_2 = 69;
128 static final int FSTORE_3 = 70;
129 static final int DSTORE_0 = 71;
130 static final int DSTORE_1 = 72;
131 static final int DSTORE_2 = 73;
132 static final int DSTORE_3 = 74;
133 static final int ASTORE_0 = 75;
134 static final int ASTORE_1 = 76;
135 static final int ASTORE_2 = 77;
136 static final int ASTORE_3 = 78;
137 static final int WIDE = 196;
138 static final int GOTO_W = 200;
139 static final int JSR_W = 201;
140
141 // Constants to convert between normal and wide jump instructions.
142
143 // The delta between the GOTO_W and JSR_W opcodes and GOTO and JUMP.
144 static final int WIDE_JUMP_OPCODE_DELTA = GOTO_W - GOTO;
145
146 // Constants to convert JVM opcodes to the equivalent ASM specific opcodes, and vice versa.
147
148 // The delta between the ASM_IFEQ, ..., ASM_IF_ACMPNE, ASM_GOTO and ASM_JSR opcodes
149 // and IFEQ, ..., IF_ACMPNE, GOTO and JSR.
150 static final int ASM_OPCODE_DELTA = 49;
151
152 // The delta between the ASM_IFNULL and ASM_IFNONNULL opcodes and IFNULL and IFNONNULL.
153 static final int ASM_IFNULL_OPCODE_DELTA = 20;
154
155 // ASM specific opcodes, used for long forward jump instructions.
156
157 static final int ASM_IFEQ = IFEQ + ASM_OPCODE_DELTA;
158 static final int ASM_IFNE = IFNE + ASM_OPCODE_DELTA;
159 static final int ASM_IFLT = IFLT + ASM_OPCODE_DELTA;
160 static final int ASM_IFGE = IFGE + ASM_OPCODE_DELTA;
161 static final int ASM_IFGT = IFGT + ASM_OPCODE_DELTA;
162 static final int ASM_IFLE = IFLE + ASM_OPCODE_DELTA;
163 static final int ASM_IF_ICMPEQ = IF_ICMPEQ + ASM_OPCODE_DELTA;
164 static final int ASM_IF_ICMPNE = IF_ICMPNE + ASM_OPCODE_DELTA;
165 static final int ASM_IF_ICMPLT = IF_ICMPLT + ASM_OPCODE_DELTA;
166 static final int ASM_IF_ICMPGE = IF_ICMPGE + ASM_OPCODE_DELTA;
167 static final int ASM_IF_ICMPGT = IF_ICMPGT + ASM_OPCODE_DELTA;
168 static final int ASM_IF_ICMPLE = IF_ICMPLE + ASM_OPCODE_DELTA;
169 static final int ASM_IF_ACMPEQ = IF_ACMPEQ + ASM_OPCODE_DELTA;
170 static final int ASM_IF_ACMPNE = IF_ACMPNE + ASM_OPCODE_DELTA;
171 static final int ASM_GOTO = GOTO + ASM_OPCODE_DELTA;
172 static final int ASM_JSR = JSR + ASM_OPCODE_DELTA;
173 static final int ASM_IFNULL = IFNULL + ASM_IFNULL_OPCODE_DELTA;
174 static final int ASM_IFNONNULL = IFNONNULL + ASM_IFNULL_OPCODE_DELTA;
175 static final int ASM_GOTO_W = 220;
176 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 package org.eclipse.persistence.internal.libraries.asm;
31
32 /**
33 * Information about a class being parsed in a {@link ClassReader}.
34 *
35 * @author Eric Bruneton
36 */
37 class Context {
38
39 /**
40 * Prototypes of the attributes that must be parsed for this class.
41 */
42 Attribute[] attrs;
43
44 /**
45 * The {@link ClassReader} option flags for the parsing of this class.
46 */
47 int flags;
48
49 /**
50 * The buffer used to read strings.
51 */
52 char[] buffer;
53
54 /**
55 * The start index of each bootstrap method.
56 */
57 int[] bootstrapMethods;
58
59 /**
60 * The access flags of the method currently being parsed.
61 */
62 int access;
63
64 /**
65 * The name of the method currently being parsed.
66 */
67 String name;
68
69 /**
70 * The descriptor of the method currently being parsed.
71 */
72 String desc;
73
74 /**
75 * The label objects, indexed by bytecode offset, of the method currently
76 * being parsed (only bytecode offsets for which a label is needed have a
77 * non null associated Label object).
78 */
79 Label[] labels;
80
81 /**
82 * The target of the type annotation currently being parsed.
83 */
84 int typeRef;
85
86 /**
87 * The path of the type annotation currently being parsed.
88 */
89 TypePath typePath;
90
91 /**
92 * The offset of the latest stack map frame that has been parsed.
93 */
94 int offset;
95
96 /**
97 * The labels corresponding to the start of the local variable ranges in the
98 * local variable type annotation currently being parsed.
99 */
100 Label[] start;
101
102 /**
103 * The labels corresponding to the end of the local variable ranges in the
104 * local variable type annotation currently being parsed.
105 */
106 Label[] end;
107
108 /**
109 * The local variable indices for each local variable range in the local
110 * variable type annotation currently being parsed.
111 */
112 int[] index;
113
114 /**
115 * The encoding of the latest stack map frame that has been parsed.
116 */
117 int mode;
118
119 /**
120 * The number of locals in the latest stack map frame that has been parsed.
121 */
122 int localCount;
123
124 /**
125 * The number locals in the latest stack map frame that has been parsed,
126 * minus the number of locals in the previous frame.
127 */
128 int localDiff;
129
130 /**
131 * The local values of the latest stack map frame that has been parsed.
132 */
133 Object[] local;
134
135 /**
136 * The stack size of the latest stack map frame that has been parsed.
137 */
138 int stackCount;
139
140 /**
141 * The stack values of the latest stack map frame that has been parsed.
142 */
143 Object[] stack;
144 }
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
27
28 package org.eclipse.persistence.internal.libraries.asm;
29
30 /**
31 * Information about a class being parsed in a {@link ClassReader}.
32 *
33 * @author Eric Bruneton
34 */
35 final class Context {
36
37 /** The prototypes of the attributes that must be parsed in this class. */
38 Attribute[] attributePrototypes;
39
40 /**
41 * The options used to parse this class. One or more of {@link ClassReader#SKIP_CODE}, {@link
42 * ClassReader#SKIP_DEBUG}, {@link ClassReader#SKIP_FRAMES}, {@link ClassReader#EXPAND_FRAMES} or
43 * {@link ClassReader#EXPAND_ASM_INSNS}.
44 */
45 int parsingOptions;
46
47 /** The buffer used to read strings in the constant pool. */
48 char[] charBuffer;
49
50 // Information about the current method, i.e. the one read in the current (or latest) call
51 // to {@link ClassReader#readMethod()}.
52
53 /** The access flags of the current method. */
54 int currentMethodAccessFlags;
55
56 /** The name of the current method. */
57 String currentMethodName;
58
59 /** The descriptor of the current method. */
60 String currentMethodDescriptor;
61
62 /**
63 * The labels of the current method, indexed by bytecode offset (only bytecode offsets for which a
64 * label is needed have a non null associated Label).
65 */
66 Label[] currentMethodLabels;
67
68 // Information about the current type annotation target, i.e. the one read in the current
69 // (or latest) call to {@link ClassReader#readAnnotationTarget()}.
70
71 /**
72 * The target_type and target_info of the current type annotation target, encoded as described in
73 * {@link TypeReference}.
74 */
75 int currentTypeAnnotationTarget;
76
77 /** The target_path of the current type annotation target. */
78 TypePath currentTypeAnnotationTargetPath;
79
80 /** The start of each local variable range in the current local variable annotation. */
81 Label[] currentLocalVariableAnnotationRangeStarts;
82
83 /** The end of each local variable range in the current local variable annotation. */
84 Label[] currentLocalVariableAnnotationRangeEnds;
85
86 /**
87 * The local variable index of each local variable range in the current local variable annotation.
88 */
89 int[] currentLocalVariableAnnotationRangeIndices;
90
91 // Information about the current stack map frame, i.e. the one read in the current (or latest)
92 // call to {@link ClassReader#readFrame()}.
93
94 /** The bytecode offset of the current stack map frame. */
95 int currentFrameOffset;
96
97 /**
98 * The type of the current stack map frame. One of {@link Opcodes#F_FULL}, {@link
99 * Opcodes#F_APPEND}, {@link Opcodes#F_CHOP}, {@link Opcodes#F_SAME} or {@link Opcodes#F_SAME1}.
100 */
101 int currentFrameType;
102
103 /**
104 * The number of local variable types in the current stack map frame. Each type is represented
105 * with a single array element (even long and double).
106 */
107 int currentFrameLocalCount;
108
109 /**
110 * The delta number of local variable types in the current stack map frame (each type is
111 * represented with a single array element - even long and double). This is the number of local
112 * variable types in this frame, minus the number of local variable types in the previous frame.
113 */
114 int currentFrameLocalCountDelta;
115
116 /**
117 * The types of the local variables in the current stack map frame. Each type is represented with
118 * a single array element (even long and double), using the format described in {@link
119 * MethodVisitor#visitFrame}. Depending on {@link #currentFrameType}, this contains the types of
120 * all the local variables, or only those of the additional ones (compared to the previous frame).
121 */
122 Object[] currentFrameLocalTypes;
123
124 /**
125 * The number stack element types in the current stack map frame. Each type is represented with a
126 * single array element (even long and double).
127 */
128 int currentFrameStackCount;
129
130 /**
131 * The types of the stack elements in the current stack map frame. Each type is represented with a
132 * single array element (even long and double), using the format described in {@link
133 * MethodVisitor#visitFrame}.
134 */
135 Object[] currentFrameStackTypes;
136 }
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
27
28 package org.eclipse.persistence.internal.libraries.asm;
29
30 /**
31 * Information about the input stack map frame at the "current" instruction of a method. This is
32 * implemented as a Frame subclass for a "basic block" containing only one instruction.
33 *
34 * @author Eric Bruneton
35 */
36 final class CurrentFrame extends Frame {
37
38 CurrentFrame(final Label owner) {
39 super(owner);
40 }
41
42 /**
43 * Sets this CurrentFrame to the input stack map frame of the next "current" instruction, i.e. the
44 * instruction just after the given one. It is assumed that the value of this object when this
45 * method is called is the stack map frame status just before the given instruction is executed.
46 */
47 @Override
48 void execute(
49 final int opcode, final int arg, final Symbol symbolArg, final SymbolTable symbolTable) {
50 super.execute(opcode, arg, symbolArg, symbolTable);
51 Frame successor = new Frame(null);
52 merge(symbolTable, successor, 0);
53 copyFrom(successor);
54 }
55 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm;
3028
3129 /**
32 * An edge in the control flow graph of a method body. See {@link Label Label}.
33 *
30 * An edge in the control flow graph of a method. Each node of this graph is a basic block,
31 * represented with the Label corresponding to its first instruction. Each edge goes from one node
32 * to another, i.e. from one basic block to another (called the predecessor and successor blocks,
33 * respectively). An edge corresponds either to a jump or ret instruction or to an exception
34 * handler.
35 *
36 * @see Label
3437 * @author Eric Bruneton
3538 */
36 class Edge {
39 final class Edge {
3740
38 /**
39 * Denotes a normal control flow graph edge.
40 */
41 static final int NORMAL = 0;
41 /**
42 * A control flow graph edge corresponding to a jump or ret instruction. Only used with {@link
43 * ClassWriter#COMPUTE_FRAMES}.
44 */
45 static final int JUMP = 0;
4246
43 /**
44 * Denotes a control flow graph edge corresponding to an exception handler.
45 * More precisely any {@link Edge} whose {@link #info} is strictly positive
46 * corresponds to an exception handler. The actual value of {@link #info} is
47 * the index, in the {@link ClassWriter} type table, of the exception that
48 * is catched.
49 */
50 static final int EXCEPTION = 0x7FFFFFFF;
47 /**
48 * A control flow graph edge corresponding to an exception handler. Only used with {@link
49 * ClassWriter#COMPUTE_MAXS}.
50 */
51 static final int EXCEPTION = 0x7FFFFFFF;
5152
52 /**
53 * Information about this control flow graph edge. If
54 * {@link ClassWriter#COMPUTE_MAXS} is used this field is the (relative)
55 * stack size in the basic block from which this edge originates. This size
56 * is equal to the stack size at the "jump" instruction to which this edge
57 * corresponds, relatively to the stack size at the beginning of the
58 * originating basic block. If {@link ClassWriter#COMPUTE_FRAMES} is used,
59 * this field is the kind of this control flow graph edge (i.e. NORMAL or
60 * EXCEPTION).
61 */
62 int info;
53 /**
54 * Information about this control flow graph edge.
55 *
56 * <ul>
57 * <li>If {@link ClassWriter#COMPUTE_MAXS} is used, this field contains either a stack size
58 * delta (for an edge corresponding to a jump instruction), or the value EXCEPTION (for an
59 * edge corresponding to an exception handler). The stack size delta is the stack size just
60 * after the jump instruction, minus the stack size at the beginning of the predecessor
61 * basic block, i.e. the one containing the jump instruction.
62 * <li>If {@link ClassWriter#COMPUTE_FRAMES} is used, this field contains either the value JUMP
63 * (for an edge corresponding to a jump instruction), or the index, in the {@link
64 * ClassWriter} type table, of the exception type that is handled (for an edge corresponding
65 * to an exception handler).
66 * </ul>
67 */
68 final int info;
6369
64 /**
65 * The successor block of the basic block from which this edge originates.
66 */
67 Label successor;
70 /** The successor block of this control flow graph edge. */
71 final Label successor;
6872
69 /**
70 * The next edge in the list of successors of the originating basic block.
71 * See {@link Label#successors successors}.
72 */
73 Edge next;
73 /**
74 * The next edge in the list of outgoing edges of a basic block. See {@link Label#outgoingEdges}.
75 */
76 Edge nextEdge;
77
78 /**
79 * Constructs a new Edge.
80 *
81 * @param info see {@link #info}.
82 * @param successor see {@link #successor}.
83 * @param nextEdge see {@link #nextEdge}.
84 */
85 Edge(final int info, final Label successor, final Edge nextEdge) {
86 this.info = info;
87 this.successor = successor;
88 this.nextEdge = nextEdge;
89 }
7490 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm;
3028
3129 /**
32 * A visitor to visit a Java field. The methods of this class must be called in
33 * the following order: ( <tt>visitAnnotation</tt> |
34 * <tt>visitTypeAnnotation</tt> | <tt>visitAttribute</tt> )* <tt>visitEnd</tt>.
35 *
30 * A visitor to visit a Java field. The methods of this class must be called in the following order:
31 * ( <tt>visitAnnotation</tt> | <tt>visitTypeAnnotation</tt> | <tt>visitAttribute</tt> )*
32 * <tt>visitEnd</tt>.
33 *
3634 * @author Eric Bruneton
3735 */
3836 public abstract class FieldVisitor {
3937
40 /**
41 * The ASM API version implemented by this visitor. The value of this field
42 * must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
43 */
44 protected final int api;
38 /**
39 * The ASM API version implemented by this visitor. The value of this field must be one of {@link
40 * Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7_EXPERIMENTAL}.
41 */
42 protected final int api;
4543
46 /**
47 * The field visitor to which this visitor must delegate method calls. May
48 * be null.
49 */
50 protected FieldVisitor fv;
44 /** The field visitor to which this visitor must delegate method calls. May be null. */
45 protected FieldVisitor fv;
5146
52 /**
53 * Constructs a new {@link FieldVisitor}.
54 *
55 * @param api
56 * the ASM API version implemented by this visitor. Must be one
57 * of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
58 */
59 public FieldVisitor(final int api) {
60 this(api, null);
47 /**
48 * Constructs a new {@link FieldVisitor}.
49 *
50 * @param api the ASM API version implemented by this visitor. Must be one of {@link
51 * Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link
52 * Opcodes#ASM7_EXPERIMENTAL}.
53 */
54 public FieldVisitor(final int api) {
55 this(api, null);
56 }
57
58 /**
59 * Constructs a new {@link FieldVisitor}.
60 *
61 * @param api the ASM API version implemented by this visitor. Must be one of {@link
62 * Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link
63 * Opcodes#ASM7_EXPERIMENTAL}.
64 * @param fieldVisitor the field visitor to which this visitor must delegate method calls. May be
65 * null.
66 */
67 public FieldVisitor(final int api, final FieldVisitor fieldVisitor) {
68 if (api != Opcodes.ASM6
69 && api != Opcodes.ASM5
70 && api != Opcodes.ASM4
71 && api != Opcodes.ASM7_EXPERIMENTAL) {
72 throw new IllegalArgumentException();
6173 }
74 this.api = api;
75 this.fv = fieldVisitor;
76 }
6277
63 /**
64 * Constructs a new {@link FieldVisitor}.
65 *
66 * @param api
67 * the ASM API version implemented by this visitor. Must be one
68 * of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
69 * @param fv
70 * the field visitor to which this visitor must delegate method
71 * calls. May be null.
72 */
73 public FieldVisitor(final int api, final FieldVisitor fv) {
74 if (api < Opcodes.ASM4 || api > Opcodes.ASM6) {
75 throw new IllegalArgumentException();
76 }
77 this.api = api;
78 this.fv = fv;
78 /**
79 * Visits an annotation of the field.
80 *
81 * @param descriptor the class descriptor of the annotation class.
82 * @param visible <tt>true</tt> if the annotation is visible at runtime.
83 * @return a visitor to visit the annotation values, or <tt>null</tt> if this visitor is not
84 * interested in visiting this annotation.
85 */
86 public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
87 if (fv != null) {
88 return fv.visitAnnotation(descriptor, visible);
7989 }
90 return null;
91 }
8092
81 /**
82 * Visits an annotation of the field.
83 *
84 * @param desc
85 * the class descriptor of the annotation class.
86 * @param visible
87 * <tt>true</tt> if the annotation is visible at runtime.
88 * @return a visitor to visit the annotation values, or <tt>null</tt> if
89 * this visitor is not interested in visiting this annotation.
90 */
91 public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
92 if (fv != null) {
93 return fv.visitAnnotation(desc, visible);
94 }
95 return null;
93 /**
94 * Visits an annotation on the type of the field.
95 *
96 * @param typeRef a reference to the annotated type. The sort of this type reference must be
97 * {@link TypeReference#FIELD}. See {@link TypeReference}.
98 * @param typePath the path to the annotated type argument, wildcard bound, array element type, or
99 * static inner type within 'typeRef'. May be <tt>null</tt> if the annotation targets
100 * 'typeRef' as a whole.
101 * @param descriptor the class descriptor of the annotation class.
102 * @param visible <tt>true</tt> if the annotation is visible at runtime.
103 * @return a visitor to visit the annotation values, or <tt>null</tt> if this visitor is not
104 * interested in visiting this annotation.
105 */
106 public AnnotationVisitor visitTypeAnnotation(
107 final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
108 if (api < Opcodes.ASM5) {
109 throw new UnsupportedOperationException();
96110 }
111 if (fv != null) {
112 return fv.visitTypeAnnotation(typeRef, typePath, descriptor, visible);
113 }
114 return null;
115 }
97116
98 /**
99 * Visits an annotation on the type of the field.
100 *
101 * @param typeRef
102 * a reference to the annotated type. The sort of this type
103 * reference must be {@link TypeReference#FIELD FIELD}. See
104 * {@link TypeReference}.
105 * @param typePath
106 * the path to the annotated type argument, wildcard bound, array
107 * element type, or static inner type within 'typeRef'. May be
108 * <tt>null</tt> if the annotation targets 'typeRef' as a whole.
109 * @param desc
110 * the class descriptor of the annotation class.
111 * @param visible
112 * <tt>true</tt> if the annotation is visible at runtime.
113 * @return a visitor to visit the annotation values, or <tt>null</tt> if
114 * this visitor is not interested in visiting this annotation.
115 */
116 public AnnotationVisitor visitTypeAnnotation(int typeRef,
117 TypePath typePath, String desc, boolean visible) {
118 if (api < Opcodes.ASM5) {
119 throw new RuntimeException();
120 }
121 if (fv != null) {
122 return fv.visitTypeAnnotation(typeRef, typePath, desc, visible);
123 }
124 return null;
117 /**
118 * Visits a non standard attribute of the field.
119 *
120 * @param attribute an attribute.
121 */
122 public void visitAttribute(final Attribute attribute) {
123 if (fv != null) {
124 fv.visitAttribute(attribute);
125125 }
126 }
126127
127 /**
128 * Visits a non standard attribute of the field.
129 *
130 * @param attr
131 * an attribute.
132 */
133 public void visitAttribute(Attribute attr) {
134 if (fv != null) {
135 fv.visitAttribute(attr);
136 }
128 /**
129 * Visits the end of the field. This method, which is the last one to be called, is used to inform
130 * the visitor that all the annotations and attributes of the field have been visited.
131 */
132 public void visitEnd() {
133 if (fv != null) {
134 fv.visitEnd();
137135 }
138
139 /**
140 * Visits the end of the field. This method, which is the last one to be
141 * called, is used to inform the visitor that all the annotations and
142 * attributes of the field have been visited.
143 */
144 public void visitEnd() {
145 if (fv != null) {
146 fv.visitEnd();
147 }
148 }
136 }
149137 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
27 package org.eclipse.persistence.internal.libraries.asm;
28
29 /**
30 * A {@link FieldVisitor} that generates a corresponding 'field_info' structure, as defined in the
31 * Java Virtual Machine Specification (JVMS).
432 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 package org.eclipse.persistence.internal.libraries.asm;
30
31 /**
32 * An {@link FieldVisitor} that generates Java fields in bytecode form.
33 *
33 * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.5">JVMS
34 * 4.5</a>
3435 * @author Eric Bruneton
3536 */
3637 final class FieldWriter extends FieldVisitor {
3738
38 /**
39 * The class writer to which this field must be added.
40 */
41 private final ClassWriter cw;
42
43 /**
44 * Access flags of this field.
45 */
46 private final int access;
47
48 /**
49 * The index of the constant pool item that contains the name of this
50 * method.
51 */
52 private final int name;
53
54 /**
55 * The index of the constant pool item that contains the descriptor of this
56 * field.
57 */
58 private final int desc;
59
60 /**
61 * The index of the constant pool item that contains the signature of this
62 * field.
63 */
64 private int signature;
65
66 /**
67 * The index of the constant pool item that contains the constant value of
68 * this field.
69 */
70 private int value;
71
72 /**
73 * The runtime visible annotations of this field. May be <tt>null</tt>.
74 */
75 private AnnotationWriter anns;
76
77 /**
78 * The runtime invisible annotations of this field. May be <tt>null</tt>.
79 */
80 private AnnotationWriter ianns;
81
82 /**
83 * The runtime visible type annotations of this field. May be <tt>null</tt>.
84 */
85 private AnnotationWriter tanns;
86
87 /**
88 * The runtime invisible type annotations of this field. May be
89 * <tt>null</tt>.
90 */
91 private AnnotationWriter itanns;
92
93 /**
94 * The non standard attributes of this field. May be <tt>null</tt>.
95 */
96 private Attribute attrs;
97
98 // ------------------------------------------------------------------------
99 // Constructor
100 // ------------------------------------------------------------------------
101
102 /**
103 * Constructs a new {@link FieldWriter}.
104 *
105 * @param cw
106 * the class writer to which this field must be added.
107 * @param access
108 * the field's access flags (see {@link Opcodes}).
109 * @param name
110 * the field's name.
111 * @param desc
112 * the field's descriptor (see {@link Type}).
113 * @param signature
114 * the field's signature. May be <tt>null</tt>.
115 * @param value
116 * the field's constant value. May be <tt>null</tt>.
117 */
118 FieldWriter(final ClassWriter cw, final int access, final String name,
119 final String desc, final String signature, final Object value) {
120 super(Opcodes.ASM6);
121 if (cw.firstField == null) {
122 cw.firstField = this;
123 } else {
124 cw.lastField.fv = this;
125 }
126 cw.lastField = this;
127 this.cw = cw;
128 this.access = access;
129 this.name = cw.newUTF8(name);
130 this.desc = cw.newUTF8(desc);
131 if (ClassReader.SIGNATURES && signature != null) {
132 this.signature = cw.newUTF8(signature);
133 }
134 if (value != null) {
135 this.value = cw.newConstItem(value).index;
136 }
137 }
138
139 // ------------------------------------------------------------------------
140 // Implementation of the FieldVisitor abstract class
141 // ------------------------------------------------------------------------
142
143 @Override
144 public AnnotationVisitor visitAnnotation(final String desc,
145 final boolean visible) {
146 if (!ClassReader.ANNOTATIONS) {
147 return null;
148 }
149 ByteVector bv = new ByteVector();
150 // write type, and reserve space for values count
151 bv.putShort(cw.newUTF8(desc)).putShort(0);
152 AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2);
153 if (visible) {
154 aw.next = anns;
155 anns = aw;
156 } else {
157 aw.next = ianns;
158 ianns = aw;
159 }
160 return aw;
161 }
162
163 @Override
164 public AnnotationVisitor visitTypeAnnotation(final int typeRef,
165 final TypePath typePath, final String desc, final boolean visible) {
166 if (!ClassReader.ANNOTATIONS) {
167 return null;
168 }
169 ByteVector bv = new ByteVector();
170 // write target_type and target_info
171 AnnotationWriter.putTarget(typeRef, typePath, bv);
172 // write type, and reserve space for values count
173 bv.putShort(cw.newUTF8(desc)).putShort(0);
174 AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv,
175 bv.length - 2);
176 if (visible) {
177 aw.next = tanns;
178 tanns = aw;
179 } else {
180 aw.next = itanns;
181 itanns = aw;
182 }
183 return aw;
184 }
185
186 @Override
187 public void visitAttribute(final Attribute attr) {
188 attr.next = attrs;
189 attrs = attr;
190 }
191
192 @Override
193 public void visitEnd() {
194 }
195
196 // ------------------------------------------------------------------------
197 // Utility methods
198 // ------------------------------------------------------------------------
199
200 /**
201 * Returns the size of this field.
202 *
203 * @return the size of this field.
204 */
205 int getSize() {
206 int size = 8;
207 if (value != 0) {
208 cw.newUTF8("ConstantValue");
209 size += 8;
210 }
211 if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
212 if ((cw.version & 0xFFFF) < Opcodes.V1_5
213 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
214 cw.newUTF8("Synthetic");
215 size += 6;
216 }
217 }
218 if ((access & Opcodes.ACC_DEPRECATED) != 0) {
219 cw.newUTF8("Deprecated");
220 size += 6;
221 }
222 if (ClassReader.SIGNATURES && signature != 0) {
223 cw.newUTF8("Signature");
224 size += 8;
225 }
226 if (ClassReader.ANNOTATIONS && anns != null) {
227 cw.newUTF8("RuntimeVisibleAnnotations");
228 size += 8 + anns.getSize();
229 }
230 if (ClassReader.ANNOTATIONS && ianns != null) {
231 cw.newUTF8("RuntimeInvisibleAnnotations");
232 size += 8 + ianns.getSize();
233 }
234 if (ClassReader.ANNOTATIONS && tanns != null) {
235 cw.newUTF8("RuntimeVisibleTypeAnnotations");
236 size += 8 + tanns.getSize();
237 }
238 if (ClassReader.ANNOTATIONS && itanns != null) {
239 cw.newUTF8("RuntimeInvisibleTypeAnnotations");
240 size += 8 + itanns.getSize();
241 }
242 if (attrs != null) {
243 size += attrs.getSize(cw, null, 0, -1, -1);
244 }
245 return size;
246 }
247
248 /**
249 * Puts the content of this field into the given byte vector.
250 *
251 * @param out
252 * where the content of this field must be put.
253 */
254 void put(final ByteVector out) {
255 final int FACTOR = ClassWriter.TO_ACC_SYNTHETIC;
256 int mask = Opcodes.ACC_DEPRECATED | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE
257 | ((access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) / FACTOR);
258 out.putShort(access & ~mask).putShort(name).putShort(desc);
259 int attributeCount = 0;
260 if (value != 0) {
261 ++attributeCount;
262 }
263 if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
264 if ((cw.version & 0xFFFF) < Opcodes.V1_5
265 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
266 ++attributeCount;
267 }
268 }
269 if ((access & Opcodes.ACC_DEPRECATED) != 0) {
270 ++attributeCount;
271 }
272 if (ClassReader.SIGNATURES && signature != 0) {
273 ++attributeCount;
274 }
275 if (ClassReader.ANNOTATIONS && anns != null) {
276 ++attributeCount;
277 }
278 if (ClassReader.ANNOTATIONS && ianns != null) {
279 ++attributeCount;
280 }
281 if (ClassReader.ANNOTATIONS && tanns != null) {
282 ++attributeCount;
283 }
284 if (ClassReader.ANNOTATIONS && itanns != null) {
285 ++attributeCount;
286 }
287 if (attrs != null) {
288 attributeCount += attrs.getCount();
289 }
290 out.putShort(attributeCount);
291 if (value != 0) {
292 out.putShort(cw.newUTF8("ConstantValue"));
293 out.putInt(2).putShort(value);
294 }
295 if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
296 if ((cw.version & 0xFFFF) < Opcodes.V1_5
297 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
298 out.putShort(cw.newUTF8("Synthetic")).putInt(0);
299 }
300 }
301 if ((access & Opcodes.ACC_DEPRECATED) != 0) {
302 out.putShort(cw.newUTF8("Deprecated")).putInt(0);
303 }
304 if (ClassReader.SIGNATURES && signature != 0) {
305 out.putShort(cw.newUTF8("Signature"));
306 out.putInt(2).putShort(signature);
307 }
308 if (ClassReader.ANNOTATIONS && anns != null) {
309 out.putShort(cw.newUTF8("RuntimeVisibleAnnotations"));
310 anns.put(out);
311 }
312 if (ClassReader.ANNOTATIONS && ianns != null) {
313 out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations"));
314 ianns.put(out);
315 }
316 if (ClassReader.ANNOTATIONS && tanns != null) {
317 out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations"));
318 tanns.put(out);
319 }
320 if (ClassReader.ANNOTATIONS && itanns != null) {
321 out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations"));
322 itanns.put(out);
323 }
324 if (attrs != null) {
325 attrs.put(cw, null, 0, -1, -1, out);
326 }
327 }
39 /** Where the constants used in this FieldWriter must be stored. */
40 private final SymbolTable symbolTable;
41
42 // Note: fields are ordered as in the field_info structure, and those related to attributes are
43 // ordered as in Section 4.7 of the JVMS.
44
45 /**
46 * The access_flags field of the field_info JVMS structure. This field can contain ASM specific
47 * access flags, such as {@link Opcodes#ACC_DEPRECATED}, which are removed when generating the
48 * ClassFile structure.
49 */
50 private final int accessFlags;
51
52 /** The name_index field of the field_info JVMS structure. */
53 private final int nameIndex;
54
55 /** The descriptor_index field of the field_info JVMS structure. */
56 private final int descriptorIndex;
57
58 /**
59 * The signature_index field of the Signature attribute of this field_info, or 0 if there is no
60 * Signature attribute.
61 */
62 private int signatureIndex;
63
64 /**
65 * The constantvalue_index field of the ConstantValue attribute of this field_info, or 0 if there
66 * is no ConstantValue attribute.
67 */
68 private int constantValueIndex;
69
70 /**
71 * The last runtime visible annotation of this field. The previous ones can be accessed with the
72 * {@link AnnotationWriter#previousAnnotation} field. May be <tt>null</tt>.
73 */
74 private AnnotationWriter lastRuntimeVisibleAnnotation;
75
76 /**
77 * The last runtime invisible annotation of this field. The previous ones can be accessed with the
78 * {@link AnnotationWriter#previousAnnotation} field. May be <tt>null</tt>.
79 */
80 private AnnotationWriter lastRuntimeInvisibleAnnotation;
81
82 /**
83 * The last runtime visible type annotation of this field. The previous ones can be accessed with
84 * the {@link AnnotationWriter#previousAnnotation} field. May be <tt>null</tt>.
85 */
86 private AnnotationWriter lastRuntimeVisibleTypeAnnotation;
87
88 /**
89 * The last runtime invisible type annotation of this field. The previous ones can be accessed
90 * with the {@link AnnotationWriter#previousAnnotation} field. May be <tt>null</tt>.
91 */
92 private AnnotationWriter lastRuntimeInvisibleTypeAnnotation;
93
94 /**
95 * The first non standard attribute of this field. The next ones can be accessed with the {@link
96 * Attribute#nextAttribute} field. May be <tt>null</tt>.
97 *
98 * <p><b>WARNING</b>: this list stores the attributes in the <i>reverse</i> order of their visit.
99 * firstAttribute is actually the last attribute visited in {@link #visitAttribute}. The {@link
100 * #putFieldInfo} method writes the attributes in the order defined by this list, i.e. in the
101 * reverse order specified by the user.
102 */
103 private Attribute firstAttribute;
104
105 // -----------------------------------------------------------------------------------------------
106 // Constructor
107 // -----------------------------------------------------------------------------------------------
108
109 /**
110 * Constructs a new {@link FieldWriter}.
111 *
112 * @param symbolTable where the constants used in this FieldWriter must be stored.
113 * @param access the field's access flags (see {@link Opcodes}).
114 * @param name the field's name.
115 * @param descriptor the field's descriptor (see {@link Type}).
116 * @param signature the field's signature. May be <tt>null</tt>.
117 * @param constantValue the field's constant value. May be <tt>null</tt>.
118 */
119 FieldWriter(
120 final SymbolTable symbolTable,
121 final int access,
122 final String name,
123 final String descriptor,
124 final String signature,
125 final Object constantValue) {
126 super(Opcodes.ASM6);
127 this.symbolTable = symbolTable;
128 this.accessFlags = access;
129 this.nameIndex = symbolTable.addConstantUtf8(name);
130 this.descriptorIndex = symbolTable.addConstantUtf8(descriptor);
131 if (signature != null) {
132 this.signatureIndex = symbolTable.addConstantUtf8(signature);
133 }
134 if (constantValue != null) {
135 this.constantValueIndex = symbolTable.addConstant(constantValue).index;
136 }
137 }
138
139 // -----------------------------------------------------------------------------------------------
140 // Implementation of the FieldVisitor abstract class
141 // -----------------------------------------------------------------------------------------------
142
143 @Override
144 public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
145 // Create a ByteVector to hold an 'annotation' JVMS structure.
146 // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.
147 ByteVector annotation = new ByteVector();
148 // Write type_index and reserve space for num_element_value_pairs.
149 annotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0);
150 if (visible) {
151 return lastRuntimeVisibleAnnotation =
152 new AnnotationWriter(symbolTable, annotation, lastRuntimeVisibleAnnotation);
153 } else {
154 return lastRuntimeInvisibleAnnotation =
155 new AnnotationWriter(symbolTable, annotation, lastRuntimeInvisibleAnnotation);
156 }
157 }
158
159 @Override
160 public AnnotationVisitor visitTypeAnnotation(
161 final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
162 // Create a ByteVector to hold a 'type_annotation' JVMS structure.
163 // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20.
164 ByteVector typeAnnotation = new ByteVector();
165 // Write target_type, target_info, and target_path.
166 TypeReference.putTarget(typeRef, typeAnnotation);
167 TypePath.put(typePath, typeAnnotation);
168 // Write type_index and reserve space for num_element_value_pairs.
169 typeAnnotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0);
170 if (visible) {
171 return lastRuntimeVisibleTypeAnnotation =
172 new AnnotationWriter(symbolTable, typeAnnotation, lastRuntimeVisibleTypeAnnotation);
173 } else {
174 return lastRuntimeInvisibleTypeAnnotation =
175 new AnnotationWriter(symbolTable, typeAnnotation, lastRuntimeInvisibleTypeAnnotation);
176 }
177 }
178
179 @Override
180 public void visitAttribute(final Attribute attribute) {
181 // Store the attributes in the <i>reverse</i> order of their visit by this method.
182 attribute.nextAttribute = firstAttribute;
183 firstAttribute = attribute;
184 }
185
186 @Override
187 public void visitEnd() {
188 // Nothing to do.
189 }
190
191 // -----------------------------------------------------------------------------------------------
192 // Utility methods
193 // -----------------------------------------------------------------------------------------------
194
195 /**
196 * Returns the size of the field_info JVMS structure generated by this FieldWriter. Also adds the
197 * names of the attributes of this field in the constant pool.
198 *
199 * @return the size in bytes of the field_info JVMS structure.
200 */
201 int computeFieldInfoSize() {
202 // The access_flags, name_index, descriptor_index and attributes_count fields use 8 bytes.
203 int size = 8;
204 // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS.
205 if (constantValueIndex != 0) {
206 // ConstantValue attributes always use 8 bytes.
207 symbolTable.addConstantUtf8(Constants.CONSTANT_VALUE);
208 size += 8;
209 }
210 // Before Java 1.5, synthetic fields are represented with a Synthetic attribute.
211 if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0
212 && symbolTable.getMajorVersion() < Opcodes.V1_5) {
213 // Synthetic attributes always use 6 bytes.
214 symbolTable.addConstantUtf8(Constants.SYNTHETIC);
215 size += 6;
216 }
217 if (signatureIndex != 0) {
218 // Signature attributes always use 8 bytes.
219 symbolTable.addConstantUtf8(Constants.SIGNATURE);
220 size += 8;
221 }
222 // ACC_DEPRECATED is ASM specific, the ClassFile format uses a Deprecated attribute instead.
223 if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) {
224 // Deprecated attributes always use 6 bytes.
225 symbolTable.addConstantUtf8(Constants.DEPRECATED);
226 size += 6;
227 }
228 if (lastRuntimeVisibleAnnotation != null) {
229 size +=
230 lastRuntimeVisibleAnnotation.computeAnnotationsSize(
231 Constants.RUNTIME_VISIBLE_ANNOTATIONS);
232 }
233 if (lastRuntimeInvisibleAnnotation != null) {
234 size +=
235 lastRuntimeInvisibleAnnotation.computeAnnotationsSize(
236 Constants.RUNTIME_INVISIBLE_ANNOTATIONS);
237 }
238 if (lastRuntimeVisibleTypeAnnotation != null) {
239 size +=
240 lastRuntimeVisibleTypeAnnotation.computeAnnotationsSize(
241 Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS);
242 }
243 if (lastRuntimeInvisibleTypeAnnotation != null) {
244 size +=
245 lastRuntimeInvisibleTypeAnnotation.computeAnnotationsSize(
246 Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS);
247 }
248 if (firstAttribute != null) {
249 size += firstAttribute.computeAttributesSize(symbolTable);
250 }
251 return size;
252 }
253
254 /**
255 * Puts the content of the field_info JVMS structure generated by this FieldWriter into the given
256 * ByteVector.
257 *
258 * @param output where the field_info structure must be put.
259 */
260 void putFieldInfo(final ByteVector output) {
261 boolean useSyntheticAttribute = symbolTable.getMajorVersion() < Opcodes.V1_5;
262 // Put the access_flags, name_index and descriptor_index fields.
263 int mask = useSyntheticAttribute ? Opcodes.ACC_SYNTHETIC : 0;
264 output.putShort(accessFlags & ~mask).putShort(nameIndex).putShort(descriptorIndex);
265 // Compute and put the attributes_count field.
266 // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS.
267 int attributesCount = 0;
268 if (constantValueIndex != 0) {
269 ++attributesCount;
270 }
271 if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 && useSyntheticAttribute) {
272 ++attributesCount;
273 }
274 if (signatureIndex != 0) {
275 ++attributesCount;
276 }
277 if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) {
278 ++attributesCount;
279 }
280 if (lastRuntimeVisibleAnnotation != null) {
281 ++attributesCount;
282 }
283 if (lastRuntimeInvisibleAnnotation != null) {
284 ++attributesCount;
285 }
286 if (lastRuntimeVisibleTypeAnnotation != null) {
287 ++attributesCount;
288 }
289 if (lastRuntimeInvisibleTypeAnnotation != null) {
290 ++attributesCount;
291 }
292 if (firstAttribute != null) {
293 attributesCount += firstAttribute.getAttributeCount();
294 }
295 output.putShort(attributesCount);
296 // Put the field_info attributes.
297 // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS.
298 if (constantValueIndex != 0) {
299 output
300 .putShort(symbolTable.addConstantUtf8(Constants.CONSTANT_VALUE))
301 .putInt(2)
302 .putShort(constantValueIndex);
303 }
304 if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 && useSyntheticAttribute) {
305 output.putShort(symbolTable.addConstantUtf8(Constants.SYNTHETIC)).putInt(0);
306 }
307 if (signatureIndex != 0) {
308 output
309 .putShort(symbolTable.addConstantUtf8(Constants.SIGNATURE))
310 .putInt(2)
311 .putShort(signatureIndex);
312 }
313 if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) {
314 output.putShort(symbolTable.addConstantUtf8(Constants.DEPRECATED)).putInt(0);
315 }
316 if (lastRuntimeVisibleAnnotation != null) {
317 lastRuntimeVisibleAnnotation.putAnnotations(
318 symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_ANNOTATIONS), output);
319 }
320 if (lastRuntimeInvisibleAnnotation != null) {
321 lastRuntimeInvisibleAnnotation.putAnnotations(
322 symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_ANNOTATIONS), output);
323 }
324 if (lastRuntimeVisibleTypeAnnotation != null) {
325 lastRuntimeVisibleTypeAnnotation.putAnnotations(
326 symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS), output);
327 }
328 if (lastRuntimeInvisibleTypeAnnotation != null) {
329 lastRuntimeInvisibleTypeAnnotation.putAnnotations(
330 symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS), output);
331 }
332 if (firstAttribute != null) {
333 firstAttribute.putAttributes(symbolTable, output);
334 }
335 }
336
337 /**
338 * Collects the attributes of this field into the given set of attribute prototypes.
339 *
340 * @param attributePrototypes a set of attribute prototypes.
341 */
342 final void collectAttributePrototypes(final Attribute.Set attributePrototypes) {
343 attributePrototypes.addAttributes(firstAttribute);
344 }
328345 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
27 package org.eclipse.persistence.internal.libraries.asm;
28
29 /**
30 * The input and output stack map frames of a basic block.
431 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
32 * <p>Stack map frames are computed in two steps:
1633 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 package org.eclipse.persistence.internal.libraries.asm;
30
31 /**
32 * Information about the input and output stack map frames of a basic block.
33 *
34 * <ul>
35 * <li>During the visit of each instruction in MethodWriter, the state of the frame at the end of
36 * the current basic block is updated by simulating the action of the instruction on the
37 * previous state of this so called "output frame".
38 * <li>After all instructions have been visited, a fix point algorithm is used in MethodWriter to
39 * compute the "input frame" of each basic block (i.e. the stack map frame at the beginning of
40 * the basic block). See {@link MethodWriter#computeAllFrames}.
41 * </ul>
42 *
43 * <p>Output stack map frames are computed relatively to the input frame of the basic block, which
44 * is not yet known when output frames are computed. It is therefore necessary to be able to
45 * represent abstract types such as "the type at position x in the input frame locals" or "the type
46 * at position x from the top of the input frame stack" or even "the type at position x in the input
47 * frame, with y more (or less) array dimensions". This explains the rather complicated type format
48 * used in this class, explained below.
49 *
50 * <p>The local variables and the operand stack of input and output frames contain values called
51 * "abstract types" hereafter. An abstract type is represented with 4 fields named DIM, KIND, FLAGS
52 * and VALUE, packed in a single int value for better performance and memory efficiency:
53 *
54 * <pre>
55 * =====================================
56 * |.DIM|KIND|FLAG|...............VALUE|
57 * =====================================
58 * </pre>
59 *
60 * <ul>
61 * <li>the DIM field, stored in the 4 most significant bits, is a signed number of array
62 * dimensions (from -8 to 7, included). It can be retrieved with {@link #DIM_MASK} and a right
63 * shift of {@link #DIM_SHIFT}.
64 * <li>the KIND field, stored in 4 bits, indicates the kind of VALUE used. These 4 bits can be
65 * retrieved with {@link #KIND_MASK} and, without any shift, must be equal to {@link
66 * #CONSTANT_KIND}, {@link #REFERENCE_KIND}, {@link #UNINITIALIZED_KIND}, {@link #LOCAL_KIND}
67 * or {@link #STACK_KIND}.
68 * <li>the FLAGS field, stored in 4 bits, contains up to 4 boolean flags. Currently only one flag
69 * is defined, namely {@link #TOP_IF_LONG_OR_DOUBLE_FLAG}.
70 * <li>the VALUE field, stored in the remaining 20 bits, contains either
71 * <ul>
72 * <li>one of the constants {@link #ITEM_TOP}, {@link #ITEM_ASM_BOOLEAN}, {@link
73 * #ITEM_ASM_BYTE}, {@link #ITEM_ASM_CHAR} or {@link #ITEM_ASM_SHORT}, {@link
74 * #ITEM_INTEGER}, {@link #ITEM_FLOAT}, {@link #ITEM_LONG}, {@link #ITEM_DOUBLE}, {@link
75 * #ITEM_NULL} or {@link #ITEM_UNINITIALIZED_THIS}, if KIND is equal to {@link
76 * #CONSTANT_KIND}.
77 * <li>the index of a {@link Symbol#TYPE_TAG} {@link Symbol} in the type table of a {@link
78 * SymbolTable}, if KIND is equal to {@link #REFERENCE_KIND}.
79 * <li>the index of an {@link Symbol#UNINITIALIZED_TYPE_TAG} {@link Symbol} in the type
80 * table of a SymbolTable, if KIND is equal to {@link #UNINITIALIZED_KIND}.
81 * <li>the index of a local variable in the input stack frame, if KIND is equal to {@link
82 * #LOCAL_KIND}.
83 * <li>a position relatively to the top of the stack of the input stack frame, if KIND is
84 * equal to {@link #STACK_KIND},
85 * </ul>
86 * </ul>
87 *
88 * <p>Output frames can contain abstract types of any kind and with a positive or negative array
89 * dimension (and even unassigned types, represented by 0 - which does not correspond to any valid
90 * abstract type value). Input frames can only contain CONSTANT_KIND, REFERENCE_KIND or
91 * UNINITIALIZED_KIND abstract types of positive or null array dimension. In all cases the type
92 * table contains only internal type names (array type descriptors are forbidden - array dimensions
93 * must be represented through the DIM field).
94 *
95 * <p>The LONG and DOUBLE types are always represented by using two slots (LONG + TOP or DOUBLE +
96 * TOP), for local variables as well as in the operand stack. This is necessary to be able to
97 * simulate DUPx_y instructions, whose effect would be dependent on the concrete types represented
98 * by the abstract types in the stack (which are not always known).
99 *
34100 * @author Eric Bruneton
35101 */
36 final class Frame {
37
38 /*
39 * Frames are computed in a two steps process: during the visit of each
40 * instruction, the state of the frame at the end of current basic block is
41 * updated by simulating the action of the instruction on the previous state
42 * of this so called "output frame". In visitMaxs, a fix point algorithm is
43 * used to compute the "input frame" of each basic block, i.e. the stack map
44 * frame at the beginning of the basic block, starting from the input frame
45 * of the first basic block (which is computed from the method descriptor),
46 * and by using the previously computed output frames to compute the input
47 * state of the other blocks.
48 *
49 * All output and input frames are stored as arrays of integers. Reference
50 * and array types are represented by an index into a type table (which is
51 * not the same as the constant pool of the class, in order to avoid adding
52 * unnecessary constants in the pool - not all computed frames will end up
53 * being stored in the stack map table). This allows very fast type
54 * comparisons.
55 *
56 * Output stack map frames are computed relatively to the input frame of the
57 * basic block, which is not yet known when output frames are computed. It
58 * is therefore necessary to be able to represent abstract types such as
59 * "the type at position x in the input frame locals" or "the type at
60 * position x from the top of the input frame stack" or even "the type at
61 * position x in the input frame, with y more (or less) array dimensions".
62 * This explains the rather complicated type format used in output frames.
63 *
64 * This format is the following: DIM KIND VALUE (4, 4 and 24 bits). DIM is a
65 * signed number of array dimensions (from -8 to 7). KIND is either BASE,
66 * LOCAL or STACK. BASE is used for types that are not relative to the input
67 * frame. LOCAL is used for types that are relative to the input local
68 * variable types. STACK is used for types that are relative to the input
69 * stack types. VALUE depends on KIND. For LOCAL types, it is an index in
70 * the input local variable types. For STACK types, it is a position
71 * relatively to the top of input frame stack. For BASE types, it is either
72 * one of the constants defined below, or for OBJECT and UNINITIALIZED
73 * types, a tag and an index in the type table.
74 *
75 * Output frames can contain types of any kind and with a positive or
76 * negative dimension (and even unassigned types, represented by 0 - which
77 * does not correspond to any valid type value). Input frames can only
78 * contain BASE types of positive or null dimension. In all cases the type
79 * table contains only internal type names (array type descriptors are
80 * forbidden - dimensions must be represented through the DIM field).
81 *
82 * The LONG and DOUBLE types are always represented by using two slots (LONG
83 * + TOP or DOUBLE + TOP), for local variable types as well as in the
84 * operand stack. This is necessary to be able to simulate DUPx_y
85 * instructions, whose effect would be dependent on the actual type values
86 * if types were always represented by a single slot in the stack (and this
87 * is not possible, since actual type values are not always known - cf LOCAL
88 * and STACK type kinds).
89 */
90
91 /**
92 * Mask to get the dimension of a frame type. This dimension is a signed
93 * integer between -8 and 7.
94 */
95 static final int DIM = 0xF0000000;
96
97 /**
98 * Constant to be added to a type to get a type with one more dimension.
99 */
100 static final int ARRAY_OF = 0x10000000;
101
102 /**
103 * Constant to be added to a type to get a type with one less dimension.
104 */
105 static final int ELEMENT_OF = 0xF0000000;
106
107 /**
108 * Mask to get the kind of a frame type.
109 *
110 * @see #BASE
111 * @see #LOCAL
112 * @see #STACK
113 */
114 static final int KIND = 0xF000000;
115
116 /**
117 * Flag used for LOCAL and STACK types. Indicates that if this type happens
118 * to be a long or double type (during the computations of input frames),
119 * then it must be set to TOP because the second word of this value has been
120 * reused to store other data in the basic block. Hence the first word no
121 * longer stores a valid long or double value.
122 */
123 static final int TOP_IF_LONG_OR_DOUBLE = 0x800000;
124
125 /**
126 * Mask to get the value of a frame type.
127 */
128 static final int VALUE = 0x7FFFFF;
129
130 /**
131 * Mask to get the kind of base types.
132 */
133 static final int BASE_KIND = 0xFF00000;
134
135 /**
136 * Mask to get the value of base types.
137 */
138 static final int BASE_VALUE = 0xFFFFF;
139
140 /**
141 * Kind of the types that are not relative to an input stack map frame.
142 */
143 static final int BASE = 0x1000000;
144
145 /**
146 * Base kind of the base reference types. The BASE_VALUE of such types is an
147 * index into the type table.
148 */
149 static final int OBJECT = BASE | 0x700000;
150
151 /**
152 * Base kind of the uninitialized base types. The BASE_VALUE of such types
153 * in an index into the type table (the Item at that index contains both an
154 * instruction offset and an internal class name).
155 */
156 static final int UNINITIALIZED = BASE | 0x800000;
157
158 /**
159 * Kind of the types that are relative to the local variable types of an
160 * input stack map frame. The value of such types is a local variable index.
161 */
162 private static final int LOCAL = 0x2000000;
163
164 /**
165 * Kind of the the types that are relative to the stack of an input stack
166 * map frame. The value of such types is a position relatively to the top of
167 * this stack.
168 */
169 private static final int STACK = 0x3000000;
170
171 /**
172 * The TOP type. This is a BASE type.
173 */
174 static final int TOP = BASE | 0;
175
176 /**
177 * The BOOLEAN type. This is a BASE type mainly used for array types.
178 */
179 static final int BOOLEAN = BASE | 9;
180
181 /**
182 * The BYTE type. This is a BASE type mainly used for array types.
183 */
184 static final int BYTE = BASE | 10;
185
186 /**
187 * The CHAR type. This is a BASE type mainly used for array types.
188 */
189 static final int CHAR = BASE | 11;
190
191 /**
192 * The SHORT type. This is a BASE type mainly used for array types.
193 */
194 static final int SHORT = BASE | 12;
195
196 /**
197 * The INTEGER type. This is a BASE type.
198 */
199 static final int INTEGER = BASE | 1;
200
201 /**
202 * The FLOAT type. This is a BASE type.
203 */
204 static final int FLOAT = BASE | 2;
205
206 /**
207 * The DOUBLE type. This is a BASE type.
208 */
209 static final int DOUBLE = BASE | 3;
210
211 /**
212 * The LONG type. This is a BASE type.
213 */
214 static final int LONG = BASE | 4;
215
216 /**
217 * The NULL type. This is a BASE type.
218 */
219 static final int NULL = BASE | 5;
220
221 /**
222 * The UNINITIALIZED_THIS type. This is a BASE type.
223 */
224 static final int UNINITIALIZED_THIS = BASE | 6;
225
226 /**
227 * The stack size variation corresponding to each JVM instruction. This
228 * stack variation is equal to the size of the values produced by an
229 * instruction, minus the size of the values consumed by this instruction.
230 */
231 static final int[] SIZE;
232
233 /**
234 * Computes the stack size variation corresponding to each JVM instruction.
235 */
236 static {
237 int i;
238 int[] b = new int[202];
239 String s = "EFFFFFFFFGGFFFGGFFFEEFGFGFEEEEEEEEEEEEEEEEEEEEDEDEDDDDD"
240 + "CDCDEEEEEEEEEEEEEEEEEEEEBABABBBBDCFFFGGGEDCDCDCDCDCDCDCDCD"
241 + "CDCEEEEDDDDDDDCDCDCEFEFDDEEFFDEDEEEBDDBBDDDDDDCCCCCCCCEFED"
242 + "DDCDCDEEEEEEEEEEFEEEEEEDDEEDDEE";
243 for (i = 0; i < b.length; ++i) {
244 b[i] = s.charAt(i) - 'E';
245 }
246 SIZE = b;
247
248 // code to generate the above string
249 //
250 // int NA = 0; // not applicable (unused opcode or variable size opcode)
251 //
252 // b = new int[] {
253 // 0, //NOP, // visitInsn
254 // 1, //ACONST_NULL, // -
255 // 1, //ICONST_M1, // -
256 // 1, //ICONST_0, // -
257 // 1, //ICONST_1, // -
258 // 1, //ICONST_2, // -
259 // 1, //ICONST_3, // -
260 // 1, //ICONST_4, // -
261 // 1, //ICONST_5, // -
262 // 2, //LCONST_0, // -
263 // 2, //LCONST_1, // -
264 // 1, //FCONST_0, // -
265 // 1, //FCONST_1, // -
266 // 1, //FCONST_2, // -
267 // 2, //DCONST_0, // -
268 // 2, //DCONST_1, // -
269 // 1, //BIPUSH, // visitIntInsn
270 // 1, //SIPUSH, // -
271 // 1, //LDC, // visitLdcInsn
272 // NA, //LDC_W, // -
273 // NA, //LDC2_W, // -
274 // 1, //ILOAD, // visitVarInsn
275 // 2, //LLOAD, // -
276 // 1, //FLOAD, // -
277 // 2, //DLOAD, // -
278 // 1, //ALOAD, // -
279 // NA, //ILOAD_0, // -
280 // NA, //ILOAD_1, // -
281 // NA, //ILOAD_2, // -
282 // NA, //ILOAD_3, // -
283 // NA, //LLOAD_0, // -
284 // NA, //LLOAD_1, // -
285 // NA, //LLOAD_2, // -
286 // NA, //LLOAD_3, // -
287 // NA, //FLOAD_0, // -
288 // NA, //FLOAD_1, // -
289 // NA, //FLOAD_2, // -
290 // NA, //FLOAD_3, // -
291 // NA, //DLOAD_0, // -
292 // NA, //DLOAD_1, // -
293 // NA, //DLOAD_2, // -
294 // NA, //DLOAD_3, // -
295 // NA, //ALOAD_0, // -
296 // NA, //ALOAD_1, // -
297 // NA, //ALOAD_2, // -
298 // NA, //ALOAD_3, // -
299 // -1, //IALOAD, // visitInsn
300 // 0, //LALOAD, // -
301 // -1, //FALOAD, // -
302 // 0, //DALOAD, // -
303 // -1, //AALOAD, // -
304 // -1, //BALOAD, // -
305 // -1, //CALOAD, // -
306 // -1, //SALOAD, // -
307 // -1, //ISTORE, // visitVarInsn
308 // -2, //LSTORE, // -
309 // -1, //FSTORE, // -
310 // -2, //DSTORE, // -
311 // -1, //ASTORE, // -
312 // NA, //ISTORE_0, // -
313 // NA, //ISTORE_1, // -
314 // NA, //ISTORE_2, // -
315 // NA, //ISTORE_3, // -
316 // NA, //LSTORE_0, // -
317 // NA, //LSTORE_1, // -
318 // NA, //LSTORE_2, // -
319 // NA, //LSTORE_3, // -
320 // NA, //FSTORE_0, // -
321 // NA, //FSTORE_1, // -
322 // NA, //FSTORE_2, // -
323 // NA, //FSTORE_3, // -
324 // NA, //DSTORE_0, // -
325 // NA, //DSTORE_1, // -
326 // NA, //DSTORE_2, // -
327 // NA, //DSTORE_3, // -
328 // NA, //ASTORE_0, // -
329 // NA, //ASTORE_1, // -
330 // NA, //ASTORE_2, // -
331 // NA, //ASTORE_3, // -
332 // -3, //IASTORE, // visitInsn
333 // -4, //LASTORE, // -
334 // -3, //FASTORE, // -
335 // -4, //DASTORE, // -
336 // -3, //AASTORE, // -
337 // -3, //BASTORE, // -
338 // -3, //CASTORE, // -
339 // -3, //SASTORE, // -
340 // -1, //POP, // -
341 // -2, //POP2, // -
342 // 1, //DUP, // -
343 // 1, //DUP_X1, // -
344 // 1, //DUP_X2, // -
345 // 2, //DUP2, // -
346 // 2, //DUP2_X1, // -
347 // 2, //DUP2_X2, // -
348 // 0, //SWAP, // -
349 // -1, //IADD, // -
350 // -2, //LADD, // -
351 // -1, //FADD, // -
352 // -2, //DADD, // -
353 // -1, //ISUB, // -
354 // -2, //LSUB, // -
355 // -1, //FSUB, // -
356 // -2, //DSUB, // -
357 // -1, //IMUL, // -
358 // -2, //LMUL, // -
359 // -1, //FMUL, // -
360 // -2, //DMUL, // -
361 // -1, //IDIV, // -
362 // -2, //LDIV, // -
363 // -1, //FDIV, // -
364 // -2, //DDIV, // -
365 // -1, //IREM, // -
366 // -2, //LREM, // -
367 // -1, //FREM, // -
368 // -2, //DREM, // -
369 // 0, //INEG, // -
370 // 0, //LNEG, // -
371 // 0, //FNEG, // -
372 // 0, //DNEG, // -
373 // -1, //ISHL, // -
374 // -1, //LSHL, // -
375 // -1, //ISHR, // -
376 // -1, //LSHR, // -
377 // -1, //IUSHR, // -
378 // -1, //LUSHR, // -
379 // -1, //IAND, // -
380 // -2, //LAND, // -
381 // -1, //IOR, // -
382 // -2, //LOR, // -
383 // -1, //IXOR, // -
384 // -2, //LXOR, // -
385 // 0, //IINC, // visitIincInsn
386 // 1, //I2L, // visitInsn
387 // 0, //I2F, // -
388 // 1, //I2D, // -
389 // -1, //L2I, // -
390 // -1, //L2F, // -
391 // 0, //L2D, // -
392 // 0, //F2I, // -
393 // 1, //F2L, // -
394 // 1, //F2D, // -
395 // -1, //D2I, // -
396 // 0, //D2L, // -
397 // -1, //D2F, // -
398 // 0, //I2B, // -
399 // 0, //I2C, // -
400 // 0, //I2S, // -
401 // -3, //LCMP, // -
402 // -1, //FCMPL, // -
403 // -1, //FCMPG, // -
404 // -3, //DCMPL, // -
405 // -3, //DCMPG, // -
406 // -1, //IFEQ, // visitJumpInsn
407 // -1, //IFNE, // -
408 // -1, //IFLT, // -
409 // -1, //IFGE, // -
410 // -1, //IFGT, // -
411 // -1, //IFLE, // -
412 // -2, //IF_ICMPEQ, // -
413 // -2, //IF_ICMPNE, // -
414 // -2, //IF_ICMPLT, // -
415 // -2, //IF_ICMPGE, // -
416 // -2, //IF_ICMPGT, // -
417 // -2, //IF_ICMPLE, // -
418 // -2, //IF_ACMPEQ, // -
419 // -2, //IF_ACMPNE, // -
420 // 0, //GOTO, // -
421 // 1, //JSR, // -
422 // 0, //RET, // visitVarInsn
423 // -1, //TABLESWITCH, // visiTableSwitchInsn
424 // -1, //LOOKUPSWITCH, // visitLookupSwitch
425 // -1, //IRETURN, // visitInsn
426 // -2, //LRETURN, // -
427 // -1, //FRETURN, // -
428 // -2, //DRETURN, // -
429 // -1, //ARETURN, // -
430 // 0, //RETURN, // -
431 // NA, //GETSTATIC, // visitFieldInsn
432 // NA, //PUTSTATIC, // -
433 // NA, //GETFIELD, // -
434 // NA, //PUTFIELD, // -
435 // NA, //INVOKEVIRTUAL, // visitMethodInsn
436 // NA, //INVOKESPECIAL, // -
437 // NA, //INVOKESTATIC, // -
438 // NA, //INVOKEINTERFACE, // -
439 // NA, //INVOKEDYNAMIC, // visitInvokeDynamicInsn
440 // 1, //NEW, // visitTypeInsn
441 // 0, //NEWARRAY, // visitIntInsn
442 // 0, //ANEWARRAY, // visitTypeInsn
443 // 0, //ARRAYLENGTH, // visitInsn
444 // NA, //ATHROW, // -
445 // 0, //CHECKCAST, // visitTypeInsn
446 // 0, //INSTANCEOF, // -
447 // -1, //MONITORENTER, // visitInsn
448 // -1, //MONITOREXIT, // -
449 // NA, //WIDE, // NOT VISITED
450 // NA, //MULTIANEWARRAY, // visitMultiANewArrayInsn
451 // -1, //IFNULL, // visitJumpInsn
452 // -1, //IFNONNULL, // -
453 // NA, //GOTO_W, // -
454 // NA, //JSR_W, // -
455 // };
456 // for (i = 0; i < b.length; ++i) {
457 // System.err.print((char)('E' + b[i]));
458 // }
459 // System.err.println();
460 }
461
462 /**
463 * The label (i.e. basic block) to which these input and output stack map
464 * frames correspond.
465 */
466 Label owner;
467
468 /**
469 * The input stack map frame locals.
470 */
471 int[] inputLocals;
472
473 /**
474 * The input stack map frame stack.
475 */
476 int[] inputStack;
477
478 /**
479 * The output stack map frame locals.
480 */
481 private int[] outputLocals;
482
483 /**
484 * The output stack map frame stack.
485 */
486 private int[] outputStack;
487
488 /**
489 * Relative size of the output stack. The exact semantics of this field
490 * depends on the algorithm that is used.
491 *
492 * When only the maximum stack size is computed, this field is the size of
493 * the output stack relatively to the top of the input stack.
494 *
495 * When the stack map frames are completely computed, this field is the
496 * actual number of types in {@link #outputStack}.
497 */
498 private int outputStackTop;
499
500 /**
501 * Number of types that are initialized in the basic block.
502 *
503 * @see #initializations
504 */
505 private int initializationCount;
506
507 /**
508 * The types that are initialized in the basic block. A constructor
509 * invocation on an UNINITIALIZED or UNINITIALIZED_THIS type must replace
510 * <i>every occurence</i> of this type in the local variables and in the
511 * operand stack. This cannot be done during the first phase of the
512 * algorithm since, during this phase, the local variables and the operand
513 * stack are not completely computed. It is therefore necessary to store the
514 * types on which constructors are invoked in the basic block, in order to
515 * do this replacement during the second phase of the algorithm, where the
516 * frames are fully computed. Note that this array can contain types that
517 * are relative to input locals or to the input stack (see below for the
518 * description of the algorithm).
519 */
520 private int[] initializations;
521
522 /**
523 * Returns the output frame local variable type at the given index.
524 *
525 * @param local
526 * the index of the local that must be returned.
527 * @return the output frame local variable type at the given index.
528 */
529 private int get(final int local) {
530 if (outputLocals == null || local >= outputLocals.length) {
531 // this local has never been assigned in this basic block,
532 // so it is still equal to its value in the input frame
533 return LOCAL | local;
534 } else {
535 int type = outputLocals[local];
536 if (type == 0) {
537 // this local has never been assigned in this basic block,
538 // so it is still equal to its value in the input frame
539 type = outputLocals[local] = LOCAL | local;
540 }
541 return type;
542 }
543 }
544
545 /**
546 * Sets the output frame local variable type at the given index.
547 *
548 * @param local
549 * the index of the local that must be set.
550 * @param type
551 * the value of the local that must be set.
552 */
553 private void set(final int local, final int type) {
554 // creates and/or resizes the output local variables array if necessary
555 if (outputLocals == null) {
556 outputLocals = new int[10];
557 }
558 int n = outputLocals.length;
559 if (local >= n) {
560 int[] t = new int[Math.max(local + 1, 2 * n)];
561 System.arraycopy(outputLocals, 0, t, 0, n);
562 outputLocals = t;
563 }
564 // sets the local variable
565 outputLocals[local] = type;
566 }
567
568 /**
569 * Pushes a new type onto the output frame stack.
570 *
571 * @param type
572 * the type that must be pushed.
573 */
574 private void push(final int type) {
575 // creates and/or resizes the output stack array if necessary
576 if (outputStack == null) {
577 outputStack = new int[10];
578 }
579 int n = outputStack.length;
580 if (outputStackTop >= n) {
581 int[] t = new int[Math.max(outputStackTop + 1, 2 * n)];
582 System.arraycopy(outputStack, 0, t, 0, n);
583 outputStack = t;
584 }
585 // pushes the type on the output stack
586 outputStack[outputStackTop++] = type;
587 // updates the maximun height reached by the output stack, if needed
588 int top = owner.inputStackTop + outputStackTop;
589 if (top > owner.outputStackMax) {
590 owner.outputStackMax = top;
591 }
592 }
593
594 /**
595 * Pushes a new type onto the output frame stack.
596 *
597 * @param cw
598 * the ClassWriter to which this label belongs.
599 * @param desc
600 * the descriptor of the type to be pushed. Can also be a method
601 * descriptor (in this case this method pushes its return type
602 * onto the output frame stack).
603 */
604 private void push(final ClassWriter cw, final String desc) {
605 int type = type(cw, desc);
606 if (type != 0) {
607 push(type);
608 if (type == LONG || type == DOUBLE) {
609 push(TOP);
610 }
611 }
612 }
613
614 /**
615 * Returns the int encoding of the given type.
616 *
617 * @param cw
618 * the ClassWriter to which this label belongs.
619 * @param desc
620 * a type descriptor.
621 * @return the int encoding of the given type.
622 */
623 private static int type(final ClassWriter cw, final String desc) {
624 String t;
625 int index = desc.charAt(0) == '(' ? desc.indexOf(')') + 1 : 0;
626 switch (desc.charAt(index)) {
627 case 'V':
628 return 0;
629 case 'Z':
630 case 'C':
631 case 'B':
632 case 'S':
633 case 'I':
634 return INTEGER;
635 case 'F':
636 return FLOAT;
637 case 'J':
638 return LONG;
639 case 'D':
640 return DOUBLE;
641 case 'L':
642 // stores the internal name, not the descriptor!
643 t = desc.substring(index + 1, desc.length() - 1);
644 return OBJECT | cw.addType(t);
645 // case '[':
646 default:
647 // extracts the dimensions and the element type
648 int data;
649 int dims = index + 1;
650 while (desc.charAt(dims) == '[') {
651 ++dims;
652 }
653 switch (desc.charAt(dims)) {
654 case 'Z':
655 data = BOOLEAN;
656 break;
657 case 'C':
658 data = CHAR;
659 break;
660 case 'B':
661 data = BYTE;
662 break;
663 case 'S':
664 data = SHORT;
665 break;
666 case 'I':
667 data = INTEGER;
668 break;
669 case 'F':
670 data = FLOAT;
671 break;
672 case 'J':
673 data = LONG;
674 break;
675 case 'D':
676 data = DOUBLE;
677 break;
678 // case 'L':
679 default:
680 // stores the internal name, not the descriptor
681 t = desc.substring(dims + 1, desc.length() - 1);
682 data = OBJECT | cw.addType(t);
683 }
684 return (dims - index) << 28 | data;
685 }
686 }
687
688 /**
689 * Pops a type from the output frame stack and returns its value.
690 *
691 * @return the type that has been popped from the output frame stack.
692 */
693 private int pop() {
694 if (outputStackTop > 0) {
695 return outputStack[--outputStackTop];
696 } else {
697 // if the output frame stack is empty, pops from the input stack
698 return STACK | -(--owner.inputStackTop);
699 }
700 }
701
702 /**
703 * Pops the given number of types from the output frame stack.
704 *
705 * @param elements
706 * the number of types that must be popped.
707 */
708 private void pop(final int elements) {
709 if (outputStackTop >= elements) {
710 outputStackTop -= elements;
711 } else {
712 // if the number of elements to be popped is greater than the number
713 // of elements in the output stack, clear it, and pops the remaining
714 // elements from the input stack.
715 owner.inputStackTop -= elements - outputStackTop;
716 outputStackTop = 0;
717 }
718 }
719
720 /**
721 * Pops a type from the output frame stack.
722 *
723 * @param desc
724 * the descriptor of the type to be popped. Can also be a method
725 * descriptor (in this case this method pops the types
726 * corresponding to the method arguments).
727 */
728 private void pop(final String desc) {
729 char c = desc.charAt(0);
730 if (c == '(') {
731 pop((Type.getArgumentsAndReturnSizes(desc) >> 2) - 1);
732 } else if (c == 'J' || c == 'D') {
733 pop(2);
734 } else {
735 pop(1);
736 }
737 }
738
739 /**
740 * Adds a new type to the list of types on which a constructor is invoked in
741 * the basic block.
742 *
743 * @param var
744 * a type on a which a constructor is invoked.
745 */
746 private void init(final int var) {
747 // creates and/or resizes the initializations array if necessary
748 if (initializations == null) {
749 initializations = new int[2];
750 }
751 int n = initializations.length;
752 if (initializationCount >= n) {
753 int[] t = new int[Math.max(initializationCount + 1, 2 * n)];
754 System.arraycopy(initializations, 0, t, 0, n);
755 initializations = t;
756 }
757 // stores the type to be initialized
758 initializations[initializationCount++] = var;
759 }
760
761 /**
762 * Replaces the given type with the appropriate type if it is one of the
763 * types on which a constructor is invoked in the basic block.
764 *
765 * @param cw
766 * the ClassWriter to which this label belongs.
767 * @param t
768 * a type
769 * @return t or, if t is one of the types on which a constructor is invoked
770 * in the basic block, the type corresponding to this constructor.
771 */
772 private int init(final ClassWriter cw, final int t) {
773 int s;
774 if (t == UNINITIALIZED_THIS) {
775 s = OBJECT | cw.addType(cw.thisName);
776 } else if ((t & (DIM | BASE_KIND)) == UNINITIALIZED) {
777 String type = cw.typeTable[t & BASE_VALUE].strVal1;
778 s = OBJECT | cw.addType(type);
779 } else {
780 return t;
781 }
782 for (int j = 0; j < initializationCount; ++j) {
783 int u = initializations[j];
784 int dim = u & DIM;
785 int kind = u & KIND;
786 if (kind == LOCAL) {
787 u = dim + inputLocals[u & VALUE];
788 } else if (kind == STACK) {
789 u = dim + inputStack[inputStack.length - (u & VALUE)];
790 }
791 if (t == u) {
792 return s;
793 }
794 }
795 return t;
796 }
797
798 /**
799 * Initializes the input frame of the first basic block from the method
800 * descriptor.
801 *
802 * @param cw
803 * the ClassWriter to which this label belongs.
804 * @param access
805 * the access flags of the method to which this label belongs.
806 * @param args
807 * the formal parameter types of this method.
808 * @param maxLocals
809 * the maximum number of local variables of this method.
810 */
811 void initInputFrame(final ClassWriter cw, final int access,
812 final Type[] args, final int maxLocals) {
813 inputLocals = new int[maxLocals];
814 inputStack = new int[0];
815 int i = 0;
816 if ((access & Opcodes.ACC_STATIC) == 0) {
817 if ((access & MethodWriter.ACC_CONSTRUCTOR) == 0) {
818 inputLocals[i++] = OBJECT | cw.addType(cw.thisName);
819 } else {
820 inputLocals[i++] = UNINITIALIZED_THIS;
821 }
822 }
823 for (int j = 0; j < args.length; ++j) {
824 int t = type(cw, args[j].getDescriptor());
825 inputLocals[i++] = t;
826 if (t == LONG || t == DOUBLE) {
827 inputLocals[i++] = TOP;
828 }
829 }
830 while (i < maxLocals) {
831 inputLocals[i++] = TOP;
832 }
833 }
834
835 /**
836 * Simulates the action of the given instruction on the output stack frame.
837 *
838 * @param opcode
839 * the opcode of the instruction.
840 * @param arg
841 * the operand of the instruction, if any.
842 * @param cw
843 * the class writer to which this label belongs.
844 * @param item
845 * the operand of the instructions, if any.
846 */
847 void execute(final int opcode, final int arg, final ClassWriter cw,
848 final Item item) {
849 int t1, t2, t3, t4;
850 switch (opcode) {
851 case Opcodes.NOP:
852 case Opcodes.INEG:
853 case Opcodes.LNEG:
854 case Opcodes.FNEG:
855 case Opcodes.DNEG:
856 case Opcodes.I2B:
857 case Opcodes.I2C:
858 case Opcodes.I2S:
859 case Opcodes.GOTO:
860 case Opcodes.RETURN:
861 break;
862 case Opcodes.ACONST_NULL:
863 push(NULL);
864 break;
865 case Opcodes.ICONST_M1:
866 case Opcodes.ICONST_0:
867 case Opcodes.ICONST_1:
868 case Opcodes.ICONST_2:
869 case Opcodes.ICONST_3:
870 case Opcodes.ICONST_4:
871 case Opcodes.ICONST_5:
872 case Opcodes.BIPUSH:
873 case Opcodes.SIPUSH:
874 case Opcodes.ILOAD:
102 class Frame {
103
104 // Constants used in the StackMapTable attribute.
105 // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.4.
106
107 static final int SAME_FRAME = 0;
108 static final int SAME_LOCALS_1_STACK_ITEM_FRAME = 64;
109 static final int RESERVED = 128;
110 static final int SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED = 247;
111 static final int CHOP_FRAME = 248;
112 static final int SAME_FRAME_EXTENDED = 251;
113 static final int APPEND_FRAME = 252;
114 static final int FULL_FRAME = 255;
115
116 static final int ITEM_TOP = 0;
117 static final int ITEM_INTEGER = 1;
118 static final int ITEM_FLOAT = 2;
119 static final int ITEM_DOUBLE = 3;
120 static final int ITEM_LONG = 4;
121 static final int ITEM_NULL = 5;
122 static final int ITEM_UNINITIALIZED_THIS = 6;
123 static final int ITEM_OBJECT = 7;
124 static final int ITEM_UNINITIALIZED = 8;
125 // Additional, ASM specific constants used in abstract types below.
126 private static final int ITEM_ASM_BOOLEAN = 9;
127 private static final int ITEM_ASM_BYTE = 10;
128 private static final int ITEM_ASM_CHAR = 11;
129 private static final int ITEM_ASM_SHORT = 12;
130
131 // Bitmasks to get each field of an abstract type.
132
133 private static final int DIM_MASK = 0xF0000000;
134 private static final int KIND_MASK = 0x0F000000;
135 private static final int FLAGS_MASK = 0x00F00000;
136 private static final int VALUE_MASK = 0x000FFFFF;
137
138 // Constants to manipulate the DIM field of an abstract type.
139
140 /** The number of right shift bits to use to get the array dimensions of an abstract type. */
141 private static final int DIM_SHIFT = 28;
142
143 /** The constant to be added to an abstract type to get one with one more array dimension. */
144 private static final int ARRAY_OF = +1 << DIM_SHIFT;
145
146 /** The constant to be added to an abstract type to get one with one less array dimension. */
147 private static final int ELEMENT_OF = -1 << DIM_SHIFT;
148
149 // Possible values for the KIND field of an abstract type.
150
151 private static final int CONSTANT_KIND = 0x01000000;
152 private static final int REFERENCE_KIND = 0x02000000;
153 private static final int UNINITIALIZED_KIND = 0x03000000;
154 private static final int LOCAL_KIND = 0x04000000;
155 private static final int STACK_KIND = 0x05000000;
156
157 // Possible flags for the FLAGS field of an abstract type.
158
159 /**
160 * A flag used for LOCAL_KIND and STACK_KIND abstract types, indicating that if the resolved,
161 * concrete type is LONG or DOUBLE, TOP should be used instead (because the value has been
162 * partially overridden with an xSTORE instruction).
163 */
164 private static final int TOP_IF_LONG_OR_DOUBLE_FLAG = 0x00100000 & FLAGS_MASK;
165
166 // Useful predefined abstract types (all the possible CONSTANT_KIND types).
167
168 private static final int TOP = CONSTANT_KIND | ITEM_TOP;
169 private static final int BOOLEAN = CONSTANT_KIND | ITEM_ASM_BOOLEAN;
170 private static final int BYTE = CONSTANT_KIND | ITEM_ASM_BYTE;
171 private static final int CHAR = CONSTANT_KIND | ITEM_ASM_CHAR;
172 private static final int SHORT = CONSTANT_KIND | ITEM_ASM_SHORT;
173 private static final int INTEGER = CONSTANT_KIND | ITEM_INTEGER;
174 private static final int FLOAT = CONSTANT_KIND | ITEM_FLOAT;
175 private static final int LONG = CONSTANT_KIND | ITEM_LONG;
176 private static final int DOUBLE = CONSTANT_KIND | ITEM_DOUBLE;
177 private static final int NULL = CONSTANT_KIND | ITEM_NULL;
178 private static final int UNINITIALIZED_THIS = CONSTANT_KIND | ITEM_UNINITIALIZED_THIS;
179
180 // -----------------------------------------------------------------------------------------------
181 // Instance fields
182 // -----------------------------------------------------------------------------------------------
183
184 /** The basic block to which these input and output stack map frames correspond. */
185 Label owner;
186
187 /** The input stack map frame locals. This is an array of abstract types. */
188 private int[] inputLocals;
189
190 /** The input stack map frame stack. This is an array of abstract types. */
191 private int[] inputStack;
192
193 /** The output stack map frame locals. This is an array of abstract types. */
194 private int[] outputLocals;
195
196 /** The output stack map frame stack. This is an array of abstract types. */
197 private int[] outputStack;
198
199 /**
200 * The start of the output stack, relatively to the input stack. This offset is always negative or
201 * null. A null offset means that the output stack must be appended to the input stack. A -n
202 * offset means that the first n output stack elements must replace the top n input stack
203 * elements, and that the other elements must be appended to the input stack.
204 */
205 private short outputStackStart;
206
207 /** The index of the top stack element in {@link #outputStack}. */
208 private short outputStackTop;
209
210 /** The number of types that are initialized in the basic block. See {@link #initializations}. */
211 private int initializationCount;
212
213 /**
214 * The abstract types that are initialized in the basic block. A constructor invocation on an
215 * UNINITIALIZED or UNINITIALIZED_THIS abstract type must replace <i>every occurrence</i> of this
216 * type in the local variables and in the operand stack. This cannot be done during the first step
217 * of the algorithm since, during this step, the local variables and the operand stack types are
218 * still abstract. It is therefore necessary to store the abstract types of the constructors which
219 * are invoked in the basic block, in order to do this replacement during the second step of the
220 * algorithm, where the frames are fully computed. Note that this array can contain abstract types
221 * that are relative to the input locals or to the input stack.
222 */
223 private int[] initializations;
224
225 // -----------------------------------------------------------------------------------------------
226 // Static methods to get abstract types from other type formats
227 // -----------------------------------------------------------------------------------------------
228
229 /**
230 * Returns the abstract type corresponding to the given public API frame element type.
231 *
232 * @param symbolTable the type table to use to lookup and store type {@link Symbol}.
233 * @param type a frame element type described using the same format as in {@link
234 * MethodVisitor#visitFrame}, i.e. either {@link Opcodes#TOP}, {@link Opcodes#INTEGER}, {@link
235 * Opcodes#FLOAT}, {@link Opcodes#LONG}, {@link Opcodes#DOUBLE}, {@link Opcodes#NULL}, or
236 * {@link Opcodes#UNINITIALIZED_THIS}, or the internal name of a class, or a Label designating
237 * a NEW instruction (for uninitialized types).
238 * @return the abstract type corresponding to the given frame element type.
239 */
240 static int getAbstractTypeFromApiFormat(final SymbolTable symbolTable, final Object type) {
241 if (type instanceof Integer) {
242 return CONSTANT_KIND | ((Integer) type).intValue();
243 } else if (type instanceof String) {
244 String descriptor = Type.getObjectType((String) type).getDescriptor();
245 return getAbstractTypeFromDescriptor(symbolTable, descriptor, 0);
246 } else {
247 return UNINITIALIZED_KIND
248 | symbolTable.addUninitializedType("", ((Label) type).bytecodeOffset);
249 }
250 }
251
252 /**
253 * Returns the abstract type corresponding to the internal name of a class.
254 *
255 * @param symbolTable the type table to use to lookup and store type {@link Symbol}.
256 * @param internalName the internal name of a class. This must <i>not</i> be an array type
257 * descriptor.
258 * @return the abstract type value corresponding to the given internal name.
259 */
260 static int getAbstractTypeFromInternalName(
261 final SymbolTable symbolTable, final String internalName) {
262 return REFERENCE_KIND | symbolTable.addType(internalName);
263 }
264
265 /**
266 * Returns the abstract type corresponding to the given type descriptor.
267 *
268 * @param symbolTable the type table to use to lookup and store type {@link Symbol}.
269 * @param buffer a string ending with a type descriptor.
270 * @param offset the start offset of the type descriptor in buffer.
271 * @return the abstract type corresponding to the given type descriptor.
272 */
273 private static int getAbstractTypeFromDescriptor(
274 final SymbolTable symbolTable, final String buffer, final int offset) {
275 String internalName;
276 switch (buffer.charAt(offset)) {
277 case 'V':
278 return 0;
279 case 'Z':
280 case 'C':
281 case 'B':
282 case 'S':
283 case 'I':
284 return INTEGER;
285 case 'F':
286 return FLOAT;
287 case 'J':
288 return LONG;
289 case 'D':
290 return DOUBLE;
291 case 'L':
292 internalName = buffer.substring(offset + 1, buffer.length() - 1);
293 return REFERENCE_KIND | symbolTable.addType(internalName);
294 case '[':
295 int elementDescriptorOffset = offset + 1;
296 while (buffer.charAt(elementDescriptorOffset) == '[') {
297 ++elementDescriptorOffset;
298 }
299 int typeValue;
300 switch (buffer.charAt(elementDescriptorOffset)) {
301 case 'Z':
302 typeValue = BOOLEAN;
303 break;
304 case 'C':
305 typeValue = CHAR;
306 break;
307 case 'B':
308 typeValue = BYTE;
309 break;
310 case 'S':
311 typeValue = SHORT;
312 break;
313 case 'I':
314 typeValue = INTEGER;
315 break;
316 case 'F':
317 typeValue = FLOAT;
318 break;
319 case 'J':
320 typeValue = LONG;
321 break;
322 case 'D':
323 typeValue = DOUBLE;
324 break;
325 case 'L':
326 internalName = buffer.substring(elementDescriptorOffset + 1, buffer.length() - 1);
327 typeValue = REFERENCE_KIND | symbolTable.addType(internalName);
328 break;
329 default:
330 throw new IllegalArgumentException();
331 }
332 return ((elementDescriptorOffset - offset) << DIM_SHIFT) | typeValue;
333 default:
334 throw new IllegalArgumentException();
335 }
336 }
337
338 // -----------------------------------------------------------------------------------------------
339 // Constructor
340 // -----------------------------------------------------------------------------------------------
341
342 /**
343 * Constructs a new Frame.
344 *
345 * @param owner the basic block to which these input and output stack map frames correspond.
346 */
347 Frame(final Label owner) {
348 this.owner = owner;
349 }
350
351 /**
352 * Sets this frame to the value of the given frame.
353 *
354 * <p>WARNING: after this method is called the two frames share the same data structures. It is
355 * recommended to discard the given frame to avoid unexpected side effects.
356 *
357 * @param frame The new frame value.
358 */
359 final void copyFrom(final Frame frame) {
360 inputLocals = frame.inputLocals;
361 inputStack = frame.inputStack;
362 outputStackStart = 0;
363 outputLocals = frame.outputLocals;
364 outputStack = frame.outputStack;
365 outputStackTop = frame.outputStackTop;
366 initializationCount = frame.initializationCount;
367 initializations = frame.initializations;
368 }
369
370 // -----------------------------------------------------------------------------------------------
371 // Methods related to the input frame
372 // -----------------------------------------------------------------------------------------------
373
374 /**
375 * Sets the input frame from the given method description. This method is used to initialize the
376 * first frame of a method, which is implicit (i.e. not stored explicitly in the StackMapTable
377 * attribute).
378 *
379 * @param symbolTable the type table to use to lookup and store type {@link Symbol}.
380 * @param access the method's access flags.
381 * @param descriptor the method descriptor.
382 * @param maxLocals the maximum number of local variables of the method.
383 */
384 final void setInputFrameFromDescriptor(
385 final SymbolTable symbolTable,
386 final int access,
387 final String descriptor,
388 final int maxLocals) {
389 inputLocals = new int[maxLocals];
390 inputStack = new int[0];
391 int inputLocalIndex = 0;
392 if ((access & Opcodes.ACC_STATIC) == 0) {
393 if ((access & Constants.ACC_CONSTRUCTOR) == 0) {
394 inputLocals[inputLocalIndex++] =
395 REFERENCE_KIND | symbolTable.addType(symbolTable.getClassName());
396 } else {
397 inputLocals[inputLocalIndex++] = UNINITIALIZED_THIS;
398 }
399 }
400 for (Type argumentType : Type.getArgumentTypes(descriptor)) {
401 int abstractType =
402 getAbstractTypeFromDescriptor(symbolTable, argumentType.getDescriptor(), 0);
403 inputLocals[inputLocalIndex++] = abstractType;
404 if (abstractType == LONG || abstractType == DOUBLE) {
405 inputLocals[inputLocalIndex++] = TOP;
406 }
407 }
408 while (inputLocalIndex < maxLocals) {
409 inputLocals[inputLocalIndex++] = TOP;
410 }
411 }
412
413 /**
414 * Sets the input frame from the given public API frame description.
415 *
416 * @param symbolTable the type table to use to lookup and store type {@link Symbol}.
417 * @param nLocal the number of local variables.
418 * @param local the local variable types, described using the same format as in {@link
419 * MethodVisitor#visitFrame}.
420 * @param nStack the number of operand stack elements.
421 * @param stack the operand stack types, described using the same format as in {@link
422 * MethodVisitor#visitFrame}.
423 */
424 final void setInputFrameFromApiFormat(
425 final SymbolTable symbolTable,
426 final int nLocal,
427 final Object[] local,
428 final int nStack,
429 final Object[] stack) {
430 int inputLocalIndex = 0;
431 for (int i = 0; i < nLocal; ++i) {
432 inputLocals[inputLocalIndex++] = getAbstractTypeFromApiFormat(symbolTable, local[i]);
433 if (local[i] == Opcodes.LONG || local[i] == Opcodes.DOUBLE) {
434 inputLocals[inputLocalIndex++] = TOP;
435 }
436 }
437 while (inputLocalIndex < inputLocals.length) {
438 inputLocals[inputLocalIndex++] = TOP;
439 }
440 int nStackTop = 0;
441 for (int i = 0; i < nStack; ++i) {
442 if (stack[i] == Opcodes.LONG || stack[i] == Opcodes.DOUBLE) {
443 ++nStackTop;
444 }
445 }
446 inputStack = new int[nStack + nStackTop];
447 int inputStackIndex = 0;
448 for (int i = 0; i < nStack; ++i) {
449 inputStack[inputStackIndex++] = getAbstractTypeFromApiFormat(symbolTable, stack[i]);
450 if (stack[i] == Opcodes.LONG || stack[i] == Opcodes.DOUBLE) {
451 inputStack[inputStackIndex++] = TOP;
452 }
453 }
454 outputStackTop = 0;
455 initializationCount = 0;
456 }
457
458 final int getInputStackSize() {
459 return inputStack.length;
460 }
461
462 // -----------------------------------------------------------------------------------------------
463 // Methods related to the output frame
464 // -----------------------------------------------------------------------------------------------
465
466 /**
467 * Returns the abstract type stored at the given local variable index in the output frame.
468 *
469 * @param localIndex the index of the local variable whose value must be returned.
470 * @return the abstract type stored at the given local variable index in the output frame.
471 */
472 private int getLocal(final int localIndex) {
473 if (outputLocals == null || localIndex >= outputLocals.length) {
474 // If this local has never been assigned in this basic block, it is still equal to its value
475 // in the input frame.
476 return LOCAL_KIND | localIndex;
477 } else {
478 int abstractType = outputLocals[localIndex];
479 if (abstractType == 0) {
480 // If this local has never been assigned in this basic block, so it is still equal to its
481 // value in the input frame.
482 abstractType = outputLocals[localIndex] = LOCAL_KIND | localIndex;
483 }
484 return abstractType;
485 }
486 }
487
488 /**
489 * Replaces the abstract type stored at the given local variable index in the output frame.
490 *
491 * @param localIndex the index of the output frame local variable that must be set.
492 * @param abstractType the value that must be set.
493 */
494 private void setLocal(final int localIndex, final int abstractType) {
495 // Create and/or resize the output local variables array if necessary.
496 if (outputLocals == null) {
497 outputLocals = new int[10];
498 }
499 int outputLocalsLength = outputLocals.length;
500 if (localIndex >= outputLocalsLength) {
501 int[] newOutputLocals = new int[Math.max(localIndex + 1, 2 * outputLocalsLength)];
502 System.arraycopy(outputLocals, 0, newOutputLocals, 0, outputLocalsLength);
503 outputLocals = newOutputLocals;
504 }
505 // Set the local variable.
506 outputLocals[localIndex] = abstractType;
507 }
508
509 /**
510 * Pushes the given abstract type on the output frame stack.
511 *
512 * @param abstractType an abstract type.
513 */
514 private void push(final int abstractType) {
515 // Create and/or resize the output stack array if necessary.
516 if (outputStack == null) {
517 outputStack = new int[10];
518 }
519 int outputStackLength = outputStack.length;
520 if (outputStackTop >= outputStackLength) {
521 int[] newOutputStack = new int[Math.max(outputStackTop + 1, 2 * outputStackLength)];
522 System.arraycopy(outputStack, 0, newOutputStack, 0, outputStackLength);
523 outputStack = newOutputStack;
524 }
525 // Pushes the abstract type on the output stack.
526 outputStack[outputStackTop++] = abstractType;
527 // Updates the maximum size reached by the output stack, if needed (note that this size is
528 // relative to the input stack size, which is not known yet).
529 short outputStackSize = (short) (outputStackStart + outputStackTop);
530 if (outputStackSize > owner.outputStackMax) {
531 owner.outputStackMax = outputStackSize;
532 }
533 }
534
535 /**
536 * Pushes the abstract type corresponding to the given descriptor on the output frame stack.
537 *
538 * @param symbolTable the type table to use to lookup and store type {@link Symbol}.
539 * @param descriptor a type or method descriptor (in which case its return type is pushed).
540 */
541 private void push(final SymbolTable symbolTable, final String descriptor) {
542 int typeDescriptorOffset = descriptor.charAt(0) == '(' ? descriptor.indexOf(')') + 1 : 0;
543 int abstractType = getAbstractTypeFromDescriptor(symbolTable, descriptor, typeDescriptorOffset);
544 if (abstractType != 0) {
545 push(abstractType);
546 if (abstractType == LONG || abstractType == DOUBLE) {
547 push(TOP);
548 }
549 }
550 }
551
552 /**
553 * Pops an abstract type from the output frame stack and returns its value.
554 *
555 * @return the abstract type that has been popped from the output frame stack.
556 */
557 private int pop() {
558 if (outputStackTop > 0) {
559 return outputStack[--outputStackTop];
560 } else {
561 // If the output frame stack is empty, pop from the input stack.
562 return STACK_KIND | -(--outputStackStart);
563 }
564 }
565
566 /**
567 * Pops the given number of abstract types from the output frame stack.
568 *
569 * @param elements the number of abstract types that must be popped.
570 */
571 private void pop(final int elements) {
572 if (outputStackTop >= elements) {
573 outputStackTop -= elements;
574 } else {
575 // If the number of elements to be popped is greater than the number of elements in the output
576 // stack, clear it, and pop the remaining elements from the input stack.
577 outputStackStart -= elements - outputStackTop;
578 outputStackTop = 0;
579 }
580 }
581
582 /**
583 * Pops as many abstract types from the output frame stack as described by the given descriptor.
584 *
585 * @param descriptor a type or method descriptor (in which case its argument types are popped).
586 */
587 private void pop(final String descriptor) {
588 char firstDescriptorChar = descriptor.charAt(0);
589 if (firstDescriptorChar == '(') {
590 pop((Type.getArgumentsAndReturnSizes(descriptor) >> 2) - 1);
591 } else if (firstDescriptorChar == 'J' || firstDescriptorChar == 'D') {
592 pop(2);
593 } else {
594 pop(1);
595 }
596 }
597
598 // -----------------------------------------------------------------------------------------------
599 // Methods to handle uninitialized types
600 // -----------------------------------------------------------------------------------------------
601
602 /**
603 * Adds an abstract type to the list of types on which a constructor is invoked in the basic
604 * block.
605 *
606 * @param abstractType an abstract type on a which a constructor is invoked.
607 */
608 private void addInitializedType(final int abstractType) {
609 // Create and/or resize the initializations array if necessary.
610 if (initializations == null) {
611 initializations = new int[2];
612 }
613 int initializationsLength = initializations.length;
614 if (initializationCount >= initializationsLength) {
615 int[] newInitializations =
616 new int[Math.max(initializationCount + 1, 2 * initializationsLength)];
617 System.arraycopy(initializations, 0, newInitializations, 0, initializationsLength);
618 initializations = newInitializations;
619 }
620 // Store the abstract type.
621 initializations[initializationCount++] = abstractType;
622 }
623
624 /**
625 * Returns the "initialized" abstract type corresponding to the given abstract type.
626 *
627 * @param symbolTable the type table to use to lookup and store type {@link Symbol}.
628 * @param abstractType an abstract type.
629 * @return the REFERENCE_KIND abstract type corresponding to abstractType if it is
630 * UNINITIALIZED_THIS or an UNINITIALIZED_KIND abstract type for one of the types on which a
631 * constructor is invoked in the basic block. Otherwise returns abstractType.
632 */
633 private int getInitializedType(final SymbolTable symbolTable, final int abstractType) {
634 if (abstractType == UNINITIALIZED_THIS
635 || (abstractType & (DIM_MASK | KIND_MASK)) == UNINITIALIZED_KIND) {
636 for (int i = 0; i < initializationCount; ++i) {
637 int initializedType = initializations[i];
638 int dim = initializedType & DIM_MASK;
639 int kind = initializedType & KIND_MASK;
640 int value = initializedType & VALUE_MASK;
641 if (kind == LOCAL_KIND) {
642 initializedType = dim + inputLocals[value];
643 } else if (kind == STACK_KIND) {
644 initializedType = dim + inputStack[inputStack.length - value];
645 }
646 if (abstractType == initializedType) {
647 if (abstractType == UNINITIALIZED_THIS) {
648 return REFERENCE_KIND | symbolTable.addType(symbolTable.getClassName());
649 } else {
650 return REFERENCE_KIND
651 | symbolTable.addType(symbolTable.getType(abstractType & VALUE_MASK).value);
652 }
653 }
654 }
655 }
656 return abstractType;
657 }
658
659 // -----------------------------------------------------------------------------------------------
660 // Main method, to simulate the execution of each instruction on the output frame
661 // -----------------------------------------------------------------------------------------------
662
663 /**
664 * Simulates the action of the given instruction on the output stack frame.
665 *
666 * @param opcode the opcode of the instruction.
667 * @param arg the numeric operand of the instruction, if any.
668 * @param argSymbol the Symbol operand of the instruction, if any.
669 * @param symbolTable the type table to use to lookup and store type {@link Symbol}.
670 */
671 void execute(
672 final int opcode, final int arg, final Symbol argSymbol, final SymbolTable symbolTable) {
673 // Abstract types popped from the stack or read from local variables.
674 int abstractType1;
675 int abstractType2;
676 int abstractType3;
677 int abstractType4;
678 switch (opcode) {
679 case Opcodes.NOP:
680 case Opcodes.INEG:
681 case Opcodes.LNEG:
682 case Opcodes.FNEG:
683 case Opcodes.DNEG:
684 case Opcodes.I2B:
685 case Opcodes.I2C:
686 case Opcodes.I2S:
687 case Opcodes.GOTO:
688 case Opcodes.RETURN:
689 break;
690 case Opcodes.ACONST_NULL:
691 push(NULL);
692 break;
693 case Opcodes.ICONST_M1:
694 case Opcodes.ICONST_0:
695 case Opcodes.ICONST_1:
696 case Opcodes.ICONST_2:
697 case Opcodes.ICONST_3:
698 case Opcodes.ICONST_4:
699 case Opcodes.ICONST_5:
700 case Opcodes.BIPUSH:
701 case Opcodes.SIPUSH:
702 case Opcodes.ILOAD:
703 push(INTEGER);
704 break;
705 case Opcodes.LCONST_0:
706 case Opcodes.LCONST_1:
707 case Opcodes.LLOAD:
708 push(LONG);
709 push(TOP);
710 break;
711 case Opcodes.FCONST_0:
712 case Opcodes.FCONST_1:
713 case Opcodes.FCONST_2:
714 case Opcodes.FLOAD:
715 push(FLOAT);
716 break;
717 case Opcodes.DCONST_0:
718 case Opcodes.DCONST_1:
719 case Opcodes.DLOAD:
720 push(DOUBLE);
721 push(TOP);
722 break;
723 case Opcodes.LDC:
724 switch (argSymbol.tag) {
725 case Symbol.CONSTANT_INTEGER_TAG:
875726 push(INTEGER);
876727 break;
877 case Opcodes.LCONST_0:
878 case Opcodes.LCONST_1:
879 case Opcodes.LLOAD:
728 case Symbol.CONSTANT_LONG_TAG:
880729 push(LONG);
881730 push(TOP);
882731 break;
883 case Opcodes.FCONST_0:
884 case Opcodes.FCONST_1:
885 case Opcodes.FCONST_2:
886 case Opcodes.FLOAD:
732 case Symbol.CONSTANT_FLOAT_TAG:
887733 push(FLOAT);
888734 break;
889 case Opcodes.DCONST_0:
890 case Opcodes.DCONST_1:
891 case Opcodes.DLOAD:
735 case Symbol.CONSTANT_DOUBLE_TAG:
892736 push(DOUBLE);
893737 push(TOP);
894738 break;
895 case Opcodes.LDC:
896 switch (item.type) {
897 case ClassWriter.INT:
898 push(INTEGER);
899 break;
900 case ClassWriter.LONG:
901 push(LONG);
902 push(TOP);
903 break;
904 case ClassWriter.FLOAT:
905 push(FLOAT);
906 break;
907 case ClassWriter.DOUBLE:
908 push(DOUBLE);
909 push(TOP);
910 break;
911 case ClassWriter.CLASS:
912 push(OBJECT | cw.addType("java/lang/Class"));
913 break;
914 case ClassWriter.STR:
915 push(OBJECT | cw.addType("java/lang/String"));
916 break;
917 case ClassWriter.MTYPE:
918 push(OBJECT | cw.addType("java/lang/invoke/MethodType"));
919 break;
920 // case ClassWriter.HANDLE_BASE + [1..9]:
921 default:
922 push(OBJECT | cw.addType("java/lang/invoke/MethodHandle"));
739 case Symbol.CONSTANT_CLASS_TAG:
740 push(REFERENCE_KIND | symbolTable.addType("java/lang/Class"));
741 break;
742 case Symbol.CONSTANT_STRING_TAG:
743 push(REFERENCE_KIND | symbolTable.addType("java/lang/String"));
744 break;
745 case Symbol.CONSTANT_METHOD_TYPE_TAG:
746 push(REFERENCE_KIND | symbolTable.addType("java/lang/invoke/MethodType"));
747 break;
748 case Symbol.CONSTANT_METHOD_HANDLE_TAG:
749 push(REFERENCE_KIND | symbolTable.addType("java/lang/invoke/MethodHandle"));
750 break;
751 case Symbol.CONSTANT_DYNAMIC_TAG:
752 push(symbolTable, argSymbol.value);
753 break;
754 default:
755 throw new AssertionError();
756 }
757 break;
758 case Opcodes.ALOAD:
759 push(getLocal(arg));
760 break;
761 case Opcodes.LALOAD:
762 case Opcodes.D2L:
763 pop(2);
764 push(LONG);
765 push(TOP);
766 break;
767 case Opcodes.DALOAD:
768 case Opcodes.L2D:
769 pop(2);
770 push(DOUBLE);
771 push(TOP);
772 break;
773 case Opcodes.AALOAD:
774 pop(1);
775 abstractType1 = pop();
776 push(abstractType1 == NULL ? abstractType1 : ELEMENT_OF + abstractType1);
777 break;
778 case Opcodes.ISTORE:
779 case Opcodes.FSTORE:
780 case Opcodes.ASTORE:
781 abstractType1 = pop();
782 setLocal(arg, abstractType1);
783 if (arg > 0) {
784 int previousLocalType = getLocal(arg - 1);
785 if (previousLocalType == LONG || previousLocalType == DOUBLE) {
786 setLocal(arg - 1, TOP);
787 } else if ((previousLocalType & KIND_MASK) == LOCAL_KIND
788 || (previousLocalType & KIND_MASK) == STACK_KIND) {
789 // The type of the previous local variable is not known yet, but if it later appears
790 // to be LONG or DOUBLE, we should then use TOP instead.
791 setLocal(arg - 1, previousLocalType | TOP_IF_LONG_OR_DOUBLE_FLAG);
792 }
793 }
794 break;
795 case Opcodes.LSTORE:
796 case Opcodes.DSTORE:
797 pop(1);
798 abstractType1 = pop();
799 setLocal(arg, abstractType1);
800 setLocal(arg + 1, TOP);
801 if (arg > 0) {
802 int previousLocalType = getLocal(arg - 1);
803 if (previousLocalType == LONG || previousLocalType == DOUBLE) {
804 setLocal(arg - 1, TOP);
805 } else if ((previousLocalType & KIND_MASK) == LOCAL_KIND
806 || (previousLocalType & KIND_MASK) == STACK_KIND) {
807 // The type of the previous local variable is not known yet, but if it later appears
808 // to be LONG or DOUBLE, we should then use TOP instead.
809 setLocal(arg - 1, previousLocalType | TOP_IF_LONG_OR_DOUBLE_FLAG);
810 }
811 }
812 break;
813 case Opcodes.IASTORE:
814 case Opcodes.BASTORE:
815 case Opcodes.CASTORE:
816 case Opcodes.SASTORE:
817 case Opcodes.FASTORE:
818 case Opcodes.AASTORE:
819 pop(3);
820 break;
821 case Opcodes.LASTORE:
822 case Opcodes.DASTORE:
823 pop(4);
824 break;
825 case Opcodes.POP:
826 case Opcodes.IFEQ:
827 case Opcodes.IFNE:
828 case Opcodes.IFLT:
829 case Opcodes.IFGE:
830 case Opcodes.IFGT:
831 case Opcodes.IFLE:
832 case Opcodes.IRETURN:
833 case Opcodes.FRETURN:
834 case Opcodes.ARETURN:
835 case Opcodes.TABLESWITCH:
836 case Opcodes.LOOKUPSWITCH:
837 case Opcodes.ATHROW:
838 case Opcodes.MONITORENTER:
839 case Opcodes.MONITOREXIT:
840 case Opcodes.IFNULL:
841 case Opcodes.IFNONNULL:
842 pop(1);
843 break;
844 case Opcodes.POP2:
845 case Opcodes.IF_ICMPEQ:
846 case Opcodes.IF_ICMPNE:
847 case Opcodes.IF_ICMPLT:
848 case Opcodes.IF_ICMPGE:
849 case Opcodes.IF_ICMPGT:
850 case Opcodes.IF_ICMPLE:
851 case Opcodes.IF_ACMPEQ:
852 case Opcodes.IF_ACMPNE:
853 case Opcodes.LRETURN:
854 case Opcodes.DRETURN:
855 pop(2);
856 break;
857 case Opcodes.DUP:
858 abstractType1 = pop();
859 push(abstractType1);
860 push(abstractType1);
861 break;
862 case Opcodes.DUP_X1:
863 abstractType1 = pop();
864 abstractType2 = pop();
865 push(abstractType1);
866 push(abstractType2);
867 push(abstractType1);
868 break;
869 case Opcodes.DUP_X2:
870 abstractType1 = pop();
871 abstractType2 = pop();
872 abstractType3 = pop();
873 push(abstractType1);
874 push(abstractType3);
875 push(abstractType2);
876 push(abstractType1);
877 break;
878 case Opcodes.DUP2:
879 abstractType1 = pop();
880 abstractType2 = pop();
881 push(abstractType2);
882 push(abstractType1);
883 push(abstractType2);
884 push(abstractType1);
885 break;
886 case Opcodes.DUP2_X1:
887 abstractType1 = pop();
888 abstractType2 = pop();
889 abstractType3 = pop();
890 push(abstractType2);
891 push(abstractType1);
892 push(abstractType3);
893 push(abstractType2);
894 push(abstractType1);
895 break;
896 case Opcodes.DUP2_X2:
897 abstractType1 = pop();
898 abstractType2 = pop();
899 abstractType3 = pop();
900 abstractType4 = pop();
901 push(abstractType2);
902 push(abstractType1);
903 push(abstractType4);
904 push(abstractType3);
905 push(abstractType2);
906 push(abstractType1);
907 break;
908 case Opcodes.SWAP:
909 abstractType1 = pop();
910 abstractType2 = pop();
911 push(abstractType1);
912 push(abstractType2);
913 break;
914 case Opcodes.IALOAD:
915 case Opcodes.BALOAD:
916 case Opcodes.CALOAD:
917 case Opcodes.SALOAD:
918 case Opcodes.IADD:
919 case Opcodes.ISUB:
920 case Opcodes.IMUL:
921 case Opcodes.IDIV:
922 case Opcodes.IREM:
923 case Opcodes.IAND:
924 case Opcodes.IOR:
925 case Opcodes.IXOR:
926 case Opcodes.ISHL:
927 case Opcodes.ISHR:
928 case Opcodes.IUSHR:
929 case Opcodes.L2I:
930 case Opcodes.D2I:
931 case Opcodes.FCMPL:
932 case Opcodes.FCMPG:
933 pop(2);
934 push(INTEGER);
935 break;
936 case Opcodes.LADD:
937 case Opcodes.LSUB:
938 case Opcodes.LMUL:
939 case Opcodes.LDIV:
940 case Opcodes.LREM:
941 case Opcodes.LAND:
942 case Opcodes.LOR:
943 case Opcodes.LXOR:
944 pop(4);
945 push(LONG);
946 push(TOP);
947 break;
948 case Opcodes.FALOAD:
949 case Opcodes.FADD:
950 case Opcodes.FSUB:
951 case Opcodes.FMUL:
952 case Opcodes.FDIV:
953 case Opcodes.FREM:
954 case Opcodes.L2F:
955 case Opcodes.D2F:
956 pop(2);
957 push(FLOAT);
958 break;
959 case Opcodes.DADD:
960 case Opcodes.DSUB:
961 case Opcodes.DMUL:
962 case Opcodes.DDIV:
963 case Opcodes.DREM:
964 pop(4);
965 push(DOUBLE);
966 push(TOP);
967 break;
968 case Opcodes.LSHL:
969 case Opcodes.LSHR:
970 case Opcodes.LUSHR:
971 pop(3);
972 push(LONG);
973 push(TOP);
974 break;
975 case Opcodes.IINC:
976 setLocal(arg, INTEGER);
977 break;
978 case Opcodes.I2L:
979 case Opcodes.F2L:
980 pop(1);
981 push(LONG);
982 push(TOP);
983 break;
984 case Opcodes.I2F:
985 pop(1);
986 push(FLOAT);
987 break;
988 case Opcodes.I2D:
989 case Opcodes.F2D:
990 pop(1);
991 push(DOUBLE);
992 push(TOP);
993 break;
994 case Opcodes.F2I:
995 case Opcodes.ARRAYLENGTH:
996 case Opcodes.INSTANCEOF:
997 pop(1);
998 push(INTEGER);
999 break;
1000 case Opcodes.LCMP:
1001 case Opcodes.DCMPL:
1002 case Opcodes.DCMPG:
1003 pop(4);
1004 push(INTEGER);
1005 break;
1006 case Opcodes.JSR:
1007 case Opcodes.RET:
1008 throw new IllegalArgumentException("JSR/RET are not supported with computeFrames option");
1009 case Opcodes.GETSTATIC:
1010 push(symbolTable, argSymbol.value);
1011 break;
1012 case Opcodes.PUTSTATIC:
1013 pop(argSymbol.value);
1014 break;
1015 case Opcodes.GETFIELD:
1016 pop(1);
1017 push(symbolTable, argSymbol.value);
1018 break;
1019 case Opcodes.PUTFIELD:
1020 pop(argSymbol.value);
1021 pop();
1022 break;
1023 case Opcodes.INVOKEVIRTUAL:
1024 case Opcodes.INVOKESPECIAL:
1025 case Opcodes.INVOKESTATIC:
1026 case Opcodes.INVOKEINTERFACE:
1027 pop(argSymbol.value);
1028 if (opcode != Opcodes.INVOKESTATIC) {
1029 abstractType1 = pop();
1030 if (opcode == Opcodes.INVOKESPECIAL && argSymbol.name.charAt(0) == '<') {
1031 addInitializedType(abstractType1);
1032 }
1033 }
1034 push(symbolTable, argSymbol.value);
1035 break;
1036 case Opcodes.INVOKEDYNAMIC:
1037 pop(argSymbol.value);
1038 push(symbolTable, argSymbol.value);
1039 break;
1040 case Opcodes.NEW:
1041 push(UNINITIALIZED_KIND | symbolTable.addUninitializedType(argSymbol.value, arg));
1042 break;
1043 case Opcodes.NEWARRAY:
1044 pop();
1045 switch (arg) {
1046 case Opcodes.T_BOOLEAN:
1047 push(ARRAY_OF | BOOLEAN);
1048 break;
1049 case Opcodes.T_CHAR:
1050 push(ARRAY_OF | CHAR);
1051 break;
1052 case Opcodes.T_BYTE:
1053 push(ARRAY_OF | BYTE);
1054 break;
1055 case Opcodes.T_SHORT:
1056 push(ARRAY_OF | SHORT);
1057 break;
1058 case Opcodes.T_INT:
1059 push(ARRAY_OF | INTEGER);
1060 break;
1061 case Opcodes.T_FLOAT:
1062 push(ARRAY_OF | FLOAT);
1063 break;
1064 case Opcodes.T_DOUBLE:
1065 push(ARRAY_OF | DOUBLE);
1066 break;
1067 case Opcodes.T_LONG:
1068 push(ARRAY_OF | LONG);
1069 break;
1070 default:
1071 throw new IllegalArgumentException();
1072 }
1073 break;
1074 case Opcodes.ANEWARRAY:
1075 String arrayElementType = argSymbol.value;
1076 pop();
1077 if (arrayElementType.charAt(0) == '[') {
1078 push(symbolTable, '[' + arrayElementType);
1079 } else {
1080 push(ARRAY_OF | REFERENCE_KIND | symbolTable.addType(arrayElementType));
1081 }
1082 break;
1083 case Opcodes.CHECKCAST:
1084 String castType = argSymbol.value;
1085 pop();
1086 if (castType.charAt(0) == '[') {
1087 push(symbolTable, castType);
1088 } else {
1089 push(REFERENCE_KIND | symbolTable.addType(castType));
1090 }
1091 break;
1092 case Opcodes.MULTIANEWARRAY:
1093 pop(arg);
1094 push(symbolTable, argSymbol.value);
1095 break;
1096 default:
1097 throw new IllegalArgumentException();
1098 }
1099 }
1100
1101 // -----------------------------------------------------------------------------------------------
1102 // Frame merging methods, used in the second step of the stack map frame computation algorithm
1103 // -----------------------------------------------------------------------------------------------
1104
1105 /**
1106 * Merges the input frame of the given {@link Frame} with the input and output frames of this
1107 * {@link Frame}. Returns <tt>true</tt> if the given frame has been changed by this operation (the
1108 * input and output frames of this {@link Frame} are never changed).
1109 *
1110 * @param symbolTable the type table to use to lookup and store type {@link Symbol}.
1111 * @param dstFrame the {@link Frame} whose input frame must be updated. This should be the frame
1112 * of a successor, in the control flow graph, of the basic block corresponding to this frame.
1113 * @param catchTypeIndex if 'frame' corresponds to an exception handler basic block, the type
1114 * table index of the caught exception type, otherwise 0.
1115 * @return <tt>true</tt> if the input frame of 'frame' has been changed by this operation.
1116 */
1117 final boolean merge(
1118 final SymbolTable symbolTable, final Frame dstFrame, final int catchTypeIndex) {
1119 boolean frameChanged = false;
1120
1121 // Compute the concrete types of the local variables at the end of the basic block corresponding
1122 // to this frame, by resolving its abstract output types, and merge these concrete types with
1123 // those of the local variables in the input frame of dstFrame.
1124 int nLocal = inputLocals.length;
1125 int nStack = inputStack.length;
1126 if (dstFrame.inputLocals == null) {
1127 dstFrame.inputLocals = new int[nLocal];
1128 frameChanged = true;
1129 }
1130 for (int i = 0; i < nLocal; ++i) {
1131 int concreteOutputType;
1132 if (outputLocals != null && i < outputLocals.length) {
1133 int abstractOutputType = outputLocals[i];
1134 if (abstractOutputType == 0) {
1135 // If the local variable has never been assigned in this basic block, it is equal to its
1136 // value at the beginning of the block.
1137 concreteOutputType = inputLocals[i];
1138 } else {
1139 int dim = abstractOutputType & DIM_MASK;
1140 int kind = abstractOutputType & KIND_MASK;
1141 if (kind == LOCAL_KIND) {
1142 // By definition, a LOCAL_KIND type designates the concrete type of a local variable at
1143 // the beginning of the basic block corresponding to this frame (which is known when
1144 // this method is called, but was not when the abstract type was computed).
1145 concreteOutputType = dim + inputLocals[abstractOutputType & VALUE_MASK];
1146 if ((abstractOutputType & TOP_IF_LONG_OR_DOUBLE_FLAG) != 0
1147 && (concreteOutputType == LONG || concreteOutputType == DOUBLE)) {
1148 concreteOutputType = TOP;
9231149 }
924 break;
925 case Opcodes.ALOAD:
926 push(get(arg));
927 break;
928 case Opcodes.IALOAD:
929 case Opcodes.BALOAD:
930 case Opcodes.CALOAD:
931 case Opcodes.SALOAD:
932 pop(2);
933 push(INTEGER);
934 break;
935 case Opcodes.LALOAD:
936 case Opcodes.D2L:
937 pop(2);
938 push(LONG);
939 push(TOP);
940 break;
941 case Opcodes.FALOAD:
942 pop(2);
943 push(FLOAT);
944 break;
945 case Opcodes.DALOAD:
946 case Opcodes.L2D:
947 pop(2);
948 push(DOUBLE);
949 push(TOP);
950 break;
951 case Opcodes.AALOAD:
952 pop(1);
953 t1 = pop();
954 push(ELEMENT_OF + t1);
955 break;
956 case Opcodes.ISTORE:
957 case Opcodes.FSTORE:
958 case Opcodes.ASTORE:
959 t1 = pop();
960 set(arg, t1);
961 if (arg > 0) {
962 t2 = get(arg - 1);
963 // if t2 is of kind STACK or LOCAL we cannot know its size!
964 if (t2 == LONG || t2 == DOUBLE) {
965 set(arg - 1, TOP);
966 } else if ((t2 & KIND) != BASE) {
967 set(arg - 1, t2 | TOP_IF_LONG_OR_DOUBLE);
968 }
1150 } else if (kind == STACK_KIND) {
1151 // By definition, a STACK_KIND type designates the concrete type of a local variable at
1152 // the beginning of the basic block corresponding to this frame (which is known when
1153 // this method is called, but was not when the abstract type was computed).
1154 concreteOutputType = dim + inputStack[nStack - (abstractOutputType & VALUE_MASK)];
1155 if ((abstractOutputType & TOP_IF_LONG_OR_DOUBLE_FLAG) != 0
1156 && (concreteOutputType == LONG || concreteOutputType == DOUBLE)) {
1157 concreteOutputType = TOP;
9691158 }
970 break;
971 case Opcodes.LSTORE:
972 case Opcodes.DSTORE:
973 pop(1);
974 t1 = pop();
975 set(arg, t1);
976 set(arg + 1, TOP);
977 if (arg > 0) {
978 t2 = get(arg - 1);
979 // if t2 is of kind STACK or LOCAL we cannot know its size!
980 if (t2 == LONG || t2 == DOUBLE) {
981 set(arg - 1, TOP);
982 } else if ((t2 & KIND) != BASE) {
983 set(arg - 1, t2 | TOP_IF_LONG_OR_DOUBLE);
984 }
985 }
986 break;
987 case Opcodes.IASTORE:
988 case Opcodes.BASTORE:
989 case Opcodes.CASTORE:
990 case Opcodes.SASTORE:
991 case Opcodes.FASTORE:
992 case Opcodes.AASTORE:
993 pop(3);
994 break;
995 case Opcodes.LASTORE:
996 case Opcodes.DASTORE:
997 pop(4);
998 break;
999 case Opcodes.POP:
1000 case Opcodes.IFEQ:
1001 case Opcodes.IFNE:
1002 case Opcodes.IFLT:
1003 case Opcodes.IFGE:
1004 case Opcodes.IFGT:
1005 case Opcodes.IFLE:
1006 case Opcodes.IRETURN:
1007 case Opcodes.FRETURN:
1008 case Opcodes.ARETURN:
1009 case Opcodes.TABLESWITCH:
1010 case Opcodes.LOOKUPSWITCH:
1011 case Opcodes.ATHROW:
1012 case Opcodes.MONITORENTER:
1013 case Opcodes.MONITOREXIT:
1014 case Opcodes.IFNULL:
1015 case Opcodes.IFNONNULL:
1016 pop(1);
1017 break;
1018 case Opcodes.POP2:
1019 case Opcodes.IF_ICMPEQ:
1020 case Opcodes.IF_ICMPNE:
1021 case Opcodes.IF_ICMPLT:
1022 case Opcodes.IF_ICMPGE:
1023 case Opcodes.IF_ICMPGT:
1024 case Opcodes.IF_ICMPLE:
1025 case Opcodes.IF_ACMPEQ:
1026 case Opcodes.IF_ACMPNE:
1027 case Opcodes.LRETURN:
1028 case Opcodes.DRETURN:
1029 pop(2);
1030 break;
1031 case Opcodes.DUP:
1032 t1 = pop();
1033 push(t1);
1034 push(t1);
1035 break;
1036 case Opcodes.DUP_X1:
1037 t1 = pop();
1038 t2 = pop();
1039 push(t1);
1040 push(t2);
1041 push(t1);
1042 break;
1043 case Opcodes.DUP_X2:
1044 t1 = pop();
1045 t2 = pop();
1046 t3 = pop();
1047 push(t1);
1048 push(t3);
1049 push(t2);
1050 push(t1);
1051 break;
1052 case Opcodes.DUP2:
1053 t1 = pop();
1054 t2 = pop();
1055 push(t2);
1056 push(t1);
1057 push(t2);
1058 push(t1);
1059 break;
1060 case Opcodes.DUP2_X1:
1061 t1 = pop();
1062 t2 = pop();
1063 t3 = pop();
1064 push(t2);
1065 push(t1);
1066 push(t3);
1067 push(t2);
1068 push(t1);
1069 break;
1070 case Opcodes.DUP2_X2:
1071 t1 = pop();
1072 t2 = pop();
1073 t3 = pop();
1074 t4 = pop();
1075 push(t2);
1076 push(t1);
1077 push(t4);
1078 push(t3);
1079 push(t2);
1080 push(t1);
1081 break;
1082 case Opcodes.SWAP:
1083 t1 = pop();
1084 t2 = pop();
1085 push(t1);
1086 push(t2);
1087 break;
1088 case Opcodes.IADD:
1089 case Opcodes.ISUB:
1090 case Opcodes.IMUL:
1091 case Opcodes.IDIV:
1092 case Opcodes.IREM:
1093 case Opcodes.IAND:
1094 case Opcodes.IOR:
1095 case Opcodes.IXOR:
1096 case Opcodes.ISHL:
1097 case Opcodes.ISHR:
1098 case Opcodes.IUSHR:
1099 case Opcodes.L2I:
1100 case Opcodes.D2I:
1101 case Opcodes.FCMPL:
1102 case Opcodes.FCMPG:
1103 pop(2);
1104 push(INTEGER);
1105 break;
1106 case Opcodes.LADD:
1107 case Opcodes.LSUB:
1108 case Opcodes.LMUL:
1109 case Opcodes.LDIV:
1110 case Opcodes.LREM:
1111 case Opcodes.LAND:
1112 case Opcodes.LOR:
1113 case Opcodes.LXOR:
1114 pop(4);
1115 push(LONG);
1116 push(TOP);
1117 break;
1118 case Opcodes.FADD:
1119 case Opcodes.FSUB:
1120 case Opcodes.FMUL:
1121 case Opcodes.FDIV:
1122 case Opcodes.FREM:
1123 case Opcodes.L2F:
1124 case Opcodes.D2F:
1125 pop(2);
1126 push(FLOAT);
1127 break;
1128 case Opcodes.DADD:
1129 case Opcodes.DSUB:
1130 case Opcodes.DMUL:
1131 case Opcodes.DDIV:
1132 case Opcodes.DREM:
1133 pop(4);
1134 push(DOUBLE);
1135 push(TOP);
1136 break;
1137 case Opcodes.LSHL:
1138 case Opcodes.LSHR:
1139 case Opcodes.LUSHR:
1140 pop(3);
1141 push(LONG);
1142 push(TOP);
1143 break;
1144 case Opcodes.IINC:
1145 set(arg, INTEGER);
1146 break;
1147 case Opcodes.I2L:
1148 case Opcodes.F2L:
1149 pop(1);
1150 push(LONG);
1151 push(TOP);
1152 break;
1153 case Opcodes.I2F:
1154 pop(1);
1155 push(FLOAT);
1156 break;
1157 case Opcodes.I2D:
1158 case Opcodes.F2D:
1159 pop(1);
1160 push(DOUBLE);
1161 push(TOP);
1162 break;
1163 case Opcodes.F2I:
1164 case Opcodes.ARRAYLENGTH:
1165 case Opcodes.INSTANCEOF:
1166 pop(1);
1167 push(INTEGER);
1168 break;
1169 case Opcodes.LCMP:
1170 case Opcodes.DCMPL:
1171 case Opcodes.DCMPG:
1172 pop(4);
1173 push(INTEGER);
1174 break;
1175 case Opcodes.JSR:
1176 case Opcodes.RET:
1177 throw new RuntimeException(
1178 "JSR/RET are not supported with computeFrames option");
1179 case Opcodes.GETSTATIC:
1180 push(cw, item.strVal3);
1181 break;
1182 case Opcodes.PUTSTATIC:
1183 pop(item.strVal3);
1184 break;
1185 case Opcodes.GETFIELD:
1186 pop(1);
1187 push(cw, item.strVal3);
1188 break;
1189 case Opcodes.PUTFIELD:
1190 pop(item.strVal3);
1191 pop();
1192 break;
1193 case Opcodes.INVOKEVIRTUAL:
1194 case Opcodes.INVOKESPECIAL:
1195 case Opcodes.INVOKESTATIC:
1196 case Opcodes.INVOKEINTERFACE:
1197 pop(item.strVal3);
1198 if (opcode != Opcodes.INVOKESTATIC) {
1199 t1 = pop();
1200 if (opcode == Opcodes.INVOKESPECIAL
1201 && item.strVal2.charAt(0) == '<') {
1202 init(t1);
1203 }
1204 }
1205 push(cw, item.strVal3);
1206 break;
1207 case Opcodes.INVOKEDYNAMIC:
1208 pop(item.strVal2);
1209 push(cw, item.strVal2);
1210 break;
1211 case Opcodes.NEW:
1212 push(UNINITIALIZED | cw.addUninitializedType(item.strVal1, arg));
1213 break;
1214 case Opcodes.NEWARRAY:
1215 pop();
1216 switch (arg) {
1217 case Opcodes.T_BOOLEAN:
1218 push(ARRAY_OF | BOOLEAN);
1219 break;
1220 case Opcodes.T_CHAR:
1221 push(ARRAY_OF | CHAR);
1222 break;
1223 case Opcodes.T_BYTE:
1224 push(ARRAY_OF | BYTE);
1225 break;
1226 case Opcodes.T_SHORT:
1227 push(ARRAY_OF | SHORT);
1228 break;
1229 case Opcodes.T_INT:
1230 push(ARRAY_OF | INTEGER);
1231 break;
1232 case Opcodes.T_FLOAT:
1233 push(ARRAY_OF | FLOAT);
1234 break;
1235 case Opcodes.T_DOUBLE:
1236 push(ARRAY_OF | DOUBLE);
1237 break;
1238 // case Opcodes.T_LONG:
1239 default:
1240 push(ARRAY_OF | LONG);
1241 break;
1242 }
1243 break;
1244 case Opcodes.ANEWARRAY:
1245 String s = item.strVal1;
1246 pop();
1247 if (s.charAt(0) == '[') {
1248 push(cw, '[' + s);
1249 } else {
1250 push(ARRAY_OF | OBJECT | cw.addType(s));
1251 }
1252 break;
1253 case Opcodes.CHECKCAST:
1254 s = item.strVal1;
1255 pop();
1256 if (s.charAt(0) == '[') {
1257 push(cw, s);
1258 } else {
1259 push(OBJECT | cw.addType(s));
1260 }
1261 break;
1262 // case Opcodes.MULTIANEWARRAY:
1159 } else {
1160 concreteOutputType = abstractOutputType;
1161 }
1162 }
1163 } else {
1164 // If the local variable has never been assigned in this basic block, it is equal to its
1165 // value at the beginning of the block.
1166 concreteOutputType = inputLocals[i];
1167 }
1168 // concreteOutputType might be an uninitialized type from the input locals or from the input
1169 // stack. However, if a constructor has been called for this class type in the basic block,
1170 // then this type is no longer uninitialized at the end of basic block.
1171 if (initializations != null) {
1172 concreteOutputType = getInitializedType(symbolTable, concreteOutputType);
1173 }
1174 frameChanged |= merge(symbolTable, concreteOutputType, dstFrame.inputLocals, i);
1175 }
1176
1177 // If dstFrame is an exception handler block, it can be reached from any instruction of the
1178 // basic block corresponding to this frame, in particular from the first one. Therefore, the
1179 // input locals of dstFrame should be compatible (i.e. merged) with the input locals of this
1180 // frame (and the input stack of dstFrame should be compatible, i.e. merged, with a one
1181 // element stack containing the caught exception type).
1182 if (catchTypeIndex > 0) {
1183 for (int i = 0; i < nLocal; ++i) {
1184 frameChanged |= merge(symbolTable, inputLocals[i], dstFrame.inputLocals, i);
1185 }
1186 if (dstFrame.inputStack == null) {
1187 dstFrame.inputStack = new int[1];
1188 frameChanged = true;
1189 }
1190 frameChanged |= merge(symbolTable, catchTypeIndex, dstFrame.inputStack, 0);
1191 return frameChanged;
1192 }
1193
1194 // Compute the concrete types of the stack operands at the end of the basic block corresponding
1195 // to this frame, by resolving its abstract output types, and merge these concrete types with
1196 // those of the stack operands in the input frame of dstFrame.
1197 int nInputStack = inputStack.length + outputStackStart;
1198 if (dstFrame.inputStack == null) {
1199 dstFrame.inputStack = new int[nInputStack + outputStackTop];
1200 frameChanged = true;
1201 }
1202 // First, do this for the stack operands that have not been popped in the basic block
1203 // corresponding to this frame, and which are therefore equal to their value in the input
1204 // frame (except for uninitialized types, which may have been initialized).
1205 for (int i = 0; i < nInputStack; ++i) {
1206 int concreteOutputType = inputStack[i];
1207 if (initializations != null) {
1208 concreteOutputType = getInitializedType(symbolTable, concreteOutputType);
1209 }
1210 frameChanged |= merge(symbolTable, concreteOutputType, dstFrame.inputStack, i);
1211 }
1212 // Then, do this for the stack operands that have pushed in the basic block (this code is the
1213 // same as the one above for local variables).
1214 for (int i = 0; i < outputStackTop; ++i) {
1215 int concreteOutputType;
1216 int abstractOutputType = outputStack[i];
1217 int dim = abstractOutputType & DIM_MASK;
1218 int kind = abstractOutputType & KIND_MASK;
1219 if (kind == LOCAL_KIND) {
1220 concreteOutputType = dim + inputLocals[abstractOutputType & VALUE_MASK];
1221 if ((abstractOutputType & TOP_IF_LONG_OR_DOUBLE_FLAG) != 0
1222 && (concreteOutputType == LONG || concreteOutputType == DOUBLE)) {
1223 concreteOutputType = TOP;
1224 }
1225 } else if (kind == STACK_KIND) {
1226 concreteOutputType = dim + inputStack[nStack - (abstractOutputType & VALUE_MASK)];
1227 if ((abstractOutputType & TOP_IF_LONG_OR_DOUBLE_FLAG) != 0
1228 && (concreteOutputType == LONG || concreteOutputType == DOUBLE)) {
1229 concreteOutputType = TOP;
1230 }
1231 } else {
1232 concreteOutputType = abstractOutputType;
1233 }
1234 if (initializations != null) {
1235 concreteOutputType = getInitializedType(symbolTable, concreteOutputType);
1236 }
1237 frameChanged |= merge(symbolTable, concreteOutputType, dstFrame.inputStack, nInputStack + i);
1238 }
1239 return frameChanged;
1240 }
1241
1242 /**
1243 * Merges the type at the given index in the given abstract type array with the given type.
1244 * Returns <tt>true</tt> if the type array has been modified by this operation.
1245 *
1246 * @param symbolTable the type table to use to lookup and store type {@link Symbol}.
1247 * @param sourceType the abstract type with which the abstract type array element must be merged.
1248 * This type should be of {@link #CONSTANT_KIND}, {@link #REFERENCE_KIND} or {@link
1249 * #UNINITIALIZED_KIND} kind, with positive or null array dimensions.
1250 * @param dstTypes an array of abstract types. These types should be of {@link #CONSTANT_KIND},
1251 * {@link #REFERENCE_KIND} or {@link #UNINITIALIZED_KIND} kind, with positive or null array
1252 * dimensions.
1253 * @param dstIndex the index of the type that must be merged in dstTypes.
1254 * @return <tt>true</tt> if the type array has been modified by this operation.
1255 */
1256 private static boolean merge(
1257 final SymbolTable symbolTable,
1258 final int sourceType,
1259 final int[] dstTypes,
1260 final int dstIndex) {
1261 int dstType = dstTypes[dstIndex];
1262 if (dstType == sourceType) {
1263 // If the types are equal, merge(sourceType, dstType) = dstType, so there is no change.
1264 return false;
1265 }
1266 int srcType = sourceType;
1267 if ((sourceType & ~DIM_MASK) == NULL) {
1268 if (dstType == NULL) {
1269 return false;
1270 }
1271 srcType = NULL;
1272 }
1273 if (dstType == 0) {
1274 // If dstTypes[dstIndex] has never been assigned, merge(srcType, dstType) = srcType.
1275 dstTypes[dstIndex] = srcType;
1276 return true;
1277 }
1278 int mergedType;
1279 if ((dstType & DIM_MASK) != 0 || (dstType & KIND_MASK) == REFERENCE_KIND) {
1280 // If dstType is a reference type of any array dimension.
1281 if (srcType == NULL) {
1282 // If srcType is the NULL type, merge(srcType, dstType) = dstType, so there is no change.
1283 return false;
1284 } else if ((srcType & (DIM_MASK | KIND_MASK)) == (dstType & (DIM_MASK | KIND_MASK))) {
1285 // If srcType has the same array dimension and the same kind as dstType.
1286 if ((dstType & KIND_MASK) == REFERENCE_KIND) {
1287 // If srcType and dstType are reference types with the same array dimension,
1288 // merge(srcType, dstType) = dim(srcType) | common super class of srcType and dstType.
1289 mergedType =
1290 (srcType & DIM_MASK)
1291 | REFERENCE_KIND
1292 | symbolTable.addMergedType(srcType & VALUE_MASK, dstType & VALUE_MASK);
1293 } else {
1294 // If srcType and dstType are array types of equal dimension but different element types,
1295 // merge(srcType, dstType) = dim(srcType) - 1 | java/lang/Object.
1296 int mergedDim = ELEMENT_OF + (srcType & DIM_MASK);
1297 mergedType = mergedDim | REFERENCE_KIND | symbolTable.addType("java/lang/Object");
1298 }
1299 } else if ((srcType & DIM_MASK) != 0 || (srcType & KIND_MASK) == REFERENCE_KIND) {
1300 // If srcType is any other reference or array type,
1301 // merge(srcType, dstType) = min(srcDdim, dstDim) | java/lang/Object
1302 // where srcDim is the array dimension of srcType, minus 1 if srcType is an array type
1303 // with a non reference element type (and similarly for dstDim).
1304 int srcDim = srcType & DIM_MASK;
1305 if (srcDim != 0 && (srcType & KIND_MASK) != REFERENCE_KIND) {
1306 srcDim = ELEMENT_OF + srcDim;
1307 }
1308 int dstDim = dstType & DIM_MASK;
1309 if (dstDim != 0 && (dstType & KIND_MASK) != REFERENCE_KIND) {
1310 dstDim = ELEMENT_OF + dstDim;
1311 }
1312 mergedType =
1313 Math.min(srcDim, dstDim) | REFERENCE_KIND | symbolTable.addType("java/lang/Object");
1314 } else {
1315 // If srcType is any other type, merge(srcType, dstType) = TOP.
1316 mergedType = TOP;
1317 }
1318 } else if (dstType == NULL) {
1319 // If dstType is the NULL type, merge(srcType, dstType) = srcType, or TOP if srcType is not a
1320 // an array type or a reference type.
1321 mergedType =
1322 (srcType & DIM_MASK) != 0 || (srcType & KIND_MASK) == REFERENCE_KIND ? srcType : TOP;
1323 } else {
1324 // If dstType is any other type, merge(srcType, dstType) = TOP whatever srcType.
1325 mergedType = TOP;
1326 }
1327 if (mergedType != dstType) {
1328 dstTypes[dstIndex] = mergedType;
1329 return true;
1330 }
1331 return false;
1332 }
1333
1334 // -----------------------------------------------------------------------------------------------
1335 // Frame output methods, to generate StackMapFrame attributes
1336 // -----------------------------------------------------------------------------------------------
1337
1338 /**
1339 * Makes the given {@link MethodWriter} visit the input frame of this {@link Frame}. The visit is
1340 * done with the {@link MethodWriter#visitFrameStart}, {@link MethodWriter#visitAbstractType} and
1341 * {@link MethodWriter#visitFrameEnd} methods.
1342 *
1343 * @param methodWriter the {@link MethodWriter} that should visit the input frame of this {@link
1344 * Frame}.
1345 */
1346 final void accept(final MethodWriter methodWriter) {
1347 // Compute the number of locals, ignoring TOP types that are just after a LONG or a DOUBLE, and
1348 // all trailing TOP types.
1349 int[] localTypes = inputLocals;
1350 int nLocal = 0;
1351 int nTrailingTop = 0;
1352 int i = 0;
1353 while (i < localTypes.length) {
1354 int localType = localTypes[i];
1355 i += (localType == LONG || localType == DOUBLE) ? 2 : 1;
1356 if (localType == TOP) {
1357 nTrailingTop++;
1358 } else {
1359 nLocal += nTrailingTop + 1;
1360 nTrailingTop = 0;
1361 }
1362 }
1363 // Compute the stack size, ignoring TOP types that are just after a LONG or a DOUBLE.
1364 int[] stackTypes = inputStack;
1365 int nStack = 0;
1366 i = 0;
1367 while (i < stackTypes.length) {
1368 int stackType = stackTypes[i];
1369 i += (stackType == LONG || stackType == DOUBLE) ? 2 : 1;
1370 nStack++;
1371 }
1372 // Visit the frame and its content.
1373 int frameIndex = methodWriter.visitFrameStart(owner.bytecodeOffset, nLocal, nStack);
1374 i = 0;
1375 while (nLocal-- > 0) {
1376 int localType = localTypes[i];
1377 i += (localType == LONG || localType == DOUBLE) ? 2 : 1;
1378 methodWriter.visitAbstractType(frameIndex++, localType);
1379 }
1380 i = 0;
1381 while (nStack-- > 0) {
1382 int stackType = stackTypes[i];
1383 i += (stackType == LONG || stackType == DOUBLE) ? 2 : 1;
1384 methodWriter.visitAbstractType(frameIndex++, stackType);
1385 }
1386 methodWriter.visitFrameEnd();
1387 }
1388
1389 /**
1390 * Put the given abstract type in the given ByteVector, using the JVMS verification_type_info
1391 * format used in StackMapTable attributes.
1392 *
1393 * @param symbolTable the type table to use to lookup and store type {@link Symbol}.
1394 * @param abstractType an abstract type, restricted to {@link Frame#CONSTANT_KIND}, {@link
1395 * Frame#REFERENCE_KIND} or {@link Frame#UNINITIALIZED_KIND} types.
1396 * @param output where the abstract type must be put.
1397 * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.4">JVMS
1398 * 4.7.4</a>
1399 */
1400 static void putAbstractType(
1401 final SymbolTable symbolTable, final int abstractType, final ByteVector output) {
1402 int arrayDimensions = (abstractType & Frame.DIM_MASK) >> DIM_SHIFT;
1403 if (arrayDimensions == 0) {
1404 int typeValue = abstractType & VALUE_MASK;
1405 switch (abstractType & KIND_MASK) {
1406 case CONSTANT_KIND:
1407 output.putByte(typeValue);
1408 break;
1409 case REFERENCE_KIND:
1410 output
1411 .putByte(ITEM_OBJECT)
1412 .putShort(symbolTable.addConstantClass(symbolTable.getType(typeValue).value).index);
1413 break;
1414 case UNINITIALIZED_KIND:
1415 output.putByte(ITEM_UNINITIALIZED).putShort((int) symbolTable.getType(typeValue).data);
1416 break;
12631417 default:
1264 pop(arg);
1265 push(cw, item.strVal1);
1266 break;
1267 }
1268 }
1269
1270 /**
1271 * Merges the input frame of the given basic block with the input and output
1272 * frames of this basic block. Returns <tt>true</tt> if the input frame of
1273 * the given label has been changed by this operation.
1274 *
1275 * @param cw
1276 * the ClassWriter to which this label belongs.
1277 * @param frame
1278 * the basic block whose input frame must be updated.
1279 * @param edge
1280 * the kind of the {@link Edge} between this label and 'label'.
1281 * See {@link Edge#info}.
1282 * @return <tt>true</tt> if the input frame of the given label has been
1283 * changed by this operation.
1284 */
1285 boolean merge(final ClassWriter cw, final Frame frame, final int edge) {
1286 boolean changed = false;
1287 int i, s, dim, kind, t;
1288
1289 int nLocal = inputLocals.length;
1290 int nStack = inputStack.length;
1291 if (frame.inputLocals == null) {
1292 frame.inputLocals = new int[nLocal];
1293 changed = true;
1294 }
1295
1296 for (i = 0; i < nLocal; ++i) {
1297 if (outputLocals != null && i < outputLocals.length) {
1298 s = outputLocals[i];
1299 if (s == 0) {
1300 t = inputLocals[i];
1301 } else {
1302 dim = s & DIM;
1303 kind = s & KIND;
1304 if (kind == BASE) {
1305 t = s;
1306 } else {
1307 if (kind == LOCAL) {
1308 t = dim + inputLocals[s & VALUE];
1309 } else {
1310 t = dim + inputStack[nStack - (s & VALUE)];
1311 }
1312 if ((s & TOP_IF_LONG_OR_DOUBLE) != 0
1313 && (t == LONG || t == DOUBLE)) {
1314 t = TOP;
1315 }
1316 }
1317 }
1318 } else {
1319 t = inputLocals[i];
1320 }
1321 if (initializations != null) {
1322 t = init(cw, t);
1323 }
1324 changed |= merge(cw, t, frame.inputLocals, i);
1325 }
1326
1327 if (edge > 0) {
1328 for (i = 0; i < nLocal; ++i) {
1329 t = inputLocals[i];
1330 changed |= merge(cw, t, frame.inputLocals, i);
1331 }
1332 if (frame.inputStack == null) {
1333 frame.inputStack = new int[1];
1334 changed = true;
1335 }
1336 changed |= merge(cw, edge, frame.inputStack, 0);
1337 return changed;
1338 }
1339
1340 int nInputStack = inputStack.length + owner.inputStackTop;
1341 if (frame.inputStack == null) {
1342 frame.inputStack = new int[nInputStack + outputStackTop];
1343 changed = true;
1344 }
1345
1346 for (i = 0; i < nInputStack; ++i) {
1347 t = inputStack[i];
1348 if (initializations != null) {
1349 t = init(cw, t);
1350 }
1351 changed |= merge(cw, t, frame.inputStack, i);
1352 }
1353 for (i = 0; i < outputStackTop; ++i) {
1354 s = outputStack[i];
1355 dim = s & DIM;
1356 kind = s & KIND;
1357 if (kind == BASE) {
1358 t = s;
1359 } else {
1360 if (kind == LOCAL) {
1361 t = dim + inputLocals[s & VALUE];
1362 } else {
1363 t = dim + inputStack[nStack - (s & VALUE)];
1364 }
1365 if ((s & TOP_IF_LONG_OR_DOUBLE) != 0
1366 && (t == LONG || t == DOUBLE)) {
1367 t = TOP;
1368 }
1369 }
1370 if (initializations != null) {
1371 t = init(cw, t);
1372 }
1373 changed |= merge(cw, t, frame.inputStack, nInputStack + i);
1374 }
1375 return changed;
1376 }
1377
1378 /**
1379 * Merges the type at the given index in the given type array with the given
1380 * type. Returns <tt>true</tt> if the type array has been modified by this
1381 * operation.
1382 *
1383 * @param cw
1384 * the ClassWriter to which this label belongs.
1385 * @param t
1386 * the type with which the type array element must be merged.
1387 * @param types
1388 * an array of types.
1389 * @param index
1390 * the index of the type that must be merged in 'types'.
1391 * @return <tt>true</tt> if the type array has been modified by this
1392 * operation.
1393 */
1394 private static boolean merge(final ClassWriter cw, int t,
1395 final int[] types, final int index) {
1396 int u = types[index];
1397 if (u == t) {
1398 // if the types are equal, merge(u,t)=u, so there is no change
1399 return false;
1400 }
1401 if ((t & ~DIM) == NULL) {
1402 if (u == NULL) {
1403 return false;
1404 }
1405 t = NULL;
1406 }
1407 if (u == 0) {
1408 // if types[index] has never been assigned, merge(u,t)=t
1409 types[index] = t;
1410 return true;
1411 }
1412 int v;
1413 if ((u & BASE_KIND) == OBJECT || (u & DIM) != 0) {
1414 // if u is a reference type of any dimension
1415 if (t == NULL) {
1416 // if t is the NULL type, merge(u,t)=u, so there is no change
1417 return false;
1418 } else if ((t & (DIM | BASE_KIND)) == (u & (DIM | BASE_KIND))) {
1419 // if t and u have the same dimension and same base kind
1420 if ((u & BASE_KIND) == OBJECT) {
1421 // if t is also a reference type, and if u and t have the
1422 // same dimension merge(u,t) = dim(t) | common parent of the
1423 // element types of u and t
1424 v = (t & DIM) | OBJECT
1425 | cw.getMergedType(t & BASE_VALUE, u & BASE_VALUE);
1426 } else {
1427 // if u and t are array types, but not with the same element
1428 // type, merge(u,t) = dim(u) - 1 | java/lang/Object
1429 int vdim = ELEMENT_OF + (u & DIM);
1430 v = vdim | OBJECT | cw.addType("java/lang/Object");
1431 }
1432 } else if ((t & BASE_KIND) == OBJECT || (t & DIM) != 0) {
1433 // if t is any other reference or array type, the merged type
1434 // is min(udim, tdim) | java/lang/Object, where udim is the
1435 // array dimension of u, minus 1 if u is an array type with a
1436 // primitive element type (and similarly for tdim).
1437 int tdim = (((t & DIM) == 0 || (t & BASE_KIND) == OBJECT) ? 0
1438 : ELEMENT_OF) + (t & DIM);
1439 int udim = (((u & DIM) == 0 || (u & BASE_KIND) == OBJECT) ? 0
1440 : ELEMENT_OF) + (u & DIM);
1441 v = Math.min(tdim, udim) | OBJECT
1442 | cw.addType("java/lang/Object");
1443 } else {
1444 // if t is any other type, merge(u,t)=TOP
1445 v = TOP;
1446 }
1447 } else if (u == NULL) {
1448 // if u is the NULL type, merge(u,t)=t,
1449 // or TOP if t is not a reference type
1450 v = (t & BASE_KIND) == OBJECT || (t & DIM) != 0 ? t : TOP;
1451 } else {
1452 // if u is any other type, merge(u,t)=TOP whatever t
1453 v = TOP;
1454 }
1455 if (u != v) {
1456 types[index] = v;
1457 return true;
1458 }
1459 return false;
1460 }
1418 throw new AssertionError();
1419 }
1420 } else {
1421 // Case of an array type, we need to build its descriptor first.
1422 StringBuilder typeDescriptor = new StringBuilder();
1423 while (arrayDimensions-- > 0) {
1424 typeDescriptor.append('[');
1425 }
1426 if ((abstractType & KIND_MASK) == REFERENCE_KIND) {
1427 typeDescriptor
1428 .append('L')
1429 .append(symbolTable.getType(abstractType & VALUE_MASK).value)
1430 .append(';');
1431 } else {
1432 switch (abstractType & VALUE_MASK) {
1433 case Frame.ITEM_ASM_BOOLEAN:
1434 typeDescriptor.append('Z');
1435 break;
1436 case Frame.ITEM_ASM_BYTE:
1437 typeDescriptor.append('B');
1438 break;
1439 case Frame.ITEM_ASM_CHAR:
1440 typeDescriptor.append('C');
1441 break;
1442 case Frame.ITEM_ASM_SHORT:
1443 typeDescriptor.append('S');
1444 break;
1445 case Frame.ITEM_INTEGER:
1446 typeDescriptor.append('I');
1447 break;
1448 case Frame.ITEM_FLOAT:
1449 typeDescriptor.append('F');
1450 break;
1451 case Frame.ITEM_LONG:
1452 typeDescriptor.append('J');
1453 break;
1454 case Frame.ITEM_DOUBLE:
1455 typeDescriptor.append('D');
1456 break;
1457 default:
1458 throw new AssertionError();
1459 }
1460 }
1461 output
1462 .putByte(ITEM_OBJECT)
1463 .putShort(symbolTable.addConstantClass(typeDescriptor.toString()).index);
1464 }
1465 }
14611466 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927
3028 package org.eclipse.persistence.internal.libraries.asm;
3129
3230 /**
3331 * A reference to a field or a method.
34 *
32 *
3533 * @author Remi Forax
3634 * @author Eric Bruneton
3735 */
3836 public final class Handle {
3937
40 /**
41 * The kind of field or method designated by this Handle. Should be
42 * {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC},
43 * {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC},
44 * {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC},
45 * {@link Opcodes#H_INVOKESPECIAL}, {@link Opcodes#H_NEWINVOKESPECIAL} or
46 * {@link Opcodes#H_INVOKEINTERFACE}.
47 */
48 final int tag;
38 /**
39 * The kind of field or method designated by this Handle. Should be {@link Opcodes#H_GETFIELD},
40 * {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, {@link
41 * Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL},
42 * {@link Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}.
43 */
44 private final int tag;
4945
50 /**
51 * The internal name of the class that owns the field or method designated
52 * by this handle.
53 */
54 final String owner;
46 /** The internal name of the class that owns the field or method designated by this handle. */
47 private final String owner;
5548
56 /**
57 * The name of the field or method designated by this handle.
58 */
59 final String name;
49 /** The name of the field or method designated by this handle. */
50 private final String name;
6051
61 /**
62 * The descriptor of the field or method designated by this handle.
63 */
64 final String desc;
65
66
67 /**
68 * Indicate if the owner is an interface or not.
69 */
70 final boolean itf;
52 /** The descriptor of the field or method designated by this handle. */
53 private final String descriptor;
7154
72 /**
73 * Constructs a new field or method handle.
74 *
75 * @param tag
76 * the kind of field or method designated by this Handle. Must be
77 * {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC},
78 * {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC},
79 * {@link Opcodes#H_INVOKEVIRTUAL},
80 * {@link Opcodes#H_INVOKESTATIC},
81 * {@link Opcodes#H_INVOKESPECIAL},
82 * {@link Opcodes#H_NEWINVOKESPECIAL} or
83 * {@link Opcodes#H_INVOKEINTERFACE}.
84 * @param owner
85 * the internal name of the class that owns the field or method
86 * designated by this handle.
87 * @param name
88 * the name of the field or method designated by this handle.
89 * @param desc
90 * the descriptor of the field or method designated by this
91 * handle.
92 *
93 * @deprecated this constructor has been superseded
94 * by {@link #Handle(int, String, String, String, boolean)}.
95 */
96 @Deprecated
97 public Handle(int tag, String owner, String name, String desc) {
98 this(tag, owner, name, desc, tag == Opcodes.H_INVOKEINTERFACE);
55 /** Whether the owner is an interface or not. */
56 private final boolean isInterface;
57
58 /**
59 * Constructs a new field or method handle.
60 *
61 * @param tag the kind of field or method designated by this Handle. Must be {@link
62 * Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link
63 * Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC},
64 * {@link Opcodes#H_INVOKESPECIAL}, {@link Opcodes#H_NEWINVOKESPECIAL} or {@link
65 * Opcodes#H_INVOKEINTERFACE}.
66 * @param owner the internal name of the class that owns the field or method designated by this
67 * handle.
68 * @param name the name of the field or method designated by this handle.
69 * @param descriptor the descriptor of the field or method designated by this handle.
70 * @deprecated this constructor has been superseded by {@link #Handle(int, String, String, String,
71 * boolean)}.
72 */
73 @Deprecated
74 public Handle(final int tag, final String owner, final String name, final String descriptor) {
75 this(tag, owner, name, descriptor, tag == Opcodes.H_INVOKEINTERFACE);
76 }
77
78 /**
79 * Constructs a new field or method handle.
80 *
81 * @param tag the kind of field or method designated by this Handle. Must be {@link
82 * Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link
83 * Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC},
84 * {@link Opcodes#H_INVOKESPECIAL}, {@link Opcodes#H_NEWINVOKESPECIAL} or {@link
85 * Opcodes#H_INVOKEINTERFACE}.
86 * @param owner the internal name of the class that owns the field or method designated by this
87 * handle.
88 * @param name the name of the field or method designated by this handle.
89 * @param descriptor the descriptor of the field or method designated by this handle.
90 * @param isInterface whether the owner is an interface or not.
91 */
92 public Handle(
93 final int tag,
94 final String owner,
95 final String name,
96 final String descriptor,
97 final boolean isInterface) {
98 this.tag = tag;
99 this.owner = owner;
100 this.name = name;
101 this.descriptor = descriptor;
102 this.isInterface = isInterface;
103 }
104
105 /**
106 * Returns the kind of field or method designated by this handle.
107 *
108 * @return {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD},
109 * {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, {@link
110 * Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL}, {@link
111 * Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}.
112 */
113 public int getTag() {
114 return tag;
115 }
116
117 /**
118 * Returns the internal name of the class that owns the field or method designated by this handle.
119 *
120 * @return the internal name of the class that owns the field or method designated by this handle.
121 */
122 public String getOwner() {
123 return owner;
124 }
125
126 /**
127 * Returns the name of the field or method designated by this handle.
128 *
129 * @return the name of the field or method designated by this handle.
130 */
131 public String getName() {
132 return name;
133 }
134
135 /**
136 * Returns the descriptor of the field or method designated by this handle.
137 *
138 * @return the descriptor of the field or method designated by this handle.
139 */
140 public String getDesc() {
141 return descriptor;
142 }
143
144 /**
145 * Returns true if the owner of the field or method designated by this handle is an interface.
146 *
147 * @return true if the owner of the field or method designated by this handle is an interface.
148 */
149 public boolean isInterface() {
150 return isInterface;
151 }
152
153 @Override
154 public boolean equals(final Object object) {
155 if (object == this) {
156 return true;
99157 }
158 if (!(object instanceof Handle)) {
159 return false;
160 }
161 Handle handle = (Handle) object;
162 return tag == handle.tag
163 && isInterface == handle.isInterface
164 && owner.equals(handle.owner)
165 && name.equals(handle.name)
166 && descriptor.equals(handle.descriptor);
167 }
100168
101 /**
102 * Constructs a new field or method handle.
103 *
104 * @param tag
105 * the kind of field or method designated by this Handle. Must be
106 * {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC},
107 * {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC},
108 * {@link Opcodes#H_INVOKEVIRTUAL},
109 * {@link Opcodes#H_INVOKESTATIC},
110 * {@link Opcodes#H_INVOKESPECIAL},
111 * {@link Opcodes#H_NEWINVOKESPECIAL} or
112 * {@link Opcodes#H_INVOKEINTERFACE}.
113 * @param owner
114 * the internal name of the class that owns the field or method
115 * designated by this handle.
116 * @param name
117 * the name of the field or method designated by this handle.
118 * @param desc
119 * the descriptor of the field or method designated by this
120 * handle.
121 * @param itf
122 * true if the owner is an interface.
123 */
124 public Handle(int tag, String owner, String name, String desc, boolean itf) {
125 this.tag = tag;
126 this.owner = owner;
127 this.name = name;
128 this.desc = desc;
129 this.itf = itf;
130 }
131
132 /**
133 * Returns the kind of field or method designated by this handle.
134 *
135 * @return {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC},
136 * {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC},
137 * {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC},
138 * {@link Opcodes#H_INVOKESPECIAL},
139 * {@link Opcodes#H_NEWINVOKESPECIAL} or
140 * {@link Opcodes#H_INVOKEINTERFACE}.
141 */
142 public int getTag() {
143 return tag;
144 }
169 @Override
170 public int hashCode() {
171 return tag
172 + (isInterface ? 64 : 0)
173 + owner.hashCode() * name.hashCode() * descriptor.hashCode();
174 }
145175
146 /**
147 * Returns the internal name of the class that owns the field or method
148 * designated by this handle.
149 *
150 * @return the internal name of the class that owns the field or method
151 * designated by this handle.
152 */
153 public String getOwner() {
154 return owner;
155 }
156
157 /**
158 * Returns the name of the field or method designated by this handle.
159 *
160 * @return the name of the field or method designated by this handle.
161 */
162 public String getName() {
163 return name;
164 }
165
166 /**
167 * Returns the descriptor of the field or method designated by this handle.
168 *
169 * @return the descriptor of the field or method designated by this handle.
170 */
171 public String getDesc() {
172 return desc;
173 }
174
175 /**
176 * Returns true if the owner of the field or method designated
177 * by this handle is an interface.
178 *
179 * @return true if the owner of the field or method designated
180 * by this handle is an interface.
181 */
182 public boolean isInterface() {
183 return itf;
184 }
185
186 @Override
187 public boolean equals(Object obj) {
188 if (obj == this) {
189 return true;
190 }
191 if (!(obj instanceof Handle)) {
192 return false;
193 }
194 Handle h = (Handle) obj;
195 return tag == h.tag && itf == h.itf && owner.equals(h.owner)
196 && name.equals(h.name) && desc.equals(h.desc);
197 }
198
199 @Override
200 public int hashCode() {
201 return tag + (itf? 64: 0) + owner.hashCode() * name.hashCode() * desc.hashCode();
202 }
203
204 /**
205 * Returns the textual representation of this handle. The textual
206 * representation is:
207 *
208 * <pre>
209 * for a reference to a class:
210 * owner '.' name desc ' ' '(' tag ')'
211 * for a reference to an interface:
212 * owner '.' name desc ' ' '(' tag ' ' itf ')'
213 * </pre>
214 *
215 * . As this format is unambiguous, it can be parsed if necessary.
216 */
217 @Override
218 public String toString() {
219 return owner + '.' + name + desc + " (" + tag + (itf? " itf": "") + ')';
220 }
176 /**
177 * Returns the textual representation of this handle. The textual representation is:
178 *
179 * <ul>
180 * <li>for a reference to a class: owner "." name descriptor " (" tag ")",
181 * <li>for a reference to an interface: owner "." name descriptor " (" tag " itf)".
182 * </ul>
183 */
184 @Override
185 public String toString() {
186 return owner + '.' + name + descriptor + " (" + tag + (isInterface ? " itf" : "") + ')';
187 }
221188 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm;
3028
3129 /**
32 * Information about an exception handler block.
33 *
30 * Information about an exception handler. Corresponds to an element of the exception_table array of
31 * a Code attribute, as defined in the Java Virtual Machine Specification (JVMS). Handler instances
32 * can be chained together, with their {@link #nextHandler} field, to describe a full JVMS
33 * exception_table array.
34 *
35 * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.3">JVMS
36 * 4.7.3</a>
3437 * @author Eric Bruneton
3538 */
36 class Handler {
39 final class Handler {
3740
38 /**
39 * Beginning of the exception handler's scope (inclusive).
40 */
41 Label start;
41 /**
42 * The start_pc field of this JVMS exception_table entry. Corresponds to the beginning of the
43 * exception handler's scope (inclusive).
44 */
45 final Label startPc;
4246
43 /**
44 * End of the exception handler's scope (exclusive).
45 */
46 Label end;
47 /**
48 * The end_pc field of this JVMS exception_table entry. Corresponds to the end of the exception
49 * handler's scope (exclusive).
50 */
51 final Label endPc;
4752
48 /**
49 * Beginning of the exception handler's code.
50 */
51 Label handler;
53 /**
54 * The handler_pc field of this JVMS exception_table entry. Corresponding to the beginning of the
55 * exception handler's code.
56 */
57 final Label handlerPc;
5258
53 /**
54 * Internal name of the type of exceptions handled by this handler, or
55 * <tt>null</tt> to catch any exceptions.
56 */
57 String desc;
59 /**
60 * The catch_type field of this JVMS exception_table entry. This is the constant pool index of the
61 * internal name of the type of exceptions handled by this handler, or 0 to catch any exceptions.
62 */
63 final int catchType;
5864
59 /**
60 * Constant pool index of the internal name of the type of exceptions
61 * handled by this handler, or 0 to catch any exceptions.
62 */
63 int type;
65 /**
66 * The internal name of the type of exceptions handled by this handler, or <tt>null</tt> to catch
67 * any exceptions.
68 */
69 final String catchTypeDescriptor;
6470
65 /**
66 * Next exception handler block info.
67 */
68 Handler next;
71 /** The next exception handler. */
72 Handler nextHandler;
6973
70 /**
71 * Removes the range between start and end from the given exception
72 * handlers.
73 *
74 * @param h
75 * an exception handler list.
76 * @param start
77 * the start of the range to be removed.
78 * @param end
79 * the end of the range to be removed. Maybe null.
80 * @return the exception handler list with the start-end range removed.
81 */
82 static Handler remove(Handler h, Label start, Label end) {
83 if (h == null) {
84 return null;
85 } else {
86 h.next = remove(h.next, start, end);
87 }
88 int hstart = h.start.position;
89 int hend = h.end.position;
90 int s = start.position;
91 int e = end == null ? Integer.MAX_VALUE : end.position;
92 // if [hstart,hend[ and [s,e[ intervals intersect...
93 if (s < hend && e > hstart) {
94 if (s <= hstart) {
95 if (e >= hend) {
96 // [hstart,hend[ fully included in [s,e[, h removed
97 h = h.next;
98 } else {
99 // [hstart,hend[ minus [s,e[ = [e,hend[
100 h.start = end;
101 }
102 } else if (e >= hend) {
103 // [hstart,hend[ minus [s,e[ = [hstart,s[
104 h.end = start;
105 } else {
106 // [hstart,hend[ minus [s,e[ = [hstart,s[ + [e,hend[
107 Handler g = new Handler();
108 g.start = end;
109 g.end = h.end;
110 g.handler = h.handler;
111 g.desc = h.desc;
112 g.type = h.type;
113 g.next = h.next;
114 h.end = start;
115 h.next = g;
116 }
117 }
118 return h;
74 /**
75 * Constructs a new Handler.
76 *
77 * @param startPc the start_pc field of this JVMS exception_table entry.
78 * @param endPc the end_pc field of this JVMS exception_table entry.
79 * @param handlerPc the handler_pc field of this JVMS exception_table entry.
80 * @param catchType The catch_type field of this JVMS exception_table entry.
81 * @param catchTypeDescriptor The internal name of the type of exceptions handled by this handler,
82 * or <tt>null</tt> to catch any exceptions.
83 */
84 Handler(
85 final Label startPc,
86 final Label endPc,
87 final Label handlerPc,
88 final int catchType,
89 final String catchTypeDescriptor) {
90 this.startPc = startPc;
91 this.endPc = endPc;
92 this.handlerPc = handlerPc;
93 this.catchType = catchType;
94 this.catchTypeDescriptor = catchTypeDescriptor;
95 }
96
97 /**
98 * Constructs a new Handler from the given one, with a different scope.
99 *
100 * @param handler an existing Handler.
101 * @param startPc the start_pc field of this JVMS exception_table entry.
102 * @param endPc the end_pc field of this JVMS exception_table entry.
103 */
104 Handler(final Handler handler, final Label startPc, final Label endPc) {
105 this(startPc, endPc, handler.handlerPc, handler.catchType, handler.catchTypeDescriptor);
106 this.nextHandler = handler.nextHandler;
107 }
108
109 /**
110 * Removes the range between start and end from the Handler list that begins with the given
111 * element.
112 *
113 * @param firstHandler the beginning of a Handler list. May be <tt>null</tt>.
114 * @param start the start of the range to be removed.
115 * @param end the end of the range to be removed. Maybe <tt>null</tt>.
116 * @return the exception handler list with the start-end range removed.
117 */
118 static Handler removeRange(final Handler firstHandler, final Label start, final Label end) {
119 if (firstHandler == null) {
120 return null;
121 } else {
122 firstHandler.nextHandler = removeRange(firstHandler.nextHandler, start, end);
119123 }
124 int handlerStart = firstHandler.startPc.bytecodeOffset;
125 int handlerEnd = firstHandler.endPc.bytecodeOffset;
126 int rangeStart = start.bytecodeOffset;
127 int rangeEnd = end == null ? Integer.MAX_VALUE : end.bytecodeOffset;
128 // Return early if [handlerStart,handlerEnd[ and [rangeStart,rangeEnd[ don't intersect.
129 if (rangeStart >= handlerEnd || rangeEnd <= handlerStart) {
130 return firstHandler;
131 }
132 if (rangeStart <= handlerStart) {
133 if (rangeEnd >= handlerEnd) {
134 // If [handlerStart,handlerEnd[ is included in [rangeStart,rangeEnd[, remove firstHandler.
135 return firstHandler.nextHandler;
136 } else {
137 // [handlerStart,handlerEnd[ - [rangeStart,rangeEnd[ = [rangeEnd,handlerEnd[
138 return new Handler(firstHandler, end, firstHandler.endPc);
139 }
140 } else if (rangeEnd >= handlerEnd) {
141 // [handlerStart,handlerEnd[ - [rangeStart,rangeEnd[ = [handlerStart,rangeStart[
142 return new Handler(firstHandler, firstHandler.startPc, start);
143 } else {
144 // [handlerStart,handlerEnd[ - [rangeStart,rangeEnd[ =
145 // [handlerStart,rangeStart[ + [rangeEnd,handerEnd[
146 firstHandler.nextHandler = new Handler(firstHandler, end, firstHandler.endPc);
147 return new Handler(firstHandler, firstHandler.startPc, start);
148 }
149 }
150
151 /**
152 * Returns the number of elements of the Handler list that begins with the given element.
153 *
154 * @param firstHandler the beginning of a Handler list. May be <tt>null</tt>.
155 * @return the number of elements of the Handler list that begins with 'handler'.
156 */
157 static int getExceptionTableLength(final Handler firstHandler) {
158 int length = 0;
159 Handler handler = firstHandler;
160 while (handler != null) {
161 length++;
162 handler = handler.nextHandler;
163 }
164 return length;
165 }
166
167 /**
168 * Returns the size in bytes of the JVMS exception_table corresponding to the Handler list that
169 * begins with the given element. <i>This includes the exception_table_length field.</i>
170 *
171 * @param firstHandler the beginning of a Handler list. May be <tt>null</tt>.
172 * @return the size in bytes of the exception_table_length and exception_table structures.
173 */
174 static int getExceptionTableSize(final Handler firstHandler) {
175 return 2 + 8 * getExceptionTableLength(firstHandler);
176 }
177
178 /**
179 * Puts the JVMS exception_table corresponding to the Handler list that begins with the given
180 * element. <i>This includes the exception_table_length field.</i>
181 *
182 * @param firstHandler the beginning of a Handler list. May be <tt>null</tt>.
183 * @param output where the exception_table_length and exception_table structures must be put.
184 */
185 static void putExceptionTable(final Handler firstHandler, final ByteVector output) {
186 output.putShort(getExceptionTableLength(firstHandler));
187 Handler handler = firstHandler;
188 while (handler != null) {
189 output
190 .putShort(handler.startPc.bytecodeOffset)
191 .putShort(handler.endPc.bytecodeOffset)
192 .putShort(handler.handlerPc.bytecodeOffset)
193 .putShort(handler.catchType);
194 handler = handler.nextHandler;
195 }
196 }
120197 }
+0
-313
org/eclipse/persistence/internal/libraries/asm/Item.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 package org.eclipse.persistence.internal.libraries.asm;
30
31 /**
32 * A constant pool item. Constant pool items can be created with the 'newXXX'
33 * methods in the {@link ClassWriter} class.
34 *
35 * @author Eric Bruneton
36 */
37 final class Item {
38
39 /**
40 * Index of this item in the constant pool.
41 */
42 int index;
43
44 /**
45 * Type of this constant pool item. A single class is used to represent all
46 * constant pool item types, in order to minimize the bytecode size of this
47 * package. The value of this field is one of {@link ClassWriter#INT},
48 * {@link ClassWriter#LONG}, {@link ClassWriter#FLOAT},
49 * {@link ClassWriter#DOUBLE}, {@link ClassWriter#UTF8},
50 * {@link ClassWriter#STR}, {@link ClassWriter#CLASS},
51 * {@link ClassWriter#NAME_TYPE}, {@link ClassWriter#FIELD},
52 * {@link ClassWriter#METH}, {@link ClassWriter#IMETH},
53 * {@link ClassWriter#MTYPE}, {@link ClassWriter#INDY}.
54 *
55 * MethodHandle constant 9 variations are stored using a range of 9 values
56 * from {@link ClassWriter#HANDLE_BASE} + 1 to
57 * {@link ClassWriter#HANDLE_BASE} + 9.
58 *
59 * Special Item types are used for Items that are stored in the ClassWriter
60 * {@link ClassWriter#typeTable}, instead of the constant pool, in order to
61 * avoid clashes with normal constant pool items in the ClassWriter constant
62 * pool's hash table. These special item types are
63 * {@link ClassWriter#TYPE_NORMAL}, {@link ClassWriter#TYPE_UNINIT} and
64 * {@link ClassWriter#TYPE_MERGED}.
65 */
66 int type;
67
68 /**
69 * Value of this item, for an integer item.
70 */
71 int intVal;
72
73 /**
74 * Value of this item, for a long item.
75 */
76 long longVal;
77
78 /**
79 * First part of the value of this item, for items that do not hold a
80 * primitive value.
81 */
82 String strVal1;
83
84 /**
85 * Second part of the value of this item, for items that do not hold a
86 * primitive value.
87 */
88 String strVal2;
89
90 /**
91 * Third part of the value of this item, for items that do not hold a
92 * primitive value.
93 */
94 String strVal3;
95
96 /**
97 * The hash code value of this constant pool item.
98 */
99 int hashCode;
100
101 /**
102 * Link to another constant pool item, used for collision lists in the
103 * constant pool's hash table.
104 */
105 Item next;
106
107 /**
108 * Constructs an uninitialized {@link Item}.
109 */
110 Item() {
111 }
112
113 /**
114 * Constructs an uninitialized {@link Item} for constant pool element at
115 * given position.
116 *
117 * @param index
118 * index of the item to be constructed.
119 */
120 Item(final int index) {
121 this.index = index;
122 }
123
124 /**
125 * Constructs a copy of the given item.
126 *
127 * @param index
128 * index of the item to be constructed.
129 * @param i
130 * the item that must be copied into the item to be constructed.
131 */
132 Item(final int index, final Item i) {
133 this.index = index;
134 type = i.type;
135 intVal = i.intVal;
136 longVal = i.longVal;
137 strVal1 = i.strVal1;
138 strVal2 = i.strVal2;
139 strVal3 = i.strVal3;
140 hashCode = i.hashCode;
141 }
142
143 /**
144 * Sets this item to an integer item.
145 *
146 * @param intVal
147 * the value of this item.
148 */
149 void set(final int intVal) {
150 this.type = ClassWriter.INT;
151 this.intVal = intVal;
152 this.hashCode = 0x7FFFFFFF & (type + intVal);
153 }
154
155 /**
156 * Sets this item to a long item.
157 *
158 * @param longVal
159 * the value of this item.
160 */
161 void set(final long longVal) {
162 this.type = ClassWriter.LONG;
163 this.longVal = longVal;
164 this.hashCode = 0x7FFFFFFF & (type + (int) longVal);
165 }
166
167 /**
168 * Sets this item to a float item.
169 *
170 * @param floatVal
171 * the value of this item.
172 */
173 void set(final float floatVal) {
174 this.type = ClassWriter.FLOAT;
175 this.intVal = Float.floatToRawIntBits(floatVal);
176 this.hashCode = 0x7FFFFFFF & (type + (int) floatVal);
177 }
178
179 /**
180 * Sets this item to a double item.
181 *
182 * @param doubleVal
183 * the value of this item.
184 */
185 void set(final double doubleVal) {
186 this.type = ClassWriter.DOUBLE;
187 this.longVal = Double.doubleToRawLongBits(doubleVal);
188 this.hashCode = 0x7FFFFFFF & (type + (int) doubleVal);
189 }
190
191 /**
192 * Sets this item to an item that do not hold a primitive value.
193 *
194 * @param type
195 * the type of this item.
196 * @param strVal1
197 * first part of the value of this item.
198 * @param strVal2
199 * second part of the value of this item.
200 * @param strVal3
201 * third part of the value of this item.
202 */
203 @SuppressWarnings("fallthrough")
204 void set(final int type, final String strVal1, final String strVal2,
205 final String strVal3) {
206 this.type = type;
207 this.strVal1 = strVal1;
208 this.strVal2 = strVal2;
209 this.strVal3 = strVal3;
210 switch (type) {
211 case ClassWriter.CLASS:
212 this.intVal = 0; // intVal of a class must be zero, see visitInnerClass
213 case ClassWriter.UTF8:
214 case ClassWriter.STR:
215 case ClassWriter.MTYPE:
216 case ClassWriter.TYPE_NORMAL:
217 hashCode = 0x7FFFFFFF & (type + strVal1.hashCode());
218 return;
219 case ClassWriter.NAME_TYPE: {
220 hashCode = 0x7FFFFFFF & (type + strVal1.hashCode()
221 * strVal2.hashCode());
222 return;
223 }
224 // ClassWriter.FIELD:
225 // ClassWriter.METH:
226 // ClassWriter.IMETH:
227 // ClassWriter.HANDLE_BASE + 1..9
228 default:
229 hashCode = 0x7FFFFFFF & (type + strVal1.hashCode()
230 * strVal2.hashCode() * strVal3.hashCode());
231 }
232 }
233
234 /**
235 * Sets the item to an InvokeDynamic item.
236 *
237 * @param name
238 * invokedynamic's name.
239 * @param desc
240 * invokedynamic's desc.
241 * @param bsmIndex
242 * zero based index into the class attribute BootrapMethods.
243 */
244 void set(String name, String desc, int bsmIndex) {
245 this.type = ClassWriter.INDY;
246 this.longVal = bsmIndex;
247 this.strVal1 = name;
248 this.strVal2 = desc;
249 this.hashCode = 0x7FFFFFFF & (ClassWriter.INDY + bsmIndex
250 * strVal1.hashCode() * strVal2.hashCode());
251 }
252
253 /**
254 * Sets the item to a BootstrapMethod item.
255 *
256 * @param position
257 * position in byte in the class attribute BootrapMethods.
258 * @param hashCode
259 * hashcode of the item. This hashcode is processed from the
260 * hashcode of the bootstrap method and the hashcode of all
261 * bootstrap arguments.
262 */
263 void set(int position, int hashCode) {
264 this.type = ClassWriter.BSM;
265 this.intVal = position;
266 this.hashCode = hashCode;
267 }
268
269 /**
270 * Indicates if the given item is equal to this one. <i>This method assumes
271 * that the two items have the same {@link #type}</i>.
272 *
273 * @param i
274 * the item to be compared to this one. Both items must have the
275 * same {@link #type}.
276 * @return <tt>true</tt> if the given item if equal to this one,
277 * <tt>false</tt> otherwise.
278 */
279 boolean isEqualTo(final Item i) {
280 switch (type) {
281 case ClassWriter.UTF8:
282 case ClassWriter.STR:
283 case ClassWriter.CLASS:
284 case ClassWriter.MTYPE:
285 case ClassWriter.TYPE_NORMAL:
286 return i.strVal1.equals(strVal1);
287 case ClassWriter.TYPE_MERGED:
288 case ClassWriter.LONG:
289 case ClassWriter.DOUBLE:
290 return i.longVal == longVal;
291 case ClassWriter.INT:
292 case ClassWriter.FLOAT:
293 return i.intVal == intVal;
294 case ClassWriter.TYPE_UNINIT:
295 return i.intVal == intVal && i.strVal1.equals(strVal1);
296 case ClassWriter.NAME_TYPE:
297 return i.strVal1.equals(strVal1) && i.strVal2.equals(strVal2);
298 case ClassWriter.INDY: {
299 return i.longVal == longVal && i.strVal1.equals(strVal1)
300 && i.strVal2.equals(strVal2);
301 }
302 // case ClassWriter.FIELD:
303 // case ClassWriter.METH:
304 // case ClassWriter.IMETH:
305 // case ClassWriter.HANDLE_BASE + 1..9
306 default:
307 return i.strVal1.equals(strVal1) && i.strVal2.equals(strVal2)
308 && i.strVal3.equals(strVal3);
309 }
310 }
311
312 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
27 package org.eclipse.persistence.internal.libraries.asm;
28
29 /**
30 * A position in the bytecode of a method. Labels are used for jump, goto, and switch instructions,
31 * and for try catch blocks. A label designates the <i>instruction</i> that is just after. Note
32 * however that there can be other elements between a label and the instruction it designates (such
33 * as other labels, stack map frames, line numbers, etc.).
434 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 package org.eclipse.persistence.internal.libraries.asm;
30
31 /**
32 * A label represents a position in the bytecode of a method. Labels are used
33 * for jump, goto, and switch instructions, and for try catch blocks. A label
34 * designates the <i>instruction</i> that is just after. Note however that there
35 * can be other elements between a label and the instruction it designates (such
36 * as other labels, stack map frames, line numbers, etc.).
37 *
3835 * @author Eric Bruneton
3936 */
4037 public class Label {
4138
42 /**
43 * Indicates if this label is only used for debug attributes. Such a label
44 * is not the start of a basic block, the target of a jump instruction, or
45 * an exception handler. It can be safely ignored in control flow graph
46 * analysis algorithms (for optimization purposes).
47 */
48 static final int DEBUG = 1;
49
50 /**
51 * Indicates if the position of this label is known.
52 */
53 static final int RESOLVED = 2;
54
55 /**
56 * Indicates if this label has been updated, after instruction resizing.
57 */
58 static final int RESIZED = 4;
59
60 /**
61 * Indicates if this basic block has been pushed in the basic block stack.
62 * See {@link MethodWriter#visitMaxs visitMaxs}.
63 */
64 static final int PUSHED = 8;
65
66 /**
67 * Indicates if this label is the target of a jump instruction, or the start
68 * of an exception handler.
69 */
70 static final int TARGET = 16;
71
72 /**
73 * Indicates if a stack map frame must be stored for this label.
74 */
75 static final int STORE = 32;
76
77 /**
78 * Indicates if this label corresponds to a reachable basic block.
79 */
80 static final int REACHABLE = 64;
81
82 /**
83 * Indicates if this basic block ends with a JSR instruction.
84 */
85 static final int JSR = 128;
86
87 /**
88 * Indicates if this basic block ends with a RET instruction.
89 */
90 static final int RET = 256;
91
92 /**
93 * Indicates if this basic block is the start of a subroutine.
94 */
95 static final int SUBROUTINE = 512;
96
97 /**
98 * Indicates if this subroutine basic block has been visited by a
99 * visitSubroutine(null, ...) call.
100 */
101 static final int VISITED = 1024;
102
103 /**
104 * Indicates if this subroutine basic block has been visited by a
105 * visitSubroutine(!null, ...) call.
106 */
107 static final int VISITED2 = 2048;
108
109 /**
110 * Field used to associate user information to a label. Warning: this field
111 * is used by the ASM tree package. In order to use it with the ASM tree
112 * package you must override the
113 * {@link org.eclipse.persistence.internal.libraries.asm.tree.MethodNode#getLabelNode} method.
114 */
115 public Object info;
116
117 /**
118 * Flags that indicate the status of this label.
119 *
120 * @see #DEBUG
121 * @see #RESOLVED
122 * @see #RESIZED
123 * @see #PUSHED
124 * @see #TARGET
125 * @see #STORE
126 * @see #REACHABLE
127 * @see #JSR
128 * @see #RET
129 */
130 int status;
131
132 /**
133 * The line number corresponding to this label, if known. If there are
134 * several lines, each line is stored in a separate label, all linked via
135 * their next field (these links are created in ClassReader and removed just
136 * before visitLabel is called, so that this does not impact the rest of the
137 * code).
138 */
139 int line;
140
141 /**
142 * The position of this label in the code, if known.
143 */
144 int position;
145
146 /**
147 * Number of forward references to this label, times two.
148 */
149 private int referenceCount;
150
151 /**
152 * Informations about forward references. Each forward reference is
153 * described by two consecutive integers in this array: the first one is the
154 * position of the first byte of the bytecode instruction that contains the
155 * forward reference, while the second is the position of the first byte of
156 * the forward reference itself. In fact the sign of the first integer
157 * indicates if this reference uses 2 or 4 bytes, and its absolute value
158 * gives the position of the bytecode instruction. This array is also used
159 * as a bitset to store the subroutines to which a basic block belongs. This
160 * information is needed in {@linked MethodWriter#visitMaxs}, after all
161 * forward references have been resolved. Hence the same array can be used
162 * for both purposes without problems.
163 */
164 private int[] srcAndRefPositions;
165
166 // ------------------------------------------------------------------------
167
168 /*
169 * Fields for the control flow and data flow graph analysis algorithms (used
170 * to compute the maximum stack size or the stack map frames). A control
171 * flow graph contains one node per "basic block", and one edge per "jump"
172 * from one basic block to another. Each node (i.e., each basic block) is
173 * represented by the Label object that corresponds to the first instruction
174 * of this basic block. Each node also stores the list of its successors in
175 * the graph, as a linked list of Edge objects.
176 *
177 * The control flow analysis algorithms used to compute the maximum stack
178 * size or the stack map frames are similar and use two steps. The first
179 * step, during the visit of each instruction, builds information about the
180 * state of the local variables and the operand stack at the end of each
181 * basic block, called the "output frame", <i>relatively</i> to the frame
182 * state at the beginning of the basic block, which is called the "input
183 * frame", and which is <i>unknown</i> during this step. The second step, in
184 * {@link MethodWriter#visitMaxs}, is a fix point algorithm that computes
185 * information about the input frame of each basic block, from the input
186 * state of the first basic block (known from the method signature), and by
187 * the using the previously computed relative output frames.
188 *
189 * The algorithm used to compute the maximum stack size only computes the
190 * relative output and absolute input stack heights, while the algorithm
191 * used to compute stack map frames computes relative output frames and
192 * absolute input frames.
193 */
194
195 /**
196 * Start of the output stack relatively to the input stack. The exact
197 * semantics of this field depends on the algorithm that is used.
198 *
199 * When only the maximum stack size is computed, this field is the number of
200 * elements in the input stack.
201 *
202 * When the stack map frames are completely computed, this field is the
203 * offset of the first output stack element relatively to the top of the
204 * input stack. This offset is always negative or null. A null offset means
205 * that the output stack must be appended to the input stack. A -n offset
206 * means that the first n output stack elements must replace the top n input
207 * stack elements, and that the other elements must be appended to the input
208 * stack.
209 */
210 int inputStackTop;
211
212 /**
213 * Maximum height reached by the output stack, relatively to the top of the
214 * input stack. This maximum is always positive or null.
215 */
216 int outputStackMax;
217
218 /**
219 * Information about the input and output stack map frames of this basic
220 * block. This field is only used when {@link ClassWriter#COMPUTE_FRAMES}
221 * option is used.
222 */
223 Frame frame;
224
225 /**
226 * The successor of this label, in the order they are visited. This linked
227 * list does not include labels used for debug info only. If
228 * {@link ClassWriter#COMPUTE_FRAMES} option is used then, in addition, it
229 * does not contain successive labels that denote the same bytecode position
230 * (in this case only the first label appears in this list).
231 */
232 Label successor;
233
234 /**
235 * The successors of this node in the control flow graph. These successors
236 * are stored in a linked list of {@link Edge Edge} objects, linked to each
237 * other by their {@link Edge#next} field.
238 */
239 Edge successors;
240
241 /**
242 * The next basic block in the basic block stack. This stack is used in the
243 * main loop of the fix point algorithm used in the second step of the
244 * control flow analysis algorithms. It is also used in
245 * {@link #visitSubroutine} to avoid using a recursive method, and in
246 * ClassReader to temporarily store multiple source lines for a label.
247 *
248 * @see MethodWriter#visitMaxs
249 */
250 Label next;
251
252 // ------------------------------------------------------------------------
253 // Constructor
254 // ------------------------------------------------------------------------
255
256 /**
257 * Constructs a new label.
258 */
259 public Label() {
260 }
261
262 // ------------------------------------------------------------------------
263 // Methods to compute offsets and to manage forward references
264 // ------------------------------------------------------------------------
265
266 /**
267 * Returns the offset corresponding to this label. This offset is computed
268 * from the start of the method's bytecode. <i>This method is intended for
269 * {@link Attribute} sub classes, and is normally not needed by class
270 * generators or adapters.</i>
271 *
272 * @return the offset corresponding to this label.
273 * @throws IllegalStateException
274 * if this label is not resolved yet.
275 */
276 public int getOffset() {
277 if ((status & RESOLVED) == 0) {
278 throw new IllegalStateException(
279 "Label offset position has not been resolved yet");
39 /**
40 * A flag indicating that a label is only used for debug attributes. Such a label is not the start
41 * of a basic block, the target of a jump instruction, or an exception handler. It can be safely
42 * ignored in control flow graph analysis algorithms (for optimization purposes).
43 */
44 static final int FLAG_DEBUG_ONLY = 1;
45
46 /**
47 * A flag indicating that a label is the target of a jump instruction, or the start of an
48 * exception handler.
49 */
50 static final int FLAG_JUMP_TARGET = 2;
51
52 /** A flag indicating that the bytecode offset of a label is known. */
53 static final int FLAG_RESOLVED = 4;
54
55 /** A flag indicating that a label corresponds to a reachable basic block. */
56 static final int FLAG_REACHABLE = 8;
57
58 /**
59 * A flag indicating that the basic block corresponding to a label ends with a subroutine call. By
60 * construction in {@link MethodWriter#visitJumpInsn}, labels with this flag set have at least two
61 * outgoing edges:
62 *
63 * <ul>
64 * <li>the first one corresponds to the instruction that follows the jsr instruction in the
65 * bytecode, i.e. where execution continues when it returns from the jsr call. This is a
66 * virtual control flow edge, since execution never goes directly from the jsr to the next
67 * instruction. Instead, it goes to the subroutine and eventually returns to the instruction
68 * following the jsr. This virtual edge is used to compute the real outgoing edges of the
69 * basic blocks ending with a ret instruction, in {@link #addSubroutineRetSuccessors}.
70 * <li>the second one corresponds to the target of the jsr instruction,
71 * </ul>
72 */
73 static final int FLAG_SUBROUTINE_CALLER = 16;
74
75 /**
76 * A flag indicating that the basic block corresponding to a label is the start of a subroutine.
77 */
78 static final int FLAG_SUBROUTINE_START = 32;
79
80 /** A flag indicating that the basic block corresponding to a label is the end of a subroutine. */
81 static final int FLAG_SUBROUTINE_END = 64;
82
83 /**
84 * The number of elements to add to the {@link #otherLineNumbers} array when it needs to be
85 * resized to store a new source line number.
86 */
87 static final int LINE_NUMBERS_CAPACITY_INCREMENT = 4;
88
89 /**
90 * The number of elements to add to the {@link #forwardReferences} array when it needs to be
91 * resized to store a new forward reference.
92 */
93 static final int FORWARD_REFERENCES_CAPACITY_INCREMENT = 6;
94
95 /**
96 * The bit mask to extract the type of a forward reference to this label. The extracted type is
97 * either {@link #FORWARD_REFERENCE_TYPE_SHORT} or {@link #FORWARD_REFERENCE_TYPE_WIDE}.
98 *
99 * @see #forwardReferences
100 */
101 static final int FORWARD_REFERENCE_TYPE_MASK = 0xF0000000;
102
103 /**
104 * The type of forward references stored with two bytes in the bytecode. This is the case, for
105 * instance, of a forward reference from an ifnull instruction.
106 */
107 static final int FORWARD_REFERENCE_TYPE_SHORT = 0x10000000;
108
109 /**
110 * The type of forward references stored in four bytes in the bytecode. This is the case, for
111 * instance, of a forward reference from a lookupswitch instruction.
112 */
113 static final int FORWARD_REFERENCE_TYPE_WIDE = 0x20000000;
114
115 /**
116 * The bit mask to extract the 'handle' of a forward reference to this label. The extracted handle
117 * is the bytecode offset where the forward reference value is stored (using either 2 or 4 bytes,
118 * as indicated by the {@link #FORWARD_REFERENCE_TYPE_MASK}).
119 *
120 * @see #forwardReferences
121 */
122 static final int FORWARD_REFERENCE_HANDLE_MASK = 0x0FFFFFFF;
123
124 /**
125 * A sentinel element used to indicate the end of a list of labels.
126 *
127 * @see #nextListElement
128 */
129 static final Label EMPTY_LIST = new Label();
130
131 /**
132 * A user managed state associated with this label. Warning: this field is used by the ASM tree
133 * package. In order to use it with the ASM tree package you must override the getLabelNode method
134 * in MethodNode.
135 */
136 public Object info;
137
138 /**
139 * The type and status of this label or its corresponding basic block. Must be zero or more of
140 * {@link #FLAG_DEBUG_ONLY}, {@link #FLAG_JUMP_TARGET}, {@link #FLAG_RESOLVED}, {@link
141 * #FLAG_REACHABLE}, {@link #FLAG_SUBROUTINE_CALLER}, {@link #FLAG_SUBROUTINE_START}, {@link
142 * #FLAG_SUBROUTINE_END}.
143 */
144 short flags;
145
146 /**
147 * The source line number corresponding to this label, or 0. If there are several source line
148 * numbers corresponding to this label, the first one is stored in this field, and the remaining
149 * ones are stored in {@link #otherLineNumbers}.
150 */
151 private short lineNumber;
152
153 /**
154 * The source line numbers corresponding to this label, in addition to {@link #lineNumber}, or
155 * null. The first element of this array is the number n of source line numbers it contains, which
156 * are stored between indices 1 and n (inclusive).
157 */
158 private int[] otherLineNumbers;
159
160 /**
161 * The offset of this label in the bytecode of its method, in bytes. This value is set if and only
162 * if the {@link #FLAG_RESOLVED} flag is set.
163 */
164 int bytecodeOffset;
165
166 /**
167 * The forward references to this label. The first element is the number of forward references,
168 * times 2 (this corresponds to the index of the last element actually used in this array). Then,
169 * each forward reference is described with two consecutive integers noted
170 * 'sourceInsnBytecodeOffset' and 'reference':
171 *
172 * <ul>
173 * <li>'sourceInsnBytecodeOffset' is the bytecode offset of the instruction that contains the
174 * forward reference,
175 * <li>'reference' contains the type and the offset in the bytecode where the forward reference
176 * value must be stored, which can be extracted with {@link #FORWARD_REFERENCE_TYPE_MASK}
177 * and {@link #FORWARD_REFERENCE_HANDLE_MASK}.
178 * </ul>
179 *
180 * For instance, for an ifnull instruction at bytecode offset x, 'sourceInsnBytecodeOffset' is
181 * equal to x, and 'reference' is of type {@link #FORWARD_REFERENCE_TYPE_SHORT} with value x + 1
182 * (because the ifnull instruction uses a 2 bytes bytecode offset operand stored one byte after
183 * the start of the instruction itself). For the default case of a lookupswitch instruction at
184 * bytecode offset x, 'sourceInsnBytecodeOffset' is equal to x, and 'reference' is of type {@link
185 * #FORWARD_REFERENCE_TYPE_WIDE} with value between x + 1 and x + 4 (because the lookupswitch
186 * instruction uses a 4 bytes bytecode offset operand stored one to four bytes after the start of
187 * the instruction itself).
188 */
189 private int[] forwardReferences;
190
191 // -----------------------------------------------------------------------------------------------
192
193 // Fields for the control flow and data flow graph analysis algorithms (used to compute the
194 // maximum stack size or the stack map frames). A control flow graph contains one node per "basic
195 // block", and one edge per "jump" from one basic block to another. Each node (i.e., each basic
196 // block) is represented with the Label object that corresponds to the first instruction of this
197 // basic block. Each node also stores the list of its successors in the graph, as a linked list of
198 // Edge objects.
199 //
200 // The control flow analysis algorithms used to compute the maximum stack size or the stack map
201 // frames are similar and use two steps. The first step, during the visit of each instruction,
202 // builds information about the state of the local variables and the operand stack at the end of
203 // each basic block, called the "output frame", <i>relatively</i> to the frame state at the
204 // beginning of the basic block, which is called the "input frame", and which is <i>unknown</i>
205 // during this step. The second step, in {@link MethodWriter#computeAllFrames} and {@link
206 // MethodWriter#computeMaxStackAndLocal}, is a fix point algorithm
207 // that computes information about the input frame of each basic block, from the input state of
208 // the first basic block (known from the method signature), and by the using the previously
209 // computed relative output frames.
210 //
211 // The algorithm used to compute the maximum stack size only computes the relative output and
212 // absolute input stack heights, while the algorithm used to compute stack map frames computes
213 // relative output frames and absolute input frames.
214
215 /**
216 * The number of elements in the input stack of the basic block corresponding to this label. This
217 * field is computed in {@link MethodWriter#computeMaxStackAndLocal}.
218 */
219 short inputStackSize;
220
221 /**
222 * The number of elements in the output stack, at the end of the basic block corresponding to this
223 * label. This field is only computed for basic blocks that end with a RET instruction.
224 */
225 short outputStackSize;
226
227 /**
228 * The maximum height reached by the output stack, relatively to the top of the input stack, in
229 * the basic block corresponding to this label. This maximum is always positive or null.
230 */
231 short outputStackMax;
232
233 /**
234 * The id of the subroutine to which this basic block belongs, or 0. If the basic block belongs to
235 * several subroutines, this is the id of the "oldest" subroutine that contains it (with the
236 * convention that a subroutine calling another one is "older" than the callee). This field is
237 * computed in {@link MethodWriter#computeMaxStackAndLocal}, if the method contains JSR
238 * instructions.
239 */
240 short subroutineId;
241
242 /**
243 * The input and output stack map frames of the basic block corresponding to this label. This
244 * field is only used when the {@link MethodWriter#COMPUTE_ALL_FRAMES} or {@link
245 * MethodWriter#COMPUTE_INSERTED_FRAMES} option is used.
246 */
247 Frame frame;
248
249 /**
250 * The successor of this label, in the order they are visited in {@link MethodVisitor#visitLabel}.
251 * This linked list does not include labels used for debug info only. If the {@link
252 * MethodWriter#COMPUTE_ALL_FRAMES} or {@link MethodWriter#COMPUTE_INSERTED_FRAMES} option is used
253 * then it does not contain either successive labels that denote the same bytecode offset (in this
254 * case only the first label appears in this list).
255 */
256 Label nextBasicBlock;
257
258 /**
259 * The outgoing edges of the basic block corresponding to this label, in the control flow graph of
260 * its method. These edges are stored in a linked list of {@link Edge} objects, linked to each
261 * other by their {@link Edge#nextEdge} field.
262 */
263 Edge outgoingEdges;
264
265 /**
266 * The next element in the list of labels to which this label belongs, or null if it does not
267 * belong to any list. All lists of labels must end with the {@link #EMPTY_LIST} sentinel, in
268 * order to ensure that this field is null if and only if this label does not belong to a list of
269 * labels. Note that there can be several lists of labels at the same time, but that a label can
270 * belong to at most one list at a time (unless some lists share a common tail, but this is not
271 * used in practice).
272 *
273 * <p>List of labels are used in {@link MethodWriter#computeAllFrames} and {@link
274 * MethodWriter#computeMaxStackAndLocal} to compute stack map frames and the maximum stack size,
275 * respectively, as well as in {@link #markSubroutine} and {@link #addSubroutineRetSuccessors} to
276 * compute the basic blocks belonging to subroutines and their outgoing edges. Outside of these
277 * methods, this field should be null (this property is a precondition and a postcondition of
278 * these methods).
279 */
280 Label nextListElement;
281
282 // -----------------------------------------------------------------------------------------------
283 // Constructor and accessors
284 // -----------------------------------------------------------------------------------------------
285
286 /** Constructs a new label. */
287 public Label() {
288 // Nothing to do.
289 }
290
291 /**
292 * Returns the bytecode offset corresponding to this label. This offset is computed from the start
293 * of the method's bytecode. <i>This method is intended for {@link Attribute} sub classes, and is
294 * normally not needed by class generators or adapters.</i>
295 *
296 * @return the bytecode offset corresponding to this label.
297 * @throws IllegalStateException if this label is not resolved yet.
298 */
299 public int getOffset() {
300 if ((flags & FLAG_RESOLVED) == 0) {
301 throw new IllegalStateException("Label offset position has not been resolved yet");
302 }
303 return bytecodeOffset;
304 }
305
306 /**
307 * Returns the "canonical" {@link Label} instance corresponding to this label's bytecode offset,
308 * if known, otherwise the label itself. The canonical instance is the first label (in the order
309 * of their visit by {@link MethodVisitor#visitLabel}) corresponding to this bytecode offset. It
310 * cannot be known for labels which have not been visited yet.
311 *
312 * <p><i>This method should only be used when the {@link MethodWriter#COMPUTE_ALL_FRAMES} option
313 * is used.</i>
314 *
315 * @return the label itself if {@link #frame} is null, otherwise the Label's frame owner. This
316 * corresponds to the "canonical" label instance described above thanks to the way the label
317 * frame is set in {@link MethodWriter#visitLabel}.
318 */
319 final Label getCanonicalInstance() {
320 return frame == null ? this : frame.owner;
321 }
322
323 // -----------------------------------------------------------------------------------------------
324 // Methods to manage line numbers
325 // -----------------------------------------------------------------------------------------------
326
327 /**
328 * Adds a source line number corresponding to this label.
329 *
330 * @param lineNumber a source line number (which should be strictly positive).
331 */
332 final void addLineNumber(final int lineNumber) {
333 if (this.lineNumber == 0) {
334 this.lineNumber = (short) lineNumber;
335 } else {
336 if (otherLineNumbers == null) {
337 otherLineNumbers = new int[LINE_NUMBERS_CAPACITY_INCREMENT];
338 }
339 int otherLineNumberIndex = ++otherLineNumbers[0];
340 if (otherLineNumberIndex >= otherLineNumbers.length) {
341 int[] newLineNumbers = new int[otherLineNumbers.length + LINE_NUMBERS_CAPACITY_INCREMENT];
342 System.arraycopy(otherLineNumbers, 0, newLineNumbers, 0, otherLineNumbers.length);
343 otherLineNumbers = newLineNumbers;
344 }
345 otherLineNumbers[otherLineNumberIndex] = lineNumber;
346 }
347 }
348
349 /**
350 * Makes the given visitor visit this label and its source line numbers, if applicable.
351 *
352 * @param methodVisitor a method visitor.
353 * @param visitLineNumbers whether to visit of the label's source line numbers, if any.
354 */
355 final void accept(final MethodVisitor methodVisitor, final boolean visitLineNumbers) {
356 methodVisitor.visitLabel(this);
357 if (visitLineNumbers && lineNumber != 0) {
358 methodVisitor.visitLineNumber(lineNumber & 0xFFFF, this);
359 if (otherLineNumbers != null) {
360 for (int i = 1; i <= otherLineNumbers[0]; ++i) {
361 methodVisitor.visitLineNumber(otherLineNumbers[i], this);
280362 }
281 return position;
282 }
283
284 /**
285 * Puts a reference to this label in the bytecode of a method. If the
286 * position of the label is known, the offset is computed and written
287 * directly. Otherwise, a null offset is written and a new forward reference
288 * is declared for this label.
289 *
290 * @param owner
291 * the code writer that calls this method.
292 * @param out
293 * the bytecode of the method.
294 * @param source
295 * the position of first byte of the bytecode instruction that
296 * contains this label.
297 * @param wideOffset
298 * <tt>true</tt> if the reference must be stored in 4 bytes, or
299 * <tt>false</tt> if it must be stored with 2 bytes.
300 * @throws IllegalArgumentException
301 * if this label has not been created by the given code writer.
302 */
303 void put(final MethodWriter owner, final ByteVector out, final int source,
304 final boolean wideOffset) {
305 if ((status & RESOLVED) == 0) {
306 if (wideOffset) {
307 addReference(-1 - source, out.length);
308 out.putInt(-1);
309 } else {
310 addReference(source, out.length);
311 out.putShort(-1);
312 }
313 } else {
314 if (wideOffset) {
315 out.putInt(position - source);
316 } else {
317 out.putShort(position - source);
318 }
363 }
364 }
365 }
366
367 // -----------------------------------------------------------------------------------------------
368 // Methods to compute offsets and to manage forward references
369 // -----------------------------------------------------------------------------------------------
370
371 /**
372 * Puts a reference to this label in the bytecode of a method. If the bytecode offset of the label
373 * is known, the relative bytecode offset between the label and the instruction referencing it is
374 * computed and written directly. Otherwise, a null relative offset is written and a new forward
375 * reference is declared for this label.
376 *
377 * @param code the bytecode of the method. This is where the reference is appended.
378 * @param sourceInsnBytecodeOffset the bytecode offset of the instruction that contains the
379 * reference to be appended.
380 * @param wideReference whether the reference must be stored in 4 bytes (instead of 2 bytes).
381 */
382 final void put(
383 final ByteVector code, final int sourceInsnBytecodeOffset, final boolean wideReference) {
384 if ((flags & FLAG_RESOLVED) == 0) {
385 if (wideReference) {
386 addForwardReference(sourceInsnBytecodeOffset, FORWARD_REFERENCE_TYPE_WIDE, code.length);
387 code.putInt(-1);
388 } else {
389 addForwardReference(sourceInsnBytecodeOffset, FORWARD_REFERENCE_TYPE_SHORT, code.length);
390 code.putShort(-1);
391 }
392 } else {
393 if (wideReference) {
394 code.putInt(bytecodeOffset - sourceInsnBytecodeOffset);
395 } else {
396 code.putShort(bytecodeOffset - sourceInsnBytecodeOffset);
397 }
398 }
399 }
400
401 /**
402 * Adds a forward reference to this label. This method must be called only for a true forward
403 * reference, i.e. only if this label is not resolved yet. For backward references, the relative
404 * bytecode offset of the reference can be, and must be, computed and stored directly.
405 *
406 * @param sourceInsnBytecodeOffset the bytecode offset of the instruction that contains the
407 * reference stored at referenceHandle.
408 * @param referenceType either {@link #FORWARD_REFERENCE_TYPE_SHORT} or {@link
409 * #FORWARD_REFERENCE_TYPE_WIDE}.
410 * @param referenceHandle the offset in the bytecode where the forward reference value must be
411 * stored.
412 */
413 private void addForwardReference(
414 final int sourceInsnBytecodeOffset, final int referenceType, final int referenceHandle) {
415 if (forwardReferences == null) {
416 forwardReferences = new int[FORWARD_REFERENCES_CAPACITY_INCREMENT];
417 }
418 int lastElementIndex = forwardReferences[0];
419 if (lastElementIndex + 2 >= forwardReferences.length) {
420 int[] newValues = new int[forwardReferences.length + FORWARD_REFERENCES_CAPACITY_INCREMENT];
421 System.arraycopy(forwardReferences, 0, newValues, 0, forwardReferences.length);
422 forwardReferences = newValues;
423 }
424 forwardReferences[++lastElementIndex] = sourceInsnBytecodeOffset;
425 forwardReferences[++lastElementIndex] = referenceType | referenceHandle;
426 forwardReferences[0] = lastElementIndex;
427 }
428
429 /**
430 * Sets the bytecode offset of this label to the given value and resolves the forward references
431 * to this label, if any. This method must be called when this label is added to the bytecode of
432 * the method, i.e. when its bytecode offset becomes known. This method fills in the blanks that
433 * where left in the bytecode by each forward reference previously added to this label.
434 *
435 * @param code the bytecode of the method.
436 * @param bytecodeOffset the bytecode offset of this label.
437 * @return <tt>true</tt> if a blank that was left for this label was too small to store the
438 * offset. In such a case the corresponding jump instruction is replaced with an equivalent
439 * ASM specific instruction using an unsigned two bytes offset. These ASM specific
440 * instructions are later replaced with standard bytecode instructions with wider offsets (4
441 * bytes instead of 2), in ClassReader.
442 */
443 final boolean resolve(final byte[] code, final int bytecodeOffset) {
444 this.flags |= FLAG_RESOLVED;
445 this.bytecodeOffset = bytecodeOffset;
446 if (forwardReferences == null) {
447 return false;
448 }
449 boolean hasAsmInstructions = false;
450 for (int i = forwardReferences[0]; i > 0; i -= 2) {
451 final int sourceInsnBytecodeOffset = forwardReferences[i - 1];
452 final int reference = forwardReferences[i];
453 final int relativeOffset = bytecodeOffset - sourceInsnBytecodeOffset;
454 int handle = reference & FORWARD_REFERENCE_HANDLE_MASK;
455 if ((reference & FORWARD_REFERENCE_TYPE_MASK) == FORWARD_REFERENCE_TYPE_SHORT) {
456 if (relativeOffset < Short.MIN_VALUE || relativeOffset > Short.MAX_VALUE) {
457 // Change the opcode of the jump instruction, in order to be able to find it later in
458 // ClassReader. These ASM specific opcodes are similar to jump instruction opcodes, except
459 // that the 2 bytes offset is unsigned (and can therefore represent values from 0 to
460 // 65535, which is sufficient since the size of a method is limited to 65535 bytes).
461 int opcode = code[sourceInsnBytecodeOffset] & 0xFF;
462 if (opcode < Opcodes.IFNULL) {
463 // Change IFEQ ... JSR to ASM_IFEQ ... ASM_JSR.
464 code[sourceInsnBytecodeOffset] = (byte) (opcode + Constants.ASM_OPCODE_DELTA);
465 } else {
466 // Change IFNULL and IFNONNULL to ASM_IFNULL and ASM_IFNONNULL.
467 code[sourceInsnBytecodeOffset] = (byte) (opcode + Constants.ASM_IFNULL_OPCODE_DELTA);
468 }
469 hasAsmInstructions = true;
319470 }
320 }
321
322 /**
323 * Adds a forward reference to this label. This method must be called only
324 * for a true forward reference, i.e. only if this label is not resolved
325 * yet. For backward references, the offset of the reference can be, and
326 * must be, computed and stored directly.
327 *
328 * @param sourcePosition
329 * the position of the referencing instruction. This position
330 * will be used to compute the offset of this forward reference.
331 * @param referencePosition
332 * the position where the offset for this forward reference must
333 * be stored.
334 */
335 private void addReference(final int sourcePosition,
336 final int referencePosition) {
337 if (srcAndRefPositions == null) {
338 srcAndRefPositions = new int[6];
339 }
340 if (referenceCount >= srcAndRefPositions.length) {
341 int[] a = new int[srcAndRefPositions.length + 6];
342 System.arraycopy(srcAndRefPositions, 0, a, 0,
343 srcAndRefPositions.length);
344 srcAndRefPositions = a;
345 }
346 srcAndRefPositions[referenceCount++] = sourcePosition;
347 srcAndRefPositions[referenceCount++] = referencePosition;
348 }
349
350 /**
351 * Resolves all forward references to this label. This method must be called
352 * when this label is added to the bytecode of the method, i.e. when its
353 * position becomes known. This method fills in the blanks that where left
354 * in the bytecode by each forward reference previously added to this label.
355 *
356 * @param owner
357 * the code writer that calls this method.
358 * @param position
359 * the position of this label in the bytecode.
360 * @param data
361 * the bytecode of the method.
362 * @return <tt>true</tt> if a blank that was left for this label was to
363 * small to store the offset. In such a case the corresponding jump
364 * instruction is replaced with a pseudo instruction (using unused
365 * opcodes) using an unsigned two bytes offset. These pseudo
366 * instructions will need to be replaced with true instructions with
367 * wider offsets (4 bytes instead of 2). This is done in
368 * {@link MethodWriter#resizeInstructions}.
369 * @throws IllegalArgumentException
370 * if this label has already been resolved, or if it has not
371 * been created by the given code writer.
372 */
373 boolean resolve(final MethodWriter owner, final int position,
374 final byte[] data) {
375 boolean needUpdate = false;
376 this.status |= RESOLVED;
377 this.position = position;
378 int i = 0;
379 while (i < referenceCount) {
380 int source = srcAndRefPositions[i++];
381 int reference = srcAndRefPositions[i++];
382 int offset;
383 if (source >= 0) {
384 offset = position - source;
385 if (offset < Short.MIN_VALUE || offset > Short.MAX_VALUE) {
386 /*
387 * changes the opcode of the jump instruction, in order to
388 * be able to find it later (see resizeInstructions in
389 * MethodWriter). These temporary opcodes are similar to
390 * jump instruction opcodes, except that the 2 bytes offset
391 * is unsigned (and can therefore represent values from 0 to
392 * 65535, which is sufficient since the size of a method is
393 * limited to 65535 bytes).
394 */
395 int opcode = data[reference - 1] & 0xFF;
396 if (opcode <= Opcodes.JSR) {
397 // changes IFEQ ... JSR to opcodes 202 to 217
398 data[reference - 1] = (byte) (opcode + 49);
399 } else {
400 // changes IFNULL and IFNONNULL to opcodes 218 and 219
401 data[reference - 1] = (byte) (opcode + 20);
402 }
403 needUpdate = true;
404 }
405 data[reference++] = (byte) (offset >>> 8);
406 data[reference] = (byte) offset;
407 } else {
408 offset = position + source + 1;
409 data[reference++] = (byte) (offset >>> 24);
410 data[reference++] = (byte) (offset >>> 16);
411 data[reference++] = (byte) (offset >>> 8);
412 data[reference] = (byte) offset;
413 }
414 }
415 return needUpdate;
416 }
417
418 /**
419 * Returns the first label of the series to which this label belongs. For an
420 * isolated label or for the first label in a series of successive labels,
421 * this method returns the label itself. For other labels it returns the
422 * first label of the series.
423 *
424 * @return the first label of the series to which this label belongs.
425 */
426 Label getFirst() {
427 return !ClassReader.FRAMES || frame == null ? this : frame.owner;
428 }
429
430 // ------------------------------------------------------------------------
431 // Methods related to subroutines
432 // ------------------------------------------------------------------------
433
434 /**
435 * Returns true is this basic block belongs to the given subroutine.
436 *
437 * @param id
438 * a subroutine id.
439 * @return true is this basic block belongs to the given subroutine.
440 */
441 boolean inSubroutine(final long id) {
442 if ((status & Label.VISITED) != 0) {
443 return (srcAndRefPositions[(int) (id >>> 32)] & (int) id) != 0;
444 }
445 return false;
446 }
447
448 /**
449 * Returns true if this basic block and the given one belong to a common
450 * subroutine.
451 *
452 * @param block
453 * another basic block.
454 * @return true if this basic block and the given one belong to a common
455 * subroutine.
456 */
457 boolean inSameSubroutine(final Label block) {
458 if ((status & VISITED) == 0 || (block.status & VISITED) == 0) {
459 return false;
460 }
461 for (int i = 0; i < srcAndRefPositions.length; ++i) {
462 if ((srcAndRefPositions[i] & block.srcAndRefPositions[i]) != 0) {
463 return true;
464 }
465 }
466 return false;
467 }
468
469 /**
470 * Marks this basic block as belonging to the given subroutine.
471 *
472 * @param id
473 * a subroutine id.
474 * @param nbSubroutines
475 * the total number of subroutines in the method.
476 */
477 void addToSubroutine(final long id, final int nbSubroutines) {
478 if ((status & VISITED) == 0) {
479 status |= VISITED;
480 srcAndRefPositions = new int[nbSubroutines / 32 + 1];
481 }
482 srcAndRefPositions[(int) (id >>> 32)] |= (int) id;
483 }
484
485 /**
486 * Finds the basic blocks that belong to a given subroutine, and marks these
487 * blocks as belonging to this subroutine. This method follows the control
488 * flow graph to find all the blocks that are reachable from the current
489 * block WITHOUT following any JSR target.
490 *
491 * @param JSR
492 * a JSR block that jumps to this subroutine. If this JSR is not
493 * null it is added to the successor of the RET blocks found in
494 * the subroutine.
495 * @param id
496 * the id of this subroutine.
497 * @param nbSubroutines
498 * the total number of subroutines in the method.
499 */
500 void visitSubroutine(final Label JSR, final long id, final int nbSubroutines) {
501 // user managed stack of labels, to avoid using a recursive method
502 // (recursivity can lead to stack overflow with very large methods)
503 Label stack = this;
504 while (stack != null) {
505 // removes a label l from the stack
506 Label l = stack;
507 stack = l.next;
508 l.next = null;
509
510 if (JSR != null) {
511 if ((l.status & VISITED2) != 0) {
512 continue;
513 }
514 l.status |= VISITED2;
515 // adds JSR to the successors of l, if it is a RET block
516 if ((l.status & RET) != 0) {
517 if (!l.inSameSubroutine(JSR)) {
518 Edge e = new Edge();
519 e.info = l.inputStackTop;
520 e.successor = JSR.successors.successor;
521 e.next = l.successors;
522 l.successors = e;
523 }
524 }
525 } else {
526 // if the l block already belongs to subroutine 'id', continue
527 if (l.inSubroutine(id)) {
528 continue;
529 }
530 // marks the l block as belonging to subroutine 'id'
531 l.addToSubroutine(id, nbSubroutines);
532 }
533 // pushes each successor of l on the stack, except JSR targets
534 Edge e = l.successors;
535 while (e != null) {
536 // if the l block is a JSR block, then 'l.successors.next' leads
537 // to the JSR target (see {@link #visitJumpInsn}) and must
538 // therefore not be followed
539 if ((l.status & Label.JSR) == 0 || e != l.successors.next) {
540 // pushes e.successor on the stack if it not already added
541 if (e.successor.next == null) {
542 e.successor.next = stack;
543 stack = e.successor;
544 }
545 }
546 e = e.next;
547 }
548 }
549 }
550
551 // ------------------------------------------------------------------------
552 // Overriden Object methods
553 // ------------------------------------------------------------------------
554
555 /**
556 * Returns a string representation of this label.
557 *
558 * @return a string representation of this label.
559 */
560 @Override
561 public String toString() {
562 return "L" + System.identityHashCode(this);
563 }
471 code[handle++] = (byte) (relativeOffset >>> 8);
472 code[handle] = (byte) relativeOffset;
473 } else {
474 code[handle++] = (byte) (relativeOffset >>> 24);
475 code[handle++] = (byte) (relativeOffset >>> 16);
476 code[handle++] = (byte) (relativeOffset >>> 8);
477 code[handle] = (byte) relativeOffset;
478 }
479 }
480 return hasAsmInstructions;
481 }
482
483 // -----------------------------------------------------------------------------------------------
484 // Methods related to subroutines
485 // -----------------------------------------------------------------------------------------------
486
487 /**
488 * Finds the basic blocks that belong to the subroutine starting with the basic block
489 * corresponding to this label, and marks these blocks as belonging to this subroutine. This
490 * method follows the control flow graph to find all the blocks that are reachable from the
491 * current basic block WITHOUT following any jsr target.
492 *
493 * <p>Note: a precondition and postcondition of this method is that all labels must have a null
494 * {@link #nextListElement}.
495 *
496 * @param subroutineId the id of the subroutine starting with the basic block corresponding to
497 * this label.
498 */
499 final void markSubroutine(final short subroutineId) {
500 // Data flow algorithm: put this basic block in a list of blocks to process (which are blocks
501 // belonging to subroutine subroutineId) and, while there are blocks to process, remove one from
502 // the list, mark it as belonging to the subroutine, and add its successor basic blocks in the
503 // control flow graph to the list of blocks to process (if not already done).
504 Label listOfBlocksToProcess = this;
505 listOfBlocksToProcess.nextListElement = EMPTY_LIST;
506 while (listOfBlocksToProcess != EMPTY_LIST) {
507 // Remove a basic block from the list of blocks to process.
508 Label basicBlock = listOfBlocksToProcess;
509 listOfBlocksToProcess = listOfBlocksToProcess.nextListElement;
510 basicBlock.nextListElement = null;
511
512 // If it is not already marked as belonging to a subroutine, mark it as belonging to
513 // subroutineId and add its successors to the list of blocks to process (unless already done).
514 if (basicBlock.subroutineId == 0) {
515 basicBlock.subroutineId = subroutineId;
516 listOfBlocksToProcess = basicBlock.pushSuccessors(listOfBlocksToProcess);
517 }
518 }
519 }
520
521 /**
522 * Finds the basic blocks that end a subroutine starting with the basic block corresponding to
523 * this label and, for each one of them, adds an outgoing edge to the basic block following the
524 * given subroutine call. In other words, completes the control flow graph by adding the edges
525 * corresponding to the return from this subroutine, when called from the given caller basic
526 * block.
527 *
528 * <p>Note: a precondition and postcondition of this method is that all labels must have a null
529 * {@link #nextListElement}.
530 *
531 * @param subroutineCaller a basic block that ends with a jsr to the basic block corresponding to
532 * this label. This label is supposed to correspond to the start of a subroutine.
533 */
534 final void addSubroutineRetSuccessors(final Label subroutineCaller) {
535 // Data flow algorithm: put this basic block in a list blocks to process (which are blocks
536 // belonging to a subroutine starting with this label) and, while there are blocks to process,
537 // remove one from the list, put it in a list of blocks that have been processed, add a return
538 // edge to the successor of subroutineCaller if applicable, and add its successor basic blocks
539 // in the control flow graph to the list of blocks to process (if not already done).
540 Label listOfProcessedBlocks = EMPTY_LIST;
541 Label listOfBlocksToProcess = this;
542 listOfBlocksToProcess.nextListElement = EMPTY_LIST;
543 while (listOfBlocksToProcess != EMPTY_LIST) {
544 // Move a basic block from the list of blocks to process to the list of processed blocks.
545 Label basicBlock = listOfBlocksToProcess;
546 listOfBlocksToProcess = basicBlock.nextListElement;
547 basicBlock.nextListElement = listOfProcessedBlocks;
548 listOfProcessedBlocks = basicBlock;
549
550 // Add an edge from this block to the successor of the caller basic block, if this block is
551 // the end of a subroutine and if this block and subroutineCaller do not belong to the same
552 // subroutine.
553 if ((basicBlock.flags & FLAG_SUBROUTINE_END) != 0
554 && basicBlock.subroutineId != subroutineCaller.subroutineId) {
555 basicBlock.outgoingEdges =
556 new Edge(
557 basicBlock.outputStackSize,
558 // By construction, the first outgoing edge of a basic block that ends with a jsr
559 // instruction leads to the jsr continuation block, i.e. where execution continues
560 // when ret is called (see {@link #FLAG_SUBROUTINE_CALLER}).
561 subroutineCaller.outgoingEdges.successor,
562 basicBlock.outgoingEdges);
563 }
564 // Add its successors to the list of blocks to process. Note that {@link #pushSuccessors} does
565 // not push basic blocks which are already in a list. Here this means either in the list of
566 // blocks to process, or in the list of already processed blocks. This second list is
567 // important to make sure we don't reprocess an already processed block.
568 listOfBlocksToProcess = basicBlock.pushSuccessors(listOfBlocksToProcess);
569 }
570 // Reset the {@link #nextListElement} of all the basic blocks that have been processed to null,
571 // so that this method can be called again with a different subroutine or subroutine caller.
572 while (listOfProcessedBlocks != EMPTY_LIST) {
573 Label newListOfProcessedBlocks = listOfProcessedBlocks.nextListElement;
574 listOfProcessedBlocks.nextListElement = null;
575 listOfProcessedBlocks = newListOfProcessedBlocks;
576 }
577 }
578
579 /**
580 * Adds the successors of this label in the method's control flow graph (except those
581 * corresponding to a jsr target, and those already in a list of labels) to the given list of
582 * blocks to process, and returns the new list.
583 *
584 * @param listOfLabelsToProcess a list of basic blocks to process, linked together with their
585 * {@link #nextListElement} field.
586 * @return the new list of blocks to process.
587 */
588 private Label pushSuccessors(final Label listOfLabelsToProcess) {
589 Label newListOfLabelsToProcess = listOfLabelsToProcess;
590 Edge outgoingEdge = outgoingEdges;
591 while (outgoingEdge != null) {
592 // By construction, the second outgoing edge of a basic block that ends with a jsr instruction
593 // leads to the jsr target (see {@link #FLAG_SUBROUTINE_CALLER}).
594 boolean isJsrTarget =
595 (flags & Label.FLAG_SUBROUTINE_CALLER) != 0 && outgoingEdge == outgoingEdges.nextEdge;
596 if (!isJsrTarget && outgoingEdge.successor.nextListElement == null) {
597 // Add this successor to the list of blocks to process, if it does not already belong to a
598 // list of labels.
599 outgoingEdge.successor.nextListElement = newListOfLabelsToProcess;
600 newListOfLabelsToProcess = outgoingEdge.successor;
601 }
602 outgoingEdge = outgoingEdge.nextEdge;
603 }
604 return newListOfLabelsToProcess;
605 }
606
607 // -----------------------------------------------------------------------------------------------
608 // Overridden Object methods
609 // -----------------------------------------------------------------------------------------------
610
611 /**
612 * Returns a string representation of this label.
613 *
614 * @return a string representation of this label.
615 */
616 @Override
617 public String toString() {
618 return "L" + System.identityHashCode(this);
619 }
564620 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
27 package org.eclipse.persistence.internal.libraries.asm;
28
29 /**
30 * A visitor to visit a Java method. The methods of this class must be called in the following
31 * order: ( <tt>visitParameter</tt> )* [ <tt>visitAnnotationDefault</tt> ] (
32 * <tt>visitAnnotation</tt> | <tt>visitAnnotableParameterCount</tt> |
33 * <tt>visitParameterAnnotation</tt> <tt>visitTypeAnnotation</tt> | <tt>visitAttribute</tt> )* [
34 * <tt>visitCode</tt> ( <tt>visitFrame</tt> | <tt>visit<i>X</i>Insn</tt> | <tt>visitLabel</tt> |
35 * <tt>visitInsnAnnotation</tt> | <tt>visitTryCatchBlock</tt> | <tt>visitTryCatchAnnotation</tt> |
36 * <tt>visitLocalVariable</tt> | <tt>visitLocalVariableAnnotation</tt> | <tt>visitLineNumber</tt> )*
37 * <tt>visitMaxs</tt> ] <tt>visitEnd</tt>. In addition, the <tt>visit<i>X</i>Insn</tt> and
38 * <tt>visitLabel</tt> methods must be called in the sequential order of the bytecode instructions
39 * of the visited code, <tt>visitInsnAnnotation</tt> must be called <i>after</i> the annotated
40 * instruction, <tt>visitTryCatchBlock</tt> must be called <i>before</i> the labels passed as
41 * arguments have been visited, <tt>visitTryCatchBlockAnnotation</tt> must be called <i>after</i>
42 * the corresponding try catch block has been visited, and the <tt>visitLocalVariable</tt>,
43 * <tt>visitLocalVariableAnnotation</tt> and <tt>visitLineNumber</tt> methods must be called
44 * <i>after</i> the labels passed as arguments have been visited.
445 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 package org.eclipse.persistence.internal.libraries.asm;
30
31 /**
32 * A visitor to visit a Java method. The methods of this class must be called in
33 * the following order: ( <tt>visitParameter</tt> )* [
34 * <tt>visitAnnotationDefault</tt> ] ( <tt>visitAnnotation</tt> |
35 * <tt>visitParameterAnnotation</tt> <tt>visitTypeAnnotation</tt> |
36 * <tt>visitAttribute</tt> )* [ <tt>visitCode</tt> ( <tt>visitFrame</tt> |
37 * <tt>visit<i>X</i>Insn</tt> | <tt>visitLabel</tt> |
38 * <tt>visitInsnAnnotation</tt> | <tt>visitTryCatchBlock</tt> |
39 * <tt>visitTryCatchAnnotation</tt> | <tt>visitLocalVariable</tt> |
40 * <tt>visitLocalVariableAnnotation</tt> | <tt>visitLineNumber</tt> )*
41 * <tt>visitMaxs</tt> ] <tt>visitEnd</tt>. In addition, the
42 * <tt>visit<i>X</i>Insn</tt> and <tt>visitLabel</tt> methods must be called in
43 * the sequential order of the bytecode instructions of the visited code,
44 * <tt>visitInsnAnnotation</tt> must be called <i>after</i> the annotated
45 * instruction, <tt>visitTryCatchBlock</tt> must be called <i>before</i> the
46 * labels passed as arguments have been visited,
47 * <tt>visitTryCatchBlockAnnotation</tt> must be called <i>after</i> the
48 * corresponding try catch block has been visited, and the
49 * <tt>visitLocalVariable</tt>, <tt>visitLocalVariableAnnotation</tt> and
50 * <tt>visitLineNumber</tt> methods must be called <i>after</i> the labels
51 * passed as arguments have been visited.
52 *
5346 * @author Eric Bruneton
5447 */
5548 public abstract class MethodVisitor {
5649
57 /**
58 * The ASM API version implemented by this visitor. The value of this field
59 * must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
60 */
61 protected final int api;
62
63 /**
64 * The method visitor to which this visitor must delegate method calls. May
65 * be null.
66 */
67 protected MethodVisitor mv;
68
69 /**
70 * Constructs a new {@link MethodVisitor}.
71 *
72 * @param api
73 * the ASM API version implemented by this visitor. Must be one
74 * of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
75 */
76 public MethodVisitor(final int api) {
77 this(api, null);
78 }
79
80 /**
81 * Constructs a new {@link MethodVisitor}.
82 *
83 * @param api
84 * the ASM API version implemented by this visitor. Must be one
85 * of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
86 * @param mv
87 * the method visitor to which this visitor must delegate method
88 * calls. May be null.
89 */
90 public MethodVisitor(final int api, final MethodVisitor mv) {
91 if (api < Opcodes.ASM4 || api > Opcodes.ASM6) {
92 throw new IllegalArgumentException();
93 }
94 this.api = api;
95 this.mv = mv;
96 }
97
98 // -------------------------------------------------------------------------
99 // Parameters, annotations and non standard attributes
100 // -------------------------------------------------------------------------
101
102 /**
103 * Visits a parameter of this method.
104 *
105 * @param name
106 * parameter name or null if none is provided.
107 * @param access
108 * the parameter's access flags, only <tt>ACC_FINAL</tt>,
109 * <tt>ACC_SYNTHETIC</tt> or/and <tt>ACC_MANDATED</tt> are
110 * allowed (see {@link Opcodes}).
111 */
112 public void visitParameter(String name, int access) {
113 if (api < Opcodes.ASM5) {
114 throw new RuntimeException();
115 }
116 if (mv != null) {
117 mv.visitParameter(name, access);
118 }
119 }
120
121 /**
122 * Visits the default value of this annotation interface method.
123 *
124 * @return a visitor to the visit the actual default value of this
125 * annotation interface method, or <tt>null</tt> if this visitor is
126 * not interested in visiting this default value. The 'name'
127 * parameters passed to the methods of this annotation visitor are
128 * ignored. Moreover, exacly one visit method must be called on this
129 * annotation visitor, followed by visitEnd.
130 */
131 public AnnotationVisitor visitAnnotationDefault() {
132 if (mv != null) {
133 return mv.visitAnnotationDefault();
134 }
135 return null;
136 }
137
138 /**
139 * Visits an annotation of this method.
140 *
141 * @param desc
142 * the class descriptor of the annotation class.
143 * @param visible
144 * <tt>true</tt> if the annotation is visible at runtime.
145 * @return a visitor to visit the annotation values, or <tt>null</tt> if
146 * this visitor is not interested in visiting this annotation.
147 */
148 public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
149 if (mv != null) {
150 return mv.visitAnnotation(desc, visible);
151 }
152 return null;
153 }
154
155 /**
156 * Visits an annotation on a type in the method signature.
157 *
158 * @param typeRef
159 * a reference to the annotated type. The sort of this type
160 * reference must be {@link TypeReference#METHOD_TYPE_PARAMETER
161 * METHOD_TYPE_PARAMETER},
162 * {@link TypeReference#METHOD_TYPE_PARAMETER_BOUND
163 * METHOD_TYPE_PARAMETER_BOUND},
164 * {@link TypeReference#METHOD_RETURN METHOD_RETURN},
165 * {@link TypeReference#METHOD_RECEIVER METHOD_RECEIVER},
166 * {@link TypeReference#METHOD_FORMAL_PARAMETER
167 * METHOD_FORMAL_PARAMETER} or {@link TypeReference#THROWS
168 * THROWS}. See {@link TypeReference}.
169 * @param typePath
170 * the path to the annotated type argument, wildcard bound, array
171 * element type, or static inner type within 'typeRef'. May be
172 * <tt>null</tt> if the annotation targets 'typeRef' as a whole.
173 * @param desc
174 * the class descriptor of the annotation class.
175 * @param visible
176 * <tt>true</tt> if the annotation is visible at runtime.
177 * @return a visitor to visit the annotation values, or <tt>null</tt> if
178 * this visitor is not interested in visiting this annotation.
179 */
180 public AnnotationVisitor visitTypeAnnotation(int typeRef,
181 TypePath typePath, String desc, boolean visible) {
182 if (api < Opcodes.ASM5) {
183 throw new RuntimeException();
184 }
185 if (mv != null) {
186 return mv.visitTypeAnnotation(typeRef, typePath, desc, visible);
187 }
188 return null;
189 }
190
191 /**
192 * Visits an annotation of a parameter this method.
193 *
194 * @param parameter
195 * the parameter index.
196 * @param desc
197 * the class descriptor of the annotation class.
198 * @param visible
199 * <tt>true</tt> if the annotation is visible at runtime.
200 * @return a visitor to visit the annotation values, or <tt>null</tt> if
201 * this visitor is not interested in visiting this annotation.
202 */
203 public AnnotationVisitor visitParameterAnnotation(int parameter,
204 String desc, boolean visible) {
205 if (mv != null) {
206 return mv.visitParameterAnnotation(parameter, desc, visible);
207 }
208 return null;
209 }
210
211 /**
212 * Visits a non standard attribute of this method.
213 *
214 * @param attr
215 * an attribute.
216 */
217 public void visitAttribute(Attribute attr) {
218 if (mv != null) {
219 mv.visitAttribute(attr);
220 }
221 }
222
223 /**
224 * Starts the visit of the method's code, if any (i.e. non abstract method).
225 */
226 public void visitCode() {
227 if (mv != null) {
228 mv.visitCode();
229 }
230 }
231
232 /**
233 * Visits the current state of the local variables and operand stack
234 * elements. This method must(*) be called <i>just before</i> any
235 * instruction <b>i</b> that follows an unconditional branch instruction
236 * such as GOTO or THROW, that is the target of a jump instruction, or that
237 * starts an exception handler block. The visited types must describe the
238 * values of the local variables and of the operand stack elements <i>just
239 * before</i> <b>i</b> is executed.<br>
240 * <br>
241 * (*) this is mandatory only for classes whose version is greater than or
242 * equal to {@link Opcodes#V1_6 V1_6}. <br>
243 * <br>
244 * The frames of a method must be given either in expanded form, or in
245 * compressed form (all frames must use the same format, i.e. you must not
246 * mix expanded and compressed frames within a single method):
247 * <ul>
248 * <li>In expanded form, all frames must have the F_NEW type.</li>
249 * <li>In compressed form, frames are basically "deltas" from the state of
250 * the previous frame:
251 * <ul>
252 * <li>{@link Opcodes#F_SAME} representing frame with exactly the same
253 * locals as the previous frame and with the empty stack.</li>
254 * <li>{@link Opcodes#F_SAME1} representing frame with exactly the same
255 * locals as the previous frame and with single value on the stack (
256 * <code>nStack</code> is 1 and <code>stack[0]</code> contains value for the
257 * type of the stack item).</li>
258 * <li>{@link Opcodes#F_APPEND} representing frame with current locals are
259 * the same as the locals in the previous frame, except that additional
260 * locals are defined (<code>nLocal</code> is 1, 2 or 3 and
261 * <code>local</code> elements contains values representing added types).</li>
262 * <li>{@link Opcodes#F_CHOP} representing frame with current locals are the
263 * same as the locals in the previous frame, except that the last 1-3 locals
264 * are absent and with the empty stack (<code>nLocals</code> is 1, 2 or 3).</li>
265 * <li>{@link Opcodes#F_FULL} representing complete frame data.</li>
266 * </ul>
267 * </li>
268 * </ul>
269 * <br>
270 * In both cases the first frame, corresponding to the method's parameters
271 * and access flags, is implicit and must not be visited. Also, it is
272 * illegal to visit two or more frames for the same code location (i.e., at
273 * least one instruction must be visited between two calls to visitFrame).
274 *
275 * @param type
276 * the type of this stack map frame. Must be
277 * {@link Opcodes#F_NEW} for expanded frames, or
278 * {@link Opcodes#F_FULL}, {@link Opcodes#F_APPEND},
279 * {@link Opcodes#F_CHOP}, {@link Opcodes#F_SAME} or
280 * {@link Opcodes#F_APPEND}, {@link Opcodes#F_SAME1} for
281 * compressed frames.
282 * @param nLocal
283 * the number of local variables in the visited frame.
284 * @param local
285 * the local variable types in this frame. This array must not be
286 * modified. Primitive types are represented by
287 * {@link Opcodes#TOP}, {@link Opcodes#INTEGER},
288 * {@link Opcodes#FLOAT}, {@link Opcodes#LONG},
289 * {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or
290 * {@link Opcodes#UNINITIALIZED_THIS} (long and double are
291 * represented by a single element). Reference types are
292 * represented by String objects (representing internal names),
293 * and uninitialized types by Label objects (this label
294 * designates the NEW instruction that created this uninitialized
295 * value).
296 * @param nStack
297 * the number of operand stack elements in the visited frame.
298 * @param stack
299 * the operand stack types in this frame. This array must not be
300 * modified. Its content has the same format as the "local"
301 * array.
302 * @throws IllegalStateException
303 * if a frame is visited just after another one, without any
304 * instruction between the two (unless this frame is a
305 * Opcodes#F_SAME frame, in which case it is silently ignored).
306 */
307 public void visitFrame(int type, int nLocal, Object[] local, int nStack,
308 Object[] stack) {
309 if (mv != null) {
310 mv.visitFrame(type, nLocal, local, nStack, stack);
311 }
312 }
313
314 // -------------------------------------------------------------------------
315 // Normal instructions
316 // -------------------------------------------------------------------------
317
318 /**
319 * Visits a zero operand instruction.
320 *
321 * @param opcode
322 * the opcode of the instruction to be visited. This opcode is
323 * either NOP, ACONST_NULL, ICONST_M1, ICONST_0, ICONST_1,
324 * ICONST_2, ICONST_3, ICONST_4, ICONST_5, LCONST_0, LCONST_1,
325 * FCONST_0, FCONST_1, FCONST_2, DCONST_0, DCONST_1, IALOAD,
326 * LALOAD, FALOAD, DALOAD, AALOAD, BALOAD, CALOAD, SALOAD,
327 * IASTORE, LASTORE, FASTORE, DASTORE, AASTORE, BASTORE, CASTORE,
328 * SASTORE, POP, POP2, DUP, DUP_X1, DUP_X2, DUP2, DUP2_X1,
329 * DUP2_X2, SWAP, IADD, LADD, FADD, DADD, ISUB, LSUB, FSUB, DSUB,
330 * IMUL, LMUL, FMUL, DMUL, IDIV, LDIV, FDIV, DDIV, IREM, LREM,
331 * FREM, DREM, INEG, LNEG, FNEG, DNEG, ISHL, LSHL, ISHR, LSHR,
332 * IUSHR, LUSHR, IAND, LAND, IOR, LOR, IXOR, LXOR, I2L, I2F, I2D,
333 * L2I, L2F, L2D, F2I, F2L, F2D, D2I, D2L, D2F, I2B, I2C, I2S,
334 * LCMP, FCMPL, FCMPG, DCMPL, DCMPG, IRETURN, LRETURN, FRETURN,
335 * DRETURN, ARETURN, RETURN, ARRAYLENGTH, ATHROW, MONITORENTER,
336 * or MONITOREXIT.
337 */
338 public void visitInsn(int opcode) {
339 if (mv != null) {
340 mv.visitInsn(opcode);
341 }
342 }
343
344 /**
345 * Visits an instruction with a single int operand.
346 *
347 * @param opcode
348 * the opcode of the instruction to be visited. This opcode is
349 * either BIPUSH, SIPUSH or NEWARRAY.
350 * @param operand
351 * the operand of the instruction to be visited.<br>
352 * When opcode is BIPUSH, operand value should be between
353 * Byte.MIN_VALUE and Byte.MAX_VALUE.<br>
354 * When opcode is SIPUSH, operand value should be between
355 * Short.MIN_VALUE and Short.MAX_VALUE.<br>
356 * When opcode is NEWARRAY, operand value should be one of
357 * {@link Opcodes#T_BOOLEAN}, {@link Opcodes#T_CHAR},
358 * {@link Opcodes#T_FLOAT}, {@link Opcodes#T_DOUBLE},
359 * {@link Opcodes#T_BYTE}, {@link Opcodes#T_SHORT},
360 * {@link Opcodes#T_INT} or {@link Opcodes#T_LONG}.
361 */
362 public void visitIntInsn(int opcode, int operand) {
363 if (mv != null) {
364 mv.visitIntInsn(opcode, operand);
365 }
366 }
367
368 /**
369 * Visits a local variable instruction. A local variable instruction is an
370 * instruction that loads or stores the value of a local variable.
371 *
372 * @param opcode
373 * the opcode of the local variable instruction to be visited.
374 * This opcode is either ILOAD, LLOAD, FLOAD, DLOAD, ALOAD,
375 * ISTORE, LSTORE, FSTORE, DSTORE, ASTORE or RET.
376 * @param var
377 * the operand of the instruction to be visited. This operand is
378 * the index of a local variable.
379 */
380 public void visitVarInsn(int opcode, int var) {
381 if (mv != null) {
382 mv.visitVarInsn(opcode, var);
383 }
384 }
385
386 /**
387 * Visits a type instruction. A type instruction is an instruction that
388 * takes the internal name of a class as parameter.
389 *
390 * @param opcode
391 * the opcode of the type instruction to be visited. This opcode
392 * is either NEW, ANEWARRAY, CHECKCAST or INSTANCEOF.
393 * @param type
394 * the operand of the instruction to be visited. This operand
395 * must be the internal name of an object or array class (see
396 * {@link Type#getInternalName() getInternalName}).
397 */
398 public void visitTypeInsn(int opcode, String type) {
399 if (mv != null) {
400 mv.visitTypeInsn(opcode, type);
401 }
402 }
403
404 /**
405 * Visits a field instruction. A field instruction is an instruction that
406 * loads or stores the value of a field of an object.
407 *
408 * @param opcode
409 * the opcode of the type instruction to be visited. This opcode
410 * is either GETSTATIC, PUTSTATIC, GETFIELD or PUTFIELD.
411 * @param owner
412 * the internal name of the field's owner class (see
413 * {@link Type#getInternalName() getInternalName}).
414 * @param name
415 * the field's name.
416 * @param desc
417 * the field's descriptor (see {@link Type Type}).
418 */
419 public void visitFieldInsn(int opcode, String owner, String name,
420 String desc) {
421 if (mv != null) {
422 mv.visitFieldInsn(opcode, owner, name, desc);
423 }
424 }
425
426 /**
427 * Visits a method instruction. A method instruction is an instruction that
428 * invokes a method.
429 *
430 * @param opcode
431 * the opcode of the type instruction to be visited. This opcode
432 * is either INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or
433 * INVOKEINTERFACE.
434 * @param owner
435 * the internal name of the method's owner class (see
436 * {@link Type#getInternalName() getInternalName}).
437 * @param name
438 * the method's name.
439 * @param desc
440 * the method's descriptor (see {@link Type Type}).
441 */
442 @Deprecated
443 public void visitMethodInsn(int opcode, String owner, String name,
444 String desc) {
445 if (api >= Opcodes.ASM5) {
446 boolean itf = opcode == Opcodes.INVOKEINTERFACE;
447 visitMethodInsn(opcode, owner, name, desc, itf);
448 return;
449 }
450 if (mv != null) {
451 mv.visitMethodInsn(opcode, owner, name, desc);
452 }
453 }
454
455 /**
456 * Visits a method instruction. A method instruction is an instruction that
457 * invokes a method.
458 *
459 * @param opcode
460 * the opcode of the type instruction to be visited. This opcode
461 * is either INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or
462 * INVOKEINTERFACE.
463 * @param owner
464 * the internal name of the method's owner class (see
465 * {@link Type#getInternalName() getInternalName}).
466 * @param name
467 * the method's name.
468 * @param desc
469 * the method's descriptor (see {@link Type Type}).
470 * @param itf
471 * if the method's owner class is an interface.
472 */
473 public void visitMethodInsn(int opcode, String owner, String name,
474 String desc, boolean itf) {
475 if (api < Opcodes.ASM5) {
476 if (itf != (opcode == Opcodes.INVOKEINTERFACE)) {
477 throw new IllegalArgumentException(
478 "INVOKESPECIAL/STATIC on interfaces require ASM 5");
479 }
480 visitMethodInsn(opcode, owner, name, desc);
481 return;
482 }
483 if (mv != null) {
484 mv.visitMethodInsn(opcode, owner, name, desc, itf);
485 }
486 }
487
488 /**
489 * Visits an invokedynamic instruction.
490 *
491 * @param name
492 * the method's name.
493 * @param desc
494 * the method's descriptor (see {@link Type Type}).
495 * @param bsm
496 * the bootstrap method.
497 * @param bsmArgs
498 * the bootstrap method constant arguments. Each argument must be
499 * an {@link Integer}, {@link Float}, {@link Long},
500 * {@link Double}, {@link String}, {@link Type} or {@link Handle}
501 * value. This method is allowed to modify the content of the
502 * array so a caller should expect that this array may change.
503 */
504 public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
505 Object... bsmArgs) {
506 if (mv != null) {
507 mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
508 }
509 }
510
511 /**
512 * Visits a jump instruction. A jump instruction is an instruction that may
513 * jump to another instruction.
514 *
515 * @param opcode
516 * the opcode of the type instruction to be visited. This opcode
517 * is either IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, IF_ICMPEQ,
518 * IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE,
519 * IF_ACMPEQ, IF_ACMPNE, GOTO, JSR, IFNULL or IFNONNULL.
520 * @param label
521 * the operand of the instruction to be visited. This operand is
522 * a label that designates the instruction to which the jump
523 * instruction may jump.
524 */
525 public void visitJumpInsn(int opcode, Label label) {
526 if (mv != null) {
527 mv.visitJumpInsn(opcode, label);
528 }
529 }
530
531 /**
532 * Visits a label. A label designates the instruction that will be visited
533 * just after it.
534 *
535 * @param label
536 * a {@link Label Label} object.
537 */
538 public void visitLabel(Label label) {
539 if (mv != null) {
540 mv.visitLabel(label);
541 }
542 }
543
544 // -------------------------------------------------------------------------
545 // Special instructions
546 // -------------------------------------------------------------------------
547
548 /**
549 * Visits a LDC instruction. Note that new constant types may be added in
550 * future versions of the Java Virtual Machine. To easily detect new
551 * constant types, implementations of this method should check for
552 * unexpected constant types, like this:
553 *
554 * <pre>
555 * if (cst instanceof Integer) {
556 * // ...
557 * } else if (cst instanceof Float) {
558 * // ...
559 * } else if (cst instanceof Long) {
560 * // ...
561 * } else if (cst instanceof Double) {
562 * // ...
563 * } else if (cst instanceof String) {
564 * // ...
565 * } else if (cst instanceof Type) {
566 * int sort = ((Type) cst).getSort();
567 * if (sort == Type.OBJECT) {
568 * // ...
569 * } else if (sort == Type.ARRAY) {
570 * // ...
571 * } else if (sort == Type.METHOD) {
572 * // ...
573 * } else {
574 * // throw an exception
575 * }
576 * } else if (cst instanceof Handle) {
577 * // ...
578 * } else {
579 * // throw an exception
580 * }
581 * </pre>
582 *
583 * @param cst
584 * the constant to be loaded on the stack. This parameter must be
585 * a non null {@link Integer}, a {@link Float}, a {@link Long}, a
586 * {@link Double}, a {@link String}, a {@link Type} of OBJECT or
587 * ARRAY sort for <tt>.class</tt> constants, for classes whose
588 * version is 49.0, a {@link Type} of METHOD sort or a
589 * {@link Handle} for MethodType and MethodHandle constants, for
590 * classes whose version is 51.0.
591 */
592 public void visitLdcInsn(Object cst) {
593 if (mv != null) {
594 mv.visitLdcInsn(cst);
595 }
596 }
597
598 /**
599 * Visits an IINC instruction.
600 *
601 * @param var
602 * index of the local variable to be incremented.
603 * @param increment
604 * amount to increment the local variable by.
605 */
606 public void visitIincInsn(int var, int increment) {
607 if (mv != null) {
608 mv.visitIincInsn(var, increment);
609 }
610 }
611
612 /**
613 * Visits a TABLESWITCH instruction.
614 *
615 * @param min
616 * the minimum key value.
617 * @param max
618 * the maximum key value.
619 * @param dflt
620 * beginning of the default handler block.
621 * @param labels
622 * beginnings of the handler blocks. <tt>labels[i]</tt> is the
623 * beginning of the handler block for the <tt>min + i</tt> key.
624 */
625 public void visitTableSwitchInsn(int min, int max, Label dflt,
626 Label... labels) {
627 if (mv != null) {
628 mv.visitTableSwitchInsn(min, max, dflt, labels);
629 }
630 }
631
632 /**
633 * Visits a LOOKUPSWITCH instruction.
634 *
635 * @param dflt
636 * beginning of the default handler block.
637 * @param keys
638 * the values of the keys.
639 * @param labels
640 * beginnings of the handler blocks. <tt>labels[i]</tt> is the
641 * beginning of the handler block for the <tt>keys[i]</tt> key.
642 */
643 public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
644 if (mv != null) {
645 mv.visitLookupSwitchInsn(dflt, keys, labels);
646 }
647 }
648
649 /**
650 * Visits a MULTIANEWARRAY instruction.
651 *
652 * @param desc
653 * an array type descriptor (see {@link Type Type}).
654 * @param dims
655 * number of dimensions of the array to allocate.
656 */
657 public void visitMultiANewArrayInsn(String desc, int dims) {
658 if (mv != null) {
659 mv.visitMultiANewArrayInsn(desc, dims);
660 }
661 }
662
663 /**
664 * Visits an annotation on an instruction. This method must be called just
665 * <i>after</i> the annotated instruction. It can be called several times
666 * for the same instruction.
667 *
668 * @param typeRef
669 * a reference to the annotated type. The sort of this type
670 * reference must be {@link TypeReference#INSTANCEOF INSTANCEOF},
671 * {@link TypeReference#NEW NEW},
672 * {@link TypeReference#CONSTRUCTOR_REFERENCE
673 * CONSTRUCTOR_REFERENCE}, {@link TypeReference#METHOD_REFERENCE
674 * METHOD_REFERENCE}, {@link TypeReference#CAST CAST},
675 * {@link TypeReference#CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
676 * CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT},
677 * {@link TypeReference#METHOD_INVOCATION_TYPE_ARGUMENT
678 * METHOD_INVOCATION_TYPE_ARGUMENT},
679 * {@link TypeReference#CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
680 * CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or
681 * {@link TypeReference#METHOD_REFERENCE_TYPE_ARGUMENT
682 * METHOD_REFERENCE_TYPE_ARGUMENT}. See {@link TypeReference}.
683 * @param typePath
684 * the path to the annotated type argument, wildcard bound, array
685 * element type, or static inner type within 'typeRef'. May be
686 * <tt>null</tt> if the annotation targets 'typeRef' as a whole.
687 * @param desc
688 * the class descriptor of the annotation class.
689 * @param visible
690 * <tt>true</tt> if the annotation is visible at runtime.
691 * @return a visitor to visit the annotation values, or <tt>null</tt> if
692 * this visitor is not interested in visiting this annotation.
693 */
694 public AnnotationVisitor visitInsnAnnotation(int typeRef,
695 TypePath typePath, String desc, boolean visible) {
696 if (api < Opcodes.ASM5) {
697 throw new RuntimeException();
698 }
699 if (mv != null) {
700 return mv.visitInsnAnnotation(typeRef, typePath, desc, visible);
701 }
702 return null;
703 }
704
705 // -------------------------------------------------------------------------
706 // Exceptions table entries, debug information, max stack and max locals
707 // -------------------------------------------------------------------------
708
709 /**
710 * Visits a try catch block.
711 *
712 * @param start
713 * beginning of the exception handler's scope (inclusive).
714 * @param end
715 * end of the exception handler's scope (exclusive).
716 * @param handler
717 * beginning of the exception handler's code.
718 * @param type
719 * internal name of the type of exceptions handled by the
720 * handler, or <tt>null</tt> to catch any exceptions (for
721 * "finally" blocks).
722 * @throws IllegalArgumentException
723 * if one of the labels has already been visited by this visitor
724 * (by the {@link #visitLabel visitLabel} method).
725 */
726 public void visitTryCatchBlock(Label start, Label end, Label handler,
727 String type) {
728 if (mv != null) {
729 mv.visitTryCatchBlock(start, end, handler, type);
730 }
731 }
732
733 /**
734 * Visits an annotation on an exception handler type. This method must be
735 * called <i>after</i> the {@link #visitTryCatchBlock} for the annotated
736 * exception handler. It can be called several times for the same exception
737 * handler.
738 *
739 * @param typeRef
740 * a reference to the annotated type. The sort of this type
741 * reference must be {@link TypeReference#EXCEPTION_PARAMETER
742 * EXCEPTION_PARAMETER}. See {@link TypeReference}.
743 * @param typePath
744 * the path to the annotated type argument, wildcard bound, array
745 * element type, or static inner type within 'typeRef'. May be
746 * <tt>null</tt> if the annotation targets 'typeRef' as a whole.
747 * @param desc
748 * the class descriptor of the annotation class.
749 * @param visible
750 * <tt>true</tt> if the annotation is visible at runtime.
751 * @return a visitor to visit the annotation values, or <tt>null</tt> if
752 * this visitor is not interested in visiting this annotation.
753 */
754 public AnnotationVisitor visitTryCatchAnnotation(int typeRef,
755 TypePath typePath, String desc, boolean visible) {
756 if (api < Opcodes.ASM5) {
757 throw new RuntimeException();
758 }
759 if (mv != null) {
760 return mv.visitTryCatchAnnotation(typeRef, typePath, desc, visible);
761 }
762 return null;
763 }
764
765 /**
766 * Visits a local variable declaration.
767 *
768 * @param name
769 * the name of a local variable.
770 * @param desc
771 * the type descriptor of this local variable.
772 * @param signature
773 * the type signature of this local variable. May be
774 * <tt>null</tt> if the local variable type does not use generic
775 * types.
776 * @param start
777 * the first instruction corresponding to the scope of this local
778 * variable (inclusive).
779 * @param end
780 * the last instruction corresponding to the scope of this local
781 * variable (exclusive).
782 * @param index
783 * the local variable's index.
784 * @throws IllegalArgumentException
785 * if one of the labels has not already been visited by this
786 * visitor (by the {@link #visitLabel visitLabel} method).
787 */
788 public void visitLocalVariable(String name, String desc, String signature,
789 Label start, Label end, int index) {
790 if (mv != null) {
791 mv.visitLocalVariable(name, desc, signature, start, end, index);
792 }
793 }
794
795 /**
796 * Visits an annotation on a local variable type.
797 *
798 * @param typeRef
799 * a reference to the annotated type. The sort of this type
800 * reference must be {@link TypeReference#LOCAL_VARIABLE
801 * LOCAL_VARIABLE} or {@link TypeReference#RESOURCE_VARIABLE
802 * RESOURCE_VARIABLE}. See {@link TypeReference}.
803 * @param typePath
804 * the path to the annotated type argument, wildcard bound, array
805 * element type, or static inner type within 'typeRef'. May be
806 * <tt>null</tt> if the annotation targets 'typeRef' as a whole.
807 * @param start
808 * the fist instructions corresponding to the continuous ranges
809 * that make the scope of this local variable (inclusive).
810 * @param end
811 * the last instructions corresponding to the continuous ranges
812 * that make the scope of this local variable (exclusive). This
813 * array must have the same size as the 'start' array.
814 * @param index
815 * the local variable's index in each range. This array must have
816 * the same size as the 'start' array.
817 * @param desc
818 * the class descriptor of the annotation class.
819 * @param visible
820 * <tt>true</tt> if the annotation is visible at runtime.
821 * @return a visitor to visit the annotation values, or <tt>null</tt> if
822 * this visitor is not interested in visiting this annotation.
823 */
824 public AnnotationVisitor visitLocalVariableAnnotation(int typeRef,
825 TypePath typePath, Label[] start, Label[] end, int[] index,
826 String desc, boolean visible) {
827 if (api < Opcodes.ASM5) {
828 throw new RuntimeException();
829 }
830 if (mv != null) {
831 return mv.visitLocalVariableAnnotation(typeRef, typePath, start,
832 end, index, desc, visible);
833 }
834 return null;
835 }
836
837 /**
838 * Visits a line number declaration.
839 *
840 * @param line
841 * a line number. This number refers to the source file from
842 * which the class was compiled.
843 * @param start
844 * the first instruction corresponding to this line number.
845 * @throws IllegalArgumentException
846 * if <tt>start</tt> has not already been visited by this
847 * visitor (by the {@link #visitLabel visitLabel} method).
848 */
849 public void visitLineNumber(int line, Label start) {
850 if (mv != null) {
851 mv.visitLineNumber(line, start);
852 }
853 }
854
855 /**
856 * Visits the maximum stack size and the maximum number of local variables
857 * of the method.
858 *
859 * @param maxStack
860 * maximum stack size of the method.
861 * @param maxLocals
862 * maximum number of local variables for the method.
863 */
864 public void visitMaxs(int maxStack, int maxLocals) {
865 if (mv != null) {
866 mv.visitMaxs(maxStack, maxLocals);
867 }
868 }
869
870 /**
871 * Visits the end of the method. This method, which is the last one to be
872 * called, is used to inform the visitor that all the annotations and
873 * attributes of the method have been visited.
874 */
875 public void visitEnd() {
876 if (mv != null) {
877 mv.visitEnd();
878 }
879 }
50 private static final String REQUIRES_ASM5 = "This feature requires ASM5";
51
52 /**
53 * The ASM API version implemented by this visitor. The value of this field must be one of {@link
54 * Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7_EXPERIMENTAL}.
55 */
56 protected final int api;
57
58 /** The method visitor to which this visitor must delegate method calls. May be null. */
59 protected MethodVisitor mv;
60
61 /**
62 * Constructs a new {@link MethodVisitor}.
63 *
64 * @param api the ASM API version implemented by this visitor. Must be one of {@link
65 * Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link
66 * Opcodes#ASM7_EXPERIMENTAL}.
67 */
68 public MethodVisitor(final int api) {
69 this(api, null);
70 }
71
72 /**
73 * Constructs a new {@link MethodVisitor}.
74 *
75 * @param api the ASM API version implemented by this visitor. Must be one of {@link
76 * Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link
77 * Opcodes#ASM7_EXPERIMENTAL}.
78 * @param methodVisitor the method visitor to which this visitor must delegate method calls. May
79 * be null.
80 */
81 public MethodVisitor(final int api, final MethodVisitor methodVisitor) {
82 if (api != Opcodes.ASM6
83 && api != Opcodes.ASM5
84 && api != Opcodes.ASM4
85 && api != Opcodes.ASM7_EXPERIMENTAL) {
86 throw new IllegalArgumentException();
87 }
88 this.api = api;
89 this.mv = methodVisitor;
90 }
91
92 // -----------------------------------------------------------------------------------------------
93 // Parameters, annotations and non standard attributes
94 // -----------------------------------------------------------------------------------------------
95
96 /**
97 * Visits a parameter of this method.
98 *
99 * @param name parameter name or null if none is provided.
100 * @param access the parameter's access flags, only <tt>ACC_FINAL</tt>, <tt>ACC_SYNTHETIC</tt>
101 * or/and <tt>ACC_MANDATED</tt> are allowed (see {@link Opcodes}).
102 */
103 public void visitParameter(final String name, final int access) {
104 if (api < Opcodes.ASM5) {
105 throw new UnsupportedOperationException(REQUIRES_ASM5);
106 }
107 if (mv != null) {
108 mv.visitParameter(name, access);
109 }
110 }
111
112 /**
113 * Visits the default value of this annotation interface method.
114 *
115 * @return a visitor to the visit the actual default value of this annotation interface method, or
116 * <tt>null</tt> if this visitor is not interested in visiting this default value. The 'name'
117 * parameters passed to the methods of this annotation visitor are ignored. Moreover, exacly
118 * one visit method must be called on this annotation visitor, followed by visitEnd.
119 */
120 public AnnotationVisitor visitAnnotationDefault() {
121 if (mv != null) {
122 return mv.visitAnnotationDefault();
123 }
124 return null;
125 }
126
127 /**
128 * Visits an annotation of this method.
129 *
130 * @param descriptor the class descriptor of the annotation class.
131 * @param visible <tt>true</tt> if the annotation is visible at runtime.
132 * @return a visitor to visit the annotation values, or <tt>null</tt> if this visitor is not
133 * interested in visiting this annotation.
134 */
135 public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
136 if (mv != null) {
137 return mv.visitAnnotation(descriptor, visible);
138 }
139 return null;
140 }
141
142 /**
143 * Visits an annotation on a type in the method signature.
144 *
145 * @param typeRef a reference to the annotated type. The sort of this type reference must be
146 * {@link TypeReference#METHOD_TYPE_PARAMETER}, {@link
147 * TypeReference#METHOD_TYPE_PARAMETER_BOUND}, {@link TypeReference#METHOD_RETURN}, {@link
148 * TypeReference#METHOD_RECEIVER}, {@link TypeReference#METHOD_FORMAL_PARAMETER} or {@link
149 * TypeReference#THROWS}. See {@link TypeReference}.
150 * @param typePath the path to the annotated type argument, wildcard bound, array element type, or
151 * static inner type within 'typeRef'. May be <tt>null</tt> if the annotation targets
152 * 'typeRef' as a whole.
153 * @param descriptor the class descriptor of the annotation class.
154 * @param visible <tt>true</tt> if the annotation is visible at runtime.
155 * @return a visitor to visit the annotation values, or <tt>null</tt> if this visitor is not
156 * interested in visiting this annotation.
157 */
158 public AnnotationVisitor visitTypeAnnotation(
159 final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
160 if (api < Opcodes.ASM5) {
161 throw new UnsupportedOperationException(REQUIRES_ASM5);
162 }
163 if (mv != null) {
164 return mv.visitTypeAnnotation(typeRef, typePath, descriptor, visible);
165 }
166 return null;
167 }
168
169 /**
170 * Visits the number of method parameters that can have annotations. By default (i.e. when this
171 * method is not called), all the method parameters defined by the method descriptor can have
172 * annotations.
173 *
174 * @param parameterCount the number of method parameters than can have annotations. This number
175 * must be less or equal than the number of parameter types in the method descriptor. It can
176 * be strictly less when a method has synthetic parameters and when these parameters are
177 * ignored when computing parameter indices for the purpose of parameter annotations (see
178 * https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.18).
179 * @param visible <tt>true</tt> to define the number of method parameters that can have
180 * annotations visible at runtime, <tt>false</tt> to define the number of method parameters
181 * that can have annotations invisible at runtime.
182 */
183 public void visitAnnotableParameterCount(final int parameterCount, final boolean visible) {
184 if (mv != null) {
185 mv.visitAnnotableParameterCount(parameterCount, visible);
186 }
187 }
188
189 /**
190 * Visits an annotation of a parameter this method.
191 *
192 * @param parameter the parameter index. This index must be strictly smaller than the number of
193 * parameters in the method descriptor, and strictly smaller than the parameter count
194 * specified in {@link #visitAnnotableParameterCount}. Important note: <i>a parameter index i
195 * is not required to correspond to the i'th parameter descriptor in the method
196 * descriptor</i>, in particular in case of synthetic parameters (see
197 * https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.18).
198 * @param descriptor the class descriptor of the annotation class.
199 * @param visible <tt>true</tt> if the annotation is visible at runtime.
200 * @return a visitor to visit the annotation values, or <tt>null</tt> if this visitor is not
201 * interested in visiting this annotation.
202 */
203 public AnnotationVisitor visitParameterAnnotation(
204 final int parameter, final String descriptor, final boolean visible) {
205 if (mv != null) {
206 return mv.visitParameterAnnotation(parameter, descriptor, visible);
207 }
208 return null;
209 }
210
211 /**
212 * Visits a non standard attribute of this method.
213 *
214 * @param attribute an attribute.
215 */
216 public void visitAttribute(final Attribute attribute) {
217 if (mv != null) {
218 mv.visitAttribute(attribute);
219 }
220 }
221
222 /** Starts the visit of the method's code, if any (i.e. non abstract method). */
223 public void visitCode() {
224 if (mv != null) {
225 mv.visitCode();
226 }
227 }
228
229 /**
230 * Visits the current state of the local variables and operand stack elements. This method must(*)
231 * be called <i>just before</i> any instruction <b>i</b> that follows an unconditional branch
232 * instruction such as GOTO or THROW, that is the target of a jump instruction, or that starts an
233 * exception handler block. The visited types must describe the values of the local variables and
234 * of the operand stack elements <i>just before</i> <b>i</b> is executed.<br>
235 * <br>
236 * (*) this is mandatory only for classes whose version is greater than or equal to {@link
237 * Opcodes#V1_6}. <br>
238 * <br>
239 * The frames of a method must be given either in expanded form, or in compressed form (all frames
240 * must use the same format, i.e. you must not mix expanded and compressed frames within a single
241 * method):
242 *
243 * <ul>
244 * <li>In expanded form, all frames must have the F_NEW type.
245 * <li>In compressed form, frames are basically "deltas" from the state of the previous frame:
246 * <ul>
247 * <li>{@link Opcodes#F_SAME} representing frame with exactly the same locals as the
248 * previous frame and with the empty stack.
249 * <li>{@link Opcodes#F_SAME1} representing frame with exactly the same locals as the
250 * previous frame and with single value on the stack ( <code>nStack</code> is 1 and
251 * <code>stack[0]</code> contains value for the type of the stack item).
252 * <li>{@link Opcodes#F_APPEND} representing frame with current locals are the same as the
253 * locals in the previous frame, except that additional locals are defined (<code>
254 * nLocal</code> is 1, 2 or 3 and <code>local</code> elements contains values
255 * representing added types).
256 * <li>{@link Opcodes#F_CHOP} representing frame with current locals are the same as the
257 * locals in the previous frame, except that the last 1-3 locals are absent and with
258 * the empty stack (<code>nLocals</code> is 1, 2 or 3).
259 * <li>{@link Opcodes#F_FULL} representing complete frame data.
260 * </ul>
261 * </ul>
262 *
263 * <br>
264 * In both cases the first frame, corresponding to the method's parameters and access flags, is
265 * implicit and must not be visited. Also, it is illegal to visit two or more frames for the same
266 * code location (i.e., at least one instruction must be visited between two calls to visitFrame).
267 *
268 * @param type the type of this stack map frame. Must be {@link Opcodes#F_NEW} for expanded
269 * frames, or {@link Opcodes#F_FULL}, {@link Opcodes#F_APPEND}, {@link Opcodes#F_CHOP}, {@link
270 * Opcodes#F_SAME} or {@link Opcodes#F_APPEND}, {@link Opcodes#F_SAME1} for compressed frames.
271 * @param nLocal the number of local variables in the visited frame.
272 * @param local the local variable types in this frame. This array must not be modified. Primitive
273 * types are represented by {@link Opcodes#TOP}, {@link Opcodes#INTEGER}, {@link
274 * Opcodes#FLOAT}, {@link Opcodes#LONG}, {@link Opcodes#DOUBLE}, {@link Opcodes#NULL} or
275 * {@link Opcodes#UNINITIALIZED_THIS} (long and double are represented by a single element).
276 * Reference types are represented by String objects (representing internal names), and
277 * uninitialized types by Label objects (this label designates the NEW instruction that
278 * created this uninitialized value).
279 * @param nStack the number of operand stack elements in the visited frame.
280 * @param stack the operand stack types in this frame. This array must not be modified. Its
281 * content has the same format as the "local" array.
282 * @throws IllegalStateException if a frame is visited just after another one, without any
283 * instruction between the two (unless this frame is a Opcodes#F_SAME frame, in which case it
284 * is silently ignored).
285 */
286 public void visitFrame(
287 final int type,
288 final int nLocal,
289 final Object[] local,
290 final int nStack,
291 final Object[] stack) {
292 if (mv != null) {
293 mv.visitFrame(type, nLocal, local, nStack, stack);
294 }
295 }
296
297 // -----------------------------------------------------------------------------------------------
298 // Normal instructions
299 // -----------------------------------------------------------------------------------------------
300
301 /**
302 * Visits a zero operand instruction.
303 *
304 * @param opcode the opcode of the instruction to be visited. This opcode is either NOP,
305 * ACONST_NULL, ICONST_M1, ICONST_0, ICONST_1, ICONST_2, ICONST_3, ICONST_4, ICONST_5,
306 * LCONST_0, LCONST_1, FCONST_0, FCONST_1, FCONST_2, DCONST_0, DCONST_1, IALOAD, LALOAD,
307 * FALOAD, DALOAD, AALOAD, BALOAD, CALOAD, SALOAD, IASTORE, LASTORE, FASTORE, DASTORE,
308 * AASTORE, BASTORE, CASTORE, SASTORE, POP, POP2, DUP, DUP_X1, DUP_X2, DUP2, DUP2_X1, DUP2_X2,
309 * SWAP, IADD, LADD, FADD, DADD, ISUB, LSUB, FSUB, DSUB, IMUL, LMUL, FMUL, DMUL, IDIV, LDIV,
310 * FDIV, DDIV, IREM, LREM, FREM, DREM, INEG, LNEG, FNEG, DNEG, ISHL, LSHL, ISHR, LSHR, IUSHR,
311 * LUSHR, IAND, LAND, IOR, LOR, IXOR, LXOR, I2L, I2F, I2D, L2I, L2F, L2D, F2I, F2L, F2D, D2I,
312 * D2L, D2F, I2B, I2C, I2S, LCMP, FCMPL, FCMPG, DCMPL, DCMPG, IRETURN, LRETURN, FRETURN,
313 * DRETURN, ARETURN, RETURN, ARRAYLENGTH, ATHROW, MONITORENTER, or MONITOREXIT.
314 */
315 public void visitInsn(final int opcode) {
316 if (mv != null) {
317 mv.visitInsn(opcode);
318 }
319 }
320
321 /**
322 * Visits an instruction with a single int operand.
323 *
324 * @param opcode the opcode of the instruction to be visited. This opcode is either BIPUSH, SIPUSH
325 * or NEWARRAY.
326 * @param operand the operand of the instruction to be visited.<br>
327 * When opcode is BIPUSH, operand value should be between Byte.MIN_VALUE and Byte.MAX_VALUE.
328 * <br>
329 * When opcode is SIPUSH, operand value should be between Short.MIN_VALUE and Short.MAX_VALUE.
330 * <br>
331 * When opcode is NEWARRAY, operand value should be one of {@link Opcodes#T_BOOLEAN}, {@link
332 * Opcodes#T_CHAR}, {@link Opcodes#T_FLOAT}, {@link Opcodes#T_DOUBLE}, {@link Opcodes#T_BYTE},
333 * {@link Opcodes#T_SHORT}, {@link Opcodes#T_INT} or {@link Opcodes#T_LONG}.
334 */
335 public void visitIntInsn(final int opcode, final int operand) {
336 if (mv != null) {
337 mv.visitIntInsn(opcode, operand);
338 }
339 }
340
341 /**
342 * Visits a local variable instruction. A local variable instruction is an instruction that loads
343 * or stores the value of a local variable.
344 *
345 * @param opcode the opcode of the local variable instruction to be visited. This opcode is either
346 * ILOAD, LLOAD, FLOAD, DLOAD, ALOAD, ISTORE, LSTORE, FSTORE, DSTORE, ASTORE or RET.
347 * @param var the operand of the instruction to be visited. This operand is the index of a local
348 * variable.
349 */
350 public void visitVarInsn(final int opcode, final int var) {
351 if (mv != null) {
352 mv.visitVarInsn(opcode, var);
353 }
354 }
355
356 /**
357 * Visits a type instruction. A type instruction is an instruction that takes the internal name of
358 * a class as parameter.
359 *
360 * @param opcode the opcode of the type instruction to be visited. This opcode is either NEW,
361 * ANEWARRAY, CHECKCAST or INSTANCEOF.
362 * @param type the operand of the instruction to be visited. This operand must be the internal
363 * name of an object or array class (see {@link Type#getInternalName()}).
364 */
365 public void visitTypeInsn(final int opcode, final String type) {
366 if (mv != null) {
367 mv.visitTypeInsn(opcode, type);
368 }
369 }
370
371 /**
372 * Visits a field instruction. A field instruction is an instruction that loads or stores the
373 * value of a field of an object.
374 *
375 * @param opcode the opcode of the type instruction to be visited. This opcode is either
376 * GETSTATIC, PUTSTATIC, GETFIELD or PUTFIELD.
377 * @param owner the internal name of the field's owner class (see {@link Type#getInternalName()}).
378 * @param name the field's name.
379 * @param descriptor the field's descriptor (see {@link Type}).
380 */
381 public void visitFieldInsn(
382 final int opcode, final String owner, final String name, final String descriptor) {
383 if (mv != null) {
384 mv.visitFieldInsn(opcode, owner, name, descriptor);
385 }
386 }
387
388 /**
389 * Visits a method instruction. A method instruction is an instruction that invokes a method.
390 *
391 * @param opcode the opcode of the type instruction to be visited. This opcode is either
392 * INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or INVOKEINTERFACE.
393 * @param owner the internal name of the method's owner class (see {@link
394 * Type#getInternalName()}).
395 * @param name the method's name.
396 * @param descriptor the method's descriptor (see {@link Type}).
397 * @deprecated
398 */
399 @Deprecated
400 public void visitMethodInsn(
401 final int opcode, final String owner, final String name, final String descriptor) {
402 if (api >= Opcodes.ASM5) {
403 boolean isInterface = opcode == Opcodes.INVOKEINTERFACE;
404 visitMethodInsn(opcode, owner, name, descriptor, isInterface);
405 return;
406 }
407 if (mv != null) {
408 mv.visitMethodInsn(opcode, owner, name, descriptor);
409 }
410 }
411
412 /**
413 * Visits a method instruction. A method instruction is an instruction that invokes a method.
414 *
415 * @param opcode the opcode of the type instruction to be visited. This opcode is either
416 * INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or INVOKEINTERFACE.
417 * @param owner the internal name of the method's owner class (see {@link
418 * Type#getInternalName()}).
419 * @param name the method's name.
420 * @param descriptor the method's descriptor (see {@link Type}).
421 * @param isInterface if the method's owner class is an interface.
422 */
423 public void visitMethodInsn(
424 final int opcode,
425 final String owner,
426 final String name,
427 final String descriptor,
428 final boolean isInterface) {
429 if (api < Opcodes.ASM5) {
430 if (isInterface != (opcode == Opcodes.INVOKEINTERFACE)) {
431 throw new IllegalArgumentException("INVOKESPECIAL/STATIC on interfaces requires ASM5");
432 }
433 visitMethodInsn(opcode, owner, name, descriptor);
434 return;
435 }
436 if (mv != null) {
437 mv.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
438 }
439 }
440
441 /**
442 * Visits an invokedynamic instruction.
443 *
444 * @param name the method's name.
445 * @param descriptor the method's descriptor (see {@link Type}).
446 * @param bootstrapMethodHandle the bootstrap method.
447 * @param bootstrapMethodArguments the bootstrap method constant arguments. Each argument must be
448 * an {@link Integer}, {@link Float}, {@link Long}, {@link Double}, {@link String}, {@link
449 * Type}, {@link Handle} or {@link ConstantDynamic} value. This method is allowed to modify
450 * the content of the array so a caller should expect that this array may change.
451 */
452 public void visitInvokeDynamicInsn(
453 final String name,
454 final String descriptor,
455 final Handle bootstrapMethodHandle,
456 final Object... bootstrapMethodArguments) {
457 if (api < Opcodes.ASM5) {
458 throw new UnsupportedOperationException(REQUIRES_ASM5);
459 }
460 if (mv != null) {
461 mv.visitInvokeDynamicInsn(name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments);
462 }
463 }
464
465 /**
466 * Visits a jump instruction. A jump instruction is an instruction that may jump to another
467 * instruction.
468 *
469 * @param opcode the opcode of the type instruction to be visited. This opcode is either IFEQ,
470 * IFNE, IFLT, IFGE, IFGT, IFLE, IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT,
471 * IF_ICMPLE, IF_ACMPEQ, IF_ACMPNE, GOTO, JSR, IFNULL or IFNONNULL.
472 * @param label the operand of the instruction to be visited. This operand is a label that
473 * designates the instruction to which the jump instruction may jump.
474 */
475 public void visitJumpInsn(final int opcode, final Label label) {
476 if (mv != null) {
477 mv.visitJumpInsn(opcode, label);
478 }
479 }
480
481 /**
482 * Visits a label. A label designates the instruction that will be visited just after it.
483 *
484 * @param label a {@link Label} object.
485 */
486 public void visitLabel(final Label label) {
487 if (mv != null) {
488 mv.visitLabel(label);
489 }
490 }
491
492 // -----------------------------------------------------------------------------------------------
493 // Special instructions
494 // -----------------------------------------------------------------------------------------------
495
496 /**
497 * Visits a LDC instruction. Note that new constant types may be added in future versions of the
498 * Java Virtual Machine. To easily detect new constant types, implementations of this method
499 * should check for unexpected constant types, like this:
500 *
501 * <pre>
502 * if (cst instanceof Integer) {
503 * // ...
504 * } else if (cst instanceof Float) {
505 * // ...
506 * } else if (cst instanceof Long) {
507 * // ...
508 * } else if (cst instanceof Double) {
509 * // ...
510 * } else if (cst instanceof String) {
511 * // ...
512 * } else if (cst instanceof Type) {
513 * int sort = ((Type) cst).getSort();
514 * if (sort == Type.OBJECT) {
515 * // ...
516 * } else if (sort == Type.ARRAY) {
517 * // ...
518 * } else if (sort == Type.METHOD) {
519 * // ...
520 * } else {
521 * // throw an exception
522 * }
523 * } else if (cst instanceof Handle) {
524 * // ...
525 * } else if (cst instanceof Condy) {
526 * // ...
527 * } else {
528 * // throw an exception
529 * }
530 * </pre>
531 *
532 * @param value the constant to be loaded on the stack. This parameter must be a non null {@link
533 * Integer}, a {@link Float}, a {@link Long}, a {@link Double}, a {@link String}, a {@link
534 * Type} of OBJECT or ARRAY sort for <tt>.class</tt> constants, for classes whose version is
535 * 49, a {@link Type} of METHOD sort for MethodType, a {@link Handle} for MethodHandle
536 * constants, for classes whose version is 51 or a {@link ConstantDynamic} for a constant
537 * dynamic for classes whose version is 55.
538 */
539 public void visitLdcInsn(final Object value) {
540 if (api < Opcodes.ASM5
541 && (value instanceof Handle
542 || (value instanceof Type && ((Type) value).getSort() == Type.METHOD))) {
543 throw new UnsupportedOperationException(REQUIRES_ASM5);
544 }
545 if (api != Opcodes.ASM7_EXPERIMENTAL && value instanceof ConstantDynamic) {
546 throw new UnsupportedOperationException("This feature requires ASM7");
547 }
548 if (mv != null) {
549 mv.visitLdcInsn(value);
550 }
551 }
552
553 /**
554 * Visits an IINC instruction.
555 *
556 * @param var index of the local variable to be incremented.
557 * @param increment amount to increment the local variable by.
558 */
559 public void visitIincInsn(final int var, final int increment) {
560 if (mv != null) {
561 mv.visitIincInsn(var, increment);
562 }
563 }
564
565 /**
566 * Visits a TABLESWITCH instruction.
567 *
568 * @param min the minimum key value.
569 * @param max the maximum key value.
570 * @param dflt beginning of the default handler block.
571 * @param labels beginnings of the handler blocks. <tt>labels[i]</tt> is the beginning of the
572 * handler block for the <tt>min + i</tt> key.
573 */
574 public void visitTableSwitchInsn(
575 final int min, final int max, final Label dflt, final Label... labels) {
576 if (mv != null) {
577 mv.visitTableSwitchInsn(min, max, dflt, labels);
578 }
579 }
580
581 /**
582 * Visits a LOOKUPSWITCH instruction.
583 *
584 * @param dflt beginning of the default handler block.
585 * @param keys the values of the keys.
586 * @param labels beginnings of the handler blocks. <tt>labels[i]</tt> is the beginning of the
587 * handler block for the <tt>keys[i]</tt> key.
588 */
589 public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) {
590 if (mv != null) {
591 mv.visitLookupSwitchInsn(dflt, keys, labels);
592 }
593 }
594
595 /**
596 * Visits a MULTIANEWARRAY instruction.
597 *
598 * @param descriptor an array type descriptor (see {@link Type}).
599 * @param numDimensions the number of dimensions of the array to allocate.
600 */
601 public void visitMultiANewArrayInsn(final String descriptor, final int numDimensions) {
602 if (mv != null) {
603 mv.visitMultiANewArrayInsn(descriptor, numDimensions);
604 }
605 }
606
607 /**
608 * Visits an annotation on an instruction. This method must be called just <i>after</i> the
609 * annotated instruction. It can be called several times for the same instruction.
610 *
611 * @param typeRef a reference to the annotated type. The sort of this type reference must be
612 * {@link TypeReference#INSTANCEOF}, {@link TypeReference#NEW}, {@link
613 * TypeReference#CONSTRUCTOR_REFERENCE}, {@link TypeReference#METHOD_REFERENCE}, {@link
614 * TypeReference#CAST}, {@link TypeReference#CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, {@link
615 * TypeReference#METHOD_INVOCATION_TYPE_ARGUMENT}, {@link
616 * TypeReference#CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or {@link
617 * TypeReference#METHOD_REFERENCE_TYPE_ARGUMENT}. See {@link TypeReference}.
618 * @param typePath the path to the annotated type argument, wildcard bound, array element type, or
619 * static inner type within 'typeRef'. May be <tt>null</tt> if the annotation targets
620 * 'typeRef' as a whole.
621 * @param descriptor the class descriptor of the annotation class.
622 * @param visible <tt>true</tt> if the annotation is visible at runtime.
623 * @return a visitor to visit the annotation values, or <tt>null</tt> if this visitor is not
624 * interested in visiting this annotation.
625 */
626 public AnnotationVisitor visitInsnAnnotation(
627 final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
628 if (api < Opcodes.ASM5) {
629 throw new UnsupportedOperationException(REQUIRES_ASM5);
630 }
631 if (mv != null) {
632 return mv.visitInsnAnnotation(typeRef, typePath, descriptor, visible);
633 }
634 return null;
635 }
636
637 // -----------------------------------------------------------------------------------------------
638 // Exceptions table entries, debug information, max stack and max locals
639 // -----------------------------------------------------------------------------------------------
640
641 /**
642 * Visits a try catch block.
643 *
644 * @param start the beginning of the exception handler's scope (inclusive).
645 * @param end the end of the exception handler's scope (exclusive).
646 * @param handler the beginning of the exception handler's code.
647 * @param type the internal name of the type of exceptions handled by the handler, or
648 * <tt>null</tt> to catch any exceptions (for "finally" blocks).
649 * @throws IllegalArgumentException if one of the labels has already been visited by this visitor
650 * (by the {@link #visitLabel} method).
651 */
652 public void visitTryCatchBlock(
653 final Label start, final Label end, final Label handler, final String type) {
654 if (mv != null) {
655 mv.visitTryCatchBlock(start, end, handler, type);
656 }
657 }
658
659 /**
660 * Visits an annotation on an exception handler type. This method must be called <i>after</i> the
661 * {@link #visitTryCatchBlock} for the annotated exception handler. It can be called several times
662 * for the same exception handler.
663 *
664 * @param typeRef a reference to the annotated type. The sort of this type reference must be
665 * {@link TypeReference#EXCEPTION_PARAMETER}. See {@link TypeReference}.
666 * @param typePath the path to the annotated type argument, wildcard bound, array element type, or
667 * static inner type within 'typeRef'. May be <tt>null</tt> if the annotation targets
668 * 'typeRef' as a whole.
669 * @param descriptor the class descriptor of the annotation class.
670 * @param visible <tt>true</tt> if the annotation is visible at runtime.
671 * @return a visitor to visit the annotation values, or <tt>null</tt> if this visitor is not
672 * interested in visiting this annotation.
673 */
674 public AnnotationVisitor visitTryCatchAnnotation(
675 final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
676 if (api < Opcodes.ASM5) {
677 throw new UnsupportedOperationException(REQUIRES_ASM5);
678 }
679 if (mv != null) {
680 return mv.visitTryCatchAnnotation(typeRef, typePath, descriptor, visible);
681 }
682 return null;
683 }
684
685 /**
686 * Visits a local variable declaration.
687 *
688 * @param name the name of a local variable.
689 * @param descriptor the type descriptor of this local variable.
690 * @param signature the type signature of this local variable. May be <tt>null</tt> if the local
691 * variable type does not use generic types.
692 * @param start the first instruction corresponding to the scope of this local variable
693 * (inclusive).
694 * @param end the last instruction corresponding to the scope of this local variable (exclusive).
695 * @param index the local variable's index.
696 * @throws IllegalArgumentException if one of the labels has not already been visited by this
697 * visitor (by the {@link #visitLabel} method).
698 */
699 public void visitLocalVariable(
700 final String name,
701 final String descriptor,
702 final String signature,
703 final Label start,
704 final Label end,
705 final int index) {
706 if (mv != null) {
707 mv.visitLocalVariable(name, descriptor, signature, start, end, index);
708 }
709 }
710
711 /**
712 * Visits an annotation on a local variable type.
713 *
714 * @param typeRef a reference to the annotated type. The sort of this type reference must be
715 * {@link TypeReference#LOCAL_VARIABLE} or {@link TypeReference#RESOURCE_VARIABLE}. See {@link
716 * TypeReference}.
717 * @param typePath the path to the annotated type argument, wildcard bound, array element type, or
718 * static inner type within 'typeRef'. May be <tt>null</tt> if the annotation targets
719 * 'typeRef' as a whole.
720 * @param start the fist instructions corresponding to the continuous ranges that make the scope
721 * of this local variable (inclusive).
722 * @param end the last instructions corresponding to the continuous ranges that make the scope of
723 * this local variable (exclusive). This array must have the same size as the 'start' array.
724 * @param index the local variable's index in each range. This array must have the same size as
725 * the 'start' array.
726 * @param descriptor the class descriptor of the annotation class.
727 * @param visible <tt>true</tt> if the annotation is visible at runtime.
728 * @return a visitor to visit the annotation values, or <tt>null</tt> if this visitor is not
729 * interested in visiting this annotation.
730 */
731 public AnnotationVisitor visitLocalVariableAnnotation(
732 final int typeRef,
733 final TypePath typePath,
734 final Label[] start,
735 final Label[] end,
736 final int[] index,
737 final String descriptor,
738 final boolean visible) {
739 if (api < Opcodes.ASM5) {
740 throw new UnsupportedOperationException(REQUIRES_ASM5);
741 }
742 if (mv != null) {
743 return mv.visitLocalVariableAnnotation(
744 typeRef, typePath, start, end, index, descriptor, visible);
745 }
746 return null;
747 }
748
749 /**
750 * Visits a line number declaration.
751 *
752 * @param line a line number. This number refers to the source file from which the class was
753 * compiled.
754 * @param start the first instruction corresponding to this line number.
755 * @throws IllegalArgumentException if <tt>start</tt> has not already been visited by this visitor
756 * (by the {@link #visitLabel} method).
757 */
758 public void visitLineNumber(final int line, final Label start) {
759 if (mv != null) {
760 mv.visitLineNumber(line, start);
761 }
762 }
763
764 /**
765 * Visits the maximum stack size and the maximum number of local variables of the method.
766 *
767 * @param maxStack maximum stack size of the method.
768 * @param maxLocals maximum number of local variables for the method.
769 */
770 public void visitMaxs(final int maxStack, final int maxLocals) {
771 if (mv != null) {
772 mv.visitMaxs(maxStack, maxLocals);
773 }
774 }
775
776 /**
777 * Visits the end of the method. This method, which is the last one to be called, is used to
778 * inform the visitor that all the annotations and attributes of the method have been visited.
779 */
780 public void visitEnd() {
781 if (mv != null) {
782 mv.visitEnd();
783 }
784 }
880785 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
27 package org.eclipse.persistence.internal.libraries.asm;
28
29 /**
30 * A {@link MethodVisitor} that generates a corresponding 'method_info' structure, as defined in the
31 * Java Virtual Machine Specification (JVMS).
432 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 package org.eclipse.persistence.internal.libraries.asm;
30
31 /**
32 * A {@link MethodVisitor} that generates methods in bytecode form. Each visit
33 * method of this class appends the bytecode corresponding to the visited
34 * instruction to a byte vector, in the order these methods are called.
35 *
33 * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.6">JVMS
34 * 4.6</a>
3635 * @author Eric Bruneton
3736 * @author Eugene Kuleshov
3837 */
39 class MethodWriter extends MethodVisitor {
40
41 /**
42 * Pseudo access flag used to denote constructors.
43 */
44 static final int ACC_CONSTRUCTOR = 0x80000;
45
46 /**
47 * Frame has exactly the same locals as the previous stack map frame and
48 * number of stack items is zero.
49 */
50 static final int SAME_FRAME = 0; // to 63 (0-3f)
51
52 /**
53 * Frame has exactly the same locals as the previous stack map frame and
54 * number of stack items is 1
55 */
56 static final int SAME_LOCALS_1_STACK_ITEM_FRAME = 64; // to 127 (40-7f)
57
58 /**
59 * Reserved for future use
60 */
61 static final int RESERVED = 128;
62
63 /**
64 * Frame has exactly the same locals as the previous stack map frame and
65 * number of stack items is 1. Offset is bigger then 63;
66 */
67 static final int SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED = 247; // f7
68
69 /**
70 * Frame where current locals are the same as the locals in the previous
71 * frame, except that the k last locals are absent. The value of k is given
72 * by the formula 251-frame_type.
73 */
74 static final int CHOP_FRAME = 248; // to 250 (f8-fA)
75
76 /**
77 * Frame has exactly the same locals as the previous stack map frame and
78 * number of stack items is zero. Offset is bigger then 63;
79 */
80 static final int SAME_FRAME_EXTENDED = 251; // fb
81
82 /**
83 * Frame where current locals are the same as the locals in the previous
84 * frame, except that k additional locals are defined. The value of k is
85 * given by the formula frame_type-251.
86 */
87 static final int APPEND_FRAME = 252; // to 254 // fc-fe
88
89 /**
90 * Full frame
91 */
92 static final int FULL_FRAME = 255; // ff
93
94 /**
95 * Indicates that the stack map frames must be recomputed from scratch. In
96 * this case the maximum stack size and number of local variables is also
97 * recomputed from scratch.
98 *
99 * @see #compute
100 */
101 private static final int FRAMES = 0;
102
103 /**
104 * Indicates that the maximum stack size and number of local variables must
105 * be automatically computed.
106 *
107 * @see #compute
108 */
109 private static final int MAXS = 1;
110
111 /**
112 * Indicates that nothing must be automatically computed.
113 *
114 * @see #compute
115 */
116 private static final int NOTHING = 2;
117
118 /**
119 * The class writer to which this method must be added.
120 */
121 final ClassWriter cw;
122
123 /**
124 * Access flags of this method.
125 */
126 private int access;
127
128 /**
129 * The index of the constant pool item that contains the name of this
130 * method.
131 */
132 private final int name;
133
134 /**
135 * The index of the constant pool item that contains the descriptor of this
136 * method.
137 */
138 private final int desc;
139
140 /**
141 * The descriptor of this method.
142 */
143 private final String descriptor;
144
145 /**
146 * The signature of this method.
147 */
148 String signature;
149
150 /**
151 * If not zero, indicates that the code of this method must be copied from
152 * the ClassReader associated to this writer in <code>cw.cr</code>. More
153 * precisely, this field gives the index of the first byte to copied from
154 * <code>cw.cr.b</code>.
155 */
156 int classReaderOffset;
157
158 /**
159 * If not zero, indicates that the code of this method must be copied from
160 * the ClassReader associated to this writer in <code>cw.cr</code>. More
161 * precisely, this field gives the number of bytes to copied from
162 * <code>cw.cr.b</code>.
163 */
164 int classReaderLength;
165
166 /**
167 * Number of exceptions that can be thrown by this method.
168 */
169 int exceptionCount;
170
171 /**
172 * The exceptions that can be thrown by this method. More precisely, this
173 * array contains the indexes of the constant pool items that contain the
174 * internal names of these exception classes.
175 */
176 int[] exceptions;
177
178 /**
179 * The annotation default attribute of this method. May be <tt>null</tt>.
180 */
181 private ByteVector annd;
182
183 /**
184 * The runtime visible annotations of this method. May be <tt>null</tt>.
185 */
186 private AnnotationWriter anns;
187
188 /**
189 * The runtime invisible annotations of this method. May be <tt>null</tt>.
190 */
191 private AnnotationWriter ianns;
192
193 /**
194 * The runtime visible type annotations of this method. May be <tt>null</tt>
195 * .
196 */
197 private AnnotationWriter tanns;
198
199 /**
200 * The runtime invisible type annotations of this method. May be
201 * <tt>null</tt>.
202 */
203 private AnnotationWriter itanns;
204
205 /**
206 * The runtime visible parameter annotations of this method. May be
207 * <tt>null</tt>.
208 */
209 private AnnotationWriter[] panns;
210
211 /**
212 * The runtime invisible parameter annotations of this method. May be
213 * <tt>null</tt>.
214 */
215 private AnnotationWriter[] ipanns;
216
217 /**
218 * The number of synthetic parameters of this method.
219 */
220 private int synthetics;
221
222 /**
223 * The non standard attributes of the method.
224 */
225 private Attribute attrs;
226
227 /**
228 * The bytecode of this method.
229 */
230 private ByteVector code = new ByteVector();
231
232 /**
233 * Maximum stack size of this method.
234 */
235 private int maxStack;
236
237 /**
238 * Maximum number of local variables for this method.
239 */
240 private int maxLocals;
241
242 /**
243 * Number of local variables in the current stack map frame.
244 */
245 private int currentLocals;
246
247 /**
248 * Number of stack map frames in the StackMapTable attribute.
249 */
250 private int frameCount;
251
252 /**
253 * The StackMapTable attribute.
254 */
255 private ByteVector stackMap;
256
257 /**
258 * The offset of the last frame that was written in the StackMapTable
259 * attribute.
260 */
261 private int previousFrameOffset;
262
263 /**
264 * The last frame that was written in the StackMapTable attribute.
265 *
266 * @see #frame
267 */
268 private int[] previousFrame;
269
270 /**
271 * The current stack map frame. The first element contains the offset of the
272 * instruction to which the frame corresponds, the second element is the
273 * number of locals and the third one is the number of stack elements. The
274 * local variables start at index 3 and are followed by the operand stack
275 * values. In summary frame[0] = offset, frame[1] = nLocal, frame[2] =
276 * nStack, frame[3] = nLocal. All types are encoded as integers, with the
277 * same format as the one used in {@link Label}, but limited to BASE types.
278 */
279 private int[] frame;
280
281 /**
282 * Number of elements in the exception handler list.
283 */
284 private int handlerCount;
285
286 /**
287 * The first element in the exception handler list.
288 */
289 private Handler firstHandler;
290
291 /**
292 * The last element in the exception handler list.
293 */
294 private Handler lastHandler;
295
296 /**
297 * Number of entries in the MethodParameters attribute.
298 */
299 private int methodParametersCount;
300
301 /**
302 * The MethodParameters attribute.
303 */
304 private ByteVector methodParameters;
305
306 /**
307 * Number of entries in the LocalVariableTable attribute.
308 */
309 private int localVarCount;
310
311 /**
312 * The LocalVariableTable attribute.
313 */
314 private ByteVector localVar;
315
316 /**
317 * Number of entries in the LocalVariableTypeTable attribute.
318 */
319 private int localVarTypeCount;
320
321 /**
322 * The LocalVariableTypeTable attribute.
323 */
324 private ByteVector localVarType;
325
326 /**
327 * Number of entries in the LineNumberTable attribute.
328 */
329 private int lineNumberCount;
330
331 /**
332 * The LineNumberTable attribute.
333 */
334 private ByteVector lineNumber;
335
336 /**
337 * The start offset of the last visited instruction.
338 */
339 private int lastCodeOffset;
340
341 /**
342 * The runtime visible type annotations of the code. May be <tt>null</tt>.
343 */
344 private AnnotationWriter ctanns;
345
346 /**
347 * The runtime invisible type annotations of the code. May be <tt>null</tt>.
348 */
349 private AnnotationWriter ictanns;
350
351 /**
352 * The non standard attributes of the method's code.
353 */
354 private Attribute cattrs;
355
356 /**
357 * Indicates if some jump instructions are too small and need to be resized.
358 */
359 private boolean resize;
360
361 /**
362 * The number of subroutines in this method.
363 */
364 private int subroutines;
365
366 // ------------------------------------------------------------------------
367
368 /*
369 * Fields for the control flow graph analysis algorithm (used to compute the
370 * maximum stack size). A control flow graph contains one node per "basic
371 * block", and one edge per "jump" from one basic block to another. Each
372 * node (i.e., each basic block) is represented by the Label object that
373 * corresponds to the first instruction of this basic block. Each node also
374 * stores the list of its successors in the graph, as a linked list of Edge
375 * objects.
376 */
377
378 /**
379 * Indicates what must be automatically computed.
380 *
381 * @see #FRAMES
382 * @see #MAXS
383 * @see #NOTHING
384 */
385 private final int compute;
386
387 /**
388 * A list of labels. This list is the list of basic blocks in the method,
389 * i.e. a list of Label objects linked to each other by their
390 * {@link Label#successor} field, in the order they are visited by
391 * {@link MethodVisitor#visitLabel}, and starting with the first basic
392 * block.
393 */
394 private Label labels;
395
396 /**
397 * The previous basic block.
398 */
399 private Label previousBlock;
400
401 /**
402 * The current basic block.
403 */
404 private Label currentBlock;
405
406 /**
407 * The (relative) stack size after the last visited instruction. This size
408 * is relative to the beginning of the current basic block, i.e., the true
409 * stack size after the last visited instruction is equal to the
410 * {@link Label#inputStackTop beginStackSize} of the current basic block
411 * plus <tt>stackSize</tt>.
412 */
413 private int stackSize;
414
415 /**
416 * The (relative) maximum stack size after the last visited instruction.
417 * This size is relative to the beginning of the current basic block, i.e.,
418 * the true maximum stack size after the last visited instruction is equal
419 * to the {@link Label#inputStackTop beginStackSize} of the current basic
420 * block plus <tt>stackSize</tt>.
421 */
422 private int maxStackSize;
423
424 // ------------------------------------------------------------------------
425 // Constructor
426 // ------------------------------------------------------------------------
427
428 /**
429 * Constructs a new {@link MethodWriter}.
430 *
431 * @param cw
432 * the class writer in which the method must be added.
433 * @param access
434 * the method's access flags (see {@link Opcodes}).
435 * @param name
436 * the method's name.
437 * @param desc
438 * the method's descriptor (see {@link Type}).
439 * @param signature
440 * the method's signature. May be <tt>null</tt>.
441 * @param exceptions
442 * the internal names of the method's exceptions. May be
443 * <tt>null</tt>.
444 * @param computeMaxs
445 * <tt>true</tt> if the maximum stack size and number of local
446 * variables must be automatically computed.
447 * @param computeFrames
448 * <tt>true</tt> if the stack map tables must be recomputed from
449 * scratch.
450 */
451 MethodWriter(final ClassWriter cw, final int access, final String name,
452 final String desc, final String signature,
453 final String[] exceptions, final boolean computeMaxs,
454 final boolean computeFrames) {
455 super(Opcodes.ASM6);
456 if (cw.firstMethod == null) {
457 cw.firstMethod = this;
38 final class MethodWriter extends MethodVisitor {
39
40 /** Indicates that nothing must be computed. */
41 static final int COMPUTE_NOTHING = 0;
42
43 /**
44 * Indicates that the maximum stack size and the maximum number of local variables must be
45 * computed, from scratch.
46 */
47 static final int COMPUTE_MAX_STACK_AND_LOCAL = 1;
48
49 /**
50 * Indicates that the maximum stack size and the maximum number of local variables must be
51 * computed, from the existing stack map frames. This can be done more efficiently than with the
52 * control flow graph algorithm used for {@link #COMPUTE_MAX_STACK_AND_LOCAL}, by using a linear
53 * scan of the bytecode instructions.
54 */
55 static final int COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES = 2;
56
57 /**
58 * Indicates that the stack map frames of type F_INSERT must be computed. The other frames are not
59 * computed. They should all be of type F_NEW and should be sufficient to compute the content of
60 * the F_INSERT frames, together with the bytecode instructions between a F_NEW and a F_INSERT
61 * frame - and without any knowledge of the type hierarchy (by definition of F_INSERT).
62 */
63 static final int COMPUTE_INSERTED_FRAMES = 3;
64
65 /**
66 * Indicates that all the stack map frames must be computed. In this case the maximum stack size
67 * and the maximum number of local variables is also computed.
68 */
69 static final int COMPUTE_ALL_FRAMES = 4;
70
71 /** Indicates that {@link #STACK_SIZE_DELTA} is not applicable (not constant or never used). */
72 private static final int NA = 0;
73
74 /**
75 * The stack size variation corresponding to each JVM opcode. The stack size variation for opcode
76 * 'o' is given by the array element at index 'o'.
77 *
78 * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-6.html">JVMS 6</a>
79 */
80 private static final int[] STACK_SIZE_DELTA = {
81 0, // nop = 0 (0x0)
82 1, // aconst_null = 1 (0x1)
83 1, // iconst_m1 = 2 (0x2)
84 1, // iconst_0 = 3 (0x3)
85 1, // iconst_1 = 4 (0x4)
86 1, // iconst_2 = 5 (0x5)
87 1, // iconst_3 = 6 (0x6)
88 1, // iconst_4 = 7 (0x7)
89 1, // iconst_5 = 8 (0x8)
90 2, // lconst_0 = 9 (0x9)
91 2, // lconst_1 = 10 (0xa)
92 1, // fconst_0 = 11 (0xb)
93 1, // fconst_1 = 12 (0xc)
94 1, // fconst_2 = 13 (0xd)
95 2, // dconst_0 = 14 (0xe)
96 2, // dconst_1 = 15 (0xf)
97 1, // bipush = 16 (0x10)
98 1, // sipush = 17 (0x11)
99 1, // ldc = 18 (0x12)
100 NA, // ldc_w = 19 (0x13)
101 NA, // ldc2_w = 20 (0x14)
102 1, // iload = 21 (0x15)
103 2, // lload = 22 (0x16)
104 1, // fload = 23 (0x17)
105 2, // dload = 24 (0x18)
106 1, // aload = 25 (0x19)
107 NA, // iload_0 = 26 (0x1a)
108 NA, // iload_1 = 27 (0x1b)
109 NA, // iload_2 = 28 (0x1c)
110 NA, // iload_3 = 29 (0x1d)
111 NA, // lload_0 = 30 (0x1e)
112 NA, // lload_1 = 31 (0x1f)
113 NA, // lload_2 = 32 (0x20)
114 NA, // lload_3 = 33 (0x21)
115 NA, // fload_0 = 34 (0x22)
116 NA, // fload_1 = 35 (0x23)
117 NA, // fload_2 = 36 (0x24)
118 NA, // fload_3 = 37 (0x25)
119 NA, // dload_0 = 38 (0x26)
120 NA, // dload_1 = 39 (0x27)
121 NA, // dload_2 = 40 (0x28)
122 NA, // dload_3 = 41 (0x29)
123 NA, // aload_0 = 42 (0x2a)
124 NA, // aload_1 = 43 (0x2b)
125 NA, // aload_2 = 44 (0x2c)
126 NA, // aload_3 = 45 (0x2d)
127 -1, // iaload = 46 (0x2e)
128 0, // laload = 47 (0x2f)
129 -1, // faload = 48 (0x30)
130 0, // daload = 49 (0x31)
131 -1, // aaload = 50 (0x32)
132 -1, // baload = 51 (0x33)
133 -1, // caload = 52 (0x34)
134 -1, // saload = 53 (0x35)
135 -1, // istore = 54 (0x36)
136 -2, // lstore = 55 (0x37)
137 -1, // fstore = 56 (0x38)
138 -2, // dstore = 57 (0x39)
139 -1, // astore = 58 (0x3a)
140 NA, // istore_0 = 59 (0x3b)
141 NA, // istore_1 = 60 (0x3c)
142 NA, // istore_2 = 61 (0x3d)
143 NA, // istore_3 = 62 (0x3e)
144 NA, // lstore_0 = 63 (0x3f)
145 NA, // lstore_1 = 64 (0x40)
146 NA, // lstore_2 = 65 (0x41)
147 NA, // lstore_3 = 66 (0x42)
148 NA, // fstore_0 = 67 (0x43)
149 NA, // fstore_1 = 68 (0x44)
150 NA, // fstore_2 = 69 (0x45)
151 NA, // fstore_3 = 70 (0x46)
152 NA, // dstore_0 = 71 (0x47)
153 NA, // dstore_1 = 72 (0x48)
154 NA, // dstore_2 = 73 (0x49)
155 NA, // dstore_3 = 74 (0x4a)
156 NA, // astore_0 = 75 (0x4b)
157 NA, // astore_1 = 76 (0x4c)
158 NA, // astore_2 = 77 (0x4d)
159 NA, // astore_3 = 78 (0x4e)
160 -3, // iastore = 79 (0x4f)
161 -4, // lastore = 80 (0x50)
162 -3, // fastore = 81 (0x51)
163 -4, // dastore = 82 (0x52)
164 -3, // aastore = 83 (0x53)
165 -3, // bastore = 84 (0x54)
166 -3, // castore = 85 (0x55)
167 -3, // sastore = 86 (0x56)
168 -1, // pop = 87 (0x57)
169 -2, // pop2 = 88 (0x58)
170 1, // dup = 89 (0x59)
171 1, // dup_x1 = 90 (0x5a)
172 1, // dup_x2 = 91 (0x5b)
173 2, // dup2 = 92 (0x5c)
174 2, // dup2_x1 = 93 (0x5d)
175 2, // dup2_x2 = 94 (0x5e)
176 0, // swap = 95 (0x5f)
177 -1, // iadd = 96 (0x60)
178 -2, // ladd = 97 (0x61)
179 -1, // fadd = 98 (0x62)
180 -2, // dadd = 99 (0x63)
181 -1, // isub = 100 (0x64)
182 -2, // lsub = 101 (0x65)
183 -1, // fsub = 102 (0x66)
184 -2, // dsub = 103 (0x67)
185 -1, // imul = 104 (0x68)
186 -2, // lmul = 105 (0x69)
187 -1, // fmul = 106 (0x6a)
188 -2, // dmul = 107 (0x6b)
189 -1, // idiv = 108 (0x6c)
190 -2, // ldiv = 109 (0x6d)
191 -1, // fdiv = 110 (0x6e)
192 -2, // ddiv = 111 (0x6f)
193 -1, // irem = 112 (0x70)
194 -2, // lrem = 113 (0x71)
195 -1, // frem = 114 (0x72)
196 -2, // drem = 115 (0x73)
197 0, // ineg = 116 (0x74)
198 0, // lneg = 117 (0x75)
199 0, // fneg = 118 (0x76)
200 0, // dneg = 119 (0x77)
201 -1, // ishl = 120 (0x78)
202 -1, // lshl = 121 (0x79)
203 -1, // ishr = 122 (0x7a)
204 -1, // lshr = 123 (0x7b)
205 -1, // iushr = 124 (0x7c)
206 -1, // lushr = 125 (0x7d)
207 -1, // iand = 126 (0x7e)
208 -2, // land = 127 (0x7f)
209 -1, // ior = 128 (0x80)
210 -2, // lor = 129 (0x81)
211 -1, // ixor = 130 (0x82)
212 -2, // lxor = 131 (0x83)
213 0, // iinc = 132 (0x84)
214 1, // i2l = 133 (0x85)
215 0, // i2f = 134 (0x86)
216 1, // i2d = 135 (0x87)
217 -1, // l2i = 136 (0x88)
218 -1, // l2f = 137 (0x89)
219 0, // l2d = 138 (0x8a)
220 0, // f2i = 139 (0x8b)
221 1, // f2l = 140 (0x8c)
222 1, // f2d = 141 (0x8d)
223 -1, // d2i = 142 (0x8e)
224 0, // d2l = 143 (0x8f)
225 -1, // d2f = 144 (0x90)
226 0, // i2b = 145 (0x91)
227 0, // i2c = 146 (0x92)
228 0, // i2s = 147 (0x93)
229 -3, // lcmp = 148 (0x94)
230 -1, // fcmpl = 149 (0x95)
231 -1, // fcmpg = 150 (0x96)
232 -3, // dcmpl = 151 (0x97)
233 -3, // dcmpg = 152 (0x98)
234 -1, // ifeq = 153 (0x99)
235 -1, // ifne = 154 (0x9a)
236 -1, // iflt = 155 (0x9b)
237 -1, // ifge = 156 (0x9c)
238 -1, // ifgt = 157 (0x9d)
239 -1, // ifle = 158 (0x9e)
240 -2, // if_icmpeq = 159 (0x9f)
241 -2, // if_icmpne = 160 (0xa0)
242 -2, // if_icmplt = 161 (0xa1)
243 -2, // if_icmpge = 162 (0xa2)
244 -2, // if_icmpgt = 163 (0xa3)
245 -2, // if_icmple = 164 (0xa4)
246 -2, // if_acmpeq = 165 (0xa5)
247 -2, // if_acmpne = 166 (0xa6)
248 0, // goto = 167 (0xa7)
249 1, // jsr = 168 (0xa8)
250 0, // ret = 169 (0xa9)
251 -1, // tableswitch = 170 (0xaa)
252 -1, // lookupswitch = 171 (0xab)
253 -1, // ireturn = 172 (0xac)
254 -2, // lreturn = 173 (0xad)
255 -1, // freturn = 174 (0xae)
256 -2, // dreturn = 175 (0xaf)
257 -1, // areturn = 176 (0xb0)
258 0, // return = 177 (0xb1)
259 NA, // getstatic = 178 (0xb2)
260 NA, // putstatic = 179 (0xb3)
261 NA, // getfield = 180 (0xb4)
262 NA, // putfield = 181 (0xb5)
263 NA, // invokevirtual = 182 (0xb6)
264 NA, // invokespecial = 183 (0xb7)
265 NA, // invokestatic = 184 (0xb8)
266 NA, // invokeinterface = 185 (0xb9)
267 NA, // invokedynamic = 186 (0xba)
268 1, // new = 187 (0xbb)
269 0, // newarray = 188 (0xbc)
270 0, // anewarray = 189 (0xbd)
271 0, // arraylength = 190 (0xbe)
272 NA, // athrow = 191 (0xbf)
273 0, // checkcast = 192 (0xc0)
274 0, // instanceof = 193 (0xc1)
275 -1, // monitorenter = 194 (0xc2)
276 -1, // monitorexit = 195 (0xc3)
277 NA, // wide = 196 (0xc4)
278 NA, // multianewarray = 197 (0xc5)
279 -1, // ifnull = 198 (0xc6)
280 -1, // ifnonnull = 199 (0xc7)
281 NA, // goto_w = 200 (0xc8)
282 NA // jsr_w = 201 (0xc9)
283 };
284
285 /** Where the constants used in this MethodWriter must be stored. */
286 private final SymbolTable symbolTable;
287
288 // Note: fields are ordered as in the method_info structure, and those related to attributes are
289 // ordered as in Section 4.7 of the JVMS.
290
291 /**
292 * The access_flags field of the method_info JVMS structure. This field can contain ASM specific
293 * access flags, such as {@link Opcodes#ACC_DEPRECATED}, which are removed when generating the
294 * ClassFile structure.
295 */
296 private final int accessFlags;
297
298 /** The name_index field of the method_info JVMS structure. */
299 private final int nameIndex;
300
301 /** The descriptor_index field of the method_info JVMS structure. */
302 private final int descriptorIndex;
303
304 /** The descriptor of this method. */
305 private final String descriptor;
306
307 // Code attribute fields and sub attributes:
308
309 /** The max_stack field of the Code attribute. */
310 private int maxStack;
311
312 /** The max_locals field of the Code attribute. */
313 private int maxLocals;
314
315 /** The 'code' field of the Code attribute. */
316 private final ByteVector code = new ByteVector();
317
318 /**
319 * The first element in the exception handler list (used to generate the exception_table of the
320 * Code attribute). The next ones can be accessed with the {@link Handler#nextHandler} field. May
321 * be <tt>null</tt>.
322 */
323 private Handler firstHandler;
324
325 /**
326 * The last element in the exception handler list (used to generate the exception_table of the
327 * Code attribute). The next ones can be accessed with the {@link Handler#nextHandler} field. May
328 * be <tt>null</tt>.
329 */
330 private Handler lastHandler;
331
332 /** The line_number_table_length field of the LineNumberTable code attribute. */
333 private int lineNumberTableLength;
334
335 /** The line_number_table array of the LineNumberTable code attribute, or <tt>null</tt>. */
336 private ByteVector lineNumberTable;
337
338 /** The local_variable_table_length field of the LocalVariableTable code attribute. */
339 private int localVariableTableLength;
340
341 /** The local_variable_table array of the LocalVariableTable code attribute, or <tt>null</tt>. */
342 private ByteVector localVariableTable;
343
344 /** The local_variable_type_table_length field of the LocalVariableTypeTable code attribute. */
345 private int localVariableTypeTableLength;
346
347 /**
348 * The local_variable_type_table array of the LocalVariableTypeTable code attribute, or
349 * <tt>null</tt>.
350 */
351 private ByteVector localVariableTypeTable;
352
353 /** The number_of_entries field of the StackMapTable code attribute. */
354 private int stackMapTableNumberOfEntries;
355
356 /** The 'entries' array of the StackMapTable code attribute. */
357 private ByteVector stackMapTableEntries;
358
359 /**
360 * The last runtime visible type annotation of the Code attribute. The previous ones can be
361 * accessed with the {@link AnnotationWriter#previousAnnotation} field. May be <tt>null</tt>.
362 */
363 private AnnotationWriter lastCodeRuntimeVisibleTypeAnnotation;
364
365 /**
366 * The last runtime invisible type annotation of the Code attribute. The previous ones can be
367 * accessed with the {@link AnnotationWriter#previousAnnotation} field. May be <tt>null</tt>.
368 */
369 private AnnotationWriter lastCodeRuntimeInvisibleTypeAnnotation;
370
371 /**
372 * The first non standard attribute of the Code attribute. The next ones can be accessed with the
373 * {@link Attribute#nextAttribute} field. May be <tt>null</tt>.
374 *
375 * <p><b>WARNING</b>: this list stores the attributes in the <i>reverse</i> order of their visit.
376 * firstAttribute is actually the last attribute visited in {@link #visitAttribute}. The {@link
377 * #putMethodInfo} method writes the attributes in the order defined by this list, i.e. in the
378 * reverse order specified by the user.
379 */
380 private Attribute firstCodeAttribute;
381
382 // Other method_info attributes:
383
384 /** The number_of_exceptions field of the Exceptions attribute. */
385 private final int numberOfExceptions;
386
387 /** The exception_index_table array of the Exceptions attribute, or <tt>null</tt>. */
388 private final int[] exceptionIndexTable;
389
390 /** The signature_index field of the Signature attribute. */
391 private final int signatureIndex;
392
393 /**
394 * The last runtime visible annotation of this method. The previous ones can be accessed with the
395 * {@link AnnotationWriter#previousAnnotation} field. May be <tt>null</tt>.
396 */
397 private AnnotationWriter lastRuntimeVisibleAnnotation;
398
399 /**
400 * The last runtime invisible annotation of this method. The previous ones can be accessed with
401 * the {@link AnnotationWriter#previousAnnotation} field. May be <tt>null</tt>.
402 */
403 private AnnotationWriter lastRuntimeInvisibleAnnotation;
404
405 /** The number of method parameters that can have runtime visible annotations, or 0. */
406 private int visibleAnnotableParameterCount;
407
408 /**
409 * The runtime visible parameter annotations of this method. Each array element contains the last
410 * annotation of a parameter (which can be <tt>null</tt> - the previous ones can be accessed with
411 * the {@link AnnotationWriter#previousAnnotation} field). May be <tt>null</tt>.
412 */
413 private AnnotationWriter[] lastRuntimeVisibleParameterAnnotations;
414
415 /** The number of method parameters that can have runtime visible annotations, or 0. */
416 private int invisibleAnnotableParameterCount;
417
418 /**
419 * The runtime invisible parameter annotations of this method. Each array element contains the
420 * last annotation of a parameter (which can be <tt>null</tt> - the previous ones can be accessed
421 * with the {@link AnnotationWriter#previousAnnotation} field). May be <tt>null</tt>.
422 */
423 private AnnotationWriter[] lastRuntimeInvisibleParameterAnnotations;
424
425 /**
426 * The last runtime visible type annotation of this method. The previous ones can be accessed with
427 * the {@link AnnotationWriter#previousAnnotation} field. May be <tt>null</tt>.
428 */
429 private AnnotationWriter lastRuntimeVisibleTypeAnnotation;
430
431 /**
432 * The last runtime invisible type annotation of this method. The previous ones can be accessed
433 * with the {@link AnnotationWriter#previousAnnotation} field. May be <tt>null</tt>.
434 */
435 private AnnotationWriter lastRuntimeInvisibleTypeAnnotation;
436
437 /** The default_value field of the AnnotationDefault attribute, or <tt>null</tt>. */
438 private ByteVector defaultValue;
439
440 /** The parameters_count field of the MethodParameters attribute. */
441 private int parametersCount;
442
443 /** The 'parameters' array of the MethodParameters attribute, or <tt>null</tt>. */
444 private ByteVector parameters;
445
446 /**
447 * The first non standard attribute of this method. The next ones can be accessed with the {@link
448 * Attribute#nextAttribute} field. May be <tt>null</tt>.
449 *
450 * <p><b>WARNING</b>: this list stores the attributes in the <i>reverse</i> order of their visit.
451 * firstAttribute is actually the last attribute visited in {@link #visitAttribute}. The {@link
452 * #putMethodInfo} method writes the attributes in the order defined by this list, i.e. in the
453 * reverse order specified by the user.
454 */
455 private Attribute firstAttribute;
456
457 // -----------------------------------------------------------------------------------------------
458 // Fields used to compute the maximum stack size and number of locals, and the stack map frames
459 // -----------------------------------------------------------------------------------------------
460
461 /**
462 * Indicates what must be computed. Must be one of {@link #COMPUTE_ALL_FRAMES}, {@link
463 * #COMPUTE_INSERTED_FRAMES}, {@link #COMPUTE_MAX_STACK_AND_LOCAL} or {@link #COMPUTE_NOTHING}.
464 */
465 private final int compute;
466
467 /**
468 * The first basic block of the method. The next ones (in bytecode offset order) can be accessed
469 * with the {@link Label#nextBasicBlock} field.
470 */
471 private Label firstBasicBlock;
472
473 /**
474 * The last basic block of the method (in bytecode offset order). This field is updated each time
475 * a basic block is encountered, and is used to append it at the end of the basic block list.
476 */
477 private Label lastBasicBlock;
478
479 /**
480 * The current basic block, i.e. the basic block of the last visited instruction. When {@link
481 * #compute} is equal to {@link #COMPUTE_MAX_STACK_AND_LOCAL} or {@link #COMPUTE_ALL_FRAMES}, this
482 * field is <tt>null</tt> for unreachable code. When {@link #compute} is equal to {@link
483 * #COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES} or {@link #COMPUTE_INSERTED_FRAMES}, this field stays
484 * unchanged throughout the whole method (i.e. the whole code is seen as a single basic block;
485 * indeed, the existing frames are sufficient by hypothesis to compute any intermediate frame -
486 * and the maximum stack size as well - without using any control flow graph).
487 */
488 private Label currentBasicBlock;
489
490 /**
491 * The relative stack size after the last visited instruction. This size is relative to the
492 * beginning of {@link #currentBasicBlock}, i.e. the true stack size after the last visited
493 * instruction is equal to the {@link Label#inputStackSize} of the current basic block plus {@link
494 * #relativeStackSize}. When {@link #compute} is equal to {@link
495 * #COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES}, {@link #currentBasicBlock} is always the start of
496 * the method, so this relative size is also equal to the absolute stack size after the last
497 * visited instruction.
498 */
499 private int relativeStackSize;
500
501 /**
502 * The maximum relative stack size after the last visited instruction. This size is relative to
503 * the beginning of {@link #currentBasicBlock}, i.e. the true maximum stack size after the last
504 * visited instruction is equal to the {@link Label#inputStackSize} of the current basic block
505 * plus {@link #maxRelativeStackSize}.When {@link #compute} is equal to {@link
506 * #COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES}, {@link #currentBasicBlock} is always the start of
507 * the method, so this relative size is also equal to the absolute maximum stack size after the
508 * last visited instruction.
509 */
510 private int maxRelativeStackSize;
511
512 /** The number of local variables in the last visited stack map frame. */
513 private int currentLocals;
514
515 /** The bytecode offset of the last frame that was written in {@link #stackMapTableEntries}. */
516 private int previousFrameOffset;
517
518 /**
519 * The last frame that was written in {@link #stackMapTableEntries}. This field has the same
520 * format as {@link #currentFrame}.
521 */
522 private int[] previousFrame;
523
524 /**
525 * The current stack map frame. The first element contains the bytecode offset of the instruction
526 * to which the frame corresponds, the second element is the number of locals and the third one is
527 * the number of stack elements. The local variables start at index 3 and are followed by the
528 * operand stack elements. In summary frame[0] = offset, frame[1] = nLocal, frame[2] = nStack,
529 * frame[3] = nLocal. Local variables and operand stack entries contain abstract types, as defined
530 * in {@link Frame}, but restricted to {@link Frame#CONSTANT_KIND}, {@link Frame#REFERENCE_KIND}
531 * or {@link Frame#UNINITIALIZED_KIND} abstract types. Long and double types use only one array
532 * entry.
533 */
534 private int[] currentFrame;
535
536 /** Whether this method contains subroutines. */
537 private boolean hasSubroutines;
538
539 // -----------------------------------------------------------------------------------------------
540 // Other miscellaneous status fields
541 // -----------------------------------------------------------------------------------------------
542
543 /** Whether the bytecode of this method contains ASM specific instructions. */
544 private boolean hasAsmInstructions;
545
546 /**
547 * The start offset of the last visited instruction. Used to set the offset field of type
548 * annotations of type 'offset_target' (see <a
549 * href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20.1">JVMS
550 * 4.7.20.1</a>).
551 */
552 private int lastBytecodeOffset;
553
554 /**
555 * The offset in bytes in {@link SymbolTable#getSource} from which the method_info for this method
556 * (excluding its first 6 bytes) must be copied, or 0.
557 */
558 private int sourceOffset;
559
560 /**
561 * The length in bytes in {@link SymbolTable#getSource} which must be copied to get the
562 * method_info for this method (excluding its first 6 bytes for access_flags, name_index and
563 * descriptor_index).
564 */
565 private int sourceLength;
566
567 // -----------------------------------------------------------------------------------------------
568 // Constructor and accessors
569 // -----------------------------------------------------------------------------------------------
570
571 /**
572 * Constructs a new {@link MethodWriter}.
573 *
574 * @param symbolTable where the constants used in this AnnotationWriter must be stored.
575 * @param access the method's access flags (see {@link Opcodes}).
576 * @param name the method's name.
577 * @param descriptor the method's descriptor (see {@link Type}).
578 * @param signature the method's signature. May be <tt>null</tt>.
579 * @param exceptions the internal names of the method's exceptions. May be <tt>null</tt>.
580 * @param compute indicates what must be computed (see #compute).
581 */
582 MethodWriter(
583 final SymbolTable symbolTable,
584 final int access,
585 final String name,
586 final String descriptor,
587 final String signature,
588 final String[] exceptions,
589 final int compute) {
590 super(Opcodes.ASM6);
591 this.symbolTable = symbolTable;
592 this.accessFlags = "<init>".equals(name) ? access | Constants.ACC_CONSTRUCTOR : access;
593 this.nameIndex = symbolTable.addConstantUtf8(name);
594 this.descriptorIndex = symbolTable.addConstantUtf8(descriptor);
595 this.descriptor = descriptor;
596 this.signatureIndex = signature == null ? 0 : symbolTable.addConstantUtf8(signature);
597 if (exceptions != null && exceptions.length > 0) {
598 numberOfExceptions = exceptions.length;
599 this.exceptionIndexTable = new int[numberOfExceptions];
600 for (int i = 0; i < numberOfExceptions; ++i) {
601 this.exceptionIndexTable[i] = symbolTable.addConstantClass(exceptions[i]).index;
602 }
603 } else {
604 numberOfExceptions = 0;
605 this.exceptionIndexTable = null;
606 }
607 this.compute = compute;
608 if (compute != COMPUTE_NOTHING) {
609 // Update maxLocals and currentLocals.
610 int argumentsSize = Type.getArgumentsAndReturnSizes(descriptor) >> 2;
611 if ((access & Opcodes.ACC_STATIC) != 0) {
612 --argumentsSize;
613 }
614 maxLocals = argumentsSize;
615 currentLocals = argumentsSize;
616 // Create and visit the label for the first basic block.
617 firstBasicBlock = new Label();
618 visitLabel(firstBasicBlock);
619 }
620 }
621
622 boolean hasFrames() {
623 return stackMapTableNumberOfEntries > 0;
624 }
625
626 boolean hasAsmInstructions() {
627 return hasAsmInstructions;
628 }
629
630 // -----------------------------------------------------------------------------------------------
631 // Implementation of the MethodVisitor abstract class
632 // -----------------------------------------------------------------------------------------------
633
634 @Override
635 public void visitParameter(final String name, final int access) {
636 if (parameters == null) {
637 parameters = new ByteVector();
638 }
639 ++parametersCount;
640 parameters.putShort((name == null) ? 0 : symbolTable.addConstantUtf8(name)).putShort(access);
641 }
642
643 @Override
644 public AnnotationVisitor visitAnnotationDefault() {
645 defaultValue = new ByteVector();
646 return new AnnotationWriter(symbolTable, /* useNamedValues = */ false, defaultValue, null);
647 }
648
649 @Override
650 public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
651 // Create a ByteVector to hold an 'annotation' JVMS structure.
652 // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.
653 ByteVector annotation = new ByteVector();
654 // Write type_index and reserve space for num_element_value_pairs.
655 annotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0);
656 if (visible) {
657 return lastRuntimeVisibleAnnotation =
658 new AnnotationWriter(symbolTable, annotation, lastRuntimeVisibleAnnotation);
659 } else {
660 return lastRuntimeInvisibleAnnotation =
661 new AnnotationWriter(symbolTable, annotation, lastRuntimeInvisibleAnnotation);
662 }
663 }
664
665 @Override
666 public AnnotationVisitor visitTypeAnnotation(
667 final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
668 // Create a ByteVector to hold a 'type_annotation' JVMS structure.
669 // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20.
670 ByteVector typeAnnotation = new ByteVector();
671 // Write target_type, target_info, and target_path.
672 TypeReference.putTarget(typeRef, typeAnnotation);
673 TypePath.put(typePath, typeAnnotation);
674 // Write type_index and reserve space for num_element_value_pairs.
675 typeAnnotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0);
676 if (visible) {
677 return lastRuntimeVisibleTypeAnnotation =
678 new AnnotationWriter(symbolTable, typeAnnotation, lastRuntimeVisibleTypeAnnotation);
679 } else {
680 return lastRuntimeInvisibleTypeAnnotation =
681 new AnnotationWriter(symbolTable, typeAnnotation, lastRuntimeInvisibleTypeAnnotation);
682 }
683 }
684
685 @Override
686 public void visitAnnotableParameterCount(final int parameterCount, final boolean visible) {
687 if (visible) {
688 visibleAnnotableParameterCount = parameterCount;
689 } else {
690 invisibleAnnotableParameterCount = parameterCount;
691 }
692 }
693
694 @Override
695 public AnnotationVisitor visitParameterAnnotation(
696 final int parameter, final String annotationDescriptor, final boolean visible) {
697 // Create a ByteVector to hold an 'annotation' JVMS structure.
698 // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.
699 ByteVector annotation = new ByteVector();
700 // Write type_index and reserve space for num_element_value_pairs.
701 annotation.putShort(symbolTable.addConstantUtf8(annotationDescriptor)).putShort(0);
702 if (visible) {
703 if (lastRuntimeVisibleParameterAnnotations == null) {
704 lastRuntimeVisibleParameterAnnotations =
705 new AnnotationWriter[Type.getArgumentTypes(descriptor).length];
706 }
707 return lastRuntimeVisibleParameterAnnotations[parameter] =
708 new AnnotationWriter(
709 symbolTable, annotation, lastRuntimeVisibleParameterAnnotations[parameter]);
710 } else {
711 if (lastRuntimeInvisibleParameterAnnotations == null) {
712 lastRuntimeInvisibleParameterAnnotations =
713 new AnnotationWriter[Type.getArgumentTypes(descriptor).length];
714 }
715 return lastRuntimeInvisibleParameterAnnotations[parameter] =
716 new AnnotationWriter(
717 symbolTable, annotation, lastRuntimeInvisibleParameterAnnotations[parameter]);
718 }
719 }
720
721 @Override
722 public void visitAttribute(final Attribute attribute) {
723 // Store the attributes in the <i>reverse</i> order of their visit by this method.
724 if (attribute.isCodeAttribute()) {
725 attribute.nextAttribute = firstCodeAttribute;
726 firstCodeAttribute = attribute;
727 } else {
728 attribute.nextAttribute = firstAttribute;
729 firstAttribute = attribute;
730 }
731 }
732
733 @Override
734 public void visitCode() {
735 // Nothing to do.
736 }
737
738 @Override
739 public void visitFrame(
740 final int type,
741 final int nLocal,
742 final Object[] local,
743 final int nStack,
744 final Object[] stack) {
745 if (compute == COMPUTE_ALL_FRAMES) {
746 return;
747 }
748
749 if (compute == COMPUTE_INSERTED_FRAMES) {
750 if (currentBasicBlock.frame == null) {
751 // This should happen only once, for the implicit first frame (which is explicitly visited
752 // in ClassReader if the EXPAND_ASM_INSNS option is used - and COMPUTE_INSERTED_FRAMES
753 // can't be set if EXPAND_ASM_INSNS is not used).
754 currentBasicBlock.frame = new CurrentFrame(currentBasicBlock);
755 currentBasicBlock.frame.setInputFrameFromDescriptor(
756 symbolTable, accessFlags, descriptor, nLocal);
757 currentBasicBlock.frame.accept(this);
758 } else {
759 if (type == Opcodes.F_NEW) {
760 currentBasicBlock.frame.setInputFrameFromApiFormat(
761 symbolTable, nLocal, local, nStack, stack);
458762 } else {
459 cw.lastMethod.mv = this;
460 }
461 cw.lastMethod = this;
462 this.cw = cw;
463 this.access = access;
464 if ("<init>".equals(name)) {
465 this.access |= ACC_CONSTRUCTOR;
466 }
467 this.name = cw.newUTF8(name);
468 this.desc = cw.newUTF8(desc);
469 this.descriptor = desc;
470 if (ClassReader.SIGNATURES) {
471 this.signature = signature;
472 }
473 if (exceptions != null && exceptions.length > 0) {
474 exceptionCount = exceptions.length;
475 this.exceptions = new int[exceptionCount];
476 for (int i = 0; i < exceptionCount; ++i) {
477 this.exceptions[i] = cw.newClass(exceptions[i]);
763 // In this case type is equal to F_INSERT by hypothesis, and currentBlock.frame contains
764 // the stack map frame at the current instruction, computed from the last F_NEW frame
765 // and the bytecode instructions in between (via calls to CurrentFrame#execute).
766 }
767 currentBasicBlock.frame.accept(this);
768 }
769 } else if (type == Opcodes.F_NEW) {
770 if (previousFrame == null) {
771 int argumentsSize = Type.getArgumentsAndReturnSizes(descriptor) >> 2;
772 Frame implicitFirstFrame = new Frame(new Label());
773 implicitFirstFrame.setInputFrameFromDescriptor(
774 symbolTable, accessFlags, descriptor, argumentsSize);
775 implicitFirstFrame.accept(this);
776 }
777 currentLocals = nLocal;
778 int frameIndex = visitFrameStart(code.length, nLocal, nStack);
779 for (int i = 0; i < nLocal; ++i) {
780 currentFrame[frameIndex++] = Frame.getAbstractTypeFromApiFormat(symbolTable, local[i]);
781 }
782 for (int i = 0; i < nStack; ++i) {
783 currentFrame[frameIndex++] = Frame.getAbstractTypeFromApiFormat(symbolTable, stack[i]);
784 }
785 visitFrameEnd();
786 } else {
787 int offsetDelta;
788 if (stackMapTableEntries == null) {
789 stackMapTableEntries = new ByteVector();
790 offsetDelta = code.length;
791 } else {
792 offsetDelta = code.length - previousFrameOffset - 1;
793 if (offsetDelta < 0) {
794 if (type == Opcodes.F_SAME) {
795 return;
796 } else {
797 throw new IllegalStateException();
798 }
799 }
800 }
801
802 switch (type) {
803 case Opcodes.F_FULL:
804 currentLocals = nLocal;
805 stackMapTableEntries.putByte(Frame.FULL_FRAME).putShort(offsetDelta).putShort(nLocal);
806 for (int i = 0; i < nLocal; ++i) {
807 putFrameType(local[i]);
808 }
809 stackMapTableEntries.putShort(nStack);
810 for (int i = 0; i < nStack; ++i) {
811 putFrameType(stack[i]);
812 }
813 break;
814 case Opcodes.F_APPEND:
815 currentLocals += nLocal;
816 stackMapTableEntries.putByte(Frame.SAME_FRAME_EXTENDED + nLocal).putShort(offsetDelta);
817 for (int i = 0; i < nLocal; ++i) {
818 putFrameType(local[i]);
819 }
820 break;
821 case Opcodes.F_CHOP:
822 currentLocals -= nLocal;
823 stackMapTableEntries.putByte(Frame.SAME_FRAME_EXTENDED - nLocal).putShort(offsetDelta);
824 break;
825 case Opcodes.F_SAME:
826 if (offsetDelta < 64) {
827 stackMapTableEntries.putByte(offsetDelta);
828 } else {
829 stackMapTableEntries.putByte(Frame.SAME_FRAME_EXTENDED).putShort(offsetDelta);
830 }
831 break;
832 case Opcodes.F_SAME1:
833 if (offsetDelta < 64) {
834 stackMapTableEntries.putByte(Frame.SAME_LOCALS_1_STACK_ITEM_FRAME + offsetDelta);
835 } else {
836 stackMapTableEntries
837 .putByte(Frame.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED)
838 .putShort(offsetDelta);
839 }
840 putFrameType(stack[0]);
841 break;
842 default:
843 throw new IllegalArgumentException();
844 }
845
846 previousFrameOffset = code.length;
847 ++stackMapTableNumberOfEntries;
848 }
849
850 if (compute == COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES) {
851 relativeStackSize = nStack;
852 if (nStack > maxRelativeStackSize) {
853 maxRelativeStackSize = relativeStackSize;
854 }
855 }
856
857 maxStack = Math.max(maxStack, nStack);
858 maxLocals = Math.max(maxLocals, currentLocals);
859 }
860
861 @Override
862 public void visitInsn(final int opcode) {
863 lastBytecodeOffset = code.length;
864 // Add the instruction to the bytecode of the method.
865 code.putByte(opcode);
866 // If needed, update the maximum stack size and number of locals, and stack map frames.
867 if (currentBasicBlock != null) {
868 if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) {
869 currentBasicBlock.frame.execute(opcode, 0, null, null);
870 } else {
871 int size = relativeStackSize + STACK_SIZE_DELTA[opcode];
872 if (size > maxRelativeStackSize) {
873 maxRelativeStackSize = size;
874 }
875 relativeStackSize = size;
876 }
877 if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN) || opcode == Opcodes.ATHROW) {
878 endCurrentBasicBlockWithNoSuccessor();
879 }
880 }
881 }
882
883 @Override
884 public void visitIntInsn(final int opcode, final int operand) {
885 lastBytecodeOffset = code.length;
886 // Add the instruction to the bytecode of the method.
887 if (opcode == Opcodes.SIPUSH) {
888 code.put12(opcode, operand);
889 } else { // BIPUSH or NEWARRAY
890 code.put11(opcode, operand);
891 }
892 // If needed, update the maximum stack size and number of locals, and stack map frames.
893 if (currentBasicBlock != null) {
894 if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) {
895 currentBasicBlock.frame.execute(opcode, operand, null, null);
896 } else if (opcode != Opcodes.NEWARRAY) {
897 // The stack size delta is 1 for BIPUSH or SIPUSH, and 0 for NEWARRAY.
898 int size = relativeStackSize + 1;
899 if (size > maxRelativeStackSize) {
900 maxRelativeStackSize = size;
901 }
902 relativeStackSize = size;
903 }
904 }
905 }
906
907 @Override
908 public void visitVarInsn(final int opcode, final int var) {
909 lastBytecodeOffset = code.length;
910 // Add the instruction to the bytecode of the method.
911 if (var < 4 && opcode != Opcodes.RET) {
912 int optimizedOpcode;
913 if (opcode < Opcodes.ISTORE) {
914 optimizedOpcode = Constants.ILOAD_0 + ((opcode - Opcodes.ILOAD) << 2) + var;
915 } else {
916 optimizedOpcode = Constants.ISTORE_0 + ((opcode - Opcodes.ISTORE) << 2) + var;
917 }
918 code.putByte(optimizedOpcode);
919 } else if (var >= 256) {
920 code.putByte(Constants.WIDE).put12(opcode, var);
921 } else {
922 code.put11(opcode, var);
923 }
924 // If needed, update the maximum stack size and number of locals, and stack map frames.
925 if (currentBasicBlock != null) {
926 if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) {
927 currentBasicBlock.frame.execute(opcode, var, null, null);
928 } else {
929 if (opcode == Opcodes.RET) {
930 // No stack size delta.
931 currentBasicBlock.flags |= Label.FLAG_SUBROUTINE_END;
932 currentBasicBlock.outputStackSize = (short) relativeStackSize;
933 endCurrentBasicBlockWithNoSuccessor();
934 } else { // xLOAD or xSTORE
935 int size = relativeStackSize + STACK_SIZE_DELTA[opcode];
936 if (size > maxRelativeStackSize) {
937 maxRelativeStackSize = size;
938 }
939 relativeStackSize = size;
940 }
941 }
942 }
943 if (compute != COMPUTE_NOTHING) {
944 int currentMaxLocals;
945 if (opcode == Opcodes.LLOAD
946 || opcode == Opcodes.DLOAD
947 || opcode == Opcodes.LSTORE
948 || opcode == Opcodes.DSTORE) {
949 currentMaxLocals = var + 2;
950 } else {
951 currentMaxLocals = var + 1;
952 }
953 if (currentMaxLocals > maxLocals) {
954 maxLocals = currentMaxLocals;
955 }
956 }
957 if (opcode >= Opcodes.ISTORE && compute == COMPUTE_ALL_FRAMES && firstHandler != null) {
958 // If there are exception handler blocks, each instruction within a handler range is, in
959 // theory, a basic block (since execution can jump from this instruction to the exception
960 // handler). As a consequence, the local variable types at the beginning of the handler
961 // block should be the merge of the local variable types at all the instructions within the
962 // handler range. However, instead of creating a basic block for each instruction, we can
963 // get the same result in a more efficient way. Namely, by starting a new basic block after
964 // each xSTORE instruction, which is what we do here.
965 visitLabel(new Label());
966 }
967 }
968
969 @Override
970 public void visitTypeInsn(final int opcode, final String type) {
971 lastBytecodeOffset = code.length;
972 // Add the instruction to the bytecode of the method.
973 Symbol typeSymbol = symbolTable.addConstantClass(type);
974 code.put12(opcode, typeSymbol.index);
975 // If needed, update the maximum stack size and number of locals, and stack map frames.
976 if (currentBasicBlock != null) {
977 if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) {
978 currentBasicBlock.frame.execute(opcode, lastBytecodeOffset, typeSymbol, symbolTable);
979 } else if (opcode == Opcodes.NEW) {
980 // The stack size delta is 1 for NEW, and 0 for ANEWARRAY, CHECKCAST, or INSTANCEOF.
981 int size = relativeStackSize + 1;
982 if (size > maxRelativeStackSize) {
983 maxRelativeStackSize = size;
984 }
985 relativeStackSize = size;
986 }
987 }
988 }
989
990 @Override
991 public void visitFieldInsn(
992 final int opcode, final String owner, final String name, final String descriptor) {
993 lastBytecodeOffset = code.length;
994 // Add the instruction to the bytecode of the method.
995 Symbol fieldrefSymbol = symbolTable.addConstantFieldref(owner, name, descriptor);
996 code.put12(opcode, fieldrefSymbol.index);
997 // If needed, update the maximum stack size and number of locals, and stack map frames.
998 if (currentBasicBlock != null) {
999 if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) {
1000 currentBasicBlock.frame.execute(opcode, 0, fieldrefSymbol, symbolTable);
1001 } else {
1002 int size;
1003 char firstDescChar = descriptor.charAt(0);
1004 switch (opcode) {
1005 case Opcodes.GETSTATIC:
1006 size = relativeStackSize + (firstDescChar == 'D' || firstDescChar == 'J' ? 2 : 1);
1007 break;
1008 case Opcodes.PUTSTATIC:
1009 size = relativeStackSize + (firstDescChar == 'D' || firstDescChar == 'J' ? -2 : -1);
1010 break;
1011 case Opcodes.GETFIELD:
1012 size = relativeStackSize + (firstDescChar == 'D' || firstDescChar == 'J' ? 1 : 0);
1013 break;
1014 case Opcodes.PUTFIELD:
1015 default:
1016 size = relativeStackSize + (firstDescChar == 'D' || firstDescChar == 'J' ? -3 : -2);
1017 break;
1018 }
1019 if (size > maxRelativeStackSize) {
1020 maxRelativeStackSize = size;
1021 }
1022 relativeStackSize = size;
1023 }
1024 }
1025 }
1026
1027 @Override
1028 public void visitMethodInsn(
1029 final int opcode,
1030 final String owner,
1031 final String name,
1032 final String descriptor,
1033 final boolean isInterface) {
1034 lastBytecodeOffset = code.length;
1035 // Add the instruction to the bytecode of the method.
1036 Symbol methodrefSymbol = symbolTable.addConstantMethodref(owner, name, descriptor, isInterface);
1037 if (opcode == Opcodes.INVOKEINTERFACE) {
1038 code.put12(Opcodes.INVOKEINTERFACE, methodrefSymbol.index)
1039 .put11(methodrefSymbol.getArgumentsAndReturnSizes() >> 2, 0);
1040 } else {
1041 code.put12(opcode, methodrefSymbol.index);
1042 }
1043 // If needed, update the maximum stack size and number of locals, and stack map frames.
1044 if (currentBasicBlock != null) {
1045 if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) {
1046 currentBasicBlock.frame.execute(opcode, 0, methodrefSymbol, symbolTable);
1047 } else {
1048 int argumentsAndReturnSize = methodrefSymbol.getArgumentsAndReturnSizes();
1049 int stackSizeDelta = (argumentsAndReturnSize & 3) - (argumentsAndReturnSize >> 2);
1050 int size;
1051 if (opcode == Opcodes.INVOKESTATIC) {
1052 size = relativeStackSize + stackSizeDelta + 1;
1053 } else {
1054 size = relativeStackSize + stackSizeDelta;
1055 }
1056 if (size > maxRelativeStackSize) {
1057 maxRelativeStackSize = size;
1058 }
1059 relativeStackSize = size;
1060 }
1061 }
1062 }
1063
1064 @Override
1065 public void visitInvokeDynamicInsn(
1066 final String name,
1067 final String descriptor,
1068 final Handle bootstrapMethodHandle,
1069 final Object... bootstrapMethodArguments) {
1070 lastBytecodeOffset = code.length;
1071 // Add the instruction to the bytecode of the method.
1072 Symbol invokeDynamicSymbol =
1073 symbolTable.addConstantInvokeDynamic(
1074 name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments);
1075 code.put12(Opcodes.INVOKEDYNAMIC, invokeDynamicSymbol.index);
1076 code.putShort(0);
1077 // If needed, update the maximum stack size and number of locals, and stack map frames.
1078 if (currentBasicBlock != null) {
1079 if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) {
1080 currentBasicBlock.frame.execute(Opcodes.INVOKEDYNAMIC, 0, invokeDynamicSymbol, symbolTable);
1081 } else {
1082 int argumentsAndReturnSize = invokeDynamicSymbol.getArgumentsAndReturnSizes();
1083 int stackSizeDelta = (argumentsAndReturnSize & 3) - (argumentsAndReturnSize >> 2) + 1;
1084 int size = relativeStackSize + stackSizeDelta;
1085 if (size > maxRelativeStackSize) {
1086 maxRelativeStackSize = size;
1087 }
1088 relativeStackSize = size;
1089 }
1090 }
1091 }
1092
1093 @Override
1094 public void visitJumpInsn(final int opcode, final Label label) {
1095 lastBytecodeOffset = code.length;
1096 // Add the instruction to the bytecode of the method.
1097 // Compute the 'base' opcode, i.e. GOTO or JSR if opcode is GOTO_W or JSR_W, otherwise opcode.
1098 int baseOpcode =
1099 opcode >= Constants.GOTO_W ? opcode - Constants.WIDE_JUMP_OPCODE_DELTA : opcode;
1100 boolean nextInsnIsJumpTarget = false;
1101 if ((label.flags & Label.FLAG_RESOLVED) != 0
1102 && label.bytecodeOffset - code.length < Short.MIN_VALUE) {
1103 // Case of a backward jump with an offset < -32768. In this case we automatically replace GOTO
1104 // with GOTO_W, JSR with JSR_W and IFxxx <l> with IFNOTxxx <L> GOTO_W <l> L:..., where
1105 // IFNOTxxx is the "opposite" opcode of IFxxx (e.g. IFNE for IFEQ) and where <L> designates
1106 // the instruction just after the GOTO_W.
1107 if (baseOpcode == Opcodes.GOTO) {
1108 code.putByte(Constants.GOTO_W);
1109 } else if (baseOpcode == Opcodes.JSR) {
1110 code.putByte(Constants.JSR_W);
1111 } else {
1112 // Put the "opposite" opcode of baseOpcode. This can be done by flipping the least
1113 // significant bit for IFNULL and IFNONNULL, and similarly for IFEQ ... IF_ACMPEQ (with a
1114 // pre and post offset by 1). The jump offset is 8 bytes (3 for IFNOTxxx, 5 for GOTO_W).
1115 code.putByte(baseOpcode >= Opcodes.IFNULL ? baseOpcode ^ 1 : ((baseOpcode + 1) ^ 1) - 1);
1116 code.putShort(8);
1117 // Here we could put a GOTO_W in theory, but if ASM specific instructions are used in this
1118 // method or another one, and if the class has frames, we will need to insert a frame after
1119 // this GOTO_W during the additional ClassReader -> ClassWriter round trip to remove the ASM
1120 // specific instructions. To not miss this additional frame, we need to use an ASM_GOTO_W
1121 // here, which has the unfortunate effect of forcing this additional round trip (which in
1122 // some case would not have been really necessary, but we can't know this at this point).
1123 code.putByte(Constants.ASM_GOTO_W);
1124 hasAsmInstructions = true;
1125 // The instruction after the GOTO_W becomes the target of the IFNOT instruction.
1126 nextInsnIsJumpTarget = true;
1127 }
1128 label.put(code, code.length - 1, true);
1129 } else if (baseOpcode != opcode) {
1130 // Case of a GOTO_W or JSR_W specified by the user (normally ClassReader when used to remove
1131 // ASM specific instructions). In this case we keep the original instruction.
1132 code.putByte(opcode);
1133 label.put(code, code.length - 1, true);
1134 } else {
1135 // Case of a jump with an offset >= -32768, or of a jump with an unknown offset. In these
1136 // cases we store the offset in 2 bytes (which will be increased via a ClassReader ->
1137 // ClassWriter round trip if it turns out that 2 bytes are not sufficient).
1138 code.putByte(baseOpcode);
1139 label.put(code, code.length - 1, false);
1140 }
1141
1142 // If needed, update the maximum stack size and number of locals, and stack map frames.
1143 if (currentBasicBlock != null) {
1144 Label nextBasicBlock = null;
1145 if (compute == COMPUTE_ALL_FRAMES) {
1146 currentBasicBlock.frame.execute(baseOpcode, 0, null, null);
1147 // Record the fact that 'label' is the target of a jump instruction.
1148 label.getCanonicalInstance().flags |= Label.FLAG_JUMP_TARGET;
1149 // Add 'label' as a successor of the current basic block.
1150 addSuccessorToCurrentBasicBlock(Edge.JUMP, label);
1151 if (baseOpcode != Opcodes.GOTO) {
1152 // The next instruction starts a new basic block (except for GOTO: by default the code
1153 // following a goto is unreachable - unless there is an explicit label for it - and we
1154 // should not compute stack frame types for its instructions).
1155 nextBasicBlock = new Label();
1156 }
1157 } else if (compute == COMPUTE_INSERTED_FRAMES) {
1158 currentBasicBlock.frame.execute(baseOpcode, 0, null, null);
1159 } else if (compute == COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES) {
1160 // No need to update maxRelativeStackSize (the stack size delta is always negative).
1161 relativeStackSize += STACK_SIZE_DELTA[baseOpcode];
1162 } else {
1163 if (baseOpcode == Opcodes.JSR) {
1164 // Record the fact that 'label' designates a subroutine, if not already done.
1165 if ((label.flags & Label.FLAG_SUBROUTINE_START) == 0) {
1166 label.flags |= Label.FLAG_SUBROUTINE_START;
1167 hasSubroutines = true;
1168 }
1169 currentBasicBlock.flags |= Label.FLAG_SUBROUTINE_CALLER;
1170 // Note that, by construction in this method, a block which calls a subroutine has at
1171 // least two successors in the control flow graph: the first one (added below) leads to
1172 // the instruction after the JSR, while the second one (added here) leads to the JSR
1173 // target. Note that the first successor is virtual (it does not correspond to a possible
1174 // execution path): it is only used to compute the successors of the basic blocks ending
1175 // with a ret, in {@link Label#addSubroutineRetSuccessors}.
1176 addSuccessorToCurrentBasicBlock(relativeStackSize + 1, label);
1177 // The instruction after the JSR starts a new basic block.
1178 nextBasicBlock = new Label();
1179 } else {
1180 // No need to update maxRelativeStackSize (the stack size delta is always negative).
1181 relativeStackSize += STACK_SIZE_DELTA[baseOpcode];
1182 addSuccessorToCurrentBasicBlock(relativeStackSize, label);
1183 }
1184 }
1185 // If the next instruction starts a new basic block, call visitLabel to add the label of this
1186 // instruction as a successor of the current block, and to start a new basic block.
1187 if (nextBasicBlock != null) {
1188 if (nextInsnIsJumpTarget) {
1189 nextBasicBlock.flags |= Label.FLAG_JUMP_TARGET;
1190 }
1191 visitLabel(nextBasicBlock);
1192 }
1193 if (baseOpcode == Opcodes.GOTO) {
1194 endCurrentBasicBlockWithNoSuccessor();
1195 }
1196 }
1197 }
1198
1199 @Override
1200 public void visitLabel(final Label label) {
1201 // Resolve the forward references to this label, if any.
1202 hasAsmInstructions |= label.resolve(code.data, code.length);
1203 // visitLabel starts a new basic block (except for debug only labels), so we need to update the
1204 // previous and current block references and list of successors.
1205 if ((label.flags & Label.FLAG_DEBUG_ONLY) != 0) {
1206 return;
1207 }
1208 if (compute == COMPUTE_ALL_FRAMES) {
1209 if (currentBasicBlock != null) {
1210 if (label.bytecodeOffset == currentBasicBlock.bytecodeOffset) {
1211 // We use {@link Label#getCanonicalInstance} to store the state of a basic block in only
1212 // one place, but this does not work for labels which have not been visited yet.
1213 // Therefore, when we detect here two labels having the same bytecode offset, we need to
1214 // - consolidate the state scattered in these two instances into the canonical instance:
1215 currentBasicBlock.flags |= (label.flags & Label.FLAG_JUMP_TARGET);
1216 // - make sure the two instances share the same Frame instance (the implementation of
1217 // {@link Label#getCanonicalInstance} relies on this property; here label.frame should be
1218 // null):
1219 label.frame = currentBasicBlock.frame;
1220 // - and make sure to NOT assign 'label' into 'currentBasicBlock' or 'lastBasicBlock', so
1221 // that they still refer to the canonical instance for this bytecode offset.
1222 return;
1223 }
1224 // End the current basic block (with one new successor).
1225 addSuccessorToCurrentBasicBlock(Edge.JUMP, label);
1226 }
1227 // Append 'label' at the end of the basic block list.
1228 if (lastBasicBlock != null) {
1229 if (label.bytecodeOffset == lastBasicBlock.bytecodeOffset) {
1230 // Same comment as above.
1231 lastBasicBlock.flags |= (label.flags & Label.FLAG_JUMP_TARGET);
1232 // Here label.frame should be null.
1233 label.frame = lastBasicBlock.frame;
1234 currentBasicBlock = lastBasicBlock;
1235 return;
1236 }
1237 lastBasicBlock.nextBasicBlock = label;
1238 }
1239 lastBasicBlock = label;
1240 // Make it the new current basic block.
1241 currentBasicBlock = label;
1242 // Here label.frame should be null.
1243 label.frame = new Frame(label);
1244 } else if (compute == COMPUTE_INSERTED_FRAMES) {
1245 if (currentBasicBlock == null) {
1246 // This case should happen only once, for the visitLabel call in the constructor. Indeed, if
1247 // compute is equal to COMPUTE_INSERTED_FRAMES, currentBasicBlock stays unchanged.
1248 currentBasicBlock = label;
1249 } else {
1250 // Update the frame owner so that a correct frame offset is computed in Frame.accept().
1251 currentBasicBlock.frame.owner = label;
1252 }
1253 } else if (compute == COMPUTE_MAX_STACK_AND_LOCAL) {
1254 if (currentBasicBlock != null) {
1255 // End the current basic block (with one new successor).
1256 currentBasicBlock.outputStackMax = (short) maxRelativeStackSize;
1257 addSuccessorToCurrentBasicBlock(relativeStackSize, label);
1258 }
1259 // Start a new current basic block, and reset the current and maximum relative stack sizes.
1260 currentBasicBlock = label;
1261 relativeStackSize = 0;
1262 maxRelativeStackSize = 0;
1263 // Append the new basic block at the end of the basic block list.
1264 if (lastBasicBlock != null) {
1265 lastBasicBlock.nextBasicBlock = label;
1266 }
1267 lastBasicBlock = label;
1268 } else if (compute == COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES && currentBasicBlock == null) {
1269 // This case should happen only once, for the visitLabel call in the constructor. Indeed, if
1270 // compute is equal to COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES, currentBasicBlock stays
1271 // unchanged.
1272 currentBasicBlock = label;
1273 }
1274 }
1275
1276 @Override
1277 public void visitLdcInsn(final Object value) {
1278 lastBytecodeOffset = code.length;
1279 // Add the instruction to the bytecode of the method.
1280 Symbol constantSymbol = symbolTable.addConstant(value);
1281 int constantIndex = constantSymbol.index;
1282 boolean isLongOrDouble =
1283 constantSymbol.tag == Symbol.CONSTANT_LONG_TAG
1284 || constantSymbol.tag == Symbol.CONSTANT_DOUBLE_TAG;
1285 if (isLongOrDouble) {
1286 code.put12(Constants.LDC2_W, constantIndex);
1287 } else if (constantIndex >= 256) {
1288 code.put12(Constants.LDC_W, constantIndex);
1289 } else {
1290 code.put11(Opcodes.LDC, constantIndex);
1291 }
1292 // If needed, update the maximum stack size and number of locals, and stack map frames.
1293 if (currentBasicBlock != null) {
1294 if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) {
1295 currentBasicBlock.frame.execute(Opcodes.LDC, 0, constantSymbol, symbolTable);
1296 } else {
1297 int size = relativeStackSize + (isLongOrDouble ? 2 : 1);
1298 if (size > maxRelativeStackSize) {
1299 maxRelativeStackSize = size;
1300 }
1301 relativeStackSize = size;
1302 }
1303 }
1304 }
1305
1306 @Override
1307 public void visitIincInsn(final int var, final int increment) {
1308 lastBytecodeOffset = code.length;
1309 // Add the instruction to the bytecode of the method.
1310 if ((var > 255) || (increment > 127) || (increment < -128)) {
1311 code.putByte(Constants.WIDE).put12(Opcodes.IINC, var).putShort(increment);
1312 } else {
1313 code.putByte(Opcodes.IINC).put11(var, increment);
1314 }
1315 // If needed, update the maximum stack size and number of locals, and stack map frames.
1316 if (currentBasicBlock != null
1317 && (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES)) {
1318 currentBasicBlock.frame.execute(Opcodes.IINC, var, null, null);
1319 }
1320 if (compute != COMPUTE_NOTHING) {
1321 int currentMaxLocals = var + 1;
1322 if (currentMaxLocals > maxLocals) {
1323 maxLocals = currentMaxLocals;
1324 }
1325 }
1326 }
1327
1328 @Override
1329 public void visitTableSwitchInsn(
1330 final int min, final int max, final Label dflt, final Label... labels) {
1331 lastBytecodeOffset = code.length;
1332 // Add the instruction to the bytecode of the method.
1333 code.putByte(Opcodes.TABLESWITCH).putByteArray(null, 0, (4 - code.length % 4) % 4);
1334 dflt.put(code, lastBytecodeOffset, true);
1335 code.putInt(min).putInt(max);
1336 for (Label label : labels) {
1337 label.put(code, lastBytecodeOffset, true);
1338 }
1339 // If needed, update the maximum stack size and number of locals, and stack map frames.
1340 visitSwitchInsn(dflt, labels);
1341 }
1342
1343 @Override
1344 public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) {
1345 lastBytecodeOffset = code.length;
1346 // Add the instruction to the bytecode of the method.
1347 code.putByte(Opcodes.LOOKUPSWITCH).putByteArray(null, 0, (4 - code.length % 4) % 4);
1348 dflt.put(code, lastBytecodeOffset, true);
1349 code.putInt(labels.length);
1350 for (int i = 0; i < labels.length; ++i) {
1351 code.putInt(keys[i]);
1352 labels[i].put(code, lastBytecodeOffset, true);
1353 }
1354 // If needed, update the maximum stack size and number of locals, and stack map frames.
1355 visitSwitchInsn(dflt, labels);
1356 }
1357
1358 private void visitSwitchInsn(final Label dflt, final Label[] labels) {
1359 if (currentBasicBlock != null) {
1360 if (compute == COMPUTE_ALL_FRAMES) {
1361 currentBasicBlock.frame.execute(Opcodes.LOOKUPSWITCH, 0, null, null);
1362 // Add all the labels as successors of the current basic block.
1363 addSuccessorToCurrentBasicBlock(Edge.JUMP, dflt);
1364 dflt.getCanonicalInstance().flags |= Label.FLAG_JUMP_TARGET;
1365 for (Label label : labels) {
1366 addSuccessorToCurrentBasicBlock(Edge.JUMP, label);
1367 label.getCanonicalInstance().flags |= Label.FLAG_JUMP_TARGET;
1368 }
1369 } else if (compute == COMPUTE_MAX_STACK_AND_LOCAL) {
1370 // No need to update maxRelativeStackSize (the stack size delta is always negative).
1371 --relativeStackSize;
1372 // Add all the labels as successors of the current basic block.
1373 addSuccessorToCurrentBasicBlock(relativeStackSize, dflt);
1374 for (Label label : labels) {
1375 addSuccessorToCurrentBasicBlock(relativeStackSize, label);
1376 }
1377 }
1378 // End the current basic block.
1379 endCurrentBasicBlockWithNoSuccessor();
1380 }
1381 }
1382
1383 @Override
1384 public void visitMultiANewArrayInsn(final String descriptor, final int numDimensions) {
1385 lastBytecodeOffset = code.length;
1386 // Add the instruction to the bytecode of the method.
1387 Symbol descSymbol = symbolTable.addConstantClass(descriptor);
1388 code.put12(Opcodes.MULTIANEWARRAY, descSymbol.index).putByte(numDimensions);
1389 // If needed, update the maximum stack size and number of locals, and stack map frames.
1390 if (currentBasicBlock != null) {
1391 if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) {
1392 currentBasicBlock.frame.execute(
1393 Opcodes.MULTIANEWARRAY, numDimensions, descSymbol, symbolTable);
1394 } else {
1395 // No need to update maxRelativeStackSize (the stack size delta is always negative).
1396 relativeStackSize += 1 - numDimensions;
1397 }
1398 }
1399 }
1400
1401 @Override
1402 public AnnotationVisitor visitInsnAnnotation(
1403 final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
1404 // Create a ByteVector to hold a 'type_annotation' JVMS structure.
1405 // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20.
1406 ByteVector typeAnnotation = new ByteVector();
1407 // Write target_type, target_info, and target_path.
1408 TypeReference.putTarget((typeRef & 0xFF0000FF) | (lastBytecodeOffset << 8), typeAnnotation);
1409 TypePath.put(typePath, typeAnnotation);
1410 // Write type_index and reserve space for num_element_value_pairs.
1411 typeAnnotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0);
1412 if (visible) {
1413 return lastCodeRuntimeVisibleTypeAnnotation =
1414 new AnnotationWriter(symbolTable, typeAnnotation, lastCodeRuntimeVisibleTypeAnnotation);
1415 } else {
1416 return lastCodeRuntimeInvisibleTypeAnnotation =
1417 new AnnotationWriter(symbolTable, typeAnnotation, lastCodeRuntimeInvisibleTypeAnnotation);
1418 }
1419 }
1420
1421 @Override
1422 public void visitTryCatchBlock(
1423 final Label start, final Label end, final Label handler, final String type) {
1424 Handler newHandler =
1425 new Handler(
1426 start, end, handler, type != null ? symbolTable.addConstantClass(type).index : 0, type);
1427 if (firstHandler == null) {
1428 firstHandler = newHandler;
1429 } else {
1430 lastHandler.nextHandler = newHandler;
1431 }
1432 lastHandler = newHandler;
1433 }
1434
1435 @Override
1436 public AnnotationVisitor visitTryCatchAnnotation(
1437 final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
1438 // Create a ByteVector to hold a 'type_annotation' JVMS structure.
1439 // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20.
1440 ByteVector typeAnnotation = new ByteVector();
1441 // Write target_type, target_info, and target_path.
1442 TypeReference.putTarget(typeRef, typeAnnotation);
1443 TypePath.put(typePath, typeAnnotation);
1444 // Write type_index and reserve space for num_element_value_pairs.
1445 typeAnnotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0);
1446 if (visible) {
1447 return lastCodeRuntimeVisibleTypeAnnotation =
1448 new AnnotationWriter(symbolTable, typeAnnotation, lastCodeRuntimeVisibleTypeAnnotation);
1449 } else {
1450 return lastCodeRuntimeInvisibleTypeAnnotation =
1451 new AnnotationWriter(symbolTable, typeAnnotation, lastCodeRuntimeInvisibleTypeAnnotation);
1452 }
1453 }
1454
1455 @Override
1456 public void visitLocalVariable(
1457 final String name,
1458 final String descriptor,
1459 final String signature,
1460 final Label start,
1461 final Label end,
1462 final int index) {
1463 if (signature != null) {
1464 if (localVariableTypeTable == null) {
1465 localVariableTypeTable = new ByteVector();
1466 }
1467 ++localVariableTypeTableLength;
1468 localVariableTypeTable
1469 .putShort(start.bytecodeOffset)
1470 .putShort(end.bytecodeOffset - start.bytecodeOffset)
1471 .putShort(symbolTable.addConstantUtf8(name))
1472 .putShort(symbolTable.addConstantUtf8(signature))
1473 .putShort(index);
1474 }
1475 if (localVariableTable == null) {
1476 localVariableTable = new ByteVector();
1477 }
1478 ++localVariableTableLength;
1479 localVariableTable
1480 .putShort(start.bytecodeOffset)
1481 .putShort(end.bytecodeOffset - start.bytecodeOffset)
1482 .putShort(symbolTable.addConstantUtf8(name))
1483 .putShort(symbolTable.addConstantUtf8(descriptor))
1484 .putShort(index);
1485 if (compute != COMPUTE_NOTHING) {
1486 char firstDescChar = descriptor.charAt(0);
1487 int currentMaxLocals = index + (firstDescChar == 'J' || firstDescChar == 'D' ? 2 : 1);
1488 if (currentMaxLocals > maxLocals) {
1489 maxLocals = currentMaxLocals;
1490 }
1491 }
1492 }
1493
1494 @Override
1495 public AnnotationVisitor visitLocalVariableAnnotation(
1496 final int typeRef,
1497 final TypePath typePath,
1498 final Label[] start,
1499 final Label[] end,
1500 final int[] index,
1501 final String descriptor,
1502 final boolean visible) {
1503 // Create a ByteVector to hold a 'type_annotation' JVMS structure.
1504 // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20.
1505 ByteVector typeAnnotation = new ByteVector();
1506 // Write target_type, target_info, and target_path.
1507 typeAnnotation.putByte(typeRef >>> 24).putShort(start.length);
1508 for (int i = 0; i < start.length; ++i) {
1509 typeAnnotation
1510 .putShort(start[i].bytecodeOffset)
1511 .putShort(end[i].bytecodeOffset - start[i].bytecodeOffset)
1512 .putShort(index[i]);
1513 }
1514 TypePath.put(typePath, typeAnnotation);
1515 // Write type_index and reserve space for num_element_value_pairs.
1516 typeAnnotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0);
1517 if (visible) {
1518 return lastCodeRuntimeVisibleTypeAnnotation =
1519 new AnnotationWriter(symbolTable, typeAnnotation, lastCodeRuntimeVisibleTypeAnnotation);
1520 } else {
1521 return lastCodeRuntimeInvisibleTypeAnnotation =
1522 new AnnotationWriter(symbolTable, typeAnnotation, lastCodeRuntimeInvisibleTypeAnnotation);
1523 }
1524 }
1525
1526 @Override
1527 public void visitLineNumber(final int line, final Label start) {
1528 if (lineNumberTable == null) {
1529 lineNumberTable = new ByteVector();
1530 }
1531 ++lineNumberTableLength;
1532 lineNumberTable.putShort(start.bytecodeOffset);
1533 lineNumberTable.putShort(line);
1534 }
1535
1536 @Override
1537 public void visitMaxs(final int maxStack, final int maxLocals) {
1538 if (compute == COMPUTE_ALL_FRAMES) {
1539 computeAllFrames();
1540 } else if (compute == COMPUTE_MAX_STACK_AND_LOCAL) {
1541 computeMaxStackAndLocal();
1542 } else if (compute == COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES) {
1543 this.maxStack = maxRelativeStackSize;
1544 } else {
1545 this.maxStack = maxStack;
1546 this.maxLocals = maxLocals;
1547 }
1548 }
1549
1550 /** Computes all the stack map frames of the method, from scratch. */
1551 private void computeAllFrames() {
1552 // Complete the control flow graph with exception handler blocks.
1553 Handler handler = firstHandler;
1554 while (handler != null) {
1555 String catchTypeDescriptor =
1556 handler.catchTypeDescriptor == null ? "java/lang/Throwable" : handler.catchTypeDescriptor;
1557 int catchType = Frame.getAbstractTypeFromInternalName(symbolTable, catchTypeDescriptor);
1558 // Mark handlerBlock as an exception handler.
1559 Label handlerBlock = handler.handlerPc.getCanonicalInstance();
1560 handlerBlock.flags |= Label.FLAG_JUMP_TARGET;
1561 // Add handlerBlock as a successor of all the basic blocks in the exception handler range.
1562 Label handlerRangeBlock = handler.startPc.getCanonicalInstance();
1563 Label handlerRangeEnd = handler.endPc.getCanonicalInstance();
1564 while (handlerRangeBlock != handlerRangeEnd) {
1565 handlerRangeBlock.outgoingEdges =
1566 new Edge(catchType, handlerBlock, handlerRangeBlock.outgoingEdges);
1567 handlerRangeBlock = handlerRangeBlock.nextBasicBlock;
1568 }
1569 handler = handler.nextHandler;
1570 }
1571
1572 // Create and visit the first (implicit) frame.
1573 Frame firstFrame = firstBasicBlock.frame;
1574 firstFrame.setInputFrameFromDescriptor(symbolTable, accessFlags, descriptor, this.maxLocals);
1575 firstFrame.accept(this);
1576
1577 // Fix point algorithm: add the first basic block to a list of blocks to process (i.e. blocks
1578 // whose stack map frame has changed) and, while there are blocks to process, remove one from
1579 // the list and update the stack map frames of its successor blocks in the control flow graph
1580 // (which might change them, in which case these blocks must be processed too, and are thus
1581 // added to the list of blocks to process). Also compute the maximum stack size of the method,
1582 // as a by-product.
1583 Label listOfBlocksToProcess = firstBasicBlock;
1584 listOfBlocksToProcess.nextListElement = Label.EMPTY_LIST;
1585 int maxStackSize = 0;
1586 while (listOfBlocksToProcess != Label.EMPTY_LIST) {
1587 // Remove a basic block from the list of blocks to process.
1588 Label basicBlock = listOfBlocksToProcess;
1589 listOfBlocksToProcess = listOfBlocksToProcess.nextListElement;
1590 basicBlock.nextListElement = null;
1591 // By definition, basicBlock is reachable.
1592 basicBlock.flags |= Label.FLAG_REACHABLE;
1593 // Update the (absolute) maximum stack size.
1594 int maxBlockStackSize = basicBlock.frame.getInputStackSize() + basicBlock.outputStackMax;
1595 if (maxBlockStackSize > maxStackSize) {
1596 maxStackSize = maxBlockStackSize;
1597 }
1598 // Update the successor blocks of basicBlock in the control flow graph.
1599 Edge outgoingEdge = basicBlock.outgoingEdges;
1600 while (outgoingEdge != null) {
1601 Label successorBlock = outgoingEdge.successor.getCanonicalInstance();
1602 boolean successorBlockChanged =
1603 basicBlock.frame.merge(symbolTable, successorBlock.frame, outgoingEdge.info);
1604 if (successorBlockChanged && successorBlock.nextListElement == null) {
1605 // If successorBlock has changed it must be processed. Thus, if it is not already in the
1606 // list of blocks to process, add it to this list.
1607 successorBlock.nextListElement = listOfBlocksToProcess;
1608 listOfBlocksToProcess = successorBlock;
1609 }
1610 outgoingEdge = outgoingEdge.nextEdge;
1611 }
1612 }
1613
1614 // Loop over all the basic blocks and visit the stack map frames that must be stored in the
1615 // StackMapTable attribute. Also replace unreachable code with NOP* ATHROW, and remove it from
1616 // exception handler ranges.
1617 Label basicBlock = firstBasicBlock;
1618 while (basicBlock != null) {
1619 if ((basicBlock.flags & (Label.FLAG_JUMP_TARGET | Label.FLAG_REACHABLE))
1620 == (Label.FLAG_JUMP_TARGET | Label.FLAG_REACHABLE)) {
1621 basicBlock.frame.accept(this);
1622 }
1623 if ((basicBlock.flags & Label.FLAG_REACHABLE) == 0) {
1624 // Find the start and end bytecode offsets of this unreachable block.
1625 Label nextBasicBlock = basicBlock.nextBasicBlock;
1626 int startOffset = basicBlock.bytecodeOffset;
1627 int endOffset = (nextBasicBlock == null ? code.length : nextBasicBlock.bytecodeOffset) - 1;
1628 if (endOffset >= startOffset) {
1629 // Replace its instructions with NOP ... NOP ATHROW.
1630 for (int i = startOffset; i < endOffset; ++i) {
1631 code.data[i] = Opcodes.NOP;
1632 }
1633 code.data[endOffset] = (byte) Opcodes.ATHROW;
1634 // Emit a frame for this unreachable block, with no local and a Throwable on the stack
1635 // (so that the ATHROW could consume this Throwable if it were reachable).
1636 int frameIndex = visitFrameStart(startOffset, /* nLocal = */ 0, /* nStack = */ 1);
1637 currentFrame[frameIndex] =
1638 Frame.getAbstractTypeFromInternalName(symbolTable, "java/lang/Throwable");
1639 visitFrameEnd();
1640 // Remove this unreachable basic block from the exception handler ranges.
1641 firstHandler = Handler.removeRange(firstHandler, basicBlock, nextBasicBlock);
1642 // The maximum stack size is now at least one, because of the Throwable declared above.
1643 maxStackSize = Math.max(maxStackSize, 1);
1644 }
1645 }
1646 basicBlock = basicBlock.nextBasicBlock;
1647 }
1648
1649 this.maxStack = maxStackSize;
1650 }
1651
1652 /** Computes the maximum stack size of the method. */
1653 private void computeMaxStackAndLocal() {
1654 // Complete the control flow graph with exception handler blocks.
1655 Handler handler = firstHandler;
1656 while (handler != null) {
1657 Label handlerBlock = handler.handlerPc;
1658 Label handlerRangeBlock = handler.startPc;
1659 Label handlerRangeEnd = handler.endPc;
1660 // Add handlerBlock as a successor of all the basic blocks in the exception handler range.
1661 while (handlerRangeBlock != handlerRangeEnd) {
1662 if ((handlerRangeBlock.flags & Label.FLAG_SUBROUTINE_CALLER) == 0) {
1663 handlerRangeBlock.outgoingEdges =
1664 new Edge(Edge.EXCEPTION, handlerBlock, handlerRangeBlock.outgoingEdges);
1665 } else {
1666 // If handlerRangeBlock is a JSR block, add handlerBlock after the first two outgoing
1667 // edges to preserve the hypothesis about JSR block successors order (see
1668 // {@link #visitJumpInsn}).
1669 handlerRangeBlock.outgoingEdges.nextEdge.nextEdge =
1670 new Edge(
1671 Edge.EXCEPTION, handlerBlock, handlerRangeBlock.outgoingEdges.nextEdge.nextEdge);
1672 }
1673 handlerRangeBlock = handlerRangeBlock.nextBasicBlock;
1674 }
1675 handler = handler.nextHandler;
1676 }
1677
1678 // Complete the control flow graph with the successor blocks of subroutines, if needed.
1679 if (hasSubroutines) {
1680 // First step: find the subroutines. This step determines, for each basic block, to which
1681 // subroutine(s) it belongs. Start with the main "subroutine":
1682 short numSubroutines = 1;
1683 firstBasicBlock.markSubroutine(numSubroutines);
1684 // Then, mark the subroutines called by the main subroutine, then the subroutines called by
1685 // those called by the main subroutine, etc.
1686 for (short currentSubroutine = 1; currentSubroutine <= numSubroutines; ++currentSubroutine) {
1687 Label basicBlock = firstBasicBlock;
1688 while (basicBlock != null) {
1689 if ((basicBlock.flags & Label.FLAG_SUBROUTINE_CALLER) != 0
1690 && basicBlock.subroutineId == currentSubroutine) {
1691 Label jsrTarget = basicBlock.outgoingEdges.nextEdge.successor;
1692 if (jsrTarget.subroutineId == 0) {
1693 // If this subroutine has not been marked yet, find its basic blocks.
1694 jsrTarget.markSubroutine(++numSubroutines);
4781695 }
479 }
480 this.compute = computeFrames ? FRAMES : (computeMaxs ? MAXS : NOTHING);
481 if (computeMaxs || computeFrames) {
482 // updates maxLocals
483 int size = Type.getArgumentsAndReturnSizes(descriptor) >> 2;
484 if ((access & Opcodes.ACC_STATIC) != 0) {
485 --size;
486 }
487 maxLocals = size;
488 currentLocals = size;
489 // creates and visits the label for the first basic block
490 labels = new Label();
491 labels.status |= Label.PUSHED;
492 visitLabel(labels);
493 }
494 }
495
496 // ------------------------------------------------------------------------
497 // Implementation of the MethodVisitor abstract class
498 // ------------------------------------------------------------------------
499
500 @Override
501 public void visitParameter(String name, int access) {
502 if (methodParameters == null) {
503 methodParameters = new ByteVector();
504 }
505 ++methodParametersCount;
506 methodParameters.putShort((name == null) ? 0 : cw.newUTF8(name))
507 .putShort(access);
508 }
509
510 @Override
511 public AnnotationVisitor visitAnnotationDefault() {
512 if (!ClassReader.ANNOTATIONS) {
513 return null;
514 }
515 annd = new ByteVector();
516 return new AnnotationWriter(cw, false, annd, null, 0);
517 }
518
519 @Override
520 public AnnotationVisitor visitAnnotation(final String desc,
521 final boolean visible) {
522 if (!ClassReader.ANNOTATIONS) {
523 return null;
524 }
525 ByteVector bv = new ByteVector();
526 // write type, and reserve space for values count
527 bv.putShort(cw.newUTF8(desc)).putShort(0);
528 AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2);
529 if (visible) {
530 aw.next = anns;
531 anns = aw;
532 } else {
533 aw.next = ianns;
534 ianns = aw;
535 }
536 return aw;
537 }
538
539 @Override
540 public AnnotationVisitor visitTypeAnnotation(final int typeRef,
541 final TypePath typePath, final String desc, final boolean visible) {
542 if (!ClassReader.ANNOTATIONS) {
543 return null;
544 }
545 ByteVector bv = new ByteVector();
546 // write target_type and target_info
547 AnnotationWriter.putTarget(typeRef, typePath, bv);
548 // write type, and reserve space for values count
549 bv.putShort(cw.newUTF8(desc)).putShort(0);
550 AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv,
551 bv.length - 2);
552 if (visible) {
553 aw.next = tanns;
554 tanns = aw;
555 } else {
556 aw.next = itanns;
557 itanns = aw;
558 }
559 return aw;
560 }
561
562 @Override
563 public AnnotationVisitor visitParameterAnnotation(final int parameter,
564 final String desc, final boolean visible) {
565 if (!ClassReader.ANNOTATIONS) {
566 return null;
567 }
568 ByteVector bv = new ByteVector();
569 if ("Ljava/lang/Synthetic;".equals(desc)) {
570 // workaround for a bug in javac with synthetic parameters
571 // see ClassReader.readParameterAnnotations
572 synthetics = Math.max(synthetics, parameter + 1);
573 return new AnnotationWriter(cw, false, bv, null, 0);
574 }
575 // write type, and reserve space for values count
576 bv.putShort(cw.newUTF8(desc)).putShort(0);
577 AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2);
578 if (visible) {
579 if (panns == null) {
580 panns = new AnnotationWriter[Type.getArgumentTypes(descriptor).length];
581 }
582 aw.next = panns[parameter];
583 panns[parameter] = aw;
584 } else {
585 if (ipanns == null) {
586 ipanns = new AnnotationWriter[Type.getArgumentTypes(descriptor).length];
587 }
588 aw.next = ipanns[parameter];
589 ipanns[parameter] = aw;
590 }
591 return aw;
592 }
593
594 @Override
595 public void visitAttribute(final Attribute attr) {
596 if (attr.isCodeAttribute()) {
597 attr.next = cattrs;
598 cattrs = attr;
599 } else {
600 attr.next = attrs;
601 attrs = attr;
602 }
603 }
604
605 @Override
606 public void visitCode() {
607 }
608
609 @Override
610 public void visitFrame(final int type, final int nLocal,
611 final Object[] local, final int nStack, final Object[] stack) {
612 if (!ClassReader.FRAMES || compute == FRAMES) {
613 return;
614 }
615
616 if (type == Opcodes.F_NEW) {
617 if (previousFrame == null) {
618 visitImplicitFirstFrame();
619 }
620 currentLocals = nLocal;
621 int frameIndex = startFrame(code.length, nLocal, nStack);
622 for (int i = 0; i < nLocal; ++i) {
623 if (local[i] instanceof String) {
624 frame[frameIndex++] = Frame.OBJECT
625 | cw.addType((String) local[i]);
626 } else if (local[i] instanceof Integer) {
627 frame[frameIndex++] = ((Integer) local[i]).intValue();
628 } else {
629 frame[frameIndex++] = Frame.UNINITIALIZED
630 | cw.addUninitializedType("",
631 ((Label) local[i]).position);
632 }
633 }
634 for (int i = 0; i < nStack; ++i) {
635 if (stack[i] instanceof String) {
636 frame[frameIndex++] = Frame.OBJECT
637 | cw.addType((String) stack[i]);
638 } else if (stack[i] instanceof Integer) {
639 frame[frameIndex++] = ((Integer) stack[i]).intValue();
640 } else {
641 frame[frameIndex++] = Frame.UNINITIALIZED
642 | cw.addUninitializedType("",
643 ((Label) stack[i]).position);
644 }
645 }
646 endFrame();
647 } else {
648 int delta;
649 if (stackMap == null) {
650 stackMap = new ByteVector();
651 delta = code.length;
652 } else {
653 delta = code.length - previousFrameOffset - 1;
654 if (delta < 0) {
655 if (type == Opcodes.F_SAME) {
656 return;
657 } else {
658 throw new IllegalStateException();
659 }
660 }
661 }
662
663 switch (type) {
664 case Opcodes.F_FULL:
665 currentLocals = nLocal;
666 stackMap.putByte(FULL_FRAME).putShort(delta).putShort(nLocal);
667 for (int i = 0; i < nLocal; ++i) {
668 writeFrameType(local[i]);
669 }
670 stackMap.putShort(nStack);
671 for (int i = 0; i < nStack; ++i) {
672 writeFrameType(stack[i]);
673 }
674 break;
675 case Opcodes.F_APPEND:
676 currentLocals += nLocal;
677 stackMap.putByte(SAME_FRAME_EXTENDED + nLocal).putShort(delta);
678 for (int i = 0; i < nLocal; ++i) {
679 writeFrameType(local[i]);
680 }
681 break;
682 case Opcodes.F_CHOP:
683 currentLocals -= nLocal;
684 stackMap.putByte(SAME_FRAME_EXTENDED - nLocal).putShort(delta);
685 break;
686 case Opcodes.F_SAME:
687 if (delta < 64) {
688 stackMap.putByte(delta);
689 } else {
690 stackMap.putByte(SAME_FRAME_EXTENDED).putShort(delta);
691 }
692 break;
693 case Opcodes.F_SAME1:
694 if (delta < 64) {
695 stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME + delta);
696 } else {
697 stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED)
698 .putShort(delta);
699 }
700 writeFrameType(stack[0]);
701 break;
702 }
703
704 previousFrameOffset = code.length;
705 ++frameCount;
706 }
707
708 maxStack = Math.max(maxStack, nStack);
709 maxLocals = Math.max(maxLocals, currentLocals);
710 }
711
712 @Override
713 public void visitInsn(final int opcode) {
714 lastCodeOffset = code.length;
715 // adds the instruction to the bytecode of the method
716 code.putByte(opcode);
717 // update currentBlock
718 // Label currentBlock = this.currentBlock;
719 if (currentBlock != null) {
720 if (compute == FRAMES) {
721 currentBlock.frame.execute(opcode, 0, null, null);
722 } else {
723 // updates current and max stack sizes
724 int size = stackSize + Frame.SIZE[opcode];
725 if (size > maxStackSize) {
726 maxStackSize = size;
727 }
728 stackSize = size;
729 }
730 // if opcode == ATHROW or xRETURN, ends current block (no successor)
731 if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN)
732 || opcode == Opcodes.ATHROW) {
733 noSuccessor();
734 }
735 }
736 }
737
738 @Override
739 public void visitIntInsn(final int opcode, final int operand) {
740 lastCodeOffset = code.length;
741 // Label currentBlock = this.currentBlock;
742 if (currentBlock != null) {
743 if (compute == FRAMES) {
744 currentBlock.frame.execute(opcode, operand, null, null);
745 } else if (opcode != Opcodes.NEWARRAY) {
746 // updates current and max stack sizes only for NEWARRAY
747 // (stack size variation = 0 for BIPUSH or SIPUSH)
748 int size = stackSize + 1;
749 if (size > maxStackSize) {
750 maxStackSize = size;
751 }
752 stackSize = size;
753 }
754 }
755 // adds the instruction to the bytecode of the method
756 if (opcode == Opcodes.SIPUSH) {
757 code.put12(opcode, operand);
758 } else { // BIPUSH or NEWARRAY
759 code.put11(opcode, operand);
760 }
761 }
762
763 @Override
764 public void visitVarInsn(final int opcode, final int var) {
765 lastCodeOffset = code.length;
766 // Label currentBlock = this.currentBlock;
767 if (currentBlock != null) {
768 if (compute == FRAMES) {
769 currentBlock.frame.execute(opcode, var, null, null);
770 } else {
771 // updates current and max stack sizes
772 if (opcode == Opcodes.RET) {
773 // no stack change, but end of current block (no successor)
774 currentBlock.status |= Label.RET;
775 // save 'stackSize' here for future use
776 // (see {@link #findSubroutineSuccessors})
777 currentBlock.inputStackTop = stackSize;
778 noSuccessor();
779 } else { // xLOAD or xSTORE
780 int size = stackSize + Frame.SIZE[opcode];
781 if (size > maxStackSize) {
782 maxStackSize = size;
783 }
784 stackSize = size;
785 }
786 }
787 }
788 if (compute != NOTHING) {
789 // updates max locals
790 int n;
791 if (opcode == Opcodes.LLOAD || opcode == Opcodes.DLOAD
792 || opcode == Opcodes.LSTORE || opcode == Opcodes.DSTORE) {
793 n = var + 2;
794 } else {
795 n = var + 1;
796 }
797 if (n > maxLocals) {
798 maxLocals = n;
799 }
800 }
801 // adds the instruction to the bytecode of the method
802 if (var < 4 && opcode != Opcodes.RET) {
803 int opt;
804 if (opcode < Opcodes.ISTORE) {
805 /* ILOAD_0 */
806 opt = 26 + ((opcode - Opcodes.ILOAD) << 2) + var;
807 } else {
808 /* ISTORE_0 */
809 opt = 59 + ((opcode - Opcodes.ISTORE) << 2) + var;
810 }
811 code.putByte(opt);
812 } else if (var >= 256) {
813 code.putByte(196 /* WIDE */).put12(opcode, var);
814 } else {
815 code.put11(opcode, var);
816 }
817 if (opcode >= Opcodes.ISTORE && compute == FRAMES && handlerCount > 0) {
818 visitLabel(new Label());
819 }
820 }
821
822 @Override
823 public void visitTypeInsn(final int opcode, final String type) {
824 lastCodeOffset = code.length;
825 Item i = cw.newClassItem(type);
826 // Label currentBlock = this.currentBlock;
827 if (currentBlock != null) {
828 if (compute == FRAMES) {
829 currentBlock.frame.execute(opcode, code.length, cw, i);
830 } else if (opcode == Opcodes.NEW) {
831 // updates current and max stack sizes only if opcode == NEW
832 // (no stack change for ANEWARRAY, CHECKCAST, INSTANCEOF)
833 int size = stackSize + 1;
834 if (size > maxStackSize) {
835 maxStackSize = size;
836 }
837 stackSize = size;
838 }
839 }
840 // adds the instruction to the bytecode of the method
841 code.put12(opcode, i.index);
842 }
843
844 @Override
845 public void visitFieldInsn(final int opcode, final String owner,
846 final String name, final String desc) {
847 lastCodeOffset = code.length;
848 Item i = cw.newFieldItem(owner, name, desc);
849 // Label currentBlock = this.currentBlock;
850 if (currentBlock != null) {
851 if (compute == FRAMES) {
852 currentBlock.frame.execute(opcode, 0, cw, i);
853 } else {
854 int size;
855 // computes the stack size variation
856 char c = desc.charAt(0);
857 switch (opcode) {
858 case Opcodes.GETSTATIC:
859 size = stackSize + (c == 'D' || c == 'J' ? 2 : 1);
860 break;
861 case Opcodes.PUTSTATIC:
862 size = stackSize + (c == 'D' || c == 'J' ? -2 : -1);
863 break;
864 case Opcodes.GETFIELD:
865 size = stackSize + (c == 'D' || c == 'J' ? 1 : 0);
866 break;
867 // case Constants.PUTFIELD:
868 default:
869 size = stackSize + (c == 'D' || c == 'J' ? -3 : -2);
870 break;
871 }
872 // updates current and max stack sizes
873 if (size > maxStackSize) {
874 maxStackSize = size;
875 }
876 stackSize = size;
877 }
878 }
879 // adds the instruction to the bytecode of the method
880 code.put12(opcode, i.index);
881 }
882
883 @Override
884 public void visitMethodInsn(final int opcode, final String owner,
885 final String name, final String desc, final boolean itf) {
886 lastCodeOffset = code.length;
887 Item i = cw.newMethodItem(owner, name, desc, itf);
888 int argSize = i.intVal;
889 // Label currentBlock = this.currentBlock;
890 if (currentBlock != null) {
891 if (compute == FRAMES) {
892 currentBlock.frame.execute(opcode, 0, cw, i);
893 } else {
894 /*
895 * computes the stack size variation. In order not to recompute
896 * several times this variation for the same Item, we use the
897 * intVal field of this item to store this variation, once it
898 * has been computed. More precisely this intVal field stores
899 * the sizes of the arguments and of the return value
900 * corresponding to desc.
901 */
902 if (argSize == 0) {
903 // the above sizes have not been computed yet,
904 // so we compute them...
905 argSize = Type.getArgumentsAndReturnSizes(desc);
906 // ... and we save them in order
907 // not to recompute them in the future
908 i.intVal = argSize;
909 }
910 int size;
911 if (opcode == Opcodes.INVOKESTATIC) {
912 size = stackSize - (argSize >> 2) + (argSize & 0x03) + 1;
913 } else {
914 size = stackSize - (argSize >> 2) + (argSize & 0x03);
915 }
916 // updates current and max stack sizes
917 if (size > maxStackSize) {
918 maxStackSize = size;
919 }
920 stackSize = size;
921 }
922 }
923 // adds the instruction to the bytecode of the method
924 if (opcode == Opcodes.INVOKEINTERFACE) {
925 if (argSize == 0) {
926 argSize = Type.getArgumentsAndReturnSizes(desc);
927 i.intVal = argSize;
928 }
929 code.put12(Opcodes.INVOKEINTERFACE, i.index).put11(argSize >> 2, 0);
930 } else {
931 code.put12(opcode, i.index);
932 }
933 }
934
935 @Override
936 public void visitInvokeDynamicInsn(final String name, final String desc,
937 final Handle bsm, final Object... bsmArgs) {
938 lastCodeOffset = code.length;
939 Item i = cw.newInvokeDynamicItem(name, desc, bsm, bsmArgs);
940 int argSize = i.intVal;
941 // Label currentBlock = this.currentBlock;
942 if (currentBlock != null) {
943 if (compute == FRAMES) {
944 currentBlock.frame.execute(Opcodes.INVOKEDYNAMIC, 0, cw, i);
945 } else {
946 /*
947 * computes the stack size variation. In order not to recompute
948 * several times this variation for the same Item, we use the
949 * intVal field of this item to store this variation, once it
950 * has been computed. More precisely this intVal field stores
951 * the sizes of the arguments and of the return value
952 * corresponding to desc.
953 */
954 if (argSize == 0) {
955 // the above sizes have not been computed yet,
956 // so we compute them...
957 argSize = Type.getArgumentsAndReturnSizes(desc);
958 // ... and we save them in order
959 // not to recompute them in the future
960 i.intVal = argSize;
961 }
962 int size = stackSize - (argSize >> 2) + (argSize & 0x03) + 1;
963
964 // updates current and max stack sizes
965 if (size > maxStackSize) {
966 maxStackSize = size;
967 }
968 stackSize = size;
969 }
970 }
971 // adds the instruction to the bytecode of the method
972 code.put12(Opcodes.INVOKEDYNAMIC, i.index);
973 code.putShort(0);
974 }
975
976 @Override
977 public void visitJumpInsn(final int opcode, final Label label) {
978 lastCodeOffset = code.length;
979 Label nextInsn = null;
980 // Label currentBlock = this.currentBlock;
981 if (currentBlock != null) {
982 if (compute == FRAMES) {
983 currentBlock.frame.execute(opcode, 0, null, null);
984 // 'label' is the target of a jump instruction
985 label.getFirst().status |= Label.TARGET;
986 // adds 'label' as a successor of this basic block
987 addSuccessor(Edge.NORMAL, label);
988 if (opcode != Opcodes.GOTO) {
989 // creates a Label for the next basic block
990 nextInsn = new Label();
991 }
992 } else {
993 if (opcode == Opcodes.JSR) {
994 if ((label.status & Label.SUBROUTINE) == 0) {
995 label.status |= Label.SUBROUTINE;
996 ++subroutines;
997 }
998 currentBlock.status |= Label.JSR;
999 addSuccessor(stackSize + 1, label);
1000 // creates a Label for the next basic block
1001 nextInsn = new Label();
1002 /*
1003 * note that, by construction in this method, a JSR block
1004 * has at least two successors in the control flow graph:
1005 * the first one leads the next instruction after the JSR,
1006 * while the second one leads to the JSR target.
1007 */
1008 } else {
1009 // updates current stack size (max stack size unchanged
1010 // because stack size variation always negative in this
1011 // case)
1012 stackSize += Frame.SIZE[opcode];
1013 addSuccessor(stackSize, label);
1014 }
1015 }
1016 }
1017 // adds the instruction to the bytecode of the method
1018 if ((label.status & Label.RESOLVED) != 0
1019 && label.position - code.length < Short.MIN_VALUE) {
1020 /*
1021 * case of a backward jump with an offset < -32768. In this case we
1022 * automatically replace GOTO with GOTO_W, JSR with JSR_W and IFxxx
1023 * <l> with IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx is the
1024 * "opposite" opcode of IFxxx (i.e., IFNE for IFEQ) and where <l'>
1025 * designates the instruction just after the GOTO_W.
1026 */
1027 if (opcode == Opcodes.GOTO) {
1028 code.putByte(200); // GOTO_W
1029 } else if (opcode == Opcodes.JSR) {
1030 code.putByte(201); // JSR_W
1031 } else {
1032 // if the IF instruction is transformed into IFNOT GOTO_W the
1033 // next instruction becomes the target of the IFNOT instruction
1034 if (nextInsn != null) {
1035 nextInsn.status |= Label.TARGET;
1036 }
1037 code.putByte(opcode <= 166 ? ((opcode + 1) ^ 1) - 1
1038 : opcode ^ 1);
1039 code.putShort(8); // jump offset
1040 code.putByte(200); // GOTO_W
1041 }
1042 label.put(this, code, code.length - 1, true);
1043 } else {
1044 /*
1045 * case of a backward jump with an offset >= -32768, or of a forward
1046 * jump with, of course, an unknown offset. In these cases we store
1047 * the offset in 2 bytes (which will be increased in
1048 * resizeInstructions, if needed).
1049 */
1050 code.putByte(opcode);
1051 label.put(this, code, code.length - 1, false);
1052 }
1053 if (currentBlock != null) {
1054 if (nextInsn != null) {
1055 // if the jump instruction is not a GOTO, the next instruction
1056 // is also a successor of this instruction. Calling visitLabel
1057 // adds the label of this next instruction as a successor of the
1058 // current block, and starts a new basic block
1059 visitLabel(nextInsn);
1060 }
1061 if (opcode == Opcodes.GOTO) {
1062 noSuccessor();
1063 }
1064 }
1065 }
1066
1067 @Override
1068 public void visitLabel(final Label label) {
1069 // resolves previous forward references to label, if any
1070 resize |= label.resolve(this, code.length, code.data);
1071 // updates currentBlock
1072 if ((label.status & Label.DEBUG) != 0) {
1073 return;
1074 }
1075 if (compute == FRAMES) {
1076 if (currentBlock != null) {
1077 if (label.position == currentBlock.position) {
1078 // successive labels, do not start a new basic block
1079 currentBlock.status |= (label.status & Label.TARGET);
1080 label.frame = currentBlock.frame;
1081 return;
1082 }
1083 // ends current block (with one new successor)
1084 addSuccessor(Edge.NORMAL, label);
1085 }
1086 // begins a new current block
1087 currentBlock = label;
1088 if (label.frame == null) {
1089 label.frame = new Frame();
1090 label.frame.owner = label;
1091 }
1092 // updates the basic block list
1093 if (previousBlock != null) {
1094 if (label.position == previousBlock.position) {
1095 previousBlock.status |= (label.status & Label.TARGET);
1096 label.frame = previousBlock.frame;
1097 currentBlock = previousBlock;
1098 return;
1099 }
1100 previousBlock.successor = label;
1101 }
1102 previousBlock = label;
1103 } else if (compute == MAXS) {
1104 if (currentBlock != null) {
1105 // ends current block (with one new successor)
1106 currentBlock.outputStackMax = maxStackSize;
1107 addSuccessor(stackSize, label);
1108 }
1109 // begins a new current block
1110 currentBlock = label;
1111 // resets the relative current and max stack sizes
1112 stackSize = 0;
1113 maxStackSize = 0;
1114 // updates the basic block list
1115 if (previousBlock != null) {
1116 previousBlock.successor = label;
1117 }
1118 previousBlock = label;
1119 }
1120 }
1121
1122 @Override
1123 public void visitLdcInsn(final Object cst) {
1124 lastCodeOffset = code.length;
1125 Item i = cw.newConstItem(cst);
1126 // Label currentBlock = this.currentBlock;
1127 if (currentBlock != null) {
1128 if (compute == FRAMES) {
1129 currentBlock.frame.execute(Opcodes.LDC, 0, cw, i);
1130 } else {
1131 int size;
1132 // computes the stack size variation
1133 if (i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE) {
1134 size = stackSize + 2;
1135 } else {
1136 size = stackSize + 1;
1137 }
1138 // updates current and max stack sizes
1139 if (size > maxStackSize) {
1140 maxStackSize = size;
1141 }
1142 stackSize = size;
1143 }
1144 }
1145 // adds the instruction to the bytecode of the method
1146 int index = i.index;
1147 if (i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE) {
1148 code.put12(20 /* LDC2_W */, index);
1149 } else if (index >= 256) {
1150 code.put12(19 /* LDC_W */, index);
1151 } else {
1152 code.put11(Opcodes.LDC, index);
1153 }
1154 }
1155
1156 @Override
1157 public void visitIincInsn(final int var, final int increment) {
1158 lastCodeOffset = code.length;
1159 if (currentBlock != null) {
1160 if (compute == FRAMES) {
1161 currentBlock.frame.execute(Opcodes.IINC, var, null, null);
1162 }
1163 }
1164 if (compute != NOTHING) {
1165 // updates max locals
1166 int n = var + 1;
1167 if (n > maxLocals) {
1168 maxLocals = n;
1169 }
1170 }
1171 // adds the instruction to the bytecode of the method
1172 if ((var > 255) || (increment > 127) || (increment < -128)) {
1173 code.putByte(196 /* WIDE */).put12(Opcodes.IINC, var)
1174 .putShort(increment);
1175 } else {
1176 code.putByte(Opcodes.IINC).put11(var, increment);
1177 }
1178 }
1179
1180 @Override
1181 public void visitTableSwitchInsn(final int min, final int max,
1182 final Label dflt, final Label... labels) {
1183 lastCodeOffset = code.length;
1184 // adds the instruction to the bytecode of the method
1185 int source = code.length;
1186 code.putByte(Opcodes.TABLESWITCH);
1187 code.putByteArray(null, 0, (4 - code.length % 4) % 4);
1188 dflt.put(this, code, source, true);
1189 code.putInt(min).putInt(max);
1190 for (int i = 0; i < labels.length; ++i) {
1191 labels[i].put(this, code, source, true);
1192 }
1193 // updates currentBlock
1194 visitSwitchInsn(dflt, labels);
1195 }
1196
1197 @Override
1198 public void visitLookupSwitchInsn(final Label dflt, final int[] keys,
1199 final Label[] labels) {
1200 lastCodeOffset = code.length;
1201 // adds the instruction to the bytecode of the method
1202 int source = code.length;
1203 code.putByte(Opcodes.LOOKUPSWITCH);
1204 code.putByteArray(null, 0, (4 - code.length % 4) % 4);
1205 dflt.put(this, code, source, true);
1206 code.putInt(labels.length);
1207 for (int i = 0; i < labels.length; ++i) {
1208 code.putInt(keys[i]);
1209 labels[i].put(this, code, source, true);
1210 }
1211 // updates currentBlock
1212 visitSwitchInsn(dflt, labels);
1213 }
1214
1215 private void visitSwitchInsn(final Label dflt, final Label[] labels) {
1216 // Label currentBlock = this.currentBlock;
1217 if (currentBlock != null) {
1218 if (compute == FRAMES) {
1219 currentBlock.frame.execute(Opcodes.LOOKUPSWITCH, 0, null, null);
1220 // adds current block successors
1221 addSuccessor(Edge.NORMAL, dflt);
1222 dflt.getFirst().status |= Label.TARGET;
1223 for (int i = 0; i < labels.length; ++i) {
1224 addSuccessor(Edge.NORMAL, labels[i]);
1225 labels[i].getFirst().status |= Label.TARGET;
1226 }
1227 } else {
1228 // updates current stack size (max stack size unchanged)
1229 --stackSize;
1230 // adds current block successors
1231 addSuccessor(stackSize, dflt);
1232 for (int i = 0; i < labels.length; ++i) {
1233 addSuccessor(stackSize, labels[i]);
1234 }
1235 }
1236 // ends current block
1237 noSuccessor();
1238 }
1239 }
1240
1241 @Override
1242 public void visitMultiANewArrayInsn(final String desc, final int dims) {
1243 lastCodeOffset = code.length;
1244 Item i = cw.newClassItem(desc);
1245 // Label currentBlock = this.currentBlock;
1246 if (currentBlock != null) {
1247 if (compute == FRAMES) {
1248 currentBlock.frame.execute(Opcodes.MULTIANEWARRAY, dims, cw, i);
1249 } else {
1250 // updates current stack size (max stack size unchanged because
1251 // stack size variation always negative or null)
1252 stackSize += 1 - dims;
1253 }
1254 }
1255 // adds the instruction to the bytecode of the method
1256 code.put12(Opcodes.MULTIANEWARRAY, i.index).putByte(dims);
1257 }
1258
1259 @Override
1260 public AnnotationVisitor visitInsnAnnotation(int typeRef,
1261 TypePath typePath, String desc, boolean visible) {
1262 if (!ClassReader.ANNOTATIONS) {
1263 return null;
1264 }
1265 ByteVector bv = new ByteVector();
1266 // write target_type and target_info
1267 typeRef = (typeRef & 0xFF0000FF) | (lastCodeOffset << 8);
1268 AnnotationWriter.putTarget(typeRef, typePath, bv);
1269 // write type, and reserve space for values count
1270 bv.putShort(cw.newUTF8(desc)).putShort(0);
1271 AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv,
1272 bv.length - 2);
1273 if (visible) {
1274 aw.next = ctanns;
1275 ctanns = aw;
1276 } else {
1277 aw.next = ictanns;
1278 ictanns = aw;
1279 }
1280 return aw;
1281 }
1282
1283 @Override
1284 public void visitTryCatchBlock(final Label start, final Label end,
1285 final Label handler, final String type) {
1286 ++handlerCount;
1287 Handler h = new Handler();
1288 h.start = start;
1289 h.end = end;
1290 h.handler = handler;
1291 h.desc = type;
1292 h.type = type != null ? cw.newClass(type) : 0;
1293 if (lastHandler == null) {
1294 firstHandler = h;
1295 } else {
1296 lastHandler.next = h;
1297 }
1298 lastHandler = h;
1299 }
1300
1301 @Override
1302 public AnnotationVisitor visitTryCatchAnnotation(int typeRef,
1303 TypePath typePath, String desc, boolean visible) {
1304 if (!ClassReader.ANNOTATIONS) {
1305 return null;
1306 }
1307 ByteVector bv = new ByteVector();
1308 // write target_type and target_info
1309 AnnotationWriter.putTarget(typeRef, typePath, bv);
1310 // write type, and reserve space for values count
1311 bv.putShort(cw.newUTF8(desc)).putShort(0);
1312 AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv,
1313 bv.length - 2);
1314 if (visible) {
1315 aw.next = ctanns;
1316 ctanns = aw;
1317 } else {
1318 aw.next = ictanns;
1319 ictanns = aw;
1320 }
1321 return aw;
1322 }
1323
1324 @Override
1325 public void visitLocalVariable(final String name, final String desc,
1326 final String signature, final Label start, final Label end,
1327 final int index) {
1328 if (signature != null) {
1329 if (localVarType == null) {
1330 localVarType = new ByteVector();
1331 }
1332 ++localVarTypeCount;
1333 localVarType.putShort(start.position)
1334 .putShort(end.position - start.position)
1335 .putShort(cw.newUTF8(name)).putShort(cw.newUTF8(signature))
1336 .putShort(index);
1337 }
1338 if (localVar == null) {
1339 localVar = new ByteVector();
1340 }
1341 ++localVarCount;
1342 localVar.putShort(start.position)
1343 .putShort(end.position - start.position)
1344 .putShort(cw.newUTF8(name)).putShort(cw.newUTF8(desc))
1345 .putShort(index);
1346 if (compute != NOTHING) {
1347 // updates max locals
1348 char c = desc.charAt(0);
1349 int n = index + (c == 'J' || c == 'D' ? 2 : 1);
1350 if (n > maxLocals) {
1351 maxLocals = n;
1352 }
1353 }
1354 }
1355
1356 @Override
1357 public AnnotationVisitor visitLocalVariableAnnotation(int typeRef,
1358 TypePath typePath, Label[] start, Label[] end, int[] index,
1359 String desc, boolean visible) {
1360 if (!ClassReader.ANNOTATIONS) {
1361 return null;
1362 }
1363 ByteVector bv = new ByteVector();
1364 // write target_type and target_info
1365 bv.putByte(typeRef >>> 24).putShort(start.length);
1366 for (int i = 0; i < start.length; ++i) {
1367 bv.putShort(start[i].position)
1368 .putShort(end[i].position - start[i].position)
1369 .putShort(index[i]);
1370 }
1371 if (typePath == null) {
1372 bv.putByte(0);
1373 } else {
1374 int length = typePath.b[typePath.offset] * 2 + 1;
1375 bv.putByteArray(typePath.b, typePath.offset, length);
1376 }
1377 // write type, and reserve space for values count
1378 bv.putShort(cw.newUTF8(desc)).putShort(0);
1379 AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv,
1380 bv.length - 2);
1381 if (visible) {
1382 aw.next = ctanns;
1383 ctanns = aw;
1384 } else {
1385 aw.next = ictanns;
1386 ictanns = aw;
1387 }
1388 return aw;
1389 }
1390
1391 @Override
1392 public void visitLineNumber(final int line, final Label start) {
1393 if (lineNumber == null) {
1394 lineNumber = new ByteVector();
1395 }
1396 ++lineNumberCount;
1397 lineNumber.putShort(start.position);
1398 lineNumber.putShort(line);
1399 }
1400
1401 @Override
1402 public void visitMaxs(final int maxStack, final int maxLocals) {
1403 if (resize) {
1404 // replaces the temporary jump opcodes introduced by Label.resolve.
1405 if (ClassReader.RESIZE) {
1406 resizeInstructions();
1407 } else {
1408 throw new RuntimeException("Method code too large!");
1409 }
1410 }
1411 if (ClassReader.FRAMES && compute == FRAMES) {
1412 // completes the control flow graph with exception handler blocks
1413 Handler handler = firstHandler;
1414 while (handler != null) {
1415 Label l = handler.start.getFirst();
1416 Label h = handler.handler.getFirst();
1417 Label e = handler.end.getFirst();
1418 // computes the kind of the edges to 'h'
1419 String t = handler.desc == null ? "java/lang/Throwable"
1420 : handler.desc;
1421 int kind = Frame.OBJECT | cw.addType(t);
1422 // h is an exception handler
1423 h.status |= Label.TARGET;
1424 // adds 'h' as a successor of labels between 'start' and 'end'
1425 while (l != e) {
1426 // creates an edge to 'h'
1427 Edge b = new Edge();
1428 b.info = kind;
1429 b.successor = h;
1430 // adds it to the successors of 'l'
1431 b.next = l.successors;
1432 l.successors = b;
1433 // goes to the next label
1434 l = l.successor;
1435 }
1436 handler = handler.next;
1437 }
1438
1439 // creates and visits the first (implicit) frame
1440 Frame f = labels.frame;
1441 Type[] args = Type.getArgumentTypes(descriptor);
1442 f.initInputFrame(cw, access, args, this.maxLocals);
1443 visitFrame(f);
1444
1445 /*
1446 * fix point algorithm: mark the first basic block as 'changed'
1447 * (i.e. put it in the 'changed' list) and, while there are changed
1448 * basic blocks, choose one, mark it as unchanged, and update its
1449 * successors (which can be changed in the process).
1450 */
1451 int max = 0;
1452 Label changed = labels;
1453 while (changed != null) {
1454 // removes a basic block from the list of changed basic blocks
1455 Label l = changed;
1456 changed = changed.next;
1457 l.next = null;
1458 f = l.frame;
1459 // a reachable jump target must be stored in the stack map
1460 if ((l.status & Label.TARGET) != 0) {
1461 l.status |= Label.STORE;
1462 }
1463 // all visited labels are reachable, by definition
1464 l.status |= Label.REACHABLE;
1465 // updates the (absolute) maximum stack size
1466 int blockMax = f.inputStack.length + l.outputStackMax;
1467 if (blockMax > max) {
1468 max = blockMax;
1469 }
1470 // updates the successors of the current basic block
1471 Edge e = l.successors;
1472 while (e != null) {
1473 Label n = e.successor.getFirst();
1474 boolean change = f.merge(cw, n.frame, e.info);
1475 if (change && n.next == null) {
1476 // if n has changed and is not already in the 'changed'
1477 // list, adds it to this list
1478 n.next = changed;
1479 changed = n;
1480 }
1481 e = e.next;
1482 }
1483 }
1484
1485 // visits all the frames that must be stored in the stack map
1486 Label l = labels;
1487 while (l != null) {
1488 f = l.frame;
1489 if ((l.status & Label.STORE) != 0) {
1490 visitFrame(f);
1491 }
1492 if ((l.status & Label.REACHABLE) == 0) {
1493 // finds start and end of dead basic block
1494 Label k = l.successor;
1495 int start = l.position;
1496 int end = (k == null ? code.length : k.position) - 1;
1497 // if non empty basic block
1498 if (end >= start) {
1499 max = Math.max(max, 1);
1500 // replaces instructions with NOP ... NOP ATHROW
1501 for (int i = start; i < end; ++i) {
1502 code.data[i] = Opcodes.NOP;
1503 }
1504 code.data[end] = (byte) Opcodes.ATHROW;
1505 // emits a frame for this unreachable block
1506 int frameIndex = startFrame(start, 0, 1);
1507 frame[frameIndex] = Frame.OBJECT
1508 | cw.addType("java/lang/Throwable");
1509 endFrame();
1510 // removes the start-end range from the exception
1511 // handlers
1512 firstHandler = Handler.remove(firstHandler, l, k);
1513 }
1514 }
1515 l = l.successor;
1516 }
1517
1518 handler = firstHandler;
1519 handlerCount = 0;
1520 while (handler != null) {
1521 handlerCount += 1;
1522 handler = handler.next;
1523 }
1524
1525 this.maxStack = max;
1526 } else if (compute == MAXS) {
1527 // completes the control flow graph with exception handler blocks
1528 Handler handler = firstHandler;
1529 while (handler != null) {
1530 Label l = handler.start;
1531 Label h = handler.handler;
1532 Label e = handler.end;
1533 // adds 'h' as a successor of labels between 'start' and 'end'
1534 while (l != e) {
1535 // creates an edge to 'h'
1536 Edge b = new Edge();
1537 b.info = Edge.EXCEPTION;
1538 b.successor = h;
1539 // adds it to the successors of 'l'
1540 if ((l.status & Label.JSR) == 0) {
1541 b.next = l.successors;
1542 l.successors = b;
1543 } else {
1544 // if l is a JSR block, adds b after the first two edges
1545 // to preserve the hypothesis about JSR block successors
1546 // order (see {@link #visitJumpInsn})
1547 b.next = l.successors.next.next;
1548 l.successors.next.next = b;
1549 }
1550 // goes to the next label
1551 l = l.successor;
1552 }
1553 handler = handler.next;
1554 }
1555
1556 if (subroutines > 0) {
1557 // completes the control flow graph with the RET successors
1558 /*
1559 * first step: finds the subroutines. This step determines, for
1560 * each basic block, to which subroutine(s) it belongs.
1561 */
1562 // finds the basic blocks that belong to the "main" subroutine
1563 int id = 0;
1564 labels.visitSubroutine(null, 1, subroutines);
1565 // finds the basic blocks that belong to the real subroutines
1566 Label l = labels;
1567 while (l != null) {
1568 if ((l.status & Label.JSR) != 0) {
1569 // the subroutine is defined by l's TARGET, not by l
1570 Label subroutine = l.successors.next.successor;
1571 // if this subroutine has not been visited yet...
1572 if ((subroutine.status & Label.VISITED) == 0) {
1573 // ...assigns it a new id and finds its basic blocks
1574 id += 1;
1575 subroutine.visitSubroutine(null, (id / 32L) << 32
1576 | (1L << (id % 32)), subroutines);
1577 }
1578 }
1579 l = l.successor;
1580 }
1581 // second step: finds the successors of RET blocks
1582 l = labels;
1583 while (l != null) {
1584 if ((l.status & Label.JSR) != 0) {
1585 Label L = labels;
1586 while (L != null) {
1587 L.status &= ~Label.VISITED2;
1588 L = L.successor;
1589 }
1590 // the subroutine is defined by l's TARGET, not by l
1591 Label subroutine = l.successors.next.successor;
1592 subroutine.visitSubroutine(l, 0, subroutines);
1593 }
1594 l = l.successor;
1595 }
1596 }
1597
1598 /*
1599 * control flow analysis algorithm: while the block stack is not
1600 * empty, pop a block from this stack, update the max stack size,
1601 * compute the true (non relative) begin stack size of the
1602 * successors of this block, and push these successors onto the
1603 * stack (unless they have already been pushed onto the stack).
1604 * Note: by hypothesis, the {@link Label#inputStackTop} of the
1605 * blocks in the block stack are the true (non relative) beginning
1606 * stack sizes of these blocks.
1607 */
1608 int max = 0;
1609 Label stack = labels;
1610 while (stack != null) {
1611 // pops a block from the stack
1612 Label l = stack;
1613 stack = stack.next;
1614 // computes the true (non relative) max stack size of this block
1615 int start = l.inputStackTop;
1616 int blockMax = start + l.outputStackMax;
1617 // updates the global max stack size
1618 if (blockMax > max) {
1619 max = blockMax;
1620 }
1621 // analyzes the successors of the block
1622 Edge b = l.successors;
1623 if ((l.status & Label.JSR) != 0) {
1624 // ignores the first edge of JSR blocks (virtual successor)
1625 b = b.next;
1626 }
1627 while (b != null) {
1628 l = b.successor;
1629 // if this successor has not already been pushed...
1630 if ((l.status & Label.PUSHED) == 0) {
1631 // computes its true beginning stack size...
1632 l.inputStackTop = b.info == Edge.EXCEPTION ? 1 : start
1633 + b.info;
1634 // ...and pushes it onto the stack
1635 l.status |= Label.PUSHED;
1636 l.next = stack;
1637 stack = l;
1638 }
1639 b = b.next;
1640 }
1641 }
1642 this.maxStack = Math.max(maxStack, max);
1643 } else {
1644 this.maxStack = maxStack;
1645 this.maxLocals = maxLocals;
1646 }
1647 }
1648
1649 @Override
1650 public void visitEnd() {
1651 }
1652
1653 // ------------------------------------------------------------------------
1654 // Utility methods: control flow analysis algorithm
1655 // ------------------------------------------------------------------------
1656
1657 /**
1658 * Adds a successor to the {@link #currentBlock currentBlock} block.
1659 *
1660 * @param info
1661 * information about the control flow edge to be added.
1662 * @param successor
1663 * the successor block to be added to the current block.
1664 */
1665 private void addSuccessor(final int info, final Label successor) {
1666 // creates and initializes an Edge object...
1667 Edge b = new Edge();
1668 b.info = info;
1669 b.successor = successor;
1670 // ...and adds it to the successor list of the currentBlock block
1671 b.next = currentBlock.successors;
1672 currentBlock.successors = b;
1673 }
1674
1675 /**
1676 * Ends the current basic block. This method must be used in the case where
1677 * the current basic block does not have any successor.
1678 */
1679 private void noSuccessor() {
1680 if (compute == FRAMES) {
1681 Label l = new Label();
1682 l.frame = new Frame();
1683 l.frame.owner = l;
1684 l.resolve(this, code.length, code.data);
1685 previousBlock.successor = l;
1686 previousBlock = l;
1687 } else {
1688 currentBlock.outputStackMax = maxStackSize;
1689 }
1690 currentBlock = null;
1691 }
1692
1693 // ------------------------------------------------------------------------
1694 // Utility methods: stack map frames
1695 // ------------------------------------------------------------------------
1696
1697 /**
1698 * Visits a frame that has been computed from scratch.
1699 *
1700 * @param f
1701 * the frame that must be visited.
1702 */
1703 private void visitFrame(final Frame f) {
1704 int i, t;
1705 int nTop = 0;
1706 int nLocal = 0;
1707 int nStack = 0;
1708 int[] locals = f.inputLocals;
1709 int[] stacks = f.inputStack;
1710 // computes the number of locals (ignores TOP types that are just after
1711 // a LONG or a DOUBLE, and all trailing TOP types)
1712 for (i = 0; i < locals.length; ++i) {
1713 t = locals[i];
1714 if (t == Frame.TOP) {
1715 ++nTop;
1716 } else {
1717 nLocal += nTop + 1;
1718 nTop = 0;
1719 }
1720 if (t == Frame.LONG || t == Frame.DOUBLE) {
1721 ++i;
1722 }
1723 }
1724 // computes the stack size (ignores TOP types that are just after
1725 // a LONG or a DOUBLE)
1726 for (i = 0; i < stacks.length; ++i) {
1727 t = stacks[i];
1728 ++nStack;
1729 if (t == Frame.LONG || t == Frame.DOUBLE) {
1730 ++i;
1731 }
1732 }
1733 // visits the frame and its content
1734 int frameIndex = startFrame(f.owner.position, nLocal, nStack);
1735 for (i = 0; nLocal > 0; ++i, --nLocal) {
1736 t = locals[i];
1737 frame[frameIndex++] = t;
1738 if (t == Frame.LONG || t == Frame.DOUBLE) {
1739 ++i;
1740 }
1741 }
1742 for (i = 0; i < stacks.length; ++i) {
1743 t = stacks[i];
1744 frame[frameIndex++] = t;
1745 if (t == Frame.LONG || t == Frame.DOUBLE) {
1746 ++i;
1747 }
1748 }
1749 endFrame();
1750 }
1751
1752 /**
1753 * Visit the implicit first frame of this method.
1754 */
1755 private void visitImplicitFirstFrame() {
1756 // There can be at most descriptor.length() + 1 locals
1757 int frameIndex = startFrame(0, descriptor.length() + 1, 0);
1758 if ((access & Opcodes.ACC_STATIC) == 0) {
1759 if ((access & ACC_CONSTRUCTOR) == 0) {
1760 frame[frameIndex++] = Frame.OBJECT | cw.addType(cw.thisName);
1761 } else {
1762 frame[frameIndex++] = 6; // Opcodes.UNINITIALIZED_THIS;
1763 }
1764 }
1765 int i = 1;
1766 loop: while (true) {
1767 int j = i;
1768 switch (descriptor.charAt(i++)) {
1769 case 'Z':
1770 case 'C':
1771 case 'B':
1772 case 'S':
1773 case 'I':
1774 frame[frameIndex++] = 1; // Opcodes.INTEGER;
1775 break;
1776 case 'F':
1777 frame[frameIndex++] = 2; // Opcodes.FLOAT;
1778 break;
1779 case 'J':
1780 frame[frameIndex++] = 4; // Opcodes.LONG;
1781 break;
1782 case 'D':
1783 frame[frameIndex++] = 3; // Opcodes.DOUBLE;
1784 break;
1785 case '[':
1786 while (descriptor.charAt(i) == '[') {
1787 ++i;
1788 }
1789 if (descriptor.charAt(i) == 'L') {
1790 ++i;
1791 while (descriptor.charAt(i) != ';') {
1792 ++i;
1793 }
1794 }
1795 frame[frameIndex++] = Frame.OBJECT
1796 | cw.addType(descriptor.substring(j, ++i));
1797 break;
1798 case 'L':
1799 while (descriptor.charAt(i) != ';') {
1800 ++i;
1801 }
1802 frame[frameIndex++] = Frame.OBJECT
1803 | cw.addType(descriptor.substring(j + 1, i++));
1804 break;
1805 default:
1806 break loop;
1807 }
1808 }
1809 frame[1] = frameIndex - 3;
1810 endFrame();
1811 }
1812
1813 /**
1814 * Starts the visit of a stack map frame.
1815 *
1816 * @param offset
1817 * the offset of the instruction to which the frame corresponds.
1818 * @param nLocal
1819 * the number of local variables in the frame.
1820 * @param nStack
1821 * the number of stack elements in the frame.
1822 * @return the index of the next element to be written in this frame.
1823 */
1824 private int startFrame(final int offset, final int nLocal, final int nStack) {
1825 int n = 3 + nLocal + nStack;
1826 if (frame == null || frame.length < n) {
1827 frame = new int[n];
1828 }
1829 frame[0] = offset;
1830 frame[1] = nLocal;
1831 frame[2] = nStack;
1832 return 3;
1833 }
1834
1835 /**
1836 * Checks if the visit of the current frame {@link #frame} is finished, and
1837 * if yes, write it in the StackMapTable attribute.
1838 */
1839 private void endFrame() {
1840 if (previousFrame != null) { // do not write the first frame
1841 if (stackMap == null) {
1842 stackMap = new ByteVector();
1843 }
1844 writeFrame();
1845 ++frameCount;
1846 }
1847 previousFrame = frame;
1848 frame = null;
1849 }
1850
1851 /**
1852 * Compress and writes the current frame {@link #frame} in the StackMapTable
1853 * attribute.
1854 */
1855 private void writeFrame() {
1856 int clocalsSize = frame[1];
1857 int cstackSize = frame[2];
1858 if ((cw.version & 0xFFFF) < Opcodes.V1_6) {
1859 stackMap.putShort(frame[0]).putShort(clocalsSize);
1860 writeFrameTypes(3, 3 + clocalsSize);
1861 stackMap.putShort(cstackSize);
1862 writeFrameTypes(3 + clocalsSize, 3 + clocalsSize + cstackSize);
1863 return;
1864 }
1865 int localsSize = previousFrame[1];
1866 int type = FULL_FRAME;
1867 int k = 0;
1868 int delta;
1869 if (frameCount == 0) {
1870 delta = frame[0];
1871 } else {
1872 delta = frame[0] - previousFrame[0] - 1;
1873 }
1874 if (cstackSize == 0) {
1875 k = clocalsSize - localsSize;
1876 switch (k) {
1877 case -3:
1878 case -2:
1879 case -1:
1880 type = CHOP_FRAME;
1881 localsSize = clocalsSize;
1882 break;
1883 case 0:
1884 type = delta < 64 ? SAME_FRAME : SAME_FRAME_EXTENDED;
1885 break;
1886 case 1:
1887 case 2:
1888 case 3:
1889 type = APPEND_FRAME;
1890 break;
1891 }
1892 } else if (clocalsSize == localsSize && cstackSize == 1) {
1893 type = delta < 63 ? SAME_LOCALS_1_STACK_ITEM_FRAME
1894 : SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED;
1895 }
1896 if (type != FULL_FRAME) {
1897 // verify if locals are the same
1898 int l = 3;
1899 for (int j = 0; j < localsSize; j++) {
1900 if (frame[l] != previousFrame[l]) {
1901 type = FULL_FRAME;
1902 break;
1903 }
1904 l++;
1905 }
1906 }
1907 switch (type) {
1908 case SAME_FRAME:
1909 stackMap.putByte(delta);
1910 break;
1911 case SAME_LOCALS_1_STACK_ITEM_FRAME:
1912 stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME + delta);
1913 writeFrameTypes(3 + clocalsSize, 4 + clocalsSize);
1914 break;
1915 case SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED:
1916 stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED).putShort(
1917 delta);
1918 writeFrameTypes(3 + clocalsSize, 4 + clocalsSize);
1919 break;
1920 case SAME_FRAME_EXTENDED:
1921 stackMap.putByte(SAME_FRAME_EXTENDED).putShort(delta);
1922 break;
1923 case CHOP_FRAME:
1924 stackMap.putByte(SAME_FRAME_EXTENDED + k).putShort(delta);
1925 break;
1926 case APPEND_FRAME:
1927 stackMap.putByte(SAME_FRAME_EXTENDED + k).putShort(delta);
1928 writeFrameTypes(3 + localsSize, 3 + clocalsSize);
1929 break;
1930 // case FULL_FRAME:
1696 }
1697 basicBlock = basicBlock.nextBasicBlock;
1698 }
1699 }
1700 // Second step: find the successors in the control flow graph of each subroutine basic block
1701 // 'r' ending with a RET instruction. These successors are the virtual successors of the basic
1702 // blocks ending with JSR instructions (see {@link #visitJumpInsn)} that can reach 'r'.
1703 Label basicBlock = firstBasicBlock;
1704 while (basicBlock != null) {
1705 if ((basicBlock.flags & Label.FLAG_SUBROUTINE_CALLER) != 0) {
1706 // By construction, jsr targets are stored in the second outgoing edge of basic blocks
1707 // that ends with a jsr instruction (see {@link #FLAG_SUBROUTINE_CALLER}).
1708 Label subroutine = basicBlock.outgoingEdges.nextEdge.successor;
1709 subroutine.addSubroutineRetSuccessors(basicBlock);
1710 }
1711 basicBlock = basicBlock.nextBasicBlock;
1712 }
1713 }
1714
1715 // Data flow algorithm: put the first basic block in a list of blocks to process (i.e. blocks
1716 // whose input stack size has changed) and, while there are blocks to process, remove one
1717 // from the list, update the input stack size of its successor blocks in the control flow
1718 // graph, and add these blocks to the list of blocks to process (if not already done).
1719 Label listOfBlocksToProcess = firstBasicBlock;
1720 listOfBlocksToProcess.nextListElement = Label.EMPTY_LIST;
1721 int maxStackSize = maxStack;
1722 while (listOfBlocksToProcess != Label.EMPTY_LIST) {
1723 // Remove a basic block from the list of blocks to process. Note that we don't reset
1724 // basicBlock.nextListElement to null on purpose, to make sure we don't reprocess already
1725 // processed basic blocks.
1726 Label basicBlock = listOfBlocksToProcess;
1727 listOfBlocksToProcess = listOfBlocksToProcess.nextListElement;
1728 // Compute the (absolute) input stack size and maximum stack size of this block.
1729 int inputStackTop = basicBlock.inputStackSize;
1730 int maxBlockStackSize = inputStackTop + basicBlock.outputStackMax;
1731 // Update the absolute maximum stack size of the method.
1732 if (maxBlockStackSize > maxStackSize) {
1733 maxStackSize = maxBlockStackSize;
1734 }
1735 // Update the input stack size of the successor blocks of basicBlock in the control flow
1736 // graph, and add these blocks to the list of blocks to process, if not already done.
1737 Edge outgoingEdge = basicBlock.outgoingEdges;
1738 if ((basicBlock.flags & Label.FLAG_SUBROUTINE_CALLER) != 0) {
1739 // Ignore the first outgoing edge of the basic blocks ending with a jsr: these are virtual
1740 // edges which lead to the instruction just after the jsr, and do not correspond to a
1741 // possible execution path (see {@link #visitJumpInsn} and
1742 // {@link Label#FLAG_SUBROUTINE_CALLER}).
1743 outgoingEdge = outgoingEdge.nextEdge;
1744 }
1745 while (outgoingEdge != null) {
1746 Label successorBlock = outgoingEdge.successor;
1747 if (successorBlock.nextListElement == null) {
1748 successorBlock.inputStackSize =
1749 (short) (outgoingEdge.info == Edge.EXCEPTION ? 1 : inputStackTop + outgoingEdge.info);
1750 successorBlock.nextListElement = listOfBlocksToProcess;
1751 listOfBlocksToProcess = successorBlock;
1752 }
1753 outgoingEdge = outgoingEdge.nextEdge;
1754 }
1755 }
1756 this.maxStack = maxStackSize;
1757 }
1758
1759 @Override
1760 public void visitEnd() {
1761 // Nothing to do.
1762 }
1763
1764 // -----------------------------------------------------------------------------------------------
1765 // Utility methods: control flow analysis algorithm
1766 // -----------------------------------------------------------------------------------------------
1767
1768 /**
1769 * Adds a successor to {@link #currentBasicBlock} in the control flow graph.
1770 *
1771 * @param info information about the control flow edge to be added.
1772 * @param successor the successor block to be added to the current basic block.
1773 */
1774 private void addSuccessorToCurrentBasicBlock(final int info, final Label successor) {
1775 currentBasicBlock.outgoingEdges = new Edge(info, successor, currentBasicBlock.outgoingEdges);
1776 }
1777
1778 /**
1779 * Ends the current basic block. This method must be used in the case where the current basic
1780 * block does not have any successor.
1781 *
1782 * <p>WARNING: this method must be called after the currently visited instruction has been put in
1783 * {@link #code} (if frames are computed, this method inserts a new Label to start a new basic
1784 * block after the current instruction).
1785 */
1786 private void endCurrentBasicBlockWithNoSuccessor() {
1787 if (compute == COMPUTE_ALL_FRAMES) {
1788 Label nextBasicBlock = new Label();
1789 nextBasicBlock.frame = new Frame(nextBasicBlock);
1790 nextBasicBlock.resolve(code.data, code.length);
1791 lastBasicBlock.nextBasicBlock = nextBasicBlock;
1792 lastBasicBlock = nextBasicBlock;
1793 currentBasicBlock = null;
1794 } else if (compute == COMPUTE_MAX_STACK_AND_LOCAL) {
1795 currentBasicBlock.outputStackMax = (short) maxRelativeStackSize;
1796 currentBasicBlock = null;
1797 }
1798 }
1799
1800 // -----------------------------------------------------------------------------------------------
1801 // Utility methods: stack map frames
1802 // -----------------------------------------------------------------------------------------------
1803
1804 /**
1805 * Starts the visit of a new stack map frame, stored in {@link #currentFrame}.
1806 *
1807 * @param offset the bytecode offset of the instruction to which the frame corresponds.
1808 * @param nLocal the number of local variables in the frame.
1809 * @param nStack the number of stack elements in the frame.
1810 * @return the index of the next element to be written in this frame.
1811 */
1812 int visitFrameStart(final int offset, final int nLocal, final int nStack) {
1813 int frameLength = 3 + nLocal + nStack;
1814 if (currentFrame == null || currentFrame.length < frameLength) {
1815 currentFrame = new int[frameLength];
1816 }
1817 currentFrame[0] = offset;
1818 currentFrame[1] = nLocal;
1819 currentFrame[2] = nStack;
1820 return 3;
1821 }
1822
1823 /**
1824 * Sets an abstract type in {@link #currentFrame}.
1825 *
1826 * @param frameIndex the index of the element to be set in {@link #currentFrame}.
1827 * @param abstractType an abstract type.
1828 */
1829 void visitAbstractType(final int frameIndex, final int abstractType) {
1830 currentFrame[frameIndex] = abstractType;
1831 }
1832
1833 /**
1834 * Ends the visit of {@link #currentFrame} by writing it in the StackMapTable entries and by
1835 * updating the StackMapTable number_of_entries (except if the current frame is the first one,
1836 * which is implicit in StackMapTable). Then resets {@link #currentFrame} to <tt>null</tt>.
1837 */
1838 void visitFrameEnd() {
1839 if (previousFrame != null) {
1840 if (stackMapTableEntries == null) {
1841 stackMapTableEntries = new ByteVector();
1842 }
1843 putFrame();
1844 ++stackMapTableNumberOfEntries;
1845 }
1846 previousFrame = currentFrame;
1847 currentFrame = null;
1848 }
1849
1850 /** Compresses and writes {@link #currentFrame} in a new StackMapTable entry. */
1851 private void putFrame() {
1852 final int nLocal = currentFrame[1];
1853 final int nStack = currentFrame[2];
1854 if (symbolTable.getMajorVersion() < Opcodes.V1_6) {
1855 // Generate a StackMap attribute entry, which are always uncompressed.
1856 stackMapTableEntries.putShort(currentFrame[0]).putShort(nLocal);
1857 putAbstractTypes(3, 3 + nLocal);
1858 stackMapTableEntries.putShort(nStack);
1859 putAbstractTypes(3 + nLocal, 3 + nLocal + nStack);
1860 return;
1861 }
1862 final int offsetDelta =
1863 stackMapTableNumberOfEntries == 0
1864 ? currentFrame[0]
1865 : currentFrame[0] - previousFrame[0] - 1;
1866 final int previousNlocal = previousFrame[1];
1867 final int nLocalDelta = nLocal - previousNlocal;
1868 int type = Frame.FULL_FRAME;
1869 if (nStack == 0) {
1870 switch (nLocalDelta) {
1871 case -3:
1872 case -2:
1873 case -1:
1874 type = Frame.CHOP_FRAME;
1875 break;
1876 case 0:
1877 type = offsetDelta < 64 ? Frame.SAME_FRAME : Frame.SAME_FRAME_EXTENDED;
1878 break;
1879 case 1:
1880 case 2:
1881 case 3:
1882 type = Frame.APPEND_FRAME;
1883 break;
19311884 default:
1932 stackMap.putByte(FULL_FRAME).putShort(delta).putShort(clocalsSize);
1933 writeFrameTypes(3, 3 + clocalsSize);
1934 stackMap.putShort(cstackSize);
1935 writeFrameTypes(3 + clocalsSize, 3 + clocalsSize + cstackSize);
1936 }
1937 }
1938
1939 /**
1940 * Writes some types of the current frame {@link #frame} into the
1941 * StackMapTableAttribute. This method converts types from the format used
1942 * in {@link Label} to the format used in StackMapTable attributes. In
1943 * particular, it converts type table indexes to constant pool indexes.
1944 *
1945 * @param start
1946 * index of the first type in {@link #frame} to write.
1947 * @param end
1948 * index of last type in {@link #frame} to write (exclusive).
1949 */
1950 private void writeFrameTypes(final int start, final int end) {
1951 for (int i = start; i < end; ++i) {
1952 int t = frame[i];
1953 int d = t & Frame.DIM;
1954 if (d == 0) {
1955 int v = t & Frame.BASE_VALUE;
1956 switch (t & Frame.BASE_KIND) {
1957 case Frame.OBJECT:
1958 stackMap.putByte(7).putShort(
1959 cw.newClass(cw.typeTable[v].strVal1));
1960 break;
1961 case Frame.UNINITIALIZED:
1962 stackMap.putByte(8).putShort(cw.typeTable[v].intVal);
1963 break;
1964 default:
1965 stackMap.putByte(v);
1966 }
1967 } else {
1968 StringBuilder sb = new StringBuilder();
1969 d >>= 28;
1970 while (d-- > 0) {
1971 sb.append('[');
1972 }
1973 if ((t & Frame.BASE_KIND) == Frame.OBJECT) {
1974 sb.append('L');
1975 sb.append(cw.typeTable[t & Frame.BASE_VALUE].strVal1);
1976 sb.append(';');
1977 } else {
1978 switch (t & 0xF) {
1979 case 1:
1980 sb.append('I');
1981 break;
1982 case 2:
1983 sb.append('F');
1984 break;
1985 case 3:
1986 sb.append('D');
1987 break;
1988 case 9:
1989 sb.append('Z');
1990 break;
1991 case 10:
1992 sb.append('B');
1993 break;
1994 case 11:
1995 sb.append('C');
1996 break;
1997 case 12:
1998 sb.append('S');
1999 break;
2000 default:
2001 sb.append('J');
2002 }
2003 }
2004 stackMap.putByte(7).putShort(cw.newClass(sb.toString()));
2005 }
2006 }
2007 }
2008
2009 private void writeFrameType(final Object type) {
2010 if (type instanceof String) {
2011 stackMap.putByte(7).putShort(cw.newClass((String) type));
2012 } else if (type instanceof Integer) {
2013 stackMap.putByte(((Integer) type).intValue());
2014 } else {
2015 stackMap.putByte(8).putShort(((Label) type).position);
2016 }
2017 }
2018
2019 // ------------------------------------------------------------------------
2020 // Utility methods: dump bytecode array
2021 // ------------------------------------------------------------------------
2022
2023 /**
2024 * Returns the size of the bytecode of this method.
2025 *
2026 * @return the size of the bytecode of this method.
2027 */
2028 final int getSize() {
2029 if (classReaderOffset != 0) {
2030 return 6 + classReaderLength;
2031 }
2032 int size = 8;
2033 if (code.length > 0) {
2034 if (code.length > 65535) {
2035 throw new RuntimeException("Method code too large!");
2036 }
2037 cw.newUTF8("Code");
2038 size += 18 + code.length + 8 * handlerCount;
2039 if (localVar != null) {
2040 cw.newUTF8("LocalVariableTable");
2041 size += 8 + localVar.length;
2042 }
2043 if (localVarType != null) {
2044 cw.newUTF8("LocalVariableTypeTable");
2045 size += 8 + localVarType.length;
2046 }
2047 if (lineNumber != null) {
2048 cw.newUTF8("LineNumberTable");
2049 size += 8 + lineNumber.length;
2050 }
2051 if (stackMap != null) {
2052 boolean zip = (cw.version & 0xFFFF) >= Opcodes.V1_6;
2053 cw.newUTF8(zip ? "StackMapTable" : "StackMap");
2054 size += 8 + stackMap.length;
2055 }
2056 if (ClassReader.ANNOTATIONS && ctanns != null) {
2057 cw.newUTF8("RuntimeVisibleTypeAnnotations");
2058 size += 8 + ctanns.getSize();
2059 }
2060 if (ClassReader.ANNOTATIONS && ictanns != null) {
2061 cw.newUTF8("RuntimeInvisibleTypeAnnotations");
2062 size += 8 + ictanns.getSize();
2063 }
2064 if (cattrs != null) {
2065 size += cattrs.getSize(cw, code.data, code.length, maxStack,
2066 maxLocals);
2067 }
2068 }
2069 if (exceptionCount > 0) {
2070 cw.newUTF8("Exceptions");
2071 size += 8 + 2 * exceptionCount;
2072 }
2073 if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
2074 if ((cw.version & 0xFFFF) < Opcodes.V1_5
2075 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
2076 cw.newUTF8("Synthetic");
2077 size += 6;
2078 }
2079 }
2080 if ((access & Opcodes.ACC_DEPRECATED) != 0) {
2081 cw.newUTF8("Deprecated");
2082 size += 6;
2083 }
2084 if (ClassReader.SIGNATURES && signature != null) {
2085 cw.newUTF8("Signature");
2086 cw.newUTF8(signature);
2087 size += 8;
2088 }
2089 if (methodParameters != null) {
2090 cw.newUTF8("MethodParameters");
2091 size += 7 + methodParameters.length;
2092 }
2093 if (ClassReader.ANNOTATIONS && annd != null) {
2094 cw.newUTF8("AnnotationDefault");
2095 size += 6 + annd.length;
2096 }
2097 if (ClassReader.ANNOTATIONS && anns != null) {
2098 cw.newUTF8("RuntimeVisibleAnnotations");
2099 size += 8 + anns.getSize();
2100 }
2101 if (ClassReader.ANNOTATIONS && ianns != null) {
2102 cw.newUTF8("RuntimeInvisibleAnnotations");
2103 size += 8 + ianns.getSize();
2104 }
2105 if (ClassReader.ANNOTATIONS && tanns != null) {
2106 cw.newUTF8("RuntimeVisibleTypeAnnotations");
2107 size += 8 + tanns.getSize();
2108 }
2109 if (ClassReader.ANNOTATIONS && itanns != null) {
2110 cw.newUTF8("RuntimeInvisibleTypeAnnotations");
2111 size += 8 + itanns.getSize();
2112 }
2113 if (ClassReader.ANNOTATIONS && panns != null) {
2114 cw.newUTF8("RuntimeVisibleParameterAnnotations");
2115 size += 7 + 2 * (panns.length - synthetics);
2116 for (int i = panns.length - 1; i >= synthetics; --i) {
2117 size += panns[i] == null ? 0 : panns[i].getSize();
2118 }
2119 }
2120 if (ClassReader.ANNOTATIONS && ipanns != null) {
2121 cw.newUTF8("RuntimeInvisibleParameterAnnotations");
2122 size += 7 + 2 * (ipanns.length - synthetics);
2123 for (int i = ipanns.length - 1; i >= synthetics; --i) {
2124 size += ipanns[i] == null ? 0 : ipanns[i].getSize();
2125 }
2126 }
2127 if (attrs != null) {
2128 size += attrs.getSize(cw, null, 0, -1, -1);
2129 }
2130 return size;
2131 }
2132
2133 /**
2134 * Puts the bytecode of this method in the given byte vector.
2135 *
2136 * @param out
2137 * the byte vector into which the bytecode of this method must be
2138 * copied.
2139 */
2140 final void put(final ByteVector out) {
2141 final int FACTOR = ClassWriter.TO_ACC_SYNTHETIC;
2142 int mask = ACC_CONSTRUCTOR | Opcodes.ACC_DEPRECATED
2143 | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE
2144 | ((access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) / FACTOR);
2145 out.putShort(access & ~mask).putShort(name).putShort(desc);
2146 if (classReaderOffset != 0) {
2147 out.putByteArray(cw.cr.b, classReaderOffset, classReaderLength);
2148 return;
2149 }
2150 int attributeCount = 0;
2151 if (code.length > 0) {
2152 ++attributeCount;
2153 }
2154 if (exceptionCount > 0) {
2155 ++attributeCount;
2156 }
2157 if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
2158 if ((cw.version & 0xFFFF) < Opcodes.V1_5
2159 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
2160 ++attributeCount;
2161 }
2162 }
2163 if ((access & Opcodes.ACC_DEPRECATED) != 0) {
2164 ++attributeCount;
2165 }
2166 if (ClassReader.SIGNATURES && signature != null) {
2167 ++attributeCount;
2168 }
2169 if (methodParameters != null) {
2170 ++attributeCount;
2171 }
2172 if (ClassReader.ANNOTATIONS && annd != null) {
2173 ++attributeCount;
2174 }
2175 if (ClassReader.ANNOTATIONS && anns != null) {
2176 ++attributeCount;
2177 }
2178 if (ClassReader.ANNOTATIONS && ianns != null) {
2179 ++attributeCount;
2180 }
2181 if (ClassReader.ANNOTATIONS && tanns != null) {
2182 ++attributeCount;
2183 }
2184 if (ClassReader.ANNOTATIONS && itanns != null) {
2185 ++attributeCount;
2186 }
2187 if (ClassReader.ANNOTATIONS && panns != null) {
2188 ++attributeCount;
2189 }
2190 if (ClassReader.ANNOTATIONS && ipanns != null) {
2191 ++attributeCount;
2192 }
2193 if (attrs != null) {
2194 attributeCount += attrs.getCount();
2195 }
2196 out.putShort(attributeCount);
2197 if (code.length > 0) {
2198 int size = 12 + code.length + 8 * handlerCount;
2199 if (localVar != null) {
2200 size += 8 + localVar.length;
2201 }
2202 if (localVarType != null) {
2203 size += 8 + localVarType.length;
2204 }
2205 if (lineNumber != null) {
2206 size += 8 + lineNumber.length;
2207 }
2208 if (stackMap != null) {
2209 size += 8 + stackMap.length;
2210 }
2211 if (ClassReader.ANNOTATIONS && ctanns != null) {
2212 size += 8 + ctanns.getSize();
2213 }
2214 if (ClassReader.ANNOTATIONS && ictanns != null) {
2215 size += 8 + ictanns.getSize();
2216 }
2217 if (cattrs != null) {
2218 size += cattrs.getSize(cw, code.data, code.length, maxStack,
2219 maxLocals);
2220 }
2221 out.putShort(cw.newUTF8("Code")).putInt(size);
2222 out.putShort(maxStack).putShort(maxLocals);
2223 out.putInt(code.length).putByteArray(code.data, 0, code.length);
2224 out.putShort(handlerCount);
2225 if (handlerCount > 0) {
2226 Handler h = firstHandler;
2227 while (h != null) {
2228 out.putShort(h.start.position).putShort(h.end.position)
2229 .putShort(h.handler.position).putShort(h.type);
2230 h = h.next;
2231 }
2232 }
2233 attributeCount = 0;
2234 if (localVar != null) {
2235 ++attributeCount;
2236 }
2237 if (localVarType != null) {
2238 ++attributeCount;
2239 }
2240 if (lineNumber != null) {
2241 ++attributeCount;
2242 }
2243 if (stackMap != null) {
2244 ++attributeCount;
2245 }
2246 if (ClassReader.ANNOTATIONS && ctanns != null) {
2247 ++attributeCount;
2248 }
2249 if (ClassReader.ANNOTATIONS && ictanns != null) {
2250 ++attributeCount;
2251 }
2252 if (cattrs != null) {
2253 attributeCount += cattrs.getCount();
2254 }
2255 out.putShort(attributeCount);
2256 if (localVar != null) {
2257 out.putShort(cw.newUTF8("LocalVariableTable"));
2258 out.putInt(localVar.length + 2).putShort(localVarCount);
2259 out.putByteArray(localVar.data, 0, localVar.length);
2260 }
2261 if (localVarType != null) {
2262 out.putShort(cw.newUTF8("LocalVariableTypeTable"));
2263 out.putInt(localVarType.length + 2).putShort(localVarTypeCount);
2264 out.putByteArray(localVarType.data, 0, localVarType.length);
2265 }
2266 if (lineNumber != null) {
2267 out.putShort(cw.newUTF8("LineNumberTable"));
2268 out.putInt(lineNumber.length + 2).putShort(lineNumberCount);
2269 out.putByteArray(lineNumber.data, 0, lineNumber.length);
2270 }
2271 if (stackMap != null) {
2272 boolean zip = (cw.version & 0xFFFF) >= Opcodes.V1_6;
2273 out.putShort(cw.newUTF8(zip ? "StackMapTable" : "StackMap"));
2274 out.putInt(stackMap.length + 2).putShort(frameCount);
2275 out.putByteArray(stackMap.data, 0, stackMap.length);
2276 }
2277 if (ClassReader.ANNOTATIONS && ctanns != null) {
2278 out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations"));
2279 ctanns.put(out);
2280 }
2281 if (ClassReader.ANNOTATIONS && ictanns != null) {
2282 out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations"));
2283 ictanns.put(out);
2284 }
2285 if (cattrs != null) {
2286 cattrs.put(cw, code.data, code.length, maxLocals, maxStack, out);
2287 }
2288 }
2289 if (exceptionCount > 0) {
2290 out.putShort(cw.newUTF8("Exceptions")).putInt(
2291 2 * exceptionCount + 2);
2292 out.putShort(exceptionCount);
2293 for (int i = 0; i < exceptionCount; ++i) {
2294 out.putShort(exceptions[i]);
2295 }
2296 }
2297 if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
2298 if ((cw.version & 0xFFFF) < Opcodes.V1_5
2299 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
2300 out.putShort(cw.newUTF8("Synthetic")).putInt(0);
2301 }
2302 }
2303 if ((access & Opcodes.ACC_DEPRECATED) != 0) {
2304 out.putShort(cw.newUTF8("Deprecated")).putInt(0);
2305 }
2306 if (ClassReader.SIGNATURES && signature != null) {
2307 out.putShort(cw.newUTF8("Signature")).putInt(2)
2308 .putShort(cw.newUTF8(signature));
2309 }
2310 if (methodParameters != null) {
2311 out.putShort(cw.newUTF8("MethodParameters"));
2312 out.putInt(methodParameters.length + 1).putByte(
2313 methodParametersCount);
2314 out.putByteArray(methodParameters.data, 0, methodParameters.length);
2315 }
2316 if (ClassReader.ANNOTATIONS && annd != null) {
2317 out.putShort(cw.newUTF8("AnnotationDefault"));
2318 out.putInt(annd.length);
2319 out.putByteArray(annd.data, 0, annd.length);
2320 }
2321 if (ClassReader.ANNOTATIONS && anns != null) {
2322 out.putShort(cw.newUTF8("RuntimeVisibleAnnotations"));
2323 anns.put(out);
2324 }
2325 if (ClassReader.ANNOTATIONS && ianns != null) {
2326 out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations"));
2327 ianns.put(out);
2328 }
2329 if (ClassReader.ANNOTATIONS && tanns != null) {
2330 out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations"));
2331 tanns.put(out);
2332 }
2333 if (ClassReader.ANNOTATIONS && itanns != null) {
2334 out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations"));
2335 itanns.put(out);
2336 }
2337 if (ClassReader.ANNOTATIONS && panns != null) {
2338 out.putShort(cw.newUTF8("RuntimeVisibleParameterAnnotations"));
2339 AnnotationWriter.put(panns, synthetics, out);
2340 }
2341 if (ClassReader.ANNOTATIONS && ipanns != null) {
2342 out.putShort(cw.newUTF8("RuntimeInvisibleParameterAnnotations"));
2343 AnnotationWriter.put(ipanns, synthetics, out);
2344 }
2345 if (attrs != null) {
2346 attrs.put(cw, null, 0, -1, -1, out);
2347 }
2348 }
2349
2350 // ------------------------------------------------------------------------
2351 // Utility methods: instruction resizing (used to handle GOTO_W and JSR_W)
2352 // ------------------------------------------------------------------------
2353
2354 /**
2355 * Resizes and replaces the temporary instructions inserted by
2356 * {@link Label#resolve} for wide forward jumps, while keeping jump offsets
2357 * and instruction addresses consistent. This may require to resize other
2358 * existing instructions, or even to introduce new instructions: for
2359 * example, increasing the size of an instruction by 2 at the middle of a
2360 * method can increases the offset of an IFEQ instruction from 32766 to
2361 * 32768, in which case IFEQ 32766 must be replaced with IFNEQ 8 GOTO_W
2362 * 32765. This, in turn, may require to increase the size of another jump
2363 * instruction, and so on... All these operations are handled automatically
2364 * by this method.
2365 * <p>
2366 * <i>This method must be called after all the method that is being built
2367 * has been visited</i>. In particular, the {@link Label Label} objects used
2368 * to construct the method are no longer valid after this method has been
2369 * called.
2370 */
2371 private void resizeInstructions() {
2372 byte[] b = code.data; // bytecode of the method
2373 int u, v, label; // indexes in b
2374 int i, j; // loop indexes
2375 /*
2376 * 1st step: As explained above, resizing an instruction may require to
2377 * resize another one, which may require to resize yet another one, and
2378 * so on. The first step of the algorithm consists in finding all the
2379 * instructions that need to be resized, without modifying the code.
2380 * This is done by the following "fix point" algorithm:
2381 *
2382 * Parse the code to find the jump instructions whose offset will need
2383 * more than 2 bytes to be stored (the future offset is computed from
2384 * the current offset and from the number of bytes that will be inserted
2385 * or removed between the source and target instructions). For each such
2386 * instruction, adds an entry in (a copy of) the indexes and sizes
2387 * arrays (if this has not already been done in a previous iteration!).
2388 *
2389 * If at least one entry has been added during the previous step, go
2390 * back to the beginning, otherwise stop.
2391 *
2392 * In fact the real algorithm is complicated by the fact that the size
2393 * of TABLESWITCH and LOOKUPSWITCH instructions depends on their
2394 * position in the bytecode (because of padding). In order to ensure the
2395 * convergence of the algorithm, the number of bytes to be added or
2396 * removed from these instructions is over estimated during the previous
2397 * loop, and computed exactly only after the loop is finished (this
2398 * requires another pass to parse the bytecode of the method).
2399 */
2400 int[] allIndexes = new int[0]; // copy of indexes
2401 int[] allSizes = new int[0]; // copy of sizes
2402 boolean[] resize; // instructions to be resized
2403 int newOffset; // future offset of a jump instruction
2404
2405 resize = new boolean[code.length];
2406
2407 // 3 = loop again, 2 = loop ended, 1 = last pass, 0 = done
2408 int state = 3;
2409 do {
2410 if (state == 3) {
2411 state = 2;
2412 }
2413 u = 0;
2414 while (u < b.length) {
2415 int opcode = b[u] & 0xFF; // opcode of current instruction
2416 int insert = 0; // bytes to be added after this instruction
2417
2418 switch (ClassWriter.TYPE[opcode]) {
2419 case ClassWriter.NOARG_INSN:
2420 case ClassWriter.IMPLVAR_INSN:
2421 u += 1;
2422 break;
2423 case ClassWriter.LABEL_INSN:
2424 if (opcode > 201) {
2425 // converts temporary opcodes 202 to 217, 218 and
2426 // 219 to IFEQ ... JSR (inclusive), IFNULL and
2427 // IFNONNULL
2428 opcode = opcode < 218 ? opcode - 49 : opcode - 20;
2429 label = u + readUnsignedShort(b, u + 1);
2430 } else {
2431 label = u + readShort(b, u + 1);
2432 }
2433 newOffset = getNewOffset(allIndexes, allSizes, u, label);
2434 if (newOffset < Short.MIN_VALUE
2435 || newOffset > Short.MAX_VALUE) {
2436 if (!resize[u]) {
2437 if (opcode == Opcodes.GOTO || opcode == Opcodes.JSR) {
2438 // two additional bytes will be required to
2439 // replace this GOTO or JSR instruction with
2440 // a GOTO_W or a JSR_W
2441 insert = 2;
2442 } else {
2443 // five additional bytes will be required to
2444 // replace this IFxxx <l> instruction with
2445 // IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx
2446 // is the "opposite" opcode of IFxxx (i.e.,
2447 // IFNE for IFEQ) and where <l'> designates
2448 // the instruction just after the GOTO_W.
2449 insert = 5;
2450 }
2451 resize[u] = true;
2452 }
2453 }
2454 u += 3;
2455 break;
2456 case ClassWriter.LABELW_INSN:
2457 u += 5;
2458 break;
2459 case ClassWriter.TABL_INSN:
2460 if (state == 1) {
2461 // true number of bytes to be added (or removed)
2462 // from this instruction = (future number of padding
2463 // bytes - current number of padding byte) -
2464 // previously over estimated variation =
2465 // = ((3 - newOffset%4) - (3 - u%4)) - u%4
2466 // = (-newOffset%4 + u%4) - u%4
2467 // = -(newOffset & 3)
2468 newOffset = getNewOffset(allIndexes, allSizes, 0, u);
2469 insert = -(newOffset & 3);
2470 } else if (!resize[u]) {
2471 // over estimation of the number of bytes to be
2472 // added to this instruction = 3 - current number
2473 // of padding bytes = 3 - (3 - u%4) = u%4 = u & 3
2474 insert = u & 3;
2475 resize[u] = true;
2476 }
2477 // skips instruction
2478 u = u + 4 - (u & 3);
2479 u += 4 * (readInt(b, u + 8) - readInt(b, u + 4) + 1) + 12;
2480 break;
2481 case ClassWriter.LOOK_INSN:
2482 if (state == 1) {
2483 // like TABL_INSN
2484 newOffset = getNewOffset(allIndexes, allSizes, 0, u);
2485 insert = -(newOffset & 3);
2486 } else if (!resize[u]) {
2487 // like TABL_INSN
2488 insert = u & 3;
2489 resize[u] = true;
2490 }
2491 // skips instruction
2492 u = u + 4 - (u & 3);
2493 u += 8 * readInt(b, u + 4) + 8;
2494 break;
2495 case ClassWriter.WIDE_INSN:
2496 opcode = b[u + 1] & 0xFF;
2497 if (opcode == Opcodes.IINC) {
2498 u += 6;
2499 } else {
2500 u += 4;
2501 }
2502 break;
2503 case ClassWriter.VAR_INSN:
2504 case ClassWriter.SBYTE_INSN:
2505 case ClassWriter.LDC_INSN:
2506 u += 2;
2507 break;
2508 case ClassWriter.SHORT_INSN:
2509 case ClassWriter.LDCW_INSN:
2510 case ClassWriter.FIELDORMETH_INSN:
2511 case ClassWriter.TYPE_INSN:
2512 case ClassWriter.IINC_INSN:
2513 u += 3;
2514 break;
2515 case ClassWriter.ITFMETH_INSN:
2516 case ClassWriter.INDYMETH_INSN:
2517 u += 5;
2518 break;
2519 // case ClassWriter.MANA_INSN:
2520 default:
2521 u += 4;
2522 break;
2523 }
2524 if (insert != 0) {
2525 // adds a new (u, insert) entry in the allIndexes and
2526 // allSizes arrays
2527 int[] newIndexes = new int[allIndexes.length + 1];
2528 int[] newSizes = new int[allSizes.length + 1];
2529 System.arraycopy(allIndexes, 0, newIndexes, 0,
2530 allIndexes.length);
2531 System.arraycopy(allSizes, 0, newSizes, 0, allSizes.length);
2532 newIndexes[allIndexes.length] = u;
2533 newSizes[allSizes.length] = insert;
2534 allIndexes = newIndexes;
2535 allSizes = newSizes;
2536 if (insert > 0) {
2537 state = 3;
2538 }
2539 }
2540 }
2541 if (state < 3) {
2542 --state;
2543 }
2544 } while (state != 0);
2545
2546 // 2nd step:
2547 // copies the bytecode of the method into a new bytevector, updates the
2548 // offsets, and inserts (or removes) bytes as requested.
2549
2550 ByteVector newCode = new ByteVector(code.length);
2551
2552 u = 0;
2553 while (u < code.length) {
2554 int opcode = b[u] & 0xFF;
2555 switch (ClassWriter.TYPE[opcode]) {
2556 case ClassWriter.NOARG_INSN:
2557 case ClassWriter.IMPLVAR_INSN:
2558 newCode.putByte(opcode);
2559 u += 1;
2560 break;
2561 case ClassWriter.LABEL_INSN:
2562 if (opcode > 201) {
2563 // changes temporary opcodes 202 to 217 (inclusive), 218
2564 // and 219 to IFEQ ... JSR (inclusive), IFNULL and
2565 // IFNONNULL
2566 opcode = opcode < 218 ? opcode - 49 : opcode - 20;
2567 label = u + readUnsignedShort(b, u + 1);
2568 } else {
2569 label = u + readShort(b, u + 1);
2570 }
2571 newOffset = getNewOffset(allIndexes, allSizes, u, label);
2572 if (resize[u]) {
2573 // replaces GOTO with GOTO_W, JSR with JSR_W and IFxxx
2574 // <l> with IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx is
2575 // the "opposite" opcode of IFxxx (i.e., IFNE for IFEQ)
2576 // and where <l'> designates the instruction just after
2577 // the GOTO_W.
2578 if (opcode == Opcodes.GOTO) {
2579 newCode.putByte(200); // GOTO_W
2580 } else if (opcode == Opcodes.JSR) {
2581 newCode.putByte(201); // JSR_W
2582 } else {
2583 newCode.putByte(opcode <= 166 ? ((opcode + 1) ^ 1) - 1
2584 : opcode ^ 1);
2585 newCode.putShort(8); // jump offset
2586 newCode.putByte(200); // GOTO_W
2587 // newOffset now computed from start of GOTO_W
2588 newOffset -= 3;
2589 }
2590 newCode.putInt(newOffset);
2591 } else {
2592 newCode.putByte(opcode);
2593 newCode.putShort(newOffset);
2594 }
2595 u += 3;
2596 break;
2597 case ClassWriter.LABELW_INSN:
2598 label = u + readInt(b, u + 1);
2599 newOffset = getNewOffset(allIndexes, allSizes, u, label);
2600 newCode.putByte(opcode);
2601 newCode.putInt(newOffset);
2602 u += 5;
2603 break;
2604 case ClassWriter.TABL_INSN:
2605 // skips 0 to 3 padding bytes
2606 v = u;
2607 u = u + 4 - (v & 3);
2608 // reads and copies instruction
2609 newCode.putByte(Opcodes.TABLESWITCH);
2610 newCode.putByteArray(null, 0, (4 - newCode.length % 4) % 4);
2611 label = v + readInt(b, u);
2612 u += 4;
2613 newOffset = getNewOffset(allIndexes, allSizes, v, label);
2614 newCode.putInt(newOffset);
2615 j = readInt(b, u);
2616 u += 4;
2617 newCode.putInt(j);
2618 j = readInt(b, u) - j + 1;
2619 u += 4;
2620 newCode.putInt(readInt(b, u - 4));
2621 for (; j > 0; --j) {
2622 label = v + readInt(b, u);
2623 u += 4;
2624 newOffset = getNewOffset(allIndexes, allSizes, v, label);
2625 newCode.putInt(newOffset);
2626 }
2627 break;
2628 case ClassWriter.LOOK_INSN:
2629 // skips 0 to 3 padding bytes
2630 v = u;
2631 u = u + 4 - (v & 3);
2632 // reads and copies instruction
2633 newCode.putByte(Opcodes.LOOKUPSWITCH);
2634 newCode.putByteArray(null, 0, (4 - newCode.length % 4) % 4);
2635 label = v + readInt(b, u);
2636 u += 4;
2637 newOffset = getNewOffset(allIndexes, allSizes, v, label);
2638 newCode.putInt(newOffset);
2639 j = readInt(b, u);
2640 u += 4;
2641 newCode.putInt(j);
2642 for (; j > 0; --j) {
2643 newCode.putInt(readInt(b, u));
2644 u += 4;
2645 label = v + readInt(b, u);
2646 u += 4;
2647 newOffset = getNewOffset(allIndexes, allSizes, v, label);
2648 newCode.putInt(newOffset);
2649 }
2650 break;
2651 case ClassWriter.WIDE_INSN:
2652 opcode = b[u + 1] & 0xFF;
2653 if (opcode == Opcodes.IINC) {
2654 newCode.putByteArray(b, u, 6);
2655 u += 6;
2656 } else {
2657 newCode.putByteArray(b, u, 4);
2658 u += 4;
2659 }
2660 break;
2661 case ClassWriter.VAR_INSN:
2662 case ClassWriter.SBYTE_INSN:
2663 case ClassWriter.LDC_INSN:
2664 newCode.putByteArray(b, u, 2);
2665 u += 2;
2666 break;
2667 case ClassWriter.SHORT_INSN:
2668 case ClassWriter.LDCW_INSN:
2669 case ClassWriter.FIELDORMETH_INSN:
2670 case ClassWriter.TYPE_INSN:
2671 case ClassWriter.IINC_INSN:
2672 newCode.putByteArray(b, u, 3);
2673 u += 3;
2674 break;
2675 case ClassWriter.ITFMETH_INSN:
2676 case ClassWriter.INDYMETH_INSN:
2677 newCode.putByteArray(b, u, 5);
2678 u += 5;
2679 break;
2680 // case MANA_INSN:
2681 default:
2682 newCode.putByteArray(b, u, 4);
2683 u += 4;
2684 break;
2685 }
2686 }
2687
2688 // updates the stack map frame labels
2689 if (compute == FRAMES) {
2690 Label l = labels;
2691 while (l != null) {
2692 /*
2693 * Detects the labels that are just after an IF instruction that
2694 * has been resized with the IFNOT GOTO_W pattern. These labels
2695 * are now the target of a jump instruction (the IFNOT
2696 * instruction). Note that we need the original label position
2697 * here. getNewOffset must therefore never have been called for
2698 * this label.
2699 */
2700 u = l.position - 3;
2701 if (u >= 0 && resize[u]) {
2702 l.status |= Label.TARGET;
2703 }
2704 getNewOffset(allIndexes, allSizes, l);
2705 l = l.successor;
2706 }
2707 // Update the offsets in the uninitialized types
2708 if (cw.typeTable != null) {
2709 for (i = 0; i < cw.typeTable.length; ++i) {
2710 Item item = cw.typeTable[i];
2711 if (item != null && item.type == ClassWriter.TYPE_UNINIT) {
2712 item.intVal = getNewOffset(allIndexes, allSizes, 0,
2713 item.intVal);
2714 }
2715 }
2716 }
2717 // The stack map frames are not serialized yet, so we don't need
2718 // to update them. They will be serialized in visitMaxs.
2719 } else if (frameCount > 0) {
2720 /*
2721 * Resizing an existing stack map frame table is really hard. Not
2722 * only the table must be parsed to update the offets, but new
2723 * frames may be needed for jump instructions that were inserted by
2724 * this method. And updating the offsets or inserting frames can
2725 * change the format of the following frames, in case of packed
2726 * frames. In practice the whole table must be recomputed. For this
2727 * the frames are marked as potentially invalid. This will cause the
2728 * whole class to be reread and rewritten with the COMPUTE_FRAMES
2729 * option (see the ClassWriter.toByteArray method). This is not very
2730 * efficient but is much easier and requires much less code than any
2731 * other method I can think of.
2732 */
2733 cw.invalidFrames = true;
2734 }
2735 // updates the exception handler block labels
2736 Handler h = firstHandler;
2737 while (h != null) {
2738 getNewOffset(allIndexes, allSizes, h.start);
2739 getNewOffset(allIndexes, allSizes, h.end);
2740 getNewOffset(allIndexes, allSizes, h.handler);
2741 h = h.next;
2742 }
2743 // updates the instructions addresses in the
2744 // local var and line number tables
2745 for (i = 0; i < 2; ++i) {
2746 ByteVector bv = i == 0 ? localVar : localVarType;
2747 if (bv != null) {
2748 b = bv.data;
2749 u = 0;
2750 while (u < bv.length) {
2751 label = readUnsignedShort(b, u);
2752 newOffset = getNewOffset(allIndexes, allSizes, 0, label);
2753 writeShort(b, u, newOffset);
2754 label += readUnsignedShort(b, u + 2);
2755 newOffset = getNewOffset(allIndexes, allSizes, 0, label)
2756 - newOffset;
2757 writeShort(b, u + 2, newOffset);
2758 u += 10;
2759 }
2760 }
2761 }
2762 if (lineNumber != null) {
2763 b = lineNumber.data;
2764 u = 0;
2765 while (u < lineNumber.length) {
2766 writeShort(
2767 b,
2768 u,
2769 getNewOffset(allIndexes, allSizes, 0,
2770 readUnsignedShort(b, u)));
2771 u += 4;
2772 }
2773 }
2774 // updates the labels of the other attributes
2775 Attribute attr = cattrs;
2776 while (attr != null) {
2777 Label[] labels = attr.getLabels();
2778 if (labels != null) {
2779 for (i = labels.length - 1; i >= 0; --i) {
2780 getNewOffset(allIndexes, allSizes, labels[i]);
2781 }
2782 }
2783 attr = attr.next;
2784 }
2785
2786 // replaces old bytecodes with new ones
2787 code = newCode;
2788 }
2789
2790 /**
2791 * Reads an unsigned short value in the given byte array.
2792 *
2793 * @param b
2794 * a byte array.
2795 * @param index
2796 * the start index of the value to be read.
2797 * @return the read value.
2798 */
2799 static int readUnsignedShort(final byte[] b, final int index) {
2800 return ((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF);
2801 }
2802
2803 /**
2804 * Reads a signed short value in the given byte array.
2805 *
2806 * @param b
2807 * a byte array.
2808 * @param index
2809 * the start index of the value to be read.
2810 * @return the read value.
2811 */
2812 static short readShort(final byte[] b, final int index) {
2813 return (short) (((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF));
2814 }
2815
2816 /**
2817 * Reads a signed int value in the given byte array.
2818 *
2819 * @param b
2820 * a byte array.
2821 * @param index
2822 * the start index of the value to be read.
2823 * @return the read value.
2824 */
2825 static int readInt(final byte[] b, final int index) {
2826 return ((b[index] & 0xFF) << 24) | ((b[index + 1] & 0xFF) << 16)
2827 | ((b[index + 2] & 0xFF) << 8) | (b[index + 3] & 0xFF);
2828 }
2829
2830 /**
2831 * Writes a short value in the given byte array.
2832 *
2833 * @param b
2834 * a byte array.
2835 * @param index
2836 * where the first byte of the short value must be written.
2837 * @param s
2838 * the value to be written in the given byte array.
2839 */
2840 static void writeShort(final byte[] b, final int index, final int s) {
2841 b[index] = (byte) (s >>> 8);
2842 b[index + 1] = (byte) s;
2843 }
2844
2845 /**
2846 * Computes the future value of a bytecode offset.
2847 * <p>
2848 * Note: it is possible to have several entries for the same instruction in
2849 * the <tt>indexes</tt> and <tt>sizes</tt>: two entries (index=a,size=b) and
2850 * (index=a,size=b') are equivalent to a single entry (index=a,size=b+b').
2851 *
2852 * @param indexes
2853 * current positions of the instructions to be resized. Each
2854 * instruction must be designated by the index of its <i>last</i>
2855 * byte, plus one (or, in other words, by the index of the
2856 * <i>first</i> byte of the <i>next</i> instruction).
2857 * @param sizes
2858 * the number of bytes to be <i>added</i> to the above
2859 * instructions. More precisely, for each i < <tt>len</tt>,
2860 * <tt>sizes</tt>[i] bytes will be added at the end of the
2861 * instruction designated by <tt>indexes</tt>[i] or, if
2862 * <tt>sizes</tt>[i] is negative, the <i>last</i> |
2863 * <tt>sizes[i]</tt>| bytes of the instruction will be removed
2864 * (the instruction size <i>must not</i> become negative or
2865 * null).
2866 * @param begin
2867 * index of the first byte of the source instruction.
2868 * @param end
2869 * index of the first byte of the target instruction.
2870 * @return the future value of the given bytecode offset.
2871 */
2872 static int getNewOffset(final int[] indexes, final int[] sizes,
2873 final int begin, final int end) {
2874 int offset = end - begin;
2875 for (int i = 0; i < indexes.length; ++i) {
2876 if (begin < indexes[i] && indexes[i] <= end) {
2877 // forward jump
2878 offset += sizes[i];
2879 } else if (end < indexes[i] && indexes[i] <= begin) {
2880 // backward jump
2881 offset -= sizes[i];
2882 }
2883 }
2884 return offset;
2885 }
2886
2887 /**
2888 * Updates the offset of the given label.
2889 *
2890 * @param indexes
2891 * current positions of the instructions to be resized. Each
2892 * instruction must be designated by the index of its <i>last</i>
2893 * byte, plus one (or, in other words, by the index of the
2894 * <i>first</i> byte of the <i>next</i> instruction).
2895 * @param sizes
2896 * the number of bytes to be <i>added</i> to the above
2897 * instructions. More precisely, for each i < <tt>len</tt>,
2898 * <tt>sizes</tt>[i] bytes will be added at the end of the
2899 * instruction designated by <tt>indexes</tt>[i] or, if
2900 * <tt>sizes</tt>[i] is negative, the <i>last</i> |
2901 * <tt>sizes[i]</tt>| bytes of the instruction will be removed
2902 * (the instruction size <i>must not</i> become negative or
2903 * null).
2904 * @param label
2905 * the label whose offset must be updated.
2906 */
2907 static void getNewOffset(final int[] indexes, final int[] sizes,
2908 final Label label) {
2909 if ((label.status & Label.RESIZED) == 0) {
2910 label.position = getNewOffset(indexes, sizes, 0, label.position);
2911 label.status |= Label.RESIZED;
2912 }
2913 }
1885 // Keep the FULL_FRAME type.
1886 break;
1887 }
1888 } else if (nLocalDelta == 0 && nStack == 1) {
1889 type =
1890 offsetDelta < 63
1891 ? Frame.SAME_LOCALS_1_STACK_ITEM_FRAME
1892 : Frame.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED;
1893 }
1894 if (type != Frame.FULL_FRAME) {
1895 // Verify if locals are the same as in the previous frame.
1896 int frameIndex = 3;
1897 for (int i = 0; i < previousNlocal && i < nLocal; i++) {
1898 if (currentFrame[frameIndex] != previousFrame[frameIndex]) {
1899 type = Frame.FULL_FRAME;
1900 break;
1901 }
1902 frameIndex++;
1903 }
1904 }
1905 switch (type) {
1906 case Frame.SAME_FRAME:
1907 stackMapTableEntries.putByte(offsetDelta);
1908 break;
1909 case Frame.SAME_LOCALS_1_STACK_ITEM_FRAME:
1910 stackMapTableEntries.putByte(Frame.SAME_LOCALS_1_STACK_ITEM_FRAME + offsetDelta);
1911 putAbstractTypes(3 + nLocal, 4 + nLocal);
1912 break;
1913 case Frame.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED:
1914 stackMapTableEntries
1915 .putByte(Frame.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED)
1916 .putShort(offsetDelta);
1917 putAbstractTypes(3 + nLocal, 4 + nLocal);
1918 break;
1919 case Frame.SAME_FRAME_EXTENDED:
1920 stackMapTableEntries.putByte(Frame.SAME_FRAME_EXTENDED).putShort(offsetDelta);
1921 break;
1922 case Frame.CHOP_FRAME:
1923 stackMapTableEntries.putByte(Frame.SAME_FRAME_EXTENDED + nLocalDelta).putShort(offsetDelta);
1924 break;
1925 case Frame.APPEND_FRAME:
1926 stackMapTableEntries.putByte(Frame.SAME_FRAME_EXTENDED + nLocalDelta).putShort(offsetDelta);
1927 putAbstractTypes(3 + previousNlocal, 3 + nLocal);
1928 break;
1929 case Frame.FULL_FRAME:
1930 default:
1931 stackMapTableEntries.putByte(Frame.FULL_FRAME).putShort(offsetDelta).putShort(nLocal);
1932 putAbstractTypes(3, 3 + nLocal);
1933 stackMapTableEntries.putShort(nStack);
1934 putAbstractTypes(3 + nLocal, 3 + nLocal + nStack);
1935 }
1936 }
1937
1938 /**
1939 * Puts some abstract types of {@link #currentFrame} in {@link #stackMapTableEntries} , using the
1940 * JVMS verification_type_info format used in StackMapTable attributes.
1941 *
1942 * @param start index of the first type in {@link #currentFrame} to write.
1943 * @param end index of last type in {@link #currentFrame} to write (exclusive).
1944 */
1945 private void putAbstractTypes(final int start, final int end) {
1946 for (int i = start; i < end; ++i) {
1947 Frame.putAbstractType(symbolTable, currentFrame[i], stackMapTableEntries);
1948 }
1949 }
1950
1951 /**
1952 * Puts the given public API frame element type in {@link #stackMapTableEntries} , using the JVMS
1953 * verification_type_info format used in StackMapTable attributes.
1954 *
1955 * @param type a frame element type described using the same format as in {@link
1956 * MethodVisitor#visitFrame}, i.e. either {@link Opcodes#TOP}, {@link Opcodes#INTEGER}, {@link
1957 * Opcodes#FLOAT}, {@link Opcodes#LONG}, {@link Opcodes#DOUBLE}, {@link Opcodes#NULL}, or
1958 * {@link Opcodes#UNINITIALIZED_THIS}, or the internal name of a class, or a Label designating
1959 * a NEW instruction (for uninitialized types).
1960 */
1961 private void putFrameType(final Object type) {
1962 if (type instanceof Integer) {
1963 stackMapTableEntries.putByte(((Integer) type).intValue());
1964 } else if (type instanceof String) {
1965 stackMapTableEntries
1966 .putByte(Frame.ITEM_OBJECT)
1967 .putShort(symbolTable.addConstantClass((String) type).index);
1968 } else {
1969 stackMapTableEntries
1970 .putByte(Frame.ITEM_UNINITIALIZED)
1971 .putShort(((Label) type).bytecodeOffset);
1972 }
1973 }
1974
1975 // -----------------------------------------------------------------------------------------------
1976 // Utility methods
1977 // -----------------------------------------------------------------------------------------------
1978
1979 /**
1980 * Returns whether the attributes of this method can be copied from the attributes of the given
1981 * method (assuming there is no method visitor between the given ClassReader and this
1982 * MethodWriter). This method should only be called just after this MethodWriter has been created,
1983 * and before any content is visited. It returns true if the attributes corresponding to the
1984 * constructor arguments (at most a Signature, an Exception, a Deprecated and a Synthetic
1985 * attribute) are the same as the corresponding attributes in the given method.
1986 *
1987 * @param source the source ClassReader from which the attributes of this method might be copied.
1988 * @param methodInfoOffset the offset in 'source.b' of the method_info JVMS structure from which
1989 * the attributes of this method might be copied.
1990 * @param methodInfoLength the length in 'source.b' of the method_info JVMS structure from which
1991 * the attributes of this method might be copied.
1992 * @param hasSyntheticAttribute whether the method_info JVMS structure from which the attributes
1993 * of this method might be copied contains a Synthetic attribute.
1994 * @param hasDeprecatedAttribute whether the method_info JVMS structure from which the attributes
1995 * of this method might be copied contains a Deprecated attribute.
1996 * @param signatureIndex the constant pool index contained in the Signature attribute of the
1997 * method_info JVMS structure from which the attributes of this method might be copied, or 0.
1998 * @param exceptionsOffset the offset in 'source.b' of the Exceptions attribute of the method_info
1999 * JVMS structure from which the attributes of this method might be copied, or 0.
2000 * @return whether the attributes of this method can be copied from the attributes of the
2001 * method_info JVMS structure in 'source.b', between 'methodInfoOffset' and 'methodInfoOffset'
2002 * + 'methodInfoLength'.
2003 */
2004 boolean canCopyMethodAttributes(
2005 final ClassReader source,
2006 final int methodInfoOffset,
2007 final int methodInfoLength,
2008 final boolean hasSyntheticAttribute,
2009 final boolean hasDeprecatedAttribute,
2010 final int signatureIndex,
2011 final int exceptionsOffset) {
2012 if (source != symbolTable.getSource()
2013 || signatureIndex != this.signatureIndex
2014 || hasDeprecatedAttribute != ((accessFlags & Opcodes.ACC_DEPRECATED) != 0)) {
2015 return false;
2016 }
2017 boolean needSyntheticAttribute =
2018 symbolTable.getMajorVersion() < Opcodes.V1_5 && (accessFlags & Opcodes.ACC_SYNTHETIC) != 0;
2019 if (hasSyntheticAttribute != needSyntheticAttribute) {
2020 return false;
2021 }
2022 if (exceptionsOffset == 0) {
2023 if (numberOfExceptions != 0) {
2024 return false;
2025 }
2026 } else if (source.readUnsignedShort(exceptionsOffset) == numberOfExceptions) {
2027 int currentExceptionOffset = exceptionsOffset + 2;
2028 for (int i = 0; i < numberOfExceptions; ++i) {
2029 if (source.readUnsignedShort(currentExceptionOffset) != exceptionIndexTable[i]) {
2030 return false;
2031 }
2032 currentExceptionOffset += 2;
2033 }
2034 }
2035 // Don't copy the attributes yet, instead store their location in the source class reader so
2036 // they can be copied later, in {@link #putMethodInfo}. Note that we skip the 6 header bytes
2037 // of the method_info JVMS structure.
2038 this.sourceOffset = methodInfoOffset + 6;
2039 this.sourceLength = methodInfoLength - 6;
2040 return true;
2041 }
2042
2043 /**
2044 * Returns the size of the method_info JVMS structure generated by this MethodWriter. Also add the
2045 * names of the attributes of this method in the constant pool.
2046 *
2047 * @return the size in bytes of the method_info JVMS structure.
2048 */
2049 int computeMethodInfoSize() {
2050 // If this method_info must be copied from an existing one, the size computation is trivial.
2051 if (sourceOffset != 0) {
2052 // sourceLength excludes the first 6 bytes for access_flags, name_index and descriptor_index.
2053 return 6 + sourceLength;
2054 }
2055 // 2 bytes each for access_flags, name_index, descriptor_index and attributes_count.
2056 int size = 8;
2057 // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS.
2058 if (code.length > 0) {
2059 if (code.length > 65535) {
2060 throw new IndexOutOfBoundsException("Method code too large!");
2061 }
2062 symbolTable.addConstantUtf8(Constants.CODE);
2063 // The Code attribute has 6 header bytes, plus 2, 2, 4 and 2 bytes respectively for max_stack,
2064 // max_locals, code_length and attributes_count, plus the bytecode and the exception table.
2065 size += 16 + code.length + Handler.getExceptionTableSize(firstHandler);
2066 if (stackMapTableEntries != null) {
2067 boolean useStackMapTable = symbolTable.getMajorVersion() >= Opcodes.V1_6;
2068 symbolTable.addConstantUtf8(useStackMapTable ? Constants.STACK_MAP_TABLE : "StackMap");
2069 // 6 header bytes and 2 bytes for number_of_entries.
2070 size += 8 + stackMapTableEntries.length;
2071 }
2072 if (lineNumberTable != null) {
2073 symbolTable.addConstantUtf8(Constants.LINE_NUMBER_TABLE);
2074 // 6 header bytes and 2 bytes for line_number_table_length.
2075 size += 8 + lineNumberTable.length;
2076 }
2077 if (localVariableTable != null) {
2078 symbolTable.addConstantUtf8(Constants.LOCAL_VARIABLE_TABLE);
2079 // 6 header bytes and 2 bytes for local_variable_table_length.
2080 size += 8 + localVariableTable.length;
2081 }
2082 if (localVariableTypeTable != null) {
2083 symbolTable.addConstantUtf8(Constants.LOCAL_VARIABLE_TYPE_TABLE);
2084 // 6 header bytes and 2 bytes for local_variable_type_table_length.
2085 size += 8 + localVariableTypeTable.length;
2086 }
2087 if (lastCodeRuntimeVisibleTypeAnnotation != null) {
2088 size +=
2089 lastCodeRuntimeVisibleTypeAnnotation.computeAnnotationsSize(
2090 Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS);
2091 }
2092 if (lastCodeRuntimeInvisibleTypeAnnotation != null) {
2093 size +=
2094 lastCodeRuntimeInvisibleTypeAnnotation.computeAnnotationsSize(
2095 Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS);
2096 }
2097 if (firstCodeAttribute != null) {
2098 size +=
2099 firstCodeAttribute.computeAttributesSize(
2100 symbolTable, code.data, code.length, maxStack, maxLocals);
2101 }
2102 }
2103 if (numberOfExceptions > 0) {
2104 symbolTable.addConstantUtf8(Constants.EXCEPTIONS);
2105 size += 8 + 2 * numberOfExceptions;
2106 }
2107 boolean useSyntheticAttribute = symbolTable.getMajorVersion() < Opcodes.V1_5;
2108 if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 && useSyntheticAttribute) {
2109 symbolTable.addConstantUtf8(Constants.SYNTHETIC);
2110 size += 6;
2111 }
2112 if (signatureIndex != 0) {
2113 symbolTable.addConstantUtf8(Constants.SIGNATURE);
2114 size += 8;
2115 }
2116 if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) {
2117 symbolTable.addConstantUtf8(Constants.DEPRECATED);
2118 size += 6;
2119 }
2120 if (lastRuntimeVisibleAnnotation != null) {
2121 size +=
2122 lastRuntimeVisibleAnnotation.computeAnnotationsSize(
2123 Constants.RUNTIME_VISIBLE_ANNOTATIONS);
2124 }
2125 if (lastRuntimeInvisibleAnnotation != null) {
2126 size +=
2127 lastRuntimeInvisibleAnnotation.computeAnnotationsSize(
2128 Constants.RUNTIME_INVISIBLE_ANNOTATIONS);
2129 }
2130 if (lastRuntimeVisibleParameterAnnotations != null) {
2131 size +=
2132 AnnotationWriter.computeParameterAnnotationsSize(
2133 Constants.RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS,
2134 lastRuntimeVisibleParameterAnnotations,
2135 visibleAnnotableParameterCount == 0
2136 ? lastRuntimeVisibleParameterAnnotations.length
2137 : visibleAnnotableParameterCount);
2138 }
2139 if (lastRuntimeInvisibleParameterAnnotations != null) {
2140 size +=
2141 AnnotationWriter.computeParameterAnnotationsSize(
2142 Constants.RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS,
2143 lastRuntimeInvisibleParameterAnnotations,
2144 invisibleAnnotableParameterCount == 0
2145 ? lastRuntimeInvisibleParameterAnnotations.length
2146 : invisibleAnnotableParameterCount);
2147 }
2148 if (lastRuntimeVisibleTypeAnnotation != null) {
2149 size +=
2150 lastRuntimeVisibleTypeAnnotation.computeAnnotationsSize(
2151 Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS);
2152 }
2153 if (lastRuntimeInvisibleTypeAnnotation != null) {
2154 size +=
2155 lastRuntimeInvisibleTypeAnnotation.computeAnnotationsSize(
2156 Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS);
2157 }
2158 if (defaultValue != null) {
2159 symbolTable.addConstantUtf8(Constants.ANNOTATION_DEFAULT);
2160 size += 6 + defaultValue.length;
2161 }
2162 if (parameters != null) {
2163 symbolTable.addConstantUtf8(Constants.METHOD_PARAMETERS);
2164 // 6 header bytes and 1 byte for parameters_count.
2165 size += 7 + parameters.length;
2166 }
2167 if (firstAttribute != null) {
2168 size += firstAttribute.computeAttributesSize(symbolTable);
2169 }
2170 return size;
2171 }
2172
2173 /**
2174 * Puts the content of the method_info JVMS structure generated by this MethodWriter into the
2175 * given ByteVector.
2176 *
2177 * @param output where the method_info structure must be put.
2178 */
2179 void putMethodInfo(final ByteVector output) {
2180 boolean useSyntheticAttribute = symbolTable.getMajorVersion() < Opcodes.V1_5;
2181 int mask = useSyntheticAttribute ? Opcodes.ACC_SYNTHETIC : 0;
2182 output.putShort(accessFlags & ~mask).putShort(nameIndex).putShort(descriptorIndex);
2183 // If this method_info must be copied from an existing one, copy it now and return early.
2184 if (sourceOffset != 0) {
2185 output.putByteArray(symbolTable.getSource().b, sourceOffset, sourceLength);
2186 return;
2187 }
2188 // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS.
2189 int attributeCount = 0;
2190 if (code.length > 0) {
2191 ++attributeCount;
2192 }
2193 if (numberOfExceptions > 0) {
2194 ++attributeCount;
2195 }
2196 if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 && useSyntheticAttribute) {
2197 ++attributeCount;
2198 }
2199 if (signatureIndex != 0) {
2200 ++attributeCount;
2201 }
2202 if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) {
2203 ++attributeCount;
2204 }
2205 if (lastRuntimeVisibleAnnotation != null) {
2206 ++attributeCount;
2207 }
2208 if (lastRuntimeInvisibleAnnotation != null) {
2209 ++attributeCount;
2210 }
2211 if (lastRuntimeVisibleParameterAnnotations != null) {
2212 ++attributeCount;
2213 }
2214 if (lastRuntimeInvisibleParameterAnnotations != null) {
2215 ++attributeCount;
2216 }
2217 if (lastRuntimeVisibleTypeAnnotation != null) {
2218 ++attributeCount;
2219 }
2220 if (lastRuntimeInvisibleTypeAnnotation != null) {
2221 ++attributeCount;
2222 }
2223 if (defaultValue != null) {
2224 ++attributeCount;
2225 }
2226 if (parameters != null) {
2227 ++attributeCount;
2228 }
2229 if (firstAttribute != null) {
2230 attributeCount += firstAttribute.getAttributeCount();
2231 }
2232 // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS.
2233 output.putShort(attributeCount);
2234 if (code.length > 0) {
2235 // 2, 2, 4 and 2 bytes respectively for max_stack, max_locals, code_length and
2236 // attributes_count, plus the bytecode and the exception table.
2237 int size = 10 + code.length + Handler.getExceptionTableSize(firstHandler);
2238 int codeAttributeCount = 0;
2239 if (stackMapTableEntries != null) {
2240 // 6 header bytes and 2 bytes for number_of_entries.
2241 size += 8 + stackMapTableEntries.length;
2242 ++codeAttributeCount;
2243 }
2244 if (lineNumberTable != null) {
2245 // 6 header bytes and 2 bytes for line_number_table_length.
2246 size += 8 + lineNumberTable.length;
2247 ++codeAttributeCount;
2248 }
2249 if (localVariableTable != null) {
2250 // 6 header bytes and 2 bytes for local_variable_table_length.
2251 size += 8 + localVariableTable.length;
2252 ++codeAttributeCount;
2253 }
2254 if (localVariableTypeTable != null) {
2255 // 6 header bytes and 2 bytes for local_variable_type_table_length.
2256 size += 8 + localVariableTypeTable.length;
2257 ++codeAttributeCount;
2258 }
2259 if (lastCodeRuntimeVisibleTypeAnnotation != null) {
2260 size +=
2261 lastCodeRuntimeVisibleTypeAnnotation.computeAnnotationsSize(
2262 Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS);
2263 ++codeAttributeCount;
2264 }
2265 if (lastCodeRuntimeInvisibleTypeAnnotation != null) {
2266 size +=
2267 lastCodeRuntimeInvisibleTypeAnnotation.computeAnnotationsSize(
2268 Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS);
2269 ++codeAttributeCount;
2270 }
2271 if (firstCodeAttribute != null) {
2272 size +=
2273 firstCodeAttribute.computeAttributesSize(
2274 symbolTable, code.data, code.length, maxStack, maxLocals);
2275 codeAttributeCount += firstCodeAttribute.getAttributeCount();
2276 }
2277 output
2278 .putShort(symbolTable.addConstantUtf8(Constants.CODE))
2279 .putInt(size)
2280 .putShort(maxStack)
2281 .putShort(maxLocals)
2282 .putInt(code.length)
2283 .putByteArray(code.data, 0, code.length);
2284 Handler.putExceptionTable(firstHandler, output);
2285 output.putShort(codeAttributeCount);
2286 if (stackMapTableEntries != null) {
2287 boolean useStackMapTable = symbolTable.getMajorVersion() >= Opcodes.V1_6;
2288 output
2289 .putShort(
2290 symbolTable.addConstantUtf8(
2291 useStackMapTable ? Constants.STACK_MAP_TABLE : "StackMap"))
2292 .putInt(2 + stackMapTableEntries.length)
2293 .putShort(stackMapTableNumberOfEntries)
2294 .putByteArray(stackMapTableEntries.data, 0, stackMapTableEntries.length);
2295 }
2296 if (lineNumberTable != null) {
2297 output
2298 .putShort(symbolTable.addConstantUtf8(Constants.LINE_NUMBER_TABLE))
2299 .putInt(2 + lineNumberTable.length)
2300 .putShort(lineNumberTableLength)
2301 .putByteArray(lineNumberTable.data, 0, lineNumberTable.length);
2302 }
2303 if (localVariableTable != null) {
2304 output
2305 .putShort(symbolTable.addConstantUtf8(Constants.LOCAL_VARIABLE_TABLE))
2306 .putInt(2 + localVariableTable.length)
2307 .putShort(localVariableTableLength)
2308 .putByteArray(localVariableTable.data, 0, localVariableTable.length);
2309 }
2310 if (localVariableTypeTable != null) {
2311 output
2312 .putShort(symbolTable.addConstantUtf8(Constants.LOCAL_VARIABLE_TYPE_TABLE))
2313 .putInt(2 + localVariableTypeTable.length)
2314 .putShort(localVariableTypeTableLength)
2315 .putByteArray(localVariableTypeTable.data, 0, localVariableTypeTable.length);
2316 }
2317 if (lastCodeRuntimeVisibleTypeAnnotation != null) {
2318 lastCodeRuntimeVisibleTypeAnnotation.putAnnotations(
2319 symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS), output);
2320 }
2321 if (lastCodeRuntimeInvisibleTypeAnnotation != null) {
2322 lastCodeRuntimeInvisibleTypeAnnotation.putAnnotations(
2323 symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS), output);
2324 }
2325 if (firstCodeAttribute != null) {
2326 firstCodeAttribute.putAttributes(
2327 symbolTable, code.data, code.length, maxStack, maxLocals, output);
2328 }
2329 }
2330 if (numberOfExceptions > 0) {
2331 output
2332 .putShort(symbolTable.addConstantUtf8(Constants.EXCEPTIONS))
2333 .putInt(2 + 2 * numberOfExceptions)
2334 .putShort(numberOfExceptions);
2335 for (int exceptionIndex : exceptionIndexTable) {
2336 output.putShort(exceptionIndex);
2337 }
2338 }
2339 if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 && useSyntheticAttribute) {
2340 output.putShort(symbolTable.addConstantUtf8(Constants.SYNTHETIC)).putInt(0);
2341 }
2342 if (signatureIndex != 0) {
2343 output
2344 .putShort(symbolTable.addConstantUtf8(Constants.SIGNATURE))
2345 .putInt(2)
2346 .putShort(signatureIndex);
2347 }
2348 if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) {
2349 output.putShort(symbolTable.addConstantUtf8(Constants.DEPRECATED)).putInt(0);
2350 }
2351 if (lastRuntimeVisibleAnnotation != null) {
2352 lastRuntimeVisibleAnnotation.putAnnotations(
2353 symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_ANNOTATIONS), output);
2354 }
2355 if (lastRuntimeInvisibleAnnotation != null) {
2356 lastRuntimeInvisibleAnnotation.putAnnotations(
2357 symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_ANNOTATIONS), output);
2358 }
2359 if (lastRuntimeVisibleParameterAnnotations != null) {
2360 AnnotationWriter.putParameterAnnotations(
2361 symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS),
2362 lastRuntimeVisibleParameterAnnotations,
2363 visibleAnnotableParameterCount == 0
2364 ? lastRuntimeVisibleParameterAnnotations.length
2365 : visibleAnnotableParameterCount,
2366 output);
2367 }
2368 if (lastRuntimeInvisibleParameterAnnotations != null) {
2369 AnnotationWriter.putParameterAnnotations(
2370 symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS),
2371 lastRuntimeInvisibleParameterAnnotations,
2372 invisibleAnnotableParameterCount == 0
2373 ? lastRuntimeInvisibleParameterAnnotations.length
2374 : invisibleAnnotableParameterCount,
2375 output);
2376 }
2377 if (lastRuntimeVisibleTypeAnnotation != null) {
2378 lastRuntimeVisibleTypeAnnotation.putAnnotations(
2379 symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS), output);
2380 }
2381 if (lastRuntimeInvisibleTypeAnnotation != null) {
2382 lastRuntimeInvisibleTypeAnnotation.putAnnotations(
2383 symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS), output);
2384 }
2385 if (defaultValue != null) {
2386 output
2387 .putShort(symbolTable.addConstantUtf8(Constants.ANNOTATION_DEFAULT))
2388 .putInt(defaultValue.length)
2389 .putByteArray(defaultValue.data, 0, defaultValue.length);
2390 }
2391 if (parameters != null) {
2392 output
2393 .putShort(symbolTable.addConstantUtf8(Constants.METHOD_PARAMETERS))
2394 .putInt(1 + parameters.length)
2395 .putByte(parametersCount)
2396 .putByteArray(parameters.data, 0, parameters.length);
2397 }
2398 if (firstAttribute != null) {
2399 firstAttribute.putAttributes(symbolTable, output);
2400 }
2401 }
2402
2403 /**
2404 * Collects the attributes of this method into the given set of attribute prototypes.
2405 *
2406 * @param attributePrototypes a set of attribute prototypes.
2407 */
2408 final void collectAttributePrototypes(final Attribute.Set attributePrototypes) {
2409 attributePrototypes.addAttributes(firstAttribute);
2410 attributePrototypes.addAttributes(firstCodeAttribute);
2411 }
29142412 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
3027 package org.eclipse.persistence.internal.libraries.asm;
3128
3229 /**
33 * A visitor to visit a Java module. The methods of this class must be called in
34 * the following order: ( <tt>visitRequire</tt> | <tt>visitExport</tt> |
35 * <tt>visitUse</tt> | <tt>visitProvide</tt> )* <tt>visitEnd</tt>.
36 *
30 * A visitor to visit a Java module. The methods of this class must be called in the following
31 * order: <tt>visitMainClass</tt> | ( <tt>visitPackage</tt> | <tt>visitRequire</tt> |
32 * <tt>visitExport</tt> | <tt>visitOpen</tt> | <tt>visitUse</tt> | <tt>visitProvide</tt> )*
33 * <tt>visitEnd</tt>.
34 *
3735 * @author Remi Forax
36 * @author Eric Bruneton
3837 */
3938 public abstract class ModuleVisitor {
40 /**
41 * The ASM API version implemented by this visitor. The value of this field
42 * must be {@link Opcodes#ASM6}.
43 */
44 protected final int api;
45
46 /**
47 * The module visitor to which this visitor must delegate method calls. May
48 * be null.
49 */
50 protected ModuleVisitor mv;
51
52
53 public ModuleVisitor(final int api) {
54 this(api, null);
39 /**
40 * The ASM API version implemented by this visitor. The value of this field must be one of {@link
41 * Opcodes#ASM6} or {@link Opcodes#ASM7_EXPERIMENTAL}.
42 */
43 protected final int api;
44
45 /** The module visitor to which this visitor must delegate method calls. May be null. */
46 protected ModuleVisitor mv;
47
48 /**
49 * Constructs a new {@link ModuleVisitor}.
50 *
51 * @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM6}
52 * or {@link Opcodes#ASM7_EXPERIMENTAL}.
53 */
54 public ModuleVisitor(final int api) {
55 this(api, null);
56 }
57
58 /**
59 * Constructs a new {@link ModuleVisitor}.
60 *
61 * @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM6}
62 * or {@link Opcodes#ASM7_EXPERIMENTAL}.
63 * @param moduleVisitor the module visitor to which this visitor must delegate method calls. May
64 * be null.
65 */
66 public ModuleVisitor(final int api, final ModuleVisitor moduleVisitor) {
67 if (api != Opcodes.ASM6 && api != Opcodes.ASM7_EXPERIMENTAL) {
68 throw new IllegalArgumentException();
5569 }
70 this.api = api;
71 this.mv = moduleVisitor;
72 }
5673
57 /**
58 * Constructs a new {@link MethodVisitor}.
59 *
60 * @param api
61 * the ASM API version implemented by this visitor. Must be {@link Opcodes#ASM6}.
62 * @param mv
63 * the method visitor to which this visitor must delegate method
64 * calls. May be null.
65 */
66 public ModuleVisitor(final int api, final ModuleVisitor mv) {
67 if (api != Opcodes.ASM6) {
68 throw new IllegalArgumentException();
69 }
70 this.api = api;
71 this.mv = mv;
74 /**
75 * Visit the main class of the current module.
76 *
77 * @param mainClass the internal name of the main class of the current module.
78 */
79 public void visitMainClass(final String mainClass) {
80 if (mv != null) {
81 mv.visitMainClass(mainClass);
7282 }
73
74 /**
75 * Visits a dependence of the current module.
76 *
77 * @param module the module name of the dependence
78 * @param access the access flag of the dependence among
79 * ACC_PUBLIC, ACC_SYNTHETIC and ACC_MANDATED.
80 */
81 public void visitRequire(String module, int access) {
82 if (mv != null) {
83 mv.visitRequire(module, access);
84 }
83 }
84
85 /**
86 * Visit a package of the current module.
87 *
88 * @param packaze the internal name of a package.
89 */
90 public void visitPackage(final String packaze) {
91 if (mv != null) {
92 mv.visitPackage(packaze);
8593 }
86
87 /**
88 * Visit an exported package of the current module.
89 *
90 * @param packaze the name of the exported package.
91 * @param modules names of the modules that can access to
92 * the public classes of the exported package or
93 * <tt>null</tt>.
94 */
95 public void visitExport(String packaze, String... modules) {
96 if (mv != null) {
97 mv.visitExport(packaze, modules);
98 }
94 }
95
96 /**
97 * Visits a dependence of the current module.
98 *
99 * @param module the fully qualified name (using dots) of the dependence.
100 * @param access the access flag of the dependence among {@code ACC_TRANSITIVE}, {@code
101 * ACC_STATIC_PHASE}, {@code ACC_SYNTHETIC} and {@code ACC_MANDATED}.
102 * @param version the module version at compile time, or <tt>null</tt>.
103 */
104 public void visitRequire(final String module, final int access, final String version) {
105 if (mv != null) {
106 mv.visitRequire(module, access, version);
99107 }
100
101 /**
102 * Visit a service used by the current module.
103 * The name must be the name of an interface or an
104 * abstract class.
105 *
106 * @param service the internal name of the service.
107 */
108 public void visitUse(String service) {
109 if (mv != null) {
110 mv.visitUse(service);
111 }
108 }
109
110 /**
111 * Visit an exported package of the current module.
112 *
113 * @param packaze the internal name of the exported package.
114 * @param access the access flag of the exported package, valid values are among {@code
115 * ACC_SYNTHETIC} and {@code ACC_MANDATED}.
116 * @param modules the fully qualified names (using dots) of the modules that can access the public
117 * classes of the exported package, or <tt>null</tt>.
118 */
119 public void visitExport(final String packaze, final int access, final String... modules) {
120 if (mv != null) {
121 mv.visitExport(packaze, access, modules);
112122 }
113
114 /**
115 * Visit an implementation of a service.
116 *
117 * @param service the internal name of the service
118 * @param impl the internal name of the implementation
119 * of the service
120 */
121 public void visitProvide(String service, String impl) {
122 if (mv != null) {
123 mv.visitProvide(service, impl);
124 }
123 }
124
125 /**
126 * Visit an open package of the current module.
127 *
128 * @param packaze the internal name of the opened package.
129 * @param access the access flag of the opened package, valid values are among {@code
130 * ACC_SYNTHETIC} and {@code ACC_MANDATED}.
131 * @param modules the fully qualified names (using dots) of the modules that can use deep
132 * reflection to the classes of the open package, or <tt>null</tt>.
133 */
134 public void visitOpen(final String packaze, final int access, final String... modules) {
135 if (mv != null) {
136 mv.visitOpen(packaze, access, modules);
125137 }
126
127 public void visitEnd() {
128 if (mv != null) {
129 mv.visitEnd();
130 }
138 }
139
140 /**
141 * Visit a service used by the current module. The name must be the internal name of an interface
142 * or a class.
143 *
144 * @param service the internal name of the service.
145 */
146 public void visitUse(final String service) {
147 if (mv != null) {
148 mv.visitUse(service);
131149 }
150 }
151
152 /**
153 * Visit an implementation of a service.
154 *
155 * @param service the internal name of the service.
156 * @param providers the internal names of the implementations of the service (there is at least
157 * one provider).
158 */
159 public void visitProvide(final String service, final String... providers) {
160 if (mv != null) {
161 mv.visitProvide(service, providers);
162 }
163 }
164
165 /**
166 * Visits the end of the module. This method, which is the last one to be called, is used to
167 * inform the visitor that everything have been visited.
168 */
169 public void visitEnd() {
170 if (mv != null) {
171 mv.visitEnd();
172 }
173 }
132174 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
27 package org.eclipse.persistence.internal.libraries.asm;
28
29 /**
30 * A {@link ModuleVisitor} that generates the corresponding Module, ModulePackages and
31 * ModuleMainClass attributes, as defined in the Java Virtual Machine Specification (JVMS).
432 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 package org.eclipse.persistence.internal.libraries.asm;
31
32 /**
33 * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.25">JVMS
34 * 4.7.25</a>
35 * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.26">JVMS
36 * 4.7.26</a>
37 * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.27">JVMS
38 * 4.7.27</a>
3339 * @author Remi Forax
40 * @author Eric Bruneton
3441 */
3542 final class ModuleWriter extends ModuleVisitor {
36 /**
37 * The class writer to which this Module attribute must be added.
38 */
39 private final ClassWriter cw;
40
41 /**
42 * size in byte of the corresponding Module attribute.
43 */
44 private int size;
45
46 /**
47 * number of requires items
48 */
49 private int requireCount;
50
51 /**
52 * The requires items in bytecode form. This byte vector only contains
53 * the items themselves, the number of items is store in requireCount
54 */
55 private ByteVector requires;
56
57 /**
58 * number of exports items
59 */
60 private int exportCount;
61
62 /**
63 * The exports items in bytecode form. This byte vector only contains
64 * the items themselves, the number of items is store in exportCount
65 */
66 private ByteVector exports;
67
68 /**
69 * number of uses items
70 */
71 private int useCount;
72
73 /**
74 * The uses items in bytecode form. This byte vector only contains
75 * the items themselves, the number of items is store in useCount
76 */
77 private ByteVector uses;
78
79 /**
80 * number of provides items
81 */
82 private int provideCount;
83
84 /**
85 * The uses provides in bytecode form. This byte vector only contains
86 * the items themselves, the number of items is store in provideCount
87 */
88 private ByteVector provides;
89
90 ModuleWriter(final ClassWriter cw) {
91 super(Opcodes.ASM6);
92 this.cw = cw;
93 this.size = 8;
94 }
95
96 @Override
97 public void visitRequire(String module, int access) {
98 if (requires == null) {
99 requires = new ByteVector();
100 }
101 //FIXME fix bad ACC_PUBLIC value (0x0020)
102 if ((access & Opcodes.ACC_PUBLIC) != 0) {
103 access = access & ~ Opcodes.ACC_PUBLIC | 0x0020;
104 }
105 requires.putShort(cw.newUTF8(module)).putShort(access);
106 requireCount++;
107 size += 4;
108 }
109
110 @Override
111 public void visitExport(String packaze, String... modules) {
112 if (exports == null) {
113 exports = new ByteVector();
114 }
115 exports.putShort(cw.newUTF8(packaze));
116 if (modules == null) {
117 exports.putShort(0);
118 size += 4;
119 } else {
120 exports.putShort(modules.length);
121 for(String to: modules) {
122 exports.putShort(cw.newUTF8(to));
123 }
124 size += 4 + 2 * modules.length;
125 }
126 exportCount++;
127 }
128
129 @Override
130 public void visitUse(String service) {
131 if (uses == null) {
132 uses = new ByteVector();
133 }
134 uses.putShort(cw.newClass(service));
135 useCount++;
136 size += 2;
137 }
138
139 @Override
140 public void visitProvide(String service, String impl) {
141 if (provides == null) {
142 provides = new ByteVector();
143 }
144 provides.putShort(cw.newClass(service)).putShort(cw.newClass(impl));
145 provideCount++;
146 size += 4;
147 }
148
149 @Override
150 public void visitEnd() {
151 // empty
152 }
153
154 int getSize() {
155 return size;
156 }
157
158 void put(ByteVector out) {
159 out.putInt(size);
160 out.putShort(requireCount);
161 if (requires != null) {
162 out.putByteArray(requires.data, 0, requires.length);
163 }
164 out.putShort(exportCount);
165 if (exports != null) {
166 out.putByteArray(exports.data, 0, exports.length);
167 }
168 out.putShort(useCount);
169 if (uses != null) {
170 out.putByteArray(uses.data, 0, uses.length);
171 }
172 out.putShort(provideCount);
173 if (provides != null) {
174 out.putByteArray(provides.data, 0, provides.length);
175 }
176 }
43
44 /** Where the constants used in this AnnotationWriter must be stored. */
45 private final SymbolTable symbolTable;
46
47 /** The module_name_index field of the JVMS Module attribute. */
48 private final int moduleNameIndex;
49
50 /** The module_flags field of the JVMS Module attribute. */
51 private final int moduleFlags;
52
53 /** The module_version_index field of the JVMS Module attribute. */
54 private final int moduleVersionIndex;
55
56 /** The requires_count field of the JVMS Module attribute. */
57 private int requiresCount;
58
59 /** The binary content of the 'requires' array of the JVMS Module attribute. */
60 private final ByteVector requires;
61
62 /** The exports_count field of the JVMS Module attribute. */
63 private int exportsCount;
64
65 /** The binary content of the 'exports' array of the JVMS Module attribute. */
66 private final ByteVector exports;
67
68 /** The opens_count field of the JVMS Module attribute. */
69 private int opensCount;
70
71 /** The binary content of the 'opens' array of the JVMS Module attribute. */
72 private final ByteVector opens;
73
74 /** The uses_count field of the JVMS Module attribute. */
75 private int usesCount;
76
77 /** The binary content of the 'uses_index' array of the JVMS Module attribute. */
78 private final ByteVector usesIndex;
79
80 /** The provides_count field of the JVMS Module attribute. */
81 private int providesCount;
82
83 /** The binary content of the 'provides' array of the JVMS Module attribute. */
84 private final ByteVector provides;
85
86 /** The provides_count field of the JVMS ModulePackages attribute. */
87 private int packageCount;
88
89 /** The binary content of the 'package_index' array of the JVMS ModulePackages attribute. */
90 private final ByteVector packageIndex;
91
92 /** The main_class_index field of the JVMS ModuleMainClass attribute, or 0. */
93 private int mainClassIndex;
94
95 ModuleWriter(final SymbolTable symbolTable, final int name, final int access, final int version) {
96 super(Opcodes.ASM6);
97 this.symbolTable = symbolTable;
98 this.moduleNameIndex = name;
99 this.moduleFlags = access;
100 this.moduleVersionIndex = version;
101 this.requires = new ByteVector();
102 this.exports = new ByteVector();
103 this.opens = new ByteVector();
104 this.usesIndex = new ByteVector();
105 this.provides = new ByteVector();
106 this.packageIndex = new ByteVector();
107 }
108
109 @Override
110 public void visitMainClass(final String mainClass) {
111 this.mainClassIndex = symbolTable.addConstantClass(mainClass).index;
112 }
113
114 @Override
115 public void visitPackage(final String packaze) {
116 packageIndex.putShort(symbolTable.addConstantPackage(packaze).index);
117 packageCount++;
118 }
119
120 @Override
121 public void visitRequire(final String module, final int access, final String version) {
122 requires
123 .putShort(symbolTable.addConstantModule(module).index)
124 .putShort(access)
125 .putShort(version == null ? 0 : symbolTable.addConstantUtf8(version));
126 requiresCount++;
127 }
128
129 @Override
130 public void visitExport(final String packaze, final int access, final String... modules) {
131 exports.putShort(symbolTable.addConstantPackage(packaze).index).putShort(access);
132 if (modules == null) {
133 exports.putShort(0);
134 } else {
135 exports.putShort(modules.length);
136 for (String module : modules) {
137 exports.putShort(symbolTable.addConstantModule(module).index);
138 }
139 }
140 exportsCount++;
141 }
142
143 @Override
144 public void visitOpen(final String packaze, final int access, final String... modules) {
145 opens.putShort(symbolTable.addConstantPackage(packaze).index).putShort(access);
146 if (modules == null) {
147 opens.putShort(0);
148 } else {
149 opens.putShort(modules.length);
150 for (String module : modules) {
151 opens.putShort(symbolTable.addConstantModule(module).index);
152 }
153 }
154 opensCount++;
155 }
156
157 @Override
158 public void visitUse(final String service) {
159 usesIndex.putShort(symbolTable.addConstantClass(service).index);
160 usesCount++;
161 }
162
163 @Override
164 public void visitProvide(final String service, final String... providers) {
165 provides.putShort(symbolTable.addConstantClass(service).index);
166 provides.putShort(providers.length);
167 for (String provider : providers) {
168 provides.putShort(symbolTable.addConstantClass(provider).index);
169 }
170 providesCount++;
171 }
172
173 @Override
174 public void visitEnd() {
175 // Nothing to do.
176 }
177
178 /**
179 * Returns the number of Module, ModulePackages and ModuleMainClass attributes generated by this
180 * ModuleWriter.
181 *
182 * @return the number of Module, ModulePackages and ModuleMainClass attributes (between 1 and 3).
183 */
184 int getAttributeCount() {
185 return 1 + (packageCount > 0 ? 1 : 0) + (mainClassIndex > 0 ? 1 : 0);
186 }
187
188 /**
189 * Returns the size of the Module, ModulePackages and ModuleMainClass attributes generated by this
190 * ModuleWriter. Also add the names of these attributes in the constant pool.
191 *
192 * @return the size in bytes of the Module, ModulePackages and ModuleMainClass attributes.
193 */
194 int computeAttributesSize() {
195 symbolTable.addConstantUtf8(Constants.MODULE);
196 // 6 attribute header bytes, 6 bytes for name, flags and version, and 5 * 2 bytes for counts.
197 int size =
198 22 + requires.length + exports.length + opens.length + usesIndex.length + provides.length;
199 if (packageCount > 0) {
200 symbolTable.addConstantUtf8(Constants.MODULE_PACKAGES);
201 // 6 attribute header bytes, and 2 bytes for package_count.
202 size += 8 + packageIndex.length;
203 }
204 if (mainClassIndex > 0) {
205 symbolTable.addConstantUtf8(Constants.MODULE_MAIN_CLASS);
206 // 6 attribute header bytes, and 2 bytes for main_class_index.
207 size += 8;
208 }
209 return size;
210 }
211
212 /**
213 * Puts the Module, ModulePackages and ModuleMainClass attributes generated by this ModuleWriter
214 * in the given ByteVector.
215 *
216 * @param output where the attributes must be put.
217 */
218 void putAttributes(final ByteVector output) {
219 // 6 bytes for name, flags and version, and 5 * 2 bytes for counts.
220 int moduleAttributeLength =
221 16 + requires.length + exports.length + opens.length + usesIndex.length + provides.length;
222 output
223 .putShort(symbolTable.addConstantUtf8(Constants.MODULE))
224 .putInt(moduleAttributeLength)
225 .putShort(moduleNameIndex)
226 .putShort(moduleFlags)
227 .putShort(moduleVersionIndex)
228 .putShort(requiresCount)
229 .putByteArray(requires.data, 0, requires.length)
230 .putShort(exportsCount)
231 .putByteArray(exports.data, 0, exports.length)
232 .putShort(opensCount)
233 .putByteArray(opens.data, 0, opens.length)
234 .putShort(usesCount)
235 .putByteArray(usesIndex.data, 0, usesIndex.length)
236 .putShort(providesCount)
237 .putByteArray(provides.data, 0, provides.length);
238 if (packageCount > 0) {
239 output
240 .putShort(symbolTable.addConstantUtf8(Constants.MODULE_PACKAGES))
241 .putInt(2 + packageIndex.length)
242 .putShort(packageCount)
243 .putByteArray(packageIndex.data, 0, packageIndex.length);
244 }
245 if (mainClassIndex > 0) {
246 output
247 .putShort(symbolTable.addConstantUtf8(Constants.MODULE_MAIN_CLASS))
248 .putInt(2)
249 .putShort(mainClassIndex);
250 }
251 }
177252 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
27 package org.eclipse.persistence.internal.libraries.asm;
28
29 /**
30 * The JVM opcodes, access flags and array type codes. This interface does not define all the JVM
31 * opcodes because some opcodes are automatically handled. For example, the xLOAD and xSTORE opcodes
32 * are automatically replaced by xLOAD_n and xSTORE_n opcodes when possible. The xLOAD_n and
33 * xSTORE_n opcodes are therefore not defined in this interface. Likewise for LDC, automatically
34 * replaced by LDC_W or LDC2_W when necessary, WIDE, GOTO_W and JSR_W.
435 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 package org.eclipse.persistence.internal.libraries.asm;
30
31 /**
32 * Defines the JVM opcodes, access flags and array type codes. This interface
33 * does not define all the JVM opcodes because some opcodes are automatically
34 * handled. For example, the xLOAD and xSTORE opcodes are automatically replaced
35 * by xLOAD_n and xSTORE_n opcodes when possible. The xLOAD_n and xSTORE_n
36 * opcodes are therefore not defined in this interface. Likewise for LDC,
37 * automatically replaced by LDC_W or LDC2_W when necessary, WIDE, GOTO_W and
38 * JSR_W.
39 *
36 * @see <a href="https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-6.html">JVMS 6</a>
4037 * @author Eric Bruneton
4138 * @author Eugene Kuleshov
4239 */
4340 public interface Opcodes {
4441
45 // ASM API versions
46
47 int ASM4 = 4 << 16 | 0 << 8 | 0;
48 int ASM5 = 5 << 16 | 0 << 8 | 0;
49 int ASM6 = 6 << 16 | 0 << 8 | 0;
50
51 // versions
52
53 int V1_1 = 3 << 16 | 45;
54 int V1_2 = 0 << 16 | 46;
55 int V1_3 = 0 << 16 | 47;
56 int V1_4 = 0 << 16 | 48;
57 int V1_5 = 0 << 16 | 49;
58 int V1_6 = 0 << 16 | 50;
59 int V1_7 = 0 << 16 | 51;
60 int V1_8 = 0 << 16 | 52;
61 int V1_9 = 0 << 16 | 53;
62
63 // access flags
64
65 int ACC_PUBLIC = 0x0001; // class, field, method
66 int ACC_PRIVATE = 0x0002; // class, field, method
67 int ACC_PROTECTED = 0x0004; // class, field, method
68 int ACC_STATIC = 0x0008; // field, method
69 int ACC_FINAL = 0x0010; // class, field, method, parameter
70 int ACC_SUPER = 0x0020; // class
71 int ACC_SYNCHRONIZED = 0x0020; // method
72 int ACC_VOLATILE = 0x0040; // field
73 int ACC_BRIDGE = 0x0040; // method
74 int ACC_VARARGS = 0x0080; // method
75 int ACC_TRANSIENT = 0x0080; // field
76 int ACC_NATIVE = 0x0100; // method
77 int ACC_INTERFACE = 0x0200; // class
78 int ACC_ABSTRACT = 0x0400; // class, method
79 int ACC_STRICT = 0x0800; // method
80 int ACC_SYNTHETIC = 0x1000; // class, field, method, parameter
81 int ACC_ANNOTATION = 0x2000; // class
82 int ACC_ENUM = 0x4000; // class(?) field inner
83 int ACC_MANDATED = 0x8000; // parameter
84 int ACC_MODULE = 0x8000; // class
85
86 // ASM specific pseudo access flags
87
88 int ACC_DEPRECATED = 0x20000; // class, field, method
89
90 // types for NEWARRAY
91
92 int T_BOOLEAN = 4;
93 int T_CHAR = 5;
94 int T_FLOAT = 6;
95 int T_DOUBLE = 7;
96 int T_BYTE = 8;
97 int T_SHORT = 9;
98 int T_INT = 10;
99 int T_LONG = 11;
100
101 // tags for Handle
102
103 int H_GETFIELD = 1;
104 int H_GETSTATIC = 2;
105 int H_PUTFIELD = 3;
106 int H_PUTSTATIC = 4;
107 int H_INVOKEVIRTUAL = 5;
108 int H_INVOKESTATIC = 6;
109 int H_INVOKESPECIAL = 7;
110 int H_NEWINVOKESPECIAL = 8;
111 int H_INVOKEINTERFACE = 9;
112
113 // stack map frame types
114
115 /**
116 * Represents an expanded frame. See {@link ClassReader#EXPAND_FRAMES}.
117 */
118 int F_NEW = -1;
119
120 /**
121 * Represents a compressed frame with complete frame data.
122 */
123 int F_FULL = 0;
124
125 /**
126 * Represents a compressed frame where locals are the same as the locals in
127 * the previous frame, except that additional 1-3 locals are defined, and
128 * with an empty stack.
129 */
130 int F_APPEND = 1;
131
132 /**
133 * Represents a compressed frame where locals are the same as the locals in
134 * the previous frame, except that the last 1-3 locals are absent and with
135 * an empty stack.
136 */
137 int F_CHOP = 2;
138
139 /**
140 * Represents a compressed frame with exactly the same locals as the
141 * previous frame and with an empty stack.
142 */
143 int F_SAME = 3;
144
145 /**
146 * Represents a compressed frame with exactly the same locals as the
147 * previous frame and with a single value on the stack.
148 */
149 int F_SAME1 = 4;
150
151 // Do not try to change the following code to use auto-boxing,
152 // these values are compared by reference and not by value
153 // The constructor of Integer was deprecated in 9
154 // but we are stuck with it by backward compatibility
155 @SuppressWarnings("deprecation") Integer TOP = new Integer(0);
156 @SuppressWarnings("deprecation") Integer INTEGER = new Integer(1);
157 @SuppressWarnings("deprecation") Integer FLOAT = new Integer(2);
158 @SuppressWarnings("deprecation") Integer DOUBLE = new Integer(3);
159 @SuppressWarnings("deprecation") Integer LONG = new Integer(4);
160 @SuppressWarnings("deprecation") Integer NULL = new Integer(5);
161 @SuppressWarnings("deprecation") Integer UNINITIALIZED_THIS = new Integer(6);
162
163 // opcodes // visit method (- = idem)
164
165 int NOP = 0; // visitInsn
166 int ACONST_NULL = 1; // -
167 int ICONST_M1 = 2; // -
168 int ICONST_0 = 3; // -
169 int ICONST_1 = 4; // -
170 int ICONST_2 = 5; // -
171 int ICONST_3 = 6; // -
172 int ICONST_4 = 7; // -
173 int ICONST_5 = 8; // -
174 int LCONST_0 = 9; // -
175 int LCONST_1 = 10; // -
176 int FCONST_0 = 11; // -
177 int FCONST_1 = 12; // -
178 int FCONST_2 = 13; // -
179 int DCONST_0 = 14; // -
180 int DCONST_1 = 15; // -
181 int BIPUSH = 16; // visitIntInsn
182 int SIPUSH = 17; // -
183 int LDC = 18; // visitLdcInsn
184 // int LDC_W = 19; // -
185 // int LDC2_W = 20; // -
186 int ILOAD = 21; // visitVarInsn
187 int LLOAD = 22; // -
188 int FLOAD = 23; // -
189 int DLOAD = 24; // -
190 int ALOAD = 25; // -
191 // int ILOAD_0 = 26; // -
192 // int ILOAD_1 = 27; // -
193 // int ILOAD_2 = 28; // -
194 // int ILOAD_3 = 29; // -
195 // int LLOAD_0 = 30; // -
196 // int LLOAD_1 = 31; // -
197 // int LLOAD_2 = 32; // -
198 // int LLOAD_3 = 33; // -
199 // int FLOAD_0 = 34; // -
200 // int FLOAD_1 = 35; // -
201 // int FLOAD_2 = 36; // -
202 // int FLOAD_3 = 37; // -
203 // int DLOAD_0 = 38; // -
204 // int DLOAD_1 = 39; // -
205 // int DLOAD_2 = 40; // -
206 // int DLOAD_3 = 41; // -
207 // int ALOAD_0 = 42; // -
208 // int ALOAD_1 = 43; // -
209 // int ALOAD_2 = 44; // -
210 // int ALOAD_3 = 45; // -
211 int IALOAD = 46; // visitInsn
212 int LALOAD = 47; // -
213 int FALOAD = 48; // -
214 int DALOAD = 49; // -
215 int AALOAD = 50; // -
216 int BALOAD = 51; // -
217 int CALOAD = 52; // -
218 int SALOAD = 53; // -
219 int ISTORE = 54; // visitVarInsn
220 int LSTORE = 55; // -
221 int FSTORE = 56; // -
222 int DSTORE = 57; // -
223 int ASTORE = 58; // -
224 // int ISTORE_0 = 59; // -
225 // int ISTORE_1 = 60; // -
226 // int ISTORE_2 = 61; // -
227 // int ISTORE_3 = 62; // -
228 // int LSTORE_0 = 63; // -
229 // int LSTORE_1 = 64; // -
230 // int LSTORE_2 = 65; // -
231 // int LSTORE_3 = 66; // -
232 // int FSTORE_0 = 67; // -
233 // int FSTORE_1 = 68; // -
234 // int FSTORE_2 = 69; // -
235 // int FSTORE_3 = 70; // -
236 // int DSTORE_0 = 71; // -
237 // int DSTORE_1 = 72; // -
238 // int DSTORE_2 = 73; // -
239 // int DSTORE_3 = 74; // -
240 // int ASTORE_0 = 75; // -
241 // int ASTORE_1 = 76; // -
242 // int ASTORE_2 = 77; // -
243 // int ASTORE_3 = 78; // -
244 int IASTORE = 79; // visitInsn
245 int LASTORE = 80; // -
246 int FASTORE = 81; // -
247 int DASTORE = 82; // -
248 int AASTORE = 83; // -
249 int BASTORE = 84; // -
250 int CASTORE = 85; // -
251 int SASTORE = 86; // -
252 int POP = 87; // -
253 int POP2 = 88; // -
254 int DUP = 89; // -
255 int DUP_X1 = 90; // -
256 int DUP_X2 = 91; // -
257 int DUP2 = 92; // -
258 int DUP2_X1 = 93; // -
259 int DUP2_X2 = 94; // -
260 int SWAP = 95; // -
261 int IADD = 96; // -
262 int LADD = 97; // -
263 int FADD = 98; // -
264 int DADD = 99; // -
265 int ISUB = 100; // -
266 int LSUB = 101; // -
267 int FSUB = 102; // -
268 int DSUB = 103; // -
269 int IMUL = 104; // -
270 int LMUL = 105; // -
271 int FMUL = 106; // -
272 int DMUL = 107; // -
273 int IDIV = 108; // -
274 int LDIV = 109; // -
275 int FDIV = 110; // -
276 int DDIV = 111; // -
277 int IREM = 112; // -
278 int LREM = 113; // -
279 int FREM = 114; // -
280 int DREM = 115; // -
281 int INEG = 116; // -
282 int LNEG = 117; // -
283 int FNEG = 118; // -
284 int DNEG = 119; // -
285 int ISHL = 120; // -
286 int LSHL = 121; // -
287 int ISHR = 122; // -
288 int LSHR = 123; // -
289 int IUSHR = 124; // -
290 int LUSHR = 125; // -
291 int IAND = 126; // -
292 int LAND = 127; // -
293 int IOR = 128; // -
294 int LOR = 129; // -
295 int IXOR = 130; // -
296 int LXOR = 131; // -
297 int IINC = 132; // visitIincInsn
298 int I2L = 133; // visitInsn
299 int I2F = 134; // -
300 int I2D = 135; // -
301 int L2I = 136; // -
302 int L2F = 137; // -
303 int L2D = 138; // -
304 int F2I = 139; // -
305 int F2L = 140; // -
306 int F2D = 141; // -
307 int D2I = 142; // -
308 int D2L = 143; // -
309 int D2F = 144; // -
310 int I2B = 145; // -
311 int I2C = 146; // -
312 int I2S = 147; // -
313 int LCMP = 148; // -
314 int FCMPL = 149; // -
315 int FCMPG = 150; // -
316 int DCMPL = 151; // -
317 int DCMPG = 152; // -
318 int IFEQ = 153; // visitJumpInsn
319 int IFNE = 154; // -
320 int IFLT = 155; // -
321 int IFGE = 156; // -
322 int IFGT = 157; // -
323 int IFLE = 158; // -
324 int IF_ICMPEQ = 159; // -
325 int IF_ICMPNE = 160; // -
326 int IF_ICMPLT = 161; // -
327 int IF_ICMPGE = 162; // -
328 int IF_ICMPGT = 163; // -
329 int IF_ICMPLE = 164; // -
330 int IF_ACMPEQ = 165; // -
331 int IF_ACMPNE = 166; // -
332 int GOTO = 167; // -
333 int JSR = 168; // -
334 int RET = 169; // visitVarInsn
335 int TABLESWITCH = 170; // visiTableSwitchInsn
336 int LOOKUPSWITCH = 171; // visitLookupSwitch
337 int IRETURN = 172; // visitInsn
338 int LRETURN = 173; // -
339 int FRETURN = 174; // -
340 int DRETURN = 175; // -
341 int ARETURN = 176; // -
342 int RETURN = 177; // -
343 int GETSTATIC = 178; // visitFieldInsn
344 int PUTSTATIC = 179; // -
345 int GETFIELD = 180; // -
346 int PUTFIELD = 181; // -
347 int INVOKEVIRTUAL = 182; // visitMethodInsn
348 int INVOKESPECIAL = 183; // -
349 int INVOKESTATIC = 184; // -
350 int INVOKEINTERFACE = 185; // -
351 int INVOKEDYNAMIC = 186; // visitInvokeDynamicInsn
352 int NEW = 187; // visitTypeInsn
353 int NEWARRAY = 188; // visitIntInsn
354 int ANEWARRAY = 189; // visitTypeInsn
355 int ARRAYLENGTH = 190; // visitInsn
356 int ATHROW = 191; // -
357 int CHECKCAST = 192; // visitTypeInsn
358 int INSTANCEOF = 193; // -
359 int MONITORENTER = 194; // visitInsn
360 int MONITOREXIT = 195; // -
361 // int WIDE = 196; // NOT VISITED
362 int MULTIANEWARRAY = 197; // visitMultiANewArrayInsn
363 int IFNULL = 198; // visitJumpInsn
364 int IFNONNULL = 199; // -
365 // int GOTO_W = 200; // -
366 // int JSR_W = 201; // -
42 // ASM API versions.
43
44 int ASM4 = 4 << 16 | 0 << 8;
45 int ASM5 = 5 << 16 | 0 << 8;
46 int ASM6 = 6 << 16 | 0 << 8;
47
48 /**
49 * <b>Experimental, use at your own risk. This field will be renamed when it becomes stable, this
50 * will break existing code using it</b>.
51 *
52 * @deprecated This API is experimental.
53 */
54 @Deprecated int ASM7_EXPERIMENTAL = 1 << 24 | 7 << 16 | 0 << 8;
55
56 // Java ClassFile versions (the minor version is stored in the 16 most
57 // significant bits, and the
58 // major version in the 16 least significant bits).
59
60 int V1_1 = 3 << 16 | 45;
61 int V1_2 = 0 << 16 | 46;
62 int V1_3 = 0 << 16 | 47;
63 int V1_4 = 0 << 16 | 48;
64 int V1_5 = 0 << 16 | 49;
65 int V1_6 = 0 << 16 | 50;
66 int V1_7 = 0 << 16 | 51;
67 int V1_8 = 0 << 16 | 52;
68 int V9 = 0 << 16 | 53;
69 int V10 = 0 << 16 | 54;
70 int V11 = 0 << 16 | 55;
71
72 /**
73 * Version flag indicating that the class is using 'preview' features.
74 *
75 * <p>{@code version & V_PREVIEW_EXPERIMENTAL == V_PREVIEW_EXPERIMENTAL} tests if a version is
76 * flagged with {@code V_PREVIEW_EXPERIMENTAL}.
77 *
78 * @deprecated This API is experimental.
79 */
80 @Deprecated int V_PREVIEW_EXPERIMENTAL = 0xFFFF0000;
81
82 // Access flags values, defined in
83 // - https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.1-200-E.1
84 // - https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.5-200-A.1
85 // - https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.6-200-A.1
86 // - https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.25
87
88 int ACC_PUBLIC = 0x0001; // class, field, method
89 int ACC_PRIVATE = 0x0002; // class, field, method
90 int ACC_PROTECTED = 0x0004; // class, field, method
91 int ACC_STATIC = 0x0008; // field, method
92 int ACC_FINAL = 0x0010; // class, field, method, parameter
93 int ACC_SUPER = 0x0020; // class
94 int ACC_SYNCHRONIZED = 0x0020; // method
95 int ACC_OPEN = 0x0020; // module
96 int ACC_TRANSITIVE = 0x0020; // module requires
97 int ACC_VOLATILE = 0x0040; // field
98 int ACC_BRIDGE = 0x0040; // method
99 int ACC_STATIC_PHASE = 0x0040; // module requires
100 int ACC_VARARGS = 0x0080; // method
101 int ACC_TRANSIENT = 0x0080; // field
102 int ACC_NATIVE = 0x0100; // method
103 int ACC_INTERFACE = 0x0200; // class
104 int ACC_ABSTRACT = 0x0400; // class, method
105 int ACC_STRICT = 0x0800; // method
106 int ACC_SYNTHETIC = 0x1000; // class, field, method, parameter, module *
107 int ACC_ANNOTATION = 0x2000; // class
108 int ACC_ENUM = 0x4000; // class(?) field inner
109 int ACC_MANDATED = 0x8000; // parameter, module, module *
110 int ACC_MODULE = 0x8000; // class
111
112 // ASM specific access flags.
113 // WARNING: the 16 least significant bits must NOT be used, to avoid conflicts with standard
114 // access flags, and also to make sure that these flags are automatically filtered out when
115 // written in class files (because access flags are stored using 16 bits only).
116
117 int ACC_DEPRECATED = 0x20000; // class, field, method
118
119 // Possible values for the type operand of the NEWARRAY instruction.
120 // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-6.html#jvms-6.5.newarray.
121
122 int T_BOOLEAN = 4;
123 int T_CHAR = 5;
124 int T_FLOAT = 6;
125 int T_DOUBLE = 7;
126 int T_BYTE = 8;
127 int T_SHORT = 9;
128 int T_INT = 10;
129 int T_LONG = 11;
130
131 // Possible values for the reference_kind field of CONSTANT_MethodHandle_info structures.
132 // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.4.8.
133
134 int H_GETFIELD = 1;
135 int H_GETSTATIC = 2;
136 int H_PUTFIELD = 3;
137 int H_PUTSTATIC = 4;
138 int H_INVOKEVIRTUAL = 5;
139 int H_INVOKESTATIC = 6;
140 int H_INVOKESPECIAL = 7;
141 int H_NEWINVOKESPECIAL = 8;
142 int H_INVOKEINTERFACE = 9;
143
144 // ASM specific stack map frame types, used in {@link ClassVisitor#visitFrame}.
145
146 /** An expanded frame. See {@link ClassReader#EXPAND_FRAMES}. */
147 int F_NEW = -1;
148
149 /** A compressed frame with complete frame data. */
150 int F_FULL = 0;
151
152 /**
153 * A compressed frame where locals are the same as the locals in the previous frame, except that
154 * additional 1-3 locals are defined, and with an empty stack.
155 */
156 int F_APPEND = 1;
157
158 /**
159 * A compressed frame where locals are the same as the locals in the previous frame, except that
160 * the last 1-3 locals are absent and with an empty stack.
161 */
162 int F_CHOP = 2;
163
164 /**
165 * A compressed frame with exactly the same locals as the previous frame and with an empty stack.
166 */
167 int F_SAME = 3;
168
169 /**
170 * A compressed frame with exactly the same locals as the previous frame and with a single value
171 * on the stack.
172 */
173 int F_SAME1 = 4;
174
175 // Standard stack map frame element types, used in {@link ClassVisitor#visitFrame}.
176
177 Integer TOP = Frame.ITEM_TOP;
178 Integer INTEGER = Frame.ITEM_INTEGER;
179 Integer FLOAT = Frame.ITEM_FLOAT;
180 Integer DOUBLE = Frame.ITEM_DOUBLE;
181 Integer LONG = Frame.ITEM_LONG;
182 Integer NULL = Frame.ITEM_NULL;
183 Integer UNINITIALIZED_THIS = Frame.ITEM_UNINITIALIZED_THIS;
184
185 // The JVM opcode values (with the MethodVisitor method name used to visit them in comment, and
186 // where '-' means 'same method name as on the previous line').
187 // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-6.html.
188
189 int NOP = 0; // visitInsn
190 int ACONST_NULL = 1; // -
191 int ICONST_M1 = 2; // -
192 int ICONST_0 = 3; // -
193 int ICONST_1 = 4; // -
194 int ICONST_2 = 5; // -
195 int ICONST_3 = 6; // -
196 int ICONST_4 = 7; // -
197 int ICONST_5 = 8; // -
198 int LCONST_0 = 9; // -
199 int LCONST_1 = 10; // -
200 int FCONST_0 = 11; // -
201 int FCONST_1 = 12; // -
202 int FCONST_2 = 13; // -
203 int DCONST_0 = 14; // -
204 int DCONST_1 = 15; // -
205 int BIPUSH = 16; // visitIntInsn
206 int SIPUSH = 17; // -
207 int LDC = 18; // visitLdcInsn
208 int ILOAD = 21; // visitVarInsn
209 int LLOAD = 22; // -
210 int FLOAD = 23; // -
211 int DLOAD = 24; // -
212 int ALOAD = 25; // -
213 int IALOAD = 46; // visitInsn
214 int LALOAD = 47; // -
215 int FALOAD = 48; // -
216 int DALOAD = 49; // -
217 int AALOAD = 50; // -
218 int BALOAD = 51; // -
219 int CALOAD = 52; // -
220 int SALOAD = 53; // -
221 int ISTORE = 54; // visitVarInsn
222 int LSTORE = 55; // -
223 int FSTORE = 56; // -
224 int DSTORE = 57; // -
225 int ASTORE = 58; // -
226 int IASTORE = 79; // visitInsn
227 int LASTORE = 80; // -
228 int FASTORE = 81; // -
229 int DASTORE = 82; // -
230 int AASTORE = 83; // -
231 int BASTORE = 84; // -
232 int CASTORE = 85; // -
233 int SASTORE = 86; // -
234 int POP = 87; // -
235 int POP2 = 88; // -
236 int DUP = 89; // -
237 int DUP_X1 = 90; // -
238 int DUP_X2 = 91; // -
239 int DUP2 = 92; // -
240 int DUP2_X1 = 93; // -
241 int DUP2_X2 = 94; // -
242 int SWAP = 95; // -
243 int IADD = 96; // -
244 int LADD = 97; // -
245 int FADD = 98; // -
246 int DADD = 99; // -
247 int ISUB = 100; // -
248 int LSUB = 101; // -
249 int FSUB = 102; // -
250 int DSUB = 103; // -
251 int IMUL = 104; // -
252 int LMUL = 105; // -
253 int FMUL = 106; // -
254 int DMUL = 107; // -
255 int IDIV = 108; // -
256 int LDIV = 109; // -
257 int FDIV = 110; // -
258 int DDIV = 111; // -
259 int IREM = 112; // -
260 int LREM = 113; // -
261 int FREM = 114; // -
262 int DREM = 115; // -
263 int INEG = 116; // -
264 int LNEG = 117; // -
265 int FNEG = 118; // -
266 int DNEG = 119; // -
267 int ISHL = 120; // -
268 int LSHL = 121; // -
269 int ISHR = 122; // -
270 int LSHR = 123; // -
271 int IUSHR = 124; // -
272 int LUSHR = 125; // -
273 int IAND = 126; // -
274 int LAND = 127; // -
275 int IOR = 128; // -
276 int LOR = 129; // -
277 int IXOR = 130; // -
278 int LXOR = 131; // -
279 int IINC = 132; // visitIincInsn
280 int I2L = 133; // visitInsn
281 int I2F = 134; // -
282 int I2D = 135; // -
283 int L2I = 136; // -
284 int L2F = 137; // -
285 int L2D = 138; // -
286 int F2I = 139; // -
287 int F2L = 140; // -
288 int F2D = 141; // -
289 int D2I = 142; // -
290 int D2L = 143; // -
291 int D2F = 144; // -
292 int I2B = 145; // -
293 int I2C = 146; // -
294 int I2S = 147; // -
295 int LCMP = 148; // -
296 int FCMPL = 149; // -
297 int FCMPG = 150; // -
298 int DCMPL = 151; // -
299 int DCMPG = 152; // -
300 int IFEQ = 153; // visitJumpInsn
301 int IFNE = 154; // -
302 int IFLT = 155; // -
303 int IFGE = 156; // -
304 int IFGT = 157; // -
305 int IFLE = 158; // -
306 int IF_ICMPEQ = 159; // -
307 int IF_ICMPNE = 160; // -
308 int IF_ICMPLT = 161; // -
309 int IF_ICMPGE = 162; // -
310 int IF_ICMPGT = 163; // -
311 int IF_ICMPLE = 164; // -
312 int IF_ACMPEQ = 165; // -
313 int IF_ACMPNE = 166; // -
314 int GOTO = 167; // -
315 int JSR = 168; // -
316 int RET = 169; // visitVarInsn
317 int TABLESWITCH = 170; // visiTableSwitchInsn
318 int LOOKUPSWITCH = 171; // visitLookupSwitch
319 int IRETURN = 172; // visitInsn
320 int LRETURN = 173; // -
321 int FRETURN = 174; // -
322 int DRETURN = 175; // -
323 int ARETURN = 176; // -
324 int RETURN = 177; // -
325 int GETSTATIC = 178; // visitFieldInsn
326 int PUTSTATIC = 179; // -
327 int GETFIELD = 180; // -
328 int PUTFIELD = 181; // -
329 int INVOKEVIRTUAL = 182; // visitMethodInsn
330 int INVOKESPECIAL = 183; // -
331 int INVOKESTATIC = 184; // -
332 int INVOKEINTERFACE = 185; // -
333 int INVOKEDYNAMIC = 186; // visitInvokeDynamicInsn
334 int NEW = 187; // visitTypeInsn
335 int NEWARRAY = 188; // visitIntInsn
336 int ANEWARRAY = 189; // visitTypeInsn
337 int ARRAYLENGTH = 190; // visitInsn
338 int ATHROW = 191; // -
339 int CHECKCAST = 192; // visitTypeInsn
340 int INSTANCEOF = 193; // -
341 int MONITORENTER = 194; // visitInsn
342 int MONITOREXIT = 195; // -
343 int MULTIANEWARRAY = 197; // visitMultiANewArrayInsn
344 int IFNULL = 198; // visitJumpInsn
345 int IFNONNULL = 199; // -
367346 }
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
27 package org.eclipse.persistence.internal.libraries.asm;
28
29 /**
30 * An entry of the constant pool, of the BootstrapMethods attribute, or of the (ASM specific) type
31 * table of a class.
32 *
33 * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.4">JVMS
34 * 4.4</a>
35 * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.23">JVMS
36 * 4.7.23</a>
37 * @author Eric Bruneton
38 */
39 abstract class Symbol {
40
41 // Tag values for the constant pool entries (using the same order as in the JVMS).
42
43 /** The tag value of CONSTANT_Class_info JVMS structures. */
44 static final int CONSTANT_CLASS_TAG = 7;
45
46 /** The tag value of CONSTANT_Fieldref_info JVMS structures. */
47 static final int CONSTANT_FIELDREF_TAG = 9;
48
49 /** The tag value of CONSTANT_Methodref_info JVMS structures. */
50 static final int CONSTANT_METHODREF_TAG = 10;
51
52 /** The tag value of CONSTANT_InterfaceMethodref_info JVMS structures. */
53 static final int CONSTANT_INTERFACE_METHODREF_TAG = 11;
54
55 /** The tag value of CONSTANT_String_info JVMS structures. */
56 static final int CONSTANT_STRING_TAG = 8;
57
58 /** The tag value of CONSTANT_Integer_info JVMS structures. */
59 static final int CONSTANT_INTEGER_TAG = 3;
60
61 /** The tag value of CONSTANT_Float_info JVMS structures. */
62 static final int CONSTANT_FLOAT_TAG = 4;
63
64 /** The tag value of CONSTANT_Long_info JVMS structures. */
65 static final int CONSTANT_LONG_TAG = 5;
66
67 /** The tag value of CONSTANT_Double_info JVMS structures. */
68 static final int CONSTANT_DOUBLE_TAG = 6;
69
70 /** The tag value of CONSTANT_NameAndType_info JVMS structures. */
71 static final int CONSTANT_NAME_AND_TYPE_TAG = 12;
72
73 /** The tag value of CONSTANT_Utf8_info JVMS structures. */
74 static final int CONSTANT_UTF8_TAG = 1;
75
76 /** The tag value of CONSTANT_MethodHandle_info JVMS structures. */
77 static final int CONSTANT_METHOD_HANDLE_TAG = 15;
78
79 /** The tag value of CONSTANT_MethodType_info JVMS structures. */
80 static final int CONSTANT_METHOD_TYPE_TAG = 16;
81
82 /** The tag value of CONSTANT_Dynamic_info JVMS structures. */
83 static final int CONSTANT_DYNAMIC_TAG = 17;
84
85 /** The tag value of CONSTANT_InvokeDynamic_info JVMS structures. */
86 static final int CONSTANT_INVOKE_DYNAMIC_TAG = 18;
87
88 /** The tag value of CONSTANT_Module_info JVMS structures. */
89 static final int CONSTANT_MODULE_TAG = 19;
90
91 /** The tag value of CONSTANT_Package_info JVMS structures. */
92 static final int CONSTANT_PACKAGE_TAG = 20;
93
94 // Tag values for the BootstrapMethods attribute entries (ASM specific tag).
95
96 /** The tag value of the BootstrapMethods attribute entries. */
97 static final int BOOTSTRAP_METHOD_TAG = 64;
98
99 // Tag values for the type table entries (ASM specific tags).
100
101 /** The tag value of a normal type entry in the (ASM specific) type table of a class. */
102 static final int TYPE_TAG = 128;
103
104 /**
105 * The tag value of an {@link Frame#ITEM_UNINITIALIZED} type entry in the type table of a class.
106 */
107 static final int UNINITIALIZED_TYPE_TAG = 129;
108
109 /** The tag value of a merged type entry in the (ASM specific) type table of a class. */
110 static final int MERGED_TYPE_TAG = 130;
111
112 // Instance fields.
113
114 /**
115 * The index of this symbol in the constant pool, in the BootstrapMethods attribute, or in the
116 * (ASM specific) type table of a class (depending on the {@link #tag} value).
117 */
118 final int index;
119
120 /**
121 * A tag indicating the type of this symbol. Must be one of the static tag values defined in this
122 * class.
123 */
124 final int tag;
125
126 /**
127 * The internal name of the owner class of this symbol. Only used for {@link
128 * #CONSTANT_FIELDREF_TAG}, {@link #CONSTANT_METHODREF_TAG}, {@link
129 * #CONSTANT_INTERFACE_METHODREF_TAG}, and {@link #CONSTANT_METHOD_HANDLE_TAG} symbols.
130 */
131 final String owner;
132
133 /**
134 * The name of the class field or method corresponding to this symbol. Only used for {@link
135 * #CONSTANT_FIELDREF_TAG}, {@link #CONSTANT_METHODREF_TAG}, {@link
136 * #CONSTANT_INTERFACE_METHODREF_TAG}, {@link #CONSTANT_NAME_AND_TYPE_TAG}, {@link
137 * #CONSTANT_METHOD_HANDLE_TAG}, {@link #CONSTANT_DYNAMIC_TAG} and {@link
138 * #CONSTANT_INVOKE_DYNAMIC_TAG} symbols.
139 */
140 final String name;
141
142 /**
143 * The string value of this symbol. This is:
144 *
145 * <ul>
146 * <li>a field or method descriptor for {@link #CONSTANT_FIELDREF_TAG}, {@link
147 * #CONSTANT_METHODREF_TAG}, {@link #CONSTANT_INTERFACE_METHODREF_TAG}, {@link
148 * #CONSTANT_NAME_AND_TYPE_TAG}, {@link #CONSTANT_METHOD_HANDLE_TAG}, {@link
149 * #CONSTANT_METHOD_TYPE_TAG}, {@link #CONSTANT_DYNAMIC_TAG} and {@link
150 * #CONSTANT_INVOKE_DYNAMIC_TAG} symbols,
151 * <li>an arbitrary string for {@link #CONSTANT_UTF8_TAG} and {@link #CONSTANT_STRING_TAG}
152 * symbols,
153 * <li>an internal class name for {@link #CONSTANT_CLASS_TAG}, {@link #TYPE_TAG} and {@link
154 * #UNINITIALIZED_TYPE_TAG} symbols,
155 * <li><tt>null</tt> for the other types of symbol.
156 * </ul>
157 */
158 final String value;
159
160 /**
161 * The numeric value of this symbol. This is:
162 *
163 * <ul>
164 * <li>the symbol's value for {@link #CONSTANT_INTEGER_TAG},{@link #CONSTANT_FLOAT_TAG}, {@link
165 * #CONSTANT_LONG_TAG}, {@link #CONSTANT_DOUBLE_TAG},
166 * <li>the CONSTANT_MethodHandle_info reference_kind field value for {@link
167 * #CONSTANT_METHOD_HANDLE_TAG} symbols,
168 * <li>the CONSTANT_InvokeDynamic_info bootstrap_method_attr_index field value for {@link
169 * #CONSTANT_INVOKE_DYNAMIC_TAG} symbols,
170 * <li>the offset of a bootstrap method in the BootstrapMethods boostrap_methods array, for
171 * {@link #CONSTANT_DYNAMIC_TAG} or {@link #BOOTSTRAP_METHOD_TAG} symbols,
172 * <li>the bytecode offset of the NEW instruction that created an {@link
173 * Frame#ITEM_UNINITIALIZED} type for {@link #UNINITIALIZED_TYPE_TAG} symbols,
174 * <li>the indices (in the class' type table) of two {@link #TYPE_TAG} source types for {@link
175 * #MERGED_TYPE_TAG} symbols,
176 * <li>0 for the other types of symbol.
177 * </ul>
178 */
179 final long data;
180
181 /**
182 * Additional information about this symbol, generally computed lazily. <i>Warning: the value of
183 * this field is ignored when comparing Symbol instances</i> (to avoid duplicate entries in a
184 * SymbolTable). Therefore, this field should only contain data that can be computed from the
185 * other fields of this class. It contains:
186 *
187 * <ul>
188 * <li>the {@link Type#getArgumentsAndReturnSizes} of the symbol's method descriptor for {@link
189 * #CONSTANT_METHODREF_TAG}, {@link #CONSTANT_INTERFACE_METHODREF_TAG} and {@link
190 * #CONSTANT_INVOKE_DYNAMIC_TAG} symbols,
191 * <li>the index in the InnerClasses_attribute 'classes' array (plus one) corresponding to this
192 * class, for {@link #CONSTANT_CLASS_TAG} symbols,
193 * <li>the index (in the class' type table) of the merged type of the two source types for
194 * {@link #MERGED_TYPE_TAG} symbols,
195 * <li>0 for the other types of symbol, or if this field has not been computed yet.
196 * </ul>
197 */
198 int info;
199
200 /**
201 * Constructs a new Symbol. This constructor can't be used directly because the Symbol class is
202 * abstract. Instead, use the factory methods of the {@link SymbolTable} class.
203 *
204 * @param index the symbol index in the constant pool, in the BootstrapMethods attribute, or in
205 * the (ASM specific) type table of a class (depending on 'tag').
206 * @param tag the symbol type. Must be one of the static tag values defined in this class.
207 * @param owner The internal name of the symbol's owner class. Maybe <tt>null</tt>.
208 * @param name The name of the symbol's corresponding class field or method. Maybe <tt>null</tt>.
209 * @param value The string value of this symbol. Maybe <tt>null</tt>.
210 * @param data The numeric value of this symbol.
211 */
212 Symbol(
213 final int index,
214 final int tag,
215 final String owner,
216 final String name,
217 final String value,
218 final long data) {
219 this.index = index;
220 this.tag = tag;
221 this.owner = owner;
222 this.name = name;
223 this.value = value;
224 this.data = data;
225 }
226
227 /**
228 * @return the result {@link Type#getArgumentsAndReturnSizes} on {@link #value} (memoized in
229 * {@link #info} for efficiency). This should only be used for {@link
230 * #CONSTANT_METHODREF_TAG}, {@link #CONSTANT_INTERFACE_METHODREF_TAG} and {@link
231 * #CONSTANT_INVOKE_DYNAMIC_TAG} symbols.
232 */
233 int getArgumentsAndReturnSizes() {
234 if (info == 0) {
235 info = Type.getArgumentsAndReturnSizes(value);
236 }
237 return info;
238 }
239 }
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
27 package org.eclipse.persistence.internal.libraries.asm;
28
29 /**
30 * The constant pool entries, the BootstrapMethods attribute entries and the (ASM specific) type
31 * table entries of a class.
32 *
33 * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.4">JVMS
34 * 4.4</a>
35 * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.23">JVMS
36 * 4.7.23</a>
37 * @author Eric Bruneton
38 */
39 final class SymbolTable {
40
41 /**
42 * An entry of a SymbolTable. This concrete and private subclass of {@link Symbol} adds two fields
43 * which are only used inside SymbolTable, to implement hash sets of symbols (in order to avoid
44 * duplicate symbols). See {@link #entries}.
45 *
46 * @author Eric Bruneton
47 */
48 private static class Entry extends Symbol {
49
50 /** The hash code of this entry. */
51 final int hashCode;
52
53 /**
54 * Another entry (and so on recursively) having the same hash code (modulo the size of {@link
55 * #entries}) as this one.
56 */
57 Entry next;
58
59 Entry(
60 final int index,
61 final int tag,
62 final String owner,
63 final String name,
64 final String value,
65 final long data,
66 final int hashCode) {
67 super(index, tag, owner, name, value, data);
68 this.hashCode = hashCode;
69 }
70
71 Entry(final int index, final int tag, final String value, final int hashCode) {
72 super(index, tag, /* owner = */ null, /* name = */ null, value, /* data = */ 0);
73 this.hashCode = hashCode;
74 }
75
76 Entry(final int index, final int tag, final String value, final long data, final int hashCode) {
77 super(index, tag, /* owner = */ null, /* name = */ null, value, data);
78 this.hashCode = hashCode;
79 }
80
81 Entry(
82 final int index, final int tag, final String name, final String value, final int hashCode) {
83 super(index, tag, /* owner = */ null, name, value, /* data = */ 0);
84 this.hashCode = hashCode;
85 }
86
87 Entry(final int index, final int tag, final long data, final int hashCode) {
88 super(index, tag, /* owner = */ null, /* name = */ null, /* value = */ null, data);
89 this.hashCode = hashCode;
90 }
91 }
92
93 /**
94 * The ClassWriter to which this SymbolTable belongs. This is only used to get access to {@link
95 * ClassWriter#getCommonSuperClass} and to serialize custom attributes with {@link
96 * Attribute#write}.
97 */
98 final ClassWriter classWriter;
99
100 /**
101 * The ClassReader from which this SymbolTable was constructed, or <tt>null</tt> if it was
102 * constructed from scratch.
103 */
104 private final ClassReader sourceClassReader;
105
106 /** The major version number of the class to which this symbol table belongs. */
107 private int majorVersion;
108
109 /** The internal name of the class to which this symbol table belongs. */
110 private String className;
111
112 /**
113 * The total number of {@link Entry} instances in {@link #entries}. This includes entries that are
114 * accessible (recursively) via {@link Entry#next}.
115 */
116 private int entryCount;
117
118 /**
119 * A hash set of all the entries in this SymbolTable (this includes the constant pool entries, the
120 * bootstrap method entries and the type table entries). Each {@link Entry} instance is stored at
121 * the array index given by its hash code modulo the array size. If several entries must be stored
122 * at the same array index, they are linked together via their {@link Entry#next} field. The
123 * factory methods of this class make sure that this table does not contain duplicated entries.
124 */
125 private Entry[] entries;
126
127 /**
128 * The number of constant pool items in {@link #constantPool}, plus 1. The first constant pool
129 * item has index 1, and long and double items count for two items.
130 */
131 private int constantPoolCount;
132
133 /**
134 * The content of the ClassFile's constant_pool JVMS structure corresponding to this SymbolTable.
135 * The ClassFile's constant_pool_count field is <i>not</i> included.
136 */
137 private ByteVector constantPool;
138
139 /**
140 * The number of bootstrap methods in {@link #bootstrapMethods}. Corresponds to the
141 * BootstrapMethods_attribute's num_bootstrap_methods field value.
142 */
143 private int bootstrapMethodCount;
144
145 /**
146 * The content of the BootstrapMethods attribute 'bootstrap_methods' array corresponding to this
147 * SymbolTable. Note that the first 6 bytes of the BootstrapMethods_attribute, and its
148 * num_bootstrap_methods field, are <i>not</i> included.
149 */
150 private ByteVector bootstrapMethods;
151
152 /**
153 * The actual number of elements in {@link #typeTable}. These elements are stored from index 0 to
154 * typeCount (excluded). The other array entries are empty.
155 */
156 private int typeCount;
157
158 /**
159 * An ASM specific type table used to temporarily store internal names that will not necessarily
160 * be stored in the constant pool. This type table is used by the control flow and data flow
161 * analysis algorithm used to compute stack map frames from scratch. This array stores {@link
162 * Symbol#TYPE_TAG} and {@link Symbol#UNINITIALIZED_TYPE_TAG}) Symbol. The type symbol at index
163 * <tt>i</tt> has its {@link Symbol#index} equal to <tt>i</tt> (and vice versa).
164 */
165 private Entry[] typeTable;
166
167 /**
168 * Constructs a new, empty SymbolTable for the given ClassWriter.
169 *
170 * @param classWriter a ClassWriter.
171 */
172 SymbolTable(final ClassWriter classWriter) {
173 this.classWriter = classWriter;
174 this.sourceClassReader = null;
175 this.entries = new Entry[256];
176 this.constantPoolCount = 1;
177 this.constantPool = new ByteVector();
178 }
179
180 /**
181 * Constructs a new SymbolTable for the given ClassWriter, initialized with the constant pool and
182 * bootstrap methods of the given ClassReader.
183 *
184 * @param classWriter a ClassWriter.
185 * @param classReader the ClassReader whose constant pool and bootstrap methods must be copied to
186 * initialize the SymbolTable.
187 */
188 SymbolTable(final ClassWriter classWriter, final ClassReader classReader) {
189 this.classWriter = classWriter;
190 this.sourceClassReader = classReader;
191
192 // Copy the constant pool binary content.
193 byte[] inputBytes = classReader.b;
194 int constantPoolOffset = classReader.getItem(1) - 1;
195 int constantPoolLength = classReader.header - constantPoolOffset;
196 constantPoolCount = classReader.getItemCount();
197 constantPool = new ByteVector(constantPoolLength);
198 constantPool.putByteArray(inputBytes, constantPoolOffset, constantPoolLength);
199
200 // Add the constant pool items in the symbol table entries. Reserve enough space in 'entries' to
201 // avoid too many hash set collisions (entries is not dynamically resized by the addConstant*
202 // method calls below), and to account for bootstrap method entries.
203 entries = new Entry[constantPoolCount * 2];
204 char[] charBuffer = new char[classReader.getMaxStringLength()];
205 int itemIndex = 1;
206 while (itemIndex < constantPoolCount) {
207 int itemOffset = classReader.getItem(itemIndex);
208 int itemTag = inputBytes[itemOffset - 1];
209 int nameAndTypeItemOffset;
210 switch (itemTag) {
211 case Symbol.CONSTANT_FIELDREF_TAG:
212 case Symbol.CONSTANT_METHODREF_TAG:
213 case Symbol.CONSTANT_INTERFACE_METHODREF_TAG:
214 nameAndTypeItemOffset =
215 classReader.getItem(classReader.readUnsignedShort(itemOffset + 2));
216 addConstantMemberReference(
217 itemIndex,
218 itemTag,
219 classReader.readClass(itemOffset, charBuffer),
220 classReader.readUTF8(nameAndTypeItemOffset, charBuffer),
221 classReader.readUTF8(nameAndTypeItemOffset + 2, charBuffer));
222 break;
223 case Symbol.CONSTANT_INTEGER_TAG:
224 case Symbol.CONSTANT_FLOAT_TAG:
225 addConstantInteger(itemIndex, itemTag, classReader.readInt(itemOffset));
226 break;
227 case Symbol.CONSTANT_NAME_AND_TYPE_TAG:
228 addConstantNameAndType(
229 itemIndex,
230 classReader.readUTF8(itemOffset, charBuffer),
231 classReader.readUTF8(itemOffset + 2, charBuffer));
232 break;
233 case Symbol.CONSTANT_LONG_TAG:
234 case Symbol.CONSTANT_DOUBLE_TAG:
235 addConstantLong(itemIndex, itemTag, classReader.readLong(itemOffset));
236 break;
237 case Symbol.CONSTANT_UTF8_TAG:
238 addConstantUtf8(itemIndex, classReader.readUTF(itemIndex, charBuffer));
239 break;
240 case Symbol.CONSTANT_METHOD_HANDLE_TAG:
241 int memberRefItemOffset =
242 classReader.getItem(classReader.readUnsignedShort(itemOffset + 1));
243 nameAndTypeItemOffset =
244 classReader.getItem(classReader.readUnsignedShort(memberRefItemOffset + 2));
245 addConstantMethodHandle(
246 itemIndex,
247 classReader.readByte(itemOffset),
248 classReader.readClass(memberRefItemOffset, charBuffer),
249 classReader.readUTF8(nameAndTypeItemOffset, charBuffer),
250 classReader.readUTF8(nameAndTypeItemOffset + 2, charBuffer));
251 break;
252 case Symbol.CONSTANT_DYNAMIC_TAG:
253 case Symbol.CONSTANT_INVOKE_DYNAMIC_TAG:
254 nameAndTypeItemOffset =
255 classReader.getItem(classReader.readUnsignedShort(itemOffset + 2));
256 addConstantDynamicOrInvokeDynamicReference(
257 itemTag,
258 itemIndex,
259 classReader.readUTF8(nameAndTypeItemOffset, charBuffer),
260 classReader.readUTF8(nameAndTypeItemOffset + 2, charBuffer),
261 classReader.readUnsignedShort(itemOffset));
262 break;
263 case Symbol.CONSTANT_STRING_TAG:
264 case Symbol.CONSTANT_CLASS_TAG:
265 case Symbol.CONSTANT_METHOD_TYPE_TAG:
266 case Symbol.CONSTANT_MODULE_TAG:
267 case Symbol.CONSTANT_PACKAGE_TAG:
268 addConstantUtf8Reference(
269 itemIndex, itemTag, classReader.readUTF8(itemOffset, charBuffer));
270 break;
271 default:
272 throw new IllegalArgumentException();
273 }
274 itemIndex +=
275 (itemTag == Symbol.CONSTANT_LONG_TAG || itemTag == Symbol.CONSTANT_DOUBLE_TAG) ? 2 : 1;
276 }
277
278 // Copy the BootstrapMethods 'bootstrap_methods' array binary content, if any.
279 int currentAttributeOffset = classReader.getFirstAttributeOffset();
280 for (int i = classReader.readUnsignedShort(currentAttributeOffset - 2); i > 0; --i) {
281 String attributeName = classReader.readUTF8(currentAttributeOffset, charBuffer);
282 if (Constants.BOOTSTRAP_METHODS.equals(attributeName)) {
283 bootstrapMethodCount = classReader.readUnsignedShort(currentAttributeOffset + 6);
284 break;
285 }
286 currentAttributeOffset += 6 + classReader.readInt(currentAttributeOffset + 2);
287 }
288 if (bootstrapMethodCount > 0) {
289 // Compute the offset and the length of the BootstrapMethods 'bootstrap_methods' array.
290 int bootstrapMethodsOffset = currentAttributeOffset + 8;
291 int bootstrapMethodsLength = classReader.readInt(currentAttributeOffset + 2) - 2;
292 bootstrapMethods = new ByteVector(bootstrapMethodsLength);
293 bootstrapMethods.putByteArray(inputBytes, bootstrapMethodsOffset, bootstrapMethodsLength);
294
295 // Add each bootstrap method in the symbol table entries.
296 int currentOffset = bootstrapMethodsOffset;
297 for (int i = 0; i < bootstrapMethodCount; i++) {
298 int offset = currentOffset - bootstrapMethodsOffset;
299 int bootstrapMethodRef = classReader.readUnsignedShort(currentOffset);
300 currentOffset += 2;
301 int numBootstrapArguments = classReader.readUnsignedShort(currentOffset);
302 currentOffset += 2;
303 int hashCode = classReader.readConst(bootstrapMethodRef, charBuffer).hashCode();
304 while (numBootstrapArguments-- > 0) {
305 int bootstrapArgument = classReader.readUnsignedShort(currentOffset);
306 currentOffset += 2;
307 hashCode ^= classReader.readConst(bootstrapArgument, charBuffer).hashCode();
308 }
309 add(new Entry(i, Symbol.BOOTSTRAP_METHOD_TAG, offset, hashCode & 0x7FFFFFFF));
310 }
311 }
312 }
313
314 /**
315 * @return the ClassReader from which this SymbolTable was constructed, or <tt>null</tt> if it was
316 * constructed from scratch.
317 */
318 ClassReader getSource() {
319 return sourceClassReader;
320 }
321
322 /** @return the major version of the class to which this symbol table belongs. */
323 int getMajorVersion() {
324 return majorVersion;
325 }
326
327 /** @return the internal name of the class to which this symbol table belongs. */
328 String getClassName() {
329 return className;
330 }
331
332 /**
333 * Sets the major version and the name of the class to which this symbol table belongs. Also adds
334 * the class name to the constant pool.
335 *
336 * @param majorVersion a major ClassFile version number.
337 * @param className an internal class name.
338 * @return the constant pool index of a new or already existing Symbol with the given class name.
339 */
340 int setMajorVersionAndClassName(final int majorVersion, final String className) {
341 this.majorVersion = majorVersion;
342 this.className = className;
343 return addConstantClass(className).index;
344 }
345
346 /** @return the number of items in this symbol table's constant_pool array (plus 1). */
347 int getConstantPoolCount() {
348 return constantPoolCount;
349 }
350
351 /** @return the length in bytes of this symbol table's constant_pool array. */
352 int getConstantPoolLength() {
353 return constantPool.length;
354 }
355
356 /**
357 * Puts this symbol table's constant_pool array in the given ByteVector, preceded by the
358 * constant_pool_count value.
359 *
360 * @param output where the JVMS ClassFile's constant_pool array must be put.
361 */
362 void putConstantPool(final ByteVector output) {
363 output.putShort(constantPoolCount).putByteArray(constantPool.data, 0, constantPool.length);
364 }
365
366 /**
367 * Returns the size in bytes of this symbol table's BootstrapMethods attribute. Also adds the
368 * attribute name in the constant pool.
369 *
370 * @return the size in bytes of this symbol table's BootstrapMethods attribute.
371 */
372 int computeBootstrapMethodsSize() {
373 if (bootstrapMethods != null) {
374 addConstantUtf8(Constants.BOOTSTRAP_METHODS);
375 return 8 + bootstrapMethods.length;
376 } else {
377 return 0;
378 }
379 }
380
381 /**
382 * Puts this symbol table's BootstrapMethods attribute in the given ByteVector. This includes the
383 * 6 attribute header bytes and the num_bootstrap_methods value.
384 *
385 * @param output where the JVMS BootstrapMethods attribute must be put.
386 */
387 void putBootstrapMethods(final ByteVector output) {
388 if (bootstrapMethods != null) {
389 output
390 .putShort(addConstantUtf8(Constants.BOOTSTRAP_METHODS))
391 .putInt(bootstrapMethods.length + 2)
392 .putShort(bootstrapMethodCount)
393 .putByteArray(bootstrapMethods.data, 0, bootstrapMethods.length);
394 }
395 }
396
397 // -----------------------------------------------------------------------------------------------
398 // Generic symbol table entries management.
399 // -----------------------------------------------------------------------------------------------
400
401 /**
402 * @param hashCode a {@link Entry#hashCode} value.
403 * @return the list of entries which can potentially have the given hash code. The list is stored
404 * via the {@link Entry#next} field.
405 */
406 private Entry get(final int hashCode) {
407 return entries[hashCode % entries.length];
408 }
409
410 /**
411 * Puts the given entry in the {@link #entries} hash set. This method does <i>not</i> check
412 * whether {@link #entries} already contains a similar entry or not. {@link #entries} is resized
413 * if necessary to avoid hash collisions (multiple entries needing to be stored at the same {@link
414 * #entries} array index) as much as possible, with reasonable memory usage.
415 *
416 * @param entry an Entry (which must not already be contained in {@link #entries}).
417 * @return the given entry
418 */
419 private Entry put(final Entry entry) {
420 if (entryCount > (entries.length * 3) / 4) {
421 int currentCapacity = entries.length;
422 int newCapacity = currentCapacity * 2 + 1;
423 Entry[] newEntries = new Entry[newCapacity];
424 for (int i = currentCapacity - 1; i >= 0; --i) {
425 Entry currentEntry = entries[i];
426 while (currentEntry != null) {
427 int newCurrentEntryIndex = currentEntry.hashCode % newCapacity;
428 Entry nextEntry = currentEntry.next;
429 currentEntry.next = newEntries[newCurrentEntryIndex];
430 newEntries[newCurrentEntryIndex] = currentEntry;
431 currentEntry = nextEntry;
432 }
433 }
434 entries = newEntries;
435 }
436 entryCount++;
437 int index = entry.hashCode % entries.length;
438 entry.next = entries[index];
439 return entries[index] = entry;
440 }
441
442 /**
443 * Adds the given entry in the {@link #entries} hash set. This method does <i>not</i> check
444 * whether {@link #entries} already contains a similar entry or not, and does <i>not</i> resize
445 * {@link #entries} if necessary.
446 *
447 * @param entry an Entry (which must not already be contained in {@link #entries}).
448 */
449 private void add(final Entry entry) {
450 entryCount++;
451 int index = entry.hashCode % entries.length;
452 entry.next = entries[index];
453 entries[index] = entry;
454 }
455
456 // -----------------------------------------------------------------------------------------------
457 // Constant pool entries management.
458 // -----------------------------------------------------------------------------------------------
459
460 /**
461 * Adds a number or string constant to the constant pool of this symbol table. Does nothing if the
462 * constant pool already contains a similar item.
463 *
464 * @param value the value of the constant to be added to the constant pool. This parameter must be
465 * an {@link Integer}, {@link Byte}, {@link Character}, {@link Short}, {@link Boolean}, {@link
466 * Float}, {@link Long}, {@link Double}, {@link String}, {@link Type} or {@link Handle}.
467 * @return a new or already existing Symbol with the given value.
468 */
469 Symbol addConstant(final Object value) {
470 if (value instanceof Integer) {
471 return addConstantInteger(((Integer) value).intValue());
472 } else if (value instanceof Byte) {
473 return addConstantInteger(((Byte) value).intValue());
474 } else if (value instanceof Character) {
475 return addConstantInteger(((Character) value).charValue());
476 } else if (value instanceof Short) {
477 return addConstantInteger(((Short) value).intValue());
478 } else if (value instanceof Boolean) {
479 return addConstantInteger(((Boolean) value).booleanValue() ? 1 : 0);
480 } else if (value instanceof Float) {
481 return addConstantFloat(((Float) value).floatValue());
482 } else if (value instanceof Long) {
483 return addConstantLong(((Long) value).longValue());
484 } else if (value instanceof Double) {
485 return addConstantDouble(((Double) value).doubleValue());
486 } else if (value instanceof String) {
487 return addConstantString((String) value);
488 } else if (value instanceof Type) {
489 Type type = (Type) value;
490 int typeSort = type.getSort();
491 if (typeSort == Type.OBJECT) {
492 return addConstantClass(type.getInternalName());
493 } else if (typeSort == Type.METHOD) {
494 return addConstantMethodType(type.getDescriptor());
495 } else { // type is a primitive or array type.
496 return addConstantClass(type.getDescriptor());
497 }
498 } else if (value instanceof Handle) {
499 Handle handle = (Handle) value;
500 return addConstantMethodHandle(
501 handle.getTag(),
502 handle.getOwner(),
503 handle.getName(),
504 handle.getDesc(),
505 handle.isInterface());
506 } else if (value instanceof ConstantDynamic) {
507 ConstantDynamic constantDynamic = (ConstantDynamic) value;
508 return addConstantDynamic(
509 constantDynamic.getName(),
510 constantDynamic.getDescriptor(),
511 constantDynamic.getBootstrapMethod(),
512 constantDynamic.getBootstrapMethodArguments());
513 } else {
514 throw new IllegalArgumentException("value " + value);
515 }
516 }
517
518 /**
519 * Adds a CONSTANT_Class_info to the constant pool of this symbol table. Does nothing if the
520 * constant pool already contains a similar item.
521 *
522 * @param value the internal name of a class.
523 * @return a new or already existing Symbol with the given value.
524 */
525 Symbol addConstantClass(final String value) {
526 return addConstantUtf8Reference(Symbol.CONSTANT_CLASS_TAG, value);
527 }
528
529 /**
530 * Adds a CONSTANT_Fieldref_info to the constant pool of this symbol table. Does nothing if the
531 * constant pool already contains a similar item.
532 *
533 * @param owner the internal name of a class.
534 * @param name a field name.
535 * @param descriptor a field descriptor.
536 * @return a new or already existing Symbol with the given value.
537 */
538 Symbol addConstantFieldref(final String owner, final String name, final String descriptor) {
539 return addConstantMemberReference(Symbol.CONSTANT_FIELDREF_TAG, owner, name, descriptor);
540 }
541
542 /**
543 * Adds a CONSTANT_Methodref_info or CONSTANT_InterfaceMethodref_info to the constant pool of this
544 * symbol table. Does nothing if the constant pool already contains a similar item.
545 *
546 * @param owner the internal name of a class.
547 * @param name a method name.
548 * @param descriptor a method descriptor.
549 * @param isInterface whether owner is an interface or not.
550 * @return a new or already existing Symbol with the given value.
551 */
552 Symbol addConstantMethodref(
553 final String owner, final String name, final String descriptor, final boolean isInterface) {
554 int tag = isInterface ? Symbol.CONSTANT_INTERFACE_METHODREF_TAG : Symbol.CONSTANT_METHODREF_TAG;
555 return addConstantMemberReference(tag, owner, name, descriptor);
556 }
557
558 /**
559 * Adds a CONSTANT_Fieldref_info, CONSTANT_Methodref_info or CONSTANT_InterfaceMethodref_info to
560 * the constant pool of this symbol table. Does nothing if the constant pool already contains a
561 * similar item.
562 *
563 * @param tag one of {@link Symbol#CONSTANT_FIELDREF_TAG}, {@link Symbol#CONSTANT_METHODREF_TAG}
564 * or {@link Symbol#CONSTANT_INTERFACE_METHODREF_TAG}.
565 * @param owner the internal name of a class.
566 * @param name a field or method name.
567 * @param descriptor a field or method descriptor.
568 * @return a new or already existing Symbol with the given value.
569 */
570 private Entry addConstantMemberReference(
571 final int tag, final String owner, final String name, final String descriptor) {
572 int hashCode = hash(tag, owner, name, descriptor);
573 Entry entry = get(hashCode);
574 while (entry != null) {
575 if (entry.tag == tag
576 && entry.hashCode == hashCode
577 && entry.owner.equals(owner)
578 && entry.name.equals(name)
579 && entry.value.equals(descriptor)) {
580 return entry;
581 }
582 entry = entry.next;
583 }
584 constantPool.put122(
585 tag, addConstantClass(owner).index, addConstantNameAndType(name, descriptor));
586 return put(new Entry(constantPoolCount++, tag, owner, name, descriptor, 0, hashCode));
587 }
588
589 /**
590 * Adds a new CONSTANT_Fieldref_info, CONSTANT_Methodref_info or CONSTANT_InterfaceMethodref_info
591 * to the constant pool of this symbol table.
592 *
593 * @param index the constant pool index of the new Symbol.
594 * @param tag one of {@link Symbol#CONSTANT_FIELDREF_TAG}, {@link Symbol#CONSTANT_METHODREF_TAG}
595 * or {@link Symbol#CONSTANT_INTERFACE_METHODREF_TAG}.
596 * @param owner the internal name of a class.
597 * @param name a field or method name.
598 * @param descriptor a field or method descriptor.
599 */
600 private void addConstantMemberReference(
601 final int index,
602 final int tag,
603 final String owner,
604 final String name,
605 final String descriptor) {
606 add(new Entry(index, tag, owner, name, descriptor, 0, hash(tag, owner, name, descriptor)));
607 }
608
609 /**
610 * Adds a CONSTANT_String_info to the constant pool of this symbol table. Does nothing if the
611 * constant pool already contains a similar item.
612 *
613 * @param value a string.
614 * @return a new or already existing Symbol with the given value.
615 */
616 Symbol addConstantString(final String value) {
617 return addConstantUtf8Reference(Symbol.CONSTANT_STRING_TAG, value);
618 }
619
620 /**
621 * Adds a CONSTANT_Integer_info to the constant pool of this symbol table. Does nothing if the
622 * constant pool already contains a similar item.
623 *
624 * @param value an int.
625 * @return a new or already existing Symbol with the given value.
626 */
627 Symbol addConstantInteger(final int value) {
628 return addConstantInteger(Symbol.CONSTANT_INTEGER_TAG, value);
629 }
630
631 /**
632 * Adds a CONSTANT_Float_info to the constant pool of this symbol table. Does nothing if the
633 * constant pool already contains a similar item.
634 *
635 * @param value a float.
636 * @return a new or already existing Symbol with the given value.
637 */
638 Symbol addConstantFloat(final float value) {
639 return addConstantInteger(Symbol.CONSTANT_FLOAT_TAG, Float.floatToRawIntBits(value));
640 }
641
642 /**
643 * Adds a CONSTANT_Integer_info or CONSTANT_Float_info to the constant pool of this symbol table.
644 * Does nothing if the constant pool already contains a similar item.
645 *
646 * @param tag one of {@link Symbol#CONSTANT_INTEGER_TAG} or {@link Symbol#CONSTANT_FLOAT_TAG}.
647 * @param value an int or float.
648 * @return a constant pool constant with the given tag and primitive values.
649 */
650 private Symbol addConstantInteger(final int tag, final int value) {
651 int hashCode = hash(tag, value);
652 Entry entry = get(hashCode);
653 while (entry != null) {
654 if (entry.tag == tag && entry.hashCode == hashCode && entry.data == value) {
655 return entry;
656 }
657 entry = entry.next;
658 }
659 constantPool.putByte(tag).putInt(value);
660 return put(new Entry(constantPoolCount++, tag, value, hashCode));
661 }
662
663 /**
664 * Adds a new CONSTANT_Integer_info or CONSTANT_Float_info to the constant pool of this symbol
665 * table.
666 *
667 * @param index the constant pool index of the new Symbol.
668 * @param tag one of {@link Symbol#CONSTANT_INTEGER_TAG} or {@link Symbol#CONSTANT_FLOAT_TAG}.
669 * @param value an int or float.
670 */
671 private void addConstantInteger(final int index, final int tag, final int value) {
672 add(new Entry(index, tag, value, hash(tag, value)));
673 }
674
675 /**
676 * Adds a CONSTANT_Long_info to the constant pool of this symbol table. Does nothing if the
677 * constant pool already contains a similar item.
678 *
679 * @param value a long.
680 * @return a new or already existing Symbol with the given value.
681 */
682 Symbol addConstantLong(final long value) {
683 return addConstantLong(Symbol.CONSTANT_LONG_TAG, value);
684 }
685
686 /**
687 * Adds a CONSTANT_Double_info to the constant pool of this symbol table. Does nothing if the
688 * constant pool already contains a similar item.
689 *
690 * @param value a double.
691 * @return a new or already existing Symbol with the given value.
692 */
693 Symbol addConstantDouble(final double value) {
694 return addConstantLong(Symbol.CONSTANT_DOUBLE_TAG, Double.doubleToRawLongBits(value));
695 }
696
697 /**
698 * Adds a CONSTANT_Long_info or CONSTANT_Double_info to the constant pool of this symbol table.
699 * Does nothing if the constant pool already contains a similar item.
700 *
701 * @param tag one of {@link Symbol#CONSTANT_LONG_TAG} or {@link Symbol#CONSTANT_DOUBLE_TAG}.
702 * @param value a long or double.
703 * @return a constant pool constant with the given tag and primitive values.
704 */
705 private Symbol addConstantLong(final int tag, final long value) {
706 int hashCode = hash(tag, value);
707 Entry entry = get(hashCode);
708 while (entry != null) {
709 if (entry.tag == tag && entry.hashCode == hashCode && entry.data == value) {
710 return entry;
711 }
712 entry = entry.next;
713 }
714 int index = constantPoolCount;
715 constantPool.putByte(tag).putLong(value);
716 constantPoolCount += 2;
717 return put(new Entry(index, tag, value, hashCode));
718 }
719
720 /**
721 * Adds a new CONSTANT_Double_info to the constant pool of this symbol table.
722 *
723 * @param index the constant pool index of the new Symbol.
724 * @param tag one of {@link Symbol#CONSTANT_LONG_TAG} or {@link Symbol#CONSTANT_DOUBLE_TAG}.
725 * @param value a long or double.
726 */
727 private void addConstantLong(final int index, final int tag, final long value) {
728 add(new Entry(index, tag, value, hash(tag, value)));
729 }
730
731 /**
732 * Adds a CONSTANT_NameAndType_info to the constant pool of this symbol table. Does nothing if the
733 * constant pool already contains a similar item.
734 *
735 * @param name a field or method name.
736 * @param descriptor a field or method descriptor.
737 * @return a new or already existing Symbol with the given value.
738 */
739 int addConstantNameAndType(final String name, final String descriptor) {
740 final int tag = Symbol.CONSTANT_NAME_AND_TYPE_TAG;
741 int hashCode = hash(tag, name, descriptor);
742 Entry entry = get(hashCode);
743 while (entry != null) {
744 if (entry.tag == tag
745 && entry.hashCode == hashCode
746 && entry.name.equals(name)
747 && entry.value.equals(descriptor)) {
748 return entry.index;
749 }
750 entry = entry.next;
751 }
752 constantPool.put122(tag, addConstantUtf8(name), addConstantUtf8(descriptor));
753 return put(new Entry(constantPoolCount++, tag, name, descriptor, hashCode)).index;
754 }
755
756 /**
757 * Adds a new CONSTANT_NameAndType_info to the constant pool of this symbol table.
758 *
759 * @param index the constant pool index of the new Symbol.
760 * @param name a field or method name.
761 * @param descriptor a field or method descriptor.
762 */
763 private void addConstantNameAndType(final int index, final String name, final String descriptor) {
764 final int tag = Symbol.CONSTANT_NAME_AND_TYPE_TAG;
765 add(new Entry(index, tag, name, descriptor, hash(tag, name, descriptor)));
766 }
767
768 /**
769 * Adds a CONSTANT_Utf8_info to the constant pool of this symbol table. Does nothing if the
770 * constant pool already contains a similar item.
771 *
772 * @param value a string.
773 * @return a new or already existing Symbol with the given value.
774 */
775 int addConstantUtf8(final String value) {
776 int hashCode = hash(Symbol.CONSTANT_UTF8_TAG, value);
777 Entry entry = get(hashCode);
778 while (entry != null) {
779 if (entry.tag == Symbol.CONSTANT_UTF8_TAG
780 && entry.hashCode == hashCode
781 && entry.value.equals(value)) {
782 return entry.index;
783 }
784 entry = entry.next;
785 }
786 constantPool.putByte(Symbol.CONSTANT_UTF8_TAG).putUTF8(value);
787 return put(new Entry(constantPoolCount++, Symbol.CONSTANT_UTF8_TAG, value, hashCode)).index;
788 }
789
790 /**
791 * Adds a new CONSTANT_String_info to the constant pool of this symbol table.
792 *
793 * @param index the constant pool index of the new Symbol.
794 * @param value a string.
795 */
796 private void addConstantUtf8(final int index, final String value) {
797 add(new Entry(index, Symbol.CONSTANT_UTF8_TAG, value, hash(Symbol.CONSTANT_UTF8_TAG, value)));
798 }
799
800 /**
801 * Adds a CONSTANT_MethodHandle_info to the constant pool of this symbol table. Does nothing if
802 * the constant pool already contains a similar item.
803 *
804 * @param referenceKind one of {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, {@link
805 * Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, {@link
806 * Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL}, {@link
807 * Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}.
808 * @param owner the internal name of a class of interface.
809 * @param name a field or method name.
810 * @param descriptor a field or method descriptor.
811 * @param isInterface whether owner is an interface or not.
812 * @return a new or already existing Symbol with the given value.
813 */
814 Symbol addConstantMethodHandle(
815 final int referenceKind,
816 final String owner,
817 final String name,
818 final String descriptor,
819 final boolean isInterface) {
820 final int tag = Symbol.CONSTANT_METHOD_HANDLE_TAG;
821 // Note that we don't need to include isInterface in the hash computation, because it is
822 // redundant with owner (we can't have the same owner with different isInterface values).
823 int hashCode = hash(tag, owner, name, descriptor, referenceKind);
824 Entry entry = get(hashCode);
825 while (entry != null) {
826 if (entry.tag == tag
827 && entry.hashCode == hashCode
828 && entry.data == referenceKind
829 && entry.owner.equals(owner)
830 && entry.name.equals(name)
831 && entry.value.equals(descriptor)) {
832 return entry;
833 }
834 entry = entry.next;
835 }
836 if (referenceKind <= Opcodes.H_PUTSTATIC) {
837 constantPool.put112(tag, referenceKind, addConstantFieldref(owner, name, descriptor).index);
838 } else {
839 constantPool.put112(
840 tag, referenceKind, addConstantMethodref(owner, name, descriptor, isInterface).index);
841 }
842 return put(
843 new Entry(constantPoolCount++, tag, owner, name, descriptor, referenceKind, hashCode));
844 }
845
846 /**
847 * Adds a new CONSTANT_MethodHandle_info to the constant pool of this symbol table.
848 *
849 * @param index the constant pool index of the new Symbol.
850 * @param referenceKind one of {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, {@link
851 * Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, {@link
852 * Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL}, {@link
853 * Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}.
854 * @param owner the internal name of a class of interface.
855 * @param name a field or method name.
856 * @param descriptor a field or method descriptor.
857 */
858 private void addConstantMethodHandle(
859 final int index,
860 final int referenceKind,
861 final String owner,
862 final String name,
863 final String descriptor) {
864 final int tag = Symbol.CONSTANT_METHOD_HANDLE_TAG;
865 int hashCode = hash(tag, owner, name, descriptor, referenceKind);
866 add(new Entry(index, tag, owner, name, descriptor, referenceKind, hashCode));
867 }
868
869 /**
870 * Adds a CONSTANT_MethodType_info to the constant pool of this symbol table. Does nothing if the
871 * constant pool already contains a similar item.
872 *
873 * @param methodDescriptor a method descriptor.
874 * @return a new or already existing Symbol with the given value.
875 */
876 Symbol addConstantMethodType(final String methodDescriptor) {
877 return addConstantUtf8Reference(Symbol.CONSTANT_METHOD_TYPE_TAG, methodDescriptor);
878 }
879
880 /**
881 * Adds a CONSTANT_Dynamic_info to the constant pool of this symbol table. Also adds the related
882 * bootstrap method to the BootstrapMethods of this symbol table. Does nothing if the constant
883 * pool already contains a similar item.
884 *
885 * @param name a method name.
886 * @param descriptor a field descriptor.
887 * @param bootstrapMethodHandle a bootstrap method handle.
888 * @param bootstrapMethodArguments the bootstrap method arguments.
889 * @return a new or already existing Symbol with the given value.
890 */
891 Symbol addConstantDynamic(
892 final String name,
893 final String descriptor,
894 final Handle bootstrapMethodHandle,
895 final Object... bootstrapMethodArguments) {
896 Symbol bootstrapMethod = addBootstrapMethod(bootstrapMethodHandle, bootstrapMethodArguments);
897 return addConstantDynamicOrInvokeDynamicReference(
898 Symbol.CONSTANT_DYNAMIC_TAG, name, descriptor, bootstrapMethod.index);
899 }
900
901 /**
902 * Adds a CONSTANT_InvokeDynamic_info to the constant pool of this symbol table. Also adds the
903 * related bootstrap method to the BootstrapMethods of this symbol table. Does nothing if the
904 * constant pool already contains a similar item.
905 *
906 * @param name a method name.
907 * @param descriptor a method descriptor.
908 * @param bootstrapMethodHandle a bootstrap method handle.
909 * @param bootstrapMethodArguments the bootstrap method arguments.
910 * @return a new or already existing Symbol with the given value.
911 */
912 Symbol addConstantInvokeDynamic(
913 final String name,
914 final String descriptor,
915 final Handle bootstrapMethodHandle,
916 final Object... bootstrapMethodArguments) {
917 Symbol bootstrapMethod = addBootstrapMethod(bootstrapMethodHandle, bootstrapMethodArguments);
918 return addConstantDynamicOrInvokeDynamicReference(
919 Symbol.CONSTANT_INVOKE_DYNAMIC_TAG, name, descriptor, bootstrapMethod.index);
920 }
921
922 /**
923 * Adds a CONSTANT_Dynamic or a CONSTANT_InvokeDynamic_info to the constant pool of this symbol
924 * table. Does nothing if the constant pool already contains a similar item.
925 *
926 * @param tag one of {@link Symbol#CONSTANT_DYNAMIC_TAG} or {@link
927 * Symbol#CONSTANT_INVOKE_DYNAMIC_TAG}.
928 * @param name a method name.
929 * @param descriptor a field descriptor for CONSTANT_DYNAMIC_TAG) or a method descriptor for
930 * CONSTANT_INVOKE_DYNAMIC_TAG.
931 * @param bootstrapMethodIndex the index of a bootstrap method in the BootstrapMethods attribute.
932 * @return a new or already existing Symbol with the given value.
933 */
934 private Symbol addConstantDynamicOrInvokeDynamicReference(
935 final int tag, final String name, final String descriptor, final int bootstrapMethodIndex) {
936 int hashCode = hash(tag, name, descriptor, bootstrapMethodIndex);
937 Entry entry = get(hashCode);
938 while (entry != null) {
939 if (entry.tag == tag
940 && entry.hashCode == hashCode
941 && entry.data == bootstrapMethodIndex
942 && entry.name.equals(name)
943 && entry.value.equals(descriptor)) {
944 return entry;
945 }
946 entry = entry.next;
947 }
948 constantPool.put122(tag, bootstrapMethodIndex, addConstantNameAndType(name, descriptor));
949 return put(
950 new Entry(
951 constantPoolCount++, tag, null, name, descriptor, bootstrapMethodIndex, hashCode));
952 }
953
954 /**
955 * Adds a new CONSTANT_Dynamic_info or CONSTANT_InvokeDynamic_info to the constant pool of this
956 * symbol table.
957 *
958 * @param tag one of {@link Symbol#CONSTANT_DYNAMIC_TAG} or {@link
959 * Symbol#CONSTANT_INVOKE_DYNAMIC_TAG}.
960 * @param index the constant pool index of the new Symbol.
961 * @param name a method name.
962 * @param descriptor a field descriptor for CONSTANT_DYNAMIC_TAG or a method descriptor for
963 * CONSTANT_INVOKE_DYNAMIC_TAG.
964 * @param bootstrapMethodIndex the index of a bootstrap method in the BootstrapMethods attribute.
965 */
966 private void addConstantDynamicOrInvokeDynamicReference(
967 final int tag,
968 final int index,
969 final String name,
970 final String descriptor,
971 final int bootstrapMethodIndex) {
972 int hashCode = hash(tag, name, descriptor, bootstrapMethodIndex);
973 add(new Entry(index, tag, null, name, descriptor, bootstrapMethodIndex, hashCode));
974 }
975
976 /**
977 * Adds a CONSTANT_Module_info to the constant pool of this symbol table. Does nothing if the
978 * constant pool already contains a similar item.
979 *
980 * @param moduleName a fully qualified name (using dots) of a module.
981 * @return a new or already existing Symbol with the given value.
982 */
983 Symbol addConstantModule(final String moduleName) {
984 return addConstantUtf8Reference(Symbol.CONSTANT_MODULE_TAG, moduleName);
985 }
986
987 /**
988 * Adds a CONSTANT_Package_info to the constant pool of this symbol table. Does nothing if the
989 * constant pool already contains a similar item.
990 *
991 * @param packageName the internal name of a package.
992 * @return a new or already existing Symbol with the given value.
993 */
994 Symbol addConstantPackage(final String packageName) {
995 return addConstantUtf8Reference(Symbol.CONSTANT_PACKAGE_TAG, packageName);
996 }
997
998 /**
999 * Adds a CONSTANT_Class_info, CONSTANT_String_info, CONSTANT_MethodType_info,
1000 * CONSTANT_Module_info or CONSTANT_Package_info to the constant pool of this symbol table. Does
1001 * nothing if the constant pool already contains a similar item.
1002 *
1003 * @param tag one of {@link Symbol#CONSTANT_CLASS_TAG}, {@link Symbol#CONSTANT_STRING_TAG}, {@link
1004 * Symbol#CONSTANT_METHOD_TYPE_TAG}, {@link Symbol#CONSTANT_MODULE_TAG} or {@link
1005 * Symbol#CONSTANT_PACKAGE_TAG}.
1006 * @param value an internal class name, an arbitrary string, a method descriptor, a module or a
1007 * package name, depending on tag.
1008 * @return a new or already existing Symbol with the given value.
1009 */
1010 private Symbol addConstantUtf8Reference(final int tag, final String value) {
1011 int hashCode = hash(tag, value);
1012 Entry entry = get(hashCode);
1013 while (entry != null) {
1014 if (entry.tag == tag && entry.hashCode == hashCode && entry.value.equals(value)) {
1015 return entry;
1016 }
1017 entry = entry.next;
1018 }
1019 constantPool.put12(tag, addConstantUtf8(value));
1020 return put(new Entry(constantPoolCount++, tag, value, hashCode));
1021 }
1022
1023 /**
1024 * Adds a new CONSTANT_Class_info, CONSTANT_String_info, CONSTANT_MethodType_info,
1025 * CONSTANT_Module_info or CONSTANT_Package_info to the constant pool of this symbol table.
1026 *
1027 * @param index the constant pool index of the new Symbol.
1028 * @param tag one of {@link Symbol#CONSTANT_CLASS_TAG}, {@link Symbol#CONSTANT_STRING_TAG}, {@link
1029 * Symbol#CONSTANT_METHOD_TYPE_TAG}, {@link Symbol#CONSTANT_MODULE_TAG} or {@link
1030 * Symbol#CONSTANT_PACKAGE_TAG}.
1031 * @param value an internal class name, an arbitrary string, a method descriptor, a module or a
1032 * package name, depending on tag.
1033 */
1034 private void addConstantUtf8Reference(final int index, final int tag, final String value) {
1035 add(new Entry(index, tag, value, hash(tag, value)));
1036 }
1037
1038 // -----------------------------------------------------------------------------------------------
1039 // Bootstrap method entries management.
1040 // -----------------------------------------------------------------------------------------------
1041
1042 /**
1043 * Adds a bootstrap method to the BootstrapMethods attribute of this symbol table. Does nothing if
1044 * the BootstrapMethods already contains a similar bootstrap method.
1045 *
1046 * @param bootstrapMethodHandle a bootstrap method handle.
1047 * @param bootstrapMethodArguments the bootstrap method arguments.
1048 * @return a new or already existing Symbol with the given value.
1049 */
1050 Symbol addBootstrapMethod(
1051 final Handle bootstrapMethodHandle, final Object... bootstrapMethodArguments) {
1052 ByteVector bootstrapMethodsAttribute = bootstrapMethods;
1053 if (bootstrapMethodsAttribute == null) {
1054 bootstrapMethodsAttribute = bootstrapMethods = new ByteVector();
1055 }
1056
1057 // The bootstrap method arguments can be Constant_Dynamic values, which reference other
1058 // bootstrap methods. We must therefore add the bootstrap method arguments to the constant pool
1059 // and BootstrapMethods attribute first, so that the BootstrapMethods attribute is not modified
1060 // while adding the given bootstrap method to it, in the rest of this method.
1061 for (Object bootstrapMethodArgument : bootstrapMethodArguments) {
1062 addConstant(bootstrapMethodArgument);
1063 }
1064
1065 // Write the bootstrap method in the BootstrapMethods table. This is necessary to be able to
1066 // compare it with existing ones, and will be reverted below if there is already a similar
1067 // bootstrap method.
1068 int bootstrapMethodOffset = bootstrapMethodsAttribute.length;
1069 bootstrapMethodsAttribute.putShort(
1070 addConstantMethodHandle(
1071 bootstrapMethodHandle.getTag(),
1072 bootstrapMethodHandle.getOwner(),
1073 bootstrapMethodHandle.getName(),
1074 bootstrapMethodHandle.getDesc(),
1075 bootstrapMethodHandle.isInterface())
1076 .index);
1077 int numBootstrapArguments = bootstrapMethodArguments.length;
1078 bootstrapMethodsAttribute.putShort(numBootstrapArguments);
1079 for (Object bootstrapMethodArgument : bootstrapMethodArguments) {
1080 bootstrapMethodsAttribute.putShort(addConstant(bootstrapMethodArgument).index);
1081 }
1082
1083 // Compute the length and the hash code of the bootstrap method.
1084 int bootstrapMethodlength = bootstrapMethodsAttribute.length - bootstrapMethodOffset;
1085 int hashCode = bootstrapMethodHandle.hashCode();
1086 for (Object bootstrapMethodArgument : bootstrapMethodArguments) {
1087 hashCode ^= bootstrapMethodArgument.hashCode();
1088 }
1089 hashCode &= 0x7FFFFFFF;
1090
1091 // Add the bootstrap method to the symbol table or revert the above changes.
1092 return addBootstrapMethod(bootstrapMethodOffset, bootstrapMethodlength, hashCode);
1093 }
1094
1095 /**
1096 * Adds a bootstrap method to the BootstrapMethods attribute of this symbol table. Does nothing if
1097 * the BootstrapMethods already contains a similar bootstrap method (more precisely, reverts the
1098 * content of {@link #bootstrapMethods} to remove the last, duplicate bootstrap method).
1099 *
1100 * @param offset the offset of the last bootstrap method in {@link #bootstrapMethods}, in bytes.
1101 * @param length the length of this bootstrap method in {@link #bootstrapMethods}, in bytes.
1102 * @param hashCode the hash code of this bootstrap method.
1103 * @return a new or already existing Symbol with the given value.
1104 */
1105 private Symbol addBootstrapMethod(final int offset, final int length, final int hashCode) {
1106 final byte[] bootstrapMethodsData = bootstrapMethods.data;
1107 Entry entry = get(hashCode);
1108 while (entry != null) {
1109 if (entry.tag == Symbol.BOOTSTRAP_METHOD_TAG && entry.hashCode == hashCode) {
1110 int otherOffset = (int) entry.data;
1111 boolean isSameBootstrapMethod = true;
1112 for (int i = 0; i < length; ++i) {
1113 if (bootstrapMethodsData[offset + i] != bootstrapMethodsData[otherOffset + i]) {
1114 isSameBootstrapMethod = false;
1115 break;
1116 }
1117 }
1118 if (isSameBootstrapMethod) {
1119 bootstrapMethods.length = offset; // Revert to old position.
1120 return entry;
1121 }
1122 }
1123 entry = entry.next;
1124 }
1125 return put(new Entry(bootstrapMethodCount++, Symbol.BOOTSTRAP_METHOD_TAG, offset, hashCode));
1126 }
1127
1128 // -----------------------------------------------------------------------------------------------
1129 // Type table entries management.
1130 // -----------------------------------------------------------------------------------------------
1131
1132 /**
1133 * @param typeIndex a type table index.
1134 * @return the type table element whose index is given.
1135 */
1136 Symbol getType(final int typeIndex) {
1137 return typeTable[typeIndex];
1138 }
1139
1140 /**
1141 * Adds a type in the type table of this symbol table. Does nothing if the type table already
1142 * contains a similar type.
1143 *
1144 * @param value an internal class name.
1145 * @return the index of a new or already existing type Symbol with the given value.
1146 */
1147 int addType(final String value) {
1148 int hashCode = hash(Symbol.TYPE_TAG, value);
1149 Entry entry = get(hashCode);
1150 while (entry != null) {
1151 if (entry.tag == Symbol.TYPE_TAG && entry.hashCode == hashCode && entry.value.equals(value)) {
1152 return entry.index;
1153 }
1154 entry = entry.next;
1155 }
1156 return addType(new Entry(typeCount, Symbol.TYPE_TAG, value, hashCode));
1157 }
1158
1159 /**
1160 * Adds an {@link Frame#ITEM_UNINITIALIZED} type in the type table of this symbol table. Does
1161 * nothing if the type table already contains a similar type.
1162 *
1163 * @param value an internal class name.
1164 * @param bytecodeOffset the bytecode offset of the NEW instruction that created this {@link
1165 * Frame#ITEM_UNINITIALIZED} type value.
1166 * @return the index of a new or already existing type Symbol with the given value.
1167 */
1168 int addUninitializedType(final String value, final int bytecodeOffset) {
1169 int hashCode = hash(Symbol.UNINITIALIZED_TYPE_TAG, value, bytecodeOffset);
1170 Entry entry = get(hashCode);
1171 while (entry != null) {
1172 if (entry.tag == Symbol.UNINITIALIZED_TYPE_TAG
1173 && entry.hashCode == hashCode
1174 && entry.data == bytecodeOffset
1175 && entry.value.equals(value)) {
1176 return entry.index;
1177 }
1178 entry = entry.next;
1179 }
1180 return addType(
1181 new Entry(typeCount, Symbol.UNINITIALIZED_TYPE_TAG, value, bytecodeOffset, hashCode));
1182 }
1183
1184 /**
1185 * Adds a merged type in the type table of this symbol table. Does nothing if the type table
1186 * already contains a similar type.
1187 *
1188 * @param typeTableIndex1 a {@link Symbol#TYPE_TAG} type, specified by its index in the type
1189 * table.
1190 * @param typeTableIndex2 another {@link Symbol#TYPE_TAG} type, specified by its index in the type
1191 * table.
1192 * @return the index of a new or already existing {@link Symbol#TYPE_TAG} type Symbol,
1193 * corresponding to the common super class of the given types.
1194 */
1195 int addMergedType(final int typeTableIndex1, final int typeTableIndex2) {
1196 // TODO sort the arguments? The merge result should be independent of their order.
1197 long data = typeTableIndex1 | (((long) typeTableIndex2) << 32);
1198 int hashCode = hash(Symbol.MERGED_TYPE_TAG, typeTableIndex1 + typeTableIndex2);
1199 Entry entry = get(hashCode);
1200 while (entry != null) {
1201 if (entry.tag == Symbol.MERGED_TYPE_TAG && entry.hashCode == hashCode && entry.data == data) {
1202 return entry.info;
1203 }
1204 entry = entry.next;
1205 }
1206 String type1 = typeTable[typeTableIndex1].value;
1207 String type2 = typeTable[typeTableIndex2].value;
1208 int commonSuperTypeIndex = addType(classWriter.getCommonSuperClass(type1, type2));
1209 put(new Entry(typeCount, Symbol.MERGED_TYPE_TAG, data, hashCode)).info = commonSuperTypeIndex;
1210 return commonSuperTypeIndex;
1211 }
1212
1213 /**
1214 * Adds the given type Symbol to {@link #typeTable}.
1215 *
1216 * @param entry a {@link Symbol#TYPE_TAG} or {@link Symbol#UNINITIALIZED_TYPE_TAG} type symbol.
1217 * The index of this Symbol must be equal to the current value of {@link #typeCount}.
1218 * @return the index in {@link #typeTable} where the given type was added, which is also equal to
1219 * entry's index by hypothesis.
1220 */
1221 private int addType(final Entry entry) {
1222 if (typeTable == null) {
1223 typeTable = new Entry[16];
1224 }
1225 if (typeCount == typeTable.length) {
1226 Entry[] newTypeTable = new Entry[2 * typeTable.length];
1227 System.arraycopy(typeTable, 0, newTypeTable, 0, typeTable.length);
1228 typeTable = newTypeTable;
1229 }
1230 typeTable[typeCount++] = entry;
1231 return put(entry).index;
1232 }
1233
1234 // -----------------------------------------------------------------------------------------------
1235 // Static helper methods to compute hash codes.
1236 // -----------------------------------------------------------------------------------------------
1237
1238 private static int hash(final int tag, final int value) {
1239 return 0x7FFFFFFF & (tag + value);
1240 }
1241
1242 private static int hash(final int tag, final long value) {
1243 return 0x7FFFFFFF & (tag + (int) value + (int) (value >>> 32));
1244 }
1245
1246 private static int hash(final int tag, final String value) {
1247 return 0x7FFFFFFF & (tag + value.hashCode());
1248 }
1249
1250 private static int hash(final int tag, final String value1, final int value2) {
1251 return 0x7FFFFFFF & (tag + value1.hashCode() + value2);
1252 }
1253
1254 private static int hash(final int tag, final String value1, final String value2) {
1255 return 0x7FFFFFFF & (tag + value1.hashCode() * value2.hashCode());
1256 }
1257
1258 private static int hash(
1259 final int tag, final String value1, final String value2, final int value3) {
1260 return 0x7FFFFFFF & (tag + value1.hashCode() * value2.hashCode() * (value3 + 1));
1261 }
1262
1263 private static int hash(
1264 final int tag, final String value1, final String value2, final String value3) {
1265 return 0x7FFFFFFF & (tag + value1.hashCode() * value2.hashCode() * value3.hashCode());
1266 }
1267
1268 private static int hash(
1269 final int tag,
1270 final String value1,
1271 final String value2,
1272 final String value3,
1273 final int value4) {
1274 return 0x7FFFFFFF & (tag + value1.hashCode() * value2.hashCode() * value3.hashCode() * value4);
1275 }
1276 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm;
3028
3129 import java.lang.reflect.Constructor;
3230 import java.lang.reflect.Method;
3331
3432 /**
35 * A Java field or method type. This class can be used to make it easier to
36 * manipulate type and method descriptors.
37 *
33 * A Java field or method type. This class can be used to make it easier to manipulate type and
34 * method descriptors.
35 *
3836 * @author Eric Bruneton
3937 * @author Chris Nokleberg
4038 */
4139 public class Type {
4240
43 /**
44 * The sort of the <tt>void</tt> type. See {@link #getSort getSort}.
45 */
46 public static final int VOID = 0;
47
48 /**
49 * The sort of the <tt>boolean</tt> type. See {@link #getSort getSort}.
50 */
51 public static final int BOOLEAN = 1;
52
53 /**
54 * The sort of the <tt>char</tt> type. See {@link #getSort getSort}.
55 */
56 public static final int CHAR = 2;
57
58 /**
59 * The sort of the <tt>byte</tt> type. See {@link #getSort getSort}.
60 */
61 public static final int BYTE = 3;
62
63 /**
64 * The sort of the <tt>short</tt> type. See {@link #getSort getSort}.
65 */
66 public static final int SHORT = 4;
67
68 /**
69 * The sort of the <tt>int</tt> type. See {@link #getSort getSort}.
70 */
71 public static final int INT = 5;
72
73 /**
74 * The sort of the <tt>float</tt> type. See {@link #getSort getSort}.
75 */
76 public static final int FLOAT = 6;
77
78 /**
79 * The sort of the <tt>long</tt> type. See {@link #getSort getSort}.
80 */
81 public static final int LONG = 7;
82
83 /**
84 * The sort of the <tt>double</tt> type. See {@link #getSort getSort}.
85 */
86 public static final int DOUBLE = 8;
87
88 /**
89 * The sort of array reference types. See {@link #getSort getSort}.
90 */
91 public static final int ARRAY = 9;
92
93 /**
94 * The sort of object reference types. See {@link #getSort getSort}.
95 */
96 public static final int OBJECT = 10;
97
98 /**
99 * The sort of method types. See {@link #getSort getSort}.
100 */
101 public static final int METHOD = 11;
102
103 /**
104 * The <tt>void</tt> type.
105 */
106 public static final Type VOID_TYPE = new Type(VOID, null, ('V' << 24)
107 | (5 << 16) | (0 << 8) | 0, 1);
108
109 /**
110 * The <tt>boolean</tt> type.
111 */
112 public static final Type BOOLEAN_TYPE = new Type(BOOLEAN, null, ('Z' << 24)
113 | (0 << 16) | (5 << 8) | 1, 1);
114
115 /**
116 * The <tt>char</tt> type.
117 */
118 public static final Type CHAR_TYPE = new Type(CHAR, null, ('C' << 24)
119 | (0 << 16) | (6 << 8) | 1, 1);
120
121 /**
122 * The <tt>byte</tt> type.
123 */
124 public static final Type BYTE_TYPE = new Type(BYTE, null, ('B' << 24)
125 | (0 << 16) | (5 << 8) | 1, 1);
126
127 /**
128 * The <tt>short</tt> type.
129 */
130 public static final Type SHORT_TYPE = new Type(SHORT, null, ('S' << 24)
131 | (0 << 16) | (7 << 8) | 1, 1);
132
133 /**
134 * The <tt>int</tt> type.
135 */
136 public static final Type INT_TYPE = new Type(INT, null, ('I' << 24)
137 | (0 << 16) | (0 << 8) | 1, 1);
138
139 /**
140 * The <tt>float</tt> type.
141 */
142 public static final Type FLOAT_TYPE = new Type(FLOAT, null, ('F' << 24)
143 | (2 << 16) | (2 << 8) | 1, 1);
144
145 /**
146 * The <tt>long</tt> type.
147 */
148 public static final Type LONG_TYPE = new Type(LONG, null, ('J' << 24)
149 | (1 << 16) | (1 << 8) | 2, 1);
150
151 /**
152 * The <tt>double</tt> type.
153 */
154 public static final Type DOUBLE_TYPE = new Type(DOUBLE, null, ('D' << 24)
155 | (3 << 16) | (3 << 8) | 2, 1);
156
157 // ------------------------------------------------------------------------
158 // Fields
159 // ------------------------------------------------------------------------
160
161 /**
162 * The sort of this Java type.
163 */
164 private final int sort;
165
166 /**
167 * A buffer containing the internal name of this Java type. This field is
168 * only used for reference types.
169 */
170 private final char[] buf;
171
172 /**
173 * The offset of the internal name of this Java type in {@link #buf buf} or,
174 * for primitive types, the size, descriptor and getOpcode offsets for this
175 * type (byte 0 contains the size, byte 1 the descriptor, byte 2 the offset
176 * for IALOAD or IASTORE, byte 3 the offset for all other instructions).
177 */
178 private final int off;
179
180 /**
181 * The length of the internal name of this Java type.
182 */
183 private final int len;
184
185 // ------------------------------------------------------------------------
186 // Constructors
187 // ------------------------------------------------------------------------
188
189 /**
190 * Constructs a reference type.
191 *
192 * @param sort
193 * the sort of the reference type to be constructed.
194 * @param buf
195 * a buffer containing the descriptor of the previous type.
196 * @param off
197 * the offset of this descriptor in the previous buffer.
198 * @param len
199 * the length of this descriptor.
200 */
201 private Type(final int sort, final char[] buf, final int off, final int len) {
202 this.sort = sort;
203 this.buf = buf;
204 this.off = off;
205 this.len = len;
206 }
207
208 /**
209 * Returns the Java type corresponding to the given type descriptor.
210 *
211 * @param typeDescriptor
212 * a field or method type descriptor.
213 * @return the Java type corresponding to the given type descriptor.
214 */
215 public static Type getType(final String typeDescriptor) {
216 return getType(typeDescriptor.toCharArray(), 0);
217 }
218
219 /**
220 * Returns the Java type corresponding to the given internal name.
221 *
222 * @param internalName
223 * an internal name.
224 * @return the Java type corresponding to the given internal name.
225 */
226 public static Type getObjectType(final String internalName) {
227 char[] buf = internalName.toCharArray();
228 return new Type(buf[0] == '[' ? ARRAY : OBJECT, buf, 0, buf.length);
229 }
230
231 /**
232 * Returns the Java type corresponding to the given method descriptor.
233 * Equivalent to <code>Type.getType(methodDescriptor)</code>.
234 *
235 * @param methodDescriptor
236 * a method descriptor.
237 * @return the Java type corresponding to the given method descriptor.
238 */
239 public static Type getMethodType(final String methodDescriptor) {
240 return getType(methodDescriptor.toCharArray(), 0);
241 }
242
243 /**
244 * Returns the Java method type corresponding to the given argument and
245 * return types.
246 *
247 * @param returnType
248 * the return type of the method.
249 * @param argumentTypes
250 * the argument types of the method.
251 * @return the Java type corresponding to the given argument and return
252 * types.
253 */
254 public static Type getMethodType(final Type returnType,
255 final Type... argumentTypes) {
256 return getType(getMethodDescriptor(returnType, argumentTypes));
257 }
258
259 /**
260 * Returns the Java type corresponding to the given class.
261 *
262 * @param c
263 * a class.
264 * @return the Java type corresponding to the given class.
265 */
266 public static Type getType(final Class<?> c) {
267 if (c.isPrimitive()) {
268 if (c == Integer.TYPE) {
269 return INT_TYPE;
270 } else if (c == Void.TYPE) {
271 return VOID_TYPE;
272 } else if (c == Boolean.TYPE) {
273 return BOOLEAN_TYPE;
274 } else if (c == Byte.TYPE) {
275 return BYTE_TYPE;
276 } else if (c == Character.TYPE) {
277 return CHAR_TYPE;
278 } else if (c == Short.TYPE) {
279 return SHORT_TYPE;
280 } else if (c == Double.TYPE) {
281 return DOUBLE_TYPE;
282 } else if (c == Float.TYPE) {
283 return FLOAT_TYPE;
284 } else /* if (c == Long.TYPE) */{
285 return LONG_TYPE;
286 }
287 } else {
288 return getType(getDescriptor(c));
41 /** The sort of the <tt>void</tt> type. See {@link #getSort}. */
42 public static final int VOID = 0;
43
44 /** The sort of the <tt>boolean</tt> type. See {@link #getSort}. */
45 public static final int BOOLEAN = 1;
46
47 /** The sort of the <tt>char</tt> type. See {@link #getSort}. */
48 public static final int CHAR = 2;
49
50 /** The sort of the <tt>byte</tt> type. See {@link #getSort}. */
51 public static final int BYTE = 3;
52
53 /** The sort of the <tt>short</tt> type. See {@link #getSort}. */
54 public static final int SHORT = 4;
55
56 /** The sort of the <tt>int</tt> type. See {@link #getSort}. */
57 public static final int INT = 5;
58
59 /** The sort of the <tt>float</tt> type. See {@link #getSort}. */
60 public static final int FLOAT = 6;
61
62 /** The sort of the <tt>long</tt> type. See {@link #getSort}. */
63 public static final int LONG = 7;
64
65 /** The sort of the <tt>double</tt> type. See {@link #getSort}. */
66 public static final int DOUBLE = 8;
67
68 /** The sort of array reference types. See {@link #getSort}. */
69 public static final int ARRAY = 9;
70
71 /** The sort of object reference types. See {@link #getSort}. */
72 public static final int OBJECT = 10;
73
74 /** The sort of method types. See {@link #getSort}. */
75 public static final int METHOD = 11;
76
77 /** The (private) sort of object reference types represented with an internal name. */
78 private static final int INTERNAL = 12;
79
80 /** The descriptors of the primitive types. */
81 private static final String PRIMITIVE_DESCRIPTORS = "VZCBSIFJD";
82
83 /** The <tt>void</tt> type. */
84 public static final Type VOID_TYPE = new Type(VOID, PRIMITIVE_DESCRIPTORS, VOID, VOID + 1);
85
86 /** The <tt>boolean</tt> type. */
87 public static final Type BOOLEAN_TYPE =
88 new Type(BOOLEAN, PRIMITIVE_DESCRIPTORS, BOOLEAN, BOOLEAN + 1);
89
90 /** The <tt>char</tt> type. */
91 public static final Type CHAR_TYPE = new Type(CHAR, PRIMITIVE_DESCRIPTORS, CHAR, CHAR + 1);
92
93 /** The <tt>byte</tt> type. */
94 public static final Type BYTE_TYPE = new Type(BYTE, PRIMITIVE_DESCRIPTORS, BYTE, BYTE + 1);
95
96 /** The <tt>short</tt> type. */
97 public static final Type SHORT_TYPE = new Type(SHORT, PRIMITIVE_DESCRIPTORS, SHORT, SHORT + 1);
98
99 /** The <tt>int</tt> type. */
100 public static final Type INT_TYPE = new Type(INT, PRIMITIVE_DESCRIPTORS, INT, INT + 1);
101
102 /** The <tt>float</tt> type. */
103 public static final Type FLOAT_TYPE = new Type(FLOAT, PRIMITIVE_DESCRIPTORS, FLOAT, FLOAT + 1);
104
105 /** The <tt>long</tt> type. */
106 public static final Type LONG_TYPE = new Type(LONG, PRIMITIVE_DESCRIPTORS, LONG, LONG + 1);
107
108 /** The <tt>double</tt> type. */
109 public static final Type DOUBLE_TYPE =
110 new Type(DOUBLE, PRIMITIVE_DESCRIPTORS, DOUBLE, DOUBLE + 1);
111
112 // -----------------------------------------------------------------------------------------------
113 // Fields
114 // -----------------------------------------------------------------------------------------------
115
116 /**
117 * The sort of this type. Either {@link #VOID}, {@link #BOOLEAN}, {@link #CHAR}, {@link #BYTE},
118 * {@link #SHORT}, {@link #INT}, {@link #FLOAT}, {@link #LONG}, {@link #DOUBLE}, {@link #ARRAY},
119 * {@link #OBJECT}, {@link #METHOD} or {@link #INTERNAL}.
120 */
121 private final int sort;
122
123 /**
124 * A buffer containing the value of this field or method type. This value is an internal name for
125 * {@link #OBJECT} and {@link #INTERNAL} types, and a field or method descriptor in the other
126 * cases.
127 *
128 * <p>For {@link #OBJECT} types, this field also contains the descriptor: the characters in
129 * [{@link #valueBegin},{@link #valueEnd}) contain the internal name, and those in [{@link
130 * #valueBegin} - 1, {@link #valueEnd} + 1) contain the descriptor.
131 */
132 private final String valueBuffer;
133
134 /**
135 * The beginning index, inclusive, of the value of this Java field or method type in {@link
136 * #valueBuffer}. This value is an internal name for {@link #OBJECT} and {@link #INTERNAL} types,
137 * and a field or method descriptor in the other cases.
138 */
139 private final int valueBegin;
140
141 /**
142 * The end index, exclusive, of the value of this Java field or method type in {@link
143 * #valueBuffer}. This value is an internal name for {@link #OBJECT} and {@link #INTERNAL} types,
144 * and a field or method descriptor in the other cases.
145 */
146 private final int valueEnd;
147
148 // -----------------------------------------------------------------------------------------------
149 // Constructors
150 // -----------------------------------------------------------------------------------------------
151
152 /**
153 * Constructs a reference type.
154 *
155 * @param sort the sort of this type, see {@link #sort}.
156 * @param valueBuffer a buffer containing the value of this field or method type.
157 * @param valueBegin the beginning index, inclusive, of the value of this field or method type in
158 * valueBuffer.
159 * @param valueEnd tne end index, exclusive, of the value of this field or method type in
160 * valueBuffer.
161 */
162 private Type(final int sort, final String valueBuffer, final int valueBegin, final int valueEnd) {
163 this.sort = sort;
164 this.valueBuffer = valueBuffer;
165 this.valueBegin = valueBegin;
166 this.valueEnd = valueEnd;
167 }
168
169 /**
170 * Returns the {@link Type} corresponding to the given type descriptor.
171 *
172 * @param typeDescriptor a field or method type descriptor.
173 * @return the {@link Type} corresponding to the given type descriptor.
174 */
175 public static Type getType(final String typeDescriptor) {
176 return getType(typeDescriptor, 0, typeDescriptor.length());
177 }
178
179 /**
180 * Returns the {@link Type} corresponding to the given internal name.
181 *
182 * @param internalName an internal name.
183 * @return the {@link Type} corresponding to the given internal name.
184 */
185 public static Type getObjectType(final String internalName) {
186 return new Type(
187 internalName.charAt(0) == '[' ? ARRAY : INTERNAL, internalName, 0, internalName.length());
188 }
189
190 /**
191 * Returns the {@link Type} corresponding to the given method descriptor. Equivalent to <code>
192 * Type.getType(methodDescriptor)</code>.
193 *
194 * @param methodDescriptor a method descriptor.
195 * @return the {@link Type} corresponding to the given method descriptor.
196 */
197 public static Type getMethodType(final String methodDescriptor) {
198 return new Type(METHOD, methodDescriptor, 0, methodDescriptor.length());
199 }
200
201 /**
202 * Returns the method {@link Type} corresponding to the given argument and return types.
203 *
204 * @param returnType the return type of the method.
205 * @param argumentTypes the argument types of the method.
206 * @return the method {@link Type} corresponding to the given argument and return types.
207 */
208 public static Type getMethodType(final Type returnType, final Type... argumentTypes) {
209 return getType(getMethodDescriptor(returnType, argumentTypes));
210 }
211
212 /**
213 * Returns the {@link Type} corresponding to the given class.
214 *
215 * @param clazz a class.
216 * @return the {@link Type} corresponding to the given class.
217 */
218 public static Type getType(final Class<?> clazz) {
219 if (clazz.isPrimitive()) {
220 if (clazz == Integer.TYPE) {
221 return INT_TYPE;
222 } else if (clazz == Void.TYPE) {
223 return VOID_TYPE;
224 } else if (clazz == Boolean.TYPE) {
225 return BOOLEAN_TYPE;
226 } else if (clazz == Byte.TYPE) {
227 return BYTE_TYPE;
228 } else if (clazz == Character.TYPE) {
229 return CHAR_TYPE;
230 } else if (clazz == Short.TYPE) {
231 return SHORT_TYPE;
232 } else if (clazz == Double.TYPE) {
233 return DOUBLE_TYPE;
234 } else if (clazz == Float.TYPE) {
235 return FLOAT_TYPE;
236 } else if (clazz == Long.TYPE) {
237 return LONG_TYPE;
238 } else {
239 throw new AssertionError();
240 }
241 } else {
242 return getType(getDescriptor(clazz));
243 }
244 }
245
246 /**
247 * Returns the method {@link Type} corresponding to the given constructor.
248 *
249 * @param constructor a {@link Constructor} object.
250 * @return the method {@link Type} corresponding to the given constructor.
251 */
252 public static Type getType(final Constructor<?> constructor) {
253 return getType(getConstructorDescriptor(constructor));
254 }
255
256 /**
257 * Returns the method {@link Type} corresponding to the given method.
258 *
259 * @param method a {@link Method} object.
260 * @return the method {@link Type} corresponding to the given method.
261 */
262 public static Type getType(final Method method) {
263 return getType(getMethodDescriptor(method));
264 }
265
266 /**
267 * Returns the {@link Type} values corresponding to the argument types of the given method
268 * descriptor.
269 *
270 * @param methodDescriptor a method descriptor.
271 * @return the {@link Type} values corresponding to the argument types of the given method
272 * descriptor.
273 */
274 public static Type[] getArgumentTypes(final String methodDescriptor) {
275 // First step: compute the number of argument types in methodDescriptor.
276 int numArgumentTypes = 0;
277 // Skip the first character, which is always a '('.
278 int currentOffset = 1;
279 // Parse the argument types, one at a each loop iteration.
280 while (methodDescriptor.charAt(currentOffset) != ')') {
281 while (methodDescriptor.charAt(currentOffset) == '[') {
282 currentOffset++;
283 }
284 if (methodDescriptor.charAt(currentOffset++) == 'L') {
285 while (methodDescriptor.charAt(currentOffset++) != ';') {
286 // Skip the argument descriptor content.
289287 }
290 }
291
292 /**
293 * Returns the Java method type corresponding to the given constructor.
294 *
295 * @param c
296 * a {@link Constructor Constructor} object.
297 * @return the Java method type corresponding to the given constructor.
298 */
299 public static Type getType(final Constructor<?> c) {
300 return getType(getConstructorDescriptor(c));
301 }
302
303 /**
304 * Returns the Java method type corresponding to the given method.
305 *
306 * @param m
307 * a {@link Method Method} object.
308 * @return the Java method type corresponding to the given method.
309 */
310 public static Type getType(final Method m) {
311 return getType(getMethodDescriptor(m));
312 }
313
314 /**
315 * Returns the Java types corresponding to the argument types of the given
316 * method descriptor.
317 *
318 * @param methodDescriptor
319 * a method descriptor.
320 * @return the Java types corresponding to the argument types of the given
321 * method descriptor.
322 */
323 public static Type[] getArgumentTypes(final String methodDescriptor) {
324 char[] buf = methodDescriptor.toCharArray();
325 int off = 1;
326 int size = 0;
327 while (true) {
328 char car = buf[off++];
329 if (car == ')') {
330 break;
331 } else if (car == 'L') {
332 while (buf[off++] != ';') {
333 }
334 ++size;
335 } else if (car != '[') {
336 ++size;
337 }
288 }
289 ++numArgumentTypes;
290 }
291
292 // Second step: create a Type instance for each argument type.
293 Type[] argumentTypes = new Type[numArgumentTypes];
294 // Skip the first character, which is always a '('.
295 currentOffset = 1;
296 // Parse and create the argument types, one at each loop iteration.
297 int currentArgumentTypeIndex = 0;
298 while (methodDescriptor.charAt(currentOffset) != ')') {
299 final int currentArgumentTypeOffset = currentOffset;
300 while (methodDescriptor.charAt(currentOffset) == '[') {
301 currentOffset++;
302 }
303 if (methodDescriptor.charAt(currentOffset++) == 'L') {
304 while (methodDescriptor.charAt(currentOffset++) != ';') {
305 // Skip the argument descriptor content.
338306 }
339 Type[] args = new Type[size];
340 off = 1;
341 size = 0;
342 while (buf[off] != ')') {
343 args[size] = getType(buf, off);
344 off += args[size].len + (args[size].sort == OBJECT ? 2 : 0);
345 size += 1;
307 }
308 argumentTypes[currentArgumentTypeIndex++] =
309 getType(methodDescriptor, currentArgumentTypeOffset, currentOffset);
310 }
311 return argumentTypes;
312 }
313
314 /**
315 * Returns the {@link Type} values corresponding to the argument types of the given method.
316 *
317 * @param method a method.
318 * @return the {@link Type} values corresponding to the argument types of the given method.
319 */
320 public static Type[] getArgumentTypes(final Method method) {
321 Class<?>[] classes = method.getParameterTypes();
322 Type[] types = new Type[classes.length];
323 for (int i = classes.length - 1; i >= 0; --i) {
324 types[i] = getType(classes[i]);
325 }
326 return types;
327 }
328
329 /**
330 * Returns the {@link Type} corresponding to the return type of the given method descriptor.
331 *
332 * @param methodDescriptor a method descriptor.
333 * @return the {@link Type} corresponding to the return type of the given method descriptor.
334 */
335 public static Type getReturnType(final String methodDescriptor) {
336 // Skip the first character, which is always a '('.
337 int currentOffset = 1;
338 // Skip the argument types, one at a each loop iteration.
339 while (methodDescriptor.charAt(currentOffset) != ')') {
340 while (methodDescriptor.charAt(currentOffset) == '[') {
341 currentOffset++;
342 }
343 if (methodDescriptor.charAt(currentOffset++) == 'L') {
344 while (methodDescriptor.charAt(currentOffset++) != ';') {
345 // Skip the argument descriptor content.
346346 }
347 return args;
348 }
349
350 /**
351 * Returns the Java types corresponding to the argument types of the given
352 * method.
353 *
354 * @param method
355 * a method.
356 * @return the Java types corresponding to the argument types of the given
357 * method.
358 */
359 public static Type[] getArgumentTypes(final Method method) {
360 Class<?>[] classes = method.getParameterTypes();
361 Type[] types = new Type[classes.length];
362 for (int i = classes.length - 1; i >= 0; --i) {
363 types[i] = getType(classes[i]);
347 }
348 }
349 return getType(methodDescriptor, currentOffset + 1, methodDescriptor.length());
350 }
351
352 /**
353 * Returns the {@link Type} corresponding to the return type of the given method.
354 *
355 * @param method a method.
356 * @return the {@link Type} corresponding to the return type of the given method.
357 */
358 public static Type getReturnType(final Method method) {
359 return getType(method.getReturnType());
360 }
361
362 /**
363 * Computes the size of the arguments and of the return value of a method.
364 *
365 * @param methodDescriptor a method descriptor.
366 * @return the size of the arguments of the method (plus one for the implicit this argument),
367 * argumentsSize, and the size of its return value, returnSize, packed into a single int i =
368 * <tt>(argumentsSize &lt;&lt; 2) | returnSize</tt> (argumentsSize is therefore equal to <tt>i
369 * &gt;&gt; 2</tt>, and returnSize to <tt>i &amp; 0x03</tt>).
370 */
371 public static int getArgumentsAndReturnSizes(final String methodDescriptor) {
372 int argumentsSize = 1;
373 // Skip the first character, which is always a '('.
374 int currentOffset = 1;
375 int currentChar = methodDescriptor.charAt(currentOffset);
376 // Parse the argument types and compute their size, one at a each loop iteration.
377 while (currentChar != ')') {
378 if (currentChar == 'J' || currentChar == 'D') {
379 currentOffset++;
380 argumentsSize += 2;
381 } else {
382 while (methodDescriptor.charAt(currentOffset) == '[') {
383 currentOffset++;
364384 }
365 return types;
366 }
367
368 /**
369 * Returns the Java type corresponding to the return type of the given
370 * method descriptor.
371 *
372 * @param methodDescriptor
373 * a method descriptor.
374 * @return the Java type corresponding to the return type of the given
375 * method descriptor.
376 */
377 public static Type getReturnType(final String methodDescriptor) {
378 char[] buf = methodDescriptor.toCharArray();
379 int off = 1;
380 while (true) {
381 char car = buf[off++];
382 if (car == ')') {
383 return getType(buf, off);
384 } else if (car == 'L') {
385 while (buf[off++] != ';') {
386 }
387 }
385 if (methodDescriptor.charAt(currentOffset++) == 'L') {
386 while (methodDescriptor.charAt(currentOffset++) != ';') {
387 // Skip the argument descriptor content.
388 }
388389 }
389 }
390
391 /**
392 * Returns the Java type corresponding to the return type of the given
393 * method.
394 *
395 * @param method
396 * a method.
397 * @return the Java type corresponding to the return type of the given
398 * method.
399 */
400 public static Type getReturnType(final Method method) {
401 return getType(method.getReturnType());
402 }
403
404 /**
405 * Computes the size of the arguments and of the return value of a method.
406 *
407 * @param desc
408 * the descriptor of a method.
409 * @return the size of the arguments of the method (plus one for the
410 * implicit this argument), argSize, and the size of its return
411 * value, retSize, packed into a single int i =
412 * <tt>(argSize &lt;&lt; 2) | retSize</tt> (argSize is therefore equal to
413 * <tt>i &gt;&gt; 2</tt>, and retSize to <tt>i &amp; 0x03</tt>).
414 */
415 public static int getArgumentsAndReturnSizes(final String desc) {
416 int n = 1;
417 int c = 1;
418 while (true) {
419 char car = desc.charAt(c++);
420 if (car == ')') {
421 car = desc.charAt(c);
422 return n << 2
423 | (car == 'V' ? 0 : (car == 'D' || car == 'J' ? 2 : 1));
424 } else if (car == 'L') {
425 while (desc.charAt(c++) != ';') {
426 }
427 n += 1;
428 } else if (car == '[') {
429 while ((car = desc.charAt(c)) == '[') {
430 ++c;
431 }
432 if (car == 'D' || car == 'J') {
433 n -= 1;
434 }
435 } else if (car == 'D' || car == 'J') {
436 n += 2;
437 } else {
438 n += 1;
439 }
390 argumentsSize += 1;
391 }
392 currentChar = methodDescriptor.charAt(currentOffset);
393 }
394 currentChar = methodDescriptor.charAt(currentOffset + 1);
395 if (currentChar == 'V') {
396 return argumentsSize << 2;
397 } else {
398 int returnSize = (currentChar == 'J' || currentChar == 'D') ? 2 : 1;
399 return argumentsSize << 2 | returnSize;
400 }
401 }
402
403 /**
404 * Returns the {@link Type} corresponding to the given field or method descriptor.
405 *
406 * @param descriptorBuffer a buffer containing the field or method descriptor.
407 * @param descriptorBegin the beginning index, inclusive, of the field or method descriptor in
408 * descriptorBuffer.
409 * @param descriptorEnd the end index, exclusive, of the field or method descriptor in
410 * descriptorBuffer.
411 * @return the {@link Type} corresponding to the given type descriptor.
412 */
413 private static Type getType(
414 final String descriptorBuffer, final int descriptorBegin, final int descriptorEnd) {
415 switch (descriptorBuffer.charAt(descriptorBegin)) {
416 case 'V':
417 return VOID_TYPE;
418 case 'Z':
419 return BOOLEAN_TYPE;
420 case 'C':
421 return CHAR_TYPE;
422 case 'B':
423 return BYTE_TYPE;
424 case 'S':
425 return SHORT_TYPE;
426 case 'I':
427 return INT_TYPE;
428 case 'F':
429 return FLOAT_TYPE;
430 case 'J':
431 return LONG_TYPE;
432 case 'D':
433 return DOUBLE_TYPE;
434 case '[':
435 return new Type(ARRAY, descriptorBuffer, descriptorBegin, descriptorEnd);
436 case 'L':
437 return new Type(OBJECT, descriptorBuffer, descriptorBegin + 1, descriptorEnd - 1);
438 case '(':
439 return new Type(METHOD, descriptorBuffer, descriptorBegin, descriptorEnd);
440 default:
441 throw new IllegalArgumentException();
442 }
443 }
444
445 // -----------------------------------------------------------------------------------------------
446 // Accessors
447 // -----------------------------------------------------------------------------------------------
448
449 /**
450 * Returns the sort of this type.
451 *
452 * @return {@link #VOID}, {@link #BOOLEAN}, {@link #CHAR}, {@link #BYTE}, {@link #SHORT}, {@link
453 * #INT}, {@link #FLOAT}, {@link #LONG}, {@link #DOUBLE}, {@link #ARRAY}, {@link #OBJECT} or
454 * {@link #METHOD}.
455 */
456 public int getSort() {
457 return sort == INTERNAL ? OBJECT : sort;
458 }
459
460 /**
461 * Returns the number of dimensions of this array type. This method should only be used for an
462 * array type.
463 *
464 * @return the number of dimensions of this array type.
465 */
466 public int getDimensions() {
467 int numDimensions = 1;
468 while (valueBuffer.charAt(valueBegin + numDimensions) == '[') {
469 numDimensions++;
470 }
471 return numDimensions;
472 }
473
474 /**
475 * Returns the type of the elements of this array type. This method should only be used for an
476 * array type.
477 *
478 * @return Returns the type of the elements of this array type.
479 */
480 public Type getElementType() {
481 final int numDimensions = getDimensions();
482 return getType(valueBuffer, valueBegin + numDimensions, valueEnd);
483 }
484
485 /**
486 * Returns the binary name of the class corresponding to this type. This method must not be used
487 * on method types.
488 *
489 * @return the binary name of the class corresponding to this type.
490 */
491 public String getClassName() {
492 switch (sort) {
493 case VOID:
494 return "void";
495 case BOOLEAN:
496 return "boolean";
497 case CHAR:
498 return "char";
499 case BYTE:
500 return "byte";
501 case SHORT:
502 return "short";
503 case INT:
504 return "int";
505 case FLOAT:
506 return "float";
507 case LONG:
508 return "long";
509 case DOUBLE:
510 return "double";
511 case ARRAY:
512 StringBuilder stringBuilder = new StringBuilder(getElementType().getClassName());
513 for (int i = getDimensions(); i > 0; --i) {
514 stringBuilder.append("[]");
440515 }
441 }
442
443 /**
444 * Returns the Java type corresponding to the given type descriptor. For
445 * method descriptors, buf is supposed to contain nothing more than the
446 * descriptor itself.
447 *
448 * @param buf
449 * a buffer containing a type descriptor.
450 * @param off
451 * the offset of this descriptor in the previous buffer.
452 * @return the Java type corresponding to the given type descriptor.
453 */
454 private static Type getType(final char[] buf, final int off) {
455 int len;
456 switch (buf[off]) {
457 case 'V':
458 return VOID_TYPE;
459 case 'Z':
460 return BOOLEAN_TYPE;
461 case 'C':
462 return CHAR_TYPE;
463 case 'B':
464 return BYTE_TYPE;
465 case 'S':
466 return SHORT_TYPE;
467 case 'I':
468 return INT_TYPE;
469 case 'F':
470 return FLOAT_TYPE;
471 case 'J':
472 return LONG_TYPE;
473 case 'D':
474 return DOUBLE_TYPE;
475 case '[':
476 len = 1;
477 while (buf[off + len] == '[') {
478 ++len;
479 }
480 if (buf[off + len] == 'L') {
481 ++len;
482 while (buf[off + len] != ';') {
483 ++len;
484 }
485 }
486 return new Type(ARRAY, buf, off, len + 1);
487 case 'L':
488 len = 1;
489 while (buf[off + len] != ';') {
490 ++len;
491 }
492 return new Type(OBJECT, buf, off + 1, len - 1);
493 // case '(':
516 return stringBuilder.toString();
517 case OBJECT:
518 case INTERNAL:
519 return valueBuffer.substring(valueBegin, valueEnd).replace('/', '.');
520 default:
521 throw new AssertionError();
522 }
523 }
524
525 /**
526 * Returns the internal name of the class corresponding to this object or array type. The internal
527 * name of a class is its fully qualified name (as returned by Class.getName(), where '.' are
528 * replaced by '/'). This method should only be used for an object or array type.
529 *
530 * @return the internal name of the class corresponding to this object type.
531 */
532 public String getInternalName() {
533 return valueBuffer.substring(valueBegin, valueEnd);
534 }
535
536 /**
537 * Returns the argument types of methods of this type. This method should only be used for method
538 * types.
539 *
540 * @return the argument types of methods of this type.
541 */
542 public Type[] getArgumentTypes() {
543 return getArgumentTypes(getDescriptor());
544 }
545
546 /**
547 * Returns the return type of methods of this type. This method should only be used for method
548 * types.
549 *
550 * @return the return type of methods of this type.
551 */
552 public Type getReturnType() {
553 return getReturnType(getDescriptor());
554 }
555
556 /**
557 * Returns the size of the arguments and of the return value of methods of this type. This method
558 * should only be used for method types.
559 *
560 * @return the size of the arguments of the method (plus one for the implicit this argument),
561 * argumentsSize, and the size of its return value, returnSize, packed into a single int i =
562 * <tt>(argumentsSize &lt;&lt; 2) | returnSize</tt> (argumentsSize is therefore equal to <tt>i
563 * &gt;&gt; 2</tt>, and returnSize to <tt>i &amp; 0x03</tt>).
564 */
565 public int getArgumentsAndReturnSizes() {
566 return getArgumentsAndReturnSizes(getDescriptor());
567 }
568
569 // -----------------------------------------------------------------------------------------------
570 // Conversion to type descriptors
571 // -----------------------------------------------------------------------------------------------
572
573 /**
574 * Returns the descriptor corresponding to this type.
575 *
576 * @return the descriptor corresponding to this type.
577 */
578 public String getDescriptor() {
579 if (sort == OBJECT) {
580 return valueBuffer.substring(valueBegin - 1, valueEnd + 1);
581 } else if (sort == INTERNAL) {
582 StringBuilder stringBuilder = new StringBuilder();
583 stringBuilder.append('L');
584 stringBuilder.append(valueBuffer, valueBegin, valueEnd);
585 stringBuilder.append(';');
586 return stringBuilder.toString();
587 } else {
588 return valueBuffer.substring(valueBegin, valueEnd);
589 }
590 }
591
592 /**
593 * Returns the descriptor corresponding to the given argument and return types.
594 *
595 * @param returnType the return type of the method.
596 * @param argumentTypes the argument types of the method.
597 * @return the descriptor corresponding to the given argument and return types.
598 */
599 public static String getMethodDescriptor(final Type returnType, final Type... argumentTypes) {
600 StringBuilder stringBuilder = new StringBuilder();
601 stringBuilder.append('(');
602 for (int i = 0; i < argumentTypes.length; ++i) {
603 argumentTypes[i].appendDescriptor(stringBuilder);
604 }
605 stringBuilder.append(')');
606 returnType.appendDescriptor(stringBuilder);
607 return stringBuilder.toString();
608 }
609
610 /**
611 * Appends the descriptor corresponding to this type to the given string buffer.
612 *
613 * @param stringBuilder the string builder to which the descriptor must be appended.
614 */
615 private void appendDescriptor(final StringBuilder stringBuilder) {
616 if (sort == OBJECT) {
617 stringBuilder.append(valueBuffer, valueBegin - 1, valueEnd + 1);
618 } else if (sort == INTERNAL) {
619 stringBuilder.append('L');
620 stringBuilder.append(valueBuffer, valueBegin, valueEnd);
621 stringBuilder.append(';');
622 } else {
623 stringBuilder.append(valueBuffer, valueBegin, valueEnd);
624 }
625 }
626
627 // -----------------------------------------------------------------------------------------------
628 // Direct conversion from classes to type descriptors,
629 // without intermediate Type objects
630 // -----------------------------------------------------------------------------------------------
631
632 /**
633 * Returns the internal name of the given class. The internal name of a class is its fully
634 * qualified name, as returned by Class.getName(), where '.' are replaced by '/'.
635 *
636 * @param clazz an object or array class.
637 * @return the internal name of the given class.
638 */
639 public static String getInternalName(final Class<?> clazz) {
640 return clazz.getName().replace('.', '/');
641 }
642
643 /**
644 * Returns the descriptor corresponding to the given class.
645 *
646 * @param clazz an object class, a primitive class or an array class.
647 * @return the descriptor corresponding to the given class.
648 */
649 public static String getDescriptor(final Class<?> clazz) {
650 StringBuilder stringBuilder = new StringBuilder();
651 appendDescriptor(stringBuilder, clazz);
652 return stringBuilder.toString();
653 }
654
655 /**
656 * Returns the descriptor corresponding to the given constructor.
657 *
658 * @param constructor a {@link Constructor} object.
659 * @return the descriptor of the given constructor.
660 */
661 public static String getConstructorDescriptor(final Constructor<?> constructor) {
662 StringBuilder stringBuilder = new StringBuilder();
663 stringBuilder.append('(');
664 Class<?>[] parameters = constructor.getParameterTypes();
665 for (int i = 0; i < parameters.length; ++i) {
666 appendDescriptor(stringBuilder, parameters[i]);
667 }
668 return stringBuilder.append(")V").toString();
669 }
670
671 /**
672 * Returns the descriptor corresponding to the given method.
673 *
674 * @param method a {@link Method} object.
675 * @return the descriptor of the given method.
676 */
677 public static String getMethodDescriptor(final Method method) {
678 StringBuilder stringBuilder = new StringBuilder();
679 stringBuilder.append('(');
680 Class<?>[] parameters = method.getParameterTypes();
681 for (int i = 0; i < parameters.length; ++i) {
682 appendDescriptor(stringBuilder, parameters[i]);
683 }
684 stringBuilder.append(')');
685 appendDescriptor(stringBuilder, method.getReturnType());
686 return stringBuilder.toString();
687 }
688
689 /**
690 * Appends the descriptor of the given class to the given string builder.
691 *
692 * @param stringBuilder the string builder to which the descriptor must be appended.
693 * @param clazz the class whose descriptor must be computed.
694 */
695 private static void appendDescriptor(final StringBuilder stringBuilder, final Class<?> clazz) {
696 Class<?> currentClass = clazz;
697 while (currentClass.isArray()) {
698 stringBuilder.append('[');
699 currentClass = currentClass.getComponentType();
700 }
701 if (currentClass.isPrimitive()) {
702 char descriptor;
703 if (currentClass == Integer.TYPE) {
704 descriptor = 'I';
705 } else if (currentClass == Void.TYPE) {
706 descriptor = 'V';
707 } else if (currentClass == Boolean.TYPE) {
708 descriptor = 'Z';
709 } else if (currentClass == Byte.TYPE) {
710 descriptor = 'B';
711 } else if (currentClass == Character.TYPE) {
712 descriptor = 'C';
713 } else if (currentClass == Short.TYPE) {
714 descriptor = 'S';
715 } else if (currentClass == Double.TYPE) {
716 descriptor = 'D';
717 } else if (currentClass == Float.TYPE) {
718 descriptor = 'F';
719 } else if (currentClass == Long.TYPE) {
720 descriptor = 'J';
721 } else {
722 throw new AssertionError();
723 }
724 stringBuilder.append(descriptor);
725 } else {
726 stringBuilder.append('L');
727 String name = currentClass.getName();
728 int nameLength = name.length();
729 for (int i = 0; i < nameLength; ++i) {
730 char car = name.charAt(i);
731 stringBuilder.append(car == '.' ? '/' : car);
732 }
733 stringBuilder.append(';');
734 }
735 }
736
737 // -----------------------------------------------------------------------------------------------
738 // Corresponding size and opcodes
739 // -----------------------------------------------------------------------------------------------
740
741 /**
742 * Returns the size of values of this type. This method must not be used for method types.
743 *
744 * @return the size of values of this type, i.e., 2 for <tt>long</tt> and <tt>double</tt>, 0 for
745 * <tt>void</tt> and 1 otherwise.
746 */
747 public int getSize() {
748 switch (sort) {
749 case VOID:
750 return 0;
751 case BOOLEAN:
752 case CHAR:
753 case BYTE:
754 case SHORT:
755 case INT:
756 case FLOAT:
757 case ARRAY:
758 case OBJECT:
759 case INTERNAL:
760 return 1;
761 case LONG:
762 case DOUBLE:
763 return 2;
764 default:
765 throw new AssertionError();
766 }
767 }
768
769 /**
770 * Returns a JVM instruction opcode adapted to this {@link Type}. This method must not be used for
771 * method types.
772 *
773 * @param opcode a JVM instruction opcode. This opcode must be one of ILOAD, ISTORE, IALOAD,
774 * IASTORE, IADD, ISUB, IMUL, IDIV, IREM, INEG, ISHL, ISHR, IUSHR, IAND, IOR, IXOR and
775 * IRETURN.
776 * @return an opcode that is similar to the given opcode, but adapted to this {@link Type}. For
777 * example, if this type is <tt>float</tt> and <tt>opcode</tt> is IRETURN, this method returns
778 * FRETURN.
779 */
780 public int getOpcode(final int opcode) {
781 if (opcode == Opcodes.IALOAD || opcode == Opcodes.IASTORE) {
782 switch (sort) {
783 case BOOLEAN:
784 case BYTE:
785 return opcode + (Opcodes.BALOAD - Opcodes.IALOAD);
786 case CHAR:
787 return opcode + (Opcodes.CALOAD - Opcodes.IALOAD);
788 case SHORT:
789 return opcode + (Opcodes.SALOAD - Opcodes.IALOAD);
790 case INT:
791 return opcode;
792 case FLOAT:
793 return opcode + (Opcodes.FALOAD - Opcodes.IALOAD);
794 case LONG:
795 return opcode + (Opcodes.LALOAD - Opcodes.IALOAD);
796 case DOUBLE:
797 return opcode + (Opcodes.DALOAD - Opcodes.IALOAD);
798 case ARRAY:
799 case OBJECT:
800 case INTERNAL:
801 return opcode + (Opcodes.AALOAD - Opcodes.IALOAD);
802 case METHOD:
803 case VOID:
804 throw new UnsupportedOperationException();
494805 default:
495 return new Type(METHOD, buf, off, buf.length - off);
496 }
497 }
498
499 // ------------------------------------------------------------------------
500 // Accessors
501 // ------------------------------------------------------------------------
502
503 /**
504 * Returns the sort of this Java type.
505 *
506 * @return {@link #VOID VOID}, {@link #BOOLEAN BOOLEAN}, {@link #CHAR CHAR},
507 * {@link #BYTE BYTE}, {@link #SHORT SHORT}, {@link #INT INT},
508 * {@link #FLOAT FLOAT}, {@link #LONG LONG}, {@link #DOUBLE DOUBLE},
509 * {@link #ARRAY ARRAY}, {@link #OBJECT OBJECT} or {@link #METHOD
510 * METHOD}.
511 */
512 public int getSort() {
513 return sort;
514 }
515
516 /**
517 * Returns the number of dimensions of this array type. This method should
518 * only be used for an array type.
519 *
520 * @return the number of dimensions of this array type.
521 */
522 public int getDimensions() {
523 int i = 1;
524 while (buf[off + i] == '[') {
525 ++i;
526 }
527 return i;
528 }
529
530 /**
531 * Returns the type of the elements of this array type. This method should
532 * only be used for an array type.
533 *
534 * @return Returns the type of the elements of this array type.
535 */
536 public Type getElementType() {
537 return getType(buf, off + getDimensions());
538 }
539
540 /**
541 * Returns the binary name of the class corresponding to this type. This
542 * method must not be used on method types.
543 *
544 * @return the binary name of the class corresponding to this type.
545 */
546 public String getClassName() {
547 switch (sort) {
806 throw new AssertionError();
807 }
808 } else {
809 switch (sort) {
548810 case VOID:
549 return "void";
811 if (opcode != Opcodes.IRETURN) {
812 throw new UnsupportedOperationException();
813 }
814 return Opcodes.RETURN;
550815 case BOOLEAN:
551 return "boolean";
816 case BYTE:
552817 case CHAR:
553 return "char";
554 case BYTE:
555 return "byte";
556818 case SHORT:
557 return "short";
558819 case INT:
559 return "int";
820 return opcode;
560821 case FLOAT:
561 return "float";
822 return opcode + (Opcodes.FRETURN - Opcodes.IRETURN);
562823 case LONG:
563 return "long";
824 return opcode + (Opcodes.LRETURN - Opcodes.IRETURN);
564825 case DOUBLE:
565 return "double";
826 return opcode + (Opcodes.DRETURN - Opcodes.IRETURN);
566827 case ARRAY:
567 StringBuilder sb = new StringBuilder(getElementType().getClassName());
568 for (int i = getDimensions(); i > 0; --i) {
569 sb.append("[]");
570 }
571 return sb.toString();
572828 case OBJECT:
573 return new String(buf, off, len).replace('/', '.');
829 case INTERNAL:
830 if (opcode != Opcodes.ILOAD && opcode != Opcodes.ISTORE && opcode != Opcodes.IRETURN) {
831 throw new UnsupportedOperationException();
832 }
833 return opcode + (Opcodes.ARETURN - Opcodes.IRETURN);
834 case METHOD:
835 throw new UnsupportedOperationException();
574836 default:
575 return null;
576 }
577 }
578
579 /**
580 * Returns the internal name of the class corresponding to this object or
581 * array type. The internal name of a class is its fully qualified name (as
582 * returned by Class.getName(), where '.' are replaced by '/'. This method
583 * should only be used for an object or array type.
584 *
585 * @return the internal name of the class corresponding to this object type.
586 */
587 public String getInternalName() {
588 return new String(buf, off, len);
589 }
590
591 /**
592 * Returns the argument types of methods of this type. This method should
593 * only be used for method types.
594 *
595 * @return the argument types of methods of this type.
596 */
597 public Type[] getArgumentTypes() {
598 return getArgumentTypes(getDescriptor());
599 }
600
601 /**
602 * Returns the return type of methods of this type. This method should only
603 * be used for method types.
604 *
605 * @return the return type of methods of this type.
606 */
607 public Type getReturnType() {
608 return getReturnType(getDescriptor());
609 }
610
611 /**
612 * Returns the size of the arguments and of the return value of methods of
613 * this type. This method should only be used for method types.
614 *
615 * @return the size of the arguments (plus one for the implicit this
616 * argument), argSize, and the size of the return value, retSize,
617 * packed into a single
618 * int i = <tt>(argSize &lt;&lt; 2) | retSize</tt>
619 * (argSize is therefore equal to <tt>i &gt;&gt; 2</tt>,
620 * and retSize to <tt>i &amp; 0x03</tt>).
621 */
622 public int getArgumentsAndReturnSizes() {
623 return getArgumentsAndReturnSizes(getDescriptor());
624 }
625
626 // ------------------------------------------------------------------------
627 // Conversion to type descriptors
628 // ------------------------------------------------------------------------
629
630 /**
631 * Returns the descriptor corresponding to this Java type.
632 *
633 * @return the descriptor corresponding to this Java type.
634 */
635 public String getDescriptor() {
636 StringBuilder buf = new StringBuilder();
637 getDescriptor(buf);
638 return buf.toString();
639 }
640
641 /**
642 * Returns the descriptor corresponding to the given argument and return
643 * types.
644 *
645 * @param returnType
646 * the return type of the method.
647 * @param argumentTypes
648 * the argument types of the method.
649 * @return the descriptor corresponding to the given argument and return
650 * types.
651 */
652 public static String getMethodDescriptor(final Type returnType,
653 final Type... argumentTypes) {
654 StringBuilder buf = new StringBuilder();
655 buf.append('(');
656 for (int i = 0; i < argumentTypes.length; ++i) {
657 argumentTypes[i].getDescriptor(buf);
658 }
659 buf.append(')');
660 returnType.getDescriptor(buf);
661 return buf.toString();
662 }
663
664 /**
665 * Appends the descriptor corresponding to this Java type to the given
666 * string buffer.
667 *
668 * @param buf
669 * the string buffer to which the descriptor must be appended.
670 */
671 private void getDescriptor(final StringBuilder buf) {
672 if (this.buf == null) {
673 // descriptor is in byte 3 of 'off' for primitive types (buf ==
674 // null)
675 buf.append((char) ((off & 0xFF000000) >>> 24));
676 } else if (sort == OBJECT) {
677 buf.append('L');
678 buf.append(this.buf, off, len);
679 buf.append(';');
680 } else { // sort == ARRAY || sort == METHOD
681 buf.append(this.buf, off, len);
682 }
683 }
684
685 // ------------------------------------------------------------------------
686 // Direct conversion from classes to type descriptors,
687 // without intermediate Type objects
688 // ------------------------------------------------------------------------
689
690 /**
691 * Returns the internal name of the given class. The internal name of a
692 * class is its fully qualified name, as returned by Class.getName(), where
693 * '.' are replaced by '/'.
694 *
695 * @param c
696 * an object or array class.
697 * @return the internal name of the given class.
698 */
699 public static String getInternalName(final Class<?> c) {
700 return c.getName().replace('.', '/');
701 }
702
703 /**
704 * Returns the descriptor corresponding to the given Java type.
705 *
706 * @param c
707 * an object class, a primitive class or an array class.
708 * @return the descriptor corresponding to the given class.
709 */
710 public static String getDescriptor(final Class<?> c) {
711 StringBuilder buf = new StringBuilder();
712 getDescriptor(buf, c);
713 return buf.toString();
714 }
715
716 /**
717 * Returns the descriptor corresponding to the given constructor.
718 *
719 * @param c
720 * a {@link Constructor Constructor} object.
721 * @return the descriptor of the given constructor.
722 */
723 public static String getConstructorDescriptor(final Constructor<?> c) {
724 Class<?>[] parameters = c.getParameterTypes();
725 StringBuilder buf = new StringBuilder();
726 buf.append('(');
727 for (int i = 0; i < parameters.length; ++i) {
728 getDescriptor(buf, parameters[i]);
729 }
730 return buf.append(")V").toString();
731 }
732
733 /**
734 * Returns the descriptor corresponding to the given method.
735 *
736 * @param m
737 * a {@link Method Method} object.
738 * @return the descriptor of the given method.
739 */
740 public static String getMethodDescriptor(final Method m) {
741 Class<?>[] parameters = m.getParameterTypes();
742 StringBuilder buf = new StringBuilder();
743 buf.append('(');
744 for (int i = 0; i < parameters.length; ++i) {
745 getDescriptor(buf, parameters[i]);
746 }
747 buf.append(')');
748 getDescriptor(buf, m.getReturnType());
749 return buf.toString();
750 }
751
752 /**
753 * Appends the descriptor of the given class to the given string buffer.
754 *
755 * @param buf
756 * the string buffer to which the descriptor must be appended.
757 * @param c
758 * the class whose descriptor must be computed.
759 */
760 private static void getDescriptor(final StringBuilder buf, final Class<?> c) {
761 Class<?> d = c;
762 while (true) {
763 if (d.isPrimitive()) {
764 char car;
765 if (d == Integer.TYPE) {
766 car = 'I';
767 } else if (d == Void.TYPE) {
768 car = 'V';
769 } else if (d == Boolean.TYPE) {
770 car = 'Z';
771 } else if (d == Byte.TYPE) {
772 car = 'B';
773 } else if (d == Character.TYPE) {
774 car = 'C';
775 } else if (d == Short.TYPE) {
776 car = 'S';
777 } else if (d == Double.TYPE) {
778 car = 'D';
779 } else if (d == Float.TYPE) {
780 car = 'F';
781 } else /* if (d == Long.TYPE) */{
782 car = 'J';
783 }
784 buf.append(car);
785 return;
786 } else if (d.isArray()) {
787 buf.append('[');
788 d = d.getComponentType();
789 } else {
790 buf.append('L');
791 String name = d.getName();
792 int len = name.length();
793 for (int i = 0; i < len; ++i) {
794 char car = name.charAt(i);
795 buf.append(car == '.' ? '/' : car);
796 }
797 buf.append(';');
798 return;
799 }
800 }
801 }
802
803 // ------------------------------------------------------------------------
804 // Corresponding size and opcodes
805 // ------------------------------------------------------------------------
806
807 /**
808 * Returns the size of values of this type. This method must not be used for
809 * method types.
810 *
811 * @return the size of values of this type, i.e., 2 for <tt>long</tt> and
812 * <tt>double</tt>, 0 for <tt>void</tt> and 1 otherwise.
813 */
814 public int getSize() {
815 // the size is in byte 0 of 'off' for primitive types (buf == null)
816 return buf == null ? (off & 0xFF) : 1;
817 }
818
819 /**
820 * Returns a JVM instruction opcode adapted to this Java type. This method
821 * must not be used for method types.
822 *
823 * @param opcode
824 * a JVM instruction opcode. This opcode must be one of ILOAD,
825 * ISTORE, IALOAD, IASTORE, IADD, ISUB, IMUL, IDIV, IREM, INEG,
826 * ISHL, ISHR, IUSHR, IAND, IOR, IXOR and IRETURN.
827 * @return an opcode that is similar to the given opcode, but adapted to
828 * this Java type. For example, if this type is <tt>float</tt> and
829 * <tt>opcode</tt> is IRETURN, this method returns FRETURN.
830 */
831 public int getOpcode(final int opcode) {
832 if (opcode == Opcodes.IALOAD || opcode == Opcodes.IASTORE) {
833 // the offset for IALOAD or IASTORE is in byte 1 of 'off' for
834 // primitive types (buf == null)
835 return opcode + (buf == null ? (off & 0xFF00) >> 8 : 4);
836 } else {
837 // the offset for other instructions is in byte 2 of 'off' for
838 // primitive types (buf == null)
839 return opcode + (buf == null ? (off & 0xFF0000) >> 16 : 4);
840 }
841 }
842
843 // ------------------------------------------------------------------------
844 // Equals, hashCode and toString
845 // ------------------------------------------------------------------------
846
847 /**
848 * Tests if the given object is equal to this type.
849 *
850 * @param o
851 * the object to be compared to this type.
852 * @return <tt>true</tt> if the given object is equal to this type.
853 */
854 @Override
855 public boolean equals(final Object o) {
856 if (this == o) {
857 return true;
858 }
859 if (!(o instanceof Type)) {
860 return false;
861 }
862 Type t = (Type) o;
863 if (sort != t.sort) {
864 return false;
865 }
866 if (sort >= ARRAY) {
867 if (len != t.len) {
868 return false;
869 }
870 for (int i = off, j = t.off, end = i + len; i < end; i++, j++) {
871 if (buf[i] != t.buf[j]) {
872 return false;
873 }
874 }
875 }
876 return true;
877 }
878
879 /**
880 * Returns a hash code value for this type.
881 *
882 * @return a hash code value for this type.
883 */
884 @Override
885 public int hashCode() {
886 int hc = 13 * sort;
887 if (sort >= ARRAY) {
888 for (int i = off, end = i + len; i < end; i++) {
889 hc = 17 * (hc + buf[i]);
890 }
891 }
892 return hc;
893 }
894
895 /**
896 * Returns a string representation of this type.
897 *
898 * @return the descriptor of this type.
899 */
900 @Override
901 public String toString() {
902 return getDescriptor();
903 }
837 throw new AssertionError();
838 }
839 }
840 }
841
842 // -----------------------------------------------------------------------------------------------
843 // Equals, hashCode and toString
844 // -----------------------------------------------------------------------------------------------
845
846 /**
847 * Tests if the given object is equal to this type.
848 *
849 * @param object the object to be compared to this type.
850 * @return <tt>true</tt> if the given object is equal to this type.
851 */
852 @Override
853 public boolean equals(final Object object) {
854 if (this == object) {
855 return true;
856 }
857 if (!(object instanceof Type)) {
858 return false;
859 }
860 Type other = (Type) object;
861 if ((sort == INTERNAL ? OBJECT : sort) != (other.sort == INTERNAL ? OBJECT : other.sort)) {
862 return false;
863 }
864 int begin = valueBegin;
865 int end = valueEnd;
866 int otherBegin = other.valueBegin;
867 int otherEnd = other.valueEnd;
868 // Compare the values.
869 if (end - begin != otherEnd - otherBegin) {
870 return false;
871 }
872 for (int i = begin, j = otherBegin; i < end; i++, j++) {
873 if (valueBuffer.charAt(i) != other.valueBuffer.charAt(j)) {
874 return false;
875 }
876 }
877 return true;
878 }
879
880 /**
881 * Returns a hash code value for this type.
882 *
883 * @return a hash code value for this type.
884 */
885 @Override
886 public int hashCode() {
887 int hashCode = 13 * (sort == INTERNAL ? OBJECT : sort);
888 if (sort >= ARRAY) {
889 for (int i = valueBegin, end = valueEnd; i < end; i++) {
890 hashCode = 17 * (hashCode + valueBuffer.charAt(i));
891 }
892 }
893 return hashCode;
894 }
895
896 /**
897 * Returns a string representation of this type.
898 *
899 * @return the descriptor of this type.
900 */
901 @Override
902 public String toString() {
903 return getDescriptor();
904 }
904905 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2013 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 package org.eclipse.persistence.internal.libraries.asm;
31
32 /**
33 * The path to a type argument, wildcard bound, array element type, or static
34 * inner type within an enclosing type.
35 *
36 * @author Eric Bruneton
37 */
38 public class TypePath {
39
40 /**
41 * A type path step that steps into the element type of an array type. See
42 * {@link #getStep getStep}.
43 */
44 public final static int ARRAY_ELEMENT = 0;
45
46 /**
47 * A type path step that steps into the nested type of a class type. See
48 * {@link #getStep getStep}.
49 */
50 public final static int INNER_TYPE = 1;
51
52 /**
53 * A type path step that steps into the bound of a wildcard type. See
54 * {@link #getStep getStep}.
55 */
56 public final static int WILDCARD_BOUND = 2;
57
58 /**
59 * A type path step that steps into a type argument of a generic type. See
60 * {@link #getStep getStep}.
61 */
62 public final static int TYPE_ARGUMENT = 3;
63
64 /**
65 * The byte array where the path is stored, in Java class file format.
66 */
67 byte[] b;
68
69 /**
70 * The offset of the first byte of the type path in 'b'.
71 */
72 int offset;
73
74 /**
75 * Creates a new type path.
76 *
77 * @param b
78 * the byte array containing the type path in Java class file
79 * format.
80 * @param offset
81 * the offset of the first byte of the type path in 'b'.
82 */
83 TypePath(byte[] b, int offset) {
84 this.b = b;
85 this.offset = offset;
86 }
87
88 /**
89 * Returns the length of this path.
90 *
91 * @return the length of this path.
92 */
93 public int getLength() {
94 return b[offset];
95 }
96
97 /**
98 * Returns the value of the given step of this path.
99 *
100 * @param index
101 * an index between 0 and {@link #getLength()}, exclusive.
102 * @return {@link #ARRAY_ELEMENT ARRAY_ELEMENT}, {@link #INNER_TYPE
103 * INNER_TYPE}, {@link #WILDCARD_BOUND WILDCARD_BOUND}, or
104 * {@link #TYPE_ARGUMENT TYPE_ARGUMENT}.
105 */
106 public int getStep(int index) {
107 return b[offset + 2 * index + 1];
108 }
109
110 /**
111 * Returns the index of the type argument that the given step is stepping
112 * into. This method should only be used for steps whose value is
113 * {@link #TYPE_ARGUMENT TYPE_ARGUMENT}.
114 *
115 * @param index
116 * an index between 0 and {@link #getLength()}, exclusive.
117 * @return the index of the type argument that the given step is stepping
118 * into.
119 */
120 public int getStepArgument(int index) {
121 return b[offset + 2 * index + 2];
122 }
123
124 /**
125 * Converts a type path in string form, in the format used by
126 * {@link #toString()}, into a TypePath object.
127 *
128 * @param typePath
129 * a type path in string form, in the format used by
130 * {@link #toString()}. May be null or empty.
131 * @return the corresponding TypePath object, or null if the path is empty.
132 */
133 public static TypePath fromString(final String typePath) {
134 if (typePath == null || typePath.length() == 0) {
135 return null;
136 }
137 int n = typePath.length();
138 ByteVector out = new ByteVector(n);
139 out.putByte(0);
140 for (int i = 0; i < n;) {
141 char c = typePath.charAt(i++);
142 if (c == '[') {
143 out.put11(ARRAY_ELEMENT, 0);
144 } else if (c == '.') {
145 out.put11(INNER_TYPE, 0);
146 } else if (c == '*') {
147 out.put11(WILDCARD_BOUND, 0);
148 } else if (c >= '0' && c <= '9') {
149 int typeArg = c - '0';
150 while (i < n && (c = typePath.charAt(i)) >= '0' && c <= '9') {
151 typeArg = typeArg * 10 + c - '0';
152 i += 1;
153 }
154 if (i < n && typePath.charAt(i) == ';') {
155 i += 1;
156 }
157 out.put11(TYPE_ARGUMENT, typeArg);
158 }
159 }
160 out.data[0] = (byte) (out.length / 2);
161 return new TypePath(out.data, 0);
162 }
163
164 /**
165 * Returns a string representation of this type path. {@link #ARRAY_ELEMENT
166 * ARRAY_ELEMENT} steps are represented with '[', {@link #INNER_TYPE
167 * INNER_TYPE} steps with '.', {@link #WILDCARD_BOUND WILDCARD_BOUND} steps
168 * with '*' and {@link #TYPE_ARGUMENT TYPE_ARGUMENT} steps with their type
169 * argument index in decimal form followed by ';'.
170 */
171 @Override
172 public String toString() {
173 int length = getLength();
174 StringBuilder result = new StringBuilder(length * 2);
175 for (int i = 0; i < length; ++i) {
176 switch (getStep(i)) {
177 case ARRAY_ELEMENT:
178 result.append('[');
179 break;
180 case INNER_TYPE:
181 result.append('.');
182 break;
183 case WILDCARD_BOUND:
184 result.append('*');
185 break;
186 case TYPE_ARGUMENT:
187 result.append(getStepArgument(i)).append(';');
188 break;
189 default:
190 result.append('_');
191 }
192 }
193 return result.toString();
194 }
195 }
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
27
28 package org.eclipse.persistence.internal.libraries.asm;
29
30 /**
31 * The path to a type argument, wildcard bound, array element type, or static inner type within an
32 * enclosing type.
33 *
34 * @author Eric Bruneton
35 */
36 public class TypePath {
37
38 /** A type path step that steps into the element type of an array type. See {@link #getStep}. */
39 public static final int ARRAY_ELEMENT = 0;
40
41 /** A type path step that steps into the nested type of a class type. See {@link #getStep}. */
42 public static final int INNER_TYPE = 1;
43
44 /** A type path step that steps into the bound of a wildcard type. See {@link #getStep}. */
45 public static final int WILDCARD_BOUND = 2;
46
47 /** A type path step that steps into a type argument of a generic type. See {@link #getStep}. */
48 public static final int TYPE_ARGUMENT = 3;
49
50 /**
51 * The byte array where the 'type_path' structure - as defined in the Java Virtual Machine
52 * Specification (JVMS) - corresponding to this TypePath is stored. The first byte of the
53 * structure in this array is given by {@link #typePathOffset}.
54 *
55 * @see <a
56 * href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20.2">JVMS
57 * 4.7.20.2</a>
58 */
59 private final byte[] typePathContainer;
60
61 /** The offset of the first byte of the type_path JVMS structure in {@link #typePathContainer}. */
62 private final int typePathOffset;
63
64 /**
65 * Constructs a new TypePath.
66 *
67 * @param typePathContainer a byte array containing a type_path JVMS structure.
68 * @param typePathOffset the offset of the first byte of the type_path structure in
69 * typePathContainer.
70 */
71 TypePath(final byte[] typePathContainer, final int typePathOffset) {
72 this.typePathContainer = typePathContainer;
73 this.typePathOffset = typePathOffset;
74 }
75
76 /**
77 * Returns the length of this path, i.e. its number of steps.
78 *
79 * @return the length of this path.
80 */
81 public int getLength() {
82 // path_length is stored in the first byte of a type_path.
83 return typePathContainer[typePathOffset];
84 }
85
86 /**
87 * Returns the value of the given step of this path.
88 *
89 * @param index an index between 0 and {@link #getLength()}, exclusive.
90 * @return one of {@link #ARRAY_ELEMENT}, {@link #INNER_TYPE}, {@link #WILDCARD_BOUND}, or {@link
91 * #TYPE_ARGUMENT}.
92 */
93 public int getStep(final int index) {
94 // Returns the type_path_kind of the path element of the given index.
95 return typePathContainer[typePathOffset + 2 * index + 1];
96 }
97
98 /**
99 * Returns the index of the type argument that the given step is stepping into. This method should
100 * only be used for steps whose value is {@link #TYPE_ARGUMENT}.
101 *
102 * @param index an index between 0 and {@link #getLength()}, exclusive.
103 * @return the index of the type argument that the given step is stepping into.
104 */
105 public int getStepArgument(final int index) {
106 // Returns the type_argument_index of the path element of the given index.
107 return typePathContainer[typePathOffset + 2 * index + 2];
108 }
109
110 /**
111 * Converts a type path in string form, in the format used by {@link #toString()}, into a TypePath
112 * object.
113 *
114 * @param typePath a type path in string form, in the format used by {@link #toString()}. May be
115 * <tt>null</tt> or empty.
116 * @return the corresponding TypePath object, or <tt>null</tt> if the path is empty.
117 */
118 public static TypePath fromString(final String typePath) {
119 if (typePath == null || typePath.length() == 0) {
120 return null;
121 }
122 int typePathLength = typePath.length();
123 ByteVector output = new ByteVector(typePathLength);
124 output.putByte(0);
125 int typePathIndex = 0;
126 while (typePathIndex < typePathLength) {
127 char c = typePath.charAt(typePathIndex++);
128 if (c == '[') {
129 output.put11(ARRAY_ELEMENT, 0);
130 } else if (c == '.') {
131 output.put11(INNER_TYPE, 0);
132 } else if (c == '*') {
133 output.put11(WILDCARD_BOUND, 0);
134 } else if (c >= '0' && c <= '9') {
135 int typeArg = c - '0';
136 while (typePathIndex < typePathLength) {
137 c = typePath.charAt(typePathIndex++);
138 if (c >= '0' && c <= '9') {
139 typeArg = typeArg * 10 + c - '0';
140 } else if (c == ';') {
141 break;
142 } else {
143 throw new IllegalArgumentException();
144 }
145 }
146 output.put11(TYPE_ARGUMENT, typeArg);
147 } else {
148 throw new IllegalArgumentException();
149 }
150 }
151 output.data[0] = (byte) (output.length / 2);
152 return new TypePath(output.data, 0);
153 }
154
155 /**
156 * Returns a string representation of this type path. {@link #ARRAY_ELEMENT} steps are represented
157 * with '[', {@link #INNER_TYPE} steps with '.', {@link #WILDCARD_BOUND} steps with '*' and {@link
158 * #TYPE_ARGUMENT} steps with their type argument index in decimal form followed by ';'.
159 */
160 @Override
161 public String toString() {
162 int length = getLength();
163 StringBuilder result = new StringBuilder(length * 2);
164 for (int i = 0; i < length; ++i) {
165 switch (getStep(i)) {
166 case ARRAY_ELEMENT:
167 result.append('[');
168 break;
169 case INNER_TYPE:
170 result.append('.');
171 break;
172 case WILDCARD_BOUND:
173 result.append('*');
174 break;
175 case TYPE_ARGUMENT:
176 result.append(getStepArgument(i)).append(';');
177 break;
178 default:
179 throw new AssertionError();
180 }
181 }
182 return result.toString();
183 }
184
185 /**
186 * Puts the type_path JVMS structure corresponding to the given TypePath into the given
187 * ByteVector.
188 *
189 * @param typePath a TypePath instance, or <tt>null</tt> for empty paths.
190 * @param output where the type path must be put.
191 */
192 static void put(final TypePath typePath, final ByteVector output) {
193 if (typePath == null) {
194 output.putByte(0);
195 } else {
196 int length = typePath.typePathContainer[typePath.typePathOffset] * 2 + 1;
197 output.putByteArray(typePath.typePathContainer, typePath.typePathOffset, length);
198 }
199 }
200 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2013 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 package org.eclipse.persistence.internal.libraries.asm;
31
32 /**
33 * A reference to a type appearing in a class, field or method declaration, or
34 * on an instruction. Such a reference designates the part of the class where
35 * the referenced type is appearing (e.g. an 'extends', 'implements' or 'throws'
36 * clause, a 'new' instruction, a 'catch' clause, a type cast, a local variable
37 * declaration, etc).
38 *
39 * @author Eric Bruneton
40 */
41 public class TypeReference {
42
43 /**
44 * The sort of type references that target a type parameter of a generic
45 * class. See {@link #getSort getSort}.
46 */
47 public final static int CLASS_TYPE_PARAMETER = 0x00;
48
49 /**
50 * The sort of type references that target a type parameter of a generic
51 * method. See {@link #getSort getSort}.
52 */
53 public final static int METHOD_TYPE_PARAMETER = 0x01;
54
55 /**
56 * The sort of type references that target the super class of a class or one
57 * of the interfaces it implements. See {@link #getSort getSort}.
58 */
59 public final static int CLASS_EXTENDS = 0x10;
60
61 /**
62 * The sort of type references that target a bound of a type parameter of a
63 * generic class. See {@link #getSort getSort}.
64 */
65 public final static int CLASS_TYPE_PARAMETER_BOUND = 0x11;
66
67 /**
68 * The sort of type references that target a bound of a type parameter of a
69 * generic method. See {@link #getSort getSort}.
70 */
71 public final static int METHOD_TYPE_PARAMETER_BOUND = 0x12;
72
73 /**
74 * The sort of type references that target the type of a field. See
75 * {@link #getSort getSort}.
76 */
77 public final static int FIELD = 0x13;
78
79 /**
80 * The sort of type references that target the return type of a method. See
81 * {@link #getSort getSort}.
82 */
83 public final static int METHOD_RETURN = 0x14;
84
85 /**
86 * The sort of type references that target the receiver type of a method.
87 * See {@link #getSort getSort}.
88 */
89 public final static int METHOD_RECEIVER = 0x15;
90
91 /**
92 * The sort of type references that target the type of a formal parameter of
93 * a method. See {@link #getSort getSort}.
94 */
95 public final static int METHOD_FORMAL_PARAMETER = 0x16;
96
97 /**
98 * The sort of type references that target the type of an exception declared
99 * in the throws clause of a method. See {@link #getSort getSort}.
100 */
101 public final static int THROWS = 0x17;
102
103 /**
104 * The sort of type references that target the type of a local variable in a
105 * method. See {@link #getSort getSort}.
106 */
107 public final static int LOCAL_VARIABLE = 0x40;
108
109 /**
110 * The sort of type references that target the type of a resource variable
111 * in a method. See {@link #getSort getSort}.
112 */
113 public final static int RESOURCE_VARIABLE = 0x41;
114
115 /**
116 * The sort of type references that target the type of the exception of a
117 * 'catch' clause in a method. See {@link #getSort getSort}.
118 */
119 public final static int EXCEPTION_PARAMETER = 0x42;
120
121 /**
122 * The sort of type references that target the type declared in an
123 * 'instanceof' instruction. See {@link #getSort getSort}.
124 */
125 public final static int INSTANCEOF = 0x43;
126
127 /**
128 * The sort of type references that target the type of the object created by
129 * a 'new' instruction. See {@link #getSort getSort}.
130 */
131 public final static int NEW = 0x44;
132
133 /**
134 * The sort of type references that target the receiver type of a
135 * constructor reference. See {@link #getSort getSort}.
136 */
137 public final static int CONSTRUCTOR_REFERENCE = 0x45;
138
139 /**
140 * The sort of type references that target the receiver type of a method
141 * reference. See {@link #getSort getSort}.
142 */
143 public final static int METHOD_REFERENCE = 0x46;
144
145 /**
146 * The sort of type references that target the type declared in an explicit
147 * or implicit cast instruction. See {@link #getSort getSort}.
148 */
149 public final static int CAST = 0x47;
150
151 /**
152 * The sort of type references that target a type parameter of a generic
153 * constructor in a constructor call. See {@link #getSort getSort}.
154 */
155 public final static int CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT = 0x48;
156
157 /**
158 * The sort of type references that target a type parameter of a generic
159 * method in a method call. See {@link #getSort getSort}.
160 */
161 public final static int METHOD_INVOCATION_TYPE_ARGUMENT = 0x49;
162
163 /**
164 * The sort of type references that target a type parameter of a generic
165 * constructor in a constructor reference. See {@link #getSort getSort}.
166 */
167 public final static int CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT = 0x4A;
168
169 /**
170 * The sort of type references that target a type parameter of a generic
171 * method in a method reference. See {@link #getSort getSort}.
172 */
173 public final static int METHOD_REFERENCE_TYPE_ARGUMENT = 0x4B;
174
175 /**
176 * The type reference value in Java class file format.
177 */
178 private int value;
179
180 /**
181 * Creates a new TypeReference.
182 *
183 * @param typeRef
184 * the int encoded value of the type reference, as received in a
185 * visit method related to type annotations, like
186 * visitTypeAnnotation.
187 */
188 public TypeReference(int typeRef) {
189 this.value = typeRef;
190 }
191
192 /**
193 * Returns a type reference of the given sort.
194 *
195 * @param sort
196 * {@link #FIELD FIELD}, {@link #METHOD_RETURN METHOD_RETURN},
197 * {@link #METHOD_RECEIVER METHOD_RECEIVER},
198 * {@link #LOCAL_VARIABLE LOCAL_VARIABLE},
199 * {@link #RESOURCE_VARIABLE RESOURCE_VARIABLE},
200 * {@link #INSTANCEOF INSTANCEOF}, {@link #NEW NEW},
201 * {@link #CONSTRUCTOR_REFERENCE CONSTRUCTOR_REFERENCE}, or
202 * {@link #METHOD_REFERENCE METHOD_REFERENCE}.
203 * @return a type reference of the given sort.
204 */
205 public static TypeReference newTypeReference(int sort) {
206 return new TypeReference(sort << 24);
207 }
208
209 /**
210 * Returns a reference to a type parameter of a generic class or method.
211 *
212 * @param sort
213 * {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER} or
214 * {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER}.
215 * @param paramIndex
216 * the type parameter index.
217 * @return a reference to the given generic class or method type parameter.
218 */
219 public static TypeReference newTypeParameterReference(int sort,
220 int paramIndex) {
221 return new TypeReference((sort << 24) | (paramIndex << 16));
222 }
223
224 /**
225 * Returns a reference to a type parameter bound of a generic class or
226 * method.
227 *
228 * @param sort
229 * {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER} or
230 * {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER}.
231 * @param paramIndex
232 * the type parameter index.
233 * @param boundIndex
234 * the type bound index within the above type parameters.
235 * @return a reference to the given generic class or method type parameter
236 * bound.
237 */
238 public static TypeReference newTypeParameterBoundReference(int sort,
239 int paramIndex, int boundIndex) {
240 return new TypeReference((sort << 24) | (paramIndex << 16)
241 | (boundIndex << 8));
242 }
243
244 /**
245 * Returns a reference to the super class or to an interface of the
246 * 'implements' clause of a class.
247 *
248 * @param itfIndex
249 * the index of an interface in the 'implements' clause of a
250 * class, or -1 to reference the super class of the class.
251 * @return a reference to the given super type of a class.
252 */
253 public static TypeReference newSuperTypeReference(int itfIndex) {
254 itfIndex &= 0xFFFF;
255 return new TypeReference((CLASS_EXTENDS << 24) | (itfIndex << 8));
256 }
257
258 /**
259 * Returns a reference to the type of a formal parameter of a method.
260 *
261 * @param paramIndex
262 * the formal parameter index.
263 *
264 * @return a reference to the type of the given method formal parameter.
265 */
266 public static TypeReference newFormalParameterReference(int paramIndex) {
267 return new TypeReference((METHOD_FORMAL_PARAMETER << 24)
268 | (paramIndex << 16));
269 }
270
271 /**
272 * Returns a reference to the type of an exception, in a 'throws' clause of
273 * a method.
274 *
275 * @param exceptionIndex
276 * the index of an exception in a 'throws' clause of a method.
277 *
278 * @return a reference to the type of the given exception.
279 */
280 public static TypeReference newExceptionReference(int exceptionIndex) {
281 return new TypeReference((THROWS << 24) | (exceptionIndex << 8));
282 }
283
284 /**
285 * Returns a reference to the type of the exception declared in a 'catch'
286 * clause of a method.
287 *
288 * @param tryCatchBlockIndex
289 * the index of a try catch block (using the order in which they
290 * are visited with visitTryCatchBlock).
291 *
292 * @return a reference to the type of the given exception.
293 */
294 public static TypeReference newTryCatchReference(int tryCatchBlockIndex) {
295 return new TypeReference((EXCEPTION_PARAMETER << 24)
296 | (tryCatchBlockIndex << 8));
297 }
298
299 /**
300 * Returns a reference to the type of a type argument in a constructor or
301 * method call or reference.
302 *
303 * @param sort
304 * {@link #CAST CAST},
305 * {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
306 * CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT},
307 * {@link #METHOD_INVOCATION_TYPE_ARGUMENT
308 * METHOD_INVOCATION_TYPE_ARGUMENT},
309 * {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
310 * CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or
311 * {@link #METHOD_REFERENCE_TYPE_ARGUMENT
312 * METHOD_REFERENCE_TYPE_ARGUMENT}.
313 * @param argIndex
314 * the type argument index.
315 *
316 * @return a reference to the type of the given type argument.
317 */
318 public static TypeReference newTypeArgumentReference(int sort, int argIndex) {
319 return new TypeReference((sort << 24) | argIndex);
320 }
321
322 /**
323 * Returns the sort of this type reference.
324 *
325 * @return {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER},
326 * {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER},
327 * {@link #CLASS_EXTENDS CLASS_EXTENDS},
328 * {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND},
329 * {@link #METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND},
330 * {@link #FIELD FIELD}, {@link #METHOD_RETURN METHOD_RETURN},
331 * {@link #METHOD_RECEIVER METHOD_RECEIVER},
332 * {@link #METHOD_FORMAL_PARAMETER METHOD_FORMAL_PARAMETER},
333 * {@link #THROWS THROWS}, {@link #LOCAL_VARIABLE LOCAL_VARIABLE},
334 * {@link #RESOURCE_VARIABLE RESOURCE_VARIABLE},
335 * {@link #EXCEPTION_PARAMETER EXCEPTION_PARAMETER},
336 * {@link #INSTANCEOF INSTANCEOF}, {@link #NEW NEW},
337 * {@link #CONSTRUCTOR_REFERENCE CONSTRUCTOR_REFERENCE},
338 * {@link #METHOD_REFERENCE METHOD_REFERENCE}, {@link #CAST CAST},
339 * {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
340 * CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT},
341 * {@link #METHOD_INVOCATION_TYPE_ARGUMENT
342 * METHOD_INVOCATION_TYPE_ARGUMENT},
343 * {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
344 * CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or
345 * {@link #METHOD_REFERENCE_TYPE_ARGUMENT
346 * METHOD_REFERENCE_TYPE_ARGUMENT}.
347 */
348 public int getSort() {
349 return value >>> 24;
350 }
351
352 /**
353 * Returns the index of the type parameter referenced by this type
354 * reference. This method must only be used for type references whose sort
355 * is {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER},
356 * {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER},
357 * {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND} or
358 * {@link #METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND}.
359 *
360 * @return a type parameter index.
361 */
362 public int getTypeParameterIndex() {
363 return (value & 0x00FF0000) >> 16;
364 }
365
366 /**
367 * Returns the index of the type parameter bound, within the type parameter
368 * {@link #getTypeParameterIndex}, referenced by this type reference. This
369 * method must only be used for type references whose sort is
370 * {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND} or
371 * {@link #METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND}.
372 *
373 * @return a type parameter bound index.
374 */
375 public int getTypeParameterBoundIndex() {
376 return (value & 0x0000FF00) >> 8;
377 }
378
379 /**
380 * Returns the index of the "super type" of a class that is referenced by
381 * this type reference. This method must only be used for type references
382 * whose sort is {@link #CLASS_EXTENDS CLASS_EXTENDS}.
383 *
384 * @return the index of an interface in the 'implements' clause of a class,
385 * or -1 if this type reference references the type of the super
386 * class.
387 */
388 public int getSuperTypeIndex() {
389 return (short) ((value & 0x00FFFF00) >> 8);
390 }
391
392 /**
393 * Returns the index of the formal parameter whose type is referenced by
394 * this type reference. This method must only be used for type references
395 * whose sort is {@link #METHOD_FORMAL_PARAMETER METHOD_FORMAL_PARAMETER}.
396 *
397 * @return a formal parameter index.
398 */
399 public int getFormalParameterIndex() {
400 return (value & 0x00FF0000) >> 16;
401 }
402
403 /**
404 * Returns the index of the exception, in a 'throws' clause of a method,
405 * whose type is referenced by this type reference. This method must only be
406 * used for type references whose sort is {@link #THROWS THROWS}.
407 *
408 * @return the index of an exception in the 'throws' clause of a method.
409 */
410 public int getExceptionIndex() {
411 return (value & 0x00FFFF00) >> 8;
412 }
413
414 /**
415 * Returns the index of the try catch block (using the order in which they
416 * are visited with visitTryCatchBlock), whose 'catch' type is referenced by
417 * this type reference. This method must only be used for type references
418 * whose sort is {@link #EXCEPTION_PARAMETER EXCEPTION_PARAMETER} .
419 *
420 * @return the index of an exception in the 'throws' clause of a method.
421 */
422 public int getTryCatchBlockIndex() {
423 return (value & 0x00FFFF00) >> 8;
424 }
425
426 /**
427 * Returns the index of the type argument referenced by this type reference.
428 * This method must only be used for type references whose sort is
429 * {@link #CAST CAST}, {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
430 * CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT},
431 * {@link #METHOD_INVOCATION_TYPE_ARGUMENT METHOD_INVOCATION_TYPE_ARGUMENT},
432 * {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
433 * CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or
434 * {@link #METHOD_REFERENCE_TYPE_ARGUMENT METHOD_REFERENCE_TYPE_ARGUMENT}.
435 *
436 * @return a type parameter index.
437 */
438 public int getTypeArgumentIndex() {
439 return value & 0xFF;
440 }
441
442 /**
443 * Returns the int encoded value of this type reference, suitable for use in
444 * visit methods related to type annotations, like visitTypeAnnotation.
445 *
446 * @return the int encoded value of this type reference.
447 */
448 public int getValue() {
449 return value;
450 }
451 }
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
27
28 package org.eclipse.persistence.internal.libraries.asm;
29
30 /**
31 * A reference to a type appearing in a class, field or method declaration, or on an instruction.
32 * Such a reference designates the part of the class where the referenced type is appearing (e.g. an
33 * 'extends', 'implements' or 'throws' clause, a 'new' instruction, a 'catch' clause, a type cast, a
34 * local variable declaration, etc).
35 *
36 * @author Eric Bruneton
37 */
38 public class TypeReference {
39
40 /**
41 * The sort of type references that target a type parameter of a generic class. See {@link
42 * #getSort}.
43 */
44 public static final int CLASS_TYPE_PARAMETER = 0x00;
45
46 /**
47 * The sort of type references that target a type parameter of a generic method. See {@link
48 * #getSort}.
49 */
50 public static final int METHOD_TYPE_PARAMETER = 0x01;
51
52 /**
53 * The sort of type references that target the super class of a class or one of the interfaces it
54 * implements. See {@link #getSort}.
55 */
56 public static final int CLASS_EXTENDS = 0x10;
57
58 /**
59 * The sort of type references that target a bound of a type parameter of a generic class. See
60 * {@link #getSort}.
61 */
62 public static final int CLASS_TYPE_PARAMETER_BOUND = 0x11;
63
64 /**
65 * The sort of type references that target a bound of a type parameter of a generic method. See
66 * {@link #getSort}.
67 */
68 public static final int METHOD_TYPE_PARAMETER_BOUND = 0x12;
69
70 /** The sort of type references that target the type of a field. See {@link #getSort}. */
71 public static final int FIELD = 0x13;
72
73 /** The sort of type references that target the return type of a method. See {@link #getSort}. */
74 public static final int METHOD_RETURN = 0x14;
75
76 /**
77 * The sort of type references that target the receiver type of a method. See {@link #getSort}.
78 */
79 public static final int METHOD_RECEIVER = 0x15;
80
81 /**
82 * The sort of type references that target the type of a formal parameter of a method. See {@link
83 * #getSort}.
84 */
85 public static final int METHOD_FORMAL_PARAMETER = 0x16;
86
87 /**
88 * The sort of type references that target the type of an exception declared in the throws clause
89 * of a method. See {@link #getSort}.
90 */
91 public static final int THROWS = 0x17;
92
93 /**
94 * The sort of type references that target the type of a local variable in a method. See {@link
95 * #getSort}.
96 */
97 public static final int LOCAL_VARIABLE = 0x40;
98
99 /**
100 * The sort of type references that target the type of a resource variable in a method. See {@link
101 * #getSort}.
102 */
103 public static final int RESOURCE_VARIABLE = 0x41;
104
105 /**
106 * The sort of type references that target the type of the exception of a 'catch' clause in a
107 * method. See {@link #getSort}.
108 */
109 public static final int EXCEPTION_PARAMETER = 0x42;
110
111 /**
112 * The sort of type references that target the type declared in an 'instanceof' instruction. See
113 * {@link #getSort}.
114 */
115 public static final int INSTANCEOF = 0x43;
116
117 /**
118 * The sort of type references that target the type of the object created by a 'new' instruction.
119 * See {@link #getSort}.
120 */
121 public static final int NEW = 0x44;
122
123 /**
124 * The sort of type references that target the receiver type of a constructor reference. See
125 * {@link #getSort}.
126 */
127 public static final int CONSTRUCTOR_REFERENCE = 0x45;
128
129 /**
130 * The sort of type references that target the receiver type of a method reference. See {@link
131 * #getSort}.
132 */
133 public static final int METHOD_REFERENCE = 0x46;
134
135 /**
136 * The sort of type references that target the type declared in an explicit or implicit cast
137 * instruction. See {@link #getSort}.
138 */
139 public static final int CAST = 0x47;
140
141 /**
142 * The sort of type references that target a type parameter of a generic constructor in a
143 * constructor call. See {@link #getSort}.
144 */
145 public static final int CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT = 0x48;
146
147 /**
148 * The sort of type references that target a type parameter of a generic method in a method call.
149 * See {@link #getSort}.
150 */
151 public static final int METHOD_INVOCATION_TYPE_ARGUMENT = 0x49;
152
153 /**
154 * The sort of type references that target a type parameter of a generic constructor in a
155 * constructor reference. See {@link #getSort}.
156 */
157 public static final int CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT = 0x4A;
158
159 /**
160 * The sort of type references that target a type parameter of a generic method in a method
161 * reference. See {@link #getSort}.
162 */
163 public static final int METHOD_REFERENCE_TYPE_ARGUMENT = 0x4B;
164
165 /**
166 * The target_type and target_info structures - as defined in the Java Virtual Machine
167 * Specification (JVMS) - corresponding to this type reference. target_type uses one byte, and all
168 * the target_info union fields use up to 3 bytes (except localvar_target, handled with the
169 * specific method {@link MethodVisitor#visitLocalVariableAnnotation}). Thus, both structures can
170 * be stored in an int.
171 *
172 * <p>This int field stores target_type (called the TypeReference 'sort' in the public API of this
173 * class) in its most significant byte, followed by the target_info fields. Depending on
174 * target_type, 1, 2 or even 3 least significant bytes of this field are unused. target_info
175 * fields which reference bytecode offsets are set to 0 (these offsets are ignored in ClassReader,
176 * and recomputed in MethodWriter).
177 *
178 * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20">JVMS
179 * 4.7.20</a>
180 * @see <a
181 * href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20.1">JVMS
182 * 4.7.20.1</a>
183 */
184 private final int targetTypeAndInfo;
185
186 /**
187 * Constructs a new TypeReference.
188 *
189 * @param typeRef the int encoded value of the type reference, as received in a visit method
190 * related to type annotations, such as {@link ClassVisitor#visitTypeAnnotation}.
191 */
192 public TypeReference(final int typeRef) {
193 this.targetTypeAndInfo = typeRef;
194 }
195
196 /**
197 * Returns a type reference of the given sort.
198 *
199 * @param sort one of {@link #FIELD}, {@link #METHOD_RETURN}, {@link #METHOD_RECEIVER}, {@link
200 * #LOCAL_VARIABLE}, {@link #RESOURCE_VARIABLE}, {@link #INSTANCEOF}, {@link #NEW}, {@link
201 * #CONSTRUCTOR_REFERENCE}, or {@link #METHOD_REFERENCE}.
202 * @return a type reference of the given sort.
203 */
204 public static TypeReference newTypeReference(final int sort) {
205 return new TypeReference(sort << 24);
206 }
207
208 /**
209 * Returns a reference to a type parameter of a generic class or method.
210 *
211 * @param sort one of {@link #CLASS_TYPE_PARAMETER} or {@link #METHOD_TYPE_PARAMETER}.
212 * @param paramIndex the type parameter index.
213 * @return a reference to the given generic class or method type parameter.
214 */
215 public static TypeReference newTypeParameterReference(final int sort, final int paramIndex) {
216 return new TypeReference((sort << 24) | (paramIndex << 16));
217 }
218
219 /**
220 * Returns a reference to a type parameter bound of a generic class or method.
221 *
222 * @param sort one of {@link #CLASS_TYPE_PARAMETER} or {@link #METHOD_TYPE_PARAMETER}.
223 * @param paramIndex the type parameter index.
224 * @param boundIndex the type bound index within the above type parameters.
225 * @return a reference to the given generic class or method type parameter bound.
226 */
227 public static TypeReference newTypeParameterBoundReference(
228 final int sort, final int paramIndex, final int boundIndex) {
229 return new TypeReference((sort << 24) | (paramIndex << 16) | (boundIndex << 8));
230 }
231
232 /**
233 * Returns a reference to the super class or to an interface of the 'implements' clause of a
234 * class.
235 *
236 * @param itfIndex the index of an interface in the 'implements' clause of a class, or -1 to
237 * reference the super class of the class.
238 * @return a reference to the given super type of a class.
239 */
240 public static TypeReference newSuperTypeReference(final int itfIndex) {
241 return new TypeReference((CLASS_EXTENDS << 24) | ((itfIndex & 0xFFFF) << 8));
242 }
243
244 /**
245 * Returns a reference to the type of a formal parameter of a method.
246 *
247 * @param paramIndex the formal parameter index.
248 * @return a reference to the type of the given method formal parameter.
249 */
250 public static TypeReference newFormalParameterReference(final int paramIndex) {
251 return new TypeReference((METHOD_FORMAL_PARAMETER << 24) | (paramIndex << 16));
252 }
253
254 /**
255 * Returns a reference to the type of an exception, in a 'throws' clause of a method.
256 *
257 * @param exceptionIndex the index of an exception in a 'throws' clause of a method.
258 * @return a reference to the type of the given exception.
259 */
260 public static TypeReference newExceptionReference(final int exceptionIndex) {
261 return new TypeReference((THROWS << 24) | (exceptionIndex << 8));
262 }
263
264 /**
265 * Returns a reference to the type of the exception declared in a 'catch' clause of a method.
266 *
267 * @param tryCatchBlockIndex the index of a try catch block (using the order in which they are
268 * visited with visitTryCatchBlock).
269 * @return a reference to the type of the given exception.
270 */
271 public static TypeReference newTryCatchReference(final int tryCatchBlockIndex) {
272 return new TypeReference((EXCEPTION_PARAMETER << 24) | (tryCatchBlockIndex << 8));
273 }
274
275 /**
276 * Returns a reference to the type of a type argument in a constructor or method call or
277 * reference.
278 *
279 * @param sort one of {@link #CAST}, {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, {@link
280 * #METHOD_INVOCATION_TYPE_ARGUMENT}, {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or {@link
281 * #METHOD_REFERENCE_TYPE_ARGUMENT}.
282 * @param argIndex the type argument index.
283 * @return a reference to the type of the given type argument.
284 */
285 public static TypeReference newTypeArgumentReference(final int sort, final int argIndex) {
286 return new TypeReference((sort << 24) | argIndex);
287 }
288
289 /**
290 * Returns the sort of this type reference.
291 *
292 * @return one of {@link #CLASS_TYPE_PARAMETER}, {@link #METHOD_TYPE_PARAMETER}, {@link
293 * #CLASS_EXTENDS}, {@link #CLASS_TYPE_PARAMETER_BOUND}, {@link #METHOD_TYPE_PARAMETER_BOUND},
294 * {@link #FIELD}, {@link #METHOD_RETURN}, {@link #METHOD_RECEIVER}, {@link
295 * #METHOD_FORMAL_PARAMETER}, {@link #THROWS}, {@link #LOCAL_VARIABLE}, {@link
296 * #RESOURCE_VARIABLE}, {@link #EXCEPTION_PARAMETER}, {@link #INSTANCEOF}, {@link #NEW},
297 * {@link #CONSTRUCTOR_REFERENCE}, {@link #METHOD_REFERENCE}, {@link #CAST}, {@link
298 * #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, {@link #METHOD_INVOCATION_TYPE_ARGUMENT}, {@link
299 * #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or {@link #METHOD_REFERENCE_TYPE_ARGUMENT}.
300 */
301 public int getSort() {
302 return targetTypeAndInfo >>> 24;
303 }
304
305 /**
306 * Returns the index of the type parameter referenced by this type reference. This method must
307 * only be used for type references whose sort is {@link #CLASS_TYPE_PARAMETER}, {@link
308 * #METHOD_TYPE_PARAMETER}, {@link #CLASS_TYPE_PARAMETER_BOUND} or {@link
309 * #METHOD_TYPE_PARAMETER_BOUND}.
310 *
311 * @return a type parameter index.
312 */
313 public int getTypeParameterIndex() {
314 return (targetTypeAndInfo & 0x00FF0000) >> 16;
315 }
316
317 /**
318 * Returns the index of the type parameter bound, within the type parameter {@link
319 * #getTypeParameterIndex}, referenced by this type reference. This method must only be used for
320 * type references whose sort is {@link #CLASS_TYPE_PARAMETER_BOUND} or {@link
321 * #METHOD_TYPE_PARAMETER_BOUND}.
322 *
323 * @return a type parameter bound index.
324 */
325 public int getTypeParameterBoundIndex() {
326 return (targetTypeAndInfo & 0x0000FF00) >> 8;
327 }
328
329 /**
330 * Returns the index of the "super type" of a class that is referenced by this type reference.
331 * This method must only be used for type references whose sort is {@link #CLASS_EXTENDS}.
332 *
333 * @return the index of an interface in the 'implements' clause of a class, or -1 if this type
334 * reference references the type of the super class.
335 */
336 public int getSuperTypeIndex() {
337 return (short) ((targetTypeAndInfo & 0x00FFFF00) >> 8);
338 }
339
340 /**
341 * Returns the index of the formal parameter whose type is referenced by this type reference. This
342 * method must only be used for type references whose sort is {@link #METHOD_FORMAL_PARAMETER}.
343 *
344 * @return a formal parameter index.
345 */
346 public int getFormalParameterIndex() {
347 return (targetTypeAndInfo & 0x00FF0000) >> 16;
348 }
349
350 /**
351 * Returns the index of the exception, in a 'throws' clause of a method, whose type is referenced
352 * by this type reference. This method must only be used for type references whose sort is {@link
353 * #THROWS}.
354 *
355 * @return the index of an exception in the 'throws' clause of a method.
356 */
357 public int getExceptionIndex() {
358 return (targetTypeAndInfo & 0x00FFFF00) >> 8;
359 }
360
361 /**
362 * Returns the index of the try catch block (using the order in which they are visited with
363 * visitTryCatchBlock), whose 'catch' type is referenced by this type reference. This method must
364 * only be used for type references whose sort is {@link #EXCEPTION_PARAMETER} .
365 *
366 * @return the index of an exception in the 'throws' clause of a method.
367 */
368 public int getTryCatchBlockIndex() {
369 return (targetTypeAndInfo & 0x00FFFF00) >> 8;
370 }
371
372 /**
373 * Returns the index of the type argument referenced by this type reference. This method must only
374 * be used for type references whose sort is {@link #CAST}, {@link
375 * #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, {@link #METHOD_INVOCATION_TYPE_ARGUMENT}, {@link
376 * #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or {@link #METHOD_REFERENCE_TYPE_ARGUMENT}.
377 *
378 * @return a type parameter index.
379 */
380 public int getTypeArgumentIndex() {
381 return targetTypeAndInfo & 0xFF;
382 }
383
384 /**
385 * Returns the int encoded value of this type reference, suitable for use in visit methods related
386 * to type annotations, like visitTypeAnnotation.
387 *
388 * @return the int encoded value of this type reference.
389 */
390 public int getValue() {
391 return targetTypeAndInfo;
392 }
393
394 /**
395 * Puts the given target_type and target_info JVMS structures into the given ByteVector.
396 *
397 * @param targetTypeAndInfo a target_type and a target_info structures encoded as in {@link
398 * #targetTypeAndInfo}. LOCAL_VARIABLE and RESOURCE_VARIABLE target types are not supported.
399 * @param output where the type reference must be put.
400 */
401 static void putTarget(final int targetTypeAndInfo, final ByteVector output) {
402 switch (targetTypeAndInfo >>> 24) {
403 case CLASS_TYPE_PARAMETER:
404 case METHOD_TYPE_PARAMETER:
405 case METHOD_FORMAL_PARAMETER:
406 output.putShort(targetTypeAndInfo >>> 16);
407 break;
408 case FIELD:
409 case METHOD_RETURN:
410 case METHOD_RECEIVER:
411 output.putByte(targetTypeAndInfo >>> 24);
412 break;
413 case CAST:
414 case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
415 case METHOD_INVOCATION_TYPE_ARGUMENT:
416 case CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT:
417 case METHOD_REFERENCE_TYPE_ARGUMENT:
418 output.putInt(targetTypeAndInfo);
419 break;
420 case CLASS_EXTENDS:
421 case CLASS_TYPE_PARAMETER_BOUND:
422 case METHOD_TYPE_PARAMETER_BOUND:
423 case THROWS:
424 case EXCEPTION_PARAMETER:
425 case INSTANCEOF:
426 case NEW:
427 case CONSTRUCTOR_REFERENCE:
428 case METHOD_REFERENCE:
429 output.put12(targetTypeAndInfo >>> 24, (targetTypeAndInfo & 0xFFFF00) >> 8);
430 break;
431 default:
432 throw new IllegalArgumentException();
433 }
434 }
435 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.commons;
3028
3129 import java.util.ArrayList;
4038 import org.eclipse.persistence.internal.libraries.asm.Type;
4139
4240 /**
43 * A {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor} to insert before, after and around
44 * advices in methods and constructors.
45 * <p>
46 * The behavior for constructors is like this:
41 * A {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor} to insert before, after and around advices in methods
42 * and constructors.
43 *
44 * <p>The behavior for constructors is like this:
45 *
4746 * <ol>
48 *
49 * <li>as long as the INVOKESPECIAL for the object initialization has not been
50 * reached, every bytecode instruction is dispatched in the ctor code visitor</li>
51 *
52 * <li>when this one is reached, it is only added in the ctor code visitor and a
53 * JP invoke is added</li>
54 *
55 * <li>after that, only the other code visitor receives the instructions</li>
56 *
47 * <li>as long as the INVOKESPECIAL for the object initialization has not been reached, every
48 * bytecode instruction is dispatched in the ctor code visitor
49 * <li>when this one is reached, it is only added in the ctor code visitor and a JP invoke is
50 * added
51 * <li>after that, only the other code visitor receives the instructions
5752 * </ol>
58 *
53 *
5954 * @author Eugene Kuleshov
6055 * @author Eric Bruneton
6156 */
6257 public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes {
6358
64 private static final Object THIS = new Object();
65
66 private static final Object OTHER = new Object();
67
68 protected int methodAccess;
69
70 protected String methodDesc;
71
72 private boolean constructor;
73
74 private boolean superInitialized;
75
76 private List<Object> stackFrame;
77
78 private Map<Label, List<Object>> branches;
79
80 /**
81 * Creates a new {@link AdviceAdapter}.
82 *
83 * @param api
84 * the ASM API version implemented by this visitor. Must be one
85 * of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
86 * @param mv
87 * the method visitor to which this adapter delegates calls.
88 * @param access
89 * the method's access flags (see {@link Opcodes}).
90 * @param name
91 * the method's name.
92 * @param desc
93 * the method's descriptor (see {@link Type Type}).
94 */
95 protected AdviceAdapter(final int api, final MethodVisitor mv,
96 final int access, final String name, final String desc) {
97 super(api, mv, access, name, desc);
98 methodAccess = access;
99 methodDesc = desc;
100 constructor = "<init>".equals(name);
101 }
102
103 @Override
104 public void visitCode() {
105 mv.visitCode();
106 if (constructor) {
107 stackFrame = new ArrayList<Object>();
108 branches = new HashMap<Label, List<Object>>();
109 } else {
59 private static final Object THIS = new Object();
60
61 private static final Object OTHER = new Object();
62
63 protected int methodAccess;
64
65 protected String methodDesc;
66
67 private boolean constructor;
68
69 private boolean superInitialized;
70
71 private List<Object> stackFrame;
72
73 private Map<Label, List<Object>> branches;
74
75 /**
76 * Constructs a new {@link AdviceAdapter}.
77 *
78 * @param api the ASM API version implemented by this visitor. Must be one of {@link
79 * Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
80 * @param mv the method visitor to which this adapter delegates calls.
81 * @param access the method's access flags (see {@link Opcodes}).
82 * @param name the method's name.
83 * @param desc the method's descriptor (see {@link Type Type}).
84 */
85 protected AdviceAdapter(
86 final int api,
87 final MethodVisitor mv,
88 final int access,
89 final String name,
90 final String desc) {
91 super(api, mv, access, name, desc);
92 methodAccess = access;
93 methodDesc = desc;
94 constructor = "<init>".equals(name);
95 }
96
97 @Override
98 public void visitCode() {
99 super.visitCode();
100 if (constructor) {
101 stackFrame = new ArrayList<Object>();
102 branches = new HashMap<Label, List<Object>>();
103 } else {
104 superInitialized = true;
105 onMethodEnter();
106 }
107 }
108
109 @Override
110 public void visitLabel(final Label label) {
111 super.visitLabel(label);
112 if (constructor && branches != null) {
113 List<Object> frame = branches.get(label);
114 if (frame != null) {
115 stackFrame = frame;
116 branches.remove(label);
117 }
118 }
119 }
120
121 @Override
122 public void visitInsn(final int opcode) {
123 if (constructor) {
124 int s;
125 switch (opcode) {
126 case RETURN: // empty stack
127 onMethodExit(opcode);
128 break;
129 case IRETURN: // 1 before n/a after
130 case FRETURN: // 1 before n/a after
131 case ARETURN: // 1 before n/a after
132 case ATHROW: // 1 before n/a after
133 popValue();
134 onMethodExit(opcode);
135 break;
136 case LRETURN: // 2 before n/a after
137 case DRETURN: // 2 before n/a after
138 popValue();
139 popValue();
140 onMethodExit(opcode);
141 break;
142 case NOP:
143 case LALOAD: // remove 2 add 2
144 case DALOAD: // remove 2 add 2
145 case LNEG:
146 case DNEG:
147 case FNEG:
148 case INEG:
149 case L2D:
150 case D2L:
151 case F2I:
152 case I2B:
153 case I2C:
154 case I2S:
155 case I2F:
156 case ARRAYLENGTH:
157 break;
158 case ACONST_NULL:
159 case ICONST_M1:
160 case ICONST_0:
161 case ICONST_1:
162 case ICONST_2:
163 case ICONST_3:
164 case ICONST_4:
165 case ICONST_5:
166 case FCONST_0:
167 case FCONST_1:
168 case FCONST_2:
169 case F2L: // 1 before 2 after
170 case F2D:
171 case I2L:
172 case I2D:
173 pushValue(OTHER);
174 break;
175 case LCONST_0:
176 case LCONST_1:
177 case DCONST_0:
178 case DCONST_1:
179 pushValue(OTHER);
180 pushValue(OTHER);
181 break;
182 case IALOAD: // remove 2 add 1
183 case FALOAD: // remove 2 add 1
184 case AALOAD: // remove 2 add 1
185 case BALOAD: // remove 2 add 1
186 case CALOAD: // remove 2 add 1
187 case SALOAD: // remove 2 add 1
188 case POP:
189 case IADD:
190 case FADD:
191 case ISUB:
192 case LSHL: // 3 before 2 after
193 case LSHR: // 3 before 2 after
194 case LUSHR: // 3 before 2 after
195 case L2I: // 2 before 1 after
196 case L2F: // 2 before 1 after
197 case D2I: // 2 before 1 after
198 case D2F: // 2 before 1 after
199 case FSUB:
200 case FMUL:
201 case FDIV:
202 case FREM:
203 case FCMPL: // 2 before 1 after
204 case FCMPG: // 2 before 1 after
205 case IMUL:
206 case IDIV:
207 case IREM:
208 case ISHL:
209 case ISHR:
210 case IUSHR:
211 case IAND:
212 case IOR:
213 case IXOR:
214 case MONITORENTER:
215 case MONITOREXIT:
216 popValue();
217 break;
218 case POP2:
219 case LSUB:
220 case LMUL:
221 case LDIV:
222 case LREM:
223 case LADD:
224 case LAND:
225 case LOR:
226 case LXOR:
227 case DADD:
228 case DMUL:
229 case DSUB:
230 case DDIV:
231 case DREM:
232 popValue();
233 popValue();
234 break;
235 case IASTORE:
236 case FASTORE:
237 case AASTORE:
238 case BASTORE:
239 case CASTORE:
240 case SASTORE:
241 case LCMP: // 4 before 1 after
242 case DCMPL:
243 case DCMPG:
244 popValue();
245 popValue();
246 popValue();
247 break;
248 case LASTORE:
249 case DASTORE:
250 popValue();
251 popValue();
252 popValue();
253 popValue();
254 break;
255 case DUP:
256 pushValue(peekValue());
257 break;
258 case DUP_X1:
259 s = stackFrame.size();
260 stackFrame.add(s - 2, stackFrame.get(s - 1));
261 break;
262 case DUP_X2:
263 s = stackFrame.size();
264 stackFrame.add(s - 3, stackFrame.get(s - 1));
265 break;
266 case DUP2:
267 s = stackFrame.size();
268 stackFrame.add(s - 2, stackFrame.get(s - 1));
269 stackFrame.add(s - 2, stackFrame.get(s - 1));
270 break;
271 case DUP2_X1:
272 s = stackFrame.size();
273 stackFrame.add(s - 3, stackFrame.get(s - 1));
274 stackFrame.add(s - 3, stackFrame.get(s - 1));
275 break;
276 case DUP2_X2:
277 s = stackFrame.size();
278 stackFrame.add(s - 4, stackFrame.get(s - 1));
279 stackFrame.add(s - 4, stackFrame.get(s - 1));
280 break;
281 case SWAP:
282 s = stackFrame.size();
283 stackFrame.add(s - 2, stackFrame.get(s - 1));
284 stackFrame.remove(s);
285 break;
286 }
287 } else {
288 switch (opcode) {
289 case RETURN:
290 case IRETURN:
291 case FRETURN:
292 case ARETURN:
293 case LRETURN:
294 case DRETURN:
295 case ATHROW:
296 onMethodExit(opcode);
297 break;
298 }
299 }
300 super.visitInsn(opcode);
301 }
302
303 @Override
304 public void visitVarInsn(final int opcode, final int var) {
305 super.visitVarInsn(opcode, var);
306 if (constructor) {
307 switch (opcode) {
308 case ILOAD:
309 case FLOAD:
310 pushValue(OTHER);
311 break;
312 case LLOAD:
313 case DLOAD:
314 pushValue(OTHER);
315 pushValue(OTHER);
316 break;
317 case ALOAD:
318 pushValue(var == 0 ? THIS : OTHER);
319 break;
320 case ASTORE:
321 case ISTORE:
322 case FSTORE:
323 popValue();
324 break;
325 case LSTORE:
326 case DSTORE:
327 popValue();
328 popValue();
329 break;
330 }
331 }
332 }
333
334 @Override
335 public void visitFieldInsn(
336 final int opcode, final String owner, final String name, final String desc) {
337 super.visitFieldInsn(opcode, owner, name, desc);
338 if (constructor) {
339 char c = desc.charAt(0);
340 boolean longOrDouble = c == 'J' || c == 'D';
341 switch (opcode) {
342 case GETSTATIC:
343 pushValue(OTHER);
344 if (longOrDouble) {
345 pushValue(OTHER);
346 }
347 break;
348 case PUTSTATIC:
349 popValue();
350 if (longOrDouble) {
351 popValue();
352 }
353 break;
354 case PUTFIELD:
355 popValue();
356 popValue();
357 if (longOrDouble) {
358 popValue();
359 }
360 break;
361 // case GETFIELD:
362 default:
363 if (longOrDouble) {
364 pushValue(OTHER);
365 }
366 }
367 }
368 }
369
370 @Override
371 public void visitIntInsn(final int opcode, final int operand) {
372 super.visitIntInsn(opcode, operand);
373 if (constructor && opcode != NEWARRAY) {
374 pushValue(OTHER);
375 }
376 }
377
378 @Override
379 public void visitLdcInsn(final Object cst) {
380 super.visitLdcInsn(cst);
381 if (constructor) {
382 pushValue(OTHER);
383 if (cst instanceof Double || cst instanceof Long) {
384 pushValue(OTHER);
385 }
386 }
387 }
388
389 @Override
390 public void visitMultiANewArrayInsn(final String desc, final int dims) {
391 super.visitMultiANewArrayInsn(desc, dims);
392 if (constructor) {
393 for (int i = 0; i < dims; i++) {
394 popValue();
395 }
396 pushValue(OTHER);
397 }
398 }
399
400 @Override
401 public void visitTypeInsn(final int opcode, final String type) {
402 super.visitTypeInsn(opcode, type);
403 // ANEWARRAY, CHECKCAST or INSTANCEOF don't change stack
404 if (constructor && opcode == NEW) {
405 pushValue(OTHER);
406 }
407 }
408
409 @Deprecated
410 @Override
411 public void visitMethodInsn(
412 final int opcode, final String owner, final String name, final String desc) {
413 if (api >= Opcodes.ASM5) {
414 super.visitMethodInsn(opcode, owner, name, desc);
415 return;
416 }
417 doVisitMethodInsn(opcode, owner, name, desc, opcode == Opcodes.INVOKEINTERFACE);
418 }
419
420 @Override
421 public void visitMethodInsn(
422 final int opcode,
423 final String owner,
424 final String name,
425 final String desc,
426 final boolean itf) {
427 if (api < Opcodes.ASM5) {
428 super.visitMethodInsn(opcode, owner, name, desc, itf);
429 return;
430 }
431 doVisitMethodInsn(opcode, owner, name, desc, itf);
432 }
433
434 private void doVisitMethodInsn(
435 int opcode, final String owner, final String name, final String desc, final boolean itf) {
436 mv.visitMethodInsn(opcode, owner, name, desc, itf);
437 if (constructor) {
438 Type[] types = Type.getArgumentTypes(desc);
439 for (int i = 0; i < types.length; i++) {
440 popValue();
441 if (types[i].getSize() == 2) {
442 popValue();
443 }
444 }
445 switch (opcode) {
446 // case INVOKESTATIC:
447 // break;
448 case INVOKEINTERFACE:
449 case INVOKEVIRTUAL:
450 popValue(); // objectref
451 break;
452 case INVOKESPECIAL:
453 Object type = popValue(); // objectref
454 if (type == THIS && !superInitialized) {
455 onMethodEnter();
110456 superInitialized = true;
111 onMethodEnter();
457 // once super has been initialized it is no longer
458 // necessary to keep track of stack state
459 constructor = false;
460 }
461 break;
462 }
463
464 Type returnType = Type.getReturnType(desc);
465 if (returnType != Type.VOID_TYPE) {
466 pushValue(OTHER);
467 if (returnType.getSize() == 2) {
468 pushValue(OTHER);
112469 }
113 }
114
115 @Override
116 public void visitLabel(final Label label) {
117 mv.visitLabel(label);
118 if (constructor && branches != null) {
119 List<Object> frame = branches.get(label);
120 if (frame != null) {
121 stackFrame = frame;
122 branches.remove(label);
123 }
470 }
471 }
472 }
473
474 @Override
475 public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) {
476 super.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
477 if (constructor) {
478 Type[] types = Type.getArgumentTypes(desc);
479 for (int i = 0; i < types.length; i++) {
480 popValue();
481 if (types[i].getSize() == 2) {
482 popValue();
124483 }
125 }
126
127 @Override
128 public void visitInsn(final int opcode) {
129 if (constructor) {
130 int s;
131 switch (opcode) {
132 case RETURN: // empty stack
133 onMethodExit(opcode);
134 break;
135 case IRETURN: // 1 before n/a after
136 case FRETURN: // 1 before n/a after
137 case ARETURN: // 1 before n/a after
138 case ATHROW: // 1 before n/a after
139 popValue();
140 onMethodExit(opcode);
141 break;
142 case LRETURN: // 2 before n/a after
143 case DRETURN: // 2 before n/a after
144 popValue();
145 popValue();
146 onMethodExit(opcode);
147 break;
148 case NOP:
149 case LALOAD: // remove 2 add 2
150 case DALOAD: // remove 2 add 2
151 case LNEG:
152 case DNEG:
153 case FNEG:
154 case INEG:
155 case L2D:
156 case D2L:
157 case F2I:
158 case I2B:
159 case I2C:
160 case I2S:
161 case I2F:
162 case ARRAYLENGTH:
163 break;
164 case ACONST_NULL:
165 case ICONST_M1:
166 case ICONST_0:
167 case ICONST_1:
168 case ICONST_2:
169 case ICONST_3:
170 case ICONST_4:
171 case ICONST_5:
172 case FCONST_0:
173 case FCONST_1:
174 case FCONST_2:
175 case F2L: // 1 before 2 after
176 case F2D:
177 case I2L:
178 case I2D:
179 pushValue(OTHER);
180 break;
181 case LCONST_0:
182 case LCONST_1:
183 case DCONST_0:
184 case DCONST_1:
185 pushValue(OTHER);
186 pushValue(OTHER);
187 break;
188 case IALOAD: // remove 2 add 1
189 case FALOAD: // remove 2 add 1
190 case AALOAD: // remove 2 add 1
191 case BALOAD: // remove 2 add 1
192 case CALOAD: // remove 2 add 1
193 case SALOAD: // remove 2 add 1
194 case POP:
195 case IADD:
196 case FADD:
197 case ISUB:
198 case LSHL: // 3 before 2 after
199 case LSHR: // 3 before 2 after
200 case LUSHR: // 3 before 2 after
201 case L2I: // 2 before 1 after
202 case L2F: // 2 before 1 after
203 case D2I: // 2 before 1 after
204 case D2F: // 2 before 1 after
205 case FSUB:
206 case FMUL:
207 case FDIV:
208 case FREM:
209 case FCMPL: // 2 before 1 after
210 case FCMPG: // 2 before 1 after
211 case IMUL:
212 case IDIV:
213 case IREM:
214 case ISHL:
215 case ISHR:
216 case IUSHR:
217 case IAND:
218 case IOR:
219 case IXOR:
220 case MONITORENTER:
221 case MONITOREXIT:
222 popValue();
223 break;
224 case POP2:
225 case LSUB:
226 case LMUL:
227 case LDIV:
228 case LREM:
229 case LADD:
230 case LAND:
231 case LOR:
232 case LXOR:
233 case DADD:
234 case DMUL:
235 case DSUB:
236 case DDIV:
237 case DREM:
238 popValue();
239 popValue();
240 break;
241 case IASTORE:
242 case FASTORE:
243 case AASTORE:
244 case BASTORE:
245 case CASTORE:
246 case SASTORE:
247 case LCMP: // 4 before 1 after
248 case DCMPL:
249 case DCMPG:
250 popValue();
251 popValue();
252 popValue();
253 break;
254 case LASTORE:
255 case DASTORE:
256 popValue();
257 popValue();
258 popValue();
259 popValue();
260 break;
261 case DUP:
262 pushValue(peekValue());
263 break;
264 case DUP_X1:
265 s = stackFrame.size();
266 stackFrame.add(s - 2, stackFrame.get(s - 1));
267 break;
268 case DUP_X2:
269 s = stackFrame.size();
270 stackFrame.add(s - 3, stackFrame.get(s - 1));
271 break;
272 case DUP2:
273 s = stackFrame.size();
274 stackFrame.add(s - 2, stackFrame.get(s - 1));
275 stackFrame.add(s - 2, stackFrame.get(s - 1));
276 break;
277 case DUP2_X1:
278 s = stackFrame.size();
279 stackFrame.add(s - 3, stackFrame.get(s - 1));
280 stackFrame.add(s - 3, stackFrame.get(s - 1));
281 break;
282 case DUP2_X2:
283 s = stackFrame.size();
284 stackFrame.add(s - 4, stackFrame.get(s - 1));
285 stackFrame.add(s - 4, stackFrame.get(s - 1));
286 break;
287 case SWAP:
288 s = stackFrame.size();
289 stackFrame.add(s - 2, stackFrame.get(s - 1));
290 stackFrame.remove(s);
291 break;
292 }
293 } else {
294 switch (opcode) {
295 case RETURN:
296 case IRETURN:
297 case FRETURN:
298 case ARETURN:
299 case LRETURN:
300 case DRETURN:
301 case ATHROW:
302 onMethodExit(opcode);
303 break;
304 }
484 }
485
486 Type returnType = Type.getReturnType(desc);
487 if (returnType != Type.VOID_TYPE) {
488 pushValue(OTHER);
489 if (returnType.getSize() == 2) {
490 pushValue(OTHER);
305491 }
306 mv.visitInsn(opcode);
307 }
308
309 @Override
310 public void visitVarInsn(final int opcode, final int var) {
311 super.visitVarInsn(opcode, var);
312 if (constructor) {
313 switch (opcode) {
314 case ILOAD:
315 case FLOAD:
316 pushValue(OTHER);
317 break;
318 case LLOAD:
319 case DLOAD:
320 pushValue(OTHER);
321 pushValue(OTHER);
322 break;
323 case ALOAD:
324 pushValue(var == 0 ? THIS : OTHER);
325 break;
326 case ASTORE:
327 case ISTORE:
328 case FSTORE:
329 popValue();
330 break;
331 case LSTORE:
332 case DSTORE:
333 popValue();
334 popValue();
335 break;
336 }
337 }
338 }
339
340 @Override
341 public void visitFieldInsn(final int opcode, final String owner,
342 final String name, final String desc) {
343 mv.visitFieldInsn(opcode, owner, name, desc);
344 if (constructor) {
345 char c = desc.charAt(0);
346 boolean longOrDouble = c == 'J' || c == 'D';
347 switch (opcode) {
348 case GETSTATIC:
349 pushValue(OTHER);
350 if (longOrDouble) {
351 pushValue(OTHER);
352 }
353 break;
354 case PUTSTATIC:
355 popValue();
356 if (longOrDouble) {
357 popValue();
358 }
359 break;
360 case PUTFIELD:
361 popValue();
362 popValue();
363 if (longOrDouble) {
364 popValue();
365 }
366 break;
367 // case GETFIELD:
368 default:
369 if (longOrDouble) {
370 pushValue(OTHER);
371 }
372 }
373 }
374 }
375
376 @Override
377 public void visitIntInsn(final int opcode, final int operand) {
378 mv.visitIntInsn(opcode, operand);
379 if (constructor && opcode != NEWARRAY) {
380 pushValue(OTHER);
381 }
382 }
383
384 @Override
385 public void visitLdcInsn(final Object cst) {
386 mv.visitLdcInsn(cst);
387 if (constructor) {
388 pushValue(OTHER);
389 if (cst instanceof Double || cst instanceof Long) {
390 pushValue(OTHER);
391 }
392 }
393 }
394
395 @Override
396 public void visitMultiANewArrayInsn(final String desc, final int dims) {
397 mv.visitMultiANewArrayInsn(desc, dims);
398 if (constructor) {
399 for (int i = 0; i < dims; i++) {
400 popValue();
401 }
402 pushValue(OTHER);
403 }
404 }
405
406 @Override
407 public void visitTypeInsn(final int opcode, final String type) {
408 mv.visitTypeInsn(opcode, type);
409 // ANEWARRAY, CHECKCAST or INSTANCEOF don't change stack
410 if (constructor && opcode == NEW) {
411 pushValue(OTHER);
412 }
413 }
414
415 @Deprecated
416 @Override
417 public void visitMethodInsn(final int opcode, final String owner,
418 final String name, final String desc) {
419 if (api >= Opcodes.ASM5) {
420 super.visitMethodInsn(opcode, owner, name, desc);
421 return;
422 }
423 doVisitMethodInsn(opcode, owner, name, desc,
424 opcode == Opcodes.INVOKEINTERFACE);
425 }
426
427 @Override
428 public void visitMethodInsn(final int opcode, final String owner,
429 final String name, final String desc, final boolean itf) {
430 if (api < Opcodes.ASM5) {
431 super.visitMethodInsn(opcode, owner, name, desc, itf);
432 return;
433 }
434 doVisitMethodInsn(opcode, owner, name, desc, itf);
435 }
436
437 private void doVisitMethodInsn(int opcode, final String owner,
438 final String name, final String desc, final boolean itf) {
439 mv.visitMethodInsn(opcode, owner, name, desc, itf);
440 if (constructor) {
441 Type[] types = Type.getArgumentTypes(desc);
442 for (int i = 0; i < types.length; i++) {
443 popValue();
444 if (types[i].getSize() == 2) {
445 popValue();
446 }
447 }
448 switch (opcode) {
449 // case INVOKESTATIC:
450 // break;
451 case INVOKEINTERFACE:
452 case INVOKEVIRTUAL:
453 popValue(); // objectref
454 break;
455 case INVOKESPECIAL:
456 Object type = popValue(); // objectref
457 if (type == THIS && !superInitialized) {
458 onMethodEnter();
459 superInitialized = true;
460 // once super has been initialized it is no longer
461 // necessary to keep track of stack state
462 constructor = false;
463 }
464 break;
465 }
466
467 Type returnType = Type.getReturnType(desc);
468 if (returnType != Type.VOID_TYPE) {
469 pushValue(OTHER);
470 if (returnType.getSize() == 2) {
471 pushValue(OTHER);
472 }
473 }
474 }
475 }
476
477 @Override
478 public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
479 Object... bsmArgs) {
480 mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
481 if (constructor) {
482 Type[] types = Type.getArgumentTypes(desc);
483 for (int i = 0; i < types.length; i++) {
484 popValue();
485 if (types[i].getSize() == 2) {
486 popValue();
487 }
488 }
489
490 Type returnType = Type.getReturnType(desc);
491 if (returnType != Type.VOID_TYPE) {
492 pushValue(OTHER);
493 if (returnType.getSize() == 2) {
494 pushValue(OTHER);
495 }
496 }
497 }
498 }
499
500 @Override
501 public void visitJumpInsn(final int opcode, final Label label) {
502 mv.visitJumpInsn(opcode, label);
503 if (constructor) {
504 switch (opcode) {
505 case IFEQ:
506 case IFNE:
507 case IFLT:
508 case IFGE:
509 case IFGT:
510 case IFLE:
511 case IFNULL:
512 case IFNONNULL:
513 popValue();
514 break;
515 case IF_ICMPEQ:
516 case IF_ICMPNE:
517 case IF_ICMPLT:
518 case IF_ICMPGE:
519 case IF_ICMPGT:
520 case IF_ICMPLE:
521 case IF_ACMPEQ:
522 case IF_ACMPNE:
523 popValue();
524 popValue();
525 break;
526 case JSR:
527 pushValue(OTHER);
528 break;
529 }
530 addBranch(label);
531 }
532 }
533
534 @Override
535 public void visitLookupSwitchInsn(final Label dflt, final int[] keys,
536 final Label[] labels) {
537 mv.visitLookupSwitchInsn(dflt, keys, labels);
538 if (constructor) {
539 popValue();
540 addBranches(dflt, labels);
541 }
542 }
543
544 @Override
545 public void visitTableSwitchInsn(final int min, final int max,
546 final Label dflt, final Label... labels) {
547 mv.visitTableSwitchInsn(min, max, dflt, labels);
548 if (constructor) {
549 popValue();
550 addBranches(dflt, labels);
551 }
552 }
553
554 @Override
555 public void visitTryCatchBlock(Label start, Label end, Label handler,
556 String type) {
557 super.visitTryCatchBlock(start, end, handler, type);
558 if (constructor && !branches.containsKey(handler)) {
559 List<Object> stackFrame = new ArrayList<Object>();
560 stackFrame.add(OTHER);
561 branches.put(handler, stackFrame);
562 }
563 }
564
565 private void addBranches(final Label dflt, final Label[] labels) {
566 addBranch(dflt);
567 for (int i = 0; i < labels.length; i++) {
568 addBranch(labels[i]);
569 }
570 }
571
572 private void addBranch(final Label label) {
573 if (branches.containsKey(label)) {
574 return;
575 }
576 branches.put(label, new ArrayList<Object>(stackFrame));
577 }
578
579 private Object popValue() {
580 return stackFrame.remove(stackFrame.size() - 1);
581 }
582
583 private Object peekValue() {
584 return stackFrame.get(stackFrame.size() - 1);
585 }
586
587 private void pushValue(final Object o) {
588 stackFrame.add(o);
589 }
590
591 /**
592 * Called at the beginning of the method or after super class call in
593 * the constructor. <br>
594 * <br>
595 *
596 * <i>Custom code can use or change all the local variables, but should not
597 * change state of the stack.</i>
598 */
599 protected void onMethodEnter() {
600 }
601
602 /**
603 * Called before explicit exit from the method using either return or throw.
604 * Top element on the stack contains the return value or exception instance.
605 * For example:
606 *
607 * <pre>
608 * public void onMethodExit(int opcode) {
609 * if(opcode==RETURN) {
610 * visitInsn(ACONST_NULL);
611 * } else if(opcode==ARETURN || opcode==ATHROW) {
612 * dup();
613 * } else {
614 * if(opcode==LRETURN || opcode==DRETURN) {
615 * dup2();
616 * } else {
617 * dup();
618 * }
619 * box(Type.getReturnType(this.methodDesc));
620 * }
621 * visitIntInsn(SIPUSH, opcode);
622 * visitMethodInsn(INVOKESTATIC, owner, "onExit", "(Ljava/lang/Object;I)V");
623 * }
624 *
625 * // an actual call back method
626 * public static void onExit(Object param, int opcode) {
627 * ...
628 * </pre>
629 *
630 * <br>
631 * <br>
632 *
633 * <i>Custom code can use or change all the local variables, but should not
634 * change state of the stack.</i>
635 *
636 * @param opcode
637 * one of the RETURN, IRETURN, FRETURN, ARETURN, LRETURN, DRETURN
638 * or ATHROW
639 *
640 */
641 protected void onMethodExit(int opcode) {
642 }
643
644 // TODO onException, onMethodCall
492 }
493 }
494 }
495
496 @Override
497 public void visitJumpInsn(final int opcode, final Label label) {
498 super.visitJumpInsn(opcode, label);
499 if (constructor) {
500 switch (opcode) {
501 case IFEQ:
502 case IFNE:
503 case IFLT:
504 case IFGE:
505 case IFGT:
506 case IFLE:
507 case IFNULL:
508 case IFNONNULL:
509 popValue();
510 break;
511 case IF_ICMPEQ:
512 case IF_ICMPNE:
513 case IF_ICMPLT:
514 case IF_ICMPGE:
515 case IF_ICMPGT:
516 case IF_ICMPLE:
517 case IF_ACMPEQ:
518 case IF_ACMPNE:
519 popValue();
520 popValue();
521 break;
522 case JSR:
523 pushValue(OTHER);
524 break;
525 }
526 addBranch(label);
527 }
528 }
529
530 @Override
531 public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) {
532 super.visitLookupSwitchInsn(dflt, keys, labels);
533 if (constructor) {
534 popValue();
535 addBranches(dflt, labels);
536 }
537 }
538
539 @Override
540 public void visitTableSwitchInsn(
541 final int min, final int max, final Label dflt, final Label... labels) {
542 super.visitTableSwitchInsn(min, max, dflt, labels);
543 if (constructor) {
544 popValue();
545 addBranches(dflt, labels);
546 }
547 }
548
549 @Override
550 public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
551 super.visitTryCatchBlock(start, end, handler, type);
552 if (constructor && !branches.containsKey(handler)) {
553 List<Object> stackFrame = new ArrayList<Object>();
554 stackFrame.add(OTHER);
555 branches.put(handler, stackFrame);
556 }
557 }
558
559 private void addBranches(final Label dflt, final Label[] labels) {
560 addBranch(dflt);
561 for (int i = 0; i < labels.length; i++) {
562 addBranch(labels[i]);
563 }
564 }
565
566 private void addBranch(final Label label) {
567 if (branches.containsKey(label)) {
568 return;
569 }
570 branches.put(label, new ArrayList<Object>(stackFrame));
571 }
572
573 private Object popValue() {
574 return stackFrame.remove(stackFrame.size() - 1);
575 }
576
577 private Object peekValue() {
578 return stackFrame.get(stackFrame.size() - 1);
579 }
580
581 private void pushValue(final Object o) {
582 stackFrame.add(o);
583 }
584
585 /**
586 * Called at the beginning of the method or after super class call in the constructor. <br>
587 * <br>
588 * <i>Custom code can use or change all the local variables, but should not change state of the
589 * stack.</i>
590 */
591 protected void onMethodEnter() {}
592
593 /**
594 * Called before explicit exit from the method using either return or throw. Top element on the
595 * stack contains the return value or exception instance. For example:
596 *
597 * <pre>
598 * public void onMethodExit(int opcode) {
599 * if(opcode==RETURN) {
600 * visitInsn(ACONST_NULL);
601 * } else if(opcode==ARETURN || opcode==ATHROW) {
602 * dup();
603 * } else {
604 * if(opcode==LRETURN || opcode==DRETURN) {
605 * dup2();
606 * } else {
607 * dup();
608 * }
609 * box(Type.getReturnType(this.methodDesc));
610 * }
611 * visitIntInsn(SIPUSH, opcode);
612 * visitMethodInsn(INVOKESTATIC, owner, "onExit", "(Ljava/lang/Object;I)V");
613 * }
614 *
615 * // an actual call back method
616 * public static void onExit(Object param, int opcode) {
617 * ...
618 * </pre>
619 *
620 * <br>
621 * <br>
622 * <i>Custom code can use or change all the local variables, but should not change state of the
623 * stack.</i>
624 *
625 * @param opcode one of the RETURN, IRETURN, FRETURN, ARETURN, LRETURN, DRETURN or ATHROW
626 */
627 protected void onMethodExit(int opcode) {}
628
629 // TODO onException, onMethodCall
645630 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.commons;
3028
3129 import java.util.ArrayList;
4038 import org.eclipse.persistence.internal.libraries.asm.Type;
4139
4240 /**
43 * A {@link MethodVisitor} that keeps track of stack map frame changes between
44 * {@link #visitFrame(int, int, Object[], int, Object[]) visitFrame} calls. This
45 * adapter must be used with the
46 * {@link org.eclipse.persistence.internal.libraries.asm.ClassReader#EXPAND_FRAMES} option. Each
47 * visit<i>X</i> instruction delegates to the next visitor in the chain, if any,
48 * and then simulates the effect of this instruction on the stack map frame,
49 * represented by {@link #locals} and {@link #stack}. The next visitor in the
50 * chain can get the state of the stack map frame <i>before</i> each instruction
51 * by reading the value of these fields in its visit<i>X</i> methods (this
52 * requires a reference to the AnalyzerAdapter that is before it in the chain).
53 * If this adapter is used with a class that does not contain stack map table
54 * attributes (i.e., pre Java 6 classes) then this adapter may not be able to
55 * compute the stack map frame for each instruction. In this case no exception
56 * is thrown but the {@link #locals} and {@link #stack} fields will be null for
57 * these instructions.
58 *
41 * A {@link MethodVisitor} that keeps track of stack map frame changes between {@link
42 * #visitFrame(int, int, Object[], int, Object[]) visitFrame} calls. This adapter must be used with
43 * the {@link org.eclipse.persistence.internal.libraries.asm.ClassReader#EXPAND_FRAMES} option. Each visit<i>X</i> instruction
44 * delegates to the next visitor in the chain, if any, and then simulates the effect of this
45 * instruction on the stack map frame, represented by {@link #locals} and {@link #stack}. The next
46 * visitor in the chain can get the state of the stack map frame <i>before</i> each instruction by
47 * reading the value of these fields in its visit<i>X</i> methods (this requires a reference to the
48 * AnalyzerAdapter that is before it in the chain). If this adapter is used with a class that does
49 * not contain stack map table attributes (i.e., pre Java 6 classes) then this adapter may not be
50 * able to compute the stack map frame for each instruction. In this case no exception is thrown but
51 * the {@link #locals} and {@link #stack} fields will be null for these instructions.
52 *
5953 * @author Eric Bruneton
6054 */
6155 public class AnalyzerAdapter extends MethodVisitor {
6256
63 /**
64 * <code>List</code> of the local variable slots for current execution
65 * frame. Primitive types are represented by {@link Opcodes#TOP},
66 * {@link Opcodes#INTEGER}, {@link Opcodes#FLOAT}, {@link Opcodes#LONG},
67 * {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or
68 * {@link Opcodes#UNINITIALIZED_THIS} (long and double are represented by
69 * two elements, the second one being TOP). Reference types are represented
70 * by String objects (representing internal names), and uninitialized types
71 * by Label objects (this label designates the NEW instruction that created
72 * this uninitialized value). This field is <tt>null</tt> for unreachable
73 * instructions.
74 */
75 public List<Object> locals;
76
77 /**
78 * <code>List</code> of the operand stack slots for current execution frame.
79 * Primitive types are represented by {@link Opcodes#TOP},
80 * {@link Opcodes#INTEGER}, {@link Opcodes#FLOAT}, {@link Opcodes#LONG},
81 * {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or
82 * {@link Opcodes#UNINITIALIZED_THIS} (long and double are represented by
83 * two elements, the second one being TOP). Reference types are represented
84 * by String objects (representing internal names), and uninitialized types
85 * by Label objects (this label designates the NEW instruction that created
86 * this uninitialized value). This field is <tt>null</tt> for unreachable
87 * instructions.
88 */
89 public List<Object> stack;
90
91 /**
92 * The labels that designate the next instruction to be visited. May be
93 * <tt>null</tt>.
94 */
95 private List<Label> labels;
96
97 /**
98 * Information about uninitialized types in the current execution frame.
99 * This map associates internal names to Label objects. Each label
100 * designates a NEW instruction that created the currently uninitialized
101 * types, and the associated internal name represents the NEW operand, i.e.
102 * the final, initialized type value.
103 */
104 public Map<Object, Object> uninitializedTypes;
105
106 /**
107 * The maximum stack size of this method.
108 */
109 private int maxStack;
110
111 /**
112 * The maximum number of local variables of this method.
113 */
114 private int maxLocals;
115
116 /**
117 * The owner's class name.
118 */
119 private String owner;
120
121 /**
122 * Creates a new {@link AnalyzerAdapter}. <i>Subclasses must not use this
123 * constructor</i>. Instead, they must use the
124 * {@link #AnalyzerAdapter(int, String, int, String, String, MethodVisitor)}
125 * version.
126 *
127 * @param owner
128 * the owner's class name.
129 * @param access
130 * the method's access flags (see {@link Opcodes}).
131 * @param name
132 * the method's name.
133 * @param desc
134 * the method's descriptor (see {@link Type Type}).
135 * @param mv
136 * the method visitor to which this adapter delegates calls. May
137 * be <tt>null</tt>.
138 * @throws IllegalStateException
139 * If a subclass calls this constructor.
140 */
141 public AnalyzerAdapter(final String owner, final int access,
142 final String name, final String desc, final MethodVisitor mv) {
143 this(Opcodes.ASM6, owner, access, name, desc, mv);
144 if (getClass() != AnalyzerAdapter.class) {
145 throw new IllegalStateException();
57 /**
58 * <code>List</code> of the local variable slots for current execution frame. Primitive types are
59 * represented by {@link Opcodes#TOP}, {@link Opcodes#INTEGER}, {@link Opcodes#FLOAT}, {@link
60 * Opcodes#LONG}, {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or {@link
61 * Opcodes#UNINITIALIZED_THIS} (long and double are represented by two elements, the second one
62 * being TOP). Reference types are represented by String objects (representing internal names),
63 * and uninitialized types by Label objects (this label designates the NEW instruction that
64 * created this uninitialized value). This field is <tt>null</tt> for unreachable instructions.
65 */
66 public List<Object> locals;
67
68 /**
69 * <code>List</code> of the operand stack slots for current execution frame. Primitive types are
70 * represented by {@link Opcodes#TOP}, {@link Opcodes#INTEGER}, {@link Opcodes#FLOAT}, {@link
71 * Opcodes#LONG}, {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or {@link
72 * Opcodes#UNINITIALIZED_THIS} (long and double are represented by two elements, the second one
73 * being TOP). Reference types are represented by String objects (representing internal names),
74 * and uninitialized types by Label objects (this label designates the NEW instruction that
75 * created this uninitialized value). This field is <tt>null</tt> for unreachable instructions.
76 */
77 public List<Object> stack;
78
79 /** The labels that designate the next instruction to be visited. May be <tt>null</tt>. */
80 private List<Label> labels;
81
82 /**
83 * Information about uninitialized types in the current execution frame. This map associates
84 * internal names to Label objects. Each label designates a NEW instruction that created the
85 * currently uninitialized types, and the associated internal name represents the NEW operand,
86 * i.e. the final, initialized type value.
87 */
88 public Map<Object, Object> uninitializedTypes;
89
90 /** The maximum stack size of this method. */
91 private int maxStack;
92
93 /** The maximum number of local variables of this method. */
94 private int maxLocals;
95
96 /** The owner's class name. */
97 private String owner;
98
99 /**
100 * Constructs a new {@link AnalyzerAdapter}. <i>Subclasses must not use this constructor</i>.
101 * Instead, they must use the {@link #AnalyzerAdapter(int, String, int, String, String,
102 * MethodVisitor)} version.
103 *
104 * @param owner the owner's class name.
105 * @param access the method's access flags (see {@link Opcodes}).
106 * @param name the method's name.
107 * @param desc the method's descriptor (see {@link Type Type}).
108 * @param mv the method visitor to which this adapter delegates calls. May be <tt>null</tt>.
109 * @throws IllegalStateException If a subclass calls this constructor.
110 */
111 public AnalyzerAdapter(
112 final String owner,
113 final int access,
114 final String name,
115 final String desc,
116 final MethodVisitor mv) {
117 this(Opcodes.ASM6, owner, access, name, desc, mv);
118 if (getClass() != AnalyzerAdapter.class) {
119 throw new IllegalStateException();
120 }
121 }
122
123 /**
124 * Constructs a new {@link AnalyzerAdapter}.
125 *
126 * @param api the ASM API version implemented by this visitor. Must be one of {@link
127 * Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
128 * @param owner the owner's class name.
129 * @param access the method's access flags (see {@link Opcodes}).
130 * @param name the method's name.
131 * @param desc the method's descriptor (see {@link Type Type}).
132 * @param mv the method visitor to which this adapter delegates calls. May be <tt>null</tt>.
133 */
134 protected AnalyzerAdapter(
135 final int api,
136 final String owner,
137 final int access,
138 final String name,
139 final String desc,
140 final MethodVisitor mv) {
141 super(api, mv);
142 this.owner = owner;
143 locals = new ArrayList<Object>();
144 stack = new ArrayList<Object>();
145 uninitializedTypes = new HashMap<Object, Object>();
146
147 if ((access & Opcodes.ACC_STATIC) == 0) {
148 if ("<init>".equals(name)) {
149 locals.add(Opcodes.UNINITIALIZED_THIS);
150 } else {
151 locals.add(owner);
152 }
153 }
154 Type[] types = Type.getArgumentTypes(desc);
155 for (int i = 0; i < types.length; ++i) {
156 Type type = types[i];
157 switch (type.getSort()) {
158 case Type.BOOLEAN:
159 case Type.CHAR:
160 case Type.BYTE:
161 case Type.SHORT:
162 case Type.INT:
163 locals.add(Opcodes.INTEGER);
164 break;
165 case Type.FLOAT:
166 locals.add(Opcodes.FLOAT);
167 break;
168 case Type.LONG:
169 locals.add(Opcodes.LONG);
170 locals.add(Opcodes.TOP);
171 break;
172 case Type.DOUBLE:
173 locals.add(Opcodes.DOUBLE);
174 locals.add(Opcodes.TOP);
175 break;
176 case Type.ARRAY:
177 locals.add(types[i].getDescriptor());
178 break;
179 // case Type.OBJECT:
180 default:
181 locals.add(types[i].getInternalName());
182 }
183 }
184 maxLocals = locals.size();
185 }
186
187 @Override
188 public void visitFrame(
189 final int type,
190 final int nLocal,
191 final Object[] local,
192 final int nStack,
193 final Object[] stack) {
194 if (type != Opcodes.F_NEW) { // uncompressed frame
195 throw new IllegalArgumentException(
196 "AnalyzerAdapter only accepts expanded frames (see ClassReader.EXPAND_FRAMES)");
197 }
198
199 super.visitFrame(type, nLocal, local, nStack, stack);
200
201 if (this.locals != null) {
202 this.locals.clear();
203 this.stack.clear();
204 } else {
205 this.locals = new ArrayList<Object>();
206 this.stack = new ArrayList<Object>();
207 }
208 visitFrameTypes(nLocal, local, this.locals);
209 visitFrameTypes(nStack, stack, this.stack);
210 maxLocals = Math.max(maxLocals, this.locals.size());
211 maxStack = Math.max(maxStack, this.stack.size());
212 }
213
214 private static void visitFrameTypes(
215 final int n, final Object[] types, final List<Object> result) {
216 for (int i = 0; i < n; ++i) {
217 Object type = types[i];
218 result.add(type);
219 if (type == Opcodes.LONG || type == Opcodes.DOUBLE) {
220 result.add(Opcodes.TOP);
221 }
222 }
223 }
224
225 @Override
226 public void visitInsn(final int opcode) {
227 super.visitInsn(opcode);
228 execute(opcode, 0, null);
229 if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN) || opcode == Opcodes.ATHROW) {
230 this.locals = null;
231 this.stack = null;
232 }
233 }
234
235 @Override
236 public void visitIntInsn(final int opcode, final int operand) {
237 super.visitIntInsn(opcode, operand);
238 execute(opcode, operand, null);
239 }
240
241 @Override
242 public void visitVarInsn(final int opcode, final int var) {
243 super.visitVarInsn(opcode, var);
244 boolean isLongOrDouble =
245 opcode == Opcodes.LLOAD
246 || opcode == Opcodes.DLOAD
247 || opcode == Opcodes.LSTORE
248 || opcode == Opcodes.DSTORE;
249 maxLocals = Math.max(maxLocals, var + (isLongOrDouble ? 2 : 1));
250 execute(opcode, var, null);
251 }
252
253 @Override
254 public void visitTypeInsn(final int opcode, final String type) {
255 if (opcode == Opcodes.NEW) {
256 if (labels == null) {
257 Label l = new Label();
258 labels = new ArrayList<Label>(3);
259 labels.add(l);
260 if (mv != null) {
261 mv.visitLabel(l);
146262 }
147 }
148
149 /**
150 * Creates a new {@link AnalyzerAdapter}.
151 *
152 * @param api
153 * the ASM API version implemented by this visitor. Must be one
154 * of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
155 * @param owner
156 * the owner's class name.
157 * @param access
158 * the method's access flags (see {@link Opcodes}).
159 * @param name
160 * the method's name.
161 * @param desc
162 * the method's descriptor (see {@link Type Type}).
163 * @param mv
164 * the method visitor to which this adapter delegates calls. May
165 * be <tt>null</tt>.
166 */
167 protected AnalyzerAdapter(final int api, final String owner,
168 final int access, final String name, final String desc,
169 final MethodVisitor mv) {
170 super(api, mv);
171 this.owner = owner;
172 locals = new ArrayList<Object>();
173 stack = new ArrayList<Object>();
174 uninitializedTypes = new HashMap<Object, Object>();
175
176 if ((access & Opcodes.ACC_STATIC) == 0) {
177 if ("<init>".equals(name)) {
178 locals.add(Opcodes.UNINITIALIZED_THIS);
179 } else {
180 locals.add(owner);
181 }
263 }
264 for (int i = 0; i < labels.size(); ++i) {
265 uninitializedTypes.put(labels.get(i), type);
266 }
267 }
268 super.visitTypeInsn(opcode, type);
269 execute(opcode, 0, type);
270 }
271
272 @Override
273 public void visitFieldInsn(
274 final int opcode, final String owner, final String name, final String desc) {
275 super.visitFieldInsn(opcode, owner, name, desc);
276 execute(opcode, 0, desc);
277 }
278
279 @Deprecated
280 @Override
281 public void visitMethodInsn(
282 final int opcode, final String owner, final String name, final String desc) {
283 if (api >= Opcodes.ASM5) {
284 super.visitMethodInsn(opcode, owner, name, desc);
285 return;
286 }
287 doVisitMethodInsn(opcode, owner, name, desc, opcode == Opcodes.INVOKEINTERFACE);
288 }
289
290 @Override
291 public void visitMethodInsn(
292 final int opcode,
293 final String owner,
294 final String name,
295 final String desc,
296 final boolean itf) {
297 if (api < Opcodes.ASM5) {
298 super.visitMethodInsn(opcode, owner, name, desc, itf);
299 return;
300 }
301 doVisitMethodInsn(opcode, owner, name, desc, itf);
302 }
303
304 private void doVisitMethodInsn(
305 int opcode, final String owner, final String name, final String desc, final boolean itf) {
306 if (mv != null) {
307 mv.visitMethodInsn(opcode, owner, name, desc, itf);
308 }
309 if (this.locals == null) {
310 labels = null;
311 return;
312 }
313 pop(desc);
314 if (opcode != Opcodes.INVOKESTATIC) {
315 Object t = pop();
316 if (opcode == Opcodes.INVOKESPECIAL && name.charAt(0) == '<') {
317 Object u;
318 if (t == Opcodes.UNINITIALIZED_THIS) {
319 u = this.owner;
320 } else {
321 u = uninitializedTypes.get(t);
182322 }
183 Type[] types = Type.getArgumentTypes(desc);
184 for (int i = 0; i < types.length; ++i) {
185 Type type = types[i];
186 switch (type.getSort()) {
187 case Type.BOOLEAN:
188 case Type.CHAR:
189 case Type.BYTE:
190 case Type.SHORT:
191 case Type.INT:
192 locals.add(Opcodes.INTEGER);
193 break;
194 case Type.FLOAT:
195 locals.add(Opcodes.FLOAT);
196 break;
197 case Type.LONG:
198 locals.add(Opcodes.LONG);
199 locals.add(Opcodes.TOP);
200 break;
201 case Type.DOUBLE:
202 locals.add(Opcodes.DOUBLE);
203 locals.add(Opcodes.TOP);
204 break;
205 case Type.ARRAY:
206 locals.add(types[i].getDescriptor());
207 break;
208 // case Type.OBJECT:
209 default:
210 locals.add(types[i].getInternalName());
211 }
323 for (int i = 0; i < locals.size(); ++i) {
324 if (locals.get(i) == t) {
325 locals.set(i, u);
326 }
212327 }
213 maxLocals = locals.size();
214 }
215
216 @Override
217 public void visitFrame(final int type, final int nLocal,
218 final Object[] local, final int nStack, final Object[] stack) {
219 if (type != Opcodes.F_NEW) { // uncompressed frame
220 throw new IllegalStateException(
221 "ClassReader.accept() should be called with EXPAND_FRAMES flag");
328 for (int i = 0; i < stack.size(); ++i) {
329 if (stack.get(i) == t) {
330 stack.set(i, u);
331 }
222332 }
223
224 if (mv != null) {
225 mv.visitFrame(type, nLocal, local, nStack, stack);
333 }
334 }
335 pushDesc(desc);
336 labels = null;
337 }
338
339 @Override
340 public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) {
341 super.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
342 if (this.locals == null) {
343 labels = null;
344 return;
345 }
346 pop(desc);
347 pushDesc(desc);
348 labels = null;
349 }
350
351 @Override
352 public void visitJumpInsn(final int opcode, final Label label) {
353 super.visitJumpInsn(opcode, label);
354 execute(opcode, 0, null);
355 if (opcode == Opcodes.GOTO) {
356 this.locals = null;
357 this.stack = null;
358 }
359 }
360
361 @Override
362 public void visitLabel(final Label label) {
363 super.visitLabel(label);
364 if (labels == null) {
365 labels = new ArrayList<Label>(3);
366 }
367 labels.add(label);
368 }
369
370 @Override
371 public void visitLdcInsn(final Object cst) {
372 super.visitLdcInsn(cst);
373 if (this.locals == null) {
374 labels = null;
375 return;
376 }
377 if (cst instanceof Integer) {
378 push(Opcodes.INTEGER);
379 } else if (cst instanceof Long) {
380 push(Opcodes.LONG);
381 push(Opcodes.TOP);
382 } else if (cst instanceof Float) {
383 push(Opcodes.FLOAT);
384 } else if (cst instanceof Double) {
385 push(Opcodes.DOUBLE);
386 push(Opcodes.TOP);
387 } else if (cst instanceof String) {
388 push("java/lang/String");
389 } else if (cst instanceof Type) {
390 int sort = ((Type) cst).getSort();
391 if (sort == Type.OBJECT || sort == Type.ARRAY) {
392 push("java/lang/Class");
393 } else if (sort == Type.METHOD) {
394 push("java/lang/invoke/MethodType");
395 } else {
396 throw new IllegalArgumentException();
397 }
398 } else if (cst instanceof Handle) {
399 push("java/lang/invoke/MethodHandle");
400 } else {
401 throw new IllegalArgumentException();
402 }
403 labels = null;
404 }
405
406 @Override
407 public void visitIincInsn(final int var, final int increment) {
408 super.visitIincInsn(var, increment);
409 maxLocals = Math.max(maxLocals, var + 1);
410 execute(Opcodes.IINC, var, null);
411 }
412
413 @Override
414 public void visitTableSwitchInsn(
415 final int min, final int max, final Label dflt, final Label... labels) {
416 super.visitTableSwitchInsn(min, max, dflt, labels);
417 execute(Opcodes.TABLESWITCH, 0, null);
418 this.locals = null;
419 this.stack = null;
420 }
421
422 @Override
423 public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) {
424 super.visitLookupSwitchInsn(dflt, keys, labels);
425 execute(Opcodes.LOOKUPSWITCH, 0, null);
426 this.locals = null;
427 this.stack = null;
428 }
429
430 @Override
431 public void visitMultiANewArrayInsn(final String desc, final int dims) {
432 super.visitMultiANewArrayInsn(desc, dims);
433 execute(Opcodes.MULTIANEWARRAY, dims, desc);
434 }
435
436 @Override
437 public void visitLocalVariable(
438 String name, String descriptor, String signature, Label start, Label end, int index) {
439 char firstDescChar = descriptor.charAt(0);
440 maxLocals = Math.max(maxLocals, index + (firstDescChar == 'J' || firstDescChar == 'D' ? 2 : 1));
441 super.visitLocalVariable(name, descriptor, signature, start, end, index);
442 }
443
444 @Override
445 public void visitMaxs(final int maxStack, final int maxLocals) {
446 if (mv != null) {
447 this.maxStack = Math.max(this.maxStack, maxStack);
448 this.maxLocals = Math.max(this.maxLocals, maxLocals);
449 mv.visitMaxs(this.maxStack, this.maxLocals);
450 }
451 }
452
453 // ------------------------------------------------------------------------
454
455 private Object get(final int local) {
456 maxLocals = Math.max(maxLocals, local + 1);
457 return local < locals.size() ? locals.get(local) : Opcodes.TOP;
458 }
459
460 private void set(final int local, final Object type) {
461 maxLocals = Math.max(maxLocals, local + 1);
462 while (local >= locals.size()) {
463 locals.add(Opcodes.TOP);
464 }
465 locals.set(local, type);
466 }
467
468 private void push(final Object type) {
469 stack.add(type);
470 maxStack = Math.max(maxStack, stack.size());
471 }
472
473 private void pushDesc(final String desc) {
474 int index = desc.charAt(0) == '(' ? desc.indexOf(')') + 1 : 0;
475 switch (desc.charAt(index)) {
476 case 'V':
477 return;
478 case 'Z':
479 case 'C':
480 case 'B':
481 case 'S':
482 case 'I':
483 push(Opcodes.INTEGER);
484 return;
485 case 'F':
486 push(Opcodes.FLOAT);
487 return;
488 case 'J':
489 push(Opcodes.LONG);
490 push(Opcodes.TOP);
491 return;
492 case 'D':
493 push(Opcodes.DOUBLE);
494 push(Opcodes.TOP);
495 return;
496 case '[':
497 if (index == 0) {
498 push(desc);
499 } else {
500 push(desc.substring(index, desc.length()));
226501 }
227
228 if (this.locals != null) {
229 this.locals.clear();
230 this.stack.clear();
502 break;
503 // case 'L':
504 default:
505 if (index == 0) {
506 push(desc.substring(1, desc.length() - 1));
231507 } else {
232 this.locals = new ArrayList<Object>();
233 this.stack = new ArrayList<Object>();
508 push(desc.substring(index + 1, desc.length() - 1));
234509 }
235 visitFrameTypes(nLocal, local, this.locals);
236 visitFrameTypes(nStack, stack, this.stack);
237 maxStack = Math.max(maxStack, this.stack.size());
238 }
239
240 private static void visitFrameTypes(final int n, final Object[] types,
241 final List<Object> result) {
242 for (int i = 0; i < n; ++i) {
243 Object type = types[i];
244 result.add(type);
245 if (type == Opcodes.LONG || type == Opcodes.DOUBLE) {
246 result.add(Opcodes.TOP);
247 }
510 }
511 }
512
513 private Object pop() {
514 return stack.remove(stack.size() - 1);
515 }
516
517 private void pop(final int n) {
518 int size = stack.size();
519 int end = size - n;
520 for (int i = size - 1; i >= end; --i) {
521 stack.remove(i);
522 }
523 }
524
525 private void pop(final String desc) {
526 char c = desc.charAt(0);
527 if (c == '(') {
528 int n = 0;
529 Type[] types = Type.getArgumentTypes(desc);
530 for (int i = 0; i < types.length; ++i) {
531 n += types[i].getSize();
532 }
533 pop(n);
534 } else if (c == 'J' || c == 'D') {
535 pop(2);
536 } else {
537 pop(1);
538 }
539 }
540
541 private void execute(final int opcode, final int iarg, final String sarg) {
542 if (this.locals == null) {
543 labels = null;
544 return;
545 }
546 Object t1, t2, t3, t4;
547 switch (opcode) {
548 case Opcodes.NOP:
549 case Opcodes.INEG:
550 case Opcodes.LNEG:
551 case Opcodes.FNEG:
552 case Opcodes.DNEG:
553 case Opcodes.I2B:
554 case Opcodes.I2C:
555 case Opcodes.I2S:
556 case Opcodes.GOTO:
557 case Opcodes.RETURN:
558 break;
559 case Opcodes.ACONST_NULL:
560 push(Opcodes.NULL);
561 break;
562 case Opcodes.ICONST_M1:
563 case Opcodes.ICONST_0:
564 case Opcodes.ICONST_1:
565 case Opcodes.ICONST_2:
566 case Opcodes.ICONST_3:
567 case Opcodes.ICONST_4:
568 case Opcodes.ICONST_5:
569 case Opcodes.BIPUSH:
570 case Opcodes.SIPUSH:
571 push(Opcodes.INTEGER);
572 break;
573 case Opcodes.LCONST_0:
574 case Opcodes.LCONST_1:
575 push(Opcodes.LONG);
576 push(Opcodes.TOP);
577 break;
578 case Opcodes.FCONST_0:
579 case Opcodes.FCONST_1:
580 case Opcodes.FCONST_2:
581 push(Opcodes.FLOAT);
582 break;
583 case Opcodes.DCONST_0:
584 case Opcodes.DCONST_1:
585 push(Opcodes.DOUBLE);
586 push(Opcodes.TOP);
587 break;
588 case Opcodes.ILOAD:
589 case Opcodes.FLOAD:
590 case Opcodes.ALOAD:
591 push(get(iarg));
592 break;
593 case Opcodes.LLOAD:
594 case Opcodes.DLOAD:
595 push(get(iarg));
596 push(Opcodes.TOP);
597 break;
598 case Opcodes.IALOAD:
599 case Opcodes.BALOAD:
600 case Opcodes.CALOAD:
601 case Opcodes.SALOAD:
602 pop(2);
603 push(Opcodes.INTEGER);
604 break;
605 case Opcodes.LALOAD:
606 case Opcodes.D2L:
607 pop(2);
608 push(Opcodes.LONG);
609 push(Opcodes.TOP);
610 break;
611 case Opcodes.FALOAD:
612 pop(2);
613 push(Opcodes.FLOAT);
614 break;
615 case Opcodes.DALOAD:
616 case Opcodes.L2D:
617 pop(2);
618 push(Opcodes.DOUBLE);
619 push(Opcodes.TOP);
620 break;
621 case Opcodes.AALOAD:
622 pop(1);
623 t1 = pop();
624 if (t1 instanceof String) {
625 pushDesc(((String) t1).substring(1));
626 } else if (t1 == Opcodes.NULL) {
627 push(t1);
628 } else {
629 push("java/lang/Object");
248630 }
249 }
250
251 @Override
252 public void visitInsn(final int opcode) {
253 if (mv != null) {
254 mv.visitInsn(opcode);
631 break;
632 case Opcodes.ISTORE:
633 case Opcodes.FSTORE:
634 case Opcodes.ASTORE:
635 t1 = pop();
636 set(iarg, t1);
637 if (iarg > 0) {
638 t2 = get(iarg - 1);
639 if (t2 == Opcodes.LONG || t2 == Opcodes.DOUBLE) {
640 set(iarg - 1, Opcodes.TOP);
641 }
255642 }
256 execute(opcode, 0, null);
257 if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN)
258 || opcode == Opcodes.ATHROW) {
259 this.locals = null;
260 this.stack = null;
643 break;
644 case Opcodes.LSTORE:
645 case Opcodes.DSTORE:
646 pop(1);
647 t1 = pop();
648 set(iarg, t1);
649 set(iarg + 1, Opcodes.TOP);
650 if (iarg > 0) {
651 t2 = get(iarg - 1);
652 if (t2 == Opcodes.LONG || t2 == Opcodes.DOUBLE) {
653 set(iarg - 1, Opcodes.TOP);
654 }
261655 }
262 }
263
264 @Override
265 public void visitIntInsn(final int opcode, final int operand) {
266 if (mv != null) {
267 mv.visitIntInsn(opcode, operand);
268 }
269 execute(opcode, operand, null);
270 }
271
272 @Override
273 public void visitVarInsn(final int opcode, final int var) {
274 if (mv != null) {
275 mv.visitVarInsn(opcode, var);
276 }
277 execute(opcode, var, null);
278 }
279
280 @Override
281 public void visitTypeInsn(final int opcode, final String type) {
282 if (opcode == Opcodes.NEW) {
283 if (labels == null) {
284 Label l = new Label();
285 labels = new ArrayList<Label>(3);
286 labels.add(l);
287 if (mv != null) {
288 mv.visitLabel(l);
289 }
290 }
291 for (int i = 0; i < labels.size(); ++i) {
292 uninitializedTypes.put(labels.get(i), type);
293 }
294 }
295 if (mv != null) {
296 mv.visitTypeInsn(opcode, type);
297 }
298 execute(opcode, 0, type);
299 }
300
301 @Override
302 public void visitFieldInsn(final int opcode, final String owner,
303 final String name, final String desc) {
304 if (mv != null) {
305 mv.visitFieldInsn(opcode, owner, name, desc);
306 }
307 execute(opcode, 0, desc);
308 }
309
310 @Deprecated
311 @Override
312 public void visitMethodInsn(final int opcode, final String owner,
313 final String name, final String desc) {
314 if (api >= Opcodes.ASM5) {
315 super.visitMethodInsn(opcode, owner, name, desc);
316 return;
317 }
318 doVisitMethodInsn(opcode, owner, name, desc,
319 opcode == Opcodes.INVOKEINTERFACE);
320 }
321
322 @Override
323 public void visitMethodInsn(final int opcode, final String owner,
324 final String name, final String desc, final boolean itf) {
325 if (api < Opcodes.ASM5) {
326 super.visitMethodInsn(opcode, owner, name, desc, itf);
327 return;
328 }
329 doVisitMethodInsn(opcode, owner, name, desc, itf);
330 }
331
332 private void doVisitMethodInsn(int opcode, final String owner,
333 final String name, final String desc, final boolean itf) {
334 if (mv != null) {
335 mv.visitMethodInsn(opcode, owner, name, desc, itf);
336 }
337 if (this.locals == null) {
338 labels = null;
339 return;
340 }
341 pop(desc);
342 if (opcode != Opcodes.INVOKESTATIC) {
343 Object t = pop();
344 if (opcode == Opcodes.INVOKESPECIAL && name.charAt(0) == '<') {
345 Object u;
346 if (t == Opcodes.UNINITIALIZED_THIS) {
347 u = this.owner;
348 } else {
349 u = uninitializedTypes.get(t);
350 }
351 for (int i = 0; i < locals.size(); ++i) {
352 if (locals.get(i) == t) {
353 locals.set(i, u);
354 }
355 }
356 for (int i = 0; i < stack.size(); ++i) {
357 if (stack.get(i) == t) {
358 stack.set(i, u);
359 }
360 }
361 }
362 }
363 pushDesc(desc);
364 labels = null;
365 }
366
367 @Override
368 public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
369 Object... bsmArgs) {
370 if (mv != null) {
371 mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
372 }
373 if (this.locals == null) {
374 labels = null;
375 return;
376 }
377 pop(desc);
378 pushDesc(desc);
379 labels = null;
380 }
381
382 @Override
383 public void visitJumpInsn(final int opcode, final Label label) {
384 if (mv != null) {
385 mv.visitJumpInsn(opcode, label);
386 }
387 execute(opcode, 0, null);
388 if (opcode == Opcodes.GOTO) {
389 this.locals = null;
390 this.stack = null;
391 }
392 }
393
394 @Override
395 public void visitLabel(final Label label) {
396 if (mv != null) {
397 mv.visitLabel(label);
398 }
399 if (labels == null) {
400 labels = new ArrayList<Label>(3);
401 }
402 labels.add(label);
403 }
404
405 @Override
406 public void visitLdcInsn(final Object cst) {
407 if (mv != null) {
408 mv.visitLdcInsn(cst);
409 }
410 if (this.locals == null) {
411 labels = null;
412 return;
413 }
414 if (cst instanceof Integer) {
415 push(Opcodes.INTEGER);
416 } else if (cst instanceof Long) {
417 push(Opcodes.LONG);
418 push(Opcodes.TOP);
419 } else if (cst instanceof Float) {
420 push(Opcodes.FLOAT);
421 } else if (cst instanceof Double) {
422 push(Opcodes.DOUBLE);
423 push(Opcodes.TOP);
424 } else if (cst instanceof String) {
425 push("java/lang/String");
426 } else if (cst instanceof Type) {
427 int sort = ((Type) cst).getSort();
428 if (sort == Type.OBJECT || sort == Type.ARRAY) {
429 push("java/lang/Class");
430 } else if (sort == Type.METHOD) {
431 push("java/lang/invoke/MethodType");
432 } else {
433 throw new IllegalArgumentException();
434 }
435 } else if (cst instanceof Handle) {
436 push("java/lang/invoke/MethodHandle");
437 } else {
438 throw new IllegalArgumentException();
439 }
440 labels = null;
441 }
442
443 @Override
444 public void visitIincInsn(final int var, final int increment) {
445 if (mv != null) {
446 mv.visitIincInsn(var, increment);
447 }
448 execute(Opcodes.IINC, var, null);
449 }
450
451 @Override
452 public void visitTableSwitchInsn(final int min, final int max,
453 final Label dflt, final Label... labels) {
454 if (mv != null) {
455 mv.visitTableSwitchInsn(min, max, dflt, labels);
456 }
457 execute(Opcodes.TABLESWITCH, 0, null);
458 this.locals = null;
459 this.stack = null;
460 }
461
462 @Override
463 public void visitLookupSwitchInsn(final Label dflt, final int[] keys,
464 final Label[] labels) {
465 if (mv != null) {
466 mv.visitLookupSwitchInsn(dflt, keys, labels);
467 }
468 execute(Opcodes.LOOKUPSWITCH, 0, null);
469 this.locals = null;
470 this.stack = null;
471 }
472
473 @Override
474 public void visitMultiANewArrayInsn(final String desc, final int dims) {
475 if (mv != null) {
476 mv.visitMultiANewArrayInsn(desc, dims);
477 }
478 execute(Opcodes.MULTIANEWARRAY, dims, desc);
479 }
480
481 @Override
482 public void visitMaxs(final int maxStack, final int maxLocals) {
483 if (mv != null) {
484 this.maxStack = Math.max(this.maxStack, maxStack);
485 this.maxLocals = Math.max(this.maxLocals, maxLocals);
486 mv.visitMaxs(this.maxStack, this.maxLocals);
487 }
488 }
489
490 // ------------------------------------------------------------------------
491
492 private Object get(final int local) {
493 maxLocals = Math.max(maxLocals, local + 1);
494 return local < locals.size() ? locals.get(local) : Opcodes.TOP;
495 }
496
497 private void set(final int local, final Object type) {
498 maxLocals = Math.max(maxLocals, local + 1);
499 while (local >= locals.size()) {
500 locals.add(Opcodes.TOP);
501 }
502 locals.set(local, type);
503 }
504
505 private void push(final Object type) {
506 stack.add(type);
507 maxStack = Math.max(maxStack, stack.size());
508 }
509
510 private void pushDesc(final String desc) {
511 int index = desc.charAt(0) == '(' ? desc.indexOf(')') + 1 : 0;
512 switch (desc.charAt(index)) {
513 case 'V':
514 return;
515 case 'Z':
516 case 'C':
517 case 'B':
518 case 'S':
519 case 'I':
520 push(Opcodes.INTEGER);
521 return;
522 case 'F':
523 push(Opcodes.FLOAT);
524 return;
525 case 'J':
526 push(Opcodes.LONG);
527 push(Opcodes.TOP);
528 return;
529 case 'D':
530 push(Opcodes.DOUBLE);
531 push(Opcodes.TOP);
532 return;
533 case '[':
534 if (index == 0) {
535 push(desc);
536 } else {
537 push(desc.substring(index, desc.length()));
538 }
656 break;
657 case Opcodes.IASTORE:
658 case Opcodes.BASTORE:
659 case Opcodes.CASTORE:
660 case Opcodes.SASTORE:
661 case Opcodes.FASTORE:
662 case Opcodes.AASTORE:
663 pop(3);
664 break;
665 case Opcodes.LASTORE:
666 case Opcodes.DASTORE:
667 pop(4);
668 break;
669 case Opcodes.POP:
670 case Opcodes.IFEQ:
671 case Opcodes.IFNE:
672 case Opcodes.IFLT:
673 case Opcodes.IFGE:
674 case Opcodes.IFGT:
675 case Opcodes.IFLE:
676 case Opcodes.IRETURN:
677 case Opcodes.FRETURN:
678 case Opcodes.ARETURN:
679 case Opcodes.TABLESWITCH:
680 case Opcodes.LOOKUPSWITCH:
681 case Opcodes.ATHROW:
682 case Opcodes.MONITORENTER:
683 case Opcodes.MONITOREXIT:
684 case Opcodes.IFNULL:
685 case Opcodes.IFNONNULL:
686 pop(1);
687 break;
688 case Opcodes.POP2:
689 case Opcodes.IF_ICMPEQ:
690 case Opcodes.IF_ICMPNE:
691 case Opcodes.IF_ICMPLT:
692 case Opcodes.IF_ICMPGE:
693 case Opcodes.IF_ICMPGT:
694 case Opcodes.IF_ICMPLE:
695 case Opcodes.IF_ACMPEQ:
696 case Opcodes.IF_ACMPNE:
697 case Opcodes.LRETURN:
698 case Opcodes.DRETURN:
699 pop(2);
700 break;
701 case Opcodes.DUP:
702 t1 = pop();
703 push(t1);
704 push(t1);
705 break;
706 case Opcodes.DUP_X1:
707 t1 = pop();
708 t2 = pop();
709 push(t1);
710 push(t2);
711 push(t1);
712 break;
713 case Opcodes.DUP_X2:
714 t1 = pop();
715 t2 = pop();
716 t3 = pop();
717 push(t1);
718 push(t3);
719 push(t2);
720 push(t1);
721 break;
722 case Opcodes.DUP2:
723 t1 = pop();
724 t2 = pop();
725 push(t2);
726 push(t1);
727 push(t2);
728 push(t1);
729 break;
730 case Opcodes.DUP2_X1:
731 t1 = pop();
732 t2 = pop();
733 t3 = pop();
734 push(t2);
735 push(t1);
736 push(t3);
737 push(t2);
738 push(t1);
739 break;
740 case Opcodes.DUP2_X2:
741 t1 = pop();
742 t2 = pop();
743 t3 = pop();
744 t4 = pop();
745 push(t2);
746 push(t1);
747 push(t4);
748 push(t3);
749 push(t2);
750 push(t1);
751 break;
752 case Opcodes.SWAP:
753 t1 = pop();
754 t2 = pop();
755 push(t1);
756 push(t2);
757 break;
758 case Opcodes.IADD:
759 case Opcodes.ISUB:
760 case Opcodes.IMUL:
761 case Opcodes.IDIV:
762 case Opcodes.IREM:
763 case Opcodes.IAND:
764 case Opcodes.IOR:
765 case Opcodes.IXOR:
766 case Opcodes.ISHL:
767 case Opcodes.ISHR:
768 case Opcodes.IUSHR:
769 case Opcodes.L2I:
770 case Opcodes.D2I:
771 case Opcodes.FCMPL:
772 case Opcodes.FCMPG:
773 pop(2);
774 push(Opcodes.INTEGER);
775 break;
776 case Opcodes.LADD:
777 case Opcodes.LSUB:
778 case Opcodes.LMUL:
779 case Opcodes.LDIV:
780 case Opcodes.LREM:
781 case Opcodes.LAND:
782 case Opcodes.LOR:
783 case Opcodes.LXOR:
784 pop(4);
785 push(Opcodes.LONG);
786 push(Opcodes.TOP);
787 break;
788 case Opcodes.FADD:
789 case Opcodes.FSUB:
790 case Opcodes.FMUL:
791 case Opcodes.FDIV:
792 case Opcodes.FREM:
793 case Opcodes.L2F:
794 case Opcodes.D2F:
795 pop(2);
796 push(Opcodes.FLOAT);
797 break;
798 case Opcodes.DADD:
799 case Opcodes.DSUB:
800 case Opcodes.DMUL:
801 case Opcodes.DDIV:
802 case Opcodes.DREM:
803 pop(4);
804 push(Opcodes.DOUBLE);
805 push(Opcodes.TOP);
806 break;
807 case Opcodes.LSHL:
808 case Opcodes.LSHR:
809 case Opcodes.LUSHR:
810 pop(3);
811 push(Opcodes.LONG);
812 push(Opcodes.TOP);
813 break;
814 case Opcodes.IINC:
815 set(iarg, Opcodes.INTEGER);
816 break;
817 case Opcodes.I2L:
818 case Opcodes.F2L:
819 pop(1);
820 push(Opcodes.LONG);
821 push(Opcodes.TOP);
822 break;
823 case Opcodes.I2F:
824 pop(1);
825 push(Opcodes.FLOAT);
826 break;
827 case Opcodes.I2D:
828 case Opcodes.F2D:
829 pop(1);
830 push(Opcodes.DOUBLE);
831 push(Opcodes.TOP);
832 break;
833 case Opcodes.F2I:
834 case Opcodes.ARRAYLENGTH:
835 case Opcodes.INSTANCEOF:
836 pop(1);
837 push(Opcodes.INTEGER);
838 break;
839 case Opcodes.LCMP:
840 case Opcodes.DCMPL:
841 case Opcodes.DCMPG:
842 pop(4);
843 push(Opcodes.INTEGER);
844 break;
845 case Opcodes.JSR:
846 case Opcodes.RET:
847 throw new RuntimeException("JSR/RET are not supported");
848 case Opcodes.GETSTATIC:
849 pushDesc(sarg);
850 break;
851 case Opcodes.PUTSTATIC:
852 pop(sarg);
853 break;
854 case Opcodes.GETFIELD:
855 pop(1);
856 pushDesc(sarg);
857 break;
858 case Opcodes.PUTFIELD:
859 pop(sarg);
860 pop();
861 break;
862 case Opcodes.NEW:
863 push(labels.get(0));
864 break;
865 case Opcodes.NEWARRAY:
866 pop();
867 switch (iarg) {
868 case Opcodes.T_BOOLEAN:
869 pushDesc("[Z");
539870 break;
540 // case 'L':
541 default:
542 if (index == 0) {
543 push(desc.substring(1, desc.length() - 1));
544 } else {
545 push(desc.substring(index + 1, desc.length() - 1));
546 }
547 }
548 }
549
550 private Object pop() {
551 return stack.remove(stack.size() - 1);
552 }
553
554 private void pop(final int n) {
555 int size = stack.size();
556 int end = size - n;
557 for (int i = size - 1; i >= end; --i) {
558 stack.remove(i);
559 }
560 }
561
562 private void pop(final String desc) {
563 char c = desc.charAt(0);
564 if (c == '(') {
565 int n = 0;
566 Type[] types = Type.getArgumentTypes(desc);
567 for (int i = 0; i < types.length; ++i) {
568 n += types[i].getSize();
569 }
570 pop(n);
571 } else if (c == 'J' || c == 'D') {
572 pop(2);
573 } else {
574 pop(1);
575 }
576 }
577
578 private void execute(final int opcode, final int iarg, final String sarg) {
579 if (this.locals == null) {
580 labels = null;
581 return;
582 }
583 Object t1, t2, t3, t4;
584 switch (opcode) {
585 case Opcodes.NOP:
586 case Opcodes.INEG:
587 case Opcodes.LNEG:
588 case Opcodes.FNEG:
589 case Opcodes.DNEG:
590 case Opcodes.I2B:
591 case Opcodes.I2C:
592 case Opcodes.I2S:
593 case Opcodes.GOTO:
594 case Opcodes.RETURN:
871 case Opcodes.T_CHAR:
872 pushDesc("[C");
595873 break;
596 case Opcodes.ACONST_NULL:
597 push(Opcodes.NULL);
874 case Opcodes.T_BYTE:
875 pushDesc("[B");
598876 break;
599 case Opcodes.ICONST_M1:
600 case Opcodes.ICONST_0:
601 case Opcodes.ICONST_1:
602 case Opcodes.ICONST_2:
603 case Opcodes.ICONST_3:
604 case Opcodes.ICONST_4:
605 case Opcodes.ICONST_5:
606 case Opcodes.BIPUSH:
607 case Opcodes.SIPUSH:
608 push(Opcodes.INTEGER);
877 case Opcodes.T_SHORT:
878 pushDesc("[S");
609879 break;
610 case Opcodes.LCONST_0:
611 case Opcodes.LCONST_1:
612 push(Opcodes.LONG);
613 push(Opcodes.TOP);
880 case Opcodes.T_INT:
881 pushDesc("[I");
614882 break;
615 case Opcodes.FCONST_0:
616 case Opcodes.FCONST_1:
617 case Opcodes.FCONST_2:
618 push(Opcodes.FLOAT);
883 case Opcodes.T_FLOAT:
884 pushDesc("[F");
619885 break;
620 case Opcodes.DCONST_0:
621 case Opcodes.DCONST_1:
622 push(Opcodes.DOUBLE);
623 push(Opcodes.TOP);
886 case Opcodes.T_DOUBLE:
887 pushDesc("[D");
624888 break;
625 case Opcodes.ILOAD:
626 case Opcodes.FLOAD:
627 case Opcodes.ALOAD:
628 push(get(iarg));
629 break;
630 case Opcodes.LLOAD:
631 case Opcodes.DLOAD:
632 push(get(iarg));
633 push(Opcodes.TOP);
634 break;
635 case Opcodes.IALOAD:
636 case Opcodes.BALOAD:
637 case Opcodes.CALOAD:
638 case Opcodes.SALOAD:
639 pop(2);
640 push(Opcodes.INTEGER);
641 break;
642 case Opcodes.LALOAD:
643 case Opcodes.D2L:
644 pop(2);
645 push(Opcodes.LONG);
646 push(Opcodes.TOP);
647 break;
648 case Opcodes.FALOAD:
649 pop(2);
650 push(Opcodes.FLOAT);
651 break;
652 case Opcodes.DALOAD:
653 case Opcodes.L2D:
654 pop(2);
655 push(Opcodes.DOUBLE);
656 push(Opcodes.TOP);
657 break;
658 case Opcodes.AALOAD:
659 pop(1);
660 t1 = pop();
661 if (t1 instanceof String) {
662 pushDesc(((String) t1).substring(1));
663 } else {
664 push("java/lang/Object");
665 }
666 break;
667 case Opcodes.ISTORE:
668 case Opcodes.FSTORE:
669 case Opcodes.ASTORE:
670 t1 = pop();
671 set(iarg, t1);
672 if (iarg > 0) {
673 t2 = get(iarg - 1);
674 if (t2 == Opcodes.LONG || t2 == Opcodes.DOUBLE) {
675 set(iarg - 1, Opcodes.TOP);
676 }
677 }
678 break;
679 case Opcodes.LSTORE:
680 case Opcodes.DSTORE:
681 pop(1);
682 t1 = pop();
683 set(iarg, t1);
684 set(iarg + 1, Opcodes.TOP);
685 if (iarg > 0) {
686 t2 = get(iarg - 1);
687 if (t2 == Opcodes.LONG || t2 == Opcodes.DOUBLE) {
688 set(iarg - 1, Opcodes.TOP);
689 }
690 }
691 break;
692 case Opcodes.IASTORE:
693 case Opcodes.BASTORE:
694 case Opcodes.CASTORE:
695 case Opcodes.SASTORE:
696 case Opcodes.FASTORE:
697 case Opcodes.AASTORE:
698 pop(3);
699 break;
700 case Opcodes.LASTORE:
701 case Opcodes.DASTORE:
702 pop(4);
703 break;
704 case Opcodes.POP:
705 case Opcodes.IFEQ:
706 case Opcodes.IFNE:
707 case Opcodes.IFLT:
708 case Opcodes.IFGE:
709 case Opcodes.IFGT:
710 case Opcodes.IFLE:
711 case Opcodes.IRETURN:
712 case Opcodes.FRETURN:
713 case Opcodes.ARETURN:
714 case Opcodes.TABLESWITCH:
715 case Opcodes.LOOKUPSWITCH:
716 case Opcodes.ATHROW:
717 case Opcodes.MONITORENTER:
718 case Opcodes.MONITOREXIT:
719 case Opcodes.IFNULL:
720 case Opcodes.IFNONNULL:
721 pop(1);
722 break;
723 case Opcodes.POP2:
724 case Opcodes.IF_ICMPEQ:
725 case Opcodes.IF_ICMPNE:
726 case Opcodes.IF_ICMPLT:
727 case Opcodes.IF_ICMPGE:
728 case Opcodes.IF_ICMPGT:
729 case Opcodes.IF_ICMPLE:
730 case Opcodes.IF_ACMPEQ:
731 case Opcodes.IF_ACMPNE:
732 case Opcodes.LRETURN:
733 case Opcodes.DRETURN:
734 pop(2);
735 break;
736 case Opcodes.DUP:
737 t1 = pop();
738 push(t1);
739 push(t1);
740 break;
741 case Opcodes.DUP_X1:
742 t1 = pop();
743 t2 = pop();
744 push(t1);
745 push(t2);
746 push(t1);
747 break;
748 case Opcodes.DUP_X2:
749 t1 = pop();
750 t2 = pop();
751 t3 = pop();
752 push(t1);
753 push(t3);
754 push(t2);
755 push(t1);
756 break;
757 case Opcodes.DUP2:
758 t1 = pop();
759 t2 = pop();
760 push(t2);
761 push(t1);
762 push(t2);
763 push(t1);
764 break;
765 case Opcodes.DUP2_X1:
766 t1 = pop();
767 t2 = pop();
768 t3 = pop();
769 push(t2);
770 push(t1);
771 push(t3);
772 push(t2);
773 push(t1);
774 break;
775 case Opcodes.DUP2_X2:
776 t1 = pop();
777 t2 = pop();
778 t3 = pop();
779 t4 = pop();
780 push(t2);
781 push(t1);
782 push(t4);
783 push(t3);
784 push(t2);
785 push(t1);
786 break;
787 case Opcodes.SWAP:
788 t1 = pop();
789 t2 = pop();
790 push(t1);
791 push(t2);
792 break;
793 case Opcodes.IADD:
794 case Opcodes.ISUB:
795 case Opcodes.IMUL:
796 case Opcodes.IDIV:
797 case Opcodes.IREM:
798 case Opcodes.IAND:
799 case Opcodes.IOR:
800 case Opcodes.IXOR:
801 case Opcodes.ISHL:
802 case Opcodes.ISHR:
803 case Opcodes.IUSHR:
804 case Opcodes.L2I:
805 case Opcodes.D2I:
806 case Opcodes.FCMPL:
807 case Opcodes.FCMPG:
808 pop(2);
809 push(Opcodes.INTEGER);
810 break;
811 case Opcodes.LADD:
812 case Opcodes.LSUB:
813 case Opcodes.LMUL:
814 case Opcodes.LDIV:
815 case Opcodes.LREM:
816 case Opcodes.LAND:
817 case Opcodes.LOR:
818 case Opcodes.LXOR:
819 pop(4);
820 push(Opcodes.LONG);
821 push(Opcodes.TOP);
822 break;
823 case Opcodes.FADD:
824 case Opcodes.FSUB:
825 case Opcodes.FMUL:
826 case Opcodes.FDIV:
827 case Opcodes.FREM:
828 case Opcodes.L2F:
829 case Opcodes.D2F:
830 pop(2);
831 push(Opcodes.FLOAT);
832 break;
833 case Opcodes.DADD:
834 case Opcodes.DSUB:
835 case Opcodes.DMUL:
836 case Opcodes.DDIV:
837 case Opcodes.DREM:
838 pop(4);
839 push(Opcodes.DOUBLE);
840 push(Opcodes.TOP);
841 break;
842 case Opcodes.LSHL:
843 case Opcodes.LSHR:
844 case Opcodes.LUSHR:
845 pop(3);
846 push(Opcodes.LONG);
847 push(Opcodes.TOP);
848 break;
849 case Opcodes.IINC:
850 set(iarg, Opcodes.INTEGER);
851 break;
852 case Opcodes.I2L:
853 case Opcodes.F2L:
854 pop(1);
855 push(Opcodes.LONG);
856 push(Opcodes.TOP);
857 break;
858 case Opcodes.I2F:
859 pop(1);
860 push(Opcodes.FLOAT);
861 break;
862 case Opcodes.I2D:
863 case Opcodes.F2D:
864 pop(1);
865 push(Opcodes.DOUBLE);
866 push(Opcodes.TOP);
867 break;
868 case Opcodes.F2I:
869 case Opcodes.ARRAYLENGTH:
870 case Opcodes.INSTANCEOF:
871 pop(1);
872 push(Opcodes.INTEGER);
873 break;
874 case Opcodes.LCMP:
875 case Opcodes.DCMPL:
876 case Opcodes.DCMPG:
877 pop(4);
878 push(Opcodes.INTEGER);
879 break;
880 case Opcodes.JSR:
881 case Opcodes.RET:
882 throw new RuntimeException("JSR/RET are not supported");
883 case Opcodes.GETSTATIC:
884 pushDesc(sarg);
885 break;
886 case Opcodes.PUTSTATIC:
887 pop(sarg);
888 break;
889 case Opcodes.GETFIELD:
890 pop(1);
891 pushDesc(sarg);
892 break;
893 case Opcodes.PUTFIELD:
894 pop(sarg);
895 pop();
896 break;
897 case Opcodes.NEW:
898 push(labels.get(0));
899 break;
900 case Opcodes.NEWARRAY:
901 pop();
902 switch (iarg) {
903 case Opcodes.T_BOOLEAN:
904 pushDesc("[Z");
905 break;
906 case Opcodes.T_CHAR:
907 pushDesc("[C");
908 break;
909 case Opcodes.T_BYTE:
910 pushDesc("[B");
911 break;
912 case Opcodes.T_SHORT:
913 pushDesc("[S");
914 break;
915 case Opcodes.T_INT:
916 pushDesc("[I");
917 break;
918 case Opcodes.T_FLOAT:
919 pushDesc("[F");
920 break;
921 case Opcodes.T_DOUBLE:
922 pushDesc("[D");
923 break;
924889 // case Opcodes.T_LONG:
925 default:
926 pushDesc("[J");
927 break;
928 }
929 break;
930 case Opcodes.ANEWARRAY:
931 pop();
932 pushDesc("[" + Type.getObjectType(sarg));
933 break;
934 case Opcodes.CHECKCAST:
935 pop();
936 pushDesc(Type.getObjectType(sarg).getDescriptor());
937 break;
938 // case Opcodes.MULTIANEWARRAY:
939 default:
940 pop(iarg);
941 pushDesc(sarg);
890 default:
891 pushDesc("[J");
942892 break;
943893 }
944 labels = null;
945 }
894 break;
895 case Opcodes.ANEWARRAY:
896 pop();
897 pushDesc("[" + Type.getObjectType(sarg));
898 break;
899 case Opcodes.CHECKCAST:
900 pop();
901 pushDesc(Type.getObjectType(sarg).getDescriptor());
902 break;
903 // case Opcodes.MULTIANEWARRAY:
904 default:
905 pop(iarg);
906 pushDesc(sarg);
907 break;
908 }
909 labels = null;
910 }
946911 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927
3028 package org.eclipse.persistence.internal.libraries.asm.commons;
3129
3432
3533 /**
3634 * An {@link AnnotationVisitor} adapter for type remapping.
37 *
35 *
3836 * @author Eugene Kuleshov
3937 */
4038 public class AnnotationRemapper extends AnnotationVisitor {
4139
42 protected final Remapper remapper;
40 protected final Remapper remapper;
4341
44 public AnnotationRemapper(final AnnotationVisitor av,
45 final Remapper remapper) {
46 this(Opcodes.ASM6, av, remapper);
47 }
42 public AnnotationRemapper(final AnnotationVisitor av, final Remapper remapper) {
43 this(Opcodes.ASM6, av, remapper);
44 }
4845
49 protected AnnotationRemapper(final int api, final AnnotationVisitor av,
50 final Remapper remapper) {
51 super(api, av);
52 this.remapper = remapper;
53 }
46 protected AnnotationRemapper(final int api, final AnnotationVisitor av, final Remapper remapper) {
47 super(api, av);
48 this.remapper = remapper;
49 }
5450
55 @Override
56 public void visit(String name, Object value) {
57 av.visit(name, remapper.mapValue(value));
58 }
51 @Override
52 public void visit(String name, Object value) {
53 av.visit(name, remapper.mapValue(value));
54 }
5955
60 @Override
61 public void visitEnum(String name, String desc, String value) {
62 av.visitEnum(name, remapper.mapDesc(desc), value);
63 }
56 @Override
57 public void visitEnum(String name, String desc, String value) {
58 av.visitEnum(name, remapper.mapDesc(desc), value);
59 }
6460
65 @Override
66 public AnnotationVisitor visitAnnotation(String name, String desc) {
67 AnnotationVisitor v = av.visitAnnotation(name, remapper.mapDesc(desc));
68 return v == null ? null : (v == av ? this : new AnnotationRemapper(v,
69 remapper));
70 }
61 @Override
62 public AnnotationVisitor visitAnnotation(String name, String desc) {
63 AnnotationVisitor v = av.visitAnnotation(name, remapper.mapDesc(desc));
64 return v == null ? null : (v == av ? this : new AnnotationRemapper(api, v, remapper));
65 }
7166
72 @Override
73 public AnnotationVisitor visitArray(String name) {
74 AnnotationVisitor v = av.visitArray(name);
75 return v == null ? null : (v == av ? this : new AnnotationRemapper(v,
76 remapper));
77 }
67 @Override
68 public AnnotationVisitor visitArray(String name) {
69 AnnotationVisitor v = av.visitArray(name);
70 return v == null ? null : (v == av ? this : new AnnotationRemapper(api, v, remapper));
71 }
7872 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927
3028 package org.eclipse.persistence.internal.libraries.asm.commons;
3129
30 import java.util.List;
31
3232 import org.eclipse.persistence.internal.libraries.asm.AnnotationVisitor;
33 import org.eclipse.persistence.internal.libraries.asm.Attribute;
3334 import org.eclipse.persistence.internal.libraries.asm.ClassVisitor;
3435 import org.eclipse.persistence.internal.libraries.asm.FieldVisitor;
3536 import org.eclipse.persistence.internal.libraries.asm.MethodVisitor;
3940
4041 /**
4142 * A {@link ClassVisitor} for type remapping.
42 *
43 *
4344 * @author Eugene Kuleshov
4445 */
4546 public class ClassRemapper extends ClassVisitor {
4647
47 protected final Remapper remapper;
48 protected final Remapper remapper;
4849
49 protected String className;
50 protected String className;
5051
51 public ClassRemapper(final ClassVisitor cv, final Remapper remapper) {
52 this(Opcodes.ASM6, cv, remapper);
52 public ClassRemapper(final ClassVisitor cv, final Remapper remapper) {
53 this(Opcodes.ASM6, cv, remapper);
54 }
55
56 protected ClassRemapper(final int api, final ClassVisitor cv, final Remapper remapper) {
57 super(api, cv);
58 this.remapper = remapper;
59 }
60
61 @Override
62 public void visit(
63 int version,
64 int access,
65 String name,
66 String signature,
67 String superName,
68 String[] interfaces) {
69 this.className = name;
70 super.visit(
71 version,
72 access,
73 remapper.mapType(name),
74 remapper.mapSignature(signature, false),
75 remapper.mapType(superName),
76 interfaces == null ? null : remapper.mapTypes(interfaces));
77 }
78
79 @Override
80 public ModuleVisitor visitModule(String name, int flags, String version) {
81 ModuleVisitor mv = super.visitModule(remapper.mapModuleName(name), flags, version);
82 return mv == null ? null : createModuleRemapper(mv);
83 }
84
85 @Override
86 public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
87 AnnotationVisitor av = super.visitAnnotation(remapper.mapDesc(desc), visible);
88 return av == null ? null : createAnnotationRemapper(av);
89 }
90
91 @Override
92 public AnnotationVisitor visitTypeAnnotation(
93 int typeRef, TypePath typePath, String desc, boolean visible) {
94 AnnotationVisitor av =
95 super.visitTypeAnnotation(typeRef, typePath, remapper.mapDesc(desc), visible);
96 return av == null ? null : createAnnotationRemapper(av);
97 }
98
99 @Override
100 public void visitAttribute(Attribute attr) {
101 if (attr instanceof ModuleHashesAttribute) {
102 ModuleHashesAttribute hashesAttr = new ModuleHashesAttribute();
103 List<String> modules = hashesAttr.modules;
104 for (int i = 0; i < modules.size(); i++) {
105 modules.set(i, remapper.mapModuleName(modules.get(i)));
106 }
53107 }
108 super.visitAttribute(attr);
109 }
54110
55 protected ClassRemapper(final int api, final ClassVisitor cv,
56 final Remapper remapper) {
57 super(api, cv);
58 this.remapper = remapper;
59 }
111 @Override
112 public FieldVisitor visitField(
113 int access, String name, String desc, String signature, Object value) {
114 FieldVisitor fv =
115 super.visitField(
116 access,
117 remapper.mapFieldName(className, name, desc),
118 remapper.mapDesc(desc),
119 remapper.mapSignature(signature, true),
120 remapper.mapValue(value));
121 return fv == null ? null : createFieldRemapper(fv);
122 }
60123
61 @Override
62 public void visit(int version, int access, String name, String signature,
63 String superName, String[] interfaces) {
64 this.className = name;
65 super.visit(version, access, remapper.mapType(name), remapper
66 .mapSignature(signature, false), remapper.mapType(superName),
67 interfaces == null ? null : remapper.mapTypes(interfaces));
68 }
124 @Override
125 public MethodVisitor visitMethod(
126 int access, String name, String desc, String signature, String[] exceptions) {
127 String newDesc = remapper.mapMethodDesc(desc);
128 MethodVisitor mv =
129 super.visitMethod(
130 access,
131 remapper.mapMethodName(className, name, desc),
132 newDesc,
133 remapper.mapSignature(signature, false),
134 exceptions == null ? null : remapper.mapTypes(exceptions));
135 return mv == null ? null : createMethodRemapper(mv);
136 }
69137
70 @Override
71 public ModuleVisitor visitModule() {
72 ModuleVisitor mv = super.visitModule();
73 return mv == null ? null: createModuleRemapper(mv);
74 }
75
76 @Override
77 public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
78 AnnotationVisitor av = super.visitAnnotation(remapper.mapDesc(desc),
79 visible);
80 return av == null ? null : createAnnotationRemapper(av);
81 }
138 @Override
139 public void visitInnerClass(String name, String outerName, String innerName, int access) {
140 // TODO should innerName be changed?
141 super.visitInnerClass(
142 remapper.mapType(name),
143 outerName == null ? null : remapper.mapType(outerName),
144 innerName,
145 access);
146 }
82147
83 @Override
84 public AnnotationVisitor visitTypeAnnotation(int typeRef,
85 TypePath typePath, String desc, boolean visible) {
86 AnnotationVisitor av = super.visitTypeAnnotation(typeRef, typePath,
87 remapper.mapDesc(desc), visible);
88 return av == null ? null : createAnnotationRemapper(av);
89 }
148 @Override
149 public void visitOuterClass(String owner, String name, String desc) {
150 super.visitOuterClass(
151 remapper.mapType(owner),
152 name == null ? null : remapper.mapMethodName(owner, name, desc),
153 desc == null ? null : remapper.mapMethodDesc(desc));
154 }
90155
91 @Override
92 public FieldVisitor visitField(int access, String name, String desc,
93 String signature, Object value) {
94 FieldVisitor fv = super.visitField(access,
95 remapper.mapFieldName(className, name, desc),
96 remapper.mapDesc(desc), remapper.mapSignature(signature, true),
97 remapper.mapValue(value));
98 return fv == null ? null : createFieldRemapper(fv);
99 }
156 protected FieldVisitor createFieldRemapper(FieldVisitor fv) {
157 return new FieldRemapper(api, fv, remapper);
158 }
100159
101 @Override
102 public MethodVisitor visitMethod(int access, String name, String desc,
103 String signature, String[] exceptions) {
104 String newDesc = remapper.mapMethodDesc(desc);
105 MethodVisitor mv = super.visitMethod(access, remapper.mapMethodName(
106 className, name, desc), newDesc, remapper.mapSignature(
107 signature, false),
108 exceptions == null ? null : remapper.mapTypes(exceptions));
109 return mv == null ? null : createMethodRemapper(mv);
110 }
160 protected MethodVisitor createMethodRemapper(MethodVisitor mv) {
161 return new MethodRemapper(api, mv, remapper);
162 }
111163
112 @Override
113 public void visitInnerClass(String name, String outerName,
114 String innerName, int access) {
115 // TODO should innerName be changed?
116 super.visitInnerClass(remapper.mapType(name), outerName == null ? null
117 : remapper.mapType(outerName), innerName, access);
118 }
164 protected AnnotationVisitor createAnnotationRemapper(AnnotationVisitor av) {
165 return new AnnotationRemapper(api, av, remapper);
166 }
119167
120 @Override
121 public void visitOuterClass(String owner, String name, String desc) {
122 super.visitOuterClass(remapper.mapType(owner), name == null ? null
123 : remapper.mapMethodName(owner, name, desc),
124 desc == null ? null : remapper.mapMethodDesc(desc));
125 }
126
127 protected FieldVisitor createFieldRemapper(FieldVisitor fv) {
128 return new FieldRemapper(fv, remapper);
129 }
130
131 protected MethodVisitor createMethodRemapper(MethodVisitor mv) {
132 return new MethodRemapper(mv, remapper);
133 }
134
135 protected AnnotationVisitor createAnnotationRemapper(AnnotationVisitor av) {
136 return new AnnotationRemapper(av, remapper);
137 }
138
139 protected ModuleVisitor createModuleRemapper(ModuleVisitor mv) {
140 return new ModuleRemapper(mv, remapper);
141 }
168 protected ModuleVisitor createModuleRemapper(ModuleVisitor mv) {
169 return new ModuleRemapper(api, mv, remapper);
170 }
142171 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.commons;
3028
3129 import org.eclipse.persistence.internal.libraries.asm.Handle;
3533
3634 /**
3735 * A {@link MethodVisitor} that can be used to approximate method size.
38 *
36 *
3937 * @author Eugene Kuleshov
4038 */
4139 public class CodeSizeEvaluator extends MethodVisitor implements Opcodes {
4240
43 private int minSize;
44
45 private int maxSize;
46
47 public CodeSizeEvaluator(final MethodVisitor mv) {
48 this(Opcodes.ASM6, mv);
49 }
50
51 protected CodeSizeEvaluator(final int api, final MethodVisitor mv) {
52 super(api, mv);
53 }
54
55 public int getMinSize() {
56 return this.minSize;
57 }
58
59 public int getMaxSize() {
60 return this.maxSize;
61 }
62
63 @Override
64 public void visitInsn(final int opcode) {
65 minSize += 1;
66 maxSize += 1;
67 if (mv != null) {
68 mv.visitInsn(opcode);
69 }
70 }
71
72 @Override
73 public void visitIntInsn(final int opcode, final int operand) {
74 if (opcode == SIPUSH) {
75 minSize += 3;
76 maxSize += 3;
77 } else {
78 minSize += 2;
79 maxSize += 2;
80 }
81 if (mv != null) {
82 mv.visitIntInsn(opcode, operand);
83 }
84 }
85
86 @Override
87 public void visitVarInsn(final int opcode, final int var) {
88 if (var < 4 && opcode != RET) {
89 minSize += 1;
90 maxSize += 1;
91 } else if (var >= 256) {
92 minSize += 4;
93 maxSize += 4;
94 } else {
95 minSize += 2;
96 maxSize += 2;
97 }
98 if (mv != null) {
99 mv.visitVarInsn(opcode, var);
100 }
101 }
102
103 @Override
104 public void visitTypeInsn(final int opcode, final String type) {
105 minSize += 3;
106 maxSize += 3;
107 if (mv != null) {
108 mv.visitTypeInsn(opcode, type);
109 }
110 }
111
112 @Override
113 public void visitFieldInsn(final int opcode, final String owner,
114 final String name, final String desc) {
115 minSize += 3;
116 maxSize += 3;
117 if (mv != null) {
118 mv.visitFieldInsn(opcode, owner, name, desc);
119 }
120 }
121
122 @Deprecated
123 @Override
124 public void visitMethodInsn(final int opcode, final String owner,
125 final String name, final String desc) {
126 if (api >= Opcodes.ASM5) {
127 super.visitMethodInsn(opcode, owner, name, desc);
128 return;
129 }
130 doVisitMethodInsn(opcode, owner, name, desc,
131 opcode == Opcodes.INVOKEINTERFACE);
132 }
133
134 @Override
135 public void visitMethodInsn(final int opcode, final String owner,
136 final String name, final String desc, final boolean itf) {
137 if (api < Opcodes.ASM5) {
138 super.visitMethodInsn(opcode, owner, name, desc, itf);
139 return;
140 }
141 doVisitMethodInsn(opcode, owner, name, desc, itf);
142 }
143
144 private void doVisitMethodInsn(int opcode, final String owner,
145 final String name, final String desc, final boolean itf) {
146 if (opcode == INVOKEINTERFACE) {
147 minSize += 5;
148 maxSize += 5;
149 } else {
150 minSize += 3;
151 maxSize += 3;
152 }
153 if (mv != null) {
154 mv.visitMethodInsn(opcode, owner, name, desc, itf);
155 }
156 }
157
158 @Override
159 public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
160 Object... bsmArgs) {
161 minSize += 5;
162 maxSize += 5;
163 if (mv != null) {
164 mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
165 }
166 }
167
168 @Override
169 public void visitJumpInsn(final int opcode, final Label label) {
170 minSize += 3;
171 if (opcode == GOTO || opcode == JSR) {
172 maxSize += 5;
173 } else {
174 maxSize += 8;
175 }
176 if (mv != null) {
177 mv.visitJumpInsn(opcode, label);
178 }
179 }
180
181 @Override
182 public void visitLdcInsn(final Object cst) {
183 if (cst instanceof Long || cst instanceof Double) {
184 minSize += 3;
185 maxSize += 3;
186 } else {
187 minSize += 2;
188 maxSize += 3;
189 }
190 if (mv != null) {
191 mv.visitLdcInsn(cst);
192 }
193 }
194
195 @Override
196 public void visitIincInsn(final int var, final int increment) {
197 if (var > 255 || increment > 127 || increment < -128) {
198 minSize += 6;
199 maxSize += 6;
200 } else {
201 minSize += 3;
202 maxSize += 3;
203 }
204 if (mv != null) {
205 mv.visitIincInsn(var, increment);
206 }
207 }
208
209 @Override
210 public void visitTableSwitchInsn(final int min, final int max,
211 final Label dflt, final Label... labels) {
212 minSize += 13 + labels.length * 4;
213 maxSize += 16 + labels.length * 4;
214 if (mv != null) {
215 mv.visitTableSwitchInsn(min, max, dflt, labels);
216 }
217 }
218
219 @Override
220 public void visitLookupSwitchInsn(final Label dflt, final int[] keys,
221 final Label[] labels) {
222 minSize += 9 + keys.length * 8;
223 maxSize += 12 + keys.length * 8;
224 if (mv != null) {
225 mv.visitLookupSwitchInsn(dflt, keys, labels);
226 }
227 }
228
229 @Override
230 public void visitMultiANewArrayInsn(final String desc, final int dims) {
231 minSize += 4;
232 maxSize += 4;
233 if (mv != null) {
234 mv.visitMultiANewArrayInsn(desc, dims);
235 }
236 }
41 private int minSize;
42
43 private int maxSize;
44
45 public CodeSizeEvaluator(final MethodVisitor mv) {
46 this(Opcodes.ASM6, mv);
47 }
48
49 protected CodeSizeEvaluator(final int api, final MethodVisitor mv) {
50 super(api, mv);
51 }
52
53 public int getMinSize() {
54 return this.minSize;
55 }
56
57 public int getMaxSize() {
58 return this.maxSize;
59 }
60
61 @Override
62 public void visitInsn(final int opcode) {
63 minSize += 1;
64 maxSize += 1;
65 super.visitInsn(opcode);
66 }
67
68 @Override
69 public void visitIntInsn(final int opcode, final int operand) {
70 if (opcode == SIPUSH) {
71 minSize += 3;
72 maxSize += 3;
73 } else {
74 minSize += 2;
75 maxSize += 2;
76 }
77 super.visitIntInsn(opcode, operand);
78 }
79
80 @Override
81 public void visitVarInsn(final int opcode, final int var) {
82 if (var < 4 && opcode != RET) {
83 minSize += 1;
84 maxSize += 1;
85 } else if (var >= 256) {
86 minSize += 4;
87 maxSize += 4;
88 } else {
89 minSize += 2;
90 maxSize += 2;
91 }
92 super.visitVarInsn(opcode, var);
93 }
94
95 @Override
96 public void visitTypeInsn(final int opcode, final String type) {
97 minSize += 3;
98 maxSize += 3;
99 super.visitTypeInsn(opcode, type);
100 }
101
102 @Override
103 public void visitFieldInsn(
104 final int opcode, final String owner, final String name, final String desc) {
105 minSize += 3;
106 maxSize += 3;
107 super.visitFieldInsn(opcode, owner, name, desc);
108 }
109
110 @Deprecated
111 @Override
112 public void visitMethodInsn(
113 final int opcode, final String owner, final String name, final String desc) {
114 if (api >= Opcodes.ASM5) {
115 super.visitMethodInsn(opcode, owner, name, desc);
116 return;
117 }
118 doVisitMethodInsn(opcode, owner, name, desc, opcode == Opcodes.INVOKEINTERFACE);
119 }
120
121 @Override
122 public void visitMethodInsn(
123 final int opcode,
124 final String owner,
125 final String name,
126 final String desc,
127 final boolean itf) {
128 if (api < Opcodes.ASM5) {
129 super.visitMethodInsn(opcode, owner, name, desc, itf);
130 return;
131 }
132 doVisitMethodInsn(opcode, owner, name, desc, itf);
133 }
134
135 private void doVisitMethodInsn(
136 int opcode, final String owner, final String name, final String desc, final boolean itf) {
137 if (opcode == INVOKEINTERFACE) {
138 minSize += 5;
139 maxSize += 5;
140 } else {
141 minSize += 3;
142 maxSize += 3;
143 }
144 if (mv != null) {
145 mv.visitMethodInsn(opcode, owner, name, desc, itf);
146 }
147 }
148
149 @Override
150 public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) {
151 minSize += 5;
152 maxSize += 5;
153 super.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
154 }
155
156 @Override
157 public void visitJumpInsn(final int opcode, final Label label) {
158 minSize += 3;
159 if (opcode == GOTO || opcode == JSR) {
160 maxSize += 5;
161 } else {
162 maxSize += 8;
163 }
164 super.visitJumpInsn(opcode, label);
165 }
166
167 @Override
168 public void visitLdcInsn(final Object cst) {
169 if (cst instanceof Long || cst instanceof Double) {
170 minSize += 3;
171 maxSize += 3;
172 } else {
173 minSize += 2;
174 maxSize += 3;
175 }
176 super.visitLdcInsn(cst);
177 }
178
179 @Override
180 public void visitIincInsn(final int var, final int increment) {
181 if (var > 255 || increment > 127 || increment < -128) {
182 minSize += 6;
183 maxSize += 6;
184 } else {
185 minSize += 3;
186 maxSize += 3;
187 }
188 super.visitIincInsn(var, increment);
189 }
190
191 @Override
192 public void visitTableSwitchInsn(
193 final int min, final int max, final Label dflt, final Label... labels) {
194 minSize += 13 + labels.length * 4;
195 maxSize += 16 + labels.length * 4;
196 super.visitTableSwitchInsn(min, max, dflt, labels);
197 }
198
199 @Override
200 public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) {
201 minSize += 9 + keys.length * 8;
202 maxSize += 12 + keys.length * 8;
203 super.visitLookupSwitchInsn(dflt, keys, labels);
204 }
205
206 @Override
207 public void visitMultiANewArrayInsn(final String desc, final int dims) {
208 minSize += 4;
209 maxSize += 4;
210 super.visitMultiANewArrayInsn(desc, dims);
211 }
237212 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927
3028 package org.eclipse.persistence.internal.libraries.asm.commons;
3129
3634
3735 /**
3836 * A {@link FieldVisitor} adapter for type remapping.
39 *
37 *
4038 * @author Eugene Kuleshov
4139 */
4240 public class FieldRemapper extends FieldVisitor {
4341
44 private final Remapper remapper;
42 private final Remapper remapper;
4543
46 public FieldRemapper(final FieldVisitor fv, final Remapper remapper) {
47 this(Opcodes.ASM6, fv, remapper);
48 }
44 public FieldRemapper(final FieldVisitor fv, final Remapper remapper) {
45 this(Opcodes.ASM6, fv, remapper);
46 }
4947
50 protected FieldRemapper(final int api, final FieldVisitor fv,
51 final Remapper remapper) {
52 super(api, fv);
53 this.remapper = remapper;
54 }
48 protected FieldRemapper(final int api, final FieldVisitor fv, final Remapper remapper) {
49 super(api, fv);
50 this.remapper = remapper;
51 }
5552
56 @Override
57 public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
58 AnnotationVisitor av = fv.visitAnnotation(remapper.mapDesc(desc),
59 visible);
60 return av == null ? null : new AnnotationRemapper(av, remapper);
61 }
53 @Override
54 public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
55 AnnotationVisitor av = fv.visitAnnotation(remapper.mapDesc(desc), visible);
56 return av == null ? null : new AnnotationRemapper(api, av, remapper);
57 }
6258
63 @Override
64 public AnnotationVisitor visitTypeAnnotation(int typeRef,
65 TypePath typePath, String desc, boolean visible) {
66 AnnotationVisitor av = super.visitTypeAnnotation(typeRef, typePath,
67 remapper.mapDesc(desc), visible);
68 return av == null ? null : new AnnotationRemapper(av, remapper);
69 }
59 @Override
60 public AnnotationVisitor visitTypeAnnotation(
61 int typeRef, TypePath typePath, String desc, boolean visible) {
62 AnnotationVisitor av =
63 super.visitTypeAnnotation(typeRef, typePath, remapper.mapDesc(desc), visible);
64 return av == null ? null : new AnnotationRemapper(api, av, remapper);
65 }
7066 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.commons;
3028
3129 import java.util.ArrayList;
4038 import org.eclipse.persistence.internal.libraries.asm.Type;
4139
4240 /**
43 * A {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor} with convenient methods to generate
44 * code. For example, using this adapter, the class below
45 *
41 * A {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor} with convenient methods to generate code. For example,
42 * using this adapter, the class below
43 *
4644 * <pre>
4745 * public class Example {
4846 * public static void main(String[] args) {
5048 * }
5149 * }
5250 * </pre>
53 *
51 *
5452 * can be generated as follows:
55 *
53 *
5654 * <pre>
57 * ClassWriter cw = new ClassWriter(true);
55 * ClassWriter cw = new ClassWriter(0);
5856 * cw.visit(V1_1, ACC_PUBLIC, &quot;Example&quot;, null, &quot;java/lang/Object&quot;, null);
59 *
57 *
6058 * Method m = Method.getMethod(&quot;void &lt;init&gt; ()&quot;);
6159 * GeneratorAdapter mg = new GeneratorAdapter(ACC_PUBLIC, m, null, null, cw);
6260 * mg.loadThis();
6361 * mg.invokeConstructor(Type.getType(Object.class), m);
6462 * mg.returnValue();
6563 * mg.endMethod();
66 *
64 *
6765 * m = Method.getMethod(&quot;void main (String[])&quot;);
6866 * mg = new GeneratorAdapter(ACC_PUBLIC + ACC_STATIC, m, null, null, cw);
6967 * mg.getStatic(Type.getType(System.class), &quot;out&quot;, Type.getType(PrintStream.class));
7270 * Method.getMethod(&quot;void println (String)&quot;));
7371 * mg.returnValue();
7472 * mg.endMethod();
75 *
73 *
7674 * cw.visitEnd();
7775 * </pre>
78 *
76 *
7977 * @author Juozas Baliuka
8078 * @author Chris Nokleberg
8179 * @author Eric Bruneton
8381 */
8482 public class GeneratorAdapter extends LocalVariablesSorter {
8583
86 private static final String CLDESC = "Ljava/lang/Class;";
87
88 private static final Type BYTE_TYPE = Type.getObjectType("java/lang/Byte");
89
90 private static final Type BOOLEAN_TYPE = Type
91 .getObjectType("java/lang/Boolean");
92
93 private static final Type SHORT_TYPE = Type
94 .getObjectType("java/lang/Short");
95
96 private static final Type CHARACTER_TYPE = Type
97 .getObjectType("java/lang/Character");
98
99 private static final Type INTEGER_TYPE = Type
100 .getObjectType("java/lang/Integer");
101
102 private static final Type FLOAT_TYPE = Type
103 .getObjectType("java/lang/Float");
104
105 private static final Type LONG_TYPE = Type.getObjectType("java/lang/Long");
106
107 private static final Type DOUBLE_TYPE = Type
108 .getObjectType("java/lang/Double");
109
110 private static final Type NUMBER_TYPE = Type
111 .getObjectType("java/lang/Number");
112
113 private static final Type OBJECT_TYPE = Type
114 .getObjectType("java/lang/Object");
115
116 private static final Method BOOLEAN_VALUE = Method
117 .getMethod("boolean booleanValue()");
118
119 private static final Method CHAR_VALUE = Method
120 .getMethod("char charValue()");
121
122 private static final Method INT_VALUE = Method.getMethod("int intValue()");
123
124 private static final Method FLOAT_VALUE = Method
125 .getMethod("float floatValue()");
126
127 private static final Method LONG_VALUE = Method
128 .getMethod("long longValue()");
129
130 private static final Method DOUBLE_VALUE = Method
131 .getMethod("double doubleValue()");
132
133 /**
134 * Constant for the {@link #math math} method.
135 */
136 public static final int ADD = Opcodes.IADD;
137
138 /**
139 * Constant for the {@link #math math} method.
140 */
141 public static final int SUB = Opcodes.ISUB;
142
143 /**
144 * Constant for the {@link #math math} method.
145 */
146 public static final int MUL = Opcodes.IMUL;
147
148 /**
149 * Constant for the {@link #math math} method.
150 */
151 public static final int DIV = Opcodes.IDIV;
152
153 /**
154 * Constant for the {@link #math math} method.
155 */
156 public static final int REM = Opcodes.IREM;
157
158 /**
159 * Constant for the {@link #math math} method.
160 */
161 public static final int NEG = Opcodes.INEG;
162
163 /**
164 * Constant for the {@link #math math} method.
165 */
166 public static final int SHL = Opcodes.ISHL;
167
168 /**
169 * Constant for the {@link #math math} method.
170 */
171 public static final int SHR = Opcodes.ISHR;
172
173 /**
174 * Constant for the {@link #math math} method.
175 */
176 public static final int USHR = Opcodes.IUSHR;
177
178 /**
179 * Constant for the {@link #math math} method.
180 */
181 public static final int AND = Opcodes.IAND;
182
183 /**
184 * Constant for the {@link #math math} method.
185 */
186 public static final int OR = Opcodes.IOR;
187
188 /**
189 * Constant for the {@link #math math} method.
190 */
191 public static final int XOR = Opcodes.IXOR;
192
193 /**
194 * Constant for the {@link #ifCmp ifCmp} method.
195 */
196 public static final int EQ = Opcodes.IFEQ;
197
198 /**
199 * Constant for the {@link #ifCmp ifCmp} method.
200 */
201 public static final int NE = Opcodes.IFNE;
202
203 /**
204 * Constant for the {@link #ifCmp ifCmp} method.
205 */
206 public static final int LT = Opcodes.IFLT;
207
208 /**
209 * Constant for the {@link #ifCmp ifCmp} method.
210 */
211 public static final int GE = Opcodes.IFGE;
212
213 /**
214 * Constant for the {@link #ifCmp ifCmp} method.
215 */
216 public static final int GT = Opcodes.IFGT;
217
218 /**
219 * Constant for the {@link #ifCmp ifCmp} method.
220 */
221 public static final int LE = Opcodes.IFLE;
222
223 /**
224 * Access flags of the method visited by this adapter.
225 */
226 private final int access;
227
228 /**
229 * Return type of the method visited by this adapter.
230 */
231 private final Type returnType;
232
233 /**
234 * Argument types of the method visited by this adapter.
235 */
236 private final Type[] argumentTypes;
237
238 /**
239 * Types of the local variables of the method visited by this adapter.
240 */
241 private final List<Type> localTypes = new ArrayList<Type>();
242
243 /**
244 * Creates a new {@link GeneratorAdapter}. <i>Subclasses must not use this
245 * constructor</i>. Instead, they must use the
246 * {@link #GeneratorAdapter(int, MethodVisitor, int, String, String)}
247 * version.
248 *
249 * @param mv
250 * the method visitor to which this adapter delegates calls.
251 * @param access
252 * the method's access flags (see {@link Opcodes}).
253 * @param name
254 * the method's name.
255 * @param desc
256 * the method's descriptor (see {@link Type Type}).
257 * @throws IllegalStateException
258 * If a subclass calls this constructor.
259 */
260 public GeneratorAdapter(final MethodVisitor mv, final int access,
261 final String name, final String desc) {
262 this(Opcodes.ASM6, mv, access, name, desc);
263 if (getClass() != GeneratorAdapter.class) {
264 throw new IllegalStateException();
84 private static final String CLDESC = "Ljava/lang/Class;";
85
86 private static final Type BYTE_TYPE = Type.getObjectType("java/lang/Byte");
87
88 private static final Type BOOLEAN_TYPE = Type.getObjectType("java/lang/Boolean");
89
90 private static final Type SHORT_TYPE = Type.getObjectType("java/lang/Short");
91
92 private static final Type CHARACTER_TYPE = Type.getObjectType("java/lang/Character");
93
94 private static final Type INTEGER_TYPE = Type.getObjectType("java/lang/Integer");
95
96 private static final Type FLOAT_TYPE = Type.getObjectType("java/lang/Float");
97
98 private static final Type LONG_TYPE = Type.getObjectType("java/lang/Long");
99
100 private static final Type DOUBLE_TYPE = Type.getObjectType("java/lang/Double");
101
102 private static final Type NUMBER_TYPE = Type.getObjectType("java/lang/Number");
103
104 private static final Type OBJECT_TYPE = Type.getObjectType("java/lang/Object");
105
106 private static final Method BOOLEAN_VALUE = Method.getMethod("boolean booleanValue()");
107
108 private static final Method CHAR_VALUE = Method.getMethod("char charValue()");
109
110 private static final Method INT_VALUE = Method.getMethod("int intValue()");
111
112 private static final Method FLOAT_VALUE = Method.getMethod("float floatValue()");
113
114 private static final Method LONG_VALUE = Method.getMethod("long longValue()");
115
116 private static final Method DOUBLE_VALUE = Method.getMethod("double doubleValue()");
117
118 /** Constant for the {@link #math math} method. */
119 public static final int ADD = Opcodes.IADD;
120
121 /** Constant for the {@link #math math} method. */
122 public static final int SUB = Opcodes.ISUB;
123
124 /** Constant for the {@link #math math} method. */
125 public static final int MUL = Opcodes.IMUL;
126
127 /** Constant for the {@link #math math} method. */
128 public static final int DIV = Opcodes.IDIV;
129
130 /** Constant for the {@link #math math} method. */
131 public static final int REM = Opcodes.IREM;
132
133 /** Constant for the {@link #math math} method. */
134 public static final int NEG = Opcodes.INEG;
135
136 /** Constant for the {@link #math math} method. */
137 public static final int SHL = Opcodes.ISHL;
138
139 /** Constant for the {@link #math math} method. */
140 public static final int SHR = Opcodes.ISHR;
141
142 /** Constant for the {@link #math math} method. */
143 public static final int USHR = Opcodes.IUSHR;
144
145 /** Constant for the {@link #math math} method. */
146 public static final int AND = Opcodes.IAND;
147
148 /** Constant for the {@link #math math} method. */
149 public static final int OR = Opcodes.IOR;
150
151 /** Constant for the {@link #math math} method. */
152 public static final int XOR = Opcodes.IXOR;
153
154 /** Constant for the {@link #ifCmp ifCmp} method. */
155 public static final int EQ = Opcodes.IFEQ;
156
157 /** Constant for the {@link #ifCmp ifCmp} method. */
158 public static final int NE = Opcodes.IFNE;
159
160 /** Constant for the {@link #ifCmp ifCmp} method. */
161 public static final int LT = Opcodes.IFLT;
162
163 /** Constant for the {@link #ifCmp ifCmp} method. */
164 public static final int GE = Opcodes.IFGE;
165
166 /** Constant for the {@link #ifCmp ifCmp} method. */
167 public static final int GT = Opcodes.IFGT;
168
169 /** Constant for the {@link #ifCmp ifCmp} method. */
170 public static final int LE = Opcodes.IFLE;
171
172 /** Access flags of the method visited by this adapter. */
173 private final int access;
174
175 /** The name of the method visited by this adapter. */
176 private final String name;
177
178 /** Return type of the method visited by this adapter. */
179 private final Type returnType;
180
181 /** Argument types of the method visited by this adapter. */
182 private final Type[] argumentTypes;
183
184 /** Types of the local variables of the method visited by this adapter. */
185 private final List<Type> localTypes = new ArrayList<Type>();
186
187 /**
188 * Constructs a new {@link GeneratorAdapter}. <i>Subclasses must not use this constructor</i>.
189 * Instead, they must use the {@link #GeneratorAdapter(int, MethodVisitor, int, String, String)}
190 * version.
191 *
192 * @param mv the method visitor to which this adapter delegates calls.
193 * @param access the method's access flags (see {@link Opcodes}).
194 * @param name the method's name.
195 * @param desc the method's descriptor (see {@link Type Type}).
196 * @throws IllegalStateException If a subclass calls this constructor.
197 */
198 public GeneratorAdapter(
199 final MethodVisitor mv, final int access, final String name, final String desc) {
200 this(Opcodes.ASM6, mv, access, name, desc);
201 if (getClass() != GeneratorAdapter.class) {
202 throw new IllegalStateException();
203 }
204 }
205
206 /**
207 * Constructs a new {@link GeneratorAdapter}.
208 *
209 * @param api the ASM API version implemented by this visitor. Must be one of {@link
210 * Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
211 * @param mv the method visitor to which this adapter delegates calls.
212 * @param access the method's access flags (see {@link Opcodes}).
213 * @param name the method's name.
214 * @param desc the method's descriptor (see {@link Type Type}).
215 */
216 protected GeneratorAdapter(
217 final int api,
218 final MethodVisitor mv,
219 final int access,
220 final String name,
221 final String desc) {
222 super(api, access, desc, mv);
223 this.access = access;
224 this.name = name;
225 this.returnType = Type.getReturnType(desc);
226 this.argumentTypes = Type.getArgumentTypes(desc);
227 }
228
229 /**
230 * Constructs a new {@link GeneratorAdapter}. <i>Subclasses must not use this constructor</i>.
231 * Instead, they must use the {@link #GeneratorAdapter(int, MethodVisitor, int, String, String)}
232 * version.
233 *
234 * @param access access flags of the adapted method.
235 * @param method the adapted method.
236 * @param mv the method visitor to which this adapter delegates calls.
237 */
238 public GeneratorAdapter(final int access, final Method method, final MethodVisitor mv) {
239 this(mv, access, method.getName(), method.getDescriptor());
240 }
241
242 /**
243 * Constructs a new {@link GeneratorAdapter}. <i>Subclasses must not use this constructor</i>.
244 * Instead, they must use the {@link #GeneratorAdapter(int, MethodVisitor, int, String, String)}
245 * version.
246 *
247 * @param access access flags of the adapted method.
248 * @param method the adapted method.
249 * @param signature the signature of the adapted method (may be <tt>null</tt>).
250 * @param exceptions the exceptions thrown by the adapted method (may be <tt>null</tt>).
251 * @param cv the class visitor to which this adapter delegates calls.
252 */
253 public GeneratorAdapter(
254 final int access,
255 final Method method,
256 final String signature,
257 final Type[] exceptions,
258 final ClassVisitor cv) {
259 this(
260 access,
261 method,
262 cv.visitMethod(
263 access,
264 method.getName(),
265 method.getDescriptor(),
266 signature,
267 getInternalNames(exceptions)));
268 }
269
270 /**
271 * Returns the internal names of the given types.
272 *
273 * @param types a set of types.
274 * @return the internal names of the given types.
275 */
276 private static String[] getInternalNames(final Type[] types) {
277 if (types == null) {
278 return null;
279 }
280 String[] names = new String[types.length];
281 for (int i = 0; i < names.length; ++i) {
282 names[i] = types[i].getInternalName();
283 }
284 return names;
285 }
286
287 public int getAccess() {
288 return access;
289 }
290
291 public String getName() {
292 return name;
293 }
294
295 public Type getReturnType() {
296 return returnType;
297 }
298
299 public Type[] getArgumentTypes() {
300 return argumentTypes.clone();
301 }
302
303 // ------------------------------------------------------------------------
304 // Instructions to push constants on the stack
305 // ------------------------------------------------------------------------
306
307 /**
308 * Generates the instruction to push the given value on the stack.
309 *
310 * @param value the value to be pushed on the stack.
311 */
312 public void push(final boolean value) {
313 push(value ? 1 : 0);
314 }
315
316 /**
317 * Generates the instruction to push the given value on the stack.
318 *
319 * @param value the value to be pushed on the stack.
320 */
321 public void push(final int value) {
322 if (value >= -1 && value <= 5) {
323 mv.visitInsn(Opcodes.ICONST_0 + value);
324 } else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
325 mv.visitIntInsn(Opcodes.BIPUSH, value);
326 } else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
327 mv.visitIntInsn(Opcodes.SIPUSH, value);
328 } else {
329 mv.visitLdcInsn(value);
330 }
331 }
332
333 /**
334 * Generates the instruction to push the given value on the stack.
335 *
336 * @param value the value to be pushed on the stack.
337 */
338 public void push(final long value) {
339 if (value == 0L || value == 1L) {
340 mv.visitInsn(Opcodes.LCONST_0 + (int) value);
341 } else {
342 mv.visitLdcInsn(value);
343 }
344 }
345
346 /**
347 * Generates the instruction to push the given value on the stack.
348 *
349 * @param value the value to be pushed on the stack.
350 */
351 public void push(final float value) {
352 int bits = Float.floatToIntBits(value);
353 if (bits == 0L || bits == 0x3f800000 || bits == 0x40000000) { // 0..2
354 mv.visitInsn(Opcodes.FCONST_0 + (int) value);
355 } else {
356 mv.visitLdcInsn(value);
357 }
358 }
359
360 /**
361 * Generates the instruction to push the given value on the stack.
362 *
363 * @param value the value to be pushed on the stack.
364 */
365 public void push(final double value) {
366 long bits = Double.doubleToLongBits(value);
367 if (bits == 0L || bits == 0x3ff0000000000000L) { // +0.0d and 1.0d
368 mv.visitInsn(Opcodes.DCONST_0 + (int) value);
369 } else {
370 mv.visitLdcInsn(value);
371 }
372 }
373
374 /**
375 * Generates the instruction to push the given value on the stack.
376 *
377 * @param value the value to be pushed on the stack. May be <tt>null</tt>.
378 */
379 public void push(final String value) {
380 if (value == null) {
381 mv.visitInsn(Opcodes.ACONST_NULL);
382 } else {
383 mv.visitLdcInsn(value);
384 }
385 }
386
387 /**
388 * Generates the instruction to push the given value on the stack.
389 *
390 * @param value the value to be pushed on the stack.
391 */
392 public void push(final Type value) {
393 if (value == null) {
394 mv.visitInsn(Opcodes.ACONST_NULL);
395 } else {
396 switch (value.getSort()) {
397 case Type.BOOLEAN:
398 mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Boolean", "TYPE", CLDESC);
399 break;
400 case Type.CHAR:
401 mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Character", "TYPE", CLDESC);
402 break;
403 case Type.BYTE:
404 mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Byte", "TYPE", CLDESC);
405 break;
406 case Type.SHORT:
407 mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Short", "TYPE", CLDESC);
408 break;
409 case Type.INT:
410 mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Integer", "TYPE", CLDESC);
411 break;
412 case Type.FLOAT:
413 mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Float", "TYPE", CLDESC);
414 break;
415 case Type.LONG:
416 mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Long", "TYPE", CLDESC);
417 break;
418 case Type.DOUBLE:
419 mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Double", "TYPE", CLDESC);
420 break;
421 default:
422 mv.visitLdcInsn(value);
423 }
424 }
425 }
426
427 /**
428 * Generates the instruction to push a handle on the stack.
429 *
430 * @param handle the handle to be pushed on the stack.
431 */
432 public void push(final Handle handle) {
433 if (handle == null) {
434 mv.visitInsn(Opcodes.ACONST_NULL);
435 } else {
436 mv.visitLdcInsn(handle);
437 }
438 }
439
440 // ------------------------------------------------------------------------
441 // Instructions to load and store method arguments
442 // ------------------------------------------------------------------------
443
444 /**
445 * Returns the index of the given method argument in the frame's local variables array.
446 *
447 * @param arg the index of a method argument.
448 * @return the index of the given method argument in the frame's local variables array.
449 */
450 private int getArgIndex(final int arg) {
451 int index = (access & Opcodes.ACC_STATIC) == 0 ? 1 : 0;
452 for (int i = 0; i < arg; i++) {
453 index += argumentTypes[i].getSize();
454 }
455 return index;
456 }
457
458 /**
459 * Generates the instruction to push a local variable on the stack.
460 *
461 * @param type the type of the local variable to be loaded.
462 * @param index an index in the frame's local variables array.
463 */
464 private void loadInsn(final Type type, final int index) {
465 mv.visitVarInsn(type.getOpcode(Opcodes.ILOAD), index);
466 }
467
468 /**
469 * Generates the instruction to store the top stack value in a local variable.
470 *
471 * @param type the type of the local variable to be stored.
472 * @param index an index in the frame's local variables array.
473 */
474 private void storeInsn(final Type type, final int index) {
475 mv.visitVarInsn(type.getOpcode(Opcodes.ISTORE), index);
476 }
477
478 /** Generates the instruction to load 'this' on the stack. */
479 public void loadThis() {
480 if ((access & Opcodes.ACC_STATIC) != 0) {
481 throw new IllegalStateException("no 'this' pointer within static method");
482 }
483 mv.visitVarInsn(Opcodes.ALOAD, 0);
484 }
485
486 /**
487 * Generates the instruction to load the given method argument on the stack.
488 *
489 * @param arg the index of a method argument.
490 */
491 public void loadArg(final int arg) {
492 loadInsn(argumentTypes[arg], getArgIndex(arg));
493 }
494
495 /**
496 * Generates the instructions to load the given method arguments on the stack.
497 *
498 * @param arg the index of the first method argument to be loaded.
499 * @param count the number of method arguments to be loaded.
500 */
501 public void loadArgs(final int arg, final int count) {
502 int index = getArgIndex(arg);
503 for (int i = 0; i < count; ++i) {
504 Type t = argumentTypes[arg + i];
505 loadInsn(t, index);
506 index += t.getSize();
507 }
508 }
509
510 /** Generates the instructions to load all the method arguments on the stack. */
511 public void loadArgs() {
512 loadArgs(0, argumentTypes.length);
513 }
514
515 /**
516 * Generates the instructions to load all the method arguments on the stack, as a single object
517 * array.
518 */
519 public void loadArgArray() {
520 push(argumentTypes.length);
521 newArray(OBJECT_TYPE);
522 for (int i = 0; i < argumentTypes.length; i++) {
523 dup();
524 push(i);
525 loadArg(i);
526 box(argumentTypes[i]);
527 arrayStore(OBJECT_TYPE);
528 }
529 }
530
531 /**
532 * Generates the instruction to store the top stack value in the given method argument.
533 *
534 * @param arg the index of a method argument.
535 */
536 public void storeArg(final int arg) {
537 storeInsn(argumentTypes[arg], getArgIndex(arg));
538 }
539
540 // ------------------------------------------------------------------------
541 // Instructions to load and store local variables
542 // ------------------------------------------------------------------------
543
544 /**
545 * Returns the type of the given local variable.
546 *
547 * @param local a local variable identifier, as returned by {@link
548 * LocalVariablesSorter#newLocal(Type) newLocal()}.
549 * @return the type of the given local variable.
550 */
551 public Type getLocalType(final int local) {
552 return localTypes.get(local - firstLocal);
553 }
554
555 @Override
556 protected void setLocalType(final int local, final Type type) {
557 int index = local - firstLocal;
558 while (localTypes.size() < index + 1) {
559 localTypes.add(null);
560 }
561 localTypes.set(index, type);
562 }
563
564 /**
565 * Generates the instruction to load the given local variable on the stack.
566 *
567 * @param local a local variable identifier, as returned by {@link
568 * LocalVariablesSorter#newLocal(Type) newLocal()}.
569 */
570 public void loadLocal(final int local) {
571 loadInsn(getLocalType(local), local);
572 }
573
574 /**
575 * Generates the instruction to load the given local variable on the stack.
576 *
577 * @param local a local variable identifier, as returned by {@link
578 * LocalVariablesSorter#newLocal(Type) newLocal()}.
579 * @param type the type of this local variable.
580 */
581 public void loadLocal(final int local, final Type type) {
582 setLocalType(local, type);
583 loadInsn(type, local);
584 }
585
586 /**
587 * Generates the instruction to store the top stack value in the given local variable.
588 *
589 * @param local a local variable identifier, as returned by {@link
590 * LocalVariablesSorter#newLocal(Type) newLocal()}.
591 */
592 public void storeLocal(final int local) {
593 storeInsn(getLocalType(local), local);
594 }
595
596 /**
597 * Generates the instruction to store the top stack value in the given local variable.
598 *
599 * @param local a local variable identifier, as returned by {@link
600 * LocalVariablesSorter#newLocal(Type) newLocal()}.
601 * @param type the type of this local variable.
602 */
603 public void storeLocal(final int local, final Type type) {
604 setLocalType(local, type);
605 storeInsn(type, local);
606 }
607
608 /**
609 * Generates the instruction to load an element from an array.
610 *
611 * @param type the type of the array element to be loaded.
612 */
613 public void arrayLoad(final Type type) {
614 mv.visitInsn(type.getOpcode(Opcodes.IALOAD));
615 }
616
617 /**
618 * Generates the instruction to store an element in an array.
619 *
620 * @param type the type of the array element to be stored.
621 */
622 public void arrayStore(final Type type) {
623 mv.visitInsn(type.getOpcode(Opcodes.IASTORE));
624 }
625
626 // ------------------------------------------------------------------------
627 // Instructions to manage the stack
628 // ------------------------------------------------------------------------
629
630 /** Generates a POP instruction. */
631 public void pop() {
632 mv.visitInsn(Opcodes.POP);
633 }
634
635 /** Generates a POP2 instruction. */
636 public void pop2() {
637 mv.visitInsn(Opcodes.POP2);
638 }
639
640 /** Generates a DUP instruction. */
641 public void dup() {
642 mv.visitInsn(Opcodes.DUP);
643 }
644
645 /** Generates a DUP2 instruction. */
646 public void dup2() {
647 mv.visitInsn(Opcodes.DUP2);
648 }
649
650 /** Generates a DUP_X1 instruction. */
651 public void dupX1() {
652 mv.visitInsn(Opcodes.DUP_X1);
653 }
654
655 /** Generates a DUP_X2 instruction. */
656 public void dupX2() {
657 mv.visitInsn(Opcodes.DUP_X2);
658 }
659
660 /** Generates a DUP2_X1 instruction. */
661 public void dup2X1() {
662 mv.visitInsn(Opcodes.DUP2_X1);
663 }
664
665 /** Generates a DUP2_X2 instruction. */
666 public void dup2X2() {
667 mv.visitInsn(Opcodes.DUP2_X2);
668 }
669
670 /** Generates a SWAP instruction. */
671 public void swap() {
672 mv.visitInsn(Opcodes.SWAP);
673 }
674
675 /**
676 * Generates the instructions to swap the top two stack values.
677 *
678 * @param prev type of the top - 1 stack value.
679 * @param type type of the top stack value.
680 */
681 public void swap(final Type prev, final Type type) {
682 if (type.getSize() == 1) {
683 if (prev.getSize() == 1) {
684 swap(); // same as dupX1(), pop();
685 } else {
686 dupX2();
687 pop();
688 }
689 } else {
690 if (prev.getSize() == 1) {
691 dup2X1();
692 pop2();
693 } else {
694 dup2X2();
695 pop2();
696 }
697 }
698 }
699
700 // ------------------------------------------------------------------------
701 // Instructions to do mathematical and logical operations
702 // ------------------------------------------------------------------------
703
704 /**
705 * Generates the instruction to do the specified mathematical or logical operation.
706 *
707 * @param op a mathematical or logical operation. Must be one of ADD, SUB, MUL, DIV, REM, NEG,
708 * SHL, SHR, USHR, AND, OR, XOR.
709 * @param type the type of the operand(s) for this operation.
710 */
711 public void math(final int op, final Type type) {
712 mv.visitInsn(type.getOpcode(op));
713 }
714
715 /** Generates the instructions to compute the bitwise negation of the top stack value. */
716 public void not() {
717 mv.visitInsn(Opcodes.ICONST_1);
718 mv.visitInsn(Opcodes.IXOR);
719 }
720
721 /**
722 * Generates the instruction to increment the given local variable.
723 *
724 * @param local the local variable to be incremented.
725 * @param amount the amount by which the local variable must be incremented.
726 */
727 public void iinc(final int local, final int amount) {
728 mv.visitIincInsn(local, amount);
729 }
730
731 /**
732 * Generates the instructions to cast a numerical value from one type to another.
733 *
734 * @param from the type of the top stack value
735 * @param to the type into which this value must be cast.
736 */
737 public void cast(final Type from, final Type to) {
738 if (from != to) {
739 if (from == Type.DOUBLE_TYPE) {
740 if (to == Type.FLOAT_TYPE) {
741 mv.visitInsn(Opcodes.D2F);
742 } else if (to == Type.LONG_TYPE) {
743 mv.visitInsn(Opcodes.D2L);
744 } else {
745 mv.visitInsn(Opcodes.D2I);
746 cast(Type.INT_TYPE, to);
265747 }
266 }
267
268 /**
269 * Creates a new {@link GeneratorAdapter}.
270 *
271 * @param api
272 * the ASM API version implemented by this visitor. Must be one
273 * of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
274 * @param mv
275 * the method visitor to which this adapter delegates calls.
276 * @param access
277 * the method's access flags (see {@link Opcodes}).
278 * @param name
279 * the method's name.
280 * @param desc
281 * the method's descriptor (see {@link Type Type}).
282 */
283 protected GeneratorAdapter(final int api, final MethodVisitor mv,
284 final int access, final String name, final String desc) {
285 super(api, access, desc, mv);
286 this.access = access;
287 this.returnType = Type.getReturnType(desc);
288 this.argumentTypes = Type.getArgumentTypes(desc);
289 }
290
291 /**
292 * Creates a new {@link GeneratorAdapter}. <i>Subclasses must not use this
293 * constructor</i>. Instead, they must use the
294 * {@link #GeneratorAdapter(int, MethodVisitor, int, String, String)}
295 * version.
296 *
297 * @param access
298 * access flags of the adapted method.
299 * @param method
300 * the adapted method.
301 * @param mv
302 * the method visitor to which this adapter delegates calls.
303 */
304 public GeneratorAdapter(final int access, final Method method,
305 final MethodVisitor mv) {
306 this(mv, access, null, method.getDescriptor());
307 }
308
309 /**
310 * Creates a new {@link GeneratorAdapter}. <i>Subclasses must not use this
311 * constructor</i>. Instead, they must use the
312 * {@link #GeneratorAdapter(int, MethodVisitor, int, String, String)}
313 * version.
314 *
315 * @param access
316 * access flags of the adapted method.
317 * @param method
318 * the adapted method.
319 * @param signature
320 * the signature of the adapted method (may be <tt>null</tt>).
321 * @param exceptions
322 * the exceptions thrown by the adapted method (may be
323 * <tt>null</tt>).
324 * @param cv
325 * the class visitor to which this adapter delegates calls.
326 */
327 public GeneratorAdapter(final int access, final Method method,
328 final String signature, final Type[] exceptions,
329 final ClassVisitor cv) {
330 this(access, method, cv
331 .visitMethod(access, method.getName(), method.getDescriptor(),
332 signature, getInternalNames(exceptions)));
333 }
334
335 /**
336 * Returns the internal names of the given types.
337 *
338 * @param types
339 * a set of types.
340 * @return the internal names of the given types.
341 */
342 private static String[] getInternalNames(final Type[] types) {
343 if (types == null) {
344 return null;
748 } else if (from == Type.FLOAT_TYPE) {
749 if (to == Type.DOUBLE_TYPE) {
750 mv.visitInsn(Opcodes.F2D);
751 } else if (to == Type.LONG_TYPE) {
752 mv.visitInsn(Opcodes.F2L);
753 } else {
754 mv.visitInsn(Opcodes.F2I);
755 cast(Type.INT_TYPE, to);
345756 }
346 String[] names = new String[types.length];
347 for (int i = 0; i < names.length; ++i) {
348 names[i] = types[i].getInternalName();
757 } else if (from == Type.LONG_TYPE) {
758 if (to == Type.DOUBLE_TYPE) {
759 mv.visitInsn(Opcodes.L2D);
760 } else if (to == Type.FLOAT_TYPE) {
761 mv.visitInsn(Opcodes.L2F);
762 } else {
763 mv.visitInsn(Opcodes.L2I);
764 cast(Type.INT_TYPE, to);
349765 }
350 return names;
351 }
352
353 // ------------------------------------------------------------------------
354 // Instructions to push constants on the stack
355 // ------------------------------------------------------------------------
356
357 /**
358 * Generates the instruction to push the given value on the stack.
359 *
360 * @param value
361 * the value to be pushed on the stack.
362 */
363 public void push(final boolean value) {
364 push(value ? 1 : 0);
365 }
366
367 /**
368 * Generates the instruction to push the given value on the stack.
369 *
370 * @param value
371 * the value to be pushed on the stack.
372 */
373 public void push(final int value) {
374 if (value >= -1 && value <= 5) {
375 mv.visitInsn(Opcodes.ICONST_0 + value);
376 } else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
377 mv.visitIntInsn(Opcodes.BIPUSH, value);
378 } else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
379 mv.visitIntInsn(Opcodes.SIPUSH, value);
766 } else {
767 if (to == Type.BYTE_TYPE) {
768 mv.visitInsn(Opcodes.I2B);
769 } else if (to == Type.CHAR_TYPE) {
770 mv.visitInsn(Opcodes.I2C);
771 } else if (to == Type.DOUBLE_TYPE) {
772 mv.visitInsn(Opcodes.I2D);
773 } else if (to == Type.FLOAT_TYPE) {
774 mv.visitInsn(Opcodes.I2F);
775 } else if (to == Type.LONG_TYPE) {
776 mv.visitInsn(Opcodes.I2L);
777 } else if (to == Type.SHORT_TYPE) {
778 mv.visitInsn(Opcodes.I2S);
380779 } else {
381 mv.visitLdcInsn(value);
382 }
383 }
384
385 /**
386 * Generates the instruction to push the given value on the stack.
387 *
388 * @param value
389 * the value to be pushed on the stack.
390 */
391 public void push(final long value) {
392 if (value == 0L || value == 1L) {
393 mv.visitInsn(Opcodes.LCONST_0 + (int) value);
394 } else {
395 mv.visitLdcInsn(value);
396 }
397 }
398
399 /**
400 * Generates the instruction to push the given value on the stack.
401 *
402 * @param value
403 * the value to be pushed on the stack.
404 */
405 public void push(final float value) {
406 int bits = Float.floatToIntBits(value);
407 if (bits == 0L || bits == 0x3f800000 || bits == 0x40000000) { // 0..2
408 mv.visitInsn(Opcodes.FCONST_0 + (int) value);
409 } else {
410 mv.visitLdcInsn(value);
411 }
412 }
413
414 /**
415 * Generates the instruction to push the given value on the stack.
416 *
417 * @param value
418 * the value to be pushed on the stack.
419 */
420 public void push(final double value) {
421 long bits = Double.doubleToLongBits(value);
422 if (bits == 0L || bits == 0x3ff0000000000000L) { // +0.0d and 1.0d
423 mv.visitInsn(Opcodes.DCONST_0 + (int) value);
424 } else {
425 mv.visitLdcInsn(value);
426 }
427 }
428
429 /**
430 * Generates the instruction to push the given value on the stack.
431 *
432 * @param value
433 * the value to be pushed on the stack. May be <tt>null</tt>.
434 */
435 public void push(final String value) {
436 if (value == null) {
437 mv.visitInsn(Opcodes.ACONST_NULL);
438 } else {
439 mv.visitLdcInsn(value);
440 }
441 }
442
443 /**
444 * Generates the instruction to push the given value on the stack.
445 *
446 * @param value
447 * the value to be pushed on the stack.
448 */
449 public void push(final Type value) {
450 if (value == null) {
451 mv.visitInsn(Opcodes.ACONST_NULL);
452 } else {
453 switch (value.getSort()) {
454 case Type.BOOLEAN:
455 mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Boolean",
456 "TYPE", CLDESC);
457 break;
458 case Type.CHAR:
459 mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Character",
460 "TYPE", CLDESC);
461 break;
462 case Type.BYTE:
463 mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Byte", "TYPE",
464 CLDESC);
465 break;
466 case Type.SHORT:
467 mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Short", "TYPE",
468 CLDESC);
469 break;
470 case Type.INT:
471 mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Integer",
472 "TYPE", CLDESC);
473 break;
474 case Type.FLOAT:
475 mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Float", "TYPE",
476 CLDESC);
477 break;
478 case Type.LONG:
479 mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Long", "TYPE",
480 CLDESC);
481 break;
482 case Type.DOUBLE:
483 mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Double",
484 "TYPE", CLDESC);
485 break;
486 default:
487 mv.visitLdcInsn(value);
488 }
489 }
490 }
491
492 /**
493 * Generates the instruction to push a handle on the stack.
494 *
495 * @param handle
496 * the handle to be pushed on the stack.
497 */
498 public void push(final Handle handle) {
499 mv.visitLdcInsn(handle);
500 }
501
502 // ------------------------------------------------------------------------
503 // Instructions to load and store method arguments
504 // ------------------------------------------------------------------------
505
506 /**
507 * Returns the index of the given method argument in the frame's local
508 * variables array.
509 *
510 * @param arg
511 * the index of a method argument.
512 * @return the index of the given method argument in the frame's local
513 * variables array.
514 */
515 private int getArgIndex(final int arg) {
516 int index = (access & Opcodes.ACC_STATIC) == 0 ? 1 : 0;
517 for (int i = 0; i < arg; i++) {
518 index += argumentTypes[i].getSize();
519 }
520 return index;
521 }
522
523 /**
524 * Generates the instruction to push a local variable on the stack.
525 *
526 * @param type
527 * the type of the local variable to be loaded.
528 * @param index
529 * an index in the frame's local variables array.
530 */
531 private void loadInsn(final Type type, final int index) {
532 mv.visitVarInsn(type.getOpcode(Opcodes.ILOAD), index);
533 }
534
535 /**
536 * Generates the instruction to store the top stack value in a local
537 * variable.
538 *
539 * @param type
540 * the type of the local variable to be stored.
541 * @param index
542 * an index in the frame's local variables array.
543 */
544 private void storeInsn(final Type type, final int index) {
545 mv.visitVarInsn(type.getOpcode(Opcodes.ISTORE), index);
546 }
547
548 /**
549 * Generates the instruction to load 'this' on the stack.
550 */
551 public void loadThis() {
552 if ((access & Opcodes.ACC_STATIC) != 0) {
553 throw new IllegalStateException(
554 "no 'this' pointer within static method");
555 }
556 mv.visitVarInsn(Opcodes.ALOAD, 0);
557 }
558
559 /**
560 * Generates the instruction to load the given method argument on the stack.
561 *
562 * @param arg
563 * the index of a method argument.
564 */
565 public void loadArg(final int arg) {
566 loadInsn(argumentTypes[arg], getArgIndex(arg));
567 }
568
569 /**
570 * Generates the instructions to load the given method arguments on the
571 * stack.
572 *
573 * @param arg
574 * the index of the first method argument to be loaded.
575 * @param count
576 * the number of method arguments to be loaded.
577 */
578 public void loadArgs(final int arg, final int count) {
579 int index = getArgIndex(arg);
580 for (int i = 0; i < count; ++i) {
581 Type t = argumentTypes[arg + i];
582 loadInsn(t, index);
583 index += t.getSize();
584 }
585 }
586
587 /**
588 * Generates the instructions to load all the method arguments on the stack.
589 */
590 public void loadArgs() {
591 loadArgs(0, argumentTypes.length);
592 }
593
594 /**
595 * Generates the instructions to load all the method arguments on the stack,
596 * as a single object array.
597 */
598 public void loadArgArray() {
599 push(argumentTypes.length);
600 newArray(OBJECT_TYPE);
601 for (int i = 0; i < argumentTypes.length; i++) {
602 dup();
603 push(i);
604 loadArg(i);
605 box(argumentTypes[i]);
606 arrayStore(OBJECT_TYPE);
607 }
608 }
609
610 /**
611 * Generates the instruction to store the top stack value in the given
612 * method argument.
613 *
614 * @param arg
615 * the index of a method argument.
616 */
617 public void storeArg(final int arg) {
618 storeInsn(argumentTypes[arg], getArgIndex(arg));
619 }
620
621 // ------------------------------------------------------------------------
622 // Instructions to load and store local variables
623 // ------------------------------------------------------------------------
624
625 /**
626 * Returns the type of the given local variable.
627 *
628 * @param local
629 * a local variable identifier, as returned by
630 * {@link LocalVariablesSorter#newLocal(Type) newLocal()}.
631 * @return the type of the given local variable.
632 */
633 public Type getLocalType(final int local) {
634 return localTypes.get(local - firstLocal);
635 }
636
637 @Override
638 protected void setLocalType(final int local, final Type type) {
639 int index = local - firstLocal;
640 while (localTypes.size() < index + 1) {
641 localTypes.add(null);
642 }
643 localTypes.set(index, type);
644 }
645
646 /**
647 * Generates the instruction to load the given local variable on the stack.
648 *
649 * @param local
650 * a local variable identifier, as returned by
651 * {@link LocalVariablesSorter#newLocal(Type) newLocal()}.
652 */
653 public void loadLocal(final int local) {
654 loadInsn(getLocalType(local), local);
655 }
656
657 /**
658 * Generates the instruction to load the given local variable on the stack.
659 *
660 * @param local
661 * a local variable identifier, as returned by
662 * {@link LocalVariablesSorter#newLocal(Type) newLocal()}.
663 * @param type
664 * the type of this local variable.
665 */
666 public void loadLocal(final int local, final Type type) {
667 setLocalType(local, type);
668 loadInsn(type, local);
669 }
670
671 /**
672 * Generates the instruction to store the top stack value in the given local
673 * variable.
674 *
675 * @param local
676 * a local variable identifier, as returned by
677 * {@link LocalVariablesSorter#newLocal(Type) newLocal()}.
678 */
679 public void storeLocal(final int local) {
680 storeInsn(getLocalType(local), local);
681 }
682
683 /**
684 * Generates the instruction to store the top stack value in the given local
685 * variable.
686 *
687 * @param local
688 * a local variable identifier, as returned by
689 * {@link LocalVariablesSorter#newLocal(Type) newLocal()}.
690 * @param type
691 * the type of this local variable.
692 */
693 public void storeLocal(final int local, final Type type) {
694 setLocalType(local, type);
695 storeInsn(type, local);
696 }
697
698 /**
699 * Generates the instruction to load an element from an array.
700 *
701 * @param type
702 * the type of the array element to be loaded.
703 */
704 public void arrayLoad(final Type type) {
705 mv.visitInsn(type.getOpcode(Opcodes.IALOAD));
706 }
707
708 /**
709 * Generates the instruction to store an element in an array.
710 *
711 * @param type
712 * the type of the array element to be stored.
713 */
714 public void arrayStore(final Type type) {
715 mv.visitInsn(type.getOpcode(Opcodes.IASTORE));
716 }
717
718 // ------------------------------------------------------------------------
719 // Instructions to manage the stack
720 // ------------------------------------------------------------------------
721
722 /**
723 * Generates a POP instruction.
724 */
725 public void pop() {
726 mv.visitInsn(Opcodes.POP);
727 }
728
729 /**
730 * Generates a POP2 instruction.
731 */
732 public void pop2() {
733 mv.visitInsn(Opcodes.POP2);
734 }
735
736 /**
737 * Generates a DUP instruction.
738 */
739 public void dup() {
740 mv.visitInsn(Opcodes.DUP);
741 }
742
743 /**
744 * Generates a DUP2 instruction.
745 */
746 public void dup2() {
747 mv.visitInsn(Opcodes.DUP2);
748 }
749
750 /**
751 * Generates a DUP_X1 instruction.
752 */
753 public void dupX1() {
754 mv.visitInsn(Opcodes.DUP_X1);
755 }
756
757 /**
758 * Generates a DUP_X2 instruction.
759 */
760 public void dupX2() {
761 mv.visitInsn(Opcodes.DUP_X2);
762 }
763
764 /**
765 * Generates a DUP2_X1 instruction.
766 */
767 public void dup2X1() {
768 mv.visitInsn(Opcodes.DUP2_X1);
769 }
770
771 /**
772 * Generates a DUP2_X2 instruction.
773 */
774 public void dup2X2() {
775 mv.visitInsn(Opcodes.DUP2_X2);
776 }
777
778 /**
779 * Generates a SWAP instruction.
780 */
781 public void swap() {
782 mv.visitInsn(Opcodes.SWAP);
783 }
784
785 /**
786 * Generates the instructions to swap the top two stack values.
787 *
788 * @param prev
789 * type of the top - 1 stack value.
790 * @param type
791 * type of the top stack value.
792 */
793 public void swap(final Type prev, final Type type) {
794 if (type.getSize() == 1) {
795 if (prev.getSize() == 1) {
796 swap(); // same as dupX1(), pop();
797 } else {
798 dupX2();
799 pop();
800 }
801 } else {
802 if (prev.getSize() == 1) {
803 dup2X1();
804 pop2();
805 } else {
806 dup2X2();
807 pop2();
808 }
809 }
810 }
811
812 // ------------------------------------------------------------------------
813 // Instructions to do mathematical and logical operations
814 // ------------------------------------------------------------------------
815
816 /**
817 * Generates the instruction to do the specified mathematical or logical
818 * operation.
819 *
820 * @param op
821 * a mathematical or logical operation. Must be one of ADD, SUB,
822 * MUL, DIV, REM, NEG, SHL, SHR, USHR, AND, OR, XOR.
823 * @param type
824 * the type of the operand(s) for this operation.
825 */
826 public void math(final int op, final Type type) {
827 mv.visitInsn(type.getOpcode(op));
828 }
829
830 /**
831 * Generates the instructions to compute the bitwise negation of the top
832 * stack value.
833 */
834 public void not() {
835 mv.visitInsn(Opcodes.ICONST_1);
836 mv.visitInsn(Opcodes.IXOR);
837 }
838
839 /**
840 * Generates the instruction to increment the given local variable.
841 *
842 * @param local
843 * the local variable to be incremented.
844 * @param amount
845 * the amount by which the local variable must be incremented.
846 */
847 public void iinc(final int local, final int amount) {
848 mv.visitIincInsn(local, amount);
849 }
850
851 /**
852 * Generates the instructions to cast a numerical value from one type to
853 * another.
854 *
855 * @param from
856 * the type of the top stack value
857 * @param to
858 * the type into which this value must be cast.
859 */
860 public void cast(final Type from, final Type to) {
861 if (from != to) {
862 if (from == Type.DOUBLE_TYPE) {
863 if (to == Type.FLOAT_TYPE) {
864 mv.visitInsn(Opcodes.D2F);
865 } else if (to == Type.LONG_TYPE) {
866 mv.visitInsn(Opcodes.D2L);
867 } else {
868 mv.visitInsn(Opcodes.D2I);
869 cast(Type.INT_TYPE, to);
870 }
871 } else if (from == Type.FLOAT_TYPE) {
872 if (to == Type.DOUBLE_TYPE) {
873 mv.visitInsn(Opcodes.F2D);
874 } else if (to == Type.LONG_TYPE) {
875 mv.visitInsn(Opcodes.F2L);
876 } else {
877 mv.visitInsn(Opcodes.F2I);
878 cast(Type.INT_TYPE, to);
879 }
880 } else if (from == Type.LONG_TYPE) {
881 if (to == Type.DOUBLE_TYPE) {
882 mv.visitInsn(Opcodes.L2D);
883 } else if (to == Type.FLOAT_TYPE) {
884 mv.visitInsn(Opcodes.L2F);
885 } else {
886 mv.visitInsn(Opcodes.L2I);
887 cast(Type.INT_TYPE, to);
888 }
889 } else {
890 if (to == Type.BYTE_TYPE) {
891 mv.visitInsn(Opcodes.I2B);
892 } else if (to == Type.CHAR_TYPE) {
893 mv.visitInsn(Opcodes.I2C);
894 } else if (to == Type.DOUBLE_TYPE) {
895 mv.visitInsn(Opcodes.I2D);
896 } else if (to == Type.FLOAT_TYPE) {
897 mv.visitInsn(Opcodes.I2F);
898 } else if (to == Type.LONG_TYPE) {
899 mv.visitInsn(Opcodes.I2L);
900 } else if (to == Type.SHORT_TYPE) {
901 mv.visitInsn(Opcodes.I2S);
902 }
903 }
904 }
905 }
906
907 // ------------------------------------------------------------------------
908 // Instructions to do boxing and unboxing operations
909 // ------------------------------------------------------------------------
910
911 private static Type getBoxedType(final Type type) {
912 switch (type.getSort()) {
913 case Type.BYTE:
914 return BYTE_TYPE;
915 case Type.BOOLEAN:
916 return BOOLEAN_TYPE;
917 case Type.SHORT:
918 return SHORT_TYPE;
919 case Type.CHAR:
920 return CHARACTER_TYPE;
921 case Type.INT:
922 return INTEGER_TYPE;
923 case Type.FLOAT:
924 return FLOAT_TYPE;
925 case Type.LONG:
926 return LONG_TYPE;
927 case Type.DOUBLE:
928 return DOUBLE_TYPE;
929 }
930 return type;
931 }
932
933 /**
934 * Generates the instructions to box the top stack value. This value is
935 * replaced by its boxed equivalent on top of the stack.
936 *
937 * @param type
938 * the type of the top stack value.
939 */
940 public void box(final Type type) {
941 if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
780 throw new IllegalArgumentException();
781 }
782 }
783 }
784 }
785
786 // ------------------------------------------------------------------------
787 // Instructions to do boxing and unboxing operations
788 // ------------------------------------------------------------------------
789
790 private static Type getBoxedType(final Type type) {
791 switch (type.getSort()) {
792 case Type.BYTE:
793 return BYTE_TYPE;
794 case Type.BOOLEAN:
795 return BOOLEAN_TYPE;
796 case Type.SHORT:
797 return SHORT_TYPE;
798 case Type.CHAR:
799 return CHARACTER_TYPE;
800 case Type.INT:
801 return INTEGER_TYPE;
802 case Type.FLOAT:
803 return FLOAT_TYPE;
804 case Type.LONG:
805 return LONG_TYPE;
806 case Type.DOUBLE:
807 return DOUBLE_TYPE;
808 }
809 return type;
810 }
811
812 /**
813 * Generates the instructions to box the top stack value. This value is replaced by its boxed
814 * equivalent on top of the stack.
815 *
816 * @param type the type of the top stack value.
817 */
818 public void box(final Type type) {
819 if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
820 return;
821 }
822 if (type == Type.VOID_TYPE) {
823 push((String) null);
824 } else {
825 Type boxed = getBoxedType(type);
826 newInstance(boxed);
827 if (type.getSize() == 2) {
828 // Pp -> Ppo -> oPpo -> ooPpo -> ooPp -> o
829 dupX2();
830 dupX2();
831 pop();
832 } else {
833 // p -> po -> opo -> oop -> o
834 dupX1();
835 swap();
836 }
837 invokeConstructor(boxed, new Method("<init>", Type.VOID_TYPE, new Type[] {type}));
838 }
839 }
840
841 /**
842 * Generates the instructions to box the top stack value using Java 5's valueOf() method. This
843 * value is replaced by its boxed equivalent on top of the stack.
844 *
845 * @param type the type of the top stack value.
846 */
847 public void valueOf(final Type type) {
848 if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
849 return;
850 }
851 if (type == Type.VOID_TYPE) {
852 push((String) null);
853 } else {
854 Type boxed = getBoxedType(type);
855 invokeStatic(boxed, new Method("valueOf", boxed, new Type[] {type}));
856 }
857 }
858
859 /**
860 * Generates the instructions to unbox the top stack value. This value is replaced by its unboxed
861 * equivalent on top of the stack.
862 *
863 * @param type the type of the top stack value.
864 */
865 public void unbox(final Type type) {
866 Type t = NUMBER_TYPE;
867 Method sig = null;
868 switch (type.getSort()) {
869 case Type.VOID:
870 return;
871 case Type.CHAR:
872 t = CHARACTER_TYPE;
873 sig = CHAR_VALUE;
874 break;
875 case Type.BOOLEAN:
876 t = BOOLEAN_TYPE;
877 sig = BOOLEAN_VALUE;
878 break;
879 case Type.DOUBLE:
880 sig = DOUBLE_VALUE;
881 break;
882 case Type.FLOAT:
883 sig = FLOAT_VALUE;
884 break;
885 case Type.LONG:
886 sig = LONG_VALUE;
887 break;
888 case Type.INT:
889 case Type.SHORT:
890 case Type.BYTE:
891 sig = INT_VALUE;
892 }
893 if (sig == null) {
894 checkCast(type);
895 } else {
896 checkCast(t);
897 invokeVirtual(t, sig);
898 }
899 }
900
901 // ------------------------------------------------------------------------
902 // Instructions to jump to other instructions
903 // ------------------------------------------------------------------------
904
905 /**
906 * Constructs a new {@link Label}.
907 *
908 * @return a new {@link Label}.
909 */
910 public Label newLabel() {
911 return new Label();
912 }
913
914 /**
915 * Marks the current code position with the given label.
916 *
917 * @param label a label.
918 */
919 public void mark(final Label label) {
920 mv.visitLabel(label);
921 }
922
923 /**
924 * Marks the current code position with a new label.
925 *
926 * @return the label that was created to mark the current code position.
927 */
928 public Label mark() {
929 Label label = new Label();
930 mv.visitLabel(label);
931 return label;
932 }
933
934 /**
935 * Generates the instructions to jump to a label based on the comparison of the top two stack
936 * values.
937 *
938 * @param type the type of the top two stack values.
939 * @param mode how these values must be compared. One of EQ, NE, LT, GE, GT, LE.
940 * @param label where to jump if the comparison result is <tt>true</tt>.
941 */
942 public void ifCmp(final Type type, final int mode, final Label label) {
943 switch (type.getSort()) {
944 case Type.LONG:
945 mv.visitInsn(Opcodes.LCMP);
946 break;
947 case Type.DOUBLE:
948 mv.visitInsn(mode == GE || mode == GT ? Opcodes.DCMPL : Opcodes.DCMPG);
949 break;
950 case Type.FLOAT:
951 mv.visitInsn(mode == GE || mode == GT ? Opcodes.FCMPL : Opcodes.FCMPG);
952 break;
953 case Type.ARRAY:
954 case Type.OBJECT:
955 switch (mode) {
956 case EQ:
957 mv.visitJumpInsn(Opcodes.IF_ACMPEQ, label);
958 return;
959 case NE:
960 mv.visitJumpInsn(Opcodes.IF_ACMPNE, label);
942961 return;
943962 }
944 if (type == Type.VOID_TYPE) {
945 push((String) null);
946 } else {
947 Type boxed = getBoxedType(type);
948 newInstance(boxed);
949 if (type.getSize() == 2) {
950 // Pp -> Ppo -> oPpo -> ooPpo -> ooPp -> o
951 dupX2();
952 dupX2();
953 pop();
954 } else {
955 // p -> po -> opo -> oop -> o
956 dupX1();
957 swap();
958 }
959 invokeConstructor(boxed, new Method("<init>", Type.VOID_TYPE,
960 new Type[] { type }));
963 throw new IllegalArgumentException("Bad comparison for type " + type);
964 default:
965 int intOp = -1;
966 switch (mode) {
967 case EQ:
968 intOp = Opcodes.IF_ICMPEQ;
969 break;
970 case NE:
971 intOp = Opcodes.IF_ICMPNE;
972 break;
973 case GE:
974 intOp = Opcodes.IF_ICMPGE;
975 break;
976 case LT:
977 intOp = Opcodes.IF_ICMPLT;
978 break;
979 case LE:
980 intOp = Opcodes.IF_ICMPLE;
981 break;
982 case GT:
983 intOp = Opcodes.IF_ICMPGT;
984 break;
985 default:
986 throw new IllegalArgumentException("Bad comparison mode " + mode);
961987 }
962 }
963
964 /**
965 * Generates the instructions to box the top stack value using Java 5's
966 * valueOf() method. This value is replaced by its boxed equivalent on top
967 * of the stack.
968 *
969 * @param type
970 * the type of the top stack value.
971 */
972 public void valueOf(final Type type) {
973 if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
974 return;
988 mv.visitJumpInsn(intOp, label);
989 return;
990 }
991 mv.visitJumpInsn(mode, label);
992 }
993
994 /**
995 * Generates the instructions to jump to a label based on the comparison of the top two integer
996 * stack values.
997 *
998 * @param mode how these values must be compared. One of EQ, NE, LT, GE, GT, LE.
999 * @param label where to jump if the comparison result is <tt>true</tt>.
1000 */
1001 public void ifICmp(final int mode, final Label label) {
1002 ifCmp(Type.INT_TYPE, mode, label);
1003 }
1004
1005 /**
1006 * Generates the instructions to jump to a label based on the comparison of the top integer stack
1007 * value with zero.
1008 *
1009 * @param mode how these values must be compared. One of EQ, NE, LT, GE, GT, LE.
1010 * @param label where to jump if the comparison result is <tt>true</tt>.
1011 */
1012 public void ifZCmp(final int mode, final Label label) {
1013 mv.visitJumpInsn(mode, label);
1014 }
1015
1016 /**
1017 * Generates the instruction to jump to the given label if the top stack value is null.
1018 *
1019 * @param label where to jump if the condition is <tt>true</tt>.
1020 */
1021 public void ifNull(final Label label) {
1022 mv.visitJumpInsn(Opcodes.IFNULL, label);
1023 }
1024
1025 /**
1026 * Generates the instruction to jump to the given label if the top stack value is not null.
1027 *
1028 * @param label where to jump if the condition is <tt>true</tt>.
1029 */
1030 public void ifNonNull(final Label label) {
1031 mv.visitJumpInsn(Opcodes.IFNONNULL, label);
1032 }
1033
1034 /**
1035 * Generates the instruction to jump to the given label.
1036 *
1037 * @param label where to jump if the condition is <tt>true</tt>.
1038 */
1039 public void goTo(final Label label) {
1040 mv.visitJumpInsn(Opcodes.GOTO, label);
1041 }
1042
1043 /**
1044 * Generates a RET instruction.
1045 *
1046 * @param local a local variable identifier, as returned by {@link
1047 * LocalVariablesSorter#newLocal(Type) newLocal()}.
1048 */
1049 public void ret(final int local) {
1050 mv.visitVarInsn(Opcodes.RET, local);
1051 }
1052
1053 /**
1054 * Generates the instructions for a switch statement.
1055 *
1056 * @param keys the switch case keys.
1057 * @param generator a generator to generate the code for the switch cases.
1058 */
1059 public void tableSwitch(final int[] keys, final TableSwitchGenerator generator) {
1060 float density;
1061 if (keys.length == 0) {
1062 density = 0;
1063 } else {
1064 density = (float) keys.length / (keys[keys.length - 1] - keys[0] + 1);
1065 }
1066 tableSwitch(keys, generator, density >= 0.5f);
1067 }
1068
1069 /**
1070 * Generates the instructions for a switch statement.
1071 *
1072 * @param keys the switch case keys.
1073 * @param generator a generator to generate the code for the switch cases.
1074 * @param useTable <tt>true</tt> to use a TABLESWITCH instruction, or <tt>false</tt> to use a
1075 * LOOKUPSWITCH instruction.
1076 */
1077 public void tableSwitch(
1078 final int[] keys, final TableSwitchGenerator generator, final boolean useTable) {
1079 for (int i = 1; i < keys.length; ++i) {
1080 if (keys[i] < keys[i - 1]) {
1081 throw new IllegalArgumentException("keys must be sorted ascending");
1082 }
1083 }
1084 Label def = newLabel();
1085 Label end = newLabel();
1086 if (keys.length > 0) {
1087 int len = keys.length;
1088 int min = keys[0];
1089 int max = keys[len - 1];
1090 int range = max - min + 1;
1091 if (useTable) {
1092 Label[] labels = new Label[range];
1093 Arrays.fill(labels, def);
1094 for (int i = 0; i < len; ++i) {
1095 labels[keys[i] - min] = newLabel();
9751096 }
976 if (type == Type.VOID_TYPE) {
977 push((String) null);
978 } else {
979 Type boxed = getBoxedType(type);
980 invokeStatic(boxed, new Method("valueOf", boxed,
981 new Type[] { type }));
1097 mv.visitTableSwitchInsn(min, max, def, labels);
1098 for (int i = 0; i < range; ++i) {
1099 Label label = labels[i];
1100 if (label != def) {
1101 mark(label);
1102 generator.generateCase(i + min, end);
1103 }
9821104 }
983 }
984
985 /**
986 * Generates the instructions to unbox the top stack value. This value is
987 * replaced by its unboxed equivalent on top of the stack.
988 *
989 * @param type
990 * the type of the top stack value.
991 */
992 public void unbox(final Type type) {
993 Type t = NUMBER_TYPE;
994 Method sig = null;
995 switch (type.getSort()) {
996 case Type.VOID:
997 return;
998 case Type.CHAR:
999 t = CHARACTER_TYPE;
1000 sig = CHAR_VALUE;
1001 break;
1002 case Type.BOOLEAN:
1003 t = BOOLEAN_TYPE;
1004 sig = BOOLEAN_VALUE;
1005 break;
1006 case Type.DOUBLE:
1007 sig = DOUBLE_VALUE;
1008 break;
1009 case Type.FLOAT:
1010 sig = FLOAT_VALUE;
1011 break;
1012 case Type.LONG:
1013 sig = LONG_VALUE;
1014 break;
1015 case Type.INT:
1016 case Type.SHORT:
1017 case Type.BYTE:
1018 sig = INT_VALUE;
1105 } else {
1106 Label[] labels = new Label[len];
1107 for (int i = 0; i < len; ++i) {
1108 labels[i] = newLabel();
10191109 }
1020 if (sig == null) {
1021 checkCast(type);
1022 } else {
1023 checkCast(t);
1024 invokeVirtual(t, sig);
1110 mv.visitLookupSwitchInsn(def, keys, labels);
1111 for (int i = 0; i < len; ++i) {
1112 mark(labels[i]);
1113 generator.generateCase(keys[i], end);
10251114 }
1026 }
1027
1028 // ------------------------------------------------------------------------
1029 // Instructions to jump to other instructions
1030 // ------------------------------------------------------------------------
1031
1032 /**
1033 * Creates a new {@link Label}.
1034 *
1035 * @return a new {@link Label}.
1036 */
1037 public Label newLabel() {
1038 return new Label();
1039 }
1040
1041 /**
1042 * Marks the current code position with the given label.
1043 *
1044 * @param label
1045 * a label.
1046 */
1047 public void mark(final Label label) {
1048 mv.visitLabel(label);
1049 }
1050
1051 /**
1052 * Marks the current code position with a new label.
1053 *
1054 * @return the label that was created to mark the current code position.
1055 */
1056 public Label mark() {
1057 Label label = new Label();
1058 mv.visitLabel(label);
1059 return label;
1060 }
1061
1062 /**
1063 * Generates the instructions to jump to a label based on the comparison of
1064 * the top two stack values.
1065 *
1066 * @param type
1067 * the type of the top two stack values.
1068 * @param mode
1069 * how these values must be compared. One of EQ, NE, LT, GE, GT,
1070 * LE.
1071 * @param label
1072 * where to jump if the comparison result is <tt>true</tt>.
1073 */
1074 public void ifCmp(final Type type, final int mode, final Label label) {
1075 switch (type.getSort()) {
1076 case Type.LONG:
1077 mv.visitInsn(Opcodes.LCMP);
1078 break;
1079 case Type.DOUBLE:
1080 mv.visitInsn(mode == GE || mode == GT ? Opcodes.DCMPL
1081 : Opcodes.DCMPG);
1082 break;
1083 case Type.FLOAT:
1084 mv.visitInsn(mode == GE || mode == GT ? Opcodes.FCMPL
1085 : Opcodes.FCMPG);
1086 break;
1087 case Type.ARRAY:
1088 case Type.OBJECT:
1089 switch (mode) {
1090 case EQ:
1091 mv.visitJumpInsn(Opcodes.IF_ACMPEQ, label);
1092 return;
1093 case NE:
1094 mv.visitJumpInsn(Opcodes.IF_ACMPNE, label);
1095 return;
1096 }
1097 throw new IllegalArgumentException("Bad comparison for type "
1098 + type);
1099 default:
1100 int intOp = -1;
1101 switch (mode) {
1102 case EQ:
1103 intOp = Opcodes.IF_ICMPEQ;
1104 break;
1105 case NE:
1106 intOp = Opcodes.IF_ICMPNE;
1107 break;
1108 case GE:
1109 intOp = Opcodes.IF_ICMPGE;
1110 break;
1111 case LT:
1112 intOp = Opcodes.IF_ICMPLT;
1113 break;
1114 case LE:
1115 intOp = Opcodes.IF_ICMPLE;
1116 break;
1117 case GT:
1118 intOp = Opcodes.IF_ICMPGT;
1119 break;
1120 }
1121 mv.visitJumpInsn(intOp, label);
1122 return;
1123 }
1124 mv.visitJumpInsn(mode, label);
1125 }
1126
1127 /**
1128 * Generates the instructions to jump to a label based on the comparison of
1129 * the top two integer stack values.
1130 *
1131 * @param mode
1132 * how these values must be compared. One of EQ, NE, LT, GE, GT,
1133 * LE.
1134 * @param label
1135 * where to jump if the comparison result is <tt>true</tt>.
1136 */
1137 public void ifICmp(final int mode, final Label label) {
1138 ifCmp(Type.INT_TYPE, mode, label);
1139 }
1140
1141 /**
1142 * Generates the instructions to jump to a label based on the comparison of
1143 * the top integer stack value with zero.
1144 *
1145 * @param mode
1146 * how these values must be compared. One of EQ, NE, LT, GE, GT,
1147 * LE.
1148 * @param label
1149 * where to jump if the comparison result is <tt>true</tt>.
1150 */
1151 public void ifZCmp(final int mode, final Label label) {
1152 mv.visitJumpInsn(mode, label);
1153 }
1154
1155 /**
1156 * Generates the instruction to jump to the given label if the top stack
1157 * value is null.
1158 *
1159 * @param label
1160 * where to jump if the condition is <tt>true</tt>.
1161 */
1162 public void ifNull(final Label label) {
1163 mv.visitJumpInsn(Opcodes.IFNULL, label);
1164 }
1165
1166 /**
1167 * Generates the instruction to jump to the given label if the top stack
1168 * value is not null.
1169 *
1170 * @param label
1171 * where to jump if the condition is <tt>true</tt>.
1172 */
1173 public void ifNonNull(final Label label) {
1174 mv.visitJumpInsn(Opcodes.IFNONNULL, label);
1175 }
1176
1177 /**
1178 * Generates the instruction to jump to the given label.
1179 *
1180 * @param label
1181 * where to jump if the condition is <tt>true</tt>.
1182 */
1183 public void goTo(final Label label) {
1184 mv.visitJumpInsn(Opcodes.GOTO, label);
1185 }
1186
1187 /**
1188 * Generates a RET instruction.
1189 *
1190 * @param local
1191 * a local variable identifier, as returned by
1192 * {@link LocalVariablesSorter#newLocal(Type) newLocal()}.
1193 */
1194 public void ret(final int local) {
1195 mv.visitVarInsn(Opcodes.RET, local);
1196 }
1197
1198 /**
1199 * Generates the instructions for a switch statement.
1200 *
1201 * @param keys
1202 * the switch case keys.
1203 * @param generator
1204 * a generator to generate the code for the switch cases.
1205 */
1206 public void tableSwitch(final int[] keys,
1207 final TableSwitchGenerator generator) {
1208 float density;
1209 if (keys.length == 0) {
1210 density = 0;
1211 } else {
1212 density = (float) keys.length
1213 / (keys[keys.length - 1] - keys[0] + 1);
1214 }
1215 tableSwitch(keys, generator, density >= 0.5f);
1216 }
1217
1218 /**
1219 * Generates the instructions for a switch statement.
1220 *
1221 * @param keys
1222 * the switch case keys.
1223 * @param generator
1224 * a generator to generate the code for the switch cases.
1225 * @param useTable
1226 * <tt>true</tt> to use a TABLESWITCH instruction, or
1227 * <tt>false</tt> to use a LOOKUPSWITCH instruction.
1228 */
1229 public void tableSwitch(final int[] keys,
1230 final TableSwitchGenerator generator, final boolean useTable) {
1231 for (int i = 1; i < keys.length; ++i) {
1232 if (keys[i] < keys[i - 1]) {
1233 throw new IllegalArgumentException(
1234 "keys must be sorted ascending");
1235 }
1236 }
1237 Label def = newLabel();
1238 Label end = newLabel();
1239 if (keys.length > 0) {
1240 int len = keys.length;
1241 int min = keys[0];
1242 int max = keys[len - 1];
1243 int range = max - min + 1;
1244 if (useTable) {
1245 Label[] labels = new Label[range];
1246 Arrays.fill(labels, def);
1247 for (int i = 0; i < len; ++i) {
1248 labels[keys[i] - min] = newLabel();
1249 }
1250 mv.visitTableSwitchInsn(min, max, def, labels);
1251 for (int i = 0; i < range; ++i) {
1252 Label label = labels[i];
1253 if (label != def) {
1254 mark(label);
1255 generator.generateCase(i + min, end);
1256 }
1257 }
1258 } else {
1259 Label[] labels = new Label[len];
1260 for (int i = 0; i < len; ++i) {
1261 labels[i] = newLabel();
1262 }
1263 mv.visitLookupSwitchInsn(def, keys, labels);
1264 for (int i = 0; i < len; ++i) {
1265 mark(labels[i]);
1266 generator.generateCase(keys[i], end);
1267 }
1268 }
1269 }
1270 mark(def);
1271 generator.generateDefault();
1272 mark(end);
1273 }
1274
1275 /**
1276 * Generates the instruction to return the top stack value to the caller.
1277 */
1278 public void returnValue() {
1279 mv.visitInsn(returnType.getOpcode(Opcodes.IRETURN));
1280 }
1281
1282 // ------------------------------------------------------------------------
1283 // Instructions to load and store fields
1284 // ------------------------------------------------------------------------
1285
1286 /**
1287 * Generates a get field or set field instruction.
1288 *
1289 * @param opcode
1290 * the instruction's opcode.
1291 * @param ownerType
1292 * the class in which the field is defined.
1293 * @param name
1294 * the name of the field.
1295 * @param fieldType
1296 * the type of the field.
1297 */
1298 private void fieldInsn(final int opcode, final Type ownerType,
1299 final String name, final Type fieldType) {
1300 mv.visitFieldInsn(opcode, ownerType.getInternalName(), name,
1301 fieldType.getDescriptor());
1302 }
1303
1304 /**
1305 * Generates the instruction to push the value of a static field on the
1306 * stack.
1307 *
1308 * @param owner
1309 * the class in which the field is defined.
1310 * @param name
1311 * the name of the field.
1312 * @param type
1313 * the type of the field.
1314 */
1315 public void getStatic(final Type owner, final String name, final Type type) {
1316 fieldInsn(Opcodes.GETSTATIC, owner, name, type);
1317 }
1318
1319 /**
1320 * Generates the instruction to store the top stack value in a static field.
1321 *
1322 * @param owner
1323 * the class in which the field is defined.
1324 * @param name
1325 * the name of the field.
1326 * @param type
1327 * the type of the field.
1328 */
1329 public void putStatic(final Type owner, final String name, final Type type) {
1330 fieldInsn(Opcodes.PUTSTATIC, owner, name, type);
1331 }
1332
1333 /**
1334 * Generates the instruction to push the value of a non static field on the
1335 * stack.
1336 *
1337 * @param owner
1338 * the class in which the field is defined.
1339 * @param name
1340 * the name of the field.
1341 * @param type
1342 * the type of the field.
1343 */
1344 public void getField(final Type owner, final String name, final Type type) {
1345 fieldInsn(Opcodes.GETFIELD, owner, name, type);
1346 }
1347
1348 /**
1349 * Generates the instruction to store the top stack value in a non static
1350 * field.
1351 *
1352 * @param owner
1353 * the class in which the field is defined.
1354 * @param name
1355 * the name of the field.
1356 * @param type
1357 * the type of the field.
1358 */
1359 public void putField(final Type owner, final String name, final Type type) {
1360 fieldInsn(Opcodes.PUTFIELD, owner, name, type);
1361 }
1362
1363 // ------------------------------------------------------------------------
1364 // Instructions to invoke methods
1365 // ------------------------------------------------------------------------
1366
1367 /**
1368 * Generates an invoke method instruction.
1369 *
1370 * @param opcode
1371 * the instruction's opcode.
1372 * @param type
1373 * the class in which the method is defined.
1374 * @param method
1375 * the method to be invoked.
1376 */
1377 private void invokeInsn(final int opcode, final Type type,
1378 final Method method, final boolean itf) {
1379 String owner = type.getSort() == Type.ARRAY ? type.getDescriptor()
1380 : type.getInternalName();
1381 mv.visitMethodInsn(opcode, owner, method.getName(),
1382 method.getDescriptor(), itf);
1383 }
1384
1385 /**
1386 * Generates the instruction to invoke a normal method.
1387 *
1388 * @param owner
1389 * the class in which the method is defined.
1390 * @param method
1391 * the method to be invoked.
1392 */
1393 public void invokeVirtual(final Type owner, final Method method) {
1394 invokeInsn(Opcodes.INVOKEVIRTUAL, owner, method, false);
1395 }
1396
1397 /**
1398 * Generates the instruction to invoke a constructor.
1399 *
1400 * @param type
1401 * the class in which the constructor is defined.
1402 * @param method
1403 * the constructor to be invoked.
1404 */
1405 public void invokeConstructor(final Type type, final Method method) {
1406 invokeInsn(Opcodes.INVOKESPECIAL, type, method, false);
1407 }
1408
1409 /**
1410 * Generates the instruction to invoke a static method.
1411 *
1412 * @param owner
1413 * the class in which the method is defined.
1414 * @param method
1415 * the method to be invoked.
1416 */
1417 public void invokeStatic(final Type owner, final Method method) {
1418 invokeInsn(Opcodes.INVOKESTATIC, owner, method, false);
1419 }
1420
1421 /**
1422 * Generates the instruction to invoke an interface method.
1423 *
1424 * @param owner
1425 * the class in which the method is defined.
1426 * @param method
1427 * the method to be invoked.
1428 */
1429 public void invokeInterface(final Type owner, final Method method) {
1430 invokeInsn(Opcodes.INVOKEINTERFACE, owner, method, true);
1431 }
1432
1433 /**
1434 * Generates an invokedynamic instruction.
1435 *
1436 * @param name
1437 * the method's name.
1438 * @param desc
1439 * the method's descriptor (see {@link Type Type}).
1440 * @param bsm
1441 * the bootstrap method.
1442 * @param bsmArgs
1443 * the bootstrap method constant arguments. Each argument must be
1444 * an {@link Integer}, {@link Float}, {@link Long},
1445 * {@link Double}, {@link String}, {@link Type} or {@link Handle}
1446 * value. This method is allowed to modify the content of the
1447 * array so a caller should expect that this array may change.
1448 */
1449 public void invokeDynamic(String name, String desc, Handle bsm,
1450 Object... bsmArgs) {
1451 mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
1452 }
1453
1454 // ------------------------------------------------------------------------
1455 // Instructions to create objects and arrays
1456 // ------------------------------------------------------------------------
1457
1458 /**
1459 * Generates a type dependent instruction.
1460 *
1461 * @param opcode
1462 * the instruction's opcode.
1463 * @param type
1464 * the instruction's operand.
1465 */
1466 private void typeInsn(final int opcode, final Type type) {
1467 mv.visitTypeInsn(opcode, type.getInternalName());
1468 }
1469
1470 /**
1471 * Generates the instruction to create a new object.
1472 *
1473 * @param type
1474 * the class of the object to be created.
1475 */
1476 public void newInstance(final Type type) {
1477 typeInsn(Opcodes.NEW, type);
1478 }
1479
1480 /**
1481 * Generates the instruction to create a new array.
1482 *
1483 * @param type
1484 * the type of the array elements.
1485 */
1486 public void newArray(final Type type) {
1487 int typ;
1488 switch (type.getSort()) {
1489 case Type.BOOLEAN:
1490 typ = Opcodes.T_BOOLEAN;
1491 break;
1492 case Type.CHAR:
1493 typ = Opcodes.T_CHAR;
1494 break;
1495 case Type.BYTE:
1496 typ = Opcodes.T_BYTE;
1497 break;
1498 case Type.SHORT:
1499 typ = Opcodes.T_SHORT;
1500 break;
1501 case Type.INT:
1502 typ = Opcodes.T_INT;
1503 break;
1504 case Type.FLOAT:
1505 typ = Opcodes.T_FLOAT;
1506 break;
1507 case Type.LONG:
1508 typ = Opcodes.T_LONG;
1509 break;
1510 case Type.DOUBLE:
1511 typ = Opcodes.T_DOUBLE;
1512 break;
1513 default:
1514 typeInsn(Opcodes.ANEWARRAY, type);
1515 return;
1516 }
1517 mv.visitIntInsn(Opcodes.NEWARRAY, typ);
1518 }
1519
1520 // ------------------------------------------------------------------------
1521 // Miscelaneous instructions
1522 // ------------------------------------------------------------------------
1523
1524 /**
1525 * Generates the instruction to compute the length of an array.
1526 */
1527 public void arrayLength() {
1528 mv.visitInsn(Opcodes.ARRAYLENGTH);
1529 }
1530
1531 /**
1532 * Generates the instruction to throw an exception.
1533 */
1534 public void throwException() {
1535 mv.visitInsn(Opcodes.ATHROW);
1536 }
1537
1538 /**
1539 * Generates the instructions to create and throw an exception. The
1540 * exception class must have a constructor with a single String argument.
1541 *
1542 * @param type
1543 * the class of the exception to be thrown.
1544 * @param msg
1545 * the detailed message of the exception.
1546 */
1547 public void throwException(final Type type, final String msg) {
1548 newInstance(type);
1549 dup();
1550 push(msg);
1551 invokeConstructor(type, Method.getMethod("void <init> (String)"));
1552 throwException();
1553 }
1554
1555 /**
1556 * Generates the instruction to check that the top stack value is of the
1557 * given type.
1558 *
1559 * @param type
1560 * a class or interface type.
1561 */
1562 public void checkCast(final Type type) {
1563 if (!type.equals(OBJECT_TYPE)) {
1564 typeInsn(Opcodes.CHECKCAST, type);
1565 }
1566 }
1567
1568 /**
1569 * Generates the instruction to test if the top stack value is of the given
1570 * type.
1571 *
1572 * @param type
1573 * a class or interface type.
1574 */
1575 public void instanceOf(final Type type) {
1576 typeInsn(Opcodes.INSTANCEOF, type);
1577 }
1578
1579 /**
1580 * Generates the instruction to get the monitor of the top stack value.
1581 */
1582 public void monitorEnter() {
1583 mv.visitInsn(Opcodes.MONITORENTER);
1584 }
1585
1586 /**
1587 * Generates the instruction to release the monitor of the top stack value.
1588 */
1589 public void monitorExit() {
1590 mv.visitInsn(Opcodes.MONITOREXIT);
1591 }
1592
1593 // ------------------------------------------------------------------------
1594 // Non instructions
1595 // ------------------------------------------------------------------------
1596
1597 /**
1598 * Marks the end of the visited method.
1599 */
1600 public void endMethod() {
1601 if ((access & Opcodes.ACC_ABSTRACT) == 0) {
1602 mv.visitMaxs(0, 0);
1603 }
1604 mv.visitEnd();
1605 }
1606
1607 /**
1608 * Marks the start of an exception handler.
1609 *
1610 * @param start
1611 * beginning of the exception handler's scope (inclusive).
1612 * @param end
1613 * end of the exception handler's scope (exclusive).
1614 * @param exception
1615 * internal name of the type of exceptions handled by the
1616 * handler.
1617 */
1618 public void catchException(final Label start, final Label end,
1619 final Type exception) {
1620 Label doCatch = new Label();
1621 if (exception == null) {
1622 mv.visitTryCatchBlock(start, end, doCatch, null);
1623 } else {
1624 mv.visitTryCatchBlock(start, end, doCatch,
1625 exception.getInternalName());
1626 }
1627 mark(doCatch);
1628 }
1115 }
1116 }
1117 mark(def);
1118 generator.generateDefault();
1119 mark(end);
1120 }
1121
1122 /** Generates the instruction to return the top stack value to the caller. */
1123 public void returnValue() {
1124 mv.visitInsn(returnType.getOpcode(Opcodes.IRETURN));
1125 }
1126
1127 // ------------------------------------------------------------------------
1128 // Instructions to load and store fields
1129 // ------------------------------------------------------------------------
1130
1131 /**
1132 * Generates a get field or set field instruction.
1133 *
1134 * @param opcode the instruction's opcode.
1135 * @param ownerType the class in which the field is defined.
1136 * @param name the name of the field.
1137 * @param fieldType the type of the field.
1138 */
1139 private void fieldInsn(
1140 final int opcode, final Type ownerType, final String name, final Type fieldType) {
1141 mv.visitFieldInsn(opcode, ownerType.getInternalName(), name, fieldType.getDescriptor());
1142 }
1143
1144 /**
1145 * Generates the instruction to push the value of a static field on the stack.
1146 *
1147 * @param owner the class in which the field is defined.
1148 * @param name the name of the field.
1149 * @param type the type of the field.
1150 */
1151 public void getStatic(final Type owner, final String name, final Type type) {
1152 fieldInsn(Opcodes.GETSTATIC, owner, name, type);
1153 }
1154
1155 /**
1156 * Generates the instruction to store the top stack value in a static field.
1157 *
1158 * @param owner the class in which the field is defined.
1159 * @param name the name of the field.
1160 * @param type the type of the field.
1161 */
1162 public void putStatic(final Type owner, final String name, final Type type) {
1163 fieldInsn(Opcodes.PUTSTATIC, owner, name, type);
1164 }
1165
1166 /**
1167 * Generates the instruction to push the value of a non static field on the stack.
1168 *
1169 * @param owner the class in which the field is defined.
1170 * @param name the name of the field.
1171 * @param type the type of the field.
1172 */
1173 public void getField(final Type owner, final String name, final Type type) {
1174 fieldInsn(Opcodes.GETFIELD, owner, name, type);
1175 }
1176
1177 /**
1178 * Generates the instruction to store the top stack value in a non static field.
1179 *
1180 * @param owner the class in which the field is defined.
1181 * @param name the name of the field.
1182 * @param type the type of the field.
1183 */
1184 public void putField(final Type owner, final String name, final Type type) {
1185 fieldInsn(Opcodes.PUTFIELD, owner, name, type);
1186 }
1187
1188 // ------------------------------------------------------------------------
1189 // Instructions to invoke methods
1190 // ------------------------------------------------------------------------
1191
1192 /**
1193 * Generates an invoke method instruction.
1194 *
1195 * @param opcode the instruction's opcode.
1196 * @param type the class in which the method is defined.
1197 * @param method the method to be invoked.
1198 * @param itf whether the 'type' class is an interface or not.
1199 */
1200 private void invokeInsn(
1201 final int opcode, final Type type, final Method method, final boolean itf) {
1202 String owner = type.getSort() == Type.ARRAY ? type.getDescriptor() : type.getInternalName();
1203 mv.visitMethodInsn(opcode, owner, method.getName(), method.getDescriptor(), itf);
1204 }
1205
1206 /**
1207 * Generates the instruction to invoke a normal method.
1208 *
1209 * @param owner the class in which the method is defined.
1210 * @param method the method to be invoked.
1211 */
1212 public void invokeVirtual(final Type owner, final Method method) {
1213 invokeInsn(Opcodes.INVOKEVIRTUAL, owner, method, false);
1214 }
1215
1216 /**
1217 * Generates the instruction to invoke a constructor.
1218 *
1219 * @param type the class in which the constructor is defined.
1220 * @param method the constructor to be invoked.
1221 */
1222 public void invokeConstructor(final Type type, final Method method) {
1223 invokeInsn(Opcodes.INVOKESPECIAL, type, method, false);
1224 }
1225
1226 /**
1227 * Generates the instruction to invoke a static method.
1228 *
1229 * @param owner the class in which the method is defined.
1230 * @param method the method to be invoked.
1231 */
1232 public void invokeStatic(final Type owner, final Method method) {
1233 invokeInsn(Opcodes.INVOKESTATIC, owner, method, false);
1234 }
1235
1236 /**
1237 * Generates the instruction to invoke an interface method.
1238 *
1239 * @param owner the class in which the method is defined.
1240 * @param method the method to be invoked.
1241 */
1242 public void invokeInterface(final Type owner, final Method method) {
1243 invokeInsn(Opcodes.INVOKEINTERFACE, owner, method, true);
1244 }
1245
1246 /**
1247 * Generates an invokedynamic instruction.
1248 *
1249 * @param name the method's name.
1250 * @param desc the method's descriptor (see {@link Type Type}).
1251 * @param bsm the bootstrap method.
1252 * @param bsmArgs the bootstrap method constant arguments. Each argument must be an {@link
1253 * Integer}, {@link Float}, {@link Long}, {@link Double}, {@link String}, {@link Type} or
1254 * {@link Handle} value. This method is allowed to modify the content of the array so a caller
1255 * should expect that this array may change.
1256 */
1257 public void invokeDynamic(String name, String desc, Handle bsm, Object... bsmArgs) {
1258 mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
1259 }
1260
1261 // ------------------------------------------------------------------------
1262 // Instructions to create objects and arrays
1263 // ------------------------------------------------------------------------
1264
1265 /**
1266 * Generates a type dependent instruction.
1267 *
1268 * @param opcode the instruction's opcode.
1269 * @param type the instruction's operand.
1270 */
1271 private void typeInsn(final int opcode, final Type type) {
1272 mv.visitTypeInsn(opcode, type.getInternalName());
1273 }
1274
1275 /**
1276 * Generates the instruction to create a new object.
1277 *
1278 * @param type the class of the object to be created.
1279 */
1280 public void newInstance(final Type type) {
1281 typeInsn(Opcodes.NEW, type);
1282 }
1283
1284 /**
1285 * Generates the instruction to create a new array.
1286 *
1287 * @param type the type of the array elements.
1288 */
1289 public void newArray(final Type type) {
1290 int typ;
1291 switch (type.getSort()) {
1292 case Type.BOOLEAN:
1293 typ = Opcodes.T_BOOLEAN;
1294 break;
1295 case Type.CHAR:
1296 typ = Opcodes.T_CHAR;
1297 break;
1298 case Type.BYTE:
1299 typ = Opcodes.T_BYTE;
1300 break;
1301 case Type.SHORT:
1302 typ = Opcodes.T_SHORT;
1303 break;
1304 case Type.INT:
1305 typ = Opcodes.T_INT;
1306 break;
1307 case Type.FLOAT:
1308 typ = Opcodes.T_FLOAT;
1309 break;
1310 case Type.LONG:
1311 typ = Opcodes.T_LONG;
1312 break;
1313 case Type.DOUBLE:
1314 typ = Opcodes.T_DOUBLE;
1315 break;
1316 default:
1317 typeInsn(Opcodes.ANEWARRAY, type);
1318 return;
1319 }
1320 mv.visitIntInsn(Opcodes.NEWARRAY, typ);
1321 }
1322
1323 // ------------------------------------------------------------------------
1324 // Miscelaneous instructions
1325 // ------------------------------------------------------------------------
1326
1327 /** Generates the instruction to compute the length of an array. */
1328 public void arrayLength() {
1329 mv.visitInsn(Opcodes.ARRAYLENGTH);
1330 }
1331
1332 /** Generates the instruction to throw an exception. */
1333 public void throwException() {
1334 mv.visitInsn(Opcodes.ATHROW);
1335 }
1336
1337 /**
1338 * Generates the instructions to create and throw an exception. The exception class must have a
1339 * constructor with a single String argument.
1340 *
1341 * @param type the class of the exception to be thrown.
1342 * @param msg the detailed message of the exception.
1343 */
1344 public void throwException(final Type type, final String msg) {
1345 newInstance(type);
1346 dup();
1347 push(msg);
1348 invokeConstructor(type, Method.getMethod("void <init> (String)"));
1349 throwException();
1350 }
1351
1352 /**
1353 * Generates the instruction to check that the top stack value is of the given type.
1354 *
1355 * @param type a class or interface type.
1356 */
1357 public void checkCast(final Type type) {
1358 if (!type.equals(OBJECT_TYPE)) {
1359 typeInsn(Opcodes.CHECKCAST, type);
1360 }
1361 }
1362
1363 /**
1364 * Generates the instruction to test if the top stack value is of the given type.
1365 *
1366 * @param type a class or interface type.
1367 */
1368 public void instanceOf(final Type type) {
1369 typeInsn(Opcodes.INSTANCEOF, type);
1370 }
1371
1372 /** Generates the instruction to get the monitor of the top stack value. */
1373 public void monitorEnter() {
1374 mv.visitInsn(Opcodes.MONITORENTER);
1375 }
1376
1377 /** Generates the instruction to release the monitor of the top stack value. */
1378 public void monitorExit() {
1379 mv.visitInsn(Opcodes.MONITOREXIT);
1380 }
1381
1382 // ------------------------------------------------------------------------
1383 // Non instructions
1384 // ------------------------------------------------------------------------
1385
1386 /** Marks the end of the visited method. */
1387 public void endMethod() {
1388 if ((access & Opcodes.ACC_ABSTRACT) == 0) {
1389 mv.visitMaxs(0, 0);
1390 }
1391 mv.visitEnd();
1392 }
1393
1394 /**
1395 * Marks the start of an exception handler.
1396 *
1397 * @param start beginning of the exception handler's scope (inclusive).
1398 * @param end end of the exception handler's scope (exclusive).
1399 * @param exception internal name of the type of exceptions handled by the handler.
1400 */
1401 public void catchException(final Label start, final Label end, final Type exception) {
1402 Label doCatch = new Label();
1403 if (exception == null) {
1404 mv.visitTryCatchBlock(start, end, doCatch, null);
1405 } else {
1406 mv.visitTryCatchBlock(start, end, doCatch, exception.getInternalName());
1407 }
1408 mark(doCatch);
1409 }
16291410 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 package org.eclipse.persistence.internal.libraries.asm.commons;
31
32 import org.eclipse.persistence.internal.libraries.asm.Handle;
33 import org.eclipse.persistence.internal.libraries.asm.Label;
34 import org.eclipse.persistence.internal.libraries.asm.MethodVisitor;
35 import org.eclipse.persistence.internal.libraries.asm.Opcodes;
36 import org.eclipse.persistence.internal.libraries.asm.Type;
37
38 /**
39 * A {@link MethodVisitor} providing a more detailed API to generate and
40 * transform instructions.
41 *
42 * @author Eric Bruneton
43 */
44 public class InstructionAdapter extends MethodVisitor {
45
46 public final static Type OBJECT_TYPE = Type.getType("Ljava/lang/Object;");
47
48 /**
49 * Creates a new {@link InstructionAdapter}. <i>Subclasses must not use this
50 * constructor</i>. Instead, they must use the
51 * {@link #InstructionAdapter(int, MethodVisitor)} version.
52 *
53 * @param mv
54 * the method visitor to which this adapter delegates calls.
55 * @throws IllegalStateException
56 * If a subclass calls this constructor.
57 */
58 public InstructionAdapter(final MethodVisitor mv) {
59 this(Opcodes.ASM6, mv);
60 if (getClass() != InstructionAdapter.class) {
61 throw new IllegalStateException();
62 }
63 }
64
65 /**
66 * Creates a new {@link InstructionAdapter}.
67 *
68 * @param api
69 * the ASM API version implemented by this visitor. Must be one
70 * of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
71 * @param mv
72 * the method visitor to which this adapter delegates calls.
73 */
74 protected InstructionAdapter(final int api, final MethodVisitor mv) {
75 super(api, mv);
76 }
77
78 @Override
79 public void visitInsn(final int opcode) {
80 switch (opcode) {
81 case Opcodes.NOP:
82 nop();
83 break;
84 case Opcodes.ACONST_NULL:
85 aconst(null);
86 break;
87 case Opcodes.ICONST_M1:
88 case Opcodes.ICONST_0:
89 case Opcodes.ICONST_1:
90 case Opcodes.ICONST_2:
91 case Opcodes.ICONST_3:
92 case Opcodes.ICONST_4:
93 case Opcodes.ICONST_5:
94 iconst(opcode - Opcodes.ICONST_0);
95 break;
96 case Opcodes.LCONST_0:
97 case Opcodes.LCONST_1:
98 lconst(opcode - Opcodes.LCONST_0);
99 break;
100 case Opcodes.FCONST_0:
101 case Opcodes.FCONST_1:
102 case Opcodes.FCONST_2:
103 fconst(opcode - Opcodes.FCONST_0);
104 break;
105 case Opcodes.DCONST_0:
106 case Opcodes.DCONST_1:
107 dconst(opcode - Opcodes.DCONST_0);
108 break;
109 case Opcodes.IALOAD:
110 aload(Type.INT_TYPE);
111 break;
112 case Opcodes.LALOAD:
113 aload(Type.LONG_TYPE);
114 break;
115 case Opcodes.FALOAD:
116 aload(Type.FLOAT_TYPE);
117 break;
118 case Opcodes.DALOAD:
119 aload(Type.DOUBLE_TYPE);
120 break;
121 case Opcodes.AALOAD:
122 aload(OBJECT_TYPE);
123 break;
124 case Opcodes.BALOAD:
125 aload(Type.BYTE_TYPE);
126 break;
127 case Opcodes.CALOAD:
128 aload(Type.CHAR_TYPE);
129 break;
130 case Opcodes.SALOAD:
131 aload(Type.SHORT_TYPE);
132 break;
133 case Opcodes.IASTORE:
134 astore(Type.INT_TYPE);
135 break;
136 case Opcodes.LASTORE:
137 astore(Type.LONG_TYPE);
138 break;
139 case Opcodes.FASTORE:
140 astore(Type.FLOAT_TYPE);
141 break;
142 case Opcodes.DASTORE:
143 astore(Type.DOUBLE_TYPE);
144 break;
145 case Opcodes.AASTORE:
146 astore(OBJECT_TYPE);
147 break;
148 case Opcodes.BASTORE:
149 astore(Type.BYTE_TYPE);
150 break;
151 case Opcodes.CASTORE:
152 astore(Type.CHAR_TYPE);
153 break;
154 case Opcodes.SASTORE:
155 astore(Type.SHORT_TYPE);
156 break;
157 case Opcodes.POP:
158 pop();
159 break;
160 case Opcodes.POP2:
161 pop2();
162 break;
163 case Opcodes.DUP:
164 dup();
165 break;
166 case Opcodes.DUP_X1:
167 dupX1();
168 break;
169 case Opcodes.DUP_X2:
170 dupX2();
171 break;
172 case Opcodes.DUP2:
173 dup2();
174 break;
175 case Opcodes.DUP2_X1:
176 dup2X1();
177 break;
178 case Opcodes.DUP2_X2:
179 dup2X2();
180 break;
181 case Opcodes.SWAP:
182 swap();
183 break;
184 case Opcodes.IADD:
185 add(Type.INT_TYPE);
186 break;
187 case Opcodes.LADD:
188 add(Type.LONG_TYPE);
189 break;
190 case Opcodes.FADD:
191 add(Type.FLOAT_TYPE);
192 break;
193 case Opcodes.DADD:
194 add(Type.DOUBLE_TYPE);
195 break;
196 case Opcodes.ISUB:
197 sub(Type.INT_TYPE);
198 break;
199 case Opcodes.LSUB:
200 sub(Type.LONG_TYPE);
201 break;
202 case Opcodes.FSUB:
203 sub(Type.FLOAT_TYPE);
204 break;
205 case Opcodes.DSUB:
206 sub(Type.DOUBLE_TYPE);
207 break;
208 case Opcodes.IMUL:
209 mul(Type.INT_TYPE);
210 break;
211 case Opcodes.LMUL:
212 mul(Type.LONG_TYPE);
213 break;
214 case Opcodes.FMUL:
215 mul(Type.FLOAT_TYPE);
216 break;
217 case Opcodes.DMUL:
218 mul(Type.DOUBLE_TYPE);
219 break;
220 case Opcodes.IDIV:
221 div(Type.INT_TYPE);
222 break;
223 case Opcodes.LDIV:
224 div(Type.LONG_TYPE);
225 break;
226 case Opcodes.FDIV:
227 div(Type.FLOAT_TYPE);
228 break;
229 case Opcodes.DDIV:
230 div(Type.DOUBLE_TYPE);
231 break;
232 case Opcodes.IREM:
233 rem(Type.INT_TYPE);
234 break;
235 case Opcodes.LREM:
236 rem(Type.LONG_TYPE);
237 break;
238 case Opcodes.FREM:
239 rem(Type.FLOAT_TYPE);
240 break;
241 case Opcodes.DREM:
242 rem(Type.DOUBLE_TYPE);
243 break;
244 case Opcodes.INEG:
245 neg(Type.INT_TYPE);
246 break;
247 case Opcodes.LNEG:
248 neg(Type.LONG_TYPE);
249 break;
250 case Opcodes.FNEG:
251 neg(Type.FLOAT_TYPE);
252 break;
253 case Opcodes.DNEG:
254 neg(Type.DOUBLE_TYPE);
255 break;
256 case Opcodes.ISHL:
257 shl(Type.INT_TYPE);
258 break;
259 case Opcodes.LSHL:
260 shl(Type.LONG_TYPE);
261 break;
262 case Opcodes.ISHR:
263 shr(Type.INT_TYPE);
264 break;
265 case Opcodes.LSHR:
266 shr(Type.LONG_TYPE);
267 break;
268 case Opcodes.IUSHR:
269 ushr(Type.INT_TYPE);
270 break;
271 case Opcodes.LUSHR:
272 ushr(Type.LONG_TYPE);
273 break;
274 case Opcodes.IAND:
275 and(Type.INT_TYPE);
276 break;
277 case Opcodes.LAND:
278 and(Type.LONG_TYPE);
279 break;
280 case Opcodes.IOR:
281 or(Type.INT_TYPE);
282 break;
283 case Opcodes.LOR:
284 or(Type.LONG_TYPE);
285 break;
286 case Opcodes.IXOR:
287 xor(Type.INT_TYPE);
288 break;
289 case Opcodes.LXOR:
290 xor(Type.LONG_TYPE);
291 break;
292 case Opcodes.I2L:
293 cast(Type.INT_TYPE, Type.LONG_TYPE);
294 break;
295 case Opcodes.I2F:
296 cast(Type.INT_TYPE, Type.FLOAT_TYPE);
297 break;
298 case Opcodes.I2D:
299 cast(Type.INT_TYPE, Type.DOUBLE_TYPE);
300 break;
301 case Opcodes.L2I:
302 cast(Type.LONG_TYPE, Type.INT_TYPE);
303 break;
304 case Opcodes.L2F:
305 cast(Type.LONG_TYPE, Type.FLOAT_TYPE);
306 break;
307 case Opcodes.L2D:
308 cast(Type.LONG_TYPE, Type.DOUBLE_TYPE);
309 break;
310 case Opcodes.F2I:
311 cast(Type.FLOAT_TYPE, Type.INT_TYPE);
312 break;
313 case Opcodes.F2L:
314 cast(Type.FLOAT_TYPE, Type.LONG_TYPE);
315 break;
316 case Opcodes.F2D:
317 cast(Type.FLOAT_TYPE, Type.DOUBLE_TYPE);
318 break;
319 case Opcodes.D2I:
320 cast(Type.DOUBLE_TYPE, Type.INT_TYPE);
321 break;
322 case Opcodes.D2L:
323 cast(Type.DOUBLE_TYPE, Type.LONG_TYPE);
324 break;
325 case Opcodes.D2F:
326 cast(Type.DOUBLE_TYPE, Type.FLOAT_TYPE);
327 break;
328 case Opcodes.I2B:
329 cast(Type.INT_TYPE, Type.BYTE_TYPE);
330 break;
331 case Opcodes.I2C:
332 cast(Type.INT_TYPE, Type.CHAR_TYPE);
333 break;
334 case Opcodes.I2S:
335 cast(Type.INT_TYPE, Type.SHORT_TYPE);
336 break;
337 case Opcodes.LCMP:
338 lcmp();
339 break;
340 case Opcodes.FCMPL:
341 cmpl(Type.FLOAT_TYPE);
342 break;
343 case Opcodes.FCMPG:
344 cmpg(Type.FLOAT_TYPE);
345 break;
346 case Opcodes.DCMPL:
347 cmpl(Type.DOUBLE_TYPE);
348 break;
349 case Opcodes.DCMPG:
350 cmpg(Type.DOUBLE_TYPE);
351 break;
352 case Opcodes.IRETURN:
353 areturn(Type.INT_TYPE);
354 break;
355 case Opcodes.LRETURN:
356 areturn(Type.LONG_TYPE);
357 break;
358 case Opcodes.FRETURN:
359 areturn(Type.FLOAT_TYPE);
360 break;
361 case Opcodes.DRETURN:
362 areturn(Type.DOUBLE_TYPE);
363 break;
364 case Opcodes.ARETURN:
365 areturn(OBJECT_TYPE);
366 break;
367 case Opcodes.RETURN:
368 areturn(Type.VOID_TYPE);
369 break;
370 case Opcodes.ARRAYLENGTH:
371 arraylength();
372 break;
373 case Opcodes.ATHROW:
374 athrow();
375 break;
376 case Opcodes.MONITORENTER:
377 monitorenter();
378 break;
379 case Opcodes.MONITOREXIT:
380 monitorexit();
381 break;
382 default:
383 throw new IllegalArgumentException();
384 }
385 }
386
387 @Override
388 public void visitIntInsn(final int opcode, final int operand) {
389 switch (opcode) {
390 case Opcodes.BIPUSH:
391 iconst(operand);
392 break;
393 case Opcodes.SIPUSH:
394 iconst(operand);
395 break;
396 case Opcodes.NEWARRAY:
397 switch (operand) {
398 case Opcodes.T_BOOLEAN:
399 newarray(Type.BOOLEAN_TYPE);
400 break;
401 case Opcodes.T_CHAR:
402 newarray(Type.CHAR_TYPE);
403 break;
404 case Opcodes.T_BYTE:
405 newarray(Type.BYTE_TYPE);
406 break;
407 case Opcodes.T_SHORT:
408 newarray(Type.SHORT_TYPE);
409 break;
410 case Opcodes.T_INT:
411 newarray(Type.INT_TYPE);
412 break;
413 case Opcodes.T_FLOAT:
414 newarray(Type.FLOAT_TYPE);
415 break;
416 case Opcodes.T_LONG:
417 newarray(Type.LONG_TYPE);
418 break;
419 case Opcodes.T_DOUBLE:
420 newarray(Type.DOUBLE_TYPE);
421 break;
422 default:
423 throw new IllegalArgumentException();
424 }
425 break;
426 default:
427 throw new IllegalArgumentException();
428 }
429 }
430
431 @Override
432 public void visitVarInsn(final int opcode, final int var) {
433 switch (opcode) {
434 case Opcodes.ILOAD:
435 load(var, Type.INT_TYPE);
436 break;
437 case Opcodes.LLOAD:
438 load(var, Type.LONG_TYPE);
439 break;
440 case Opcodes.FLOAD:
441 load(var, Type.FLOAT_TYPE);
442 break;
443 case Opcodes.DLOAD:
444 load(var, Type.DOUBLE_TYPE);
445 break;
446 case Opcodes.ALOAD:
447 load(var, OBJECT_TYPE);
448 break;
449 case Opcodes.ISTORE:
450 store(var, Type.INT_TYPE);
451 break;
452 case Opcodes.LSTORE:
453 store(var, Type.LONG_TYPE);
454 break;
455 case Opcodes.FSTORE:
456 store(var, Type.FLOAT_TYPE);
457 break;
458 case Opcodes.DSTORE:
459 store(var, Type.DOUBLE_TYPE);
460 break;
461 case Opcodes.ASTORE:
462 store(var, OBJECT_TYPE);
463 break;
464 case Opcodes.RET:
465 ret(var);
466 break;
467 default:
468 throw new IllegalArgumentException();
469 }
470 }
471
472 @Override
473 public void visitTypeInsn(final int opcode, final String type) {
474 Type t = Type.getObjectType(type);
475 switch (opcode) {
476 case Opcodes.NEW:
477 anew(t);
478 break;
479 case Opcodes.ANEWARRAY:
480 newarray(t);
481 break;
482 case Opcodes.CHECKCAST:
483 checkcast(t);
484 break;
485 case Opcodes.INSTANCEOF:
486 instanceOf(t);
487 break;
488 default:
489 throw new IllegalArgumentException();
490 }
491 }
492
493 @Override
494 public void visitFieldInsn(final int opcode, final String owner,
495 final String name, final String desc) {
496 switch (opcode) {
497 case Opcodes.GETSTATIC:
498 getstatic(owner, name, desc);
499 break;
500 case Opcodes.PUTSTATIC:
501 putstatic(owner, name, desc);
502 break;
503 case Opcodes.GETFIELD:
504 getfield(owner, name, desc);
505 break;
506 case Opcodes.PUTFIELD:
507 putfield(owner, name, desc);
508 break;
509 default:
510 throw new IllegalArgumentException();
511 }
512 }
513
514 @Deprecated
515 @Override
516 public void visitMethodInsn(final int opcode, final String owner,
517 final String name, final String desc) {
518 if (api >= Opcodes.ASM5) {
519 super.visitMethodInsn(opcode, owner, name, desc);
520 return;
521 }
522 doVisitMethodInsn(opcode, owner, name, desc,
523 opcode == Opcodes.INVOKEINTERFACE);
524 }
525
526 @Override
527 public void visitMethodInsn(final int opcode, final String owner,
528 final String name, final String desc, final boolean itf) {
529 if (api < Opcodes.ASM5) {
530 super.visitMethodInsn(opcode, owner, name, desc, itf);
531 return;
532 }
533 doVisitMethodInsn(opcode, owner, name, desc, itf);
534 }
535
536 private void doVisitMethodInsn(int opcode, final String owner,
537 final String name, final String desc, final boolean itf) {
538 switch (opcode) {
539 case Opcodes.INVOKESPECIAL:
540 invokespecial(owner, name, desc, itf);
541 break;
542 case Opcodes.INVOKEVIRTUAL:
543 invokevirtual(owner, name, desc, itf);
544 break;
545 case Opcodes.INVOKESTATIC:
546 invokestatic(owner, name, desc, itf);
547 break;
548 case Opcodes.INVOKEINTERFACE:
549 invokeinterface(owner, name, desc);
550 break;
551 default:
552 throw new IllegalArgumentException();
553 }
554 }
555
556 @Override
557 public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
558 Object... bsmArgs) {
559 invokedynamic(name, desc, bsm, bsmArgs);
560 }
561
562 @Override
563 public void visitJumpInsn(final int opcode, final Label label) {
564 switch (opcode) {
565 case Opcodes.IFEQ:
566 ifeq(label);
567 break;
568 case Opcodes.IFNE:
569 ifne(label);
570 break;
571 case Opcodes.IFLT:
572 iflt(label);
573 break;
574 case Opcodes.IFGE:
575 ifge(label);
576 break;
577 case Opcodes.IFGT:
578 ifgt(label);
579 break;
580 case Opcodes.IFLE:
581 ifle(label);
582 break;
583 case Opcodes.IF_ICMPEQ:
584 ificmpeq(label);
585 break;
586 case Opcodes.IF_ICMPNE:
587 ificmpne(label);
588 break;
589 case Opcodes.IF_ICMPLT:
590 ificmplt(label);
591 break;
592 case Opcodes.IF_ICMPGE:
593 ificmpge(label);
594 break;
595 case Opcodes.IF_ICMPGT:
596 ificmpgt(label);
597 break;
598 case Opcodes.IF_ICMPLE:
599 ificmple(label);
600 break;
601 case Opcodes.IF_ACMPEQ:
602 ifacmpeq(label);
603 break;
604 case Opcodes.IF_ACMPNE:
605 ifacmpne(label);
606 break;
607 case Opcodes.GOTO:
608 goTo(label);
609 break;
610 case Opcodes.JSR:
611 jsr(label);
612 break;
613 case Opcodes.IFNULL:
614 ifnull(label);
615 break;
616 case Opcodes.IFNONNULL:
617 ifnonnull(label);
618 break;
619 default:
620 throw new IllegalArgumentException();
621 }
622 }
623
624 @Override
625 public void visitLabel(final Label label) {
626 mark(label);
627 }
628
629 @Override
630 public void visitLdcInsn(final Object cst) {
631 if (cst instanceof Integer) {
632 int val = ((Integer) cst).intValue();
633 iconst(val);
634 } else if (cst instanceof Byte) {
635 int val = ((Byte) cst).intValue();
636 iconst(val);
637 } else if (cst instanceof Character) {
638 int val = ((Character) cst).charValue();
639 iconst(val);
640 } else if (cst instanceof Short) {
641 int val = ((Short) cst).intValue();
642 iconst(val);
643 } else if (cst instanceof Boolean) {
644 int val = ((Boolean) cst).booleanValue() ? 1 : 0;
645 iconst(val);
646 } else if (cst instanceof Float) {
647 float val = ((Float) cst).floatValue();
648 fconst(val);
649 } else if (cst instanceof Long) {
650 long val = ((Long) cst).longValue();
651 lconst(val);
652 } else if (cst instanceof Double) {
653 double val = ((Double) cst).doubleValue();
654 dconst(val);
655 } else if (cst instanceof String) {
656 aconst(cst);
657 } else if (cst instanceof Type) {
658 tconst((Type) cst);
659 } else if (cst instanceof Handle) {
660 hconst((Handle) cst);
661 } else {
662 throw new IllegalArgumentException();
663 }
664 }
665
666 @Override
667 public void visitIincInsn(final int var, final int increment) {
668 iinc(var, increment);
669 }
670
671 @Override
672 public void visitTableSwitchInsn(final int min, final int max,
673 final Label dflt, final Label... labels) {
674 tableswitch(min, max, dflt, labels);
675 }
676
677 @Override
678 public void visitLookupSwitchInsn(final Label dflt, final int[] keys,
679 final Label[] labels) {
680 lookupswitch(dflt, keys, labels);
681 }
682
683 @Override
684 public void visitMultiANewArrayInsn(final String desc, final int dims) {
685 multianewarray(desc, dims);
686 }
687
688 // -----------------------------------------------------------------------
689
690 public void nop() {
691 mv.visitInsn(Opcodes.NOP);
692 }
693
694 public void aconst(final Object cst) {
695 if (cst == null) {
696 mv.visitInsn(Opcodes.ACONST_NULL);
697 } else {
698 mv.visitLdcInsn(cst);
699 }
700 }
701
702 public void iconst(final int cst) {
703 if (cst >= -1 && cst <= 5) {
704 mv.visitInsn(Opcodes.ICONST_0 + cst);
705 } else if (cst >= Byte.MIN_VALUE && cst <= Byte.MAX_VALUE) {
706 mv.visitIntInsn(Opcodes.BIPUSH, cst);
707 } else if (cst >= Short.MIN_VALUE && cst <= Short.MAX_VALUE) {
708 mv.visitIntInsn(Opcodes.SIPUSH, cst);
709 } else {
710 mv.visitLdcInsn(cst);
711 }
712 }
713
714 public void lconst(final long cst) {
715 if (cst == 0L || cst == 1L) {
716 mv.visitInsn(Opcodes.LCONST_0 + (int) cst);
717 } else {
718 mv.visitLdcInsn(cst);
719 }
720 }
721
722 public void fconst(final float cst) {
723 int bits = Float.floatToIntBits(cst);
724 if (bits == 0L || bits == 0x3f800000 || bits == 0x40000000) { // 0..2
725 mv.visitInsn(Opcodes.FCONST_0 + (int) cst);
726 } else {
727 mv.visitLdcInsn(cst);
728 }
729 }
730
731 public void dconst(final double cst) {
732 long bits = Double.doubleToLongBits(cst);
733 if (bits == 0L || bits == 0x3ff0000000000000L) { // +0.0d and 1.0d
734 mv.visitInsn(Opcodes.DCONST_0 + (int) cst);
735 } else {
736 mv.visitLdcInsn(cst);
737 }
738 }
739
740 public void tconst(final Type type) {
741 mv.visitLdcInsn(type);
742 }
743
744 public void hconst(final Handle handle) {
745 mv.visitLdcInsn(handle);
746 }
747
748 public void load(final int var, final Type type) {
749 mv.visitVarInsn(type.getOpcode(Opcodes.ILOAD), var);
750 }
751
752 public void aload(final Type type) {
753 mv.visitInsn(type.getOpcode(Opcodes.IALOAD));
754 }
755
756 public void store(final int var, final Type type) {
757 mv.visitVarInsn(type.getOpcode(Opcodes.ISTORE), var);
758 }
759
760 public void astore(final Type type) {
761 mv.visitInsn(type.getOpcode(Opcodes.IASTORE));
762 }
763
764 public void pop() {
765 mv.visitInsn(Opcodes.POP);
766 }
767
768 public void pop2() {
769 mv.visitInsn(Opcodes.POP2);
770 }
771
772 public void dup() {
773 mv.visitInsn(Opcodes.DUP);
774 }
775
776 public void dup2() {
777 mv.visitInsn(Opcodes.DUP2);
778 }
779
780 public void dupX1() {
781 mv.visitInsn(Opcodes.DUP_X1);
782 }
783
784 public void dupX2() {
785 mv.visitInsn(Opcodes.DUP_X2);
786 }
787
788 public void dup2X1() {
789 mv.visitInsn(Opcodes.DUP2_X1);
790 }
791
792 public void dup2X2() {
793 mv.visitInsn(Opcodes.DUP2_X2);
794 }
795
796 public void swap() {
797 mv.visitInsn(Opcodes.SWAP);
798 }
799
800 public void add(final Type type) {
801 mv.visitInsn(type.getOpcode(Opcodes.IADD));
802 }
803
804 public void sub(final Type type) {
805 mv.visitInsn(type.getOpcode(Opcodes.ISUB));
806 }
807
808 public void mul(final Type type) {
809 mv.visitInsn(type.getOpcode(Opcodes.IMUL));
810 }
811
812 public void div(final Type type) {
813 mv.visitInsn(type.getOpcode(Opcodes.IDIV));
814 }
815
816 public void rem(final Type type) {
817 mv.visitInsn(type.getOpcode(Opcodes.IREM));
818 }
819
820 public void neg(final Type type) {
821 mv.visitInsn(type.getOpcode(Opcodes.INEG));
822 }
823
824 public void shl(final Type type) {
825 mv.visitInsn(type.getOpcode(Opcodes.ISHL));
826 }
827
828 public void shr(final Type type) {
829 mv.visitInsn(type.getOpcode(Opcodes.ISHR));
830 }
831
832 public void ushr(final Type type) {
833 mv.visitInsn(type.getOpcode(Opcodes.IUSHR));
834 }
835
836 public void and(final Type type) {
837 mv.visitInsn(type.getOpcode(Opcodes.IAND));
838 }
839
840 public void or(final Type type) {
841 mv.visitInsn(type.getOpcode(Opcodes.IOR));
842 }
843
844 public void xor(final Type type) {
845 mv.visitInsn(type.getOpcode(Opcodes.IXOR));
846 }
847
848 public void iinc(final int var, final int increment) {
849 mv.visitIincInsn(var, increment);
850 }
851
852 public void cast(final Type from, final Type to) {
853 if (from != to) {
854 if (from == Type.DOUBLE_TYPE) {
855 if (to == Type.FLOAT_TYPE) {
856 mv.visitInsn(Opcodes.D2F);
857 } else if (to == Type.LONG_TYPE) {
858 mv.visitInsn(Opcodes.D2L);
859 } else {
860 mv.visitInsn(Opcodes.D2I);
861 cast(Type.INT_TYPE, to);
862 }
863 } else if (from == Type.FLOAT_TYPE) {
864 if (to == Type.DOUBLE_TYPE) {
865 mv.visitInsn(Opcodes.F2D);
866 } else if (to == Type.LONG_TYPE) {
867 mv.visitInsn(Opcodes.F2L);
868 } else {
869 mv.visitInsn(Opcodes.F2I);
870 cast(Type.INT_TYPE, to);
871 }
872 } else if (from == Type.LONG_TYPE) {
873 if (to == Type.DOUBLE_TYPE) {
874 mv.visitInsn(Opcodes.L2D);
875 } else if (to == Type.FLOAT_TYPE) {
876 mv.visitInsn(Opcodes.L2F);
877 } else {
878 mv.visitInsn(Opcodes.L2I);
879 cast(Type.INT_TYPE, to);
880 }
881 } else {
882 if (to == Type.BYTE_TYPE) {
883 mv.visitInsn(Opcodes.I2B);
884 } else if (to == Type.CHAR_TYPE) {
885 mv.visitInsn(Opcodes.I2C);
886 } else if (to == Type.DOUBLE_TYPE) {
887 mv.visitInsn(Opcodes.I2D);
888 } else if (to == Type.FLOAT_TYPE) {
889 mv.visitInsn(Opcodes.I2F);
890 } else if (to == Type.LONG_TYPE) {
891 mv.visitInsn(Opcodes.I2L);
892 } else if (to == Type.SHORT_TYPE) {
893 mv.visitInsn(Opcodes.I2S);
894 }
895 }
896 }
897 }
898
899 public void lcmp() {
900 mv.visitInsn(Opcodes.LCMP);
901 }
902
903 public void cmpl(final Type type) {
904 mv.visitInsn(type == Type.FLOAT_TYPE ? Opcodes.FCMPL : Opcodes.DCMPL);
905 }
906
907 public void cmpg(final Type type) {
908 mv.visitInsn(type == Type.FLOAT_TYPE ? Opcodes.FCMPG : Opcodes.DCMPG);
909 }
910
911 public void ifeq(final Label label) {
912 mv.visitJumpInsn(Opcodes.IFEQ, label);
913 }
914
915 public void ifne(final Label label) {
916 mv.visitJumpInsn(Opcodes.IFNE, label);
917 }
918
919 public void iflt(final Label label) {
920 mv.visitJumpInsn(Opcodes.IFLT, label);
921 }
922
923 public void ifge(final Label label) {
924 mv.visitJumpInsn(Opcodes.IFGE, label);
925 }
926
927 public void ifgt(final Label label) {
928 mv.visitJumpInsn(Opcodes.IFGT, label);
929 }
930
931 public void ifle(final Label label) {
932 mv.visitJumpInsn(Opcodes.IFLE, label);
933 }
934
935 public void ificmpeq(final Label label) {
936 mv.visitJumpInsn(Opcodes.IF_ICMPEQ, label);
937 }
938
939 public void ificmpne(final Label label) {
940 mv.visitJumpInsn(Opcodes.IF_ICMPNE, label);
941 }
942
943 public void ificmplt(final Label label) {
944 mv.visitJumpInsn(Opcodes.IF_ICMPLT, label);
945 }
946
947 public void ificmpge(final Label label) {
948 mv.visitJumpInsn(Opcodes.IF_ICMPGE, label);
949 }
950
951 public void ificmpgt(final Label label) {
952 mv.visitJumpInsn(Opcodes.IF_ICMPGT, label);
953 }
954
955 public void ificmple(final Label label) {
956 mv.visitJumpInsn(Opcodes.IF_ICMPLE, label);
957 }
958
959 public void ifacmpeq(final Label label) {
960 mv.visitJumpInsn(Opcodes.IF_ACMPEQ, label);
961 }
962
963 public void ifacmpne(final Label label) {
964 mv.visitJumpInsn(Opcodes.IF_ACMPNE, label);
965 }
966
967 public void goTo(final Label label) {
968 mv.visitJumpInsn(Opcodes.GOTO, label);
969 }
970
971 public void jsr(final Label label) {
972 mv.visitJumpInsn(Opcodes.JSR, label);
973 }
974
975 public void ret(final int var) {
976 mv.visitVarInsn(Opcodes.RET, var);
977 }
978
979 public void tableswitch(final int min, final int max, final Label dflt,
980 final Label... labels) {
981 mv.visitTableSwitchInsn(min, max, dflt, labels);
982 }
983
984 public void lookupswitch(final Label dflt, final int[] keys,
985 final Label[] labels) {
986 mv.visitLookupSwitchInsn(dflt, keys, labels);
987 }
988
989 public void areturn(final Type t) {
990 mv.visitInsn(t.getOpcode(Opcodes.IRETURN));
991 }
992
993 public void getstatic(final String owner, final String name,
994 final String desc) {
995 mv.visitFieldInsn(Opcodes.GETSTATIC, owner, name, desc);
996 }
997
998 public void putstatic(final String owner, final String name,
999 final String desc) {
1000 mv.visitFieldInsn(Opcodes.PUTSTATIC, owner, name, desc);
1001 }
1002
1003 public void getfield(final String owner, final String name,
1004 final String desc) {
1005 mv.visitFieldInsn(Opcodes.GETFIELD, owner, name, desc);
1006 }
1007
1008 public void putfield(final String owner, final String name,
1009 final String desc) {
1010 mv.visitFieldInsn(Opcodes.PUTFIELD, owner, name, desc);
1011 }
1012
1013 @Deprecated
1014 public void invokevirtual(final String owner, final String name,
1015 final String desc) {
1016 if (api >= Opcodes.ASM5) {
1017 invokevirtual(owner, name, desc, false);
1018 return;
1019 }
1020 mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, name, desc);
1021 }
1022
1023 public void invokevirtual(final String owner, final String name,
1024 final String desc, final boolean itf) {
1025 if (api < Opcodes.ASM5) {
1026 if (itf) {
1027 throw new IllegalArgumentException(
1028 "INVOKEVIRTUAL on interfaces require ASM 5");
1029 }
1030 invokevirtual(owner, name, desc);
1031 return;
1032 }
1033 mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, name, desc, itf);
1034 }
1035
1036 @Deprecated
1037 public void invokespecial(final String owner, final String name,
1038 final String desc) {
1039 if (api >= Opcodes.ASM5) {
1040 invokespecial(owner, name, desc, false);
1041 return;
1042 }
1043 mv.visitMethodInsn(Opcodes.INVOKESPECIAL, owner, name, desc, false);
1044 }
1045
1046 public void invokespecial(final String owner, final String name,
1047 final String desc, final boolean itf) {
1048 if (api < Opcodes.ASM5) {
1049 if (itf) {
1050 throw new IllegalArgumentException(
1051 "INVOKESPECIAL on interfaces require ASM 5");
1052 }
1053 invokespecial(owner, name, desc);
1054 return;
1055 }
1056 mv.visitMethodInsn(Opcodes.INVOKESPECIAL, owner, name, desc, itf);
1057 }
1058
1059 @Deprecated
1060 public void invokestatic(final String owner, final String name,
1061 final String desc) {
1062 if (api >= Opcodes.ASM5) {
1063 invokestatic(owner, name, desc, false);
1064 return;
1065 }
1066 mv.visitMethodInsn(Opcodes.INVOKESTATIC, owner, name, desc, false);
1067 }
1068
1069 public void invokestatic(final String owner, final String name,
1070 final String desc, final boolean itf) {
1071 if (api < Opcodes.ASM5) {
1072 if (itf) {
1073 throw new IllegalArgumentException(
1074 "INVOKESTATIC on interfaces require ASM 5");
1075 }
1076 invokestatic(owner, name, desc);
1077 return;
1078 }
1079 mv.visitMethodInsn(Opcodes.INVOKESTATIC, owner, name, desc, itf);
1080 }
1081
1082 public void invokeinterface(final String owner, final String name,
1083 final String desc) {
1084 mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, owner, name, desc, true);
1085 }
1086
1087 public void invokedynamic(String name, String desc, Handle bsm,
1088 Object[] bsmArgs) {
1089 mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
1090 }
1091
1092 public void anew(final Type type) {
1093 mv.visitTypeInsn(Opcodes.NEW, type.getInternalName());
1094 }
1095
1096 public void newarray(final Type type) {
1097 int typ;
1098 switch (type.getSort()) {
1099 case Type.BOOLEAN:
1100 typ = Opcodes.T_BOOLEAN;
1101 break;
1102 case Type.CHAR:
1103 typ = Opcodes.T_CHAR;
1104 break;
1105 case Type.BYTE:
1106 typ = Opcodes.T_BYTE;
1107 break;
1108 case Type.SHORT:
1109 typ = Opcodes.T_SHORT;
1110 break;
1111 case Type.INT:
1112 typ = Opcodes.T_INT;
1113 break;
1114 case Type.FLOAT:
1115 typ = Opcodes.T_FLOAT;
1116 break;
1117 case Type.LONG:
1118 typ = Opcodes.T_LONG;
1119 break;
1120 case Type.DOUBLE:
1121 typ = Opcodes.T_DOUBLE;
1122 break;
1123 default:
1124 mv.visitTypeInsn(Opcodes.ANEWARRAY, type.getInternalName());
1125 return;
1126 }
1127 mv.visitIntInsn(Opcodes.NEWARRAY, typ);
1128 }
1129
1130 public void arraylength() {
1131 mv.visitInsn(Opcodes.ARRAYLENGTH);
1132 }
1133
1134 public void athrow() {
1135 mv.visitInsn(Opcodes.ATHROW);
1136 }
1137
1138 public void checkcast(final Type type) {
1139 mv.visitTypeInsn(Opcodes.CHECKCAST, type.getInternalName());
1140 }
1141
1142 public void instanceOf(final Type type) {
1143 mv.visitTypeInsn(Opcodes.INSTANCEOF, type.getInternalName());
1144 }
1145
1146 public void monitorenter() {
1147 mv.visitInsn(Opcodes.MONITORENTER);
1148 }
1149
1150 public void monitorexit() {
1151 mv.visitInsn(Opcodes.MONITOREXIT);
1152 }
1153
1154 public void multianewarray(final String desc, final int dims) {
1155 mv.visitMultiANewArrayInsn(desc, dims);
1156 }
1157
1158 public void ifnull(final Label label) {
1159 mv.visitJumpInsn(Opcodes.IFNULL, label);
1160 }
1161
1162 public void ifnonnull(final Label label) {
1163 mv.visitJumpInsn(Opcodes.IFNONNULL, label);
1164 }
1165
1166 public void mark(final Label label) {
1167 mv.visitLabel(label);
1168 }
1169 }
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
27
28 package org.eclipse.persistence.internal.libraries.asm.commons;
29
30 import org.eclipse.persistence.internal.libraries.asm.Handle;
31 import org.eclipse.persistence.internal.libraries.asm.Label;
32 import org.eclipse.persistence.internal.libraries.asm.MethodVisitor;
33 import org.eclipse.persistence.internal.libraries.asm.Opcodes;
34 import org.eclipse.persistence.internal.libraries.asm.Type;
35
36 /**
37 * A {@link MethodVisitor} providing a more detailed API to generate and transform instructions.
38 *
39 * @author Eric Bruneton
40 */
41 public class InstructionAdapter extends MethodVisitor {
42
43 public static final Type OBJECT_TYPE = Type.getType("Ljava/lang/Object;");
44
45 /**
46 * Constructs a new {@link InstructionAdapter}. <i>Subclasses must not use this constructor</i>.
47 * Instead, they must use the {@link #InstructionAdapter(int, MethodVisitor)} version.
48 *
49 * @param mv the method visitor to which this adapter delegates calls.
50 * @throws IllegalStateException If a subclass calls this constructor.
51 */
52 public InstructionAdapter(final MethodVisitor mv) {
53 this(Opcodes.ASM6, mv);
54 if (getClass() != InstructionAdapter.class) {
55 throw new IllegalStateException();
56 }
57 }
58
59 /**
60 * Constructs a new {@link InstructionAdapter}.
61 *
62 * @param api the ASM API version implemented by this visitor. Must be one of {@link
63 * Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
64 * @param mv the method visitor to which this adapter delegates calls.
65 */
66 protected InstructionAdapter(final int api, final MethodVisitor mv) {
67 super(api, mv);
68 }
69
70 @Override
71 public void visitInsn(final int opcode) {
72 switch (opcode) {
73 case Opcodes.NOP:
74 nop();
75 break;
76 case Opcodes.ACONST_NULL:
77 aconst(null);
78 break;
79 case Opcodes.ICONST_M1:
80 case Opcodes.ICONST_0:
81 case Opcodes.ICONST_1:
82 case Opcodes.ICONST_2:
83 case Opcodes.ICONST_3:
84 case Opcodes.ICONST_4:
85 case Opcodes.ICONST_5:
86 iconst(opcode - Opcodes.ICONST_0);
87 break;
88 case Opcodes.LCONST_0:
89 case Opcodes.LCONST_1:
90 lconst(opcode - Opcodes.LCONST_0);
91 break;
92 case Opcodes.FCONST_0:
93 case Opcodes.FCONST_1:
94 case Opcodes.FCONST_2:
95 fconst(opcode - Opcodes.FCONST_0);
96 break;
97 case Opcodes.DCONST_0:
98 case Opcodes.DCONST_1:
99 dconst(opcode - Opcodes.DCONST_0);
100 break;
101 case Opcodes.IALOAD:
102 aload(Type.INT_TYPE);
103 break;
104 case Opcodes.LALOAD:
105 aload(Type.LONG_TYPE);
106 break;
107 case Opcodes.FALOAD:
108 aload(Type.FLOAT_TYPE);
109 break;
110 case Opcodes.DALOAD:
111 aload(Type.DOUBLE_TYPE);
112 break;
113 case Opcodes.AALOAD:
114 aload(OBJECT_TYPE);
115 break;
116 case Opcodes.BALOAD:
117 aload(Type.BYTE_TYPE);
118 break;
119 case Opcodes.CALOAD:
120 aload(Type.CHAR_TYPE);
121 break;
122 case Opcodes.SALOAD:
123 aload(Type.SHORT_TYPE);
124 break;
125 case Opcodes.IASTORE:
126 astore(Type.INT_TYPE);
127 break;
128 case Opcodes.LASTORE:
129 astore(Type.LONG_TYPE);
130 break;
131 case Opcodes.FASTORE:
132 astore(Type.FLOAT_TYPE);
133 break;
134 case Opcodes.DASTORE:
135 astore(Type.DOUBLE_TYPE);
136 break;
137 case Opcodes.AASTORE:
138 astore(OBJECT_TYPE);
139 break;
140 case Opcodes.BASTORE:
141 astore(Type.BYTE_TYPE);
142 break;
143 case Opcodes.CASTORE:
144 astore(Type.CHAR_TYPE);
145 break;
146 case Opcodes.SASTORE:
147 astore(Type.SHORT_TYPE);
148 break;
149 case Opcodes.POP:
150 pop();
151 break;
152 case Opcodes.POP2:
153 pop2();
154 break;
155 case Opcodes.DUP:
156 dup();
157 break;
158 case Opcodes.DUP_X1:
159 dupX1();
160 break;
161 case Opcodes.DUP_X2:
162 dupX2();
163 break;
164 case Opcodes.DUP2:
165 dup2();
166 break;
167 case Opcodes.DUP2_X1:
168 dup2X1();
169 break;
170 case Opcodes.DUP2_X2:
171 dup2X2();
172 break;
173 case Opcodes.SWAP:
174 swap();
175 break;
176 case Opcodes.IADD:
177 add(Type.INT_TYPE);
178 break;
179 case Opcodes.LADD:
180 add(Type.LONG_TYPE);
181 break;
182 case Opcodes.FADD:
183 add(Type.FLOAT_TYPE);
184 break;
185 case Opcodes.DADD:
186 add(Type.DOUBLE_TYPE);
187 break;
188 case Opcodes.ISUB:
189 sub(Type.INT_TYPE);
190 break;
191 case Opcodes.LSUB:
192 sub(Type.LONG_TYPE);
193 break;
194 case Opcodes.FSUB:
195 sub(Type.FLOAT_TYPE);
196 break;
197 case Opcodes.DSUB:
198 sub(Type.DOUBLE_TYPE);
199 break;
200 case Opcodes.IMUL:
201 mul(Type.INT_TYPE);
202 break;
203 case Opcodes.LMUL:
204 mul(Type.LONG_TYPE);
205 break;
206 case Opcodes.FMUL:
207 mul(Type.FLOAT_TYPE);
208 break;
209 case Opcodes.DMUL:
210 mul(Type.DOUBLE_TYPE);
211 break;
212 case Opcodes.IDIV:
213 div(Type.INT_TYPE);
214 break;
215 case Opcodes.LDIV:
216 div(Type.LONG_TYPE);
217 break;
218 case Opcodes.FDIV:
219 div(Type.FLOAT_TYPE);
220 break;
221 case Opcodes.DDIV:
222 div(Type.DOUBLE_TYPE);
223 break;
224 case Opcodes.IREM:
225 rem(Type.INT_TYPE);
226 break;
227 case Opcodes.LREM:
228 rem(Type.LONG_TYPE);
229 break;
230 case Opcodes.FREM:
231 rem(Type.FLOAT_TYPE);
232 break;
233 case Opcodes.DREM:
234 rem(Type.DOUBLE_TYPE);
235 break;
236 case Opcodes.INEG:
237 neg(Type.INT_TYPE);
238 break;
239 case Opcodes.LNEG:
240 neg(Type.LONG_TYPE);
241 break;
242 case Opcodes.FNEG:
243 neg(Type.FLOAT_TYPE);
244 break;
245 case Opcodes.DNEG:
246 neg(Type.DOUBLE_TYPE);
247 break;
248 case Opcodes.ISHL:
249 shl(Type.INT_TYPE);
250 break;
251 case Opcodes.LSHL:
252 shl(Type.LONG_TYPE);
253 break;
254 case Opcodes.ISHR:
255 shr(Type.INT_TYPE);
256 break;
257 case Opcodes.LSHR:
258 shr(Type.LONG_TYPE);
259 break;
260 case Opcodes.IUSHR:
261 ushr(Type.INT_TYPE);
262 break;
263 case Opcodes.LUSHR:
264 ushr(Type.LONG_TYPE);
265 break;
266 case Opcodes.IAND:
267 and(Type.INT_TYPE);
268 break;
269 case Opcodes.LAND:
270 and(Type.LONG_TYPE);
271 break;
272 case Opcodes.IOR:
273 or(Type.INT_TYPE);
274 break;
275 case Opcodes.LOR:
276 or(Type.LONG_TYPE);
277 break;
278 case Opcodes.IXOR:
279 xor(Type.INT_TYPE);
280 break;
281 case Opcodes.LXOR:
282 xor(Type.LONG_TYPE);
283 break;
284 case Opcodes.I2L:
285 cast(Type.INT_TYPE, Type.LONG_TYPE);
286 break;
287 case Opcodes.I2F:
288 cast(Type.INT_TYPE, Type.FLOAT_TYPE);
289 break;
290 case Opcodes.I2D:
291 cast(Type.INT_TYPE, Type.DOUBLE_TYPE);
292 break;
293 case Opcodes.L2I:
294 cast(Type.LONG_TYPE, Type.INT_TYPE);
295 break;
296 case Opcodes.L2F:
297 cast(Type.LONG_TYPE, Type.FLOAT_TYPE);
298 break;
299 case Opcodes.L2D:
300 cast(Type.LONG_TYPE, Type.DOUBLE_TYPE);
301 break;
302 case Opcodes.F2I:
303 cast(Type.FLOAT_TYPE, Type.INT_TYPE);
304 break;
305 case Opcodes.F2L:
306 cast(Type.FLOAT_TYPE, Type.LONG_TYPE);
307 break;
308 case Opcodes.F2D:
309 cast(Type.FLOAT_TYPE, Type.DOUBLE_TYPE);
310 break;
311 case Opcodes.D2I:
312 cast(Type.DOUBLE_TYPE, Type.INT_TYPE);
313 break;
314 case Opcodes.D2L:
315 cast(Type.DOUBLE_TYPE, Type.LONG_TYPE);
316 break;
317 case Opcodes.D2F:
318 cast(Type.DOUBLE_TYPE, Type.FLOAT_TYPE);
319 break;
320 case Opcodes.I2B:
321 cast(Type.INT_TYPE, Type.BYTE_TYPE);
322 break;
323 case Opcodes.I2C:
324 cast(Type.INT_TYPE, Type.CHAR_TYPE);
325 break;
326 case Opcodes.I2S:
327 cast(Type.INT_TYPE, Type.SHORT_TYPE);
328 break;
329 case Opcodes.LCMP:
330 lcmp();
331 break;
332 case Opcodes.FCMPL:
333 cmpl(Type.FLOAT_TYPE);
334 break;
335 case Opcodes.FCMPG:
336 cmpg(Type.FLOAT_TYPE);
337 break;
338 case Opcodes.DCMPL:
339 cmpl(Type.DOUBLE_TYPE);
340 break;
341 case Opcodes.DCMPG:
342 cmpg(Type.DOUBLE_TYPE);
343 break;
344 case Opcodes.IRETURN:
345 areturn(Type.INT_TYPE);
346 break;
347 case Opcodes.LRETURN:
348 areturn(Type.LONG_TYPE);
349 break;
350 case Opcodes.FRETURN:
351 areturn(Type.FLOAT_TYPE);
352 break;
353 case Opcodes.DRETURN:
354 areturn(Type.DOUBLE_TYPE);
355 break;
356 case Opcodes.ARETURN:
357 areturn(OBJECT_TYPE);
358 break;
359 case Opcodes.RETURN:
360 areturn(Type.VOID_TYPE);
361 break;
362 case Opcodes.ARRAYLENGTH:
363 arraylength();
364 break;
365 case Opcodes.ATHROW:
366 athrow();
367 break;
368 case Opcodes.MONITORENTER:
369 monitorenter();
370 break;
371 case Opcodes.MONITOREXIT:
372 monitorexit();
373 break;
374 default:
375 throw new IllegalArgumentException();
376 }
377 }
378
379 @Override
380 public void visitIntInsn(final int opcode, final int operand) {
381 switch (opcode) {
382 case Opcodes.BIPUSH:
383 iconst(operand);
384 break;
385 case Opcodes.SIPUSH:
386 iconst(operand);
387 break;
388 case Opcodes.NEWARRAY:
389 switch (operand) {
390 case Opcodes.T_BOOLEAN:
391 newarray(Type.BOOLEAN_TYPE);
392 break;
393 case Opcodes.T_CHAR:
394 newarray(Type.CHAR_TYPE);
395 break;
396 case Opcodes.T_BYTE:
397 newarray(Type.BYTE_TYPE);
398 break;
399 case Opcodes.T_SHORT:
400 newarray(Type.SHORT_TYPE);
401 break;
402 case Opcodes.T_INT:
403 newarray(Type.INT_TYPE);
404 break;
405 case Opcodes.T_FLOAT:
406 newarray(Type.FLOAT_TYPE);
407 break;
408 case Opcodes.T_LONG:
409 newarray(Type.LONG_TYPE);
410 break;
411 case Opcodes.T_DOUBLE:
412 newarray(Type.DOUBLE_TYPE);
413 break;
414 default:
415 throw new IllegalArgumentException();
416 }
417 break;
418 default:
419 throw new IllegalArgumentException();
420 }
421 }
422
423 @Override
424 public void visitVarInsn(final int opcode, final int var) {
425 switch (opcode) {
426 case Opcodes.ILOAD:
427 load(var, Type.INT_TYPE);
428 break;
429 case Opcodes.LLOAD:
430 load(var, Type.LONG_TYPE);
431 break;
432 case Opcodes.FLOAD:
433 load(var, Type.FLOAT_TYPE);
434 break;
435 case Opcodes.DLOAD:
436 load(var, Type.DOUBLE_TYPE);
437 break;
438 case Opcodes.ALOAD:
439 load(var, OBJECT_TYPE);
440 break;
441 case Opcodes.ISTORE:
442 store(var, Type.INT_TYPE);
443 break;
444 case Opcodes.LSTORE:
445 store(var, Type.LONG_TYPE);
446 break;
447 case Opcodes.FSTORE:
448 store(var, Type.FLOAT_TYPE);
449 break;
450 case Opcodes.DSTORE:
451 store(var, Type.DOUBLE_TYPE);
452 break;
453 case Opcodes.ASTORE:
454 store(var, OBJECT_TYPE);
455 break;
456 case Opcodes.RET:
457 ret(var);
458 break;
459 default:
460 throw new IllegalArgumentException();
461 }
462 }
463
464 @Override
465 public void visitTypeInsn(final int opcode, final String type) {
466 Type t = Type.getObjectType(type);
467 switch (opcode) {
468 case Opcodes.NEW:
469 anew(t);
470 break;
471 case Opcodes.ANEWARRAY:
472 newarray(t);
473 break;
474 case Opcodes.CHECKCAST:
475 checkcast(t);
476 break;
477 case Opcodes.INSTANCEOF:
478 instanceOf(t);
479 break;
480 default:
481 throw new IllegalArgumentException();
482 }
483 }
484
485 @Override
486 public void visitFieldInsn(
487 final int opcode, final String owner, final String name, final String desc) {
488 switch (opcode) {
489 case Opcodes.GETSTATIC:
490 getstatic(owner, name, desc);
491 break;
492 case Opcodes.PUTSTATIC:
493 putstatic(owner, name, desc);
494 break;
495 case Opcodes.GETFIELD:
496 getfield(owner, name, desc);
497 break;
498 case Opcodes.PUTFIELD:
499 putfield(owner, name, desc);
500 break;
501 default:
502 throw new IllegalArgumentException();
503 }
504 }
505
506 @Deprecated
507 @Override
508 public void visitMethodInsn(
509 final int opcode, final String owner, final String name, final String desc) {
510 if (api >= Opcodes.ASM5) {
511 super.visitMethodInsn(opcode, owner, name, desc);
512 return;
513 }
514 doVisitMethodInsn(opcode, owner, name, desc, opcode == Opcodes.INVOKEINTERFACE);
515 }
516
517 @Override
518 public void visitMethodInsn(
519 final int opcode,
520 final String owner,
521 final String name,
522 final String desc,
523 final boolean itf) {
524 if (api < Opcodes.ASM5) {
525 super.visitMethodInsn(opcode, owner, name, desc, itf);
526 return;
527 }
528 doVisitMethodInsn(opcode, owner, name, desc, itf);
529 }
530
531 private void doVisitMethodInsn(
532 int opcode, final String owner, final String name, final String desc, final boolean itf) {
533 switch (opcode) {
534 case Opcodes.INVOKESPECIAL:
535 invokespecial(owner, name, desc, itf);
536 break;
537 case Opcodes.INVOKEVIRTUAL:
538 invokevirtual(owner, name, desc, itf);
539 break;
540 case Opcodes.INVOKESTATIC:
541 invokestatic(owner, name, desc, itf);
542 break;
543 case Opcodes.INVOKEINTERFACE:
544 invokeinterface(owner, name, desc);
545 break;
546 default:
547 throw new IllegalArgumentException();
548 }
549 }
550
551 @Override
552 public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) {
553 invokedynamic(name, desc, bsm, bsmArgs);
554 }
555
556 @Override
557 public void visitJumpInsn(final int opcode, final Label label) {
558 switch (opcode) {
559 case Opcodes.IFEQ:
560 ifeq(label);
561 break;
562 case Opcodes.IFNE:
563 ifne(label);
564 break;
565 case Opcodes.IFLT:
566 iflt(label);
567 break;
568 case Opcodes.IFGE:
569 ifge(label);
570 break;
571 case Opcodes.IFGT:
572 ifgt(label);
573 break;
574 case Opcodes.IFLE:
575 ifle(label);
576 break;
577 case Opcodes.IF_ICMPEQ:
578 ificmpeq(label);
579 break;
580 case Opcodes.IF_ICMPNE:
581 ificmpne(label);
582 break;
583 case Opcodes.IF_ICMPLT:
584 ificmplt(label);
585 break;
586 case Opcodes.IF_ICMPGE:
587 ificmpge(label);
588 break;
589 case Opcodes.IF_ICMPGT:
590 ificmpgt(label);
591 break;
592 case Opcodes.IF_ICMPLE:
593 ificmple(label);
594 break;
595 case Opcodes.IF_ACMPEQ:
596 ifacmpeq(label);
597 break;
598 case Opcodes.IF_ACMPNE:
599 ifacmpne(label);
600 break;
601 case Opcodes.GOTO:
602 goTo(label);
603 break;
604 case Opcodes.JSR:
605 jsr(label);
606 break;
607 case Opcodes.IFNULL:
608 ifnull(label);
609 break;
610 case Opcodes.IFNONNULL:
611 ifnonnull(label);
612 break;
613 default:
614 throw new IllegalArgumentException();
615 }
616 }
617
618 @Override
619 public void visitLabel(final Label label) {
620 mark(label);
621 }
622
623 @Override
624 public void visitLdcInsn(final Object value) {
625 if (api < Opcodes.ASM5
626 && (value instanceof Handle
627 || (value instanceof Type && ((Type) value).getSort() == Type.METHOD))) {
628 throw new UnsupportedOperationException();
629 }
630 if (value instanceof Integer) {
631 int val = ((Integer) value).intValue();
632 iconst(val);
633 } else if (value instanceof Byte) {
634 int val = ((Byte) value).intValue();
635 iconst(val);
636 } else if (value instanceof Character) {
637 int val = ((Character) value).charValue();
638 iconst(val);
639 } else if (value instanceof Short) {
640 int val = ((Short) value).intValue();
641 iconst(val);
642 } else if (value instanceof Boolean) {
643 int val = ((Boolean) value).booleanValue() ? 1 : 0;
644 iconst(val);
645 } else if (value instanceof Float) {
646 float val = ((Float) value).floatValue();
647 fconst(val);
648 } else if (value instanceof Long) {
649 long val = ((Long) value).longValue();
650 lconst(val);
651 } else if (value instanceof Double) {
652 double val = ((Double) value).doubleValue();
653 dconst(val);
654 } else if (value instanceof String) {
655 aconst(value);
656 } else if (value instanceof Type) {
657 tconst((Type) value);
658 } else if (value instanceof Handle) {
659 hconst((Handle) value);
660 } else {
661 throw new IllegalArgumentException();
662 }
663 }
664
665 @Override
666 public void visitIincInsn(final int var, final int increment) {
667 iinc(var, increment);
668 }
669
670 @Override
671 public void visitTableSwitchInsn(
672 final int min, final int max, final Label dflt, final Label... labels) {
673 tableswitch(min, max, dflt, labels);
674 }
675
676 @Override
677 public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) {
678 lookupswitch(dflt, keys, labels);
679 }
680
681 @Override
682 public void visitMultiANewArrayInsn(final String desc, final int dims) {
683 multianewarray(desc, dims);
684 }
685
686 // -----------------------------------------------------------------------
687
688 public void nop() {
689 mv.visitInsn(Opcodes.NOP);
690 }
691
692 public void aconst(final Object cst) {
693 if (cst == null) {
694 mv.visitInsn(Opcodes.ACONST_NULL);
695 } else {
696 mv.visitLdcInsn(cst);
697 }
698 }
699
700 public void iconst(final int cst) {
701 if (cst >= -1 && cst <= 5) {
702 mv.visitInsn(Opcodes.ICONST_0 + cst);
703 } else if (cst >= Byte.MIN_VALUE && cst <= Byte.MAX_VALUE) {
704 mv.visitIntInsn(Opcodes.BIPUSH, cst);
705 } else if (cst >= Short.MIN_VALUE && cst <= Short.MAX_VALUE) {
706 mv.visitIntInsn(Opcodes.SIPUSH, cst);
707 } else {
708 mv.visitLdcInsn(cst);
709 }
710 }
711
712 public void lconst(final long cst) {
713 if (cst == 0L || cst == 1L) {
714 mv.visitInsn(Opcodes.LCONST_0 + (int) cst);
715 } else {
716 mv.visitLdcInsn(cst);
717 }
718 }
719
720 public void fconst(final float cst) {
721 int bits = Float.floatToIntBits(cst);
722 if (bits == 0L || bits == 0x3f800000 || bits == 0x40000000) { // 0..2
723 mv.visitInsn(Opcodes.FCONST_0 + (int) cst);
724 } else {
725 mv.visitLdcInsn(cst);
726 }
727 }
728
729 public void dconst(final double cst) {
730 long bits = Double.doubleToLongBits(cst);
731 if (bits == 0L || bits == 0x3ff0000000000000L) { // +0.0d and 1.0d
732 mv.visitInsn(Opcodes.DCONST_0 + (int) cst);
733 } else {
734 mv.visitLdcInsn(cst);
735 }
736 }
737
738 public void tconst(final Type type) {
739 mv.visitLdcInsn(type);
740 }
741
742 public void hconst(final Handle handle) {
743 mv.visitLdcInsn(handle);
744 }
745
746 public void load(final int var, final Type type) {
747 mv.visitVarInsn(type.getOpcode(Opcodes.ILOAD), var);
748 }
749
750 public void aload(final Type type) {
751 mv.visitInsn(type.getOpcode(Opcodes.IALOAD));
752 }
753
754 public void store(final int var, final Type type) {
755 mv.visitVarInsn(type.getOpcode(Opcodes.ISTORE), var);
756 }
757
758 public void astore(final Type type) {
759 mv.visitInsn(type.getOpcode(Opcodes.IASTORE));
760 }
761
762 public void pop() {
763 mv.visitInsn(Opcodes.POP);
764 }
765
766 public void pop2() {
767 mv.visitInsn(Opcodes.POP2);
768 }
769
770 public void dup() {
771 mv.visitInsn(Opcodes.DUP);
772 }
773
774 public void dup2() {
775 mv.visitInsn(Opcodes.DUP2);
776 }
777
778 public void dupX1() {
779 mv.visitInsn(Opcodes.DUP_X1);
780 }
781
782 public void dupX2() {
783 mv.visitInsn(Opcodes.DUP_X2);
784 }
785
786 public void dup2X1() {
787 mv.visitInsn(Opcodes.DUP2_X1);
788 }
789
790 public void dup2X2() {
791 mv.visitInsn(Opcodes.DUP2_X2);
792 }
793
794 public void swap() {
795 mv.visitInsn(Opcodes.SWAP);
796 }
797
798 public void add(final Type type) {
799 mv.visitInsn(type.getOpcode(Opcodes.IADD));
800 }
801
802 public void sub(final Type type) {
803 mv.visitInsn(type.getOpcode(Opcodes.ISUB));
804 }
805
806 public void mul(final Type type) {
807 mv.visitInsn(type.getOpcode(Opcodes.IMUL));
808 }
809
810 public void div(final Type type) {
811 mv.visitInsn(type.getOpcode(Opcodes.IDIV));
812 }
813
814 public void rem(final Type type) {
815 mv.visitInsn(type.getOpcode(Opcodes.IREM));
816 }
817
818 public void neg(final Type type) {
819 mv.visitInsn(type.getOpcode(Opcodes.INEG));
820 }
821
822 public void shl(final Type type) {
823 mv.visitInsn(type.getOpcode(Opcodes.ISHL));
824 }
825
826 public void shr(final Type type) {
827 mv.visitInsn(type.getOpcode(Opcodes.ISHR));
828 }
829
830 public void ushr(final Type type) {
831 mv.visitInsn(type.getOpcode(Opcodes.IUSHR));
832 }
833
834 public void and(final Type type) {
835 mv.visitInsn(type.getOpcode(Opcodes.IAND));
836 }
837
838 public void or(final Type type) {
839 mv.visitInsn(type.getOpcode(Opcodes.IOR));
840 }
841
842 public void xor(final Type type) {
843 mv.visitInsn(type.getOpcode(Opcodes.IXOR));
844 }
845
846 public void iinc(final int var, final int increment) {
847 mv.visitIincInsn(var, increment);
848 }
849
850 public void cast(final Type from, final Type to) {
851 if (from != to) {
852 if (from == Type.DOUBLE_TYPE) {
853 if (to == Type.FLOAT_TYPE) {
854 mv.visitInsn(Opcodes.D2F);
855 } else if (to == Type.LONG_TYPE) {
856 mv.visitInsn(Opcodes.D2L);
857 } else {
858 mv.visitInsn(Opcodes.D2I);
859 cast(Type.INT_TYPE, to);
860 }
861 } else if (from == Type.FLOAT_TYPE) {
862 if (to == Type.DOUBLE_TYPE) {
863 mv.visitInsn(Opcodes.F2D);
864 } else if (to == Type.LONG_TYPE) {
865 mv.visitInsn(Opcodes.F2L);
866 } else {
867 mv.visitInsn(Opcodes.F2I);
868 cast(Type.INT_TYPE, to);
869 }
870 } else if (from == Type.LONG_TYPE) {
871 if (to == Type.DOUBLE_TYPE) {
872 mv.visitInsn(Opcodes.L2D);
873 } else if (to == Type.FLOAT_TYPE) {
874 mv.visitInsn(Opcodes.L2F);
875 } else {
876 mv.visitInsn(Opcodes.L2I);
877 cast(Type.INT_TYPE, to);
878 }
879 } else {
880 if (to == Type.BYTE_TYPE) {
881 mv.visitInsn(Opcodes.I2B);
882 } else if (to == Type.CHAR_TYPE) {
883 mv.visitInsn(Opcodes.I2C);
884 } else if (to == Type.DOUBLE_TYPE) {
885 mv.visitInsn(Opcodes.I2D);
886 } else if (to == Type.FLOAT_TYPE) {
887 mv.visitInsn(Opcodes.I2F);
888 } else if (to == Type.LONG_TYPE) {
889 mv.visitInsn(Opcodes.I2L);
890 } else if (to == Type.SHORT_TYPE) {
891 mv.visitInsn(Opcodes.I2S);
892 }
893 }
894 }
895 }
896
897 public void lcmp() {
898 mv.visitInsn(Opcodes.LCMP);
899 }
900
901 public void cmpl(final Type type) {
902 mv.visitInsn(type == Type.FLOAT_TYPE ? Opcodes.FCMPL : Opcodes.DCMPL);
903 }
904
905 public void cmpg(final Type type) {
906 mv.visitInsn(type == Type.FLOAT_TYPE ? Opcodes.FCMPG : Opcodes.DCMPG);
907 }
908
909 public void ifeq(final Label label) {
910 mv.visitJumpInsn(Opcodes.IFEQ, label);
911 }
912
913 public void ifne(final Label label) {
914 mv.visitJumpInsn(Opcodes.IFNE, label);
915 }
916
917 public void iflt(final Label label) {
918 mv.visitJumpInsn(Opcodes.IFLT, label);
919 }
920
921 public void ifge(final Label label) {
922 mv.visitJumpInsn(Opcodes.IFGE, label);
923 }
924
925 public void ifgt(final Label label) {
926 mv.visitJumpInsn(Opcodes.IFGT, label);
927 }
928
929 public void ifle(final Label label) {
930 mv.visitJumpInsn(Opcodes.IFLE, label);
931 }
932
933 public void ificmpeq(final Label label) {
934 mv.visitJumpInsn(Opcodes.IF_ICMPEQ, label);
935 }
936
937 public void ificmpne(final Label label) {
938 mv.visitJumpInsn(Opcodes.IF_ICMPNE, label);
939 }
940
941 public void ificmplt(final Label label) {
942 mv.visitJumpInsn(Opcodes.IF_ICMPLT, label);
943 }
944
945 public void ificmpge(final Label label) {
946 mv.visitJumpInsn(Opcodes.IF_ICMPGE, label);
947 }
948
949 public void ificmpgt(final Label label) {
950 mv.visitJumpInsn(Opcodes.IF_ICMPGT, label);
951 }
952
953 public void ificmple(final Label label) {
954 mv.visitJumpInsn(Opcodes.IF_ICMPLE, label);
955 }
956
957 public void ifacmpeq(final Label label) {
958 mv.visitJumpInsn(Opcodes.IF_ACMPEQ, label);
959 }
960
961 public void ifacmpne(final Label label) {
962 mv.visitJumpInsn(Opcodes.IF_ACMPNE, label);
963 }
964
965 public void goTo(final Label label) {
966 mv.visitJumpInsn(Opcodes.GOTO, label);
967 }
968
969 public void jsr(final Label label) {
970 mv.visitJumpInsn(Opcodes.JSR, label);
971 }
972
973 public void ret(final int var) {
974 mv.visitVarInsn(Opcodes.RET, var);
975 }
976
977 public void tableswitch(final int min, final int max, final Label dflt, final Label... labels) {
978 mv.visitTableSwitchInsn(min, max, dflt, labels);
979 }
980
981 public void lookupswitch(final Label dflt, final int[] keys, final Label[] labels) {
982 mv.visitLookupSwitchInsn(dflt, keys, labels);
983 }
984
985 public void areturn(final Type t) {
986 mv.visitInsn(t.getOpcode(Opcodes.IRETURN));
987 }
988
989 public void getstatic(final String owner, final String name, final String desc) {
990 mv.visitFieldInsn(Opcodes.GETSTATIC, owner, name, desc);
991 }
992
993 public void putstatic(final String owner, final String name, final String desc) {
994 mv.visitFieldInsn(Opcodes.PUTSTATIC, owner, name, desc);
995 }
996
997 public void getfield(final String owner, final String name, final String desc) {
998 mv.visitFieldInsn(Opcodes.GETFIELD, owner, name, desc);
999 }
1000
1001 public void putfield(final String owner, final String name, final String desc) {
1002 mv.visitFieldInsn(Opcodes.PUTFIELD, owner, name, desc);
1003 }
1004
1005 @Deprecated
1006 public void invokevirtual(final String owner, final String name, final String desc) {
1007 if (api >= Opcodes.ASM5) {
1008 invokevirtual(owner, name, desc, false);
1009 return;
1010 }
1011 mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, name, desc);
1012 }
1013
1014 public void invokevirtual(
1015 final String owner, final String name, final String desc, final boolean itf) {
1016 if (api < Opcodes.ASM5) {
1017 if (itf) {
1018 throw new IllegalArgumentException("INVOKEVIRTUAL on interfaces require ASM 5");
1019 }
1020 invokevirtual(owner, name, desc);
1021 return;
1022 }
1023 mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, name, desc, itf);
1024 }
1025
1026 @Deprecated
1027 public void invokespecial(final String owner, final String name, final String desc) {
1028 if (api >= Opcodes.ASM5) {
1029 invokespecial(owner, name, desc, false);
1030 return;
1031 }
1032 mv.visitMethodInsn(Opcodes.INVOKESPECIAL, owner, name, desc, false);
1033 }
1034
1035 public void invokespecial(
1036 final String owner, final String name, final String desc, final boolean itf) {
1037 if (api < Opcodes.ASM5) {
1038 if (itf) {
1039 throw new IllegalArgumentException("INVOKESPECIAL on interfaces require ASM 5");
1040 }
1041 invokespecial(owner, name, desc);
1042 return;
1043 }
1044 mv.visitMethodInsn(Opcodes.INVOKESPECIAL, owner, name, desc, itf);
1045 }
1046
1047 @Deprecated
1048 public void invokestatic(final String owner, final String name, final String desc) {
1049 if (api >= Opcodes.ASM5) {
1050 invokestatic(owner, name, desc, false);
1051 return;
1052 }
1053 mv.visitMethodInsn(Opcodes.INVOKESTATIC, owner, name, desc, false);
1054 }
1055
1056 public void invokestatic(
1057 final String owner, final String name, final String desc, final boolean itf) {
1058 if (api < Opcodes.ASM5) {
1059 if (itf) {
1060 throw new IllegalArgumentException("INVOKESTATIC on interfaces require ASM 5");
1061 }
1062 invokestatic(owner, name, desc);
1063 return;
1064 }
1065 mv.visitMethodInsn(Opcodes.INVOKESTATIC, owner, name, desc, itf);
1066 }
1067
1068 public void invokeinterface(final String owner, final String name, final String desc) {
1069 mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, owner, name, desc, true);
1070 }
1071
1072 public void invokedynamic(String name, String desc, Handle bsm, Object[] bsmArgs) {
1073 mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
1074 }
1075
1076 public void anew(final Type type) {
1077 mv.visitTypeInsn(Opcodes.NEW, type.getInternalName());
1078 }
1079
1080 public void newarray(final Type type) {
1081 int typ;
1082 switch (type.getSort()) {
1083 case Type.BOOLEAN:
1084 typ = Opcodes.T_BOOLEAN;
1085 break;
1086 case Type.CHAR:
1087 typ = Opcodes.T_CHAR;
1088 break;
1089 case Type.BYTE:
1090 typ = Opcodes.T_BYTE;
1091 break;
1092 case Type.SHORT:
1093 typ = Opcodes.T_SHORT;
1094 break;
1095 case Type.INT:
1096 typ = Opcodes.T_INT;
1097 break;
1098 case Type.FLOAT:
1099 typ = Opcodes.T_FLOAT;
1100 break;
1101 case Type.LONG:
1102 typ = Opcodes.T_LONG;
1103 break;
1104 case Type.DOUBLE:
1105 typ = Opcodes.T_DOUBLE;
1106 break;
1107 default:
1108 mv.visitTypeInsn(Opcodes.ANEWARRAY, type.getInternalName());
1109 return;
1110 }
1111 mv.visitIntInsn(Opcodes.NEWARRAY, typ);
1112 }
1113
1114 public void arraylength() {
1115 mv.visitInsn(Opcodes.ARRAYLENGTH);
1116 }
1117
1118 public void athrow() {
1119 mv.visitInsn(Opcodes.ATHROW);
1120 }
1121
1122 public void checkcast(final Type type) {
1123 mv.visitTypeInsn(Opcodes.CHECKCAST, type.getInternalName());
1124 }
1125
1126 public void instanceOf(final Type type) {
1127 mv.visitTypeInsn(Opcodes.INSTANCEOF, type.getInternalName());
1128 }
1129
1130 public void monitorenter() {
1131 mv.visitInsn(Opcodes.MONITORENTER);
1132 }
1133
1134 public void monitorexit() {
1135 mv.visitInsn(Opcodes.MONITOREXIT);
1136 }
1137
1138 public void multianewarray(final String desc, final int dims) {
1139 mv.visitMultiANewArrayInsn(desc, dims);
1140 }
1141
1142 public void ifnull(final Label label) {
1143 mv.visitJumpInsn(Opcodes.IFNULL, label);
1144 }
1145
1146 public void ifnonnull(final Label label) {
1147 mv.visitJumpInsn(Opcodes.IFNONNULL, label);
1148 }
1149
1150 public void mark(final Label label) {
1151 mv.visitLabel(label);
1152 }
1153 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.commons;
3028
3129 import java.util.AbstractMap;
5452 import org.eclipse.persistence.internal.libraries.asm.tree.TryCatchBlockNode;
5553
5654 /**
57 * A {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor} that removes JSR instructions and
58 * inlines the referenced subroutines.
59 *
60 * <b>Explanation of how it works</b> TODO
61 *
55 * A {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor} that removes JSR instructions and inlines the
56 * referenced subroutines.
57 *
58 * <p><b>Explanation of how it works</b> TODO
59 *
6260 * @author Niko Matsakis
6361 */
6462 public class JSRInlinerAdapter extends MethodNode implements Opcodes {
6563
66 private static final boolean LOGGING = false;
64 private static final boolean LOGGING = false;
65
66 /** For each label that is jumped to by a JSR, we create a BitSet instance. */
67 private final Map<LabelNode, BitSet> subroutineHeads = new HashMap<LabelNode, BitSet>();
68
69 /**
70 * This subroutine instance denotes the line of execution that is not contained within any
71 * subroutine; i.e., the "subroutine" that is executing when a method first begins.
72 */
73 private final BitSet mainSubroutine = new BitSet();
74
75 /**
76 * This BitSet contains the index of every instruction that belongs to more than one subroutine.
77 * This should not happen often.
78 */
79 final BitSet dualCitizens = new BitSet();
80
81 /**
82 * Constructs a new JSRInliner. <i>Subclasses must not use this constructor</i>. Instead, they must
83 * use the {@link #JSRInlinerAdapter(int, MethodVisitor, int, String, String, String, String[])}
84 * version.
85 *
86 * @param mv the <code>MethodVisitor</code> to send the resulting inlined method code to (use
87 * <code>null</code> for none).
88 * @param access the method's access flags (see {@link Opcodes}). This parameter also indicates if
89 * the method is synthetic and/or deprecated.
90 * @param name the method's name.
91 * @param desc the method's descriptor (see {@link Type}).
92 * @param signature the method's signature. May be <tt>null</tt>.
93 * @param exceptions the internal names of the method's exception classes (see {@link
94 * Type#getInternalName() getInternalName}). May be <tt>null</tt>.
95 * @throws IllegalStateException If a subclass calls this constructor.
96 */
97 public JSRInlinerAdapter(
98 final MethodVisitor mv,
99 final int access,
100 final String name,
101 final String desc,
102 final String signature,
103 final String[] exceptions) {
104 this(Opcodes.ASM6, mv, access, name, desc, signature, exceptions);
105 if (getClass() != JSRInlinerAdapter.class) {
106 throw new IllegalStateException();
107 }
108 }
109
110 /**
111 * Constructs a new JSRInliner.
112 *
113 * @param api the ASM API version implemented by this visitor. Must be one of {@link
114 * Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
115 * @param mv the <code>MethodVisitor</code> to send the resulting inlined method code to (use
116 * <code>null</code> for none).
117 * @param access the method's access flags (see {@link Opcodes}). This parameter also indicates if
118 * the method is synthetic and/or deprecated.
119 * @param name the method's name.
120 * @param desc the method's descriptor (see {@link Type}).
121 * @param signature the method's signature. May be <tt>null</tt>.
122 * @param exceptions the internal names of the method's exception classes (see {@link
123 * Type#getInternalName() getInternalName}). May be <tt>null</tt>.
124 */
125 protected JSRInlinerAdapter(
126 final int api,
127 final MethodVisitor mv,
128 final int access,
129 final String name,
130 final String desc,
131 final String signature,
132 final String[] exceptions) {
133 super(api, access, name, desc, signature, exceptions);
134 this.mv = mv;
135 }
136
137 /** Detects a JSR instruction and sets a flag to indicate we will need to do inlining. */
138 @Override
139 public void visitJumpInsn(final int opcode, final Label lbl) {
140 super.visitJumpInsn(opcode, lbl);
141 LabelNode ln = ((JumpInsnNode) instructions.getLast()).label;
142 if (opcode == JSR && !subroutineHeads.containsKey(ln)) {
143 subroutineHeads.put(ln, new BitSet());
144 }
145 }
146
147 /**
148 * If any JSRs were seen, triggers the inlining process. Otherwise, forwards the byte codes
149 * untouched.
150 */
151 @Override
152 public void visitEnd() {
153 if (!subroutineHeads.isEmpty()) {
154 markSubroutines();
155 if (LOGGING) {
156 log(mainSubroutine.toString());
157 Iterator<BitSet> it = subroutineHeads.values().iterator();
158 while (it.hasNext()) {
159 BitSet sub = it.next();
160 log(sub.toString());
161 }
162 }
163 emitCode();
164 }
165
166 // Forward the translate opcodes on if appropriate:
167 if (mv != null) {
168 accept(mv);
169 }
170 }
171
172 /**
173 * Walks the method and determines which internal subroutine(s), if any, each instruction is a
174 * method of.
175 */
176 private void markSubroutines() {
177 BitSet anyvisited = new BitSet();
178
179 // First walk the main subroutine and find all those instructions which
180 // can be reached without invoking any JSR at all
181 markSubroutineWalk(mainSubroutine, 0, anyvisited);
182
183 // Go through the head of each subroutine and find any nodes reachable
184 // to that subroutine without following any JSR links.
185 for (Iterator<Map.Entry<LabelNode, BitSet>> it = subroutineHeads.entrySet().iterator();
186 it.hasNext();
187 ) {
188 Map.Entry<LabelNode, BitSet> entry = it.next();
189 LabelNode lab = entry.getKey();
190 BitSet sub = entry.getValue();
191 int index = instructions.indexOf(lab);
192 markSubroutineWalk(sub, index, anyvisited);
193 }
194 }
195
196 /**
197 * Performs a depth first search walking the normal byte code path starting at <code>index</code>,
198 * and adding each instruction encountered into the subroutine <code>sub</code>. After this walk
199 * is complete, iterates over the exception handlers to ensure that we also include those byte
200 * codes which are reachable through an exception that may be thrown during the execution of the
201 * subroutine. Invoked from <code>markSubroutines()</code>.
202 *
203 * @param sub the subroutine whose instructions must be computed.
204 * @param index an instruction of this subroutine.
205 * @param anyvisited indexes of the already visited instructions, i.e. marked as part of this
206 * subroutine or any previously computed subroutine.
207 */
208 private void markSubroutineWalk(final BitSet sub, final int index, final BitSet anyvisited) {
209 if (LOGGING) {
210 log("markSubroutineWalk: sub=" + sub + " index=" + index);
211 }
212
213 // First find those instructions reachable via normal execution
214 markSubroutineWalkDFS(sub, index, anyvisited);
215
216 // Now, make sure we also include any applicable exception handlers
217 boolean loop = true;
218 while (loop) {
219 loop = false;
220 for (Iterator<TryCatchBlockNode> it = tryCatchBlocks.iterator(); it.hasNext(); ) {
221 TryCatchBlockNode trycatch = it.next();
222
223 if (LOGGING) {
224 // TODO use of default toString().
225 log("Scanning try/catch " + trycatch);
226 }
227
228 // If the handler has already been processed, skip it.
229 int handlerindex = instructions.indexOf(trycatch.handler);
230 if (sub.get(handlerindex)) {
231 continue;
232 }
233
234 int startindex = instructions.indexOf(trycatch.start);
235 int endindex = instructions.indexOf(trycatch.end);
236 int nextbit = sub.nextSetBit(startindex);
237 if (nextbit != -1 && nextbit < endindex) {
238 if (LOGGING) {
239 log(
240 "Adding exception handler: "
241 + startindex
242 + '-'
243 + endindex
244 + " due to "
245 + nextbit
246 + " handler "
247 + handlerindex);
248 }
249 markSubroutineWalkDFS(sub, handlerindex, anyvisited);
250 loop = true;
251 }
252 }
253 }
254 }
255
256 /**
257 * Performs a simple DFS of the instructions, assigning each to the subroutine <code>sub</code>.
258 * Starts from <code>index</code>. Invoked only by <code>markSubroutineWalk()</code>.
259 *
260 * @param sub the subroutine whose instructions must be computed.
261 * @param index an instruction of this subroutine.
262 * @param anyvisited indexes of the already visited instructions, i.e. marked as part of this
263 * subroutine or any previously computed subroutine.
264 */
265 private void markSubroutineWalkDFS(final BitSet sub, int index, final BitSet anyvisited) {
266 while (true) {
267 AbstractInsnNode node = instructions.get(index);
268
269 // don't visit a node twice
270 if (sub.get(index)) {
271 return;
272 }
273 sub.set(index);
274
275 // check for those nodes already visited by another subroutine
276 if (anyvisited.get(index)) {
277 dualCitizens.set(index);
278 if (LOGGING) {
279 log("Instruction #" + index + " is dual citizen.");
280 }
281 }
282 anyvisited.set(index);
283
284 if (node.getType() == AbstractInsnNode.JUMP_INSN && node.getOpcode() != JSR) {
285 // we do not follow recursively called subroutines here; but any
286 // other sort of branch we do follow
287 JumpInsnNode jnode = (JumpInsnNode) node;
288 int destidx = instructions.indexOf(jnode.label);
289 markSubroutineWalkDFS(sub, destidx, anyvisited);
290 }
291 if (node.getType() == AbstractInsnNode.TABLESWITCH_INSN) {
292 TableSwitchInsnNode tsnode = (TableSwitchInsnNode) node;
293 int destidx = instructions.indexOf(tsnode.dflt);
294 markSubroutineWalkDFS(sub, destidx, anyvisited);
295 for (int i = tsnode.labels.size() - 1; i >= 0; --i) {
296 LabelNode l = tsnode.labels.get(i);
297 destidx = instructions.indexOf(l);
298 markSubroutineWalkDFS(sub, destidx, anyvisited);
299 }
300 }
301 if (node.getType() == AbstractInsnNode.LOOKUPSWITCH_INSN) {
302 LookupSwitchInsnNode lsnode = (LookupSwitchInsnNode) node;
303 int destidx = instructions.indexOf(lsnode.dflt);
304 markSubroutineWalkDFS(sub, destidx, anyvisited);
305 for (int i = lsnode.labels.size() - 1; i >= 0; --i) {
306 LabelNode l = lsnode.labels.get(i);
307 destidx = instructions.indexOf(l);
308 markSubroutineWalkDFS(sub, destidx, anyvisited);
309 }
310 }
311
312 // check to see if this opcode falls through to the next instruction
313 // or not; if not, return.
314 switch (instructions.get(index).getOpcode()) {
315 case GOTO:
316 case RET:
317 case TABLESWITCH:
318 case LOOKUPSWITCH:
319 case IRETURN:
320 case LRETURN:
321 case FRETURN:
322 case DRETURN:
323 case ARETURN:
324 case RETURN:
325 case ATHROW:
326 /*
327 * note: this either returns from this subroutine, or a parent
328 * subroutine which invoked it
329 */
330 return;
331 }
332
333 // Use tail recursion here in the form of an outer while loop to
334 // avoid our stack growing needlessly:
335 index++;
336
337 // We implicitly assumed above that execution can always fall
338 // through to the next instruction after a JSR. But a subroutine may
339 // never return, in which case the code after the JSR is unreachable
340 // and can be anything. In particular, it can seem to fall off the
341 // end of the method, so we must handle this case here (we could
342 // instead detect whether execution can return or not from a JSR,
343 // but this is more complicated).
344 if (index >= instructions.size()) {
345 return;
346 }
347 }
348 }
349
350 /**
351 * Creates the new instructions, inlining each instantiation of each subroutine until the code is
352 * fully elaborated.
353 */
354 private void emitCode() {
355 LinkedList<Instantiation> worklist = new LinkedList<Instantiation>();
356 // Create an instantiation of the "root" subroutine, which is just the
357 // main routine
358 worklist.add(new Instantiation(null, mainSubroutine));
359
360 // Emit instantiations of each subroutine we encounter, including the
361 // main subroutine
362 InsnList newInstructions = new InsnList();
363 List<TryCatchBlockNode> newTryCatchBlocks = new ArrayList<TryCatchBlockNode>();
364 List<LocalVariableNode> newLocalVariables = new ArrayList<LocalVariableNode>();
365 while (!worklist.isEmpty()) {
366 Instantiation inst = worklist.removeFirst();
367 emitSubroutine(inst, worklist, newInstructions, newTryCatchBlocks, newLocalVariables);
368 }
369 instructions = newInstructions;
370 tryCatchBlocks = newTryCatchBlocks;
371 localVariables = newLocalVariables;
372 }
373
374 /**
375 * Emits one instantiation of one subroutine, specified by <code>instant</code>. May add new
376 * instantiations that are invoked by this one to the <code>worklist</code> parameter, and new
377 * try/catch blocks to <code>newTryCatchBlocks</code>.
378 *
379 * @param instant the instantiation that must be performed.
380 * @param worklist list of the instantiations that remain to be done.
381 * @param newInstructions the instruction list to which the instantiated code must be appended.
382 * @param newTryCatchBlocks the exception handler list to which the instantiated handlers must be
383 * appended.
384 * @param newLocalVariables the local variables list to which the instantiated local variables
385 * must be appended.
386 */
387 private void emitSubroutine(
388 final Instantiation instant,
389 final List<Instantiation> worklist,
390 final InsnList newInstructions,
391 final List<TryCatchBlockNode> newTryCatchBlocks,
392 final List<LocalVariableNode> newLocalVariables) {
393 LabelNode duplbl = null;
394
395 if (LOGGING) {
396 log("--------------------------------------------------------");
397 log("Emitting instantiation of subroutine " + instant.subroutine);
398 }
399
400 // Emit the relevant instructions for this instantiation, translating
401 // labels and jump targets as we go:
402 for (int i = 0, c = instructions.size(); i < c; i++) {
403 AbstractInsnNode insn = instructions.get(i);
404 Instantiation owner = instant.findOwner(i);
405
406 // Always remap labels:
407 if (insn.getType() == AbstractInsnNode.LABEL) {
408 // Translate labels into their renamed equivalents.
409 // Avoid adding the same label more than once. Note
410 // that because we own this instruction the gotoTable
411 // and the rangeTable will always agree.
412 LabelNode ilbl = (LabelNode) insn;
413 LabelNode remap = instant.rangeLabel(ilbl);
414 if (LOGGING) {
415 // TODO use of default toString().
416 log("Translating lbl #" + i + ':' + ilbl + " to " + remap);
417 }
418 if (remap != duplbl) {
419 newInstructions.add(remap);
420 duplbl = remap;
421 }
422 continue;
423 }
424
425 // We don't want to emit instructions that were already
426 // emitted by a subroutine higher on the stack. Note that
427 // it is still possible for a given instruction to be
428 // emitted twice because it may belong to two subroutines
429 // that do not invoke each other.
430 if (owner != instant) {
431 continue;
432 }
433
434 if (LOGGING) {
435 log("Emitting inst #" + i);
436 }
437
438 if (insn.getOpcode() == RET) {
439 // Translate RET instruction(s) to a jump to the return label
440 // for the appropriate instantiation. The problem is that the
441 // subroutine may "fall through" to the ret of a parent
442 // subroutine; therefore, to find the appropriate ret label we
443 // find the lowest subroutine on the stack that claims to own
444 // this instruction. See the class javadoc comment for an
445 // explanation on why this technique is safe (note: it is only
446 // safe if the input is verifiable).
447 LabelNode retlabel = null;
448 for (Instantiation p = instant; p != null; p = p.previous) {
449 if (p.subroutine.get(i)) {
450 retlabel = p.returnLabel;
451 }
452 }
453 if (retlabel == null) {
454 // This is only possible if the mainSubroutine owns a RET
455 // instruction, which should never happen for verifiable
456 // code.
457 throw new RuntimeException("Instruction #" + i + " is a RET not owned by any subroutine");
458 }
459 newInstructions.add(new JumpInsnNode(GOTO, retlabel));
460 } else if (insn.getOpcode() == JSR) {
461 LabelNode lbl = ((JumpInsnNode) insn).label;
462 BitSet sub = subroutineHeads.get(lbl);
463 Instantiation newinst = new Instantiation(instant, sub);
464 LabelNode startlbl = newinst.gotoLabel(lbl);
465
466 if (LOGGING) {
467 log(" Creating instantiation of subr " + sub);
468 }
469
470 // Rather than JSRing, we will jump to the inline version and
471 // push NULL for what was once the return value. This hack
472 // allows us to avoid doing any sort of data flow analysis to
473 // figure out which instructions manipulate the old return value
474 // pointer which is now known to be unneeded.
475 newInstructions.add(new InsnNode(ACONST_NULL));
476 newInstructions.add(new JumpInsnNode(GOTO, startlbl));
477 newInstructions.add(newinst.returnLabel);
478
479 // Insert this new instantiation into the queue to be emitted
480 // later.
481 worklist.add(newinst);
482 } else {
483 newInstructions.add(insn.clone(instant));
484 }
485 }
486
487 // Emit try/catch blocks that are relevant to this method.
488 for (Iterator<TryCatchBlockNode> it = tryCatchBlocks.iterator(); it.hasNext(); ) {
489 TryCatchBlockNode trycatch = it.next();
490
491 if (LOGGING) {
492 // TODO use of default toString().
493 log(
494 "try catch block original labels="
495 + trycatch.start
496 + '-'
497 + trycatch.end
498 + "->"
499 + trycatch.handler);
500 }
501
502 final LabelNode start = instant.rangeLabel(trycatch.start);
503 final LabelNode end = instant.rangeLabel(trycatch.end);
504
505 // Ignore empty try/catch regions
506 if (start == end) {
507 if (LOGGING) {
508 log(" try catch block empty in this subroutine");
509 }
510 continue;
511 }
512
513 final LabelNode handler = instant.gotoLabel(trycatch.handler);
514
515 if (LOGGING) {
516 // TODO use of default toString().
517 log(" try catch block new labels=" + start + '-' + end + "->" + handler);
518 }
519
520 if (start == null || end == null || handler == null) {
521 throw new RuntimeException("Internal error!");
522 }
523
524 newTryCatchBlocks.add(new TryCatchBlockNode(start, end, handler, trycatch.type));
525 }
526
527 for (Iterator<LocalVariableNode> it = localVariables.iterator(); it.hasNext(); ) {
528 LocalVariableNode lvnode = it.next();
529 if (LOGGING) {
530 log("local var " + lvnode.name);
531 }
532 final LabelNode start = instant.rangeLabel(lvnode.start);
533 final LabelNode end = instant.rangeLabel(lvnode.end);
534 if (start == end) {
535 if (LOGGING) {
536 log(" local variable empty in this sub");
537 }
538 continue;
539 }
540 newLocalVariables.add(
541 new LocalVariableNode(
542 lvnode.name, lvnode.desc, lvnode.signature, start, end, lvnode.index));
543 }
544 }
545
546 private static void log(final String str) {
547 System.err.println(str);
548 }
549
550 /**
551 * A class that represents an instantiation of a subroutine. Each instantiation has an associate
552 * "stack" --- which is a listing of those instantiations that were active when this particular
553 * instance of this subroutine was invoked. Each instantiation also has a map from the original
554 * labels of the program to the labels appropriate for this instantiation, and finally a label to
555 * return to.
556 */
557 private class Instantiation extends AbstractMap<LabelNode, LabelNode> {
558
559 /** Previous instantiations; the stack must be statically predictable to be inlinable. */
560 final Instantiation previous;
561
562 /** The subroutine this is an instantiation of. */
563 public final BitSet subroutine;
67564
68565 /**
69 * For each label that is jumped to by a JSR, we create a BitSet instance.
566 * This table maps Labels from the original source to Labels pointing at code specific to this
567 * instantiation, for use in remapping try/catch blocks,as well as gotos.
568 *
569 * <p>Note that in the presence of dual citizens instructions, that is, instructions which
570 * belong to more than one subroutine due to the merging of control flow without a RET
571 * instruction, we will map the target label of a GOTO to the label used by the instantiation
572 * lowest on the stack. This avoids code duplication during inlining in most cases.
573 *
574 * @see #findOwner(int)
70575 */
71 private final Map<LabelNode, BitSet> subroutineHeads = new HashMap<LabelNode, BitSet>();
576 public final Map<LabelNode, LabelNode> rangeTable = new HashMap<LabelNode, LabelNode>();
577
578 /** All returns for this instantiation will be mapped to this label */
579 public final LabelNode returnLabel;
580
581 Instantiation(final Instantiation prev, final BitSet sub) {
582 previous = prev;
583 subroutine = sub;
584 for (Instantiation p = prev; p != null; p = p.previous) {
585 if (p.subroutine == sub) {
586 throw new RuntimeException("Recursive invocation of " + sub);
587 }
588 }
589
590 // Determine the label to return to when this subroutine terminates
591 // via RET: note that the main subroutine never terminates via RET.
592 if (prev != null) {
593 returnLabel = new LabelNode();
594 } else {
595 returnLabel = null;
596 }
597
598 // Each instantiation will remap the labels from the code above to
599 // refer to its particular copy of its own instructions. Note that
600 // we collapse labels which point at the same instruction into one:
601 // this is fairly common as we are often ignoring large chunks of
602 // instructions, so what were previously distinct labels become
603 // duplicates.
604 LabelNode duplbl = null;
605 for (int i = 0, c = instructions.size(); i < c; i++) {
606 AbstractInsnNode insn = instructions.get(i);
607
608 if (insn.getType() == AbstractInsnNode.LABEL) {
609 LabelNode ilbl = (LabelNode) insn;
610
611 if (duplbl == null) {
612 // if we already have a label pointing at this spot,
613 // don't recreate it.
614 duplbl = new LabelNode();
615 }
616
617 // Add an entry in the rangeTable for every label
618 // in the original code which points at the next
619 // instruction of our own to be emitted.
620 rangeTable.put(ilbl, duplbl);
621 } else if (findOwner(i) == this) {
622 // We will emit this instruction, so clear the 'duplbl' flag
623 // since the next Label will refer to a distinct
624 // instruction.
625 duplbl = null;
626 }
627 }
628 }
72629
73630 /**
74 * This subroutine instance denotes the line of execution that is not
75 * contained within any subroutine; i.e., the "subroutine" that is executing
76 * when a method first begins.
631 * Returns the "owner" of a particular instruction relative to this instantiation: the owner
632 * referes to the Instantiation which will emit the version of this instruction that we will
633 * execute.
634 *
635 * <p>Typically, the return value is either <code>this</code> or <code>null</code>. <code>this
636 * </code> indicates that this instantiation will generate the version of this instruction that
637 * we will execute, and <code>null</code> indicates that this instantiation never executes the
638 * given instruction.
639 *
640 * <p>Sometimes, however, an instruction can belong to multiple subroutines; this is called a
641 * "dual citizen" instruction (though it may belong to more than 2 subroutines), and occurs when
642 * multiple subroutines branch to common points of control. In this case, the owner is the
643 * subroutine that appears lowest on the stack, and which also owns the instruction in question.
644 *
645 * @param i the index of the instruction in the original code
646 * @return the "owner" of a particular instruction relative to this instantiation.
77647 */
78 private final BitSet mainSubroutine = new BitSet();
648 public Instantiation findOwner(final int i) {
649 if (!subroutine.get(i)) {
650 return null;
651 }
652 if (!dualCitizens.get(i)) {
653 return this;
654 }
655 Instantiation own = this;
656 for (Instantiation p = previous; p != null; p = p.previous) {
657 if (p.subroutine.get(i)) {
658 own = p;
659 }
660 }
661 return own;
662 }
79663
80664 /**
81 * This BitSet contains the index of every instruction that belongs to more
82 * than one subroutine. This should not happen often.
665 * Looks up the label <code>l</code> in the <code>gotoTable</code>, thus translating it from a
666 * Label in the original code, to a Label in the inlined code that is appropriate for use by an
667 * instruction that branched to the original label.
668 *
669 * @param l The label we will be translating
670 * @return a label for use by a branch instruction in the inlined code
671 * @see #rangeLabel
83672 */
84 final BitSet dualCitizens = new BitSet();
673 public LabelNode gotoLabel(final LabelNode l) {
674 // owner should never be null, because owner is only null
675 // if an instruction cannot be reached from this subroutine
676 Instantiation owner = findOwner(instructions.indexOf(l));
677 return owner.rangeTable.get(l);
678 }
85679
86680 /**
87 * Creates a new JSRInliner. <i>Subclasses must not use this
88 * constructor</i>. Instead, they must use the
89 * {@link #JSRInlinerAdapter(int, MethodVisitor, int, String, String, String, String[])}
90 * version.
91 *
92 * @param mv
93 * the <code>MethodVisitor</code> to send the resulting inlined
94 * method code to (use <code>null</code> for none).
95 * @param access
96 * the method's access flags (see {@link Opcodes}). This
97 * parameter also indicates if the method is synthetic and/or
98 * deprecated.
99 * @param name
100 * the method's name.
101 * @param desc
102 * the method's descriptor (see {@link Type}).
103 * @param signature
104 * the method's signature. May be <tt>null</tt>.
105 * @param exceptions
106 * the internal names of the method's exception classes (see
107 * {@link Type#getInternalName() getInternalName}). May be
108 * <tt>null</tt>.
109 * @throws IllegalStateException
110 * If a subclass calls this constructor.
681 * Looks up the label <code>l</code> in the <code>rangeTable</code>, thus translating it from a
682 * Label in the original code, to a Label in the inlined code that is appropriate for use by an
683 * try/catch or variable use annotation.
684 *
685 * @param l The label we will be translating
686 * @return a label for use by a try/catch or variable annotation in the original code
687 * @see #rangeTable
111688 */
112 public JSRInlinerAdapter(final MethodVisitor mv, final int access,
113 final String name, final String desc, final String signature,
114 final String[] exceptions) {
115 this(Opcodes.ASM6, mv, access, name, desc, signature, exceptions);
116 if (getClass() != JSRInlinerAdapter.class) {
117 throw new IllegalStateException();
118 }
119 }
120
121 /**
122 * Creates a new JSRInliner.
123 *
124 * @param api
125 * the ASM API version implemented by this visitor. Must be one
126 * of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
127 * @param mv
128 * the <code>MethodVisitor</code> to send the resulting inlined
129 * method code to (use <code>null</code> for none).
130 * @param access
131 * the method's access flags (see {@link Opcodes}). This
132 * parameter also indicates if the method is synthetic and/or
133 * deprecated.
134 * @param name
135 * the method's name.
136 * @param desc
137 * the method's descriptor (see {@link Type}).
138 * @param signature
139 * the method's signature. May be <tt>null</tt>.
140 * @param exceptions
141 * the internal names of the method's exception classes (see
142 * {@link Type#getInternalName() getInternalName}). May be
143 * <tt>null</tt>.
144 */
145 protected JSRInlinerAdapter(final int api, final MethodVisitor mv,
146 final int access, final String name, final String desc,
147 final String signature, final String[] exceptions) {
148 super(api, access, name, desc, signature, exceptions);
149 this.mv = mv;
150 }
151
152 /**
153 * Detects a JSR instruction and sets a flag to indicate we will need to do
154 * inlining.
155 */
689 public LabelNode rangeLabel(final LabelNode l) {
690 return rangeTable.get(l);
691 }
692
693 // AbstractMap implementation
694
156695 @Override
157 public void visitJumpInsn(final int opcode, final Label lbl) {
158 super.visitJumpInsn(opcode, lbl);
159 LabelNode ln = ((JumpInsnNode) instructions.getLast()).label;
160 if (opcode == JSR && !subroutineHeads.containsKey(ln)) {
161 subroutineHeads.put(ln, new BitSet());
162 }
163 }
164
165 /**
166 * If any JSRs were seen, triggers the inlining process. Otherwise, forwards
167 * the byte codes untouched.
168 */
696 public Set<Map.Entry<LabelNode, LabelNode>> entrySet() {
697 return null;
698 }
699
169700 @Override
170 public void visitEnd() {
171 if (!subroutineHeads.isEmpty()) {
172 markSubroutines();
173 if (LOGGING) {
174 log(mainSubroutine.toString());
175 Iterator<BitSet> it = subroutineHeads.values().iterator();
176 while (it.hasNext()) {
177 BitSet sub = it.next();
178 log(sub.toString());
179 }
180 }
181 emitCode();
182 }
183
184 // Forward the translate opcodes on if appropriate:
185 if (mv != null) {
186 accept(mv);
187 }
188 }
189
190 /**
191 * Walks the method and determines which internal subroutine(s), if any,
192 * each instruction is a method of.
193 */
194 private void markSubroutines() {
195 BitSet anyvisited = new BitSet();
196
197 // First walk the main subroutine and find all those instructions which
198 // can be reached without invoking any JSR at all
199 markSubroutineWalk(mainSubroutine, 0, anyvisited);
200
201 // Go through the head of each subroutine and find any nodes reachable
202 // to that subroutine without following any JSR links.
203 for (Iterator<Map.Entry<LabelNode, BitSet>> it = subroutineHeads
204 .entrySet().iterator(); it.hasNext();) {
205 Map.Entry<LabelNode, BitSet> entry = it.next();
206 LabelNode lab = entry.getKey();
207 BitSet sub = entry.getValue();
208 int index = instructions.indexOf(lab);
209 markSubroutineWalk(sub, index, anyvisited);
210 }
211 }
212
213 /**
214 * Performs a depth first search walking the normal byte code path starting
215 * at <code>index</code>, and adding each instruction encountered into the
216 * subroutine <code>sub</code>. After this walk is complete, iterates over
217 * the exception handlers to ensure that we also include those byte codes
218 * which are reachable through an exception that may be thrown during the
219 * execution of the subroutine. Invoked from <code>markSubroutines()</code>.
220 *
221 * @param sub
222 * the subroutine whose instructions must be computed.
223 * @param index
224 * an instruction of this subroutine.
225 * @param anyvisited
226 * indexes of the already visited instructions, i.e. marked as
227 * part of this subroutine or any previously computed subroutine.
228 */
229 private void markSubroutineWalk(final BitSet sub, final int index,
230 final BitSet anyvisited) {
231 if (LOGGING) {
232 log("markSubroutineWalk: sub=" + sub + " index=" + index);
233 }
234
235 // First find those instructions reachable via normal execution
236 markSubroutineWalkDFS(sub, index, anyvisited);
237
238 // Now, make sure we also include any applicable exception handlers
239 boolean loop = true;
240 while (loop) {
241 loop = false;
242 for (Iterator<TryCatchBlockNode> it = tryCatchBlocks.iterator(); it
243 .hasNext();) {
244 TryCatchBlockNode trycatch = it.next();
245
246 if (LOGGING) {
247 // TODO use of default toString().
248 log("Scanning try/catch " + trycatch);
249 }
250
251 // If the handler has already been processed, skip it.
252 int handlerindex = instructions.indexOf(trycatch.handler);
253 if (sub.get(handlerindex)) {
254 continue;
255 }
256
257 int startindex = instructions.indexOf(trycatch.start);
258 int endindex = instructions.indexOf(trycatch.end);
259 int nextbit = sub.nextSetBit(startindex);
260 if (nextbit != -1 && nextbit < endindex) {
261 if (LOGGING) {
262 log("Adding exception handler: " + startindex + '-'
263 + endindex + " due to " + nextbit + " handler "
264 + handlerindex);
265 }
266 markSubroutineWalkDFS(sub, handlerindex, anyvisited);
267 loop = true;
268 }
269 }
270 }
271 }
272
273 /**
274 * Performs a simple DFS of the instructions, assigning each to the
275 * subroutine <code>sub</code>. Starts from <code>index</code>. Invoked only
276 * by <code>markSubroutineWalk()</code>.
277 *
278 * @param sub
279 * the subroutine whose instructions must be computed.
280 * @param index
281 * an instruction of this subroutine.
282 * @param anyvisited
283 * indexes of the already visited instructions, i.e. marked as
284 * part of this subroutine or any previously computed subroutine.
285 */
286 private void markSubroutineWalkDFS(final BitSet sub, int index,
287 final BitSet anyvisited) {
288 while (true) {
289 AbstractInsnNode node = instructions.get(index);
290
291 // don't visit a node twice
292 if (sub.get(index)) {
293 return;
294 }
295 sub.set(index);
296
297 // check for those nodes already visited by another subroutine
298 if (anyvisited.get(index)) {
299 dualCitizens.set(index);
300 if (LOGGING) {
301 log("Instruction #" + index + " is dual citizen.");
302 }
303 }
304 anyvisited.set(index);
305
306 if (node.getType() == AbstractInsnNode.JUMP_INSN
307 && node.getOpcode() != JSR) {
308 // we do not follow recursively called subroutines here; but any
309 // other sort of branch we do follow
310 JumpInsnNode jnode = (JumpInsnNode) node;
311 int destidx = instructions.indexOf(jnode.label);
312 markSubroutineWalkDFS(sub, destidx, anyvisited);
313 }
314 if (node.getType() == AbstractInsnNode.TABLESWITCH_INSN) {
315 TableSwitchInsnNode tsnode = (TableSwitchInsnNode) node;
316 int destidx = instructions.indexOf(tsnode.dflt);
317 markSubroutineWalkDFS(sub, destidx, anyvisited);
318 for (int i = tsnode.labels.size() - 1; i >= 0; --i) {
319 LabelNode l = tsnode.labels.get(i);
320 destidx = instructions.indexOf(l);
321 markSubroutineWalkDFS(sub, destidx, anyvisited);
322 }
323 }
324 if (node.getType() == AbstractInsnNode.LOOKUPSWITCH_INSN) {
325 LookupSwitchInsnNode lsnode = (LookupSwitchInsnNode) node;
326 int destidx = instructions.indexOf(lsnode.dflt);
327 markSubroutineWalkDFS(sub, destidx, anyvisited);
328 for (int i = lsnode.labels.size() - 1; i >= 0; --i) {
329 LabelNode l = lsnode.labels.get(i);
330 destidx = instructions.indexOf(l);
331 markSubroutineWalkDFS(sub, destidx, anyvisited);
332 }
333 }
334
335 // check to see if this opcode falls through to the next instruction
336 // or not; if not, return.
337 switch (instructions.get(index).getOpcode()) {
338 case GOTO:
339 case RET:
340 case TABLESWITCH:
341 case LOOKUPSWITCH:
342 case IRETURN:
343 case LRETURN:
344 case FRETURN:
345 case DRETURN:
346 case ARETURN:
347 case RETURN:
348 case ATHROW:
349 /*
350 * note: this either returns from this subroutine, or a parent
351 * subroutine which invoked it
352 */
353 return;
354 }
355
356 // Use tail recursion here in the form of an outer while loop to
357 // avoid our stack growing needlessly:
358 index++;
359
360 // We implicitly assumed above that execution can always fall
361 // through to the next instruction after a JSR. But a subroutine may
362 // never return, in which case the code after the JSR is unreachable
363 // and can be anything. In particular, it can seem to fall off the
364 // end of the method, so we must handle this case here (we could
365 // instead detect whether execution can return or not from a JSR,
366 // but this is more complicated).
367 if (index >= instructions.size()) {
368 return;
369 }
370 }
371 }
372
373 /**
374 * Creates the new instructions, inlining each instantiation of each
375 * subroutine until the code is fully elaborated.
376 */
377 private void emitCode() {
378 LinkedList<Instantiation> worklist = new LinkedList<Instantiation>();
379 // Create an instantiation of the "root" subroutine, which is just the
380 // main routine
381 worklist.add(new Instantiation(null, mainSubroutine));
382
383 // Emit instantiations of each subroutine we encounter, including the
384 // main subroutine
385 InsnList newInstructions = new InsnList();
386 List<TryCatchBlockNode> newTryCatchBlocks = new ArrayList<TryCatchBlockNode>();
387 List<LocalVariableNode> newLocalVariables = new ArrayList<LocalVariableNode>();
388 while (!worklist.isEmpty()) {
389 Instantiation inst = worklist.removeFirst();
390 emitSubroutine(inst, worklist, newInstructions, newTryCatchBlocks,
391 newLocalVariables);
392 }
393 instructions = newInstructions;
394 tryCatchBlocks = newTryCatchBlocks;
395 localVariables = newLocalVariables;
396 }
397
398 /**
399 * Emits one instantiation of one subroutine, specified by
400 * <code>instant</code>. May add new instantiations that are invoked by this
401 * one to the <code>worklist</code> parameter, and new try/catch blocks to
402 * <code>newTryCatchBlocks</code>.
403 *
404 * @param instant
405 * the instantiation that must be performed.
406 * @param worklist
407 * list of the instantiations that remain to be done.
408 * @param newInstructions
409 * the instruction list to which the instantiated code must be
410 * appended.
411 * @param newTryCatchBlocks
412 * the exception handler list to which the instantiated handlers
413 * must be appended.
414 */
415 private void emitSubroutine(final Instantiation instant,
416 final List<Instantiation> worklist, final InsnList newInstructions,
417 final List<TryCatchBlockNode> newTryCatchBlocks,
418 final List<LocalVariableNode> newLocalVariables) {
419 LabelNode duplbl = null;
420
421 if (LOGGING) {
422 log("--------------------------------------------------------");
423 log("Emitting instantiation of subroutine " + instant.subroutine);
424 }
425
426 // Emit the relevant instructions for this instantiation, translating
427 // labels and jump targets as we go:
428 for (int i = 0, c = instructions.size(); i < c; i++) {
429 AbstractInsnNode insn = instructions.get(i);
430 Instantiation owner = instant.findOwner(i);
431
432 // Always remap labels:
433 if (insn.getType() == AbstractInsnNode.LABEL) {
434 // Translate labels into their renamed equivalents.
435 // Avoid adding the same label more than once. Note
436 // that because we own this instruction the gotoTable
437 // and the rangeTable will always agree.
438 LabelNode ilbl = (LabelNode) insn;
439 LabelNode remap = instant.rangeLabel(ilbl);
440 if (LOGGING) {
441 // TODO use of default toString().
442 log("Translating lbl #" + i + ':' + ilbl + " to " + remap);
443 }
444 if (remap != duplbl) {
445 newInstructions.add(remap);
446 duplbl = remap;
447 }
448 continue;
449 }
450
451 // We don't want to emit instructions that were already
452 // emitted by a subroutine higher on the stack. Note that
453 // it is still possible for a given instruction to be
454 // emitted twice because it may belong to two subroutines
455 // that do not invoke each other.
456 if (owner != instant) {
457 continue;
458 }
459
460 if (LOGGING) {
461 log("Emitting inst #" + i);
462 }
463
464 if (insn.getOpcode() == RET) {
465 // Translate RET instruction(s) to a jump to the return label
466 // for the appropriate instantiation. The problem is that the
467 // subroutine may "fall through" to the ret of a parent
468 // subroutine; therefore, to find the appropriate ret label we
469 // find the lowest subroutine on the stack that claims to own
470 // this instruction. See the class javadoc comment for an
471 // explanation on why this technique is safe (note: it is only
472 // safe if the input is verifiable).
473 LabelNode retlabel = null;
474 for (Instantiation p = instant; p != null; p = p.previous) {
475 if (p.subroutine.get(i)) {
476 retlabel = p.returnLabel;
477 }
478 }
479 if (retlabel == null) {
480 // This is only possible if the mainSubroutine owns a RET
481 // instruction, which should never happen for verifiable
482 // code.
483 throw new RuntimeException("Instruction #" + i
484 + " is a RET not owned by any subroutine");
485 }
486 newInstructions.add(new JumpInsnNode(GOTO, retlabel));
487 } else if (insn.getOpcode() == JSR) {
488 LabelNode lbl = ((JumpInsnNode) insn).label;
489 BitSet sub = subroutineHeads.get(lbl);
490 Instantiation newinst = new Instantiation(instant, sub);
491 LabelNode startlbl = newinst.gotoLabel(lbl);
492
493 if (LOGGING) {
494 log(" Creating instantiation of subr " + sub);
495 }
496
497 // Rather than JSRing, we will jump to the inline version and
498 // push NULL for what was once the return value. This hack
499 // allows us to avoid doing any sort of data flow analysis to
500 // figure out which instructions manipulate the old return value
501 // pointer which is now known to be unneeded.
502 newInstructions.add(new InsnNode(ACONST_NULL));
503 newInstructions.add(new JumpInsnNode(GOTO, startlbl));
504 newInstructions.add(newinst.returnLabel);
505
506 // Insert this new instantiation into the queue to be emitted
507 // later.
508 worklist.add(newinst);
509 } else {
510 newInstructions.add(insn.clone(instant));
511 }
512 }
513
514 // Emit try/catch blocks that are relevant to this method.
515 for (Iterator<TryCatchBlockNode> it = tryCatchBlocks.iterator(); it
516 .hasNext();) {
517 TryCatchBlockNode trycatch = it.next();
518
519 if (LOGGING) {
520 // TODO use of default toString().
521 log("try catch block original labels=" + trycatch.start + '-'
522 + trycatch.end + "->" + trycatch.handler);
523 }
524
525 final LabelNode start = instant.rangeLabel(trycatch.start);
526 final LabelNode end = instant.rangeLabel(trycatch.end);
527
528 // Ignore empty try/catch regions
529 if (start == end) {
530 if (LOGGING) {
531 log(" try catch block empty in this subroutine");
532 }
533 continue;
534 }
535
536 final LabelNode handler = instant.gotoLabel(trycatch.handler);
537
538 if (LOGGING) {
539 // TODO use of default toString().
540 log(" try catch block new labels=" + start + '-' + end + "->"
541 + handler);
542 }
543
544 if (start == null || end == null || handler == null) {
545 throw new RuntimeException("Internal error!");
546 }
547
548 newTryCatchBlocks.add(new TryCatchBlockNode(start, end, handler,
549 trycatch.type));
550 }
551
552 for (Iterator<LocalVariableNode> it = localVariables.iterator(); it
553 .hasNext();) {
554 LocalVariableNode lvnode = it.next();
555 if (LOGGING) {
556 log("local var " + lvnode.name);
557 }
558 final LabelNode start = instant.rangeLabel(lvnode.start);
559 final LabelNode end = instant.rangeLabel(lvnode.end);
560 if (start == end) {
561 if (LOGGING) {
562 log(" local variable empty in this sub");
563 }
564 continue;
565 }
566 newLocalVariables.add(new LocalVariableNode(lvnode.name,
567 lvnode.desc, lvnode.signature, start, end, lvnode.index));
568 }
569 }
570
571 private static void log(final String str) {
572 System.err.println(str);
573 }
574
575 /**
576 * A class that represents an instantiation of a subroutine. Each
577 * instantiation has an associate "stack" --- which is a listing of those
578 * instantiations that were active when this particular instance of this
579 * subroutine was invoked. Each instantiation also has a map from the
580 * original labels of the program to the labels appropriate for this
581 * instantiation, and finally a label to return to.
582 */
583 private class Instantiation extends AbstractMap<LabelNode, LabelNode> {
584
585 /**
586 * Previous instantiations; the stack must be statically predictable to
587 * be inlinable.
588 */
589 final Instantiation previous;
590
591 /**
592 * The subroutine this is an instantiation of.
593 */
594 public final BitSet subroutine;
595
596 /**
597 * This table maps Labels from the original source to Labels pointing at
598 * code specific to this instantiation, for use in remapping try/catch
599 * blocks,as well as gotos.
600 *
601 * Note that in the presence of dual citizens instructions, that is,
602 * instructions which belong to more than one subroutine due to the
603 * merging of control flow without a RET instruction, we will map the
604 * target label of a GOTO to the label used by the instantiation lowest
605 * on the stack. This avoids code duplication during inlining in most
606 * cases.
607 *
608 * @see #findOwner(int)
609 */
610 public final Map<LabelNode, LabelNode> rangeTable = new HashMap<LabelNode, LabelNode>();
611
612 /**
613 * All returns for this instantiation will be mapped to this label
614 */
615 public final LabelNode returnLabel;
616
617 Instantiation(final Instantiation prev, final BitSet sub) {
618 previous = prev;
619 subroutine = sub;
620 for (Instantiation p = prev; p != null; p = p.previous) {
621 if (p.subroutine == sub) {
622 throw new RuntimeException("Recursive invocation of " + sub);
623 }
624 }
625
626 // Determine the label to return to when this subroutine terminates
627 // via RET: note that the main subroutine never terminates via RET.
628 if (prev != null) {
629 returnLabel = new LabelNode();
630 } else {
631 returnLabel = null;
632 }
633
634 // Each instantiation will remap the labels from the code above to
635 // refer to its particular copy of its own instructions. Note that
636 // we collapse labels which point at the same instruction into one:
637 // this is fairly common as we are often ignoring large chunks of
638 // instructions, so what were previously distinct labels become
639 // duplicates.
640 LabelNode duplbl = null;
641 for (int i = 0, c = instructions.size(); i < c; i++) {
642 AbstractInsnNode insn = instructions.get(i);
643
644 if (insn.getType() == AbstractInsnNode.LABEL) {
645 LabelNode ilbl = (LabelNode) insn;
646
647 if (duplbl == null) {
648 // if we already have a label pointing at this spot,
649 // don't recreate it.
650 duplbl = new LabelNode();
651 }
652
653 // Add an entry in the rangeTable for every label
654 // in the original code which points at the next
655 // instruction of our own to be emitted.
656 rangeTable.put(ilbl, duplbl);
657 } else if (findOwner(i) == this) {
658 // We will emit this instruction, so clear the 'duplbl' flag
659 // since the next Label will refer to a distinct
660 // instruction.
661 duplbl = null;
662 }
663 }
664 }
665
666 /**
667 * Returns the "owner" of a particular instruction relative to this
668 * instantiation: the owner referes to the Instantiation which will emit
669 * the version of this instruction that we will execute.
670 *
671 * Typically, the return value is either <code>this</code> or
672 * <code>null</code>. <code>this</code> indicates that this
673 * instantiation will generate the version of this instruction that we
674 * will execute, and <code>null</code> indicates that this instantiation
675 * never executes the given instruction.
676 *
677 * Sometimes, however, an instruction can belong to multiple
678 * subroutines; this is called a "dual citizen" instruction (though it
679 * may belong to more than 2 subroutines), and occurs when multiple
680 * subroutines branch to common points of control. In this case, the
681 * owner is the subroutine that appears lowest on the stack, and which
682 * also owns the instruction in question.
683 *
684 * @param i
685 * the index of the instruction in the original code
686 * @return the "owner" of a particular instruction relative to this
687 * instantiation.
688 */
689 public Instantiation findOwner(final int i) {
690 if (!subroutine.get(i)) {
691 return null;
692 }
693 if (!dualCitizens.get(i)) {
694 return this;
695 }
696 Instantiation own = this;
697 for (Instantiation p = previous; p != null; p = p.previous) {
698 if (p.subroutine.get(i)) {
699 own = p;
700 }
701 }
702 return own;
703 }
704
705 /**
706 * Looks up the label <code>l</code> in the <code>gotoTable</code>, thus
707 * translating it from a Label in the original code, to a Label in the
708 * inlined code that is appropriate for use by an instruction that
709 * branched to the original label.
710 *
711 * @param l
712 * The label we will be translating
713 * @return a label for use by a branch instruction in the inlined code
714 * @see #rangeLabel
715 */
716 public LabelNode gotoLabel(final LabelNode l) {
717 // owner should never be null, because owner is only null
718 // if an instruction cannot be reached from this subroutine
719 Instantiation owner = findOwner(instructions.indexOf(l));
720 return owner.rangeTable.get(l);
721 }
722
723 /**
724 * Looks up the label <code>l</code> in the <code>rangeTable</code>,
725 * thus translating it from a Label in the original code, to a Label in
726 * the inlined code that is appropriate for use by an try/catch or
727 * variable use annotation.
728 *
729 * @param l
730 * The label we will be translating
731 * @return a label for use by a try/catch or variable annotation in the
732 * original code
733 * @see #rangeTable
734 */
735 public LabelNode rangeLabel(final LabelNode l) {
736 return rangeTable.get(l);
737 }
738
739 // AbstractMap implementation
740
741 @Override
742 public Set<Map.Entry<LabelNode, LabelNode>> entrySet() {
743 return null;
744 }
745
746 @Override
747 public LabelNode get(final Object o) {
748 return gotoLabel((LabelNode) o);
749 }
750 }
701 public LabelNode get(final Object o) {
702 return gotoLabel((LabelNode) o);
703 }
704 }
751705 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.commons;
3028
3129 import org.eclipse.persistence.internal.libraries.asm.AnnotationVisitor;
3634 import org.eclipse.persistence.internal.libraries.asm.TypePath;
3735
3836 /**
39 * A {@link MethodVisitor} that renumbers local variables in their order of
40 * appearance. This adapter allows one to easily add new local variables to a
41 * method. It may be used by inheriting from this class, but the preferred way
42 * of using it is via delegation: the next visitor in the chain can indeed add
43 * new locals when needed by calling {@link #newLocal} on this adapter (this
44 * requires a reference back to this {@link LocalVariablesSorter}).
45 *
37 * A {@link MethodVisitor} that renumbers local variables in their order of appearance. This adapter
38 * allows one to easily add new local variables to a method. It may be used by inheriting from this
39 * class, but the preferred way of using it is via delegation: the next visitor in the chain can
40 * indeed add new locals when needed by calling {@link #newLocal} on this adapter (this requires a
41 * reference back to this {@link LocalVariablesSorter}).
42 *
4643 * @author Chris Nokleberg
4744 * @author Eugene Kuleshov
4845 * @author Eric Bruneton
4946 */
5047 public class LocalVariablesSorter extends MethodVisitor {
5148
52 private static final Type OBJECT_TYPE = Type
53 .getObjectType("java/lang/Object");
54
55 /**
56 * Mapping from old to new local variable indexes. A local variable at index
57 * i of size 1 is remapped to 'mapping[2*i]', while a local variable at
58 * index i of size 2 is remapped to 'mapping[2*i+1]'.
59 */
60 private int[] mapping = new int[40];
61
62 /**
63 * Array used to store stack map local variable types after remapping.
64 */
65 private Object[] newLocals = new Object[20];
66
67 /**
68 * Index of the first local variable, after formal parameters.
69 */
70 protected final int firstLocal;
71
72 /**
73 * Index of the next local variable to be created by {@link #newLocal}.
74 */
75 protected int nextLocal;
76
77 /**
78 * Creates a new {@link LocalVariablesSorter}. <i>Subclasses must not use
79 * this constructor</i>. Instead, they must use the
80 * {@link #LocalVariablesSorter(int, int, String, MethodVisitor)} version.
81 *
82 * @param access
83 * access flags of the adapted method.
84 * @param desc
85 * the method's descriptor (see {@link Type Type}).
86 * @param mv
87 * the method visitor to which this adapter delegates calls.
88 * @throws IllegalStateException
89 * If a subclass calls this constructor.
90 */
91 public LocalVariablesSorter(final int access, final String desc,
92 final MethodVisitor mv) {
93 this(Opcodes.ASM6, access, desc, mv);
94 if (getClass() != LocalVariablesSorter.class) {
95 throw new IllegalStateException();
49 private static final Type OBJECT_TYPE = Type.getObjectType("java/lang/Object");
50
51 /**
52 * Mapping from old to new local variable indexes. A local variable at index i of size 1 is
53 * remapped to 'mapping[2*i]', while a local variable at index i of size 2 is remapped to
54 * 'mapping[2*i+1]'.
55 */
56 private int[] mapping = new int[40];
57
58 /** Array used to store stack map local variable types after remapping. */
59 private Object[] newLocals = new Object[20];
60
61 /** Index of the first local variable, after formal parameters. */
62 protected final int firstLocal;
63
64 /** Index of the next local variable to be created by {@link #newLocal}. */
65 protected int nextLocal;
66
67 /**
68 * Constructs a new {@link LocalVariablesSorter}. <i>Subclasses must not use this constructor</i>.
69 * Instead, they must use the {@link #LocalVariablesSorter(int, int, String, MethodVisitor)}
70 * version.
71 *
72 * @param access access flags of the adapted method.
73 * @param desc the method's descriptor (see {@link Type Type}).
74 * @param mv the method visitor to which this adapter delegates calls.
75 * @throws IllegalStateException If a subclass calls this constructor.
76 */
77 public LocalVariablesSorter(final int access, final String desc, final MethodVisitor mv) {
78 this(Opcodes.ASM6, access, desc, mv);
79 if (getClass() != LocalVariablesSorter.class) {
80 throw new IllegalStateException();
81 }
82 }
83
84 /**
85 * Constructs a new {@link LocalVariablesSorter}.
86 *
87 * @param api the ASM API version implemented by this visitor. Must be one of {@link
88 * Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
89 * @param access access flags of the adapted method.
90 * @param desc the method's descriptor (see {@link Type Type}).
91 * @param mv the method visitor to which this adapter delegates calls.
92 */
93 protected LocalVariablesSorter(
94 final int api, final int access, final String desc, final MethodVisitor mv) {
95 super(api, mv);
96 Type[] args = Type.getArgumentTypes(desc);
97 nextLocal = (Opcodes.ACC_STATIC & access) == 0 ? 1 : 0;
98 for (int i = 0; i < args.length; i++) {
99 nextLocal += args[i].getSize();
100 }
101 firstLocal = nextLocal;
102 }
103
104 @Override
105 public void visitVarInsn(final int opcode, final int var) {
106 Type type;
107 switch (opcode) {
108 case Opcodes.LLOAD:
109 case Opcodes.LSTORE:
110 type = Type.LONG_TYPE;
111 break;
112
113 case Opcodes.DLOAD:
114 case Opcodes.DSTORE:
115 type = Type.DOUBLE_TYPE;
116 break;
117
118 case Opcodes.FLOAD:
119 case Opcodes.FSTORE:
120 type = Type.FLOAT_TYPE;
121 break;
122
123 case Opcodes.ILOAD:
124 case Opcodes.ISTORE:
125 type = Type.INT_TYPE;
126 break;
127
128 default:
129 // case Opcodes.ALOAD:
130 // case Opcodes.ASTORE:
131 // case RET:
132 type = OBJECT_TYPE;
133 break;
134 }
135 mv.visitVarInsn(opcode, remap(var, type));
136 }
137
138 @Override
139 public void visitIincInsn(final int var, final int increment) {
140 mv.visitIincInsn(remap(var, Type.INT_TYPE), increment);
141 }
142
143 @Override
144 public void visitMaxs(final int maxStack, final int maxLocals) {
145 mv.visitMaxs(maxStack, nextLocal);
146 }
147
148 @Override
149 public void visitLocalVariable(
150 final String name,
151 final String desc,
152 final String signature,
153 final Label start,
154 final Label end,
155 final int index) {
156 int newIndex = remap(index, Type.getType(desc));
157 mv.visitLocalVariable(name, desc, signature, start, end, newIndex);
158 }
159
160 @Override
161 public AnnotationVisitor visitLocalVariableAnnotation(
162 int typeRef,
163 TypePath typePath,
164 Label[] start,
165 Label[] end,
166 int[] index,
167 String desc,
168 boolean visible) {
169 Type t = Type.getType(desc);
170 int[] newIndex = new int[index.length];
171 for (int i = 0; i < newIndex.length; ++i) {
172 newIndex[i] = remap(index[i], t);
173 }
174 return mv.visitLocalVariableAnnotation(typeRef, typePath, start, end, newIndex, desc, visible);
175 }
176
177 @Override
178 public void visitFrame(
179 final int type,
180 final int nLocal,
181 final Object[] local,
182 final int nStack,
183 final Object[] stack) {
184 if (type != Opcodes.F_NEW) { // uncompressed frame
185 throw new IllegalArgumentException(
186 "LocalVariablesSorter only accepts expanded frames (see ClassReader.EXPAND_FRAMES)");
187 }
188
189 // creates a copy of newLocals
190 Object[] oldLocals = new Object[newLocals.length];
191 System.arraycopy(newLocals, 0, oldLocals, 0, oldLocals.length);
192
193 updateNewLocals(newLocals);
194
195 // copies types from 'local' to 'newLocals'
196 // 'newLocals' already contains the variables added with 'newLocal'
197
198 int index = 0; // old local variable index
199 int number = 0; // old local variable number
200 for (; number < nLocal; ++number) {
201 Object t = local[number];
202 int size = t == Opcodes.LONG || t == Opcodes.DOUBLE ? 2 : 1;
203 if (t != Opcodes.TOP) {
204 Type typ = OBJECT_TYPE;
205 if (t == Opcodes.INTEGER) {
206 typ = Type.INT_TYPE;
207 } else if (t == Opcodes.FLOAT) {
208 typ = Type.FLOAT_TYPE;
209 } else if (t == Opcodes.LONG) {
210 typ = Type.LONG_TYPE;
211 } else if (t == Opcodes.DOUBLE) {
212 typ = Type.DOUBLE_TYPE;
213 } else if (t instanceof String) {
214 typ = Type.getObjectType((String) t);
96215 }
97 }
98
99 /**
100 * Creates a new {@link LocalVariablesSorter}.
101 *
102 * @param api
103 * the ASM API version implemented by this visitor. Must be one
104 * of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
105 * @param access
106 * access flags of the adapted method.
107 * @param desc
108 * the method's descriptor (see {@link Type Type}).
109 * @param mv
110 * the method visitor to which this adapter delegates calls.
111 */
112 protected LocalVariablesSorter(final int api, final int access,
113 final String desc, final MethodVisitor mv) {
114 super(api, mv);
115 Type[] args = Type.getArgumentTypes(desc);
116 nextLocal = (Opcodes.ACC_STATIC & access) == 0 ? 1 : 0;
117 for (int i = 0; i < args.length; i++) {
118 nextLocal += args[i].getSize();
216 setFrameLocal(remap(index, typ), t);
217 }
218 index += size;
219 }
220
221 // removes TOP after long and double types as well as trailing TOPs
222
223 index = 0;
224 number = 0;
225 for (int i = 0; index < newLocals.length; ++i) {
226 Object t = newLocals[index++];
227 if (t != null && t != Opcodes.TOP) {
228 newLocals[i] = t;
229 number = i + 1;
230 if (t == Opcodes.LONG || t == Opcodes.DOUBLE) {
231 index += 1;
119232 }
120 firstLocal = nextLocal;
121 }
122
123 @Override
124 public void visitVarInsn(final int opcode, final int var) {
125 Type type;
126 switch (opcode) {
127 case Opcodes.LLOAD:
128 case Opcodes.LSTORE:
129 type = Type.LONG_TYPE;
130 break;
131
132 case Opcodes.DLOAD:
133 case Opcodes.DSTORE:
134 type = Type.DOUBLE_TYPE;
135 break;
136
137 case Opcodes.FLOAD:
138 case Opcodes.FSTORE:
139 type = Type.FLOAT_TYPE;
140 break;
141
142 case Opcodes.ILOAD:
143 case Opcodes.ISTORE:
144 type = Type.INT_TYPE;
145 break;
146
147 default:
148 // case Opcodes.ALOAD:
149 // case Opcodes.ASTORE:
150 // case RET:
151 type = OBJECT_TYPE;
152 break;
153 }
154 mv.visitVarInsn(opcode, remap(var, type));
155 }
156
157 @Override
158 public void visitIincInsn(final int var, final int increment) {
159 mv.visitIincInsn(remap(var, Type.INT_TYPE), increment);
160 }
161
162 @Override
163 public void visitMaxs(final int maxStack, final int maxLocals) {
164 mv.visitMaxs(maxStack, nextLocal);
165 }
166
167 @Override
168 public void visitLocalVariable(final String name, final String desc,
169 final String signature, final Label start, final Label end,
170 final int index) {
171 int newIndex = remap(index, Type.getType(desc));
172 mv.visitLocalVariable(name, desc, signature, start, end, newIndex);
173 }
174
175 @Override
176 public AnnotationVisitor visitLocalVariableAnnotation(int typeRef,
177 TypePath typePath, Label[] start, Label[] end, int[] index,
178 String desc, boolean visible) {
179 Type t = Type.getType(desc);
180 int[] newIndex = new int[index.length];
181 for (int i = 0; i < newIndex.length; ++i) {
182 newIndex[i] = remap(index[i], t);
183 }
184 return mv.visitLocalVariableAnnotation(typeRef, typePath, start, end,
185 newIndex, desc, visible);
186 }
187
188 @Override
189 public void visitFrame(final int type, final int nLocal,
190 final Object[] local, final int nStack, final Object[] stack) {
191 if (type != Opcodes.F_NEW) { // uncompressed frame
192 throw new IllegalStateException(
193 "ClassReader.accept() should be called with EXPAND_FRAMES flag");
194 }
195
196 // creates a copy of newLocals
197 Object[] oldLocals = new Object[newLocals.length];
198 System.arraycopy(newLocals, 0, oldLocals, 0, oldLocals.length);
199
200 updateNewLocals(newLocals);
201
202 // copies types from 'local' to 'newLocals'
203 // 'newLocals' already contains the variables added with 'newLocal'
204
205 int index = 0; // old local variable index
206 int number = 0; // old local variable number
207 for (; number < nLocal; ++number) {
208 Object t = local[number];
209 int size = t == Opcodes.LONG || t == Opcodes.DOUBLE ? 2 : 1;
210 if (t != Opcodes.TOP) {
211 Type typ = OBJECT_TYPE;
212 if (t == Opcodes.INTEGER) {
213 typ = Type.INT_TYPE;
214 } else if (t == Opcodes.FLOAT) {
215 typ = Type.FLOAT_TYPE;
216 } else if (t == Opcodes.LONG) {
217 typ = Type.LONG_TYPE;
218 } else if (t == Opcodes.DOUBLE) {
219 typ = Type.DOUBLE_TYPE;
220 } else if (t instanceof String) {
221 typ = Type.getObjectType((String) t);
222 }
223 setFrameLocal(remap(index, typ), t);
224 }
225 index += size;
226 }
227
228 // removes TOP after long and double types as well as trailing TOPs
229
230 index = 0;
231 number = 0;
232 for (int i = 0; index < newLocals.length; ++i) {
233 Object t = newLocals[index++];
234 if (t != null && t != Opcodes.TOP) {
235 newLocals[i] = t;
236 number = i + 1;
237 if (t == Opcodes.LONG || t == Opcodes.DOUBLE) {
238 index += 1;
239 }
240 } else {
241 newLocals[i] = Opcodes.TOP;
242 }
243 }
244
245 // visits remapped frame
246 mv.visitFrame(type, number, newLocals, nStack, stack);
247
248 // restores original value of 'newLocals'
249 newLocals = oldLocals;
250 }
251
252 // -------------
253
254 /**
255 * Creates a new local variable of the given type.
256 *
257 * @param type
258 * the type of the local variable to be created.
259 * @return the identifier of the newly created local variable.
260 */
261 public int newLocal(final Type type) {
262 Object t;
263 switch (type.getSort()) {
264 case Type.BOOLEAN:
265 case Type.CHAR:
266 case Type.BYTE:
267 case Type.SHORT:
268 case Type.INT:
269 t = Opcodes.INTEGER;
270 break;
271 case Type.FLOAT:
272 t = Opcodes.FLOAT;
273 break;
274 case Type.LONG:
275 t = Opcodes.LONG;
276 break;
277 case Type.DOUBLE:
278 t = Opcodes.DOUBLE;
279 break;
280 case Type.ARRAY:
281 t = type.getDescriptor();
282 break;
233 } else {
234 newLocals[i] = Opcodes.TOP;
235 }
236 }
237
238 // visits remapped frame
239 mv.visitFrame(type, number, newLocals, nStack, stack);
240
241 // restores original value of 'newLocals'
242 newLocals = oldLocals;
243 }
244
245 // -------------
246
247 /**
248 * Constructs a new local variable of the given type.
249 *
250 * @param type the type of the local variable to be created.
251 * @return the identifier of the newly created local variable.
252 */
253 public int newLocal(final Type type) {
254 Object t;
255 switch (type.getSort()) {
256 case Type.BOOLEAN:
257 case Type.CHAR:
258 case Type.BYTE:
259 case Type.SHORT:
260 case Type.INT:
261 t = Opcodes.INTEGER;
262 break;
263 case Type.FLOAT:
264 t = Opcodes.FLOAT;
265 break;
266 case Type.LONG:
267 t = Opcodes.LONG;
268 break;
269 case Type.DOUBLE:
270 t = Opcodes.DOUBLE;
271 break;
272 case Type.ARRAY:
273 t = type.getDescriptor();
274 break;
283275 // case Type.OBJECT:
284 default:
285 t = type.getInternalName();
286 break;
287 }
288 int local = newLocalMapping(type);
289 setLocalType(local, type);
290 setFrameLocal(local, t);
291 return local;
292 }
293
294 /**
295 * Notifies subclasses that a new stack map frame is being visited. The
296 * array argument contains the stack map frame types corresponding to the
297 * local variables added with {@link #newLocal}. This method can update
298 * these types in place for the stack map frame being visited. The default
299 * implementation of this method does nothing, i.e. a local variable added
300 * with {@link #newLocal} will have the same type in all stack map frames.
301 * But this behavior is not always the desired one, for instance if a local
302 * variable is added in the middle of a try/catch block: the frame for the
303 * exception handler should have a TOP type for this new local.
304 *
305 * @param newLocals
306 * the stack map frame types corresponding to the local variables
307 * added with {@link #newLocal} (and null for the others). The
308 * format of this array is the same as in
309 * {@link MethodVisitor#visitFrame}, except that long and double
310 * types use two slots. The types for the current stack map frame
311 * must be updated in place in this array.
312 */
313 protected void updateNewLocals(Object[] newLocals) {
314 }
315
316 /**
317 * Notifies subclasses that a local variable has been added or remapped. The
318 * default implementation of this method does nothing.
319 *
320 * @param local
321 * a local variable identifier, as returned by {@link #newLocal
322 * newLocal()}.
323 * @param type
324 * the type of the value being stored in the local variable.
325 */
326 protected void setLocalType(final int local, final Type type) {
327 }
328
329 private void setFrameLocal(final int local, final Object type) {
330 int l = newLocals.length;
331 if (local >= l) {
332 Object[] a = new Object[Math.max(2 * l, local + 1)];
333 System.arraycopy(newLocals, 0, a, 0, l);
334 newLocals = a;
335 }
336 newLocals[local] = type;
337 }
338
339 private int remap(final int var, final Type type) {
340 if (var + type.getSize() <= firstLocal) {
341 return var;
342 }
343 int key = 2 * var + type.getSize() - 1;
344 int size = mapping.length;
345 if (key >= size) {
346 int[] newMapping = new int[Math.max(2 * size, key + 1)];
347 System.arraycopy(mapping, 0, newMapping, 0, size);
348 mapping = newMapping;
349 }
350 int value = mapping[key];
351 if (value == 0) {
352 value = newLocalMapping(type);
353 setLocalType(value, type);
354 mapping[key] = value + 1;
355 } else {
356 value--;
357 }
358 return value;
359 }
360
361 protected int newLocalMapping(final Type type) {
362 int local = nextLocal;
363 nextLocal += type.getSize();
364 return local;
365 }
276 default:
277 t = type.getInternalName();
278 break;
279 }
280 int local = newLocalMapping(type);
281 setLocalType(local, type);
282 setFrameLocal(local, t);
283 return local;
284 }
285
286 /**
287 * Notifies subclasses that a new stack map frame is being visited. The array argument contains
288 * the stack map frame types corresponding to the local variables added with {@link #newLocal}.
289 * This method can update these types in place for the stack map frame being visited. The default
290 * implementation of this method does nothing, i.e. a local variable added with {@link #newLocal}
291 * will have the same type in all stack map frames. But this behavior is not always the desired
292 * one, for instance if a local variable is added in the middle of a try/catch block: the frame
293 * for the exception handler should have a TOP type for this new local.
294 *
295 * @param newLocals the stack map frame types corresponding to the local variables added with
296 * {@link #newLocal} (and null for the others). The format of this array is the same as in
297 * {@link MethodVisitor#visitFrame}, except that long and double types use two slots. The
298 * types for the current stack map frame must be updated in place in this array.
299 */
300 protected void updateNewLocals(Object[] newLocals) {}
301
302 /**
303 * Notifies subclasses that a local variable has been added or remapped. The default
304 * implementation of this method does nothing.
305 *
306 * @param local a local variable identifier, as returned by {@link #newLocal newLocal()}.
307 * @param type the type of the value being stored in the local variable.
308 */
309 protected void setLocalType(final int local, final Type type) {}
310
311 private void setFrameLocal(final int local, final Object type) {
312 int l = newLocals.length;
313 if (local >= l) {
314 Object[] a = new Object[Math.max(2 * l, local + 1)];
315 System.arraycopy(newLocals, 0, a, 0, l);
316 newLocals = a;
317 }
318 newLocals[local] = type;
319 }
320
321 private int remap(final int var, final Type type) {
322 if (var + type.getSize() <= firstLocal) {
323 return var;
324 }
325 int key = 2 * var + type.getSize() - 1;
326 int size = mapping.length;
327 if (key >= size) {
328 int[] newMapping = new int[Math.max(2 * size, key + 1)];
329 System.arraycopy(mapping, 0, newMapping, 0, size);
330 mapping = newMapping;
331 }
332 int value = mapping[key];
333 if (value == 0) {
334 value = newLocalMapping(type);
335 setLocalType(value, type);
336 mapping[key] = value + 1;
337 } else {
338 value--;
339 }
340 return value;
341 }
342
343 protected int newLocalMapping(final Type type) {
344 int local = nextLocal;
345 nextLocal += type.getSize();
346 return local;
347 }
366348 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.commons;
3028
3129 import java.util.HashMap;
3533
3634 /**
3735 * A named method descriptor.
38 *
36 *
3937 * @author Juozas Baliuka
4038 * @author Chris Nokleberg
4139 * @author Eric Bruneton
4240 */
4341 public class Method {
4442
45 /**
46 * The method name.
47 */
48 private final String name;
49
50 /**
51 * The method descriptor.
52 */
53 private final String desc;
54
55 /**
56 * Maps primitive Java type names to their descriptors.
57 */
58 private static final Map<String, String> DESCRIPTORS;
59
60 static {
61 DESCRIPTORS = new HashMap<String, String>();
62 DESCRIPTORS.put("void", "V");
63 DESCRIPTORS.put("byte", "B");
64 DESCRIPTORS.put("char", "C");
65 DESCRIPTORS.put("double", "D");
66 DESCRIPTORS.put("float", "F");
67 DESCRIPTORS.put("int", "I");
68 DESCRIPTORS.put("long", "J");
69 DESCRIPTORS.put("short", "S");
70 DESCRIPTORS.put("boolean", "Z");
71 }
72
73 /**
74 * Creates a new {@link Method}.
75 *
76 * @param name
77 * the method's name.
78 * @param desc
79 * the method's descriptor.
80 */
81 public Method(final String name, final String desc) {
82 this.name = name;
83 this.desc = desc;
84 }
85
86 /**
87 * Creates a new {@link Method}.
88 *
89 * @param name
90 * the method's name.
91 * @param returnType
92 * the method's return type.
93 * @param argumentTypes
94 * the method's argument types.
95 */
96 public Method(final String name, final Type returnType,
97 final Type[] argumentTypes) {
98 this(name, Type.getMethodDescriptor(returnType, argumentTypes));
99 }
100
101 /**
102 * Creates a new {@link Method}.
103 *
104 * @param m
105 * a java.lang.reflect method descriptor
106 * @return a {@link Method} corresponding to the given Java method
107 * declaration.
108 */
109 public static Method getMethod(java.lang.reflect.Method m) {
110 return new Method(m.getName(), Type.getMethodDescriptor(m));
111 }
112
113 /**
114 * Creates a new {@link Method}.
115 *
116 * @param c
117 * a java.lang.reflect constructor descriptor
118 * @return a {@link Method} corresponding to the given Java constructor
119 * declaration.
120 */
121 public static Method getMethod(java.lang.reflect.Constructor<?> c) {
122 return new Method("<init>", Type.getConstructorDescriptor(c));
123 }
124
125 /**
126 * Returns a {@link Method} corresponding to the given Java method
127 * declaration.
128 *
129 * @param method
130 * a Java method declaration, without argument names, of the form
131 * "returnType name (argumentType1, ... argumentTypeN)", where
132 * the types are in plain Java (e.g. "int", "float",
133 * "java.util.List", ...). Classes of the java.lang package can
134 * be specified by their unqualified name; all other classes
135 * names must be fully qualified.
136 * @return a {@link Method} corresponding to the given Java method
137 * declaration.
138 * @throws IllegalArgumentException
139 * if <code>method</code> could not get parsed.
140 */
141 public static Method getMethod(final String method)
142 throws IllegalArgumentException {
143 return getMethod(method, false);
144 }
145
146 /**
147 * Returns a {@link Method} corresponding to the given Java method
148 * declaration.
149 *
150 * @param method
151 * a Java method declaration, without argument names, of the form
152 * "returnType name (argumentType1, ... argumentTypeN)", where
153 * the types are in plain Java (e.g. "int", "float",
154 * "java.util.List", ...). Classes of the java.lang package may
155 * be specified by their unqualified name, depending on the
156 * defaultPackage argument; all other classes names must be fully
157 * qualified.
158 * @param defaultPackage
159 * true if unqualified class names belong to the default package,
160 * or false if they correspond to java.lang classes. For instance
161 * "Object" means "Object" if this option is true, or
162 * "java.lang.Object" otherwise.
163 * @return a {@link Method} corresponding to the given Java method
164 * declaration.
165 * @throws IllegalArgumentException
166 * if <code>method</code> could not get parsed.
167 */
168 public static Method getMethod(final String method,
169 final boolean defaultPackage) throws IllegalArgumentException {
170 int space = method.indexOf(' ');
171 int start = method.indexOf('(', space) + 1;
172 int end = method.indexOf(')', start);
173 if (space == -1 || start == -1 || end == -1) {
174 throw new IllegalArgumentException();
43 /** The method name. */
44 private final String name;
45
46 /** The method descriptor. */
47 private final String desc;
48
49 /** Maps primitive Java type names to their descriptors. */
50 private static final Map<String, String> DESCRIPTORS;
51
52 static {
53 DESCRIPTORS = new HashMap<String, String>();
54 DESCRIPTORS.put("void", "V");
55 DESCRIPTORS.put("byte", "B");
56 DESCRIPTORS.put("char", "C");
57 DESCRIPTORS.put("double", "D");
58 DESCRIPTORS.put("float", "F");
59 DESCRIPTORS.put("int", "I");
60 DESCRIPTORS.put("long", "J");
61 DESCRIPTORS.put("short", "S");
62 DESCRIPTORS.put("boolean", "Z");
63 }
64
65 /**
66 * Constructs a new {@link Method}.
67 *
68 * @param name the method's name.
69 * @param desc the method's descriptor.
70 */
71 public Method(final String name, final String desc) {
72 this.name = name;
73 this.desc = desc;
74 }
75
76 /**
77 * Constructs a new {@link Method}.
78 *
79 * @param name the method's name.
80 * @param returnType the method's return type.
81 * @param argumentTypes the method's argument types.
82 */
83 public Method(final String name, final Type returnType, final Type[] argumentTypes) {
84 this(name, Type.getMethodDescriptor(returnType, argumentTypes));
85 }
86
87 /**
88 * Creates a new {@link Method}.
89 *
90 * @param m a java.lang.reflect method descriptor
91 * @return a {@link Method} corresponding to the given Java method declaration.
92 */
93 public static Method getMethod(java.lang.reflect.Method m) {
94 return new Method(m.getName(), Type.getMethodDescriptor(m));
95 }
96
97 /**
98 * Creates a new {@link Method}.
99 *
100 * @param c a java.lang.reflect constructor descriptor
101 * @return a {@link Method} corresponding to the given Java constructor declaration.
102 */
103 public static Method getMethod(java.lang.reflect.Constructor<?> c) {
104 return new Method("<init>", Type.getConstructorDescriptor(c));
105 }
106
107 /**
108 * Returns a {@link Method} corresponding to the given Java method declaration.
109 *
110 * @param method a Java method declaration, without argument names, of the form "returnType name
111 * (argumentType1, ... argumentTypeN)", where the types are in plain Java (e.g. "int",
112 * "float", "java.util.List", ...). Classes of the java.lang package can be specified by their
113 * unqualified name; all other classes names must be fully qualified.
114 * @return a {@link Method} corresponding to the given Java method declaration.
115 * @throws IllegalArgumentException if <code>method</code> could not get parsed.
116 */
117 public static Method getMethod(final String method) throws IllegalArgumentException {
118 return getMethod(method, false);
119 }
120
121 /**
122 * Returns a {@link Method} corresponding to the given Java method declaration.
123 *
124 * @param method a Java method declaration, without argument names, of the form "returnType name
125 * (argumentType1, ... argumentTypeN)", where the types are in plain Java (e.g. "int",
126 * "float", "java.util.List", ...). Classes of the java.lang package may be specified by their
127 * unqualified name, depending on the defaultPackage argument; all other classes names must be
128 * fully qualified.
129 * @param defaultPackage true if unqualified class names belong to the default package, or false
130 * if they correspond to java.lang classes. For instance "Object" means "Object" if this
131 * option is true, or "java.lang.Object" otherwise.
132 * @return a {@link Method} corresponding to the given Java method declaration.
133 * @throws IllegalArgumentException if <code>method</code> could not get parsed.
134 */
135 public static Method getMethod(final String method, final boolean defaultPackage)
136 throws IllegalArgumentException {
137 int space = method.indexOf(' ');
138 int start = method.indexOf('(', space) + 1;
139 int end = method.indexOf(')', start);
140 if (space == -1 || start == 0 || end == -1) {
141 throw new IllegalArgumentException();
142 }
143 String returnType = method.substring(0, space);
144 String methodName = method.substring(space + 1, start - 1).trim();
145 StringBuilder sb = new StringBuilder();
146 sb.append('(');
147 int p;
148 do {
149 String s;
150 p = method.indexOf(',', start);
151 if (p == -1) {
152 s = map(method.substring(start, end).trim(), defaultPackage);
153 } else {
154 s = map(method.substring(start, p).trim(), defaultPackage);
155 start = p + 1;
156 }
157 sb.append(s);
158 } while (p != -1);
159 sb.append(')');
160 sb.append(map(returnType, defaultPackage));
161 return new Method(methodName, sb.toString());
162 }
163
164 private static String map(final String type, final boolean defaultPackage) {
165 if ("".equals(type)) {
166 return type;
167 }
168
169 StringBuilder sb = new StringBuilder();
170 int index = 0;
171 while ((index = type.indexOf("[]", index) + 1) > 0) {
172 sb.append('[');
173 }
174
175 String t = type.substring(0, type.length() - sb.length() * 2);
176 String desc = DESCRIPTORS.get(t);
177 if (desc != null) {
178 sb.append(desc);
179 } else {
180 sb.append('L');
181 if (t.indexOf('.') < 0) {
182 if (!defaultPackage) {
183 sb.append("java/lang/");
175184 }
176 String returnType = method.substring(0, space);
177 String methodName = method.substring(space + 1, start - 1).trim();
178 StringBuilder sb = new StringBuilder();
179 sb.append('(');
180 int p;
181 do {
182 String s;
183 p = method.indexOf(',', start);
184 if (p == -1) {
185 s = map(method.substring(start, end).trim(), defaultPackage);
186 } else {
187 s = map(method.substring(start, p).trim(), defaultPackage);
188 start = p + 1;
189 }
190 sb.append(s);
191 } while (p != -1);
192 sb.append(')');
193 sb.append(map(returnType, defaultPackage));
194 return new Method(methodName, sb.toString());
195 }
196
197 private static String map(final String type, final boolean defaultPackage) {
198 if ("".equals(type)) {
199 return type;
200 }
201
202 StringBuilder sb = new StringBuilder();
203 int index = 0;
204 while ((index = type.indexOf("[]", index) + 1) > 0) {
205 sb.append('[');
206 }
207
208 String t = type.substring(0, type.length() - sb.length() * 2);
209 String desc = DESCRIPTORS.get(t);
210 if (desc != null) {
211 sb.append(desc);
212 } else {
213 sb.append('L');
214 if (t.indexOf('.') < 0) {
215 if (!defaultPackage) {
216 sb.append("java/lang/");
217 }
218 sb.append(t);
219 } else {
220 sb.append(t.replace('.', '/'));
221 }
222 sb.append(';');
223 }
224 return sb.toString();
225 }
226
227 /**
228 * Returns the name of the method described by this object.
229 *
230 * @return the name of the method described by this object.
231 */
232 public String getName() {
233 return name;
234 }
235
236 /**
237 * Returns the descriptor of the method described by this object.
238 *
239 * @return the descriptor of the method described by this object.
240 */
241 public String getDescriptor() {
242 return desc;
243 }
244
245 /**
246 * Returns the return type of the method described by this object.
247 *
248 * @return the return type of the method described by this object.
249 */
250 public Type getReturnType() {
251 return Type.getReturnType(desc);
252 }
253
254 /**
255 * Returns the argument types of the method described by this object.
256 *
257 * @return the argument types of the method described by this object.
258 */
259 public Type[] getArgumentTypes() {
260 return Type.getArgumentTypes(desc);
261 }
262
263 @Override
264 public String toString() {
265 return name + desc;
266 }
267
268 @Override
269 public boolean equals(final Object o) {
270 if (!(o instanceof Method)) {
271 return false;
272 }
273 Method other = (Method) o;
274 return name.equals(other.name) && desc.equals(other.desc);
275 }
276
277 @Override
278 public int hashCode() {
279 return name.hashCode() ^ desc.hashCode();
280 }
281 }
185 sb.append(t);
186 } else {
187 sb.append(t.replace('.', '/'));
188 }
189 sb.append(';');
190 }
191 return sb.toString();
192 }
193
194 /**
195 * Returns the name of the method described by this object.
196 *
197 * @return the name of the method described by this object.
198 */
199 public String getName() {
200 return name;
201 }
202
203 /**
204 * Returns the descriptor of the method described by this object.
205 *
206 * @return the descriptor of the method described by this object.
207 */
208 public String getDescriptor() {
209 return desc;
210 }
211
212 /**
213 * Returns the return type of the method described by this object.
214 *
215 * @return the return type of the method described by this object.
216 */
217 public Type getReturnType() {
218 return Type.getReturnType(desc);
219 }
220
221 /**
222 * Returns the argument types of the method described by this object.
223 *
224 * @return the argument types of the method described by this object.
225 */
226 public Type[] getArgumentTypes() {
227 return Type.getArgumentTypes(desc);
228 }
229
230 @Override
231 public String toString() {
232 return name + desc;
233 }
234
235 @Override
236 public boolean equals(final Object o) {
237 if (!(o instanceof Method)) {
238 return false;
239 }
240 Method other = (Method) o;
241 return name.equals(other.name) && desc.equals(other.desc);
242 }
243
244 @Override
245 public int hashCode() {
246 return name.hashCode() ^ desc.hashCode();
247 }
248 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927
3028 package org.eclipse.persistence.internal.libraries.asm.commons;
3129
3836
3937 /**
4038 * A {@link LocalVariablesSorter} for type mapping.
41 *
39 *
4240 * @author Eugene Kuleshov
4341 */
4442 public class MethodRemapper extends MethodVisitor {
4543
46 protected final Remapper remapper;
47
48 public MethodRemapper(final MethodVisitor mv, final Remapper remapper) {
49 this(Opcodes.ASM6, mv, remapper);
50 }
51
52 protected MethodRemapper(final int api, final MethodVisitor mv,
53 final Remapper remapper) {
54 super(api, mv);
55 this.remapper = remapper;
56 }
57
58 @Override
59 public AnnotationVisitor visitAnnotationDefault() {
60 AnnotationVisitor av = super.visitAnnotationDefault();
61 return av == null ? av : new AnnotationRemapper(av, remapper);
62 }
63
64 @Override
65 public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
66 AnnotationVisitor av = super.visitAnnotation(remapper.mapDesc(desc),
67 visible);
68 return av == null ? av : new AnnotationRemapper(av, remapper);
69 }
70
71 @Override
72 public AnnotationVisitor visitTypeAnnotation(int typeRef,
73 TypePath typePath, String desc, boolean visible) {
74 AnnotationVisitor av = super.visitTypeAnnotation(typeRef, typePath,
75 remapper.mapDesc(desc), visible);
76 return av == null ? av : new AnnotationRemapper(av, remapper);
77 }
78
79 @Override
80 public AnnotationVisitor visitParameterAnnotation(int parameter,
81 String desc, boolean visible) {
82 AnnotationVisitor av = super.visitParameterAnnotation(parameter,
83 remapper.mapDesc(desc), visible);
84 return av == null ? av : new AnnotationRemapper(av, remapper);
85 }
86
87 @Override
88 public void visitFrame(int type, int nLocal, Object[] local, int nStack,
89 Object[] stack) {
90 super.visitFrame(type, nLocal, remapEntries(nLocal, local), nStack,
91 remapEntries(nStack, stack));
92 }
93
94 private Object[] remapEntries(int n, Object[] entries) {
95 for (int i = 0; i < n; i++) {
96 if (entries[i] instanceof String) {
97 Object[] newEntries = new Object[n];
98 if (i > 0) {
99 System.arraycopy(entries, 0, newEntries, 0, i);
100 }
101 do {
102 Object t = entries[i];
103 newEntries[i++] = t instanceof String ? remapper
104 .mapType((String) t) : t;
105 } while (i < n);
106 return newEntries;
107 }
44 protected final Remapper remapper;
45
46 public MethodRemapper(final MethodVisitor mv, final Remapper remapper) {
47 this(Opcodes.ASM6, mv, remapper);
48 }
49
50 protected MethodRemapper(final int api, final MethodVisitor mv, final Remapper remapper) {
51 super(api, mv);
52 this.remapper = remapper;
53 }
54
55 @Override
56 public AnnotationVisitor visitAnnotationDefault() {
57 AnnotationVisitor av = super.visitAnnotationDefault();
58 return av == null ? av : new AnnotationRemapper(api, av, remapper);
59 }
60
61 @Override
62 public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
63 AnnotationVisitor av = super.visitAnnotation(remapper.mapDesc(desc), visible);
64 return av == null ? av : new AnnotationRemapper(api, av, remapper);
65 }
66
67 @Override
68 public AnnotationVisitor visitTypeAnnotation(
69 int typeRef, TypePath typePath, String desc, boolean visible) {
70 AnnotationVisitor av =
71 super.visitTypeAnnotation(typeRef, typePath, remapper.mapDesc(desc), visible);
72 return av == null ? av : new AnnotationRemapper(api, av, remapper);
73 }
74
75 @Override
76 public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, boolean visible) {
77 AnnotationVisitor av =
78 super.visitParameterAnnotation(parameter, remapper.mapDesc(desc), visible);
79 return av == null ? av : new AnnotationRemapper(api, av, remapper);
80 }
81
82 @Override
83 public void visitFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack) {
84 super.visitFrame(
85 type, nLocal, remapEntries(nLocal, local), nStack, remapEntries(nStack, stack));
86 }
87
88 private Object[] remapEntries(int n, Object[] entries) {
89 if (entries != null) {
90 for (int i = 0; i < n; i++) {
91 if (entries[i] instanceof String) {
92 Object[] newEntries = new Object[n];
93 if (i > 0) {
94 System.arraycopy(entries, 0, newEntries, 0, i);
95 }
96 do {
97 Object t = entries[i];
98 newEntries[i++] = t instanceof String ? remapper.mapType((String) t) : t;
99 } while (i < n);
100 return newEntries;
108101 }
109 return entries;
110 }
111
112 @Override
113 public void visitFieldInsn(int opcode, String owner, String name,
114 String desc) {
115 super.visitFieldInsn(opcode, remapper.mapType(owner),
116 remapper.mapFieldName(owner, name, desc),
117 remapper.mapDesc(desc));
118 }
119
120 @Deprecated
121 @Override
122 public void visitMethodInsn(final int opcode, final String owner,
123 final String name, final String desc) {
124 if (api >= Opcodes.ASM5) {
125 super.visitMethodInsn(opcode, owner, name, desc);
126 return;
127 }
128 doVisitMethodInsn(opcode, owner, name, desc,
129 opcode == Opcodes.INVOKEINTERFACE);
130 }
131
132 @Override
133 public void visitMethodInsn(final int opcode, final String owner,
134 final String name, final String desc, final boolean itf) {
135 if (api < Opcodes.ASM5) {
136 super.visitMethodInsn(opcode, owner, name, desc, itf);
137 return;
138 }
139 doVisitMethodInsn(opcode, owner, name, desc, itf);
140 }
141
142 private void doVisitMethodInsn(int opcode, String owner, String name,
143 String desc, boolean itf) {
144 // Calling super.visitMethodInsn requires to call the correct version
145 // depending on this.api (otherwise infinite loops can occur). To
146 // simplify and to make it easier to automatically remove the backward
147 // compatibility code, we inline the code of the overridden method here.
148 // IMPORTANT: THIS ASSUMES THAT visitMethodInsn IS NOT OVERRIDDEN IN
149 // LocalVariableSorter.
150 if (mv != null) {
151 mv.visitMethodInsn(opcode, remapper.mapType(owner),
152 remapper.mapMethodName(owner, name, desc),
153 remapper.mapMethodDesc(desc), itf);
154 }
155 }
156
157 @Override
158 public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
159 Object... bsmArgs) {
160 for (int i = 0; i < bsmArgs.length; i++) {
161 bsmArgs[i] = remapper.mapValue(bsmArgs[i]);
162 }
163 super.visitInvokeDynamicInsn(
164 remapper.mapInvokeDynamicMethodName(name, desc),
165 remapper.mapMethodDesc(desc), (Handle) remapper.mapValue(bsm),
166 bsmArgs);
167 }
168
169 @Override
170 public void visitTypeInsn(int opcode, String type) {
171 super.visitTypeInsn(opcode, remapper.mapType(type));
172 }
173
174 @Override
175 public void visitLdcInsn(Object cst) {
176 super.visitLdcInsn(remapper.mapValue(cst));
177 }
178
179 @Override
180 public void visitMultiANewArrayInsn(String desc, int dims) {
181 super.visitMultiANewArrayInsn(remapper.mapDesc(desc), dims);
182 }
183
184 @Override
185 public AnnotationVisitor visitInsnAnnotation(int typeRef,
186 TypePath typePath, String desc, boolean visible) {
187 AnnotationVisitor av = super.visitInsnAnnotation(typeRef, typePath,
188 remapper.mapDesc(desc), visible);
189 return av == null ? av : new AnnotationRemapper(av, remapper);
190 }
191
192 @Override
193 public void visitTryCatchBlock(Label start, Label end, Label handler,
194 String type) {
195 super.visitTryCatchBlock(start, end, handler, type == null ? null
196 : remapper.mapType(type));
197 }
198
199 @Override
200 public AnnotationVisitor visitTryCatchAnnotation(int typeRef,
201 TypePath typePath, String desc, boolean visible) {
202 AnnotationVisitor av = super.visitTryCatchAnnotation(typeRef, typePath,
203 remapper.mapDesc(desc), visible);
204 return av == null ? av : new AnnotationRemapper(av, remapper);
205 }
206
207 @Override
208 public void visitLocalVariable(String name, String desc, String signature,
209 Label start, Label end, int index) {
210 super.visitLocalVariable(name, remapper.mapDesc(desc),
211 remapper.mapSignature(signature, true), start, end, index);
212 }
213
214 @Override
215 public AnnotationVisitor visitLocalVariableAnnotation(int typeRef,
216 TypePath typePath, Label[] start, Label[] end, int[] index,
217 String desc, boolean visible) {
218 AnnotationVisitor av = super.visitLocalVariableAnnotation(typeRef,
219 typePath, start, end, index, remapper.mapDesc(desc), visible);
220 return av == null ? av : new AnnotationRemapper(av, remapper);
221 }
102 }
103 }
104 return entries;
105 }
106
107 @Override
108 public void visitFieldInsn(int opcode, String owner, String name, String desc) {
109 super.visitFieldInsn(
110 opcode,
111 remapper.mapType(owner),
112 remapper.mapFieldName(owner, name, desc),
113 remapper.mapDesc(desc));
114 }
115
116 @Deprecated
117 @Override
118 public void visitMethodInsn(
119 final int opcode, final String owner, final String name, final String desc) {
120 if (api >= Opcodes.ASM5) {
121 super.visitMethodInsn(opcode, owner, name, desc);
122 return;
123 }
124 doVisitMethodInsn(opcode, owner, name, desc, opcode == Opcodes.INVOKEINTERFACE);
125 }
126
127 @Override
128 public void visitMethodInsn(
129 final int opcode,
130 final String owner,
131 final String name,
132 final String desc,
133 final boolean itf) {
134 if (api < Opcodes.ASM5) {
135 super.visitMethodInsn(opcode, owner, name, desc, itf);
136 return;
137 }
138 doVisitMethodInsn(opcode, owner, name, desc, itf);
139 }
140
141 private void doVisitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
142 // Calling super.visitMethodInsn requires to call the correct version
143 // depending on this.api (otherwise infinite loops can occur). To
144 // simplify and to make it easier to automatically remove the backward
145 // compatibility code, we inline the code of the overridden method here.
146 // IMPORTANT: THIS ASSUMES THAT visitMethodInsn IS NOT OVERRIDDEN IN
147 // LocalVariableSorter.
148 if (mv != null) {
149 mv.visitMethodInsn(
150 opcode,
151 remapper.mapType(owner),
152 remapper.mapMethodName(owner, name, desc),
153 remapper.mapMethodDesc(desc),
154 itf);
155 }
156 }
157
158 @Override
159 public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) {
160 Object[] remappedBsmArgs = new Object[bsmArgs.length];
161 for (int i = 0; i < bsmArgs.length; i++) {
162 remappedBsmArgs[i] = remapper.mapValue(bsmArgs[i]);
163 }
164 super.visitInvokeDynamicInsn(
165 remapper.mapInvokeDynamicMethodName(name, desc),
166 remapper.mapMethodDesc(desc),
167 (Handle) remapper.mapValue(bsm),
168 remappedBsmArgs);
169 }
170
171 @Override
172 public void visitTypeInsn(int opcode, String type) {
173 super.visitTypeInsn(opcode, remapper.mapType(type));
174 }
175
176 @Override
177 public void visitLdcInsn(Object cst) {
178 super.visitLdcInsn(remapper.mapValue(cst));
179 }
180
181 @Override
182 public void visitMultiANewArrayInsn(String desc, int dims) {
183 super.visitMultiANewArrayInsn(remapper.mapDesc(desc), dims);
184 }
185
186 @Override
187 public AnnotationVisitor visitInsnAnnotation(
188 int typeRef, TypePath typePath, String desc, boolean visible) {
189 AnnotationVisitor av =
190 super.visitInsnAnnotation(typeRef, typePath, remapper.mapDesc(desc), visible);
191 return av == null ? av : new AnnotationRemapper(api, av, remapper);
192 }
193
194 @Override
195 public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
196 super.visitTryCatchBlock(start, end, handler, type == null ? null : remapper.mapType(type));
197 }
198
199 @Override
200 public AnnotationVisitor visitTryCatchAnnotation(
201 int typeRef, TypePath typePath, String desc, boolean visible) {
202 AnnotationVisitor av =
203 super.visitTryCatchAnnotation(typeRef, typePath, remapper.mapDesc(desc), visible);
204 return av == null ? av : new AnnotationRemapper(api, av, remapper);
205 }
206
207 @Override
208 public void visitLocalVariable(
209 String name, String desc, String signature, Label start, Label end, int index) {
210 super.visitLocalVariable(
211 name, remapper.mapDesc(desc), remapper.mapSignature(signature, true), start, end, index);
212 }
213
214 @Override
215 public AnnotationVisitor visitLocalVariableAnnotation(
216 int typeRef,
217 TypePath typePath,
218 Label[] start,
219 Label[] end,
220 int[] index,
221 String desc,
222 boolean visible) {
223 AnnotationVisitor av =
224 super.visitLocalVariableAnnotation(
225 typeRef, typePath, start, end, index, remapper.mapDesc(desc), visible);
226 return av == null ? av : new AnnotationRemapper(api, av, remapper);
227 }
222228 }
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
27
28 package org.eclipse.persistence.internal.libraries.asm.commons;
29
30 import java.util.ArrayList;
31 import java.util.List;
32
33 import org.eclipse.persistence.internal.libraries.asm.Attribute;
34 import org.eclipse.persistence.internal.libraries.asm.ByteVector;
35 import org.eclipse.persistence.internal.libraries.asm.ClassReader;
36 import org.eclipse.persistence.internal.libraries.asm.ClassWriter;
37 import org.eclipse.persistence.internal.libraries.asm.Label;
38
39 /**
40 * ModuleHashes attribute. This attribute is specific to the OpenJDK and may change in the future.
41 *
42 * @author Remi Forax
43 */
44 public final class ModuleHashesAttribute extends Attribute {
45 public String algorithm;
46 public List<String> modules;
47 public List<byte[]> hashes;
48
49 /**
50 * Constructs an attribute with a hashing algorithm, a list of module names, and a list of the same
51 * length of hashes.
52 *
53 * @param algorithm the hashing algorithm name.
54 * @param modules a list of module name
55 * @param hashes a list of hash, one for each module name.
56 */
57 public ModuleHashesAttribute(
58 final String algorithm, final List<String> modules, final List<byte[]> hashes) {
59 super("ModuleHashes");
60 this.algorithm = algorithm;
61 this.modules = modules;
62 this.hashes = hashes;
63 }
64
65 /**
66 * Constructs an empty attribute that can be used as prototype to be passed as argument of the method
67 * {@link ClassReader#accept(org.eclipse.persistence.internal.libraries.asm.ClassVisitor, Attribute[], int)}.
68 */
69 public ModuleHashesAttribute() {
70 this(null, null, null);
71 }
72
73 @Override
74 protected Attribute read(
75 ClassReader cr, int off, int len, char[] buf, int codeOff, Label[] labels) {
76 String hashAlgorithm = cr.readUTF8(off, buf);
77
78 int count = cr.readUnsignedShort(off + 2);
79 ArrayList<String> modules = new ArrayList<String>(count);
80 ArrayList<byte[]> hashes = new ArrayList<byte[]>(count);
81 off += 4;
82
83 for (int i = 0; i < count; i++) {
84 String module = cr.readModule(off, buf);
85 int hashLength = cr.readUnsignedShort(off + 2);
86 off += 4;
87
88 byte[] hash = new byte[hashLength];
89 for (int j = 0; j < hashLength; j++) {
90 hash[j] = (byte) (cr.readByte(off + j) & 0xff);
91 }
92 off += hashLength;
93
94 modules.add(module);
95 hashes.add(hash);
96 }
97 return new ModuleHashesAttribute(hashAlgorithm, modules, hashes);
98 }
99
100 @Override
101 protected ByteVector write(ClassWriter cw, byte[] code, int len, int maxStack, int maxLocals) {
102 ByteVector v = new ByteVector();
103 int index = cw.newUTF8(algorithm);
104 v.putShort(index);
105
106 int count = (modules == null) ? 0 : modules.size();
107 v.putShort(count);
108
109 for (int i = 0; i < count; i++) {
110 String module = modules.get(i);
111 v.putShort(cw.newModule(module));
112
113 byte[] hash = hashes.get(i);
114 v.putShort(hash.length);
115 for (byte b : hash) {
116 v.putByte(b);
117 }
118 }
119 return v;
120 }
121 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927
3028 package org.eclipse.persistence.internal.libraries.asm.commons;
3129
3432
3533 /**
3634 * A {@link ModuleVisitor} adapter for type remapping.
37 *
35 *
3836 * @author Remi Forax
3937 */
4038 public class ModuleRemapper extends ModuleVisitor {
41 private final Remapper remapper;
39 private final Remapper remapper;
4240
43 public ModuleRemapper(final ModuleVisitor mv, final Remapper remapper) {
44 this(Opcodes.ASM6, mv, remapper);
41 public ModuleRemapper(final ModuleVisitor mv, final Remapper remapper) {
42 this(Opcodes.ASM6, mv, remapper);
43 }
44
45 protected ModuleRemapper(final int api, final ModuleVisitor mv, final Remapper remapper) {
46 super(api, mv);
47 this.remapper = remapper;
48 }
49
50 @Override
51 public void visitMainClass(String mainClass) {
52 super.visitMainClass(remapper.mapType(mainClass));
53 }
54
55 @Override
56 public void visitPackage(String packaze) {
57 super.visitPackage(remapper.mapPackageName(packaze));
58 }
59
60 @Override
61 public void visitRequire(String module, int access, String version) {
62 super.visitRequire(remapper.mapModuleName(module), access, version);
63 }
64
65 @Override
66 public void visitExport(String packaze, int access, String... modules) {
67 String[] newModules = null;
68 if (modules != null) {
69 newModules = new String[modules.length];
70 for (int i = 0; i < modules.length; i++) {
71 newModules[i] = remapper.mapModuleName(modules[i]);
72 }
4573 }
74 super.visitExport(remapper.mapPackageName(packaze), access, newModules);
75 }
4676
47 protected ModuleRemapper(final int api, final ModuleVisitor mv,
48 final Remapper remapper) {
49 super(api, mv);
50 this.remapper = remapper;
77 @Override
78 public void visitOpen(String packaze, int access, String... modules) {
79 String[] newModules = null;
80 if (modules != null) {
81 newModules = new String[modules.length];
82 for (int i = 0; i < modules.length; i++) {
83 newModules[i] = remapper.mapModuleName(modules[i]);
84 }
5185 }
86 super.visitOpen(remapper.mapPackageName(packaze), access, newModules);
87 }
5288
53 @Override
54 public void visitRequire(String module, int access) {
55 super.visitRequire(remapper.mapModuleName(module), access);
89 @Override
90 public void visitUse(String service) {
91 super.visitUse(remapper.mapType(service));
92 }
93
94 @Override
95 public void visitProvide(String service, String... providers) {
96 String[] newProviders = new String[providers.length];
97 for (int i = 0; i < providers.length; i++) {
98 newProviders[i] = remapper.mapType(providers[i]);
5699 }
57
58 @Override
59 public void visitExport(String packaze, String... modules) {
60 String[] newTos = null;
61 if (modules != null) {
62 newTos = new String[modules.length];
63 for(int i = 0 ; i < modules.length; i++) {
64 newTos[i] = remapper.mapModuleName(modules[i]);
65 }
66 }
67 super.visitExport(remapper.mapPackageName(packaze), newTos);
68 }
69
70 @Override
71 public void visitUse(String service) {
72 super.visitUse(remapper.mapType(service));
73 }
74
75 @Override
76 public void visitProvide(String service, String impl) {
77 super.visitProvide(remapper.mapType(service), remapper.mapType(impl));
78 }
100 super.visitProvide(remapper.mapType(service), newProviders);
101 }
79102 }
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
27
28 package org.eclipse.persistence.internal.libraries.asm.commons;
29
30 import org.eclipse.persistence.internal.libraries.asm.Attribute;
31 import org.eclipse.persistence.internal.libraries.asm.ByteVector;
32 import org.eclipse.persistence.internal.libraries.asm.ClassReader;
33 import org.eclipse.persistence.internal.libraries.asm.ClassWriter;
34 import org.eclipse.persistence.internal.libraries.asm.Label;
35
36 /**
37 * ModuleResolution_attribute. This attribute is specific to the OpenJDK and may change in the
38 * future.
39 *
40 * @author Remi Forax
41 */
42 public final class ModuleResolutionAttribute extends Attribute {
43 /**
44 * Resolution state of a module meaning that the module is not available from the class-path by
45 * default.
46 */
47 public static final int RESOLUTION_DO_NOT_RESOLVE_BY_DEFAULT = 1;
48
49 /** Resolution state of a module meaning the module is marked as deprecated. */
50 public static final int RESOLUTION_WARN_DEPRECATED = 2;
51
52 /**
53 * Resolution state of a module meaning the module is marked as deprecated and will be removed in
54 * a future release.
55 */
56 public static final int RESOLUTION_WARN_DEPRECATED_FOR_REMOVAL = 4;
57
58 /**
59 * Resolution state of a module meaning the module is not yet standardized, so in incubating mode.
60 */
61 public static final int RESOLUTION_WARN_INCUBATING = 8;
62
63 public int resolution;
64
65 /**
66 * Constructs an attribute with a resolution state value.
67 *
68 * @param resolution the resolution state among {@link #RESOLUTION_WARN_DEPRECATED}, {@link
69 * #RESOLUTION_WARN_DEPRECATED_FOR_REMOVAL}, and {@link #RESOLUTION_WARN_INCUBATING}.
70 */
71 public ModuleResolutionAttribute(final int resolution) {
72 super("ModuleResolution");
73 this.resolution = resolution;
74 }
75
76 /**
77 * Constructs an empty attribute that can be used as prototype to be passed as argument of the method
78 * {@link ClassReader#accept(org.eclipse.persistence.internal.libraries.asm.ClassVisitor, Attribute[], int)}.
79 */
80 public ModuleResolutionAttribute() {
81 this(0);
82 }
83
84 @Override
85 protected Attribute read(
86 ClassReader cr, int off, int len, char[] buf, int codeOff, Label[] labels) {
87 int resolution = cr.readUnsignedShort(off);
88 return new ModuleResolutionAttribute(resolution);
89 }
90
91 @Override
92 protected ByteVector write(ClassWriter cw, byte[] code, int len, int maxStack, int maxLocals) {
93 ByteVector v = new ByteVector();
94 v.putShort(resolution);
95 return v;
96 }
97 }
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
27
28 package org.eclipse.persistence.internal.libraries.asm.commons;
29
30 import org.eclipse.persistence.internal.libraries.asm.Attribute;
31 import org.eclipse.persistence.internal.libraries.asm.ByteVector;
32 import org.eclipse.persistence.internal.libraries.asm.ClassReader;
33 import org.eclipse.persistence.internal.libraries.asm.ClassWriter;
34 import org.eclipse.persistence.internal.libraries.asm.Label;
35
36 /**
37 * ModuleTarget attribute. This attribute is specific to the OpenJDK and may change in the future.
38 *
39 * @author Remi Forax
40 */
41 public final class ModuleTargetAttribute extends Attribute {
42 public String platform;
43
44 /**
45 * Constructs an attribute with a platform name.
46 *
47 * @param platform the platform name on which the module can run.
48 */
49 public ModuleTargetAttribute(final String platform) {
50 super("ModuleTarget");
51 this.platform = platform;
52 }
53
54 /**
55 * Constructs an empty attribute that can be used as prototype to be passed as argument of the method
56 * {@link ClassReader#accept(org.eclipse.persistence.internal.libraries.asm.ClassVisitor, Attribute[], int)}.
57 */
58 public ModuleTargetAttribute() {
59 this(null);
60 }
61
62 @Override
63 protected Attribute read(
64 ClassReader cr, int off, int len, char[] buf, int codeOff, Label[] labels) {
65 String platform = cr.readUTF8(off, buf);
66 return new ModuleTargetAttribute(platform);
67 }
68
69 @Override
70 protected ByteVector write(ClassWriter cw, byte[] code, int len, int maxStack, int maxLocals) {
71 ByteVector v = new ByteVector();
72 int index = (platform == null) ? 0 : cw.newUTF8(platform);
73 v.putShort(index);
74 return v;
75 }
76 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927
3028 package org.eclipse.persistence.internal.libraries.asm.commons;
3129
3634 import org.eclipse.persistence.internal.libraries.asm.signature.SignatureWriter;
3735
3836 /**
39 * A class responsible for remapping types and names. Subclasses can override
40 * the following methods:
41 *
37 * A class responsible for remapping types and names. Subclasses can override the following methods:
38 *
4239 * <ul>
43 * <li>{@link #map(String)} - map type</li>
44 * <li>{@link #mapFieldName(String, String, String)} - map field name</li>
45 * <li>{@link #mapMethodName(String, String, String)} - map method name</li>
40 * <li>{@link #map(String)} - map type
41 * <li>{@link #mapFieldName(String, String, String)} - map field name
42 * <li>{@link #mapMethodName(String, String, String)} - map method name
4643 * </ul>
47 *
44 *
4845 * @author Eugene Kuleshov
4946 */
5047 public abstract class Remapper {
5148
52 public String mapDesc(String desc) {
53 Type t = Type.getType(desc);
54 switch (t.getSort()) {
55 case Type.ARRAY:
56 String s = mapDesc(t.getElementType().getDescriptor());
57 for (int i = 0; i < t.getDimensions(); ++i) {
58 s = '[' + s;
59 }
60 return s;
61 case Type.OBJECT:
62 String newType = map(t.getInternalName());
63 if (newType != null) {
64 return 'L' + newType + ';';
65 }
66 }
67 return desc;
68 }
69
70 private Type mapType(Type t) {
71 switch (t.getSort()) {
72 case Type.ARRAY:
73 String s = mapDesc(t.getElementType().getDescriptor());
74 for (int i = 0; i < t.getDimensions(); ++i) {
75 s = '[' + s;
76 }
77 return Type.getType(s);
78 case Type.OBJECT:
79 s = map(t.getInternalName());
80 return s != null ? Type.getObjectType(s) : t;
81 case Type.METHOD:
82 return Type.getMethodType(mapMethodDesc(t.getDescriptor()));
83 }
84 return t;
85 }
86
87 public String mapType(String type) {
88 if (type == null) {
89 return null;
90 }
91 return mapType(Type.getObjectType(type)).getInternalName();
92 }
93
94 public String[] mapTypes(String[] types) {
95 String[] newTypes = null;
96 boolean needMapping = false;
97 for (int i = 0; i < types.length; i++) {
98 String type = types[i];
99 String newType = map(type);
100 if (newType != null && newTypes == null) {
101 newTypes = new String[types.length];
102 if (i > 0) {
103 System.arraycopy(types, 0, newTypes, 0, i);
104 }
105 needMapping = true;
106 }
107 if (needMapping) {
108 newTypes[i] = newType == null ? type : newType;
109 }
110 }
111 return needMapping ? newTypes : types;
112 }
113
114 public String mapMethodDesc(String desc) {
115 if ("()V".equals(desc)) {
116 return desc;
117 }
118
119 Type[] args = Type.getArgumentTypes(desc);
120 StringBuilder sb = new StringBuilder("(");
121 for (int i = 0; i < args.length; i++) {
122 sb.append(mapDesc(args[i].getDescriptor()));
123 }
124 Type returnType = Type.getReturnType(desc);
125 if (returnType == Type.VOID_TYPE) {
126 sb.append(")V");
127 return sb.toString();
128 }
129 sb.append(')').append(mapDesc(returnType.getDescriptor()));
130 return sb.toString();
131 }
132
133 public Object mapValue(Object value) {
134 if (value instanceof Type) {
135 return mapType((Type) value);
136 }
137 if (value instanceof Handle) {
138 Handle h = (Handle) value;
139 return new Handle(h.getTag(), mapType(h.getOwner()), mapMethodName(
140 h.getOwner(), h.getName(), h.getDesc()),
141 mapMethodDesc(h.getDesc()), h.isInterface());
142 }
143 return value;
144 }
145
146 /**
147 * @param signature
148 * signature for mapper
149 * @param typeSignature
150 * true if signature is a FieldTypeSignature, such as the
151 * signature parameter of the ClassVisitor.visitField or
152 * MethodVisitor.visitLocalVariable methods
153 * @return signature rewritten as a string
154 */
155 public String mapSignature(String signature, boolean typeSignature) {
156 if (signature == null) {
157 return null;
158 }
159 SignatureReader r = new SignatureReader(signature);
160 SignatureWriter w = new SignatureWriter();
161 SignatureVisitor a = createSignatureRemapper(w);
162 if (typeSignature) {
163 r.acceptType(a);
164 } else {
165 r.accept(a);
166 }
167 return w.toString();
168 }
169
170 /**
171 * @deprecated use {@link #createSignatureRemapper} instead.
172 */
173 @Deprecated
174 protected SignatureVisitor createRemappingSignatureAdapter(
175 SignatureVisitor v) {
176 return new SignatureRemapper(v, this);
177 }
178
179 protected SignatureVisitor createSignatureRemapper(
180 SignatureVisitor v) {
181 return createRemappingSignatureAdapter(v);
182 }
183
184 /**
185 * Map method name to the new name. Subclasses can override.
186 *
187 * @param owner
188 * owner of the method.
189 * @param name
190 * name of the method.
191 * @param desc
192 * descriptor of the method.
193 * @return new name of the method
194 */
195 public String mapMethodName(String owner, String name, String desc) {
196 return name;
197 }
198
199 /**
200 * Map invokedynamic method name to the new name. Subclasses can override.
201 *
202 * @param name
203 * name of the invokedynamic.
204 * @param desc
205 * descriptor of the invokedynamic.
206 * @return new invokdynamic name.
207 */
208 public String mapInvokeDynamicMethodName(String name, String desc) {
209 return name;
210 }
211
212 /**
213 * Map field name to the new name. Subclasses can override.
214 *
215 * @param owner
216 * owner of the field.
217 * @param name
218 * name of the field
219 * @param desc
220 * descriptor of the field
221 * @return new name of the field.
222 */
223 public String mapFieldName(String owner, String name, String desc) {
224 return name;
225 }
226
227 /**
228 * Map package name to the new name. Subclasses can override.
229 *
230 * @param name name of the package
231 * @return new name of the package
232 */
233 public String mapPackageName(String name) {
234 String fakeName = map(name + ".FakeClassName");
235 int index;
236 return fakeName == null || (index = fakeName.lastIndexOf('.')) == -1 ? name: fakeName.substring(0, index);
237 }
238
239 /**
240 * Map module name to the new name. Subclasses can override.
241 *
242 * @param name name of the module
243 * @return new name of the module
244 */
245 public String mapModuleName(String name) {
246 return name;
247 }
248
249 /**
250 * Map type name to the new name. Subclasses can override.
251 *
252 * @param typeName
253 * the type name
254 * @return new name, default implementation is the identity.
255 */
256 public String map(String typeName) {
257 return typeName;
258 }
49 public String mapDesc(String desc) {
50 Type t = Type.getType(desc);
51 switch (t.getSort()) {
52 case Type.ARRAY:
53 String s = mapDesc(t.getElementType().getDescriptor());
54 for (int i = 0; i < t.getDimensions(); ++i) {
55 s = '[' + s;
56 }
57 return s;
58 case Type.OBJECT:
59 String newType = map(t.getInternalName());
60 if (newType != null) {
61 return 'L' + newType + ';';
62 }
63 }
64 return desc;
65 }
66
67 private Type mapType(Type t) {
68 switch (t.getSort()) {
69 case Type.ARRAY:
70 String s = mapDesc(t.getElementType().getDescriptor());
71 for (int i = 0; i < t.getDimensions(); ++i) {
72 s = '[' + s;
73 }
74 return Type.getType(s);
75 case Type.OBJECT:
76 s = map(t.getInternalName());
77 return s != null ? Type.getObjectType(s) : t;
78 case Type.METHOD:
79 return Type.getMethodType(mapMethodDesc(t.getDescriptor()));
80 }
81 return t;
82 }
83
84 public String mapType(String type) {
85 if (type == null) {
86 return null;
87 }
88 return mapType(Type.getObjectType(type)).getInternalName();
89 }
90
91 public String[] mapTypes(String[] types) {
92 String[] newTypes = null;
93 boolean needMapping = false;
94 for (int i = 0; i < types.length; i++) {
95 String type = types[i];
96 String newType = map(type);
97 if (newType != null && newTypes == null) {
98 newTypes = new String[types.length];
99 if (i > 0) {
100 System.arraycopy(types, 0, newTypes, 0, i);
101 }
102 needMapping = true;
103 }
104 if (needMapping) {
105 newTypes[i] = newType == null ? type : newType;
106 }
107 }
108 return needMapping ? newTypes : types;
109 }
110
111 public String mapMethodDesc(String desc) {
112 if ("()V".equals(desc)) {
113 return desc;
114 }
115
116 Type[] args = Type.getArgumentTypes(desc);
117 StringBuilder sb = new StringBuilder("(");
118 for (int i = 0; i < args.length; i++) {
119 sb.append(mapDesc(args[i].getDescriptor()));
120 }
121 Type returnType = Type.getReturnType(desc);
122 if (returnType == Type.VOID_TYPE) {
123 sb.append(")V");
124 return sb.toString();
125 }
126 sb.append(')').append(mapDesc(returnType.getDescriptor()));
127 return sb.toString();
128 }
129
130 public Object mapValue(Object value) {
131 if (value instanceof Type) {
132 return mapType((Type) value);
133 }
134 if (value instanceof Handle) {
135 Handle h = (Handle) value;
136 return new Handle(
137 h.getTag(),
138 mapType(h.getOwner()),
139 mapMethodName(h.getOwner(), h.getName(), h.getDesc()),
140 mapMethodDesc(h.getDesc()),
141 h.isInterface());
142 }
143 return value;
144 }
145
146 /**
147 * @param signature signature for mapper
148 * @param typeSignature true if signature is a FieldTypeSignature, such as the signature parameter
149 * of the ClassVisitor.visitField or MethodVisitor.visitLocalVariable methods
150 * @return signature rewritten as a string
151 */
152 public String mapSignature(String signature, boolean typeSignature) {
153 if (signature == null) {
154 return null;
155 }
156 SignatureReader r = new SignatureReader(signature);
157 SignatureWriter w = new SignatureWriter();
158 SignatureVisitor a = createSignatureRemapper(w);
159 if (typeSignature) {
160 r.acceptType(a);
161 } else {
162 r.accept(a);
163 }
164 return w.toString();
165 }
166
167 /**
168 * Constructs a new remapper for signatures.
169 *
170 * @param v the SignatureVisitor the remapper must delegate to.
171 * @return the newly created remapper.
172 * @deprecated use {@link #createSignatureRemapper} instead.
173 */
174 @Deprecated
175 protected SignatureVisitor createRemappingSignatureAdapter(SignatureVisitor v) {
176 return new SignatureRemapper(v, this);
177 }
178
179 /**
180 * Constructs a new remapper for signatures.
181 *
182 * @param v the SignatureVisitor the remapper must delegate to.
183 * @return the newly created remapper.
184 */
185 protected SignatureVisitor createSignatureRemapper(SignatureVisitor v) {
186 return createRemappingSignatureAdapter(v);
187 }
188
189 /**
190 * Map method name to the new name. Subclasses can override.
191 *
192 * @param owner owner of the method.
193 * @param name name of the method.
194 * @param desc descriptor of the method.
195 * @return new name of the method
196 */
197 public String mapMethodName(String owner, String name, String desc) {
198 return name;
199 }
200
201 /**
202 * Map invokedynamic method name to the new name. Subclasses can override.
203 *
204 * @param name name of the invokedynamic.
205 * @param desc descriptor of the invokedynamic.
206 * @return new invokdynamic name.
207 */
208 public String mapInvokeDynamicMethodName(String name, String desc) {
209 return name;
210 }
211
212 /**
213 * Map field name to the new name. Subclasses can override.
214 *
215 * @param owner owner of the field.
216 * @param name name of the field
217 * @param desc descriptor of the field
218 * @return new name of the field.
219 */
220 public String mapFieldName(String owner, String name, String desc) {
221 return name;
222 }
223
224 /**
225 * Map package name to the new name. Subclasses can override.
226 *
227 * @param name name of the package
228 * @return new name of the package
229 */
230 public String mapPackageName(String name) {
231 String fakeName = map(name + ".FakeClassName");
232 int index;
233 return fakeName == null || (index = fakeName.lastIndexOf('.')) == -1
234 ? name
235 : fakeName.substring(0, index);
236 }
237
238 /**
239 * Map module name to the new name. Subclasses can override.
240 *
241 * @param name name of the module
242 * @return new name of the module
243 */
244 public String mapModuleName(String name) {
245 return name;
246 }
247
248 /**
249 * Map type name to the new name. Subclasses can override.
250 *
251 * @param typeName the type name
252 * @return new name, default implementation is the identity.
253 */
254 public String map(String typeName) {
255 return typeName;
256 }
259257 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927
3028 package org.eclipse.persistence.internal.libraries.asm.commons;
3129
3432
3533 /**
3634 * An {@link AnnotationVisitor} adapter for type remapping.
37 *
35 *
3836 * @deprecated use {@link AnnotationRemapper} instead.
3937 * @author Eugene Kuleshov
4038 */
4139 @Deprecated
4240 public class RemappingAnnotationAdapter extends AnnotationVisitor {
4341
44 protected final Remapper remapper;
42 protected final Remapper remapper;
4543
46 public RemappingAnnotationAdapter(final AnnotationVisitor av,
47 final Remapper remapper) {
48 this(Opcodes.ASM6, av, remapper);
49 }
44 public RemappingAnnotationAdapter(final AnnotationVisitor av, final Remapper remapper) {
45 this(Opcodes.ASM6, av, remapper);
46 }
5047
51 protected RemappingAnnotationAdapter(final int api,
52 final AnnotationVisitor av, final Remapper remapper) {
53 super(api, av);
54 this.remapper = remapper;
55 }
48 protected RemappingAnnotationAdapter(
49 final int api, final AnnotationVisitor av, final Remapper remapper) {
50 super(api, av);
51 this.remapper = remapper;
52 }
5653
57 @Override
58 public void visit(String name, Object value) {
59 av.visit(name, remapper.mapValue(value));
60 }
54 @Override
55 public void visit(String name, Object value) {
56 av.visit(name, remapper.mapValue(value));
57 }
6158
62 @Override
63 public void visitEnum(String name, String desc, String value) {
64 av.visitEnum(name, remapper.mapDesc(desc), value);
65 }
59 @Override
60 public void visitEnum(String name, String desc, String value) {
61 av.visitEnum(name, remapper.mapDesc(desc), value);
62 }
6663
67 @Override
68 public AnnotationVisitor visitAnnotation(String name, String desc) {
69 AnnotationVisitor v = av.visitAnnotation(name, remapper.mapDesc(desc));
70 return v == null ? null : (v == av ? this
71 : new RemappingAnnotationAdapter(v, remapper));
72 }
64 @Override
65 public AnnotationVisitor visitAnnotation(String name, String desc) {
66 AnnotationVisitor v = av.visitAnnotation(name, remapper.mapDesc(desc));
67 return v == null ? null : (v == av ? this : new RemappingAnnotationAdapter(v, remapper));
68 }
7369
74 @Override
75 public AnnotationVisitor visitArray(String name) {
76 AnnotationVisitor v = av.visitArray(name);
77 return v == null ? null : (v == av ? this
78 : new RemappingAnnotationAdapter(v, remapper));
79 }
70 @Override
71 public AnnotationVisitor visitArray(String name) {
72 AnnotationVisitor v = av.visitArray(name);
73 return v == null ? null : (v == av ? this : new RemappingAnnotationAdapter(v, remapper));
74 }
8075 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927
3028 package org.eclipse.persistence.internal.libraries.asm.commons;
3129
3937
4038 /**
4139 * A {@link ClassVisitor} for type remapping.
42 *
40 *
4341 * @deprecated use {@link ClassRemapper} instead.
4442 * @author Eugene Kuleshov
4543 */
4644 @Deprecated
4745 public class RemappingClassAdapter extends ClassVisitor {
4846
49 protected final Remapper remapper;
47 protected final Remapper remapper;
5048
51 protected String className;
49 protected String className;
5250
53 public RemappingClassAdapter(final ClassVisitor cv, final Remapper remapper) {
54 this(Opcodes.ASM6, cv, remapper);
55 }
51 public RemappingClassAdapter(final ClassVisitor cv, final Remapper remapper) {
52 this(Opcodes.ASM6, cv, remapper);
53 }
5654
57 protected RemappingClassAdapter(final int api, final ClassVisitor cv,
58 final Remapper remapper) {
59 super(api, cv);
60 this.remapper = remapper;
61 }
55 protected RemappingClassAdapter(final int api, final ClassVisitor cv, final Remapper remapper) {
56 super(api, cv);
57 this.remapper = remapper;
58 }
6259
63 @Override
64 public void visit(int version, int access, String name, String signature,
65 String superName, String[] interfaces) {
66 this.className = name;
67 super.visit(version, access, remapper.mapType(name), remapper
68 .mapSignature(signature, false), remapper.mapType(superName),
69 interfaces == null ? null : remapper.mapTypes(interfaces));
70 }
60 @Override
61 public void visit(
62 int version,
63 int access,
64 String name,
65 String signature,
66 String superName,
67 String[] interfaces) {
68 this.className = name;
69 super.visit(
70 version,
71 access,
72 remapper.mapType(name),
73 remapper.mapSignature(signature, false),
74 remapper.mapType(superName),
75 interfaces == null ? null : remapper.mapTypes(interfaces));
76 }
7177
72 @Override
73 public ModuleVisitor visitModule() {
74 throw new RuntimeException("RemappingClassAdapter is deprecated, use ClassRemapper instead");
75 }
76
77 @Override
78 public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
79 AnnotationVisitor av = super.visitAnnotation(remapper.mapDesc(desc),
80 visible);
81 return av == null ? null : createRemappingAnnotationAdapter(av);
82 }
78 @Override
79 public ModuleVisitor visitModule(String name, int flags, String version) {
80 throw new RuntimeException("RemappingClassAdapter is deprecated, use ClassRemapper instead");
81 }
8382
84 @Override
85 public AnnotationVisitor visitTypeAnnotation(int typeRef,
86 TypePath typePath, String desc, boolean visible) {
87 AnnotationVisitor av = super.visitTypeAnnotation(typeRef, typePath,
88 remapper.mapDesc(desc), visible);
89 return av == null ? null : createRemappingAnnotationAdapter(av);
90 }
83 @Override
84 public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
85 AnnotationVisitor av = super.visitAnnotation(remapper.mapDesc(desc), visible);
86 return av == null ? null : createRemappingAnnotationAdapter(av);
87 }
9188
92 @Override
93 public FieldVisitor visitField(int access, String name, String desc,
94 String signature, Object value) {
95 FieldVisitor fv = super.visitField(access,
96 remapper.mapFieldName(className, name, desc),
97 remapper.mapDesc(desc), remapper.mapSignature(signature, true),
98 remapper.mapValue(value));
99 return fv == null ? null : createRemappingFieldAdapter(fv);
100 }
89 @Override
90 public AnnotationVisitor visitTypeAnnotation(
91 int typeRef, TypePath typePath, String desc, boolean visible) {
92 AnnotationVisitor av =
93 super.visitTypeAnnotation(typeRef, typePath, remapper.mapDesc(desc), visible);
94 return av == null ? null : createRemappingAnnotationAdapter(av);
95 }
10196
102 @Override
103 public MethodVisitor visitMethod(int access, String name, String desc,
104 String signature, String[] exceptions) {
105 String newDesc = remapper.mapMethodDesc(desc);
106 MethodVisitor mv = super.visitMethod(access, remapper.mapMethodName(
107 className, name, desc), newDesc, remapper.mapSignature(
108 signature, false),
109 exceptions == null ? null : remapper.mapTypes(exceptions));
110 return mv == null ? null : createRemappingMethodAdapter(access,
111 newDesc, mv);
112 }
97 @Override
98 public FieldVisitor visitField(
99 int access, String name, String desc, String signature, Object value) {
100 FieldVisitor fv =
101 super.visitField(
102 access,
103 remapper.mapFieldName(className, name, desc),
104 remapper.mapDesc(desc),
105 remapper.mapSignature(signature, true),
106 remapper.mapValue(value));
107 return fv == null ? null : createRemappingFieldAdapter(fv);
108 }
113109
114 @Override
115 public void visitInnerClass(String name, String outerName,
116 String innerName, int access) {
117 // TODO should innerName be changed?
118 super.visitInnerClass(remapper.mapType(name), outerName == null ? null
119 : remapper.mapType(outerName), innerName, access);
120 }
110 @Override
111 public MethodVisitor visitMethod(
112 int access, String name, String desc, String signature, String[] exceptions) {
113 String newDesc = remapper.mapMethodDesc(desc);
114 MethodVisitor mv =
115 super.visitMethod(
116 access,
117 remapper.mapMethodName(className, name, desc),
118 newDesc,
119 remapper.mapSignature(signature, false),
120 exceptions == null ? null : remapper.mapTypes(exceptions));
121 return mv == null ? null : createRemappingMethodAdapter(access, newDesc, mv);
122 }
121123
122 @Override
123 public void visitOuterClass(String owner, String name, String desc) {
124 super.visitOuterClass(remapper.mapType(owner), name == null ? null
125 : remapper.mapMethodName(owner, name, desc),
126 desc == null ? null : remapper.mapMethodDesc(desc));
127 }
124 @Override
125 public void visitInnerClass(String name, String outerName, String innerName, int access) {
126 // TODO should innerName be changed?
127 super.visitInnerClass(
128 remapper.mapType(name),
129 outerName == null ? null : remapper.mapType(outerName),
130 innerName,
131 access);
132 }
128133
129 protected FieldVisitor createRemappingFieldAdapter(FieldVisitor fv) {
130 return new RemappingFieldAdapter(fv, remapper);
131 }
134 @Override
135 public void visitOuterClass(String owner, String name, String desc) {
136 super.visitOuterClass(
137 remapper.mapType(owner),
138 name == null ? null : remapper.mapMethodName(owner, name, desc),
139 desc == null ? null : remapper.mapMethodDesc(desc));
140 }
132141
133 protected MethodVisitor createRemappingMethodAdapter(int access,
134 String newDesc, MethodVisitor mv) {
135 return new RemappingMethodAdapter(access, newDesc, mv, remapper);
136 }
142 protected FieldVisitor createRemappingFieldAdapter(FieldVisitor fv) {
143 return new RemappingFieldAdapter(fv, remapper);
144 }
137145
138 protected AnnotationVisitor createRemappingAnnotationAdapter(
139 AnnotationVisitor av) {
140 return new RemappingAnnotationAdapter(av, remapper);
141 }
146 protected MethodVisitor createRemappingMethodAdapter(
147 int access, String newDesc, MethodVisitor mv) {
148 return new RemappingMethodAdapter(access, newDesc, mv, remapper);
149 }
150
151 protected AnnotationVisitor createRemappingAnnotationAdapter(AnnotationVisitor av) {
152 return new RemappingAnnotationAdapter(av, remapper);
153 }
142154 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927
3028 package org.eclipse.persistence.internal.libraries.asm.commons;
3129
3634
3735 /**
3836 * A {@link FieldVisitor} adapter for type remapping.
39 *
37 *
4038 * @deprecated use {@link FieldRemapper} instead.
4139 * @author Eugene Kuleshov
4240 */
4341 @Deprecated
4442 public class RemappingFieldAdapter extends FieldVisitor {
4543
46 private final Remapper remapper;
44 private final Remapper remapper;
4745
48 public RemappingFieldAdapter(final FieldVisitor fv, final Remapper remapper) {
49 this(Opcodes.ASM6, fv, remapper);
50 }
46 public RemappingFieldAdapter(final FieldVisitor fv, final Remapper remapper) {
47 this(Opcodes.ASM6, fv, remapper);
48 }
5149
52 protected RemappingFieldAdapter(final int api, final FieldVisitor fv,
53 final Remapper remapper) {
54 super(api, fv);
55 this.remapper = remapper;
56 }
50 protected RemappingFieldAdapter(final int api, final FieldVisitor fv, final Remapper remapper) {
51 super(api, fv);
52 this.remapper = remapper;
53 }
5754
58 @Override
59 public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
60 AnnotationVisitor av = fv.visitAnnotation(remapper.mapDesc(desc),
61 visible);
62 return av == null ? null : new RemappingAnnotationAdapter(av, remapper);
63 }
55 @Override
56 public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
57 AnnotationVisitor av = fv.visitAnnotation(remapper.mapDesc(desc), visible);
58 return av == null ? null : new RemappingAnnotationAdapter(av, remapper);
59 }
6460
65 @Override
66 public AnnotationVisitor visitTypeAnnotation(int typeRef,
67 TypePath typePath, String desc, boolean visible) {
68 AnnotationVisitor av = super.visitTypeAnnotation(typeRef, typePath,
69 remapper.mapDesc(desc), visible);
70 return av == null ? null : new RemappingAnnotationAdapter(av, remapper);
71 }
61 @Override
62 public AnnotationVisitor visitTypeAnnotation(
63 int typeRef, TypePath typePath, String desc, boolean visible) {
64 AnnotationVisitor av =
65 super.visitTypeAnnotation(typeRef, typePath, remapper.mapDesc(desc), visible);
66 return av == null ? null : new RemappingAnnotationAdapter(av, remapper);
67 }
7268 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927
3028 package org.eclipse.persistence.internal.libraries.asm.commons;
3129
3836
3937 /**
4038 * A {@link LocalVariablesSorter} for type mapping.
41 *
39 *
4240 * @deprecated use {@link MethodRemapper} instead.
4341 * @author Eugene Kuleshov
4442 */
4543 @Deprecated
4644 public class RemappingMethodAdapter extends LocalVariablesSorter {
4745
48 protected final Remapper remapper;
49
50 public RemappingMethodAdapter(final int access, final String desc,
51 final MethodVisitor mv, final Remapper remapper) {
52 this(Opcodes.ASM6, access, desc, mv, remapper);
53 }
54
55 protected RemappingMethodAdapter(final int api, final int access,
56 final String desc, final MethodVisitor mv, final Remapper remapper) {
57 super(api, access, desc, mv);
58 this.remapper = remapper;
59 }
60
61 @Override
62 public AnnotationVisitor visitAnnotationDefault() {
63 AnnotationVisitor av = super.visitAnnotationDefault();
64 return av == null ? av : new RemappingAnnotationAdapter(av, remapper);
65 }
66
67 @Override
68 public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
69 AnnotationVisitor av = super.visitAnnotation(remapper.mapDesc(desc),
70 visible);
71 return av == null ? av : new RemappingAnnotationAdapter(av, remapper);
72 }
73
74 @Override
75 public AnnotationVisitor visitTypeAnnotation(int typeRef,
76 TypePath typePath, String desc, boolean visible) {
77 AnnotationVisitor av = super.visitTypeAnnotation(typeRef, typePath,
78 remapper.mapDesc(desc), visible);
79 return av == null ? av : new RemappingAnnotationAdapter(av, remapper);
80 }
81
82 @Override
83 public AnnotationVisitor visitParameterAnnotation(int parameter,
84 String desc, boolean visible) {
85 AnnotationVisitor av = super.visitParameterAnnotation(parameter,
86 remapper.mapDesc(desc), visible);
87 return av == null ? av : new RemappingAnnotationAdapter(av, remapper);
88 }
89
90 @Override
91 public void visitFrame(int type, int nLocal, Object[] local, int nStack,
92 Object[] stack) {
93 super.visitFrame(type, nLocal, remapEntries(nLocal, local), nStack,
94 remapEntries(nStack, stack));
95 }
96
97 private Object[] remapEntries(int n, Object[] entries) {
98 for (int i = 0; i < n; i++) {
99 if (entries[i] instanceof String) {
100 Object[] newEntries = new Object[n];
101 if (i > 0) {
102 System.arraycopy(entries, 0, newEntries, 0, i);
103 }
104 do {
105 Object t = entries[i];
106 newEntries[i++] = t instanceof String ? remapper
107 .mapType((String) t) : t;
108 } while (i < n);
109 return newEntries;
110 }
46 protected final Remapper remapper;
47
48 public RemappingMethodAdapter(
49 final int access, final String desc, final MethodVisitor mv, final Remapper remapper) {
50 this(Opcodes.ASM6, access, desc, mv, remapper);
51 }
52
53 protected RemappingMethodAdapter(
54 final int api,
55 final int access,
56 final String desc,
57 final MethodVisitor mv,
58 final Remapper remapper) {
59 super(api, access, desc, mv);
60 this.remapper = remapper;
61 }
62
63 @Override
64 public AnnotationVisitor visitAnnotationDefault() {
65 AnnotationVisitor av = super.visitAnnotationDefault();
66 return av == null ? av : new RemappingAnnotationAdapter(av, remapper);
67 }
68
69 @Override
70 public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
71 AnnotationVisitor av = super.visitAnnotation(remapper.mapDesc(desc), visible);
72 return av == null ? av : new RemappingAnnotationAdapter(av, remapper);
73 }
74
75 @Override
76 public AnnotationVisitor visitTypeAnnotation(
77 int typeRef, TypePath typePath, String desc, boolean visible) {
78 AnnotationVisitor av =
79 super.visitTypeAnnotation(typeRef, typePath, remapper.mapDesc(desc), visible);
80 return av == null ? av : new RemappingAnnotationAdapter(av, remapper);
81 }
82
83 @Override
84 public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, boolean visible) {
85 AnnotationVisitor av =
86 super.visitParameterAnnotation(parameter, remapper.mapDesc(desc), visible);
87 return av == null ? av : new RemappingAnnotationAdapter(av, remapper);
88 }
89
90 @Override
91 public void visitFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack) {
92 super.visitFrame(
93 type, nLocal, remapEntries(nLocal, local), nStack, remapEntries(nStack, stack));
94 }
95
96 private Object[] remapEntries(int n, Object[] entries) {
97 if (entries != null) {
98 for (int i = 0; i < n; i++) {
99 if (entries[i] instanceof String) {
100 Object[] newEntries = new Object[n];
101 if (i > 0) {
102 System.arraycopy(entries, 0, newEntries, 0, i);
103 }
104 do {
105 Object t = entries[i];
106 newEntries[i++] = t instanceof String ? remapper.mapType((String) t) : t;
107 } while (i < n);
108 return newEntries;
111109 }
112 return entries;
113 }
114
115 @Override
116 public void visitFieldInsn(int opcode, String owner, String name,
117 String desc) {
118 super.visitFieldInsn(opcode, remapper.mapType(owner),
119 remapper.mapFieldName(owner, name, desc),
120 remapper.mapDesc(desc));
121 }
122
123 @Deprecated
124 @Override
125 public void visitMethodInsn(final int opcode, final String owner,
126 final String name, final String desc) {
127 if (api >= Opcodes.ASM5) {
128 super.visitMethodInsn(opcode, owner, name, desc);
129 return;
130 }
131 doVisitMethodInsn(opcode, owner, name, desc,
132 opcode == Opcodes.INVOKEINTERFACE);
133 }
134
135 @Override
136 public void visitMethodInsn(final int opcode, final String owner,
137 final String name, final String desc, final boolean itf) {
138 if (api < Opcodes.ASM5) {
139 super.visitMethodInsn(opcode, owner, name, desc, itf);
140 return;
141 }
142 doVisitMethodInsn(opcode, owner, name, desc, itf);
143 }
144
145 private void doVisitMethodInsn(int opcode, String owner, String name,
146 String desc, boolean itf) {
147 // Calling super.visitMethodInsn requires to call the correct version
148 // depending on this.api (otherwise infinite loops can occur). To
149 // simplify and to make it easier to automatically remove the backward
150 // compatibility code, we inline the code of the overridden method here.
151 // IMPORTANT: THIS ASSUMES THAT visitMethodInsn IS NOT OVERRIDDEN IN
152 // LocalVariableSorter.
153 if (mv != null) {
154 mv.visitMethodInsn(opcode, remapper.mapType(owner),
155 remapper.mapMethodName(owner, name, desc),
156 remapper.mapMethodDesc(desc), itf);
157 }
158 }
159
160 @Override
161 public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
162 Object... bsmArgs) {
163 for (int i = 0; i < bsmArgs.length; i++) {
164 bsmArgs[i] = remapper.mapValue(bsmArgs[i]);
165 }
166 super.visitInvokeDynamicInsn(
167 remapper.mapInvokeDynamicMethodName(name, desc),
168 remapper.mapMethodDesc(desc), (Handle) remapper.mapValue(bsm),
169 bsmArgs);
170 }
171
172 @Override
173 public void visitTypeInsn(int opcode, String type) {
174 super.visitTypeInsn(opcode, remapper.mapType(type));
175 }
176
177 @Override
178 public void visitLdcInsn(Object cst) {
179 super.visitLdcInsn(remapper.mapValue(cst));
180 }
181
182 @Override
183 public void visitMultiANewArrayInsn(String desc, int dims) {
184 super.visitMultiANewArrayInsn(remapper.mapDesc(desc), dims);
185 }
186
187 @Override
188 public AnnotationVisitor visitInsnAnnotation(int typeRef,
189 TypePath typePath, String desc, boolean visible) {
190 AnnotationVisitor av = super.visitInsnAnnotation(typeRef, typePath,
191 remapper.mapDesc(desc), visible);
192 return av == null ? av : new RemappingAnnotationAdapter(av, remapper);
193 }
194
195 @Override
196 public void visitTryCatchBlock(Label start, Label end, Label handler,
197 String type) {
198 super.visitTryCatchBlock(start, end, handler, type == null ? null
199 : remapper.mapType(type));
200 }
201
202 @Override
203 public AnnotationVisitor visitTryCatchAnnotation(int typeRef,
204 TypePath typePath, String desc, boolean visible) {
205 AnnotationVisitor av = super.visitTryCatchAnnotation(typeRef, typePath,
206 remapper.mapDesc(desc), visible);
207 return av == null ? av : new RemappingAnnotationAdapter(av, remapper);
208 }
209
210 @Override
211 public void visitLocalVariable(String name, String desc, String signature,
212 Label start, Label end, int index) {
213 super.visitLocalVariable(name, remapper.mapDesc(desc),
214 remapper.mapSignature(signature, true), start, end, index);
215 }
216
217 @Override
218 public AnnotationVisitor visitLocalVariableAnnotation(int typeRef,
219 TypePath typePath, Label[] start, Label[] end, int[] index,
220 String desc, boolean visible) {
221 AnnotationVisitor av = super.visitLocalVariableAnnotation(typeRef,
222 typePath, start, end, index, remapper.mapDesc(desc), visible);
223 return av == null ? av : new RemappingAnnotationAdapter(av, remapper);
224 }
110 }
111 }
112 return entries;
113 }
114
115 @Override
116 public void visitFieldInsn(int opcode, String owner, String name, String desc) {
117 super.visitFieldInsn(
118 opcode,
119 remapper.mapType(owner),
120 remapper.mapFieldName(owner, name, desc),
121 remapper.mapDesc(desc));
122 }
123
124 @Deprecated
125 @Override
126 public void visitMethodInsn(
127 final int opcode, final String owner, final String name, final String desc) {
128 if (api >= Opcodes.ASM5) {
129 super.visitMethodInsn(opcode, owner, name, desc);
130 return;
131 }
132 doVisitMethodInsn(opcode, owner, name, desc, opcode == Opcodes.INVOKEINTERFACE);
133 }
134
135 @Override
136 public void visitMethodInsn(
137 final int opcode,
138 final String owner,
139 final String name,
140 final String desc,
141 final boolean itf) {
142 if (api < Opcodes.ASM5) {
143 super.visitMethodInsn(opcode, owner, name, desc, itf);
144 return;
145 }
146 doVisitMethodInsn(opcode, owner, name, desc, itf);
147 }
148
149 private void doVisitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
150 // Calling super.visitMethodInsn requires to call the correct version
151 // depending on this.api (otherwise infinite loops can occur). To
152 // simplify and to make it easier to automatically remove the backward
153 // compatibility code, we inline the code of the overridden method here.
154 // IMPORTANT: THIS ASSUMES THAT visitMethodInsn IS NOT OVERRIDDEN IN
155 // LocalVariableSorter.
156 if (mv != null) {
157 mv.visitMethodInsn(
158 opcode,
159 remapper.mapType(owner),
160 remapper.mapMethodName(owner, name, desc),
161 remapper.mapMethodDesc(desc),
162 itf);
163 }
164 }
165
166 @Override
167 public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) {
168 for (int i = 0; i < bsmArgs.length; i++) {
169 bsmArgs[i] = remapper.mapValue(bsmArgs[i]);
170 }
171 super.visitInvokeDynamicInsn(
172 remapper.mapInvokeDynamicMethodName(name, desc),
173 remapper.mapMethodDesc(desc),
174 (Handle) remapper.mapValue(bsm),
175 bsmArgs);
176 }
177
178 @Override
179 public void visitTypeInsn(int opcode, String type) {
180 super.visitTypeInsn(opcode, remapper.mapType(type));
181 }
182
183 @Override
184 public void visitLdcInsn(Object cst) {
185 super.visitLdcInsn(remapper.mapValue(cst));
186 }
187
188 @Override
189 public void visitMultiANewArrayInsn(String desc, int dims) {
190 super.visitMultiANewArrayInsn(remapper.mapDesc(desc), dims);
191 }
192
193 @Override
194 public AnnotationVisitor visitInsnAnnotation(
195 int typeRef, TypePath typePath, String desc, boolean visible) {
196 AnnotationVisitor av =
197 super.visitInsnAnnotation(typeRef, typePath, remapper.mapDesc(desc), visible);
198 return av == null ? av : new RemappingAnnotationAdapter(av, remapper);
199 }
200
201 @Override
202 public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
203 super.visitTryCatchBlock(start, end, handler, type == null ? null : remapper.mapType(type));
204 }
205
206 @Override
207 public AnnotationVisitor visitTryCatchAnnotation(
208 int typeRef, TypePath typePath, String desc, boolean visible) {
209 AnnotationVisitor av =
210 super.visitTryCatchAnnotation(typeRef, typePath, remapper.mapDesc(desc), visible);
211 return av == null ? av : new RemappingAnnotationAdapter(av, remapper);
212 }
213
214 @Override
215 public void visitLocalVariable(
216 String name, String desc, String signature, Label start, Label end, int index) {
217 super.visitLocalVariable(
218 name, remapper.mapDesc(desc), remapper.mapSignature(signature, true), start, end, index);
219 }
220
221 @Override
222 public AnnotationVisitor visitLocalVariableAnnotation(
223 int typeRef,
224 TypePath typePath,
225 Label[] start,
226 Label[] end,
227 int[] index,
228 String desc,
229 boolean visible) {
230 AnnotationVisitor av =
231 super.visitLocalVariableAnnotation(
232 typeRef, typePath, start, end, index, remapper.mapDesc(desc), visible);
233 return av == null ? av : new RemappingAnnotationAdapter(av, remapper);
234 }
225235 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927
3028 package org.eclipse.persistence.internal.libraries.asm.commons;
3129
3432
3533 /**
3634 * A {@link SignatureVisitor} adapter for type mapping.
37 *
35 *
3836 * @deprecated use {@link SignatureRemapper} instead.
3937 * @author Eugene Kuleshov
4038 */
4139 @Deprecated
4240 public class RemappingSignatureAdapter extends SignatureVisitor {
4341
44 private final SignatureVisitor v;
42 private final SignatureVisitor v;
4543
46 private final Remapper remapper;
44 private final Remapper remapper;
4745
48 private String className;
46 private String className;
4947
50 public RemappingSignatureAdapter(final SignatureVisitor v,
51 final Remapper remapper) {
52 this(Opcodes.ASM6, v, remapper);
53 }
48 public RemappingSignatureAdapter(final SignatureVisitor v, final Remapper remapper) {
49 this(Opcodes.ASM6, v, remapper);
50 }
5451
55 protected RemappingSignatureAdapter(final int api,
56 final SignatureVisitor v, final Remapper remapper) {
57 super(api);
58 this.v = v;
59 this.remapper = remapper;
60 }
52 protected RemappingSignatureAdapter(
53 final int api, final SignatureVisitor v, final Remapper remapper) {
54 super(api);
55 this.v = v;
56 this.remapper = remapper;
57 }
6158
62 @Override
63 public void visitClassType(String name) {
64 className = name;
65 v.visitClassType(remapper.mapType(name));
66 }
59 @Override
60 public void visitClassType(String name) {
61 className = name;
62 v.visitClassType(remapper.mapType(name));
63 }
6764
68 @Override
69 public void visitInnerClassType(String name) {
70 String remappedOuter = remapper.mapType(className) + '$';
71 className = className + '$' + name;
72 String remappedName = remapper.mapType(className);
73 int index = remappedName.startsWith(remappedOuter) ? remappedOuter
74 .length() : remappedName.lastIndexOf('$') + 1;
75 v.visitInnerClassType(remappedName.substring(index));
76 }
65 @Override
66 public void visitInnerClassType(String name) {
67 String remappedOuter = remapper.mapType(className) + '$';
68 className = className + '$' + name;
69 String remappedName = remapper.mapType(className);
70 int index =
71 remappedName.startsWith(remappedOuter)
72 ? remappedOuter.length()
73 : remappedName.lastIndexOf('$') + 1;
74 v.visitInnerClassType(remappedName.substring(index));
75 }
7776
78 @Override
79 public void visitFormalTypeParameter(String name) {
80 v.visitFormalTypeParameter(name);
81 }
77 @Override
78 public void visitFormalTypeParameter(String name) {
79 v.visitFormalTypeParameter(name);
80 }
8281
83 @Override
84 public void visitTypeVariable(String name) {
85 v.visitTypeVariable(name);
86 }
82 @Override
83 public void visitTypeVariable(String name) {
84 v.visitTypeVariable(name);
85 }
8786
88 @Override
89 public SignatureVisitor visitArrayType() {
90 v.visitArrayType();
91 return this;
92 }
87 @Override
88 public SignatureVisitor visitArrayType() {
89 v.visitArrayType();
90 return this;
91 }
9392
94 @Override
95 public void visitBaseType(char descriptor) {
96 v.visitBaseType(descriptor);
97 }
93 @Override
94 public void visitBaseType(char descriptor) {
95 v.visitBaseType(descriptor);
96 }
9897
99 @Override
100 public SignatureVisitor visitClassBound() {
101 v.visitClassBound();
102 return this;
103 }
98 @Override
99 public SignatureVisitor visitClassBound() {
100 v.visitClassBound();
101 return this;
102 }
104103
105 @Override
106 public SignatureVisitor visitExceptionType() {
107 v.visitExceptionType();
108 return this;
109 }
104 @Override
105 public SignatureVisitor visitExceptionType() {
106 v.visitExceptionType();
107 return this;
108 }
110109
111 @Override
112 public SignatureVisitor visitInterface() {
113 v.visitInterface();
114 return this;
115 }
110 @Override
111 public SignatureVisitor visitInterface() {
112 v.visitInterface();
113 return this;
114 }
116115
117 @Override
118 public SignatureVisitor visitInterfaceBound() {
119 v.visitInterfaceBound();
120 return this;
121 }
116 @Override
117 public SignatureVisitor visitInterfaceBound() {
118 v.visitInterfaceBound();
119 return this;
120 }
122121
123 @Override
124 public SignatureVisitor visitParameterType() {
125 v.visitParameterType();
126 return this;
127 }
122 @Override
123 public SignatureVisitor visitParameterType() {
124 v.visitParameterType();
125 return this;
126 }
128127
129 @Override
130 public SignatureVisitor visitReturnType() {
131 v.visitReturnType();
132 return this;
133 }
128 @Override
129 public SignatureVisitor visitReturnType() {
130 v.visitReturnType();
131 return this;
132 }
134133
135 @Override
136 public SignatureVisitor visitSuperclass() {
137 v.visitSuperclass();
138 return this;
139 }
134 @Override
135 public SignatureVisitor visitSuperclass() {
136 v.visitSuperclass();
137 return this;
138 }
140139
141 @Override
142 public void visitTypeArgument() {
143 v.visitTypeArgument();
144 }
140 @Override
141 public void visitTypeArgument() {
142 v.visitTypeArgument();
143 }
145144
146 @Override
147 public SignatureVisitor visitTypeArgument(char wildcard) {
148 v.visitTypeArgument(wildcard);
149 return this;
150 }
145 @Override
146 public SignatureVisitor visitTypeArgument(char wildcard) {
147 v.visitTypeArgument(wildcard);
148 return this;
149 }
151150
152 @Override
153 public void visitEnd() {
154 v.visitEnd();
155 }
151 @Override
152 public void visitEnd() {
153 v.visitEnd();
154 }
156155 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.commons;
3028
3129 import java.io.ByteArrayOutputStream;
4341 import org.eclipse.persistence.internal.libraries.asm.Opcodes;
4442
4543 /**
46 * A {@link ClassVisitor} that adds a serial version unique identifier to a
47 * class if missing. Here is typical usage of this class:
48 *
44 * A {@link ClassVisitor} that adds a serial version unique identifier to a class if missing. Here
45 * is typical usage of this class:
46 *
4947 * <pre>
5048 * ClassWriter cw = new ClassWriter(...);
5149 * ClassVisitor sv = new SerialVersionUIDAdder(cw);
5250 * ClassVisitor ca = new MyClassAdapter(sv);
5351 * new ClassReader(orginalClass).accept(ca, false);
5452 * </pre>
55 *
53 *
5654 * The SVUID algorithm can be found <a href=
5755 * "http://java.sun.com/j2se/1.4.2/docs/guide/serialization/spec/class.html"
5856 * >http://java.sun.com/j2se/1.4.2/docs/guide/serialization/spec/class.html</a>:
59 *
57 *
6058 * <pre>
6159 * The serialVersionUID is computed using the signature of a stream of bytes
6260 * that reflect the class definition. The National Institute of Standards and
6563 * 64-bit hash. A java.lang.DataOutputStream is used to convert primitive data
6664 * types to a sequence of bytes. The values input to the stream are defined by
6765 * the Java Virtual Machine (VM) specification for classes.
68 *
66 *
6967 * The sequence of items in the stream is as follows:
70 *
68 *
7169 * 1. The class name written using UTF encoding.
7270 * 2. The class modifiers written as a 32-bit integer.
7371 * 3. The name of each interface sorted by name written using UTF encoding.
9189 * 3. The descriptor of the method in UTF encoding.
9290 * 8. The SHA-1 algorithm is executed on the stream of bytes produced by
9391 * DataOutputStream and produces five 32-bit values sha[0..4].
94 *
92 *
9593 * 9. The hash value is assembled from the first and second 32-bit values of
9694 * the SHA-1 message digest. If the result of the message digest, the five
9795 * 32-bit words H0 H1 H2 H3 H4, is in an array of five int values named
9896 * sha, the hash value would be computed as follows:
99 *
97 *
10098 * long hash = ((sha[0] &gt;&gt;&gt; 24) &amp; 0xFF) |
10199 * ((sha[0] &gt;&gt;&gt; 16) &amp; 0xFF) &lt;&lt; 8 |
102100 * ((sha[0] &gt;&gt;&gt; 8) &amp; 0xFF) &lt;&lt; 16 |
106104 * ((sha[1] &gt;&gt;&gt; 8) &amp; 0xFF) &lt;&lt; 48 |
107105 * ((sha[1] &gt;&gt;&gt; 0) &amp; 0xFF) &lt;&lt; 56;
108106 * </pre>
109 *
107 *
110108 * @author Rajendra Inamdar, Vishal Vishnoi
111109 */
112110 public class SerialVersionUIDAdder extends ClassVisitor {
113111
114 /**
115 * Flag that indicates if we need to compute SVUID.
116 */
117 private boolean computeSVUID;
118
119 /**
120 * Set to true if the class already has SVUID.
121 */
122 private boolean hasSVUID;
123
124 /**
125 * Classes access flags.
126 */
127 private int access;
128
129 /**
130 * Internal name of the class
131 */
132 private String name;
133
134 /**
135 * Interfaces implemented by the class.
136 */
137 private String[] interfaces;
138
139 /**
140 * Collection of fields. (except private static and private transient
141 * fields)
142 */
143 private Collection<Item> svuidFields;
144
145 /**
146 * Set to true if the class has static initializer.
147 */
148 private boolean hasStaticInitializer;
149
150 /**
151 * Collection of non-private constructors.
152 */
153 private Collection<Item> svuidConstructors;
154
155 /**
156 * Collection of non-private methods.
157 */
158 private Collection<Item> svuidMethods;
159
160 /**
161 * Creates a new {@link SerialVersionUIDAdder}. <i>Subclasses must not use
162 * this constructor</i>. Instead, they must use the
163 * {@link #SerialVersionUIDAdder(int, ClassVisitor)} version.
164 *
165 * @param cv
166 * a {@link ClassVisitor} to which this visitor will delegate
167 * calls.
168 * @throws IllegalStateException
169 * If a subclass calls this constructor.
170 */
171 public SerialVersionUIDAdder(final ClassVisitor cv) {
172 this(Opcodes.ASM6, cv);
173 if (getClass() != SerialVersionUIDAdder.class) {
174 throw new IllegalStateException();
112 /** Flag that indicates if we need to compute SVUID. */
113 private boolean computeSVUID;
114
115 /** Set to true if the class already has SVUID. */
116 private boolean hasSVUID;
117
118 /** Classes access flags. */
119 private int access;
120
121 /** Internal name of the class */
122 private String name;
123
124 /** Interfaces implemented by the class. */
125 private String[] interfaces;
126
127 /** Collection of fields. (except private static and private transient fields) */
128 private Collection<Item> svuidFields;
129
130 /** Set to true if the class has static initializer. */
131 private boolean hasStaticInitializer;
132
133 /** Collection of non-private constructors. */
134 private Collection<Item> svuidConstructors;
135
136 /** Collection of non-private methods. */
137 private Collection<Item> svuidMethods;
138
139 /**
140 * Constructs a new {@link SerialVersionUIDAdder}. <i>Subclasses must not use this constructor</i>.
141 * Instead, they must use the {@link #SerialVersionUIDAdder(int, ClassVisitor)} version.
142 *
143 * @param cv a {@link ClassVisitor} to which this visitor will delegate calls.
144 * @throws IllegalStateException If a subclass calls this constructor.
145 */
146 public SerialVersionUIDAdder(final ClassVisitor cv) {
147 this(Opcodes.ASM6, cv);
148 if (getClass() != SerialVersionUIDAdder.class) {
149 throw new IllegalStateException();
150 }
151 }
152
153 /**
154 * Constructs a new {@link SerialVersionUIDAdder}.
155 *
156 * @param api the ASM API version implemented by this visitor. Must be one of {@link
157 * Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
158 * @param cv a {@link ClassVisitor} to which this visitor will delegate calls.
159 */
160 protected SerialVersionUIDAdder(final int api, final ClassVisitor cv) {
161 super(api, cv);
162 svuidFields = new ArrayList<Item>();
163 svuidConstructors = new ArrayList<Item>();
164 svuidMethods = new ArrayList<Item>();
165 }
166
167 // ------------------------------------------------------------------------
168 // Overridden methods
169 // ------------------------------------------------------------------------
170
171 /*
172 * Visit class header and get class name, access , and interfaces
173 * information (step 1,2, and 3) for SVUID computation.
174 */
175 @Override
176 public void visit(
177 final int version,
178 final int access,
179 final String name,
180 final String signature,
181 final String superName,
182 final String[] interfaces) {
183 computeSVUID = (access & Opcodes.ACC_ENUM) == 0;
184
185 if (computeSVUID) {
186 this.name = name;
187 this.access = access;
188 this.interfaces = new String[interfaces.length];
189 System.arraycopy(interfaces, 0, this.interfaces, 0, interfaces.length);
190 }
191
192 super.visit(version, access, name, signature, superName, interfaces);
193 }
194
195 /*
196 * Visit the methods and get constructor and method information (step 5 and
197 * 7). Also determine if there is a class initializer (step 6).
198 */
199 @Override
200 public MethodVisitor visitMethod(
201 final int access,
202 final String name,
203 final String desc,
204 final String signature,
205 final String[] exceptions) {
206 if (computeSVUID) {
207 if ("<clinit>".equals(name)) {
208 hasStaticInitializer = true;
209 }
210 /*
211 * Remembers non private constructors and methods for SVUID
212 * computation For constructor and method modifiers, only the
213 * ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC, ACC_FINAL,
214 * ACC_SYNCHRONIZED, ACC_NATIVE, ACC_ABSTRACT and ACC_STRICT flags
215 * are used.
216 */
217 int mods =
218 access
219 & (Opcodes.ACC_PUBLIC
220 | Opcodes.ACC_PRIVATE
221 | Opcodes.ACC_PROTECTED
222 | Opcodes.ACC_STATIC
223 | Opcodes.ACC_FINAL
224 | Opcodes.ACC_SYNCHRONIZED
225 | Opcodes.ACC_NATIVE
226 | Opcodes.ACC_ABSTRACT
227 | Opcodes.ACC_STRICT);
228
229 // all non private methods
230 if ((access & Opcodes.ACC_PRIVATE) == 0) {
231 if ("<init>".equals(name)) {
232 svuidConstructors.add(new Item(name, mods, desc));
233 } else if (!"<clinit>".equals(name)) {
234 svuidMethods.add(new Item(name, mods, desc));
175235 }
176 }
177
178 /**
179 * Creates a new {@link SerialVersionUIDAdder}.
180 *
181 * @param api
182 * the ASM API version implemented by this visitor. Must be one
183 * of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
184 * @param cv
185 * a {@link ClassVisitor} to which this visitor will delegate
186 * calls.
187 */
188 protected SerialVersionUIDAdder(final int api, final ClassVisitor cv) {
189 super(api, cv);
190 svuidFields = new ArrayList<Item>();
191 svuidConstructors = new ArrayList<Item>();
192 svuidMethods = new ArrayList<Item>();
193 }
194
195 // ------------------------------------------------------------------------
196 // Overridden methods
197 // ------------------------------------------------------------------------
198
199 /*
200 * Visit class header and get class name, access , and interfaces
201 * information (step 1,2, and 3) for SVUID computation.
202 */
236 }
237 }
238
239 return super.visitMethod(access, name, desc, signature, exceptions);
240 }
241
242 /*
243 * Gets class field information for step 4 of the algorithm. Also determines
244 * if the class already has a SVUID.
245 */
246 @Override
247 public FieldVisitor visitField(
248 final int access,
249 final String name,
250 final String desc,
251 final String signature,
252 final Object value) {
253 if (computeSVUID) {
254 if ("serialVersionUID".equals(name)) {
255 // since the class already has SVUID, we won't be computing it.
256 computeSVUID = false;
257 hasSVUID = true;
258 }
259 /*
260 * Remember field for SVUID computation For field modifiers, only
261 * the ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC,
262 * ACC_FINAL, ACC_VOLATILE, and ACC_TRANSIENT flags are used when
263 * computing serialVersionUID values.
264 */
265 if ((access & Opcodes.ACC_PRIVATE) == 0
266 || (access & (Opcodes.ACC_STATIC | Opcodes.ACC_TRANSIENT)) == 0) {
267 int mods =
268 access
269 & (Opcodes.ACC_PUBLIC
270 | Opcodes.ACC_PRIVATE
271 | Opcodes.ACC_PROTECTED
272 | Opcodes.ACC_STATIC
273 | Opcodes.ACC_FINAL
274 | Opcodes.ACC_VOLATILE
275 | Opcodes.ACC_TRANSIENT);
276 svuidFields.add(new Item(name, mods, desc));
277 }
278 }
279
280 return super.visitField(access, name, desc, signature, value);
281 }
282
283 /**
284 * Handle a bizarre special case. Nested classes (static classes declared inside another class)
285 * that are protected have their access bit set to public in their class files to deal with some
286 * odd reflection situation. Our SVUID computation must do as the JVM does and ignore access bits
287 * in the class file in favor of the access bits InnerClass attribute.
288 */
289 @Override
290 public void visitInnerClass(
291 final String aname, final String outerName, final String innerName, final int attr_access) {
292 if ((name != null) && name.equals(aname)) {
293 this.access = attr_access;
294 }
295 super.visitInnerClass(aname, outerName, innerName, attr_access);
296 }
297
298 /*
299 * Add the SVUID if class doesn't have one
300 */
301 @Override
302 public void visitEnd() {
303 // compute SVUID and add it to the class
304 if (computeSVUID && !hasSVUID) {
305 try {
306 addSVUID(computeSVUID());
307 } catch (Throwable e) {
308 throw new RuntimeException("Error while computing SVUID for " + name, e);
309 }
310 }
311
312 super.visitEnd();
313 }
314
315 // ------------------------------------------------------------------------
316 // Utility methods
317 // ------------------------------------------------------------------------
318
319 /**
320 * Returns true if the class already has a SVUID field. The result of this method is only valid
321 * when visitEnd is or has been called.
322 *
323 * @return true if the class already has a SVUID field.
324 */
325 public boolean hasSVUID() {
326 return hasSVUID;
327 }
328
329 protected void addSVUID(long svuid) {
330 FieldVisitor fv =
331 super.visitField(
332 Opcodes.ACC_FINAL + Opcodes.ACC_STATIC, "serialVersionUID", "J", null, svuid);
333 if (fv != null) {
334 fv.visitEnd();
335 }
336 }
337
338 /**
339 * Computes and returns the value of SVUID.
340 *
341 * @return Returns the serial version UID
342 * @throws IOException if an I/O error occurs
343 */
344 protected long computeSVUID() throws IOException {
345 ByteArrayOutputStream bos;
346 DataOutputStream dos = null;
347 long svuid = 0;
348
349 try {
350 bos = new ByteArrayOutputStream();
351 dos = new DataOutputStream(bos);
352
353 /*
354 * 1. The class name written using UTF encoding.
355 */
356 dos.writeUTF(name.replace('/', '.'));
357
358 /*
359 * 2. The class modifiers written as a 32-bit integer.
360 */
361 int access = this.access;
362 if ((access & Opcodes.ACC_INTERFACE) != 0) {
363 access =
364 (svuidMethods.size() > 0)
365 ? (access | Opcodes.ACC_ABSTRACT)
366 : (access & ~Opcodes.ACC_ABSTRACT);
367 }
368 dos.writeInt(
369 access
370 & (Opcodes.ACC_PUBLIC
371 | Opcodes.ACC_FINAL
372 | Opcodes.ACC_INTERFACE
373 | Opcodes.ACC_ABSTRACT));
374
375 /*
376 * 3. The name of each interface sorted by name written using UTF
377 * encoding.
378 */
379 Arrays.sort(interfaces);
380 for (int i = 0; i < interfaces.length; i++) {
381 dos.writeUTF(interfaces[i].replace('/', '.'));
382 }
383
384 /*
385 * 4. For each field of the class sorted by field name (except
386 * private static and private transient fields):
387 *
388 * 1. The name of the field in UTF encoding. 2. The modifiers of the
389 * field written as a 32-bit integer. 3. The descriptor of the field
390 * in UTF encoding
391 *
392 * Note that field signatures are not dot separated. Method and
393 * constructor signatures are dot separated. Go figure...
394 */
395 writeItems(svuidFields, dos, false);
396
397 /*
398 * 5. If a class initializer exists, write out the following: 1. The
399 * name of the method, <clinit>, in UTF encoding. 2. The modifier of
400 * the method, java.lang.reflect.Modifier.STATIC, written as a
401 * 32-bit integer. 3. The descriptor of the method, ()V, in UTF
402 * encoding.
403 */
404 if (hasStaticInitializer) {
405 dos.writeUTF("<clinit>");
406 dos.writeInt(Opcodes.ACC_STATIC);
407 dos.writeUTF("()V");
408 } // if..
409
410 /*
411 * 6. For each non-private constructor sorted by method name and
412 * signature: 1. The name of the method, <init>, in UTF encoding. 2.
413 * The modifiers of the method written as a 32-bit integer. 3. The
414 * descriptor of the method in UTF encoding.
415 */
416 writeItems(svuidConstructors, dos, true);
417
418 /*
419 * 7. For each non-private method sorted by method name and
420 * signature: 1. The name of the method in UTF encoding. 2. The
421 * modifiers of the method written as a 32-bit integer. 3. The
422 * descriptor of the method in UTF encoding.
423 */
424 writeItems(svuidMethods, dos, true);
425
426 dos.flush();
427
428 /*
429 * 8. The SHA-1 algorithm is executed on the stream of bytes
430 * produced by DataOutputStream and produces five 32-bit values
431 * sha[0..4].
432 */
433 byte[] hashBytes = computeSHAdigest(bos.toByteArray());
434
435 /*
436 * 9. The hash value is assembled from the first and second 32-bit
437 * values of the SHA-1 message digest. If the result of the message
438 * digest, the five 32-bit words H0 H1 H2 H3 H4, is in an array of
439 * five int values named sha, the hash value would be computed as
440 * follows:
441 *
442 * long hash = ((sha[0] >>> 24) & 0xFF) | ((sha[0] >>> 16) & 0xFF)
443 * << 8 | ((sha[0] >>> 8) & 0xFF) << 16 | ((sha[0] >>> 0) & 0xFF) <<
444 * 24 | ((sha[1] >>> 24) & 0xFF) << 32 | ((sha[1] >>> 16) & 0xFF) <<
445 * 40 | ((sha[1] >>> 8) & 0xFF) << 48 | ((sha[1] >>> 0) & 0xFF) <<
446 * 56;
447 */
448 for (int i = Math.min(hashBytes.length, 8) - 1; i >= 0; i--) {
449 svuid = (svuid << 8) | (hashBytes[i] & 0xFF);
450 }
451 } finally {
452 // close the stream (if open)
453 if (dos != null) {
454 dos.close();
455 }
456 }
457
458 return svuid;
459 }
460
461 /**
462 * Returns the SHA-1 message digest of the given value.
463 *
464 * @param value the value whose SHA message digest must be computed.
465 * @return the SHA-1 message digest of the given value.
466 */
467 protected byte[] computeSHAdigest(final byte[] value) {
468 try {
469 return MessageDigest.getInstance("SHA").digest(value);
470 } catch (Exception e) {
471 throw new UnsupportedOperationException(e.toString());
472 }
473 }
474
475 /**
476 * Sorts the items in the collection and writes it to the data output stream
477 *
478 * @param itemCollection collection of items
479 * @param dos a <code>DataOutputStream</code> value
480 * @param dotted a <code>boolean</code> value
481 * @exception IOException if an error occurs
482 */
483 private static void writeItems(
484 final Collection<Item> itemCollection, final DataOutput dos, final boolean dotted)
485 throws IOException {
486 int size = itemCollection.size();
487 Item[] items = itemCollection.toArray(new Item[size]);
488 Arrays.sort(items);
489 for (int i = 0; i < size; i++) {
490 dos.writeUTF(items[i].name);
491 dos.writeInt(items[i].access);
492 dos.writeUTF(dotted ? items[i].desc.replace('/', '.') : items[i].desc);
493 }
494 }
495
496 // ------------------------------------------------------------------------
497 // Inner classes
498 // ------------------------------------------------------------------------
499
500 private static class Item implements Comparable<Item> {
501
502 final String name;
503
504 final int access;
505
506 final String desc;
507
508 Item(final String name, final int access, final String desc) {
509 this.name = name;
510 this.access = access;
511 this.desc = desc;
512 }
513
514 public int compareTo(final Item other) {
515 int retVal = name.compareTo(other.name);
516 if (retVal == 0) {
517 retVal = desc.compareTo(other.desc);
518 }
519 return retVal;
520 }
521
203522 @Override
204 public void visit(final int version, final int access, final String name,
205 final String signature, final String superName,
206 final String[] interfaces) {
207 computeSVUID = (access & Opcodes.ACC_ENUM) == 0;
208
209 if (computeSVUID) {
210 this.name = name;
211 this.access = access;
212 this.interfaces = new String[interfaces.length];
213 System.arraycopy(interfaces, 0, this.interfaces, 0,
214 interfaces.length);
215 }
216
217 super.visit(version, access, name, signature, superName, interfaces);
218 }
219
220 /*
221 * Visit the methods and get constructor and method information (step 5 and
222 * 7). Also determine if there is a class initializer (step 6).
223 */
523 public boolean equals(final Object o) {
524 if (o instanceof Item) {
525 return compareTo((Item) o) == 0;
526 }
527 return false;
528 }
529
224530 @Override
225 public MethodVisitor visitMethod(final int access, final String name,
226 final String desc, final String signature, final String[] exceptions) {
227 if (computeSVUID) {
228 if ("<clinit>".equals(name)) {
229 hasStaticInitializer = true;
230 }
231 /*
232 * Remembers non private constructors and methods for SVUID
233 * computation For constructor and method modifiers, only the
234 * ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC, ACC_FINAL,
235 * ACC_SYNCHRONIZED, ACC_NATIVE, ACC_ABSTRACT and ACC_STRICT flags
236 * are used.
237 */
238 int mods = access
239 & (Opcodes.ACC_PUBLIC | Opcodes.ACC_PRIVATE
240 | Opcodes.ACC_PROTECTED | Opcodes.ACC_STATIC
241 | Opcodes.ACC_FINAL | Opcodes.ACC_SYNCHRONIZED
242 | Opcodes.ACC_NATIVE | Opcodes.ACC_ABSTRACT | Opcodes.ACC_STRICT);
243
244 // all non private methods
245 if ((access & Opcodes.ACC_PRIVATE) == 0) {
246 if ("<init>".equals(name)) {
247 svuidConstructors.add(new Item(name, mods, desc));
248 } else if (!"<clinit>".equals(name)) {
249 svuidMethods.add(new Item(name, mods, desc));
250 }
251 }
252 }
253
254 return super.visitMethod(access, name, desc, signature, exceptions);
255 }
256
257 /*
258 * Gets class field information for step 4 of the algorithm. Also determines
259 * if the class already has a SVUID.
260 */
261 @Override
262 public FieldVisitor visitField(final int access, final String name,
263 final String desc, final String signature, final Object value) {
264 if (computeSVUID) {
265 if ("serialVersionUID".equals(name)) {
266 // since the class already has SVUID, we won't be computing it.
267 computeSVUID = false;
268 hasSVUID = true;
269 }
270 /*
271 * Remember field for SVUID computation For field modifiers, only
272 * the ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC,
273 * ACC_FINAL, ACC_VOLATILE, and ACC_TRANSIENT flags are used when
274 * computing serialVersionUID values.
275 */
276 if ((access & Opcodes.ACC_PRIVATE) == 0
277 || (access & (Opcodes.ACC_STATIC | Opcodes.ACC_TRANSIENT)) == 0) {
278 int mods = access
279 & (Opcodes.ACC_PUBLIC | Opcodes.ACC_PRIVATE
280 | Opcodes.ACC_PROTECTED | Opcodes.ACC_STATIC
281 | Opcodes.ACC_FINAL | Opcodes.ACC_VOLATILE | Opcodes.ACC_TRANSIENT);
282 svuidFields.add(new Item(name, mods, desc));
283 }
284 }
285
286 return super.visitField(access, name, desc, signature, value);
287 }
288
289 /**
290 * Handle a bizarre special case. Nested classes (static classes declared
291 * inside another class) that are protected have their access bit set to
292 * public in their class files to deal with some odd reflection situation.
293 * Our SVUID computation must do as the JVM does and ignore access bits in
294 * the class file in favor of the access bits InnerClass attribute.
295 */
296 @Override
297 public void visitInnerClass(final String aname, final String outerName,
298 final String innerName, final int attr_access) {
299 if ((name != null) && name.equals(aname)) {
300 this.access = attr_access;
301 }
302 super.visitInnerClass(aname, outerName, innerName, attr_access);
303 }
304
305 /*
306 * Add the SVUID if class doesn't have one
307 */
308 @Override
309 public void visitEnd() {
310 // compute SVUID and add it to the class
311 if (computeSVUID && !hasSVUID) {
312 try {
313 addSVUID(computeSVUID());
314 } catch (Throwable e) {
315 throw new RuntimeException("Error while computing SVUID for "
316 + name, e);
317 }
318 }
319
320 super.visitEnd();
321 }
322
323 // ------------------------------------------------------------------------
324 // Utility methods
325 // ------------------------------------------------------------------------
326
327 /**
328 * Returns true if the class already has a SVUID field. The result of this
329 * method is only valid when visitEnd is or has been called.
330 *
331 * @return true if the class already has a SVUID field.
332 */
333 public boolean hasSVUID() {
334 return hasSVUID;
335 }
336
337 protected void addSVUID(long svuid) {
338 FieldVisitor fv = super.visitField(Opcodes.ACC_FINAL
339 + Opcodes.ACC_STATIC, "serialVersionUID", "J", null, svuid);
340 if (fv != null) {
341 fv.visitEnd();
342 }
343 }
344
345 /**
346 * Computes and returns the value of SVUID.
347 *
348 * @return Returns the serial version UID
349 * @throws IOException
350 * if an I/O error occurs
351 */
352 protected long computeSVUID() throws IOException {
353 ByteArrayOutputStream bos;
354 DataOutputStream dos = null;
355 long svuid = 0;
356
357 try {
358 bos = new ByteArrayOutputStream();
359 dos = new DataOutputStream(bos);
360
361 /*
362 * 1. The class name written using UTF encoding.
363 */
364 dos.writeUTF(name.replace('/', '.'));
365
366 /*
367 * 2. The class modifiers written as a 32-bit integer.
368 */
369 int access = this.access;
370 if ((access & Opcodes.ACC_INTERFACE) != 0) {
371 access = (svuidMethods.size() > 0) ? (access | Opcodes.ACC_ABSTRACT)
372 : (access & ~Opcodes.ACC_ABSTRACT);
373 }
374 dos.writeInt(access
375 & (Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL
376 | Opcodes.ACC_INTERFACE | Opcodes.ACC_ABSTRACT));
377
378 /*
379 * 3. The name of each interface sorted by name written using UTF
380 * encoding.
381 */
382 Arrays.sort(interfaces);
383 for (int i = 0; i < interfaces.length; i++) {
384 dos.writeUTF(interfaces[i].replace('/', '.'));
385 }
386
387 /*
388 * 4. For each field of the class sorted by field name (except
389 * private static and private transient fields):
390 *
391 * 1. The name of the field in UTF encoding. 2. The modifiers of the
392 * field written as a 32-bit integer. 3. The descriptor of the field
393 * in UTF encoding
394 *
395 * Note that field signatures are not dot separated. Method and
396 * constructor signatures are dot separated. Go figure...
397 */
398 writeItems(svuidFields, dos, false);
399
400 /*
401 * 5. If a class initializer exists, write out the following: 1. The
402 * name of the method, <clinit>, in UTF encoding. 2. The modifier of
403 * the method, java.lang.reflect.Modifier.STATIC, written as a
404 * 32-bit integer. 3. The descriptor of the method, ()V, in UTF
405 * encoding.
406 */
407 if (hasStaticInitializer) {
408 dos.writeUTF("<clinit>");
409 dos.writeInt(Opcodes.ACC_STATIC);
410 dos.writeUTF("()V");
411 } // if..
412
413 /*
414 * 6. For each non-private constructor sorted by method name and
415 * signature: 1. The name of the method, <init>, in UTF encoding. 2.
416 * The modifiers of the method written as a 32-bit integer. 3. The
417 * descriptor of the method in UTF encoding.
418 */
419 writeItems(svuidConstructors, dos, true);
420
421 /*
422 * 7. For each non-private method sorted by method name and
423 * signature: 1. The name of the method in UTF encoding. 2. The
424 * modifiers of the method written as a 32-bit integer. 3. The
425 * descriptor of the method in UTF encoding.
426 */
427 writeItems(svuidMethods, dos, true);
428
429 dos.flush();
430
431 /*
432 * 8. The SHA-1 algorithm is executed on the stream of bytes
433 * produced by DataOutputStream and produces five 32-bit values
434 * sha[0..4].
435 */
436 byte[] hashBytes = computeSHAdigest(bos.toByteArray());
437
438 /*
439 * 9. The hash value is assembled from the first and second 32-bit
440 * values of the SHA-1 message digest. If the result of the message
441 * digest, the five 32-bit words H0 H1 H2 H3 H4, is in an array of
442 * five int values named sha, the hash value would be computed as
443 * follows:
444 *
445 * long hash = ((sha[0] >>> 24) & 0xFF) | ((sha[0] >>> 16) & 0xFF)
446 * << 8 | ((sha[0] >>> 8) & 0xFF) << 16 | ((sha[0] >>> 0) & 0xFF) <<
447 * 24 | ((sha[1] >>> 24) & 0xFF) << 32 | ((sha[1] >>> 16) & 0xFF) <<
448 * 40 | ((sha[1] >>> 8) & 0xFF) << 48 | ((sha[1] >>> 0) & 0xFF) <<
449 * 56;
450 */
451 for (int i = Math.min(hashBytes.length, 8) - 1; i >= 0; i--) {
452 svuid = (svuid << 8) | (hashBytes[i] & 0xFF);
453 }
454 } finally {
455 // close the stream (if open)
456 if (dos != null) {
457 dos.close();
458 }
459 }
460
461 return svuid;
462 }
463
464 /**
465 * Returns the SHA-1 message digest of the given value.
466 *
467 * @param value
468 * the value whose SHA message digest must be computed.
469 * @return the SHA-1 message digest of the given value.
470 */
471 protected byte[] computeSHAdigest(final byte[] value) {
472 try {
473 return MessageDigest.getInstance("SHA").digest(value);
474 } catch (Exception e) {
475 throw new UnsupportedOperationException(e.toString());
476 }
477 }
478
479 /**
480 * Sorts the items in the collection and writes it to the data output stream
481 *
482 * @param itemCollection
483 * collection of items
484 * @param dos
485 * a <code>DataOutputStream</code> value
486 * @param dotted
487 * a <code>boolean</code> value
488 * @exception IOException
489 * if an error occurs
490 */
491 private static void writeItems(final Collection<Item> itemCollection,
492 final DataOutput dos, final boolean dotted) throws IOException {
493 int size = itemCollection.size();
494 Item[] items = itemCollection.toArray(new Item[size]);
495 Arrays.sort(items);
496 for (int i = 0; i < size; i++) {
497 dos.writeUTF(items[i].name);
498 dos.writeInt(items[i].access);
499 dos.writeUTF(dotted ? items[i].desc.replace('/', '.')
500 : items[i].desc);
501 }
502 }
503
504 // ------------------------------------------------------------------------
505 // Inner classes
506 // ------------------------------------------------------------------------
507
508 private static class Item implements Comparable<Item> {
509
510 final String name;
511
512 final int access;
513
514 final String desc;
515
516 Item(final String name, final int access, final String desc) {
517 this.name = name;
518 this.access = access;
519 this.desc = desc;
520 }
521
522 public int compareTo(final Item other) {
523 int retVal = name.compareTo(other.name);
524 if (retVal == 0) {
525 retVal = desc.compareTo(other.desc);
526 }
527 return retVal;
528 }
529
530 @Override
531 public boolean equals(final Object o) {
532 if (o instanceof Item) {
533 return compareTo((Item) o) == 0;
534 }
535 return false;
536 }
537
538 @Override
539 public int hashCode() {
540 return (name + desc).hashCode();
541 }
542 }
531 public int hashCode() {
532 return (name + desc).hashCode();
533 }
534 }
543535 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927
3028 package org.eclipse.persistence.internal.libraries.asm.commons;
3129
3634
3735 /**
3836 * A {@link SignatureVisitor} adapter for type mapping.
39 *
37 *
4038 * @author Eugene Kuleshov
4139 */
4240 public class SignatureRemapper extends SignatureVisitor {
4341
44 private final SignatureVisitor v;
42 private final SignatureVisitor v;
4543
46 private final Remapper remapper;
44 private final Remapper remapper;
4745
48 private Stack<String> classNames = new Stack<String>();
46 private Stack<String> classNames = new Stack<String>();
4947
50 public SignatureRemapper(final SignatureVisitor v, final Remapper remapper) {
51 this(Opcodes.ASM6, v, remapper);
52 }
48 public SignatureRemapper(final SignatureVisitor v, final Remapper remapper) {
49 this(Opcodes.ASM6, v, remapper);
50 }
5351
54 protected SignatureRemapper(final int api, final SignatureVisitor v,
55 final Remapper remapper) {
56 super(api);
57 this.v = v;
58 this.remapper = remapper;
59 }
52 protected SignatureRemapper(final int api, final SignatureVisitor v, final Remapper remapper) {
53 super(api);
54 this.v = v;
55 this.remapper = remapper;
56 }
6057
61 @Override
62 public void visitClassType(String name) {
63 classNames.push(name);
64 v.visitClassType(remapper.mapType(name));
65 }
58 @Override
59 public void visitClassType(String name) {
60 classNames.push(name);
61 v.visitClassType(remapper.mapType(name));
62 }
6663
67 @Override
68 public void visitInnerClassType(String name) {
69 String outerClassName = classNames.pop();
70 String className = outerClassName + '$' + name;
71 classNames.push(className);
72 String remappedOuter = remapper.mapType(outerClassName) + '$';
73 String remappedName = remapper.mapType(className);
74 int index = remappedName.startsWith(remappedOuter) ? remappedOuter
75 .length() : remappedName.lastIndexOf('$') + 1;
76 v.visitInnerClassType(remappedName.substring(index));
77 }
64 @Override
65 public void visitInnerClassType(String name) {
66 String outerClassName = classNames.pop();
67 String className = outerClassName + '$' + name;
68 classNames.push(className);
69 String remappedOuter = remapper.mapType(outerClassName) + '$';
70 String remappedName = remapper.mapType(className);
71 int index =
72 remappedName.startsWith(remappedOuter)
73 ? remappedOuter.length()
74 : remappedName.lastIndexOf('$') + 1;
75 v.visitInnerClassType(remappedName.substring(index));
76 }
7877
79 @Override
80 public void visitFormalTypeParameter(String name) {
81 v.visitFormalTypeParameter(name);
82 }
78 @Override
79 public void visitFormalTypeParameter(String name) {
80 v.visitFormalTypeParameter(name);
81 }
8382
84 @Override
85 public void visitTypeVariable(String name) {
86 v.visitTypeVariable(name);
87 }
83 @Override
84 public void visitTypeVariable(String name) {
85 v.visitTypeVariable(name);
86 }
8887
89 @Override
90 public SignatureVisitor visitArrayType() {
91 v.visitArrayType();
92 return this;
93 }
88 @Override
89 public SignatureVisitor visitArrayType() {
90 v.visitArrayType();
91 return this;
92 }
9493
95 @Override
96 public void visitBaseType(char descriptor) {
97 v.visitBaseType(descriptor);
98 }
94 @Override
95 public void visitBaseType(char descriptor) {
96 v.visitBaseType(descriptor);
97 }
9998
100 @Override
101 public SignatureVisitor visitClassBound() {
102 v.visitClassBound();
103 return this;
104 }
99 @Override
100 public SignatureVisitor visitClassBound() {
101 v.visitClassBound();
102 return this;
103 }
105104
106 @Override
107 public SignatureVisitor visitExceptionType() {
108 v.visitExceptionType();
109 return this;
110 }
105 @Override
106 public SignatureVisitor visitExceptionType() {
107 v.visitExceptionType();
108 return this;
109 }
111110
112 @Override
113 public SignatureVisitor visitInterface() {
114 v.visitInterface();
115 return this;
116 }
111 @Override
112 public SignatureVisitor visitInterface() {
113 v.visitInterface();
114 return this;
115 }
117116
118 @Override
119 public SignatureVisitor visitInterfaceBound() {
120 v.visitInterfaceBound();
121 return this;
122 }
117 @Override
118 public SignatureVisitor visitInterfaceBound() {
119 v.visitInterfaceBound();
120 return this;
121 }
123122
124 @Override
125 public SignatureVisitor visitParameterType() {
126 v.visitParameterType();
127 return this;
128 }
123 @Override
124 public SignatureVisitor visitParameterType() {
125 v.visitParameterType();
126 return this;
127 }
129128
130 @Override
131 public SignatureVisitor visitReturnType() {
132 v.visitReturnType();
133 return this;
134 }
129 @Override
130 public SignatureVisitor visitReturnType() {
131 v.visitReturnType();
132 return this;
133 }
135134
136 @Override
137 public SignatureVisitor visitSuperclass() {
138 v.visitSuperclass();
139 return this;
140 }
135 @Override
136 public SignatureVisitor visitSuperclass() {
137 v.visitSuperclass();
138 return this;
139 }
141140
142 @Override
143 public void visitTypeArgument() {
144 v.visitTypeArgument();
145 }
141 @Override
142 public void visitTypeArgument() {
143 v.visitTypeArgument();
144 }
146145
147 @Override
148 public SignatureVisitor visitTypeArgument(char wildcard) {
149 v.visitTypeArgument(wildcard);
150 return this;
151 }
146 @Override
147 public SignatureVisitor visitTypeArgument(char wildcard) {
148 v.visitTypeArgument(wildcard);
149 return this;
150 }
152151
153 @Override
154 public void visitEnd() {
155 v.visitEnd();
156 classNames.pop();
157 }
152 @Override
153 public void visitEnd() {
154 v.visitEnd();
155 classNames.pop();
156 }
158157 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927
3028 package org.eclipse.persistence.internal.libraries.asm.commons;
3129
3937 */
4038 public class SimpleRemapper extends Remapper {
4139
42 private final Map<String, String> mapping;
40 private final Map<String, String> mapping;
4341
44 public SimpleRemapper(Map<String, String> mapping) {
45 this.mapping = mapping;
46 }
42 public SimpleRemapper(Map<String, String> mapping) {
43 this.mapping = mapping;
44 }
4745
48 public SimpleRemapper(String oldName, String newName) {
49 this.mapping = Collections.singletonMap(oldName, newName);
50 }
46 public SimpleRemapper(String oldName, String newName) {
47 this.mapping = Collections.singletonMap(oldName, newName);
48 }
5149
52 @Override
53 public String mapMethodName(String owner, String name, String desc) {
54 String s = map(owner + '.' + name + desc);
55 return s == null ? name : s;
56 }
50 @Override
51 public String mapMethodName(String owner, String name, String desc) {
52 String s = map(owner + '.' + name + desc);
53 return s == null ? name : s;
54 }
5755
58 @Override
59 public String mapInvokeDynamicMethodName(String name, String desc) {
60 String s = map('.' + name + desc);
61 return s == null ? name : s;
62 }
56 @Override
57 public String mapInvokeDynamicMethodName(String name, String desc) {
58 String s = map('.' + name + desc);
59 return s == null ? name : s;
60 }
6361
64 @Override
65 public String mapFieldName(String owner, String name, String desc) {
66 String s = map(owner + '.' + name);
67 return s == null ? name : s;
68 }
62 @Override
63 public String mapFieldName(String owner, String name, String desc) {
64 String s = map(owner + '.' + name);
65 return s == null ? name : s;
66 }
6967
70 @Override
71 public String map(String key) {
72 return mapping.get(key);
73 }
68 @Override
69 public String map(String key) {
70 return mapping.get(key);
71 }
7472 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.commons;
3028
3129 import org.eclipse.persistence.internal.libraries.asm.ClassVisitor;
3432
3533 /**
3634 * A {@link ClassVisitor} that merges clinit methods into a single one.
37 *
35 *
3836 * @author Eric Bruneton
3937 */
4038 public class StaticInitMerger extends ClassVisitor {
4139
42 private String name;
40 private String name;
4341
44 private MethodVisitor clinit;
42 private MethodVisitor clinit;
4543
46 private final String prefix;
44 private final String prefix;
4745
48 private int counter;
46 private int counter;
4947
50 public StaticInitMerger(final String prefix, final ClassVisitor cv) {
51 this(Opcodes.ASM6, prefix, cv);
48 public StaticInitMerger(final String prefix, final ClassVisitor cv) {
49 this(Opcodes.ASM6, prefix, cv);
50 }
51
52 protected StaticInitMerger(final int api, final String prefix, final ClassVisitor cv) {
53 super(api, cv);
54 this.prefix = prefix;
55 }
56
57 @Override
58 public void visit(
59 final int version,
60 final int access,
61 final String name,
62 final String signature,
63 final String superName,
64 final String[] interfaces) {
65 cv.visit(version, access, name, signature, superName, interfaces);
66 this.name = name;
67 }
68
69 @Override
70 public MethodVisitor visitMethod(
71 final int access,
72 final String name,
73 final String desc,
74 final String signature,
75 final String[] exceptions) {
76 MethodVisitor mv;
77 if ("<clinit>".equals(name)) {
78 int a = Opcodes.ACC_PRIVATE + Opcodes.ACC_STATIC;
79 String n = prefix + counter++;
80 mv = cv.visitMethod(a, n, desc, signature, exceptions);
81
82 if (clinit == null) {
83 clinit = cv.visitMethod(a, name, desc, null, null);
84 }
85 clinit.visitMethodInsn(Opcodes.INVOKESTATIC, this.name, n, desc, false);
86 } else {
87 mv = cv.visitMethod(access, name, desc, signature, exceptions);
5288 }
89 return mv;
90 }
5391
54 protected StaticInitMerger(final int api, final String prefix,
55 final ClassVisitor cv) {
56 super(api, cv);
57 this.prefix = prefix;
92 @Override
93 public void visitEnd() {
94 if (clinit != null) {
95 clinit.visitInsn(Opcodes.RETURN);
96 clinit.visitMaxs(0, 0);
5897 }
59
60 @Override
61 public void visit(final int version, final int access, final String name,
62 final String signature, final String superName,
63 final String[] interfaces) {
64 cv.visit(version, access, name, signature, superName, interfaces);
65 this.name = name;
66 }
67
68 @Override
69 public MethodVisitor visitMethod(final int access, final String name,
70 final String desc, final String signature, final String[] exceptions) {
71 MethodVisitor mv;
72 if ("<clinit>".equals(name)) {
73 int a = Opcodes.ACC_PRIVATE + Opcodes.ACC_STATIC;
74 String n = prefix + counter++;
75 mv = cv.visitMethod(a, n, desc, signature, exceptions);
76
77 if (clinit == null) {
78 clinit = cv.visitMethod(a, name, desc, null, null);
79 }
80 clinit.visitMethodInsn(Opcodes.INVOKESTATIC, this.name, n, desc,
81 false);
82 } else {
83 mv = cv.visitMethod(access, name, desc, signature, exceptions);
84 }
85 return mv;
86 }
87
88 @Override
89 public void visitEnd() {
90 if (clinit != null) {
91 clinit.visitInsn(Opcodes.RETURN);
92 clinit.visitMaxs(0, 0);
93 }
94 cv.visitEnd();
95 }
98 cv.visitEnd();
99 }
96100 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.commons;
3028
3129 import org.eclipse.persistence.internal.libraries.asm.Label;
3230
3331 /**
3432 * A code generator for switch statements.
35 *
33 *
3634 * @author Juozas Baliuka
3735 * @author Chris Nokleberg
3836 * @author Eric Bruneton
3937 */
4038 public interface TableSwitchGenerator {
4139
42 /**
43 * Generates the code for a switch case.
44 *
45 * @param key
46 * the switch case key.
47 * @param end
48 * a label that corresponds to the end of the switch statement.
49 */
50 void generateCase(int key, Label end);
40 /**
41 * Generates the code for a switch case.
42 *
43 * @param key the switch case key.
44 * @param end a label that corresponds to the end of the switch statement.
45 */
46 void generateCase(int key, Label end);
5147
52 /**
53 * Generates the code for the default switch case.
54 */
55 void generateDefault();
48 /** Generates the code for the default switch case. */
49 void generateDefault();
5650 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927
3028 package org.eclipse.persistence.internal.libraries.asm.commons;
3129
3836 import org.eclipse.persistence.internal.libraries.asm.tree.TryCatchBlockNode;
3937
4038 /**
41 * A {@link MethodVisitor} adapter to sort the exception handlers. The handlers
42 * are sorted in a method innermost-to-outermost. This allows the programmer to
43 * add handlers without worrying about ordering them correctly with respect to
44 * existing, in-code handlers.
45 *
46 * Behavior is only defined for properly-nested handlers. If any "try" blocks
47 * overlap (something that isn't possible in Java code) then this may not do
48 * what you want. In fact, this adapter just sorts by the length of the "try"
49 * block, taking advantage of the fact that a given try block must be larger
50 * than any block it contains).
51 *
39 * A {@link MethodVisitor} adapter to sort the exception handlers. The handlers are sorted in a
40 * method innermost-to-outermost. This allows the programmer to add handlers without worrying about
41 * ordering them correctly with respect to existing, in-code handlers.
42 *
43 * <p>Behavior is only defined for properly-nested handlers. If any "try" blocks overlap (something
44 * that isn't possible in Java code) then this may not do what you want. In fact, this adapter just
45 * sorts by the length of the "try" block, taking advantage of the fact that a given try block must
46 * be larger than any block it contains).
47 *
5248 * @author Adrian Sampson
5349 */
5450 public class TryCatchBlockSorter extends MethodNode {
5551
56 public TryCatchBlockSorter(final MethodVisitor mv, final int access,
57 final String name, final String desc, final String signature,
58 final String[] exceptions) {
59 this(Opcodes.ASM6, mv, access, name, desc, signature, exceptions);
52 public TryCatchBlockSorter(
53 final MethodVisitor mv,
54 final int access,
55 final String name,
56 final String desc,
57 final String signature,
58 final String[] exceptions) {
59 this(Opcodes.ASM6, mv, access, name, desc, signature, exceptions);
60 if (getClass() != TryCatchBlockSorter.class) {
61 throw new IllegalStateException();
6062 }
63 }
6164
62 protected TryCatchBlockSorter(final int api, final MethodVisitor mv,
63 final int access, final String name, final String desc,
64 final String signature, final String[] exceptions) {
65 super(api, access, name, desc, signature, exceptions);
66 this.mv = mv;
65 protected TryCatchBlockSorter(
66 final int api,
67 final MethodVisitor mv,
68 final int access,
69 final String name,
70 final String desc,
71 final String signature,
72 final String[] exceptions) {
73 super(api, access, name, desc, signature, exceptions);
74 this.mv = mv;
75 }
76
77 @Override
78 public void visitEnd() {
79 // Compares TryCatchBlockNodes by the length of their "try" block.
80 Comparator<TryCatchBlockNode> comp =
81 new Comparator<TryCatchBlockNode>() {
82
83 public int compare(TryCatchBlockNode t1, TryCatchBlockNode t2) {
84 int len1 = blockLength(t1);
85 int len2 = blockLength(t2);
86 return len1 - len2;
87 }
88
89 private int blockLength(TryCatchBlockNode block) {
90 int startidx = instructions.indexOf(block.start);
91 int endidx = instructions.indexOf(block.end);
92 return endidx - startidx;
93 }
94 };
95 Collections.sort(tryCatchBlocks, comp);
96 // Updates the 'target' of each try catch block annotation.
97 for (int i = 0; i < tryCatchBlocks.size(); ++i) {
98 tryCatchBlocks.get(i).updateIndex(i);
6799 }
68
69 @Override
70 public void visitEnd() {
71 // Compares TryCatchBlockNodes by the length of their "try" block.
72 Comparator<TryCatchBlockNode> comp = new Comparator<TryCatchBlockNode>() {
73
74 public int compare(TryCatchBlockNode t1, TryCatchBlockNode t2) {
75 int len1 = blockLength(t1);
76 int len2 = blockLength(t2);
77 return len1 - len2;
78 }
79
80 private int blockLength(TryCatchBlockNode block) {
81 int startidx = instructions.indexOf(block.start);
82 int endidx = instructions.indexOf(block.end);
83 return endidx - startidx;
84 }
85 };
86 Collections.sort(tryCatchBlocks, comp);
87 // Updates the 'target' of each try catch block annotation.
88 for (int i = 0; i < tryCatchBlocks.size(); ++i) {
89 tryCatchBlocks.get(i).updateIndex(i);
90 }
91 if (mv != null) {
92 accept(mv);
93 }
100 if (mv != null) {
101 accept(mv);
94102 }
103 }
95104 }
+0
-48
org/eclipse/persistence/internal/libraries/asm/commons/package.html less more
0 <html>
1 <!--
2 * ASM: a very small and fast Java bytecode manipulation framework
3 * Copyright (c) 2000-2011 INRIA, France Telecom
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the copyright holders nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
28 * THE POSSIBILITY OF SUCH DAMAGE.
29 -->
30 <body>
31 Provides some useful class and method adapters. <i>The preferred way of using
32 these adapters is by chaining them together and to custom adapters (instead of
33 inheriting from them)</i>. Indeed this approach provides more combination
34 possibilities than inheritance. For instance, suppose you want to implement an
35 adapter MyAdapter than needs sorted local variables and intermediate stack map
36 frame values taking into account the local variables sort. By using inheritance,
37 this would require MyAdapter to extend AnalyzerAdapter, itself extending
38 LocalVariablesSorter. But AnalyzerAdapter is not a subclass of
39 LocalVariablesSorter, so this is not possible. On the contrary, by using
40 delegation, you can make LocalVariablesSorter delegate to AnalyzerAdapter,
41 itself delegating to MyAdapter. In this case AnalyzerAdapter computes
42 intermediate frames based on the output of LocalVariablesSorter, and MyAdapter
43 can add new locals by calling the newLocal method on LocalVariablesSorter, and
44 can get the stack map frame state before each instruction by reading the locals
45 and stack fields in AnalyzerAdapter (this requires references from MyAdapter
46 back to LocalVariablesSorter and AnalyzerAdapter).
47 </body>
+0
-147
org/eclipse/persistence/internal/libraries/asm/optimizer/AnnotationConstantsCollector.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 package org.eclipse.persistence.internal.libraries.asm.optimizer;
30
31 import org.eclipse.persistence.internal.libraries.asm.AnnotationVisitor;
32 import org.eclipse.persistence.internal.libraries.asm.Opcodes;
33 import org.eclipse.persistence.internal.libraries.asm.Type;
34
35 /**
36 * An {@link AnnotationVisitor} that collects the {@link Constant}s of the
37 * annotations it visits.
38 *
39 * @author Eric Bruneton
40 */
41 public class AnnotationConstantsCollector extends AnnotationVisitor {
42
43 private final ConstantPool cp;
44
45 public AnnotationConstantsCollector(final AnnotationVisitor av,
46 final ConstantPool cp) {
47 super(Opcodes.ASM6, av);
48 this.cp = cp;
49 }
50
51 @Override
52 public void visit(final String name, final Object value) {
53 if (name != null) {
54 cp.newUTF8(name);
55 }
56 if (value instanceof Byte) {
57 cp.newInteger(((Byte) value).byteValue());
58 } else if (value instanceof Boolean) {
59 cp.newInteger(((Boolean) value).booleanValue() ? 1 : 0);
60 } else if (value instanceof Character) {
61 cp.newInteger(((Character) value).charValue());
62 } else if (value instanceof Short) {
63 cp.newInteger(((Short) value).shortValue());
64 } else if (value instanceof Type) {
65 cp.newUTF8(((Type) value).getDescriptor());
66 } else if (value instanceof byte[]) {
67 byte[] v = (byte[]) value;
68 for (int i = 0; i < v.length; i++) {
69 cp.newInteger(v[i]);
70 }
71 } else if (value instanceof boolean[]) {
72 boolean[] v = (boolean[]) value;
73 for (int i = 0; i < v.length; i++) {
74 cp.newInteger(v[i] ? 1 : 0);
75 }
76 } else if (value instanceof short[]) {
77 short[] v = (short[]) value;
78 for (int i = 0; i < v.length; i++) {
79 cp.newInteger(v[i]);
80 }
81 } else if (value instanceof char[]) {
82 char[] v = (char[]) value;
83 for (int i = 0; i < v.length; i++) {
84 cp.newInteger(v[i]);
85 }
86 } else if (value instanceof int[]) {
87 int[] v = (int[]) value;
88 for (int i = 0; i < v.length; i++) {
89 cp.newInteger(v[i]);
90 }
91 } else if (value instanceof long[]) {
92 long[] v = (long[]) value;
93 for (int i = 0; i < v.length; i++) {
94 cp.newLong(v[i]);
95 }
96 } else if (value instanceof float[]) {
97 float[] v = (float[]) value;
98 for (int i = 0; i < v.length; i++) {
99 cp.newFloat(v[i]);
100 }
101 } else if (value instanceof double[]) {
102 double[] v = (double[]) value;
103 for (int i = 0; i < v.length; i++) {
104 cp.newDouble(v[i]);
105 }
106 } else {
107 cp.newConst(value);
108 }
109 av.visit(name, value);
110 }
111
112 @Override
113 public void visitEnum(final String name, final String desc,
114 final String value) {
115 if (name != null) {
116 cp.newUTF8(name);
117 }
118 cp.newUTF8(desc);
119 cp.newUTF8(value);
120 av.visitEnum(name, desc, value);
121 }
122
123 @Override
124 public AnnotationVisitor visitAnnotation(final String name,
125 final String desc) {
126 if (name != null) {
127 cp.newUTF8(name);
128 }
129 cp.newUTF8(desc);
130 return new AnnotationConstantsCollector(av.visitAnnotation(name, desc),
131 cp);
132 }
133
134 @Override
135 public AnnotationVisitor visitArray(final String name) {
136 if (name != null) {
137 cp.newUTF8(name);
138 }
139 return new AnnotationConstantsCollector(av.visitArray(name), cp);
140 }
141
142 @Override
143 public void visitEnd() {
144 av.visitEnd();
145 }
146 }
+0
-205
org/eclipse/persistence/internal/libraries/asm/optimizer/ClassConstantsCollector.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 package org.eclipse.persistence.internal.libraries.asm.optimizer;
30
31 import org.eclipse.persistence.internal.libraries.asm.AnnotationVisitor;
32 import org.eclipse.persistence.internal.libraries.asm.Attribute;
33 import org.eclipse.persistence.internal.libraries.asm.ClassVisitor;
34 import org.eclipse.persistence.internal.libraries.asm.FieldVisitor;
35 import org.eclipse.persistence.internal.libraries.asm.MethodVisitor;
36 import org.eclipse.persistence.internal.libraries.asm.ModuleVisitor;
37 import org.eclipse.persistence.internal.libraries.asm.Opcodes;
38 import org.eclipse.persistence.internal.libraries.asm.TypePath;
39
40 /**
41 * A {@link ClassVisitor} that collects the {@link Constant}s of the classes it
42 * visits.
43 *
44 * @author Eric Bruneton
45 */
46 public class ClassConstantsCollector extends ClassVisitor {
47
48 private final ConstantPool cp;
49
50 public ClassConstantsCollector(final ClassVisitor cv, final ConstantPool cp) {
51 super(Opcodes.ASM6, cv);
52 this.cp = cp;
53 }
54
55 @Override
56 public void visit(final int version, final int access, final String name,
57 final String signature, final String superName,
58 final String[] interfaces) {
59 if ((access & Opcodes.ACC_DEPRECATED) != 0) {
60 cp.newUTF8("Deprecated");
61 }
62 if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
63 cp.newUTF8("Synthetic");
64 }
65 cp.newClass(name);
66 if (signature != null) {
67 cp.newUTF8("Signature");
68 cp.newUTF8(signature);
69 }
70 if (superName != null) {
71 cp.newClass(superName);
72 }
73 if (interfaces != null) {
74 for (int i = 0; i < interfaces.length; ++i) {
75 cp.newClass(interfaces[i]);
76 }
77 }
78 cv.visit(version, access, name, signature, superName, interfaces);
79 }
80
81 @Override
82 public void visitSource(final String source, final String debug) {
83 if (source != null) {
84 cp.newUTF8("SourceFile");
85 cp.newUTF8(source);
86 }
87 if (debug != null) {
88 cp.newUTF8("SourceDebugExtension");
89 }
90 cv.visitSource(source, debug);
91 }
92
93 @Override
94 public ModuleVisitor visitModule() {
95 cp.newUTF8("Module");
96 return new ModuleConstantsCollector(cv.visitModule(), cp);
97 }
98
99 @Override
100 public void visitOuterClass(final String owner, final String name,
101 final String desc) {
102 cp.newUTF8("EnclosingMethod");
103 cp.newClass(owner);
104 if (name != null && desc != null) {
105 cp.newNameType(name, desc);
106 }
107 cv.visitOuterClass(owner, name, desc);
108 }
109
110 @Override
111 public AnnotationVisitor visitAnnotation(final String desc,
112 final boolean visible) {
113 cp.newUTF8(desc);
114 if (visible) {
115 cp.newUTF8("RuntimeVisibleAnnotations");
116 } else {
117 cp.newUTF8("RuntimeInvisibleAnnotations");
118 }
119 return new AnnotationConstantsCollector(cv.visitAnnotation(desc,
120 visible), cp);
121 }
122
123 @Override
124 public AnnotationVisitor visitTypeAnnotation(int typeRef,
125 TypePath typePath, String desc, boolean visible) {
126 cp.newUTF8(desc);
127 if (visible) {
128 cp.newUTF8("RuntimeVisibleTypeAnnotations");
129 } else {
130 cp.newUTF8("RuntimeInvisibleTypeAnnotations");
131 }
132 return new AnnotationConstantsCollector(cv.visitAnnotation(desc,
133 visible), cp);
134 }
135
136 @Override
137 public void visitAttribute(final Attribute attr) {
138 // can do nothing
139 cv.visitAttribute(attr);
140 }
141
142 @Override
143 public void visitInnerClass(final String name, final String outerName,
144 final String innerName, final int access) {
145 cp.newUTF8("InnerClasses");
146 if (name != null) {
147 cp.newClass(name);
148 }
149 if (outerName != null) {
150 cp.newClass(outerName);
151 }
152 if (innerName != null) {
153 cp.newUTF8(innerName);
154 }
155 cv.visitInnerClass(name, outerName, innerName, access);
156 }
157
158 @Override
159 public FieldVisitor visitField(final int access, final String name,
160 final String desc, final String signature, final Object value) {
161 if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
162 cp.newUTF8("Synthetic");
163 }
164 if ((access & Opcodes.ACC_DEPRECATED) != 0) {
165 cp.newUTF8("Deprecated");
166 }
167 cp.newUTF8(name);
168 cp.newUTF8(desc);
169 if (signature != null) {
170 cp.newUTF8("Signature");
171 cp.newUTF8(signature);
172 }
173 if (value != null) {
174 cp.newConst(value);
175 }
176 return new FieldConstantsCollector(cv.visitField(access, name, desc,
177 signature, value), cp);
178 }
179
180 @Override
181 public MethodVisitor visitMethod(final int access, final String name,
182 final String desc, final String signature, final String[] exceptions) {
183 if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
184 cp.newUTF8("Synthetic");
185 }
186 if ((access & Opcodes.ACC_DEPRECATED) != 0) {
187 cp.newUTF8("Deprecated");
188 }
189 cp.newUTF8(name);
190 cp.newUTF8(desc);
191 if (signature != null) {
192 cp.newUTF8("Signature");
193 cp.newUTF8(signature);
194 }
195 if (exceptions != null) {
196 cp.newUTF8("Exceptions");
197 for (int i = 0; i < exceptions.length; ++i) {
198 cp.newClass(exceptions[i]);
199 }
200 }
201 return new MethodConstantsCollector(cv.visitMethod(access, name, desc,
202 signature, exceptions), cp);
203 }
204 }
+0
-259
org/eclipse/persistence/internal/libraries/asm/optimizer/ClassOptimizer.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 package org.eclipse.persistence.internal.libraries.asm.optimizer;
30
31 import java.util.ArrayList;
32 import java.util.List;
33
34 import org.eclipse.persistence.internal.libraries.asm.AnnotationVisitor;
35 import org.eclipse.persistence.internal.libraries.asm.Attribute;
36 import org.eclipse.persistence.internal.libraries.asm.ClassVisitor;
37 import org.eclipse.persistence.internal.libraries.asm.FieldVisitor;
38 import org.eclipse.persistence.internal.libraries.asm.Label;
39 import org.eclipse.persistence.internal.libraries.asm.MethodVisitor;
40 import org.eclipse.persistence.internal.libraries.asm.Opcodes;
41 import org.eclipse.persistence.internal.libraries.asm.TypePath;
42 import org.eclipse.persistence.internal.libraries.asm.commons.Remapper;
43 import org.eclipse.persistence.internal.libraries.asm.commons.ClassRemapper;
44
45 /**
46 * A {@link ClassVisitor} that renames fields and methods, and removes debug
47 * info.
48 *
49 * @author Eric Bruneton
50 * @author Eugene Kuleshov
51 */
52 public class ClassOptimizer extends ClassRemapper {
53
54 private String pkgName;
55 String clsName;
56
57 boolean isInterface = false;
58 boolean hasClinitMethod = false;
59 List<String> syntheticClassFields = new ArrayList<String>();
60
61 public ClassOptimizer(final ClassVisitor cv, final Remapper remapper) {
62 super(Opcodes.ASM6, cv, remapper);
63 }
64
65 FieldVisitor syntheticFieldVisitor(final int access, final String name,
66 final String desc) {
67 return super.visitField(access, name, desc, null, null);
68 }
69
70 // ------------------------------------------------------------------------
71 // Overridden methods
72 // ------------------------------------------------------------------------
73
74 @Override
75 public void visit(final int version, final int access, final String name,
76 final String signature, final String superName,
77 final String[] interfaces) {
78 super.visit(Opcodes.V1_2, access, name, null, superName, interfaces);
79 int index = name.lastIndexOf('/');
80 if (index > 0) {
81 pkgName = name.substring(0, index);
82 } else {
83 pkgName = "";
84 }
85 clsName = name;
86 isInterface = (access & Opcodes.ACC_INTERFACE) != 0;
87 }
88
89 @Override
90 public void visitSource(final String source, final String debug) {
91 // remove debug info
92 }
93
94 @Override
95 public void visitOuterClass(final String owner, final String name,
96 final String desc) {
97 // remove debug info
98 }
99
100 @Override
101 public AnnotationVisitor visitAnnotation(final String desc,
102 final boolean visible) {
103 // remove annotations
104 return null;
105 }
106
107 @Override
108 public AnnotationVisitor visitTypeAnnotation(int typeRef,
109 TypePath typePath, String desc, boolean visible) {
110 // remove annotations
111 return null;
112 }
113
114 @Override
115 public void visitAttribute(final Attribute attr) {
116 // remove non standard attributes
117 }
118
119 @Override
120 public void visitInnerClass(final String name, final String outerName,
121 final String innerName, final int access) {
122 // remove debug info
123 }
124
125 @Override
126 public FieldVisitor visitField(final int access, final String name,
127 final String desc, final String signature, final Object value) {
128 String s = remapper.mapFieldName(className, name, desc);
129 if ("-".equals(s)) {
130 return null;
131 }
132 if ((access & (Opcodes.ACC_PUBLIC | Opcodes.ACC_PROTECTED)) == 0) {
133 if ((access & Opcodes.ACC_FINAL) != 0
134 && (access & Opcodes.ACC_STATIC) != 0 && desc.length() == 1) {
135 return null;
136 }
137 if ("org/objectweb/asm".equals(pkgName) && s.equals(name)) {
138 System.out.println("INFO: " + clsName + "." + s
139 + " could be renamed");
140 }
141 super.visitField(access, name, desc, null, value);
142 } else {
143 if (!s.equals(name)) {
144 throw new RuntimeException("The public or protected field "
145 + className + '.' + name + " must not be renamed.");
146 }
147 super.visitField(access, name, desc, null, value);
148 }
149 return null; // remove debug info
150 }
151
152 @Override
153 public MethodVisitor visitMethod(final int access, final String name,
154 final String desc, final String signature, final String[] exceptions) {
155 String s = remapper.mapMethodName(className, name, desc);
156 if ("-".equals(s)) {
157 return null;
158 }
159 if (name.equals("<clinit>") && !isInterface) {
160 hasClinitMethod = true;
161 MethodVisitor mv = super.visitMethod(access, name, desc, null,
162 exceptions);
163 return new MethodVisitor(Opcodes.ASM6, mv) {
164 @Override
165 public void visitCode() {
166 super.visitCode();
167 mv.visitMethodInsn(Opcodes.INVOKESTATIC, clsName,
168 "_clinit_", "()V", false);
169 }
170 };
171 }
172
173 if ((access & (Opcodes.ACC_PUBLIC | Opcodes.ACC_PROTECTED)) == 0) {
174 if ("org/objectweb/asm".equals(pkgName) && !name.startsWith("<")
175 && s.equals(name)) {
176 System.out.println("INFO: " + clsName + "." + s
177 + " could be renamed");
178 }
179 return super.visitMethod(access, name, desc, null, exceptions);
180 } else {
181 if (!s.equals(name)) {
182 throw new RuntimeException("The public or protected method "
183 + className + '.' + name + desc
184 + " must not be renamed.");
185 }
186 return super.visitMethod(access, name, desc, null, exceptions);
187 }
188 }
189
190 @Override
191 protected MethodVisitor createMethodRemapper(MethodVisitor mv) {
192 return new MethodOptimizer(this, mv, remapper);
193 }
194
195 @Override
196 public void visitEnd() {
197 if (syntheticClassFields.isEmpty()) {
198 if (hasClinitMethod) {
199 MethodVisitor mv = cv.visitMethod(Opcodes.ACC_STATIC
200 | Opcodes.ACC_SYNTHETIC, "_clinit_", "()V", null, null);
201 mv.visitCode();
202 mv.visitInsn(Opcodes.RETURN);
203 mv.visitMaxs(0, 0);
204 mv.visitEnd();
205 }
206 } else {
207 MethodVisitor mv = cv.visitMethod(Opcodes.ACC_STATIC
208 | Opcodes.ACC_SYNTHETIC, "class$",
209 "(Ljava/lang/String;)Ljava/lang/Class;", null, null);
210 mv.visitCode();
211 Label l0 = new Label();
212 Label l1 = new Label();
213 Label l2 = new Label();
214 mv.visitTryCatchBlock(l0, l1, l2,
215 "java/lang/ClassNotFoundException");
216 mv.visitLabel(l0);
217 mv.visitVarInsn(Opcodes.ALOAD, 0);
218 mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Class",
219 "forName", "(Ljava/lang/String;)Ljava/lang/Class;", false);
220 mv.visitLabel(l1);
221 mv.visitInsn(Opcodes.ARETURN);
222 mv.visitLabel(l2);
223 mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
224 "java/lang/ClassNotFoundException", "getMessage",
225 "()Ljava/lang/String;", false);
226 mv.visitVarInsn(Opcodes.ASTORE, 1);
227 mv.visitTypeInsn(Opcodes.NEW, "java/lang/NoClassDefFoundError");
228 mv.visitInsn(Opcodes.DUP);
229 mv.visitVarInsn(Opcodes.ALOAD, 1);
230 mv.visitMethodInsn(Opcodes.INVOKESPECIAL,
231 "java/lang/NoClassDefFoundError", "<init>",
232 "(Ljava/lang/String;)V", false);
233 mv.visitInsn(Opcodes.ATHROW);
234 mv.visitMaxs(3, 2);
235 mv.visitEnd();
236
237 if (hasClinitMethod) {
238 mv = cv.visitMethod(Opcodes.ACC_STATIC | Opcodes.ACC_PRIVATE,
239 "_clinit_", "()V", null, null);
240 } else {
241 mv = cv.visitMethod(Opcodes.ACC_STATIC, "<clinit>", "()V",
242 null, null);
243 }
244 for (String ldcName : syntheticClassFields) {
245 String fieldName = "class$" + ldcName.replace('/', '$');
246 mv.visitLdcInsn(ldcName.replace('/', '.'));
247 mv.visitMethodInsn(Opcodes.INVOKESTATIC, clsName, "class$",
248 "(Ljava/lang/String;)Ljava/lang/Class;", false);
249 mv.visitFieldInsn(Opcodes.PUTSTATIC, clsName, fieldName,
250 "Ljava/lang/Class;");
251 }
252 mv.visitInsn(Opcodes.RETURN);
253 mv.visitMaxs(1, 0);
254 mv.visitEnd();
255 }
256 super.visitEnd();
257 }
258 }
+0
-336
org/eclipse/persistence/internal/libraries/asm/optimizer/Constant.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 package org.eclipse.persistence.internal.libraries.asm.optimizer;
30
31 import java.util.Arrays;
32
33 import org.eclipse.persistence.internal.libraries.asm.ClassWriter;
34 import org.eclipse.persistence.internal.libraries.asm.Handle;
35
36 /**
37 * A constant pool item.
38 *
39 * @author Eric Bruneton
40 */
41 class Constant {
42
43 /**
44 * Type of this constant pool item. A single class is used to represent all
45 * constant pool item types, in order to minimize the bytecode size of this
46 * package. The value of this field is I, J, F, D, S, s, C, T, G, M, N, y,
47 * t, [h..r] (for Constant Integer, Long, Float, Double, STR, UTF8, Class,
48 * NameType, Fieldref, Methodref, InterfaceMethodref, InvokeDynamic,
49 * MethodType and MethodHandle constant pool items respectively).
50 *
51 * The 9 variable of MethodHandle constants are stored between h and r
52 * following this table
53 * tag type interface
54 * H_GETFIELD 1 h false
55 * H_GETSTATIC 2 i false
56 * H_PUTFIELD 3 j false
57 * H_PUTSTATIC 4 k false
58 * H_INVOKEVIRTUAL 5 l false
59 * H_INVOKESTATIC 6 m false
60 * H_INVOKESPECIAL 7 n false
61 * H_NEWINVOKESPECIAL 8 o false
62 * H_INVOKEINTERFACE 9 p true
63 * H_INVOKESTATIC 6 q true
64 * H_INVOKESPECIAL 7 r true
65 */
66 char type;
67
68 /**
69 * Value of this item, for an integer item.
70 */
71 int intVal;
72
73 /**
74 * Value of this item, for a long item.
75 */
76 long longVal;
77
78 /**
79 * Value of this item, for a float item.
80 */
81 float floatVal;
82
83 /**
84 * Value of this item, for a double item.
85 */
86 double doubleVal;
87
88 /**
89 * First part of the value of this item, for items that do not hold a
90 * primitive value.
91 */
92 String strVal1;
93
94 /**
95 * Second part of the value of this item, for items that do not hold a
96 * primitive value.
97 */
98 String strVal2;
99
100 /**
101 * Third part of the value of this item, for items that do not hold a
102 * primitive value.
103 */
104 Object objVal3;
105
106 /**
107 * InvokeDynamic's constant values.
108 */
109 Object[] objVals;
110
111 /**
112 * The hash code value of this constant pool item.
113 */
114 int hashCode;
115
116 Constant() {
117 }
118
119 Constant(final Constant i) {
120 type = i.type;
121 intVal = i.intVal;
122 longVal = i.longVal;
123 floatVal = i.floatVal;
124 doubleVal = i.doubleVal;
125 strVal1 = i.strVal1;
126 strVal2 = i.strVal2;
127 objVal3 = i.objVal3;
128 objVals = i.objVals;
129 hashCode = i.hashCode;
130 }
131
132 /**
133 * Sets this item to an integer item.
134 *
135 * @param intVal
136 * the value of this item.
137 */
138 void set(final int intVal) {
139 this.type = 'I';
140 this.intVal = intVal;
141 this.hashCode = 0x7FFFFFFF & (type + intVal);
142 }
143
144 /**
145 * Sets this item to a long item.
146 *
147 * @param longVal
148 * the value of this item.
149 */
150 void set(final long longVal) {
151 this.type = 'J';
152 this.longVal = longVal;
153 this.hashCode = 0x7FFFFFFF & (type + (int) longVal);
154 }
155
156 /**
157 * Sets this item to a float item.
158 *
159 * @param floatVal
160 * the value of this item.
161 */
162 void set(final float floatVal) {
163 this.type = 'F';
164 this.floatVal = floatVal;
165 this.hashCode = 0x7FFFFFFF & (type + (int) floatVal);
166 }
167
168 /**
169 * Sets this item to a double item.
170 *
171 * @param doubleVal
172 * the value of this item.
173 */
174 void set(final double doubleVal) {
175 this.type = 'D';
176 this.doubleVal = doubleVal;
177 this.hashCode = 0x7FFFFFFF & (type + (int) doubleVal);
178 }
179
180 /**
181 * Sets this item to an item that do not hold a primitive value.
182 *
183 * @param type
184 * the type of this item.
185 * @param strVal1
186 * first part of the value of this item.
187 * @param strVal2
188 * second part of the value of this item.
189 * @param strVal3
190 * third part of the value of this item.
191 */
192 void set(final char type, final String strVal1, final String strVal2,
193 final String strVal3) {
194 this.type = type;
195 this.strVal1 = strVal1;
196 this.strVal2 = strVal2;
197 this.objVal3 = strVal3;
198 switch (type) {
199 case 's':
200 case 'S':
201 case 'C':
202 case 't':
203 hashCode = 0x7FFFFFFF & (type + strVal1.hashCode());
204 return;
205 case 'T':
206 hashCode = 0x7FFFFFFF & (type + strVal1.hashCode()
207 * strVal2.hashCode());
208 return;
209 // case 'G':
210 // case 'M':
211 // case 'N':
212 // case 'h' ... 'r':
213 default:
214 hashCode = 0x7FFFFFFF & (type + strVal1.hashCode()
215 * strVal2.hashCode() * strVal3.hashCode());
216 }
217 }
218
219 /**
220 * Set this item to an InvokeDynamic item.
221 *
222 * @param name
223 * invokedynamic's name.
224 * @param desc
225 * invokedynamic's descriptor.
226 * @param bsm
227 * bootstrap method.
228 * @param bsmArgs
229 * bootstrap method constant arguments.
230 */
231 void set(final String name, final String desc, final Handle bsm,
232 final Object[] bsmArgs) {
233 this.type = 'y';
234 this.strVal1 = name;
235 this.strVal2 = desc;
236 this.objVal3 = bsm;
237 this.objVals = bsmArgs;
238
239 int hashCode = 'y' + name.hashCode() * desc.hashCode() * bsm.hashCode();
240 for (int i = 0; i < bsmArgs.length; i++) {
241 hashCode *= bsmArgs[i].hashCode();
242 }
243 this.hashCode = 0x7FFFFFFF & hashCode;
244 }
245
246 void write(final ClassWriter cw) {
247 switch (type) {
248 case 'I':
249 cw.newConst(intVal);
250 break;
251 case 'J':
252 cw.newConst(longVal);
253 break;
254 case 'F':
255 cw.newConst(floatVal);
256 break;
257 case 'D':
258 cw.newConst(doubleVal);
259 break;
260 case 'S':
261 cw.newConst(strVal1);
262 break;
263 case 's':
264 cw.newUTF8(strVal1);
265 break;
266 case 'C':
267 cw.newClass(strVal1);
268 break;
269 case 'T':
270 cw.newNameType(strVal1, strVal2);
271 break;
272 case 'G':
273 cw.newField(strVal1, strVal2, (String) objVal3);
274 break;
275 case 'M':
276 cw.newMethod(strVal1, strVal2, (String) objVal3, false);
277 break;
278 case 'N':
279 cw.newMethod(strVal1, strVal2, (String) objVal3, true);
280 break;
281 case 'y':
282 cw.newInvokeDynamic(strVal1, strVal2, (Handle) objVal3, objVals);
283 break;
284 case 't':
285 cw.newMethodType(strVal1);
286 break;
287 default: // 'h' ... 'r' : handle
288 cw.newHandle(type - 'h' + 1 - ((type >= 'q')? 4: 0), strVal1, strVal2, (String) objVal3, type >= 'p');
289 }
290 }
291
292 @Override
293 public boolean equals(final Object o) {
294 if (!(o instanceof Constant)) {
295 return false;
296 }
297 Constant c = (Constant) o;
298 if (c.type == type) {
299 switch (type) {
300 case 'I':
301 return c.intVal == intVal;
302 case 'J':
303 return c.longVal == longVal;
304 case 'F':
305 return Float.compare(c.floatVal, floatVal) == 0;
306 case 'D':
307 return Double.compare(c.doubleVal, doubleVal) == 0;
308 case 's':
309 case 'S':
310 case 'C':
311 case 't':
312 return c.strVal1.equals(strVal1);
313 case 'T':
314 return c.strVal1.equals(strVal1) && c.strVal2.equals(strVal2);
315 case 'y':
316 return c.strVal1.equals(strVal1) && c.strVal2.equals(strVal2)
317 && c.objVal3.equals(objVal3)
318 && Arrays.equals(c.objVals, objVals);
319 // case 'G':
320 // case 'M':
321 // case 'N':
322 // case 'h' ... 'r':
323 default:
324 return c.strVal1.equals(strVal1) && c.strVal2.equals(strVal2)
325 && c.objVal3.equals(objVal3);
326 }
327 }
328 return false;
329 }
330
331 @Override
332 public int hashCode() {
333 return hashCode;
334 }
335 }
+0
-251
org/eclipse/persistence/internal/libraries/asm/optimizer/ConstantPool.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 package org.eclipse.persistence.internal.libraries.asm.optimizer;
30
31 import java.util.HashMap;
32
33 import org.eclipse.persistence.internal.libraries.asm.Handle;
34 import org.eclipse.persistence.internal.libraries.asm.Opcodes;
35 import org.eclipse.persistence.internal.libraries.asm.Type;
36
37 /**
38 * A constant pool.
39 *
40 * @author Eric Bruneton
41 */
42 public class ConstantPool extends HashMap<Constant, Constant> {
43
44 private static final long serialVersionUID = 1L;
45
46 private final Constant key1 = new Constant();
47
48 private final Constant key2 = new Constant();
49
50 private final Constant key3 = new Constant();
51
52 private final Constant key4 = new Constant();
53
54 private final Constant key5 = new Constant();
55
56 public Constant newInteger(final int value) {
57 key1.set(value);
58 Constant result = get(key1);
59 if (result == null) {
60 result = new Constant(key1);
61 put(result);
62 }
63 return result;
64 }
65
66 public Constant newFloat(final float value) {
67 key1.set(value);
68 Constant result = get(key1);
69 if (result == null) {
70 result = new Constant(key1);
71 put(result);
72 }
73 return result;
74 }
75
76 public Constant newLong(final long value) {
77 key1.set(value);
78 Constant result = get(key1);
79 if (result == null) {
80 result = new Constant(key1);
81 put(result);
82 }
83 return result;
84 }
85
86 public Constant newDouble(final double value) {
87 key1.set(value);
88 Constant result = get(key1);
89 if (result == null) {
90 result = new Constant(key1);
91 put(result);
92 }
93 return result;
94 }
95
96 public Constant newUTF8(final String value) {
97 key1.set('s', value, null, null);
98 Constant result = get(key1);
99 if (result == null) {
100 result = new Constant(key1);
101 put(result);
102 }
103 return result;
104 }
105
106 private Constant newString(final String value) {
107 key2.set('S', value, null, null);
108 Constant result = get(key2);
109 if (result == null) {
110 newUTF8(value);
111 result = new Constant(key2);
112 put(result);
113 }
114 return result;
115 }
116
117 public Constant newClass(final String value) {
118 key2.set('C', value, null, null);
119 Constant result = get(key2);
120 if (result == null) {
121 newUTF8(value);
122 result = new Constant(key2);
123 put(result);
124 }
125 return result;
126 }
127
128 public Constant newMethodType(final String methodDescriptor) {
129 key2.set('t', methodDescriptor, null, null);
130 Constant result = get(key2);
131 if (result == null) {
132 newUTF8(methodDescriptor);
133 result = new Constant(key2);
134 put(result);
135 }
136 return result;
137 }
138
139 public Constant newHandle(final int tag, final String owner,
140 final String name, final String desc, final boolean itf) {
141 key4.set((char) ('h' + tag - 1 + (itf && tag != Opcodes.H_INVOKEINTERFACE? 4: 0)), owner, name, desc);
142 Constant result = get(key4);
143 if (result == null) {
144 if (tag <= Opcodes.H_PUTSTATIC) {
145 newField(owner, name, desc);
146 } else {
147 newMethod(owner, name, desc, itf);
148 }
149 result = new Constant(key4);
150 put(result);
151 }
152 return result;
153 }
154
155 public Constant newConst(final Object cst) {
156 if (cst instanceof Integer) {
157 int val = ((Integer) cst).intValue();
158 return newInteger(val);
159 } else if (cst instanceof Float) {
160 float val = ((Float) cst).floatValue();
161 return newFloat(val);
162 } else if (cst instanceof Long) {
163 long val = ((Long) cst).longValue();
164 return newLong(val);
165 } else if (cst instanceof Double) {
166 double val = ((Double) cst).doubleValue();
167 return newDouble(val);
168 } else if (cst instanceof String) {
169 return newString((String) cst);
170 } else if (cst instanceof Type) {
171 Type t = (Type) cst;
172 int s = t.getSort();
173 if (s == Type.OBJECT) {
174 return newClass(t.getInternalName());
175 } else if (s == Type.METHOD) {
176 return newMethodType(t.getDescriptor());
177 } else { // s == primitive type or array
178 return newClass(t.getDescriptor());
179 }
180 } else if (cst instanceof Handle) {
181 Handle h = (Handle) cst;
182 return newHandle(h.getTag(), h.getOwner(), h.getName(), h.getDesc(), h.isInterface());
183 } else {
184 throw new IllegalArgumentException("value " + cst);
185 }
186 }
187
188 public Constant newField(final String owner, final String name,
189 final String desc) {
190 key3.set('G', owner, name, desc);
191 Constant result = get(key3);
192 if (result == null) {
193 newClass(owner);
194 newNameType(name, desc);
195 result = new Constant(key3);
196 put(result);
197 }
198 return result;
199 }
200
201 public Constant newMethod(final String owner, final String name,
202 final String desc, final boolean itf) {
203 key3.set(itf ? 'N' : 'M', owner, name, desc);
204 Constant result = get(key3);
205 if (result == null) {
206 newClass(owner);
207 newNameType(name, desc);
208 result = new Constant(key3);
209 put(result);
210 }
211 return result;
212 }
213
214 public Constant newInvokeDynamic(String name, String desc, Handle bsm,
215 Object... bsmArgs) {
216 key5.set(name, desc, bsm, bsmArgs);
217 Constant result = get(key5);
218 if (result == null) {
219 newNameType(name, desc);
220 newHandle(bsm.getTag(), bsm.getOwner(), bsm.getName(),
221 bsm.getDesc(), bsm.isInterface());
222 for (int i = 0; i < bsmArgs.length; i++) {
223 newConst(bsmArgs[i]);
224 }
225 result = new Constant(key5);
226 put(result);
227 }
228 return result;
229 }
230
231 public Constant newNameType(final String name, final String desc) {
232 key2.set('T', name, desc, null);
233 Constant result = get(key2);
234 if (result == null) {
235 newUTF8(name);
236 newUTF8(desc);
237 result = new Constant(key2);
238 put(result);
239 }
240 return result;
241 }
242
243 private Constant get(final Constant key) {
244 return get((Object) key);
245 }
246
247 private void put(final Constant cst) {
248 put(cst, cst);
249 }
250 }
+0
-89
org/eclipse/persistence/internal/libraries/asm/optimizer/FieldConstantsCollector.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 package org.eclipse.persistence.internal.libraries.asm.optimizer;
30
31 import org.eclipse.persistence.internal.libraries.asm.AnnotationVisitor;
32 import org.eclipse.persistence.internal.libraries.asm.Attribute;
33 import org.eclipse.persistence.internal.libraries.asm.FieldVisitor;
34 import org.eclipse.persistence.internal.libraries.asm.Opcodes;
35 import org.eclipse.persistence.internal.libraries.asm.TypePath;
36
37 /**
38 * A {@link FieldVisitor} that collects the {@link Constant}s of the fields it
39 * visits.
40 *
41 * @author Eric Bruneton
42 */
43 public class FieldConstantsCollector extends FieldVisitor {
44
45 private final ConstantPool cp;
46
47 public FieldConstantsCollector(final FieldVisitor fv, final ConstantPool cp) {
48 super(Opcodes.ASM6, fv);
49 this.cp = cp;
50 }
51
52 @Override
53 public AnnotationVisitor visitAnnotation(final String desc,
54 final boolean visible) {
55 cp.newUTF8(desc);
56 if (visible) {
57 cp.newUTF8("RuntimeVisibleAnnotations");
58 } else {
59 cp.newUTF8("RuntimeInvisibleAnnotations");
60 }
61 return new AnnotationConstantsCollector(fv.visitAnnotation(desc,
62 visible), cp);
63 }
64
65 @Override
66 public AnnotationVisitor visitTypeAnnotation(int typeRef,
67 TypePath typePath, String desc, boolean visible) {
68 cp.newUTF8(desc);
69 if (visible) {
70 cp.newUTF8("RuntimeVisibleTypeAnnotations");
71 } else {
72 cp.newUTF8("RuntimeInvisibleTypeAnnotations");
73 }
74 return new AnnotationConstantsCollector(fv.visitAnnotation(desc,
75 visible), cp);
76 }
77
78 @Override
79 public void visitAttribute(final Attribute attr) {
80 // can do nothing
81 fv.visitAttribute(attr);
82 }
83
84 @Override
85 public void visitEnd() {
86 fv.visitEnd();
87 }
88 }
+0
-235
org/eclipse/persistence/internal/libraries/asm/optimizer/JarOptimizer.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 package org.eclipse.persistence.internal.libraries.asm.optimizer;
30
31 import java.io.BufferedReader;
32 import java.io.File;
33 import java.io.FileInputStream;
34 import java.io.FileOutputStream;
35 import java.io.IOException;
36 import java.io.InputStream;
37 import java.io.InputStreamReader;
38 import java.io.LineNumberReader;
39 import java.util.Enumeration;
40 import java.util.HashMap;
41 import java.util.HashSet;
42 import java.util.Map;
43 import java.util.Set;
44 import java.util.zip.GZIPInputStream;
45 import java.util.zip.ZipEntry;
46 import java.util.zip.ZipFile;
47 import java.util.zip.ZipOutputStream;
48
49 import org.eclipse.persistence.internal.libraries.asm.ClassReader;
50 import org.eclipse.persistence.internal.libraries.asm.ClassVisitor;
51 import org.eclipse.persistence.internal.libraries.asm.FieldVisitor;
52 import org.eclipse.persistence.internal.libraries.asm.MethodVisitor;
53 import org.eclipse.persistence.internal.libraries.asm.Opcodes;
54
55 /**
56 * A Jar file optimizer.
57 *
58 * @author Eric Bruneton
59 */
60 public class JarOptimizer {
61
62 static final Set<String> API = new HashSet<String>();
63 static final Map<String, String> HIERARCHY = new HashMap<String, String>();
64 static boolean nodebug = false;
65
66 public static void main(final String[] args) throws IOException {
67 File f = new File(args[0]);
68 InputStream is = new GZIPInputStream(new FileInputStream(f));
69 BufferedReader lnr = new LineNumberReader(new InputStreamReader(is));
70 while (true) {
71 String line = lnr.readLine();
72 if (line != null) {
73 if (line.startsWith("class")) {
74 String c = line.substring(6, line.lastIndexOf(' '));
75 String sc = line.substring(line.lastIndexOf(' ') + 1);
76 HIERARCHY.put(c, sc);
77 } else {
78 API.add(line);
79 }
80 } else {
81 break;
82 }
83 }
84
85 int argIndex = 1;
86 if (args[argIndex].equals("-nodebug")) {
87 nodebug = true;
88 argIndex++;
89 }
90
91 optimize(new File(args[argIndex]));
92 }
93
94 static void optimize(final File f) throws IOException {
95 if (nodebug && f.getName().contains("debug")) {
96 return;
97 }
98
99 if (f.isDirectory()) {
100 File[] files = f.listFiles();
101 for (int i = 0; i < files.length; ++i) {
102 optimize(files[i]);
103 }
104 } else if (f.getName().endsWith(".jar")) {
105 File g = new File(f.getParentFile(), f.getName() + ".new");
106 ZipFile zf = new ZipFile(f);
107 ZipOutputStream out = new ZipOutputStream(new FileOutputStream(g));
108 Enumeration<? extends ZipEntry> e = zf.entries();
109 byte[] buf = new byte[10000];
110 while (e.hasMoreElements()) {
111 ZipEntry ze = e.nextElement();
112 if (ze.isDirectory()) {
113 out.putNextEntry(ze);
114 continue;
115 }
116 out.putNextEntry(ze);
117 if (ze.getName().endsWith(".class")) {
118 ClassReader cr = new ClassReader(zf.getInputStream(ze));
119 // cr.accept(new ClassDump(), 0);
120 cr.accept(new ClassVerifier(), 0);
121 }
122 InputStream is = zf.getInputStream(ze);
123 int n;
124 do {
125 n = is.read(buf, 0, buf.length);
126 if (n != -1) {
127 out.write(buf, 0, n);
128 }
129 } while (n != -1);
130 out.closeEntry();
131 }
132 out.close();
133 zf.close();
134 if (!f.delete()) {
135 throw new IOException("Cannot delete file " + f);
136 }
137 if (!g.renameTo(f)) {
138 throw new IOException("Cannot rename file " + g);
139 }
140 }
141 }
142
143 static class ClassDump extends ClassVisitor {
144
145 String owner;
146
147 public ClassDump() {
148 super(Opcodes.ASM6);
149 }
150
151 @Override
152 public void visit(final int version, final int access,
153 final String name, final String signature,
154 final String superName, final String[] interfaces) {
155 owner = name;
156 if (owner.startsWith("java/")) {
157 System.out.println("class " + name + ' ' + superName);
158 }
159 }
160
161 @Override
162 public FieldVisitor visitField(final int access, final String name,
163 final String desc, final String signature, final Object value) {
164 if (owner.startsWith("java/")) {
165 System.out.println(owner + ' ' + name);
166 }
167 return null;
168 }
169
170 @Override
171 public MethodVisitor visitMethod(final int access, final String name,
172 final String desc, final String signature,
173 final String[] exceptions) {
174 if (owner.startsWith("java/")) {
175 System.out.println(owner + ' ' + name + desc);
176 }
177 return null;
178 }
179 }
180
181 static class ClassVerifier extends ClassVisitor {
182
183 String owner;
184
185 String method;
186
187 public ClassVerifier() {
188 super(Opcodes.ASM6);
189 }
190
191 @Override
192 public void visit(final int version, final int access,
193 final String name, final String signature,
194 final String superName, final String[] interfaces) {
195 owner = name;
196 }
197
198 @Override
199 public MethodVisitor visitMethod(final int access, final String name,
200 final String desc, final String signature,
201 final String[] exceptions) {
202 method = name + desc;
203 return new MethodVisitor(Opcodes.ASM6) {
204 @Override
205 public void visitFieldInsn(final int opcode,
206 final String owner, final String name, final String desc) {
207 check(owner, name);
208 }
209
210 @Override
211 public void visitMethodInsn(final int opcode,
212 final String owner, final String name,
213 final String desc, final boolean itf) {
214 check(owner, name + desc);
215 }
216 };
217 }
218
219 void check(String owner, String member) {
220 if (owner.startsWith("java/")) {
221 String o = owner;
222 while (o != null) {
223 if (API.contains(o + ' ' + member)) {
224 return;
225 }
226 o = HIERARCHY.get(o);
227 }
228 System.out.println("WARNING: " + owner + ' ' + member
229 + " called in " + this.owner + ' ' + method
230 + " is not defined in JDK 1.3 API");
231 }
232 }
233 }
234 }
+0
-224
org/eclipse/persistence/internal/libraries/asm/optimizer/MethodConstantsCollector.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 package org.eclipse.persistence.internal.libraries.asm.optimizer;
30
31 import org.eclipse.persistence.internal.libraries.asm.AnnotationVisitor;
32 import org.eclipse.persistence.internal.libraries.asm.Handle;
33 import org.eclipse.persistence.internal.libraries.asm.Label;
34 import org.eclipse.persistence.internal.libraries.asm.MethodVisitor;
35 import org.eclipse.persistence.internal.libraries.asm.Opcodes;
36 import org.eclipse.persistence.internal.libraries.asm.TypePath;
37
38 /**
39 * An {@link MethodVisitor} that collects the {@link Constant}s of the methods
40 * it visits.
41 *
42 * @author Eric Bruneton
43 */
44 public class MethodConstantsCollector extends MethodVisitor {
45
46 private final ConstantPool cp;
47
48 public MethodConstantsCollector(final MethodVisitor mv,
49 final ConstantPool cp) {
50 super(Opcodes.ASM6, mv);
51 this.cp = cp;
52 }
53
54 @Override
55 public void visitParameter(String name, int access) {
56 cp.newUTF8("MethodParameters");
57 if (name != null) {
58 cp.newUTF8(name);
59 }
60 mv.visitParameter(name, access);
61 }
62
63 @Override
64 public AnnotationVisitor visitAnnotationDefault() {
65 cp.newUTF8("AnnotationDefault");
66 return new AnnotationConstantsCollector(mv.visitAnnotationDefault(), cp);
67 }
68
69 @Override
70 public AnnotationVisitor visitAnnotation(final String desc,
71 final boolean visible) {
72 cp.newUTF8(desc);
73 if (visible) {
74 cp.newUTF8("RuntimeVisibleAnnotations");
75 } else {
76 cp.newUTF8("RuntimeInvisibleAnnotations");
77 }
78 return new AnnotationConstantsCollector(mv.visitAnnotation(desc,
79 visible), cp);
80 }
81
82 @Override
83 public AnnotationVisitor visitTypeAnnotation(int typeRef,
84 TypePath typePath, String desc, boolean visible) {
85 cp.newUTF8(desc);
86 if (visible) {
87 cp.newUTF8("RuntimeVisibleTypeAnnotations");
88 } else {
89 cp.newUTF8("RuntimeInvisibleTypeAnnotations");
90 }
91 return new AnnotationConstantsCollector(mv.visitAnnotation(desc,
92 visible), cp);
93 }
94
95 @Override
96 public AnnotationVisitor visitParameterAnnotation(final int parameter,
97 final String desc, final boolean visible) {
98 cp.newUTF8(desc);
99 if (visible) {
100 cp.newUTF8("RuntimeVisibleParameterAnnotations");
101 } else {
102 cp.newUTF8("RuntimeInvisibleParameterAnnotations");
103 }
104 return new AnnotationConstantsCollector(mv.visitParameterAnnotation(
105 parameter, desc, visible), cp);
106 }
107
108 @Override
109 public void visitTypeInsn(final int opcode, final String type) {
110 cp.newClass(type);
111 mv.visitTypeInsn(opcode, type);
112 }
113
114 @Override
115 public void visitFieldInsn(final int opcode, final String owner,
116 final String name, final String desc) {
117 cp.newField(owner, name, desc);
118 mv.visitFieldInsn(opcode, owner, name, desc);
119 }
120
121 @Override
122 public void visitMethodInsn(final int opcode, final String owner,
123 final String name, final String desc, final boolean itf) {
124 cp.newMethod(owner, name, desc, itf);
125 mv.visitMethodInsn(opcode, owner, name, desc, itf);
126 }
127
128 @Override
129 public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
130 Object... bsmArgs) {
131 cp.newInvokeDynamic(name, desc, bsm, bsmArgs);
132 mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
133 }
134
135 @Override
136 public void visitLdcInsn(final Object cst) {
137 cp.newConst(cst);
138 mv.visitLdcInsn(cst);
139 }
140
141 @Override
142 public void visitMultiANewArrayInsn(final String desc, final int dims) {
143 cp.newClass(desc);
144 mv.visitMultiANewArrayInsn(desc, dims);
145 }
146
147 @Override
148 public AnnotationVisitor visitInsnAnnotation(int typeRef,
149 TypePath typePath, String desc, boolean visible) {
150 cp.newUTF8(desc);
151 if (visible) {
152 cp.newUTF8("RuntimeVisibleTypeAnnotations");
153 } else {
154 cp.newUTF8("RuntimeInvisibleTypeAnnotations");
155 }
156 return new AnnotationConstantsCollector(mv.visitInsnAnnotation(typeRef,
157 typePath, desc, visible), cp);
158 }
159
160 @Override
161 public void visitTryCatchBlock(final Label start, final Label end,
162 final Label handler, final String type) {
163 if (type != null) {
164 cp.newClass(type);
165 }
166 mv.visitTryCatchBlock(start, end, handler, type);
167 }
168
169 @Override
170 public AnnotationVisitor visitTryCatchAnnotation(int typeRef,
171 TypePath typePath, String desc, boolean visible) {
172 cp.newUTF8(desc);
173 if (visible) {
174 cp.newUTF8("RuntimeVisibleTypeAnnotations");
175 } else {
176 cp.newUTF8("RuntimeInvisibleTypeAnnotations");
177 }
178 return new AnnotationConstantsCollector(mv.visitTryCatchAnnotation(
179 typeRef, typePath, desc, visible), cp);
180 }
181
182 @Override
183 public void visitLocalVariable(final String name, final String desc,
184 final String signature, final Label start, final Label end,
185 final int index) {
186 if (signature != null) {
187 cp.newUTF8("LocalVariableTypeTable");
188 cp.newUTF8(name);
189 cp.newUTF8(signature);
190 }
191 cp.newUTF8("LocalVariableTable");
192 cp.newUTF8(name);
193 cp.newUTF8(desc);
194 mv.visitLocalVariable(name, desc, signature, start, end, index);
195 }
196
197 @Override
198 public AnnotationVisitor visitLocalVariableAnnotation(int typeRef,
199 TypePath typePath, Label[] start, Label[] end, int[] index,
200 String desc, boolean visible) {
201 cp.newUTF8(desc);
202 if (visible) {
203 cp.newUTF8("RuntimeVisibleTypeAnnotations");
204 } else {
205 cp.newUTF8("RuntimeInvisibleTypeAnnotations");
206 }
207 return new AnnotationConstantsCollector(
208 mv.visitLocalVariableAnnotation(typeRef, typePath, start, end,
209 index, desc, visible), cp);
210 }
211
212 @Override
213 public void visitLineNumber(final int line, final Label start) {
214 cp.newUTF8("LineNumberTable");
215 mv.visitLineNumber(line, start);
216 }
217
218 @Override
219 public void visitMaxs(final int maxStack, final int maxLocals) {
220 cp.newUTF8("Code");
221 mv.visitMaxs(maxStack, maxLocals);
222 }
223 }
+0
-180
org/eclipse/persistence/internal/libraries/asm/optimizer/MethodOptimizer.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 package org.eclipse.persistence.internal.libraries.asm.optimizer;
30
31 import java.util.HashMap;
32
33 import org.eclipse.persistence.internal.libraries.asm.AnnotationVisitor;
34 import org.eclipse.persistence.internal.libraries.asm.Attribute;
35 import org.eclipse.persistence.internal.libraries.asm.FieldVisitor;
36 import org.eclipse.persistence.internal.libraries.asm.Label;
37 import org.eclipse.persistence.internal.libraries.asm.MethodVisitor;
38 import org.eclipse.persistence.internal.libraries.asm.Opcodes;
39 import org.eclipse.persistence.internal.libraries.asm.Type;
40 import org.eclipse.persistence.internal.libraries.asm.TypePath;
41 import org.eclipse.persistence.internal.libraries.asm.commons.Remapper;
42 import org.eclipse.persistence.internal.libraries.asm.commons.MethodRemapper;
43
44 /**
45 * A {@link MethodVisitor} that renames fields and methods, and removes debug
46 * info.
47 *
48 * @author Eugene Kuleshov
49 */
50 public class MethodOptimizer extends MethodRemapper implements Opcodes {
51
52 private final ClassOptimizer classOptimizer;
53
54 public MethodOptimizer(ClassOptimizer classOptimizer, MethodVisitor mv,
55 Remapper remapper) {
56 super(Opcodes.ASM6, mv, remapper);
57 this.classOptimizer = classOptimizer;
58 }
59
60 // ------------------------------------------------------------------------
61 // Overridden methods
62 // ------------------------------------------------------------------------
63
64 @Override
65 public void visitParameter(String name, int access) {
66 // remove parameter info
67 }
68
69 @Override
70 public AnnotationVisitor visitAnnotationDefault() {
71 // remove annotations
72 return null;
73 }
74
75 @Override
76 public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
77 // remove annotations
78 return null;
79 }
80
81 @Override
82 public AnnotationVisitor visitTypeAnnotation(int typeRef,
83 TypePath typePath, String desc, boolean visible) {
84 return null;
85 }
86
87 @Override
88 public AnnotationVisitor visitParameterAnnotation(final int parameter,
89 final String desc, final boolean visible) {
90 // remove annotations
91 return null;
92 }
93
94 @Override
95 public void visitLocalVariable(final String name, final String desc,
96 final String signature, final Label start, final Label end,
97 final int index) {
98 // remove debug info
99 }
100
101 @Override
102 public void visitLineNumber(final int line, final Label start) {
103 // remove debug info
104 }
105
106 @Override
107 public void visitFrame(int type, int local, Object[] local2, int stack,
108 Object[] stack2) {
109 // remove frame info
110 }
111
112 @Override
113 public void visitAttribute(Attribute attr) {
114 // remove non standard attributes
115 }
116
117 @Override
118 public void visitLdcInsn(Object cst) {
119 if (!(cst instanceof Type)) {
120 super.visitLdcInsn(cst);
121 return;
122 }
123
124 // transform Foo.class for 1.2 compatibility
125 String ldcName = ((Type) cst).getInternalName();
126 String fieldName = "class$" + ldcName.replace('/', '$');
127 if (!classOptimizer.syntheticClassFields.contains(ldcName)) {
128 classOptimizer.syntheticClassFields.add(ldcName);
129 FieldVisitor fv = classOptimizer.syntheticFieldVisitor(ACC_STATIC
130 | ACC_SYNTHETIC, fieldName, "Ljava/lang/Class;");
131 fv.visitEnd();
132 }
133
134 String clsName = classOptimizer.clsName;
135 mv.visitFieldInsn(GETSTATIC, clsName, fieldName, "Ljava/lang/Class;");
136 }
137
138 @Override
139 public void visitMethodInsn(int opcode, String owner, String name,
140 String desc, boolean itf) {
141 // rewrite boxing method call to use constructor to keep 1.3/1.4
142 // compatibility
143 String[] constructorParams;
144 if (opcode == INVOKESTATIC && name.equals("valueOf")
145 && (constructorParams = BOXING_MAP.get(owner + desc)) != null) {
146 String type = constructorParams[0];
147 String initDesc = constructorParams[1];
148 super.visitTypeInsn(NEW, type);
149 super.visitInsn(DUP);
150 super.visitInsn((initDesc == "(J)V" || initDesc == "(D)V") ? DUP2_X2
151 : DUP2_X1);
152 super.visitInsn(POP2);
153 super.visitMethodInsn(INVOKESPECIAL, type, "<init>", initDesc,
154 false);
155 return;
156 }
157 super.visitMethodInsn(opcode, owner, name, desc, itf);
158 }
159
160 private static final HashMap<String, String[]> BOXING_MAP;
161 static {
162 String[][] boxingNames = {
163 // Boolean.valueOf is 1.4 and is used by the xml package, so no
164 // rewrite
165 { "java/lang/Byte", "(B)V" }, { "java/lang/Short", "(S)V" },
166 { "java/lang/Character", "(C)V" },
167 { "java/lang/Integer", "(I)V" }, { "java/lang/Long", "(J)V" },
168 { "java/lang/Float", "(F)V" }, { "java/lang/Double", "(D)V" }, };
169 HashMap<String, String[]> map = new HashMap<String, String[]>();
170 for (String[] boxingName : boxingNames) {
171 String wrapper = boxingName[0];
172 String desc = boxingName[1];
173 String boxingMethod = wrapper + '(' + desc.charAt(1) + ")L"
174 + wrapper + ';';
175 map.put(boxingMethod, boxingName);
176 }
177 BOXING_MAP = map;
178 }
179 }
+0
-84
org/eclipse/persistence/internal/libraries/asm/optimizer/ModuleConstantsCollector.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 package org.eclipse.persistence.internal.libraries.asm.optimizer;
30
31 import org.eclipse.persistence.internal.libraries.asm.ModuleVisitor;
32 import org.eclipse.persistence.internal.libraries.asm.Opcodes;
33
34 /**
35 * A {@link ModuleVisitor} that collects the {@link Constant}s of the
36 * module declaration it visits.
37 *
38 * @author Remi Forax
39 */
40 public class ModuleConstantsCollector extends ModuleVisitor {
41
42 private final ConstantPool cp;
43
44 public ModuleConstantsCollector(final ModuleVisitor mv, final ConstantPool cp) {
45 super(Opcodes.ASM6, mv);
46 this.cp = cp;
47 }
48
49 @Override
50 public void visitRequire(String module, int access) {
51 cp.newUTF8(module);
52 mv.visitRequire(module, access);
53 }
54
55 @Override
56 public void visitExport(String packaze, String... modules) {
57 cp.newUTF8(packaze);
58 if (modules != null && modules.length > 0) {
59 for(String to: modules) {
60 cp.newUTF8(to);
61 }
62 }
63 mv.visitExport(packaze, modules);
64 }
65
66 @Override
67 public void visitUse(String service) {
68 cp.newClass(service);
69 mv.visitUse(service);
70 }
71
72 @Override
73 public void visitProvide(String service, String impl) {
74 cp.newClass(service);
75 cp.newClass(impl);
76 mv.visitProvide(service, impl);
77 }
78
79 @Override
80 public void visitEnd() {
81 mv.visitEnd();
82 }
83 }
+0
-114
org/eclipse/persistence/internal/libraries/asm/optimizer/NameMapping.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 package org.eclipse.persistence.internal.libraries.asm.optimizer;
30
31 import java.io.BufferedInputStream;
32 import java.io.FileInputStream;
33 import java.io.IOException;
34 import java.io.InputStream;
35 import java.util.HashSet;
36 import java.util.Properties;
37 import java.util.Set;
38
39 import org.eclipse.persistence.internal.libraries.asm.Type;
40
41 /**
42 * A MAPPING from names to names, used to rename classes, fields and methods.
43 *
44 * @author Eric Bruneton
45 */
46 public class NameMapping {
47
48 public final Properties mapping;
49
50 public final Set<Object> unused;
51
52 public NameMapping(final String file) throws IOException {
53 mapping = new Properties();
54 InputStream is = null;
55 try {
56 is = new BufferedInputStream(new FileInputStream(file));
57 mapping.load(is);
58 unused = new HashSet<Object>(mapping.keySet());
59 } finally {
60 if (is != null) {
61 is.close();
62 }
63 }
64 }
65
66 public String map(final String name) {
67 String s = (String) mapping.get(name);
68 if (s == null) {
69 int p = name.indexOf('.');
70 if (p == -1) {
71 s = name;
72 } else {
73 int q = name.indexOf('(');
74 if (q == -1) {
75 s = name.substring(p + 1);
76 } else {
77 s = name.substring(p + 1, q);
78 }
79 }
80 } else {
81 unused.remove(name);
82 }
83 return s;
84 }
85
86 public String fix(final String desc) {
87 if (desc.startsWith("(")) {
88 Type[] arguments = Type.getArgumentTypes(desc);
89 Type result = Type.getReturnType(desc);
90 for (int i = 0; i < arguments.length; ++i) {
91 arguments[i] = fix(arguments[i]);
92 }
93 result = fix(result);
94 return Type.getMethodDescriptor(result, arguments);
95 } else {
96 return fix(Type.getType(desc)).getDescriptor();
97 }
98 }
99
100 private Type fix(final Type t) {
101 if (t.getSort() == Type.OBJECT) {
102 return Type.getObjectType(map(t.getInternalName()));
103 } else if (t.getSort() == Type.ARRAY) {
104 String s = fix(t.getElementType()).getDescriptor();
105 for (int i = 0; i < t.getDimensions(); ++i) {
106 s = '[' + s;
107 }
108 return Type.getType(s);
109 } else {
110 return t;
111 }
112 }
113 }
+0
-282
org/eclipse/persistence/internal/libraries/asm/optimizer/Shrinker.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 package org.eclipse.persistence.internal.libraries.asm.optimizer;
30
31 import java.io.File;
32 import java.io.FileInputStream;
33 import java.io.FileOutputStream;
34 import java.io.IOException;
35 import java.io.OutputStream;
36 import java.util.Comparator;
37 import java.util.HashMap;
38 import java.util.HashSet;
39 import java.util.Iterator;
40 import java.util.Map;
41 import java.util.Properties;
42 import java.util.Set;
43 import java.util.TreeSet;
44
45 import org.eclipse.persistence.internal.libraries.asm.ClassReader;
46 import org.eclipse.persistence.internal.libraries.asm.ClassWriter;
47 import org.eclipse.persistence.internal.libraries.asm.Handle;
48 import org.eclipse.persistence.internal.libraries.asm.Type;
49 import org.eclipse.persistence.internal.libraries.asm.commons.Remapper;
50 import org.eclipse.persistence.internal.libraries.asm.commons.SimpleRemapper;
51
52 /**
53 * A class file shrinker utility.
54 *
55 * @author Eric Bruneton
56 * @author Eugene Kuleshov
57 */
58 public class Shrinker {
59
60 static final HashMap<String, String> MAPPING = new HashMap<String, String>();
61
62 public static void main(final String[] args) throws IOException {
63 Properties properties = new Properties();
64 int n = args.length - 1;
65 for (int i = 0; i < n - 1; ++i) {
66 properties.load(new FileInputStream(args[i]));
67 }
68
69 for (Map.Entry<Object, Object> entry : properties.entrySet()) {
70 MAPPING.put((String) entry.getKey(), (String) entry.getValue());
71 }
72
73 final Set<String> unused = new HashSet<String>(MAPPING.keySet());
74
75 File f = new File(args[n - 1]);
76 File d = new File(args[n]);
77
78 optimize(f, d, new SimpleRemapper(MAPPING) {
79 @Override
80 public String map(String key) {
81 String s = super.map(key);
82 if (s != null) {
83 unused.remove(key);
84 }
85 return s;
86 }
87 });
88
89 Iterator<String> i = unused.iterator();
90 while (i.hasNext()) {
91 String s = i.next();
92 if (!s.endsWith("/remove")) {
93 System.out.println("INFO: unused mapping " + s);
94 }
95 }
96 }
97
98 static void optimize(final File f, final File d, final Remapper remapper)
99 throws IOException {
100 if (f.isDirectory()) {
101 File[] files = f.listFiles();
102 for (int i = 0; i < files.length; ++i) {
103 optimize(files[i], d, remapper);
104 }
105 } else if (f.getName().endsWith(".class")) {
106 ConstantPool cp = new ConstantPool();
107 ClassReader cr = new ClassReader(new FileInputStream(f));
108 // auto-boxing removal requires to recompute the maxs
109 ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
110 ClassConstantsCollector ccc = new ClassConstantsCollector(cw, cp);
111 ClassOptimizer co = new ClassOptimizer(ccc, remapper);
112 cr.accept(co, ClassReader.SKIP_DEBUG);
113
114 Set<Constant> constants = new TreeSet<Constant>(
115 new ConstantComparator());
116 constants.addAll(cp.values());
117
118 cr = new ClassReader(cw.toByteArray());
119 cw = new ClassWriter(0);
120 Iterator<Constant> i = constants.iterator();
121 while (i.hasNext()) {
122 Constant c = i.next();
123 c.write(cw);
124 }
125 cr.accept(cw, ClassReader.SKIP_DEBUG);
126
127 if (MAPPING.get(cr.getClassName() + "/remove") != null) {
128 return;
129 }
130 String n = remapper.mapType(cr.getClassName());
131 File g = new File(d, n + ".class");
132 if (!g.exists() || g.lastModified() < f.lastModified()) {
133 if (!g.getParentFile().exists() && !g.getParentFile().mkdirs()) {
134 throw new IOException("Cannot create directory "
135 + g.getParentFile());
136 }
137 OutputStream os = new FileOutputStream(g);
138 try {
139 os.write(cw.toByteArray());
140 } finally {
141 os.close();
142 }
143 }
144 }
145 }
146
147 static class ConstantComparator implements Comparator<Constant> {
148
149 public int compare(final Constant c1, final Constant c2) {
150 int d = getSort(c1) - getSort(c2);
151 if (d == 0) {
152 switch (c1.type) {
153 case 'I':
154 return ((Integer)c1.intVal).compareTo(c2.intVal);
155 case 'J':
156 return ((Long)c1.longVal).compareTo(c2.longVal);
157 case 'F':
158 return ((Float)c1.floatVal).compareTo(c2.floatVal);
159 case 'D':
160 return ((Double)c1.doubleVal).compareTo(c2.doubleVal);
161 case 's':
162 case 'S':
163 case 'C':
164 case 't':
165 return c1.strVal1.compareTo(c2.strVal1);
166 case 'T':
167 d = c1.strVal1.compareTo(c2.strVal1);
168 if (d == 0) {
169 d = c1.strVal2.compareTo(c2.strVal2);
170 }
171 break;
172 case 'y':
173 d = c1.strVal1.compareTo(c2.strVal1);
174 if (d == 0) {
175 d = c1.strVal2.compareTo(c2.strVal2);
176 if (d == 0) {
177 Handle bsm1 = (Handle) c1.objVal3;
178 Handle bsm2 = (Handle) c2.objVal3;
179 d = compareHandle(bsm1, bsm2);
180 if (d == 0) {
181 d = compareObjects(c1.objVals, c2.objVals);
182 }
183 }
184 }
185 break;
186
187 default:
188 d = c1.strVal1.compareTo(c2.strVal1);
189 if (d == 0) {
190 d = c1.strVal2.compareTo(c2.strVal2);
191 if (d == 0) {
192 d = ((String) c1.objVal3)
193 .compareTo((String) c2.objVal3);
194 }
195 }
196 }
197 }
198 return d;
199 }
200
201 private static int compareHandle(Handle h1, Handle h2) {
202 int d = h1.getTag() - h2.getTag();
203 if (d == 0) {
204 d = h1.getOwner().compareTo(h2.getOwner());
205 if (d == 0) {
206 d = h1.getName().compareTo(h2.getName());
207 if (d == 0) {
208 d = h1.getDesc().compareTo(h2.getDesc());
209 }
210 }
211 }
212 return d;
213 }
214
215 private static int compareType(Type mtype1, Type mtype2) {
216 return mtype1.getDescriptor().compareTo(mtype2.getDescriptor());
217 }
218
219 @SuppressWarnings("unchecked")
220 private static int compareObjects(Object[] objVals1, Object[] objVals2) {
221 int length = objVals1.length;
222 int d = length - objVals2.length;
223 if (d == 0) {
224 for (int i = 0; i < length; i++) {
225 Object objVal1 = objVals1[i];
226 Object objVal2 = objVals2[i];
227 d = objVal1.getClass().getName()
228 .compareTo(objVal2.getClass().getName());
229 if (d == 0) {
230 if (objVal1 instanceof Type) {
231 d = compareType((Type) objVal1, (Type) objVal2);
232 } else if (objVal1 instanceof Handle) {
233 d = compareHandle((Handle) objVal1,
234 (Handle) objVal2);
235 } else {
236 d = ((Comparable<Object>) objVal1).compareTo(objVal2);
237 }
238 }
239
240 if (d != 0) {
241 return d;
242 }
243 }
244 }
245 return 0;
246 }
247
248 private static int getSort(final Constant c) {
249 switch (c.type) {
250 case 'I':
251 return 0;
252 case 'J':
253 return 1;
254 case 'F':
255 return 2;
256 case 'D':
257 return 3;
258 case 's':
259 return 4;
260 case 'S':
261 return 5;
262 case 'C':
263 return 6;
264 case 'T':
265 return 7;
266 case 'G':
267 return 8;
268 case 'M':
269 return 9;
270 case 'N':
271 return 10;
272 case 'y':
273 return 11;
274 case 't':
275 return 12;
276 default:
277 return 100 + c.type - 'h';
278 }
279 }
280 }
281 }
+0
-87
org/eclipse/persistence/internal/libraries/asm/package.html less more
0 <html>
1 <!--
2 * ASM: a very small and fast Java bytecode manipulation framework
3 * Copyright (c) 2000-2011 INRIA, France Telecom
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the copyright holders nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
28 * THE POSSIBILITY OF SUCH DAMAGE.
29 -->
30 <body>
31 Provides a small and fast bytecode manipulation framework.
32
33 <p>
34 The <a href="http://www.objectweb.org/asm">ASM</a> framework is organized
35 around the {@link org.objectweb.asm.ClassVisitor ClassVisitor},
36 {@link org.objectweb.asm.FieldVisitor FieldVisitor},
37 {@link org.objectweb.asm.MethodVisitor MethodVisitor} and
38 {@link org.objectweb.asm.AnnotationVisitor AnnotationVisitor} abstract classes,
39 which allow one to visit the fields, methods and annotations of a class,
40 including the bytecode instructions of each method.
41
42 <p>
43 In addition to these main abstract classes, ASM provides a {@link
44 org.objectweb.asm.ClassReader ClassReader} class, that can parse an
45 existing class and make a given visitor visit it. ASM also provides
46 a {@link org.objectweb.asm.ClassWriter ClassWriter} class, which is
47 a visitor that generates Java class files.
48
49 <p>
50 In order to generate a class from scratch, only the {@link
51 org.objectweb.asm.ClassWriter ClassWriter} class is necessary. Indeed,
52 in order to generate a class, one must just call its visit<i>Xxx</i>
53 methods with the appropriate arguments to generate the desired fields
54 and methods. See the "helloworld" example in the ASM distribution for
55 more details about class generation.
56
57 <p>
58 In order to modify existing classes, one must use a {@link
59 org.objectweb.asm.ClassReader ClassReader} class to analyze
60 the original class, a class modifier, and a {@link org.objectweb.asm.ClassWriter
61 ClassWriter} to construct the modified class. The class modifier
62 is just a {@link org.objectweb.asm.ClassVisitor ClassVisitor}
63 that delegates most of the work to another {@link org.objectweb.asm.ClassVisitor
64 ClassVisitor}, but that sometimes changes some parameter values,
65 or call additional methods, in order to implement the desired
66 modification process. In order to make it easier to implement such
67 class modifiers, the {@link org.objectweb.asm.ClassVisitor
68 ClassVisitor} and {@link org.objectweb.asm.MethodVisitor MethodVisitor}
69 classes delegate by default all the method calls they receive to an
70 optional visitor. See the "adapt" example in the ASM
71 distribution for more details about class modification.
72
73 <p>
74 The size of the core ASM library, <tt>asm.jar</tt>, is only 45KB, which is much
75 smaller than the size of the
76 <a href="http://jakarta.apache.org/bcel">BCEL</a> library (504KB), and than the
77 size of the
78 <a href="http://serp.sourceforge.net">SERP</a> library (150KB). ASM is also
79 much faster than these tools. Indeed the overhead of a load time class
80 transformation process is of the order of 60% with ASM, 700% or more with BCEL,
81 and 1100% or more with SERP (see the <tt>test/perf</tt> directory in the ASM
82 distribution)!
83
84 @since ASM 1.3
85 </body>
86 </html>
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
27 package org.eclipse.persistence.internal.libraries.asm.signature;
28
29 /**
30 * A parser for signature literals, as defined in the Java Virtual Machine Specification (JVMS), to
31 * visit them with a SignatureVisitor.
432 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 package org.eclipse.persistence.internal.libraries.asm.signature;
30
31 /**
32 * A type signature parser to make a signature visitor visit an existing
33 * signature.
34 *
33 * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.9.1">JVMS
34 * 4.7.9.1</a>
3535 * @author Thomas Hallgren
3636 * @author Eric Bruneton
3737 */
3838 public class SignatureReader {
3939
40 /**
41 * The signature to be read.
42 */
43 private final String signature;
44
45 /**
46 * Constructs a {@link SignatureReader} for the given signature.
47 *
48 * @param signature
49 * A <i>ClassSignature</i>, <i>MethodTypeSignature</i>, or
50 * <i>FieldTypeSignature</i>.
51 */
52 public SignatureReader(final String signature) {
53 this.signature = signature;
40 /** The JVMS signature to be read. */
41 private final String signatureValue;
42
43 /**
44 * Constructs a {@link SignatureReader} for the given signature.
45 *
46 * @param signature A <i>JavaTypeSignature</i>, <i>ClassSignature</i> or <i>MethodSignature</i>.
47 */
48 public SignatureReader(final String signature) {
49 this.signatureValue = signature;
50 }
51
52 /**
53 * Makes the given visitor visit the signature of this {@link SignatureReader}. This signature is
54 * the one specified in the constructor (see {@link #SignatureReader}). This method is intended to
55 * be called on a {@link SignatureReader} that was created using a <i>ClassSignature</i> (such as
56 * the <code>signature</code> parameter of the {@link org.eclipse.persistence.internal.libraries.asm.ClassVisitor#visit}
57 * method) or a <i>MethodSignature</i> (such as the <code>signature</code> parameter of the {@link
58 * org.eclipse.persistence.internal.libraries.asm.ClassVisitor#visitMethod} method).
59 *
60 * @param signatureVistor the visitor that must visit this signature.
61 */
62 public void accept(final SignatureVisitor signatureVistor) {
63 String signature = this.signatureValue;
64 int length = signature.length();
65 int offset; // Current offset in the parsed signature (parsed from left to right).
66 char currentChar; // The signature character at 'offset', or just before.
67
68 // If the signature starts with '<', it starts with TypeParameters, i.e. a formal type parameter
69 // identifier, followed by one or more pair ':',ReferenceTypeSignature (for its class bound and
70 // interface bounds).
71 if (signature.charAt(0) == '<') {
72 // Invariant: offset points to the second character of a formal type parameter name at the
73 // beginning of each iteration of the loop below.
74 offset = 2;
75 do {
76 // The formal type parameter name is everything between offset - 1 and the first ':'.
77 int classBoundStartOffset = signature.indexOf(':', offset);
78 signatureVistor.visitFormalTypeParameter(
79 signature.substring(offset - 1, classBoundStartOffset));
80
81 // If the character after the ':' class bound marker is not the start of a
82 // ReferenceTypeSignature, it means the class bound is empty (which is a valid case).
83 offset = classBoundStartOffset + 1;
84 currentChar = signature.charAt(offset);
85 if (currentChar == 'L' || currentChar == '[' || currentChar == 'T') {
86 offset = parseType(signature, offset, signatureVistor.visitClassBound());
87 }
88
89 // While the character after the class bound or after the last parsed interface bound
90 // is ':', we need to parse another interface bound.
91 while ((currentChar = signature.charAt(offset++)) == ':') {
92 offset = parseType(signature, offset, signatureVistor.visitInterfaceBound());
93 }
94
95 // At this point a TypeParameter has been fully parsed, and we need to parse the next one
96 // (note that currentChar is now the first character of the next TypeParameter, and that
97 // offset points to the second character), unless the character just after this
98 // TypeParameter signals the end of the TypeParameters.
99 } while (currentChar != '>');
100 } else {
101 offset = 0;
54102 }
55103
56 /**
57 * Makes the given visitor visit the signature of this
58 * {@link SignatureReader}. This signature is the one specified in the
59 * constructor (see {@link #SignatureReader(String) SignatureReader}). This
60 * method is intended to be called on a {@link SignatureReader} that was
61 * created using a <i>ClassSignature</i> (such as the <code>signature</code>
62 * parameter of the {@link org.eclipse.persistence.internal.libraries.asm.ClassVisitor#visit
63 * ClassVisitor.visit} method) or a <i>MethodTypeSignature</i> (such as the
64 * <code>signature</code> parameter of the
65 * {@link org.eclipse.persistence.internal.libraries.asm.ClassVisitor#visitMethod
66 * ClassVisitor.visitMethod} method).
67 *
68 * @param v
69 * the visitor that must visit this signature.
70 */
71 public void accept(final SignatureVisitor v) {
72 String signature = this.signature;
73 int len = signature.length();
74 int pos;
75 char c;
76
77 if (signature.charAt(0) == '<') {
78 pos = 2;
79 do {
80 int end = signature.indexOf(':', pos);
81 v.visitFormalTypeParameter(signature.substring(pos - 1, end));
82 pos = end + 1;
83
84 c = signature.charAt(pos);
85 if (c == 'L' || c == '[' || c == 'T') {
86 pos = parseType(signature, pos, v.visitClassBound());
87 }
88
89 while ((c = signature.charAt(pos++)) == ':') {
90 pos = parseType(signature, pos, v.visitInterfaceBound());
91 }
92 } while (c != '>');
93 } else {
94 pos = 0;
104 // If the (optional) TypeParameters is followed by '(' this means we are parsing a
105 // MethodSignature, which has JavaTypeSignature type inside parentheses, followed by a Result
106 // type and optional ThrowsSignature types.
107 if (signature.charAt(offset) == '(') {
108 offset++;
109 while (signature.charAt(offset) != ')') {
110 offset = parseType(signature, offset, signatureVistor.visitParameterType());
111 }
112 // Use offset + 1 to skip ')'.
113 offset = parseType(signature, offset + 1, signatureVistor.visitReturnType());
114 while (offset < length) {
115 // Use offset + 1 to skip the first character of a ThrowsSignature, i.e. '^'.
116 offset = parseType(signature, offset + 1, signatureVistor.visitExceptionType());
117 }
118 } else {
119 // Otherwise we are parsing a ClassSignature (by hypothesis on the method input), which has
120 // one or more ClassTypeSignature for the super class and the implemented interfaces.
121 offset = parseType(signature, offset, signatureVistor.visitSuperclass());
122 while (offset < length) {
123 offset = parseType(signature, offset, signatureVistor.visitInterface());
124 }
125 }
126 }
127
128 /**
129 * Makes the given visitor visit the signature of this {@link SignatureReader}. This signature is
130 * the one specified in the constructor (see {@link #SignatureReader}). This method is intended to
131 * be called on a {@link SignatureReader} that was created using a <i>JavaTypeSignature</i>, such
132 * as the <code>signature</code> parameter of the {@link
133 * org.eclipse.persistence.internal.libraries.asm.ClassVisitor#visitField} or {@link
134 * org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitLocalVariable} methods.
135 *
136 * @param signatureVisitor the visitor that must visit this signature.
137 */
138 public void acceptType(final SignatureVisitor signatureVisitor) {
139 parseType(signatureValue, 0, signatureVisitor);
140 }
141
142 /**
143 * Parses a JavaTypeSignature and makes the given visitor visit it.
144 *
145 * @param signature a string containing the signature that must be parsed.
146 * @param startOffset index of the first character of the signature to parsed.
147 * @param signatureVisitor the visitor that must visit this signature.
148 * @return the index of the first character after the parsed signature.
149 */
150 private static int parseType(
151 final String signature, final int startOffset, final SignatureVisitor signatureVisitor) {
152 int offset = startOffset; // Current offset in the parsed signature.
153 char currentChar = signature.charAt(offset++); // The signature character at 'offset'.
154
155 // Switch based on the first character of the JavaTypeSignature, which indicates its kind.
156 switch (currentChar) {
157 case 'Z':
158 case 'C':
159 case 'B':
160 case 'S':
161 case 'I':
162 case 'F':
163 case 'J':
164 case 'D':
165 case 'V':
166 // Case of a BaseType or a VoidDescriptor.
167 signatureVisitor.visitBaseType(currentChar);
168 return offset;
169
170 case '[':
171 // Case of an ArrayTypeSignature, a '[' followed by a JavaTypeSignature.
172 return parseType(signature, offset, signatureVisitor.visitArrayType());
173
174 case 'T':
175 // Case of TypeVariableSignature, an identifier between 'T' and ';'.
176 int endOffset = signature.indexOf(';', offset);
177 signatureVisitor.visitTypeVariable(signature.substring(offset, endOffset));
178 return endOffset + 1;
179
180 case 'L':
181 // Case of a ClassTypeSignature, which ends with ';'.
182 // These signatures have a main class type followed by zero or more inner class types
183 // (separated by '.'). Each can have type arguments, inside '<' and '>'.
184 int start = offset; // The start offset of the currently parsed main or inner class name.
185 boolean visited = false; // Whether the currently parsed class name has been visited.
186 boolean inner = false; // Whether we are currently parsing an inner class type.
187 // Parses the signature, one character at a time.
188 while (true) {
189 currentChar = signature.charAt(offset++);
190 if (currentChar == '.' || currentChar == ';') {
191 // If a '.' or ';' is encountered, this means we have fully parsed the main class name
192 // or an inner class name. This name may already have been visited it is was followed by
193 // type arguments between '<' and '>'. If not, we need to visit it here.
194 if (!visited) {
195 String name = signature.substring(start, offset - 1);
196 if (inner) {
197 signatureVisitor.visitInnerClassType(name);
198 } else {
199 signatureVisitor.visitClassType(name);
200 }
201 }
202 // If we reached the end of the ClassTypeSignature return, otherwise start the parsing
203 // of a new class name, which is necessarily an inner class name.
204 if (currentChar == ';') {
205 signatureVisitor.visitEnd();
206 break;
207 }
208 start = offset;
209 visited = false;
210 inner = true;
211 } else if (currentChar == '<') {
212 // If a '<' is encountered, this means we have fully parsed the main class name or an
213 // inner class name, and that we now need to parse TypeArguments. First, we need to
214 // visit the parsed class name.
215 String name = signature.substring(start, offset - 1);
216 if (inner) {
217 signatureVisitor.visitInnerClassType(name);
218 } else {
219 signatureVisitor.visitClassType(name);
220 }
221 visited = true;
222 // Now, parse the TypeArgument(s), one at a time.
223 while ((currentChar = signature.charAt(offset)) != '>') {
224 switch (currentChar) {
225 case '*':
226 // Unbounded TypeArgument.
227 ++offset;
228 signatureVisitor.visitTypeArgument();
229 break;
230 case '+':
231 case '-':
232 // Extends or Super TypeArgument. Use offset + 1 to skip the '+' or '-'.
233 offset =
234 parseType(
235 signature, offset + 1, signatureVisitor.visitTypeArgument(currentChar));
236 break;
237 default:
238 // Instanceof TypeArgument. The '=' is implicit.
239 offset = parseType(signature, offset, signatureVisitor.visitTypeArgument('='));
240 break;
241 }
242 }
243 }
95244 }
96
97 if (signature.charAt(pos) == '(') {
98 pos++;
99 while (signature.charAt(pos) != ')') {
100 pos = parseType(signature, pos, v.visitParameterType());
101 }
102 pos = parseType(signature, pos + 1, v.visitReturnType());
103 while (pos < len) {
104 pos = parseType(signature, pos + 1, v.visitExceptionType());
105 }
106 } else {
107 pos = parseType(signature, pos, v.visitSuperclass());
108 while (pos < len) {
109 pos = parseType(signature, pos, v.visitInterface());
110 }
111 }
245 return offset;
246
247 default:
248 throw new IllegalArgumentException();
112249 }
113
114 /**
115 * Makes the given visitor visit the signature of this
116 * {@link SignatureReader}. This signature is the one specified in the
117 * constructor (see {@link #SignatureReader(String) SignatureReader}). This
118 * method is intended to be called on a {@link SignatureReader} that was
119 * created using a <i>FieldTypeSignature</i>, such as the
120 * <code>signature</code> parameter of the
121 * {@link org.eclipse.persistence.internal.libraries.asm.ClassVisitor#visitField ClassVisitor.visitField}
122 * or {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitLocalVariable
123 * MethodVisitor.visitLocalVariable} methods.
124 *
125 * @param v
126 * the visitor that must visit this signature.
127 */
128 public void acceptType(final SignatureVisitor v) {
129 parseType(this.signature, 0, v);
130 }
131
132 /**
133 * Parses a field type signature and makes the given visitor visit it.
134 *
135 * @param signature
136 * a string containing the signature that must be parsed.
137 * @param pos
138 * index of the first character of the signature to parsed.
139 * @param v
140 * the visitor that must visit this signature.
141 * @return the index of the first character after the parsed signature.
142 */
143 private static int parseType(final String signature, int pos,
144 final SignatureVisitor v) {
145 char c;
146 int start, end;
147 boolean visited, inner;
148 String name;
149
150 switch (c = signature.charAt(pos++)) {
151 case 'Z':
152 case 'C':
153 case 'B':
154 case 'S':
155 case 'I':
156 case 'F':
157 case 'J':
158 case 'D':
159 case 'V':
160 v.visitBaseType(c);
161 return pos;
162
163 case '[':
164 return parseType(signature, pos, v.visitArrayType());
165
166 case 'T':
167 end = signature.indexOf(';', pos);
168 v.visitTypeVariable(signature.substring(pos, end));
169 return end + 1;
170
171 default: // case 'L':
172 start = pos;
173 visited = false;
174 inner = false;
175 for (;;) {
176 switch (c = signature.charAt(pos++)) {
177 case '.':
178 case ';':
179 if (!visited) {
180 name = signature.substring(start, pos - 1);
181 if (inner) {
182 v.visitInnerClassType(name);
183 } else {
184 v.visitClassType(name);
185 }
186 }
187 if (c == ';') {
188 v.visitEnd();
189 return pos;
190 }
191 start = pos;
192 visited = false;
193 inner = true;
194 break;
195
196 case '<':
197 name = signature.substring(start, pos - 1);
198 if (inner) {
199 v.visitInnerClassType(name);
200 } else {
201 v.visitClassType(name);
202 }
203 visited = true;
204 top: for (;;) {
205 switch (c = signature.charAt(pos)) {
206 case '>':
207 break top;
208 case '*':
209 ++pos;
210 v.visitTypeArgument();
211 break;
212 case '+':
213 case '-':
214 pos = parseType(signature, pos + 1,
215 v.visitTypeArgument(c));
216 break;
217 default:
218 pos = parseType(signature, pos,
219 v.visitTypeArgument('='));
220 break;
221 }
222 }
223 }
224 }
225 }
226 }
250 }
227251 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
27 package org.eclipse.persistence.internal.libraries.asm.signature;
28
29 import org.eclipse.persistence.internal.libraries.asm.Opcodes;
30
31 /**
32 * A visitor to visit a generic signature. The methods of this interface must be called in one of
33 * the three following orders (the last one is the only valid order for a {@link SignatureVisitor}
34 * that is returned by a method of this interface):
435 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
36 * <ul>
37 * <li><i>ClassSignature</i> = ( <tt>visitFormalTypeParameter</tt> <tt>visitClassBound</tt>?
38 * <tt>visitInterfaceBound</tt>* )* ( <tt>visitSuperclass</tt> <tt>visitInterface</tt>* )
39 * <li><i>MethodSignature</i> = ( <tt>visitFormalTypeParameter</tt> <tt>visitClassBound</tt>?
40 * <tt>visitInterfaceBound</tt>* )* ( <tt>visitParameterType</tt>* <tt>visitReturnType</tt>
41 * <tt>visitExceptionType</tt>* )
42 * <li><i>TypeSignature</i> = <tt>visitBaseType</tt> | <tt>visitTypeVariable</tt> |
43 * <tt>visitArrayType</tt> | ( <tt>visitClassType</tt> <tt>visitTypeArgument</tt>* (
44 * <tt>visitInnerClassType</tt> <tt>visitTypeArgument</tt>* )* <tt>visitEnd</tt> ) )
45 * </ul>
1646 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 package org.eclipse.persistence.internal.libraries.asm.signature;
30
31 import org.eclipse.persistence.internal.libraries.asm.Opcodes;
32
33 /**
34 * A visitor to visit a generic signature. The methods of this interface must be
35 * called in one of the three following orders (the last one is the only valid
36 * order for a {@link SignatureVisitor} that is returned by a method of this
37 * interface):
38 * <ul>
39 * <li><i>ClassSignature</i> = ( <tt>visitFormalTypeParameter</tt>
40 * <tt>visitClassBound</tt>? <tt>visitInterfaceBound</tt>* )* (
41 * <tt>visitSuperclass</tt> <tt>visitInterface</tt>* )</li>
42 * <li><i>MethodSignature</i> = ( <tt>visitFormalTypeParameter</tt>
43 * <tt>visitClassBound</tt>? <tt>visitInterfaceBound</tt>* )* (
44 * <tt>visitParameterType</tt>* <tt>visitReturnType</tt>
45 * <tt>visitExceptionType</tt>* )</li>
46 * <li><i>TypeSignature</i> = <tt>visitBaseType</tt> |
47 * <tt>visitTypeVariable</tt> | <tt>visitArrayType</tt> | (
48 * <tt>visitClassType</tt> <tt>visitTypeArgument</tt>* (
49 * <tt>visitInnerClassType</tt> <tt>visitTypeArgument</tt>* )* <tt>visitEnd</tt>
50 * ) )</li>
51 * </ul>
52 *
5347 * @author Thomas Hallgren
5448 * @author Eric Bruneton
5549 */
5650 public abstract class SignatureVisitor {
5751
58 /**
59 * Wildcard for an "extends" type argument.
60 */
61 public final static char EXTENDS = '+';
62
63 /**
64 * Wildcard for a "super" type argument.
65 */
66 public final static char SUPER = '-';
67
68 /**
69 * Wildcard for a normal type argument.
70 */
71 public final static char INSTANCEOF = '=';
72
73 /**
74 * The ASM API version implemented by this visitor. The value of this field
75 * must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
76 */
77 protected final int api;
78
79 /**
80 * Constructs a new {@link SignatureVisitor}.
81 *
82 * @param api
83 * the ASM API version implemented by this visitor. Must be one
84 * of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
85 */
86 public SignatureVisitor(final int api) {
87 if (api < Opcodes.ASM4 || api > Opcodes.ASM6) {
88 throw new IllegalArgumentException();
89 }
90 this.api = api;
52 /** Wildcard for an "extends" type argument. */
53 public static final char EXTENDS = '+';
54
55 /** Wildcard for a "super" type argument. */
56 public static final char SUPER = '-';
57
58 /** Wildcard for a normal type argument. */
59 public static final char INSTANCEOF = '=';
60
61 /**
62 * The ASM API version implemented by this visitor. The value of this field must be one of {@link
63 * Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7_EXPERIMENTAL}.
64 */
65 protected final int api;
66
67 /**
68 * Constructs a new {@link SignatureVisitor}.
69 *
70 * @param api the ASM API version implemented by this visitor. Must be one of {@link
71 * Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link
72 * Opcodes#ASM7_EXPERIMENTAL}.
73 */
74 public SignatureVisitor(final int api) {
75 if (api != Opcodes.ASM6
76 && api != Opcodes.ASM5
77 && api != Opcodes.ASM4
78 && api != Opcodes.ASM7_EXPERIMENTAL) {
79 throw new IllegalArgumentException();
9180 }
92
93 /**
94 * Visits a formal type parameter.
95 *
96 * @param name
97 * the name of the formal parameter.
98 */
99 public void visitFormalTypeParameter(String name) {
100 }
101
102 /**
103 * Visits the class bound of the last visited formal type parameter.
104 *
105 * @return a non null visitor to visit the signature of the class bound.
106 */
107 public SignatureVisitor visitClassBound() {
108 return this;
109 }
110
111 /**
112 * Visits an interface bound of the last visited formal type parameter.
113 *
114 * @return a non null visitor to visit the signature of the interface bound.
115 */
116 public SignatureVisitor visitInterfaceBound() {
117 return this;
118 }
119
120 /**
121 * Visits the type of the super class.
122 *
123 * @return a non null visitor to visit the signature of the super class
124 * type.
125 */
126 public SignatureVisitor visitSuperclass() {
127 return this;
128 }
129
130 /**
131 * Visits the type of an interface implemented by the class.
132 *
133 * @return a non null visitor to visit the signature of the interface type.
134 */
135 public SignatureVisitor visitInterface() {
136 return this;
137 }
138
139 /**
140 * Visits the type of a method parameter.
141 *
142 * @return a non null visitor to visit the signature of the parameter type.
143 */
144 public SignatureVisitor visitParameterType() {
145 return this;
146 }
147
148 /**
149 * Visits the return type of the method.
150 *
151 * @return a non null visitor to visit the signature of the return type.
152 */
153 public SignatureVisitor visitReturnType() {
154 return this;
155 }
156
157 /**
158 * Visits the type of a method exception.
159 *
160 * @return a non null visitor to visit the signature of the exception type.
161 */
162 public SignatureVisitor visitExceptionType() {
163 return this;
164 }
165
166 /**
167 * Visits a signature corresponding to a primitive type.
168 *
169 * @param descriptor
170 * the descriptor of the primitive type, or 'V' for <tt>void</tt>
171 * .
172 */
173 public void visitBaseType(char descriptor) {
174 }
175
176 /**
177 * Visits a signature corresponding to a type variable.
178 *
179 * @param name
180 * the name of the type variable.
181 */
182 public void visitTypeVariable(String name) {
183 }
184
185 /**
186 * Visits a signature corresponding to an array type.
187 *
188 * @return a non null visitor to visit the signature of the array element
189 * type.
190 */
191 public SignatureVisitor visitArrayType() {
192 return this;
193 }
194
195 /**
196 * Starts the visit of a signature corresponding to a class or interface
197 * type.
198 *
199 * @param name
200 * the internal name of the class or interface.
201 */
202 public void visitClassType(String name) {
203 }
204
205 /**
206 * Visits an inner class.
207 *
208 * @param name
209 * the local name of the inner class in its enclosing class.
210 */
211 public void visitInnerClassType(String name) {
212 }
213
214 /**
215 * Visits an unbounded type argument of the last visited class or inner
216 * class type.
217 */
218 public void visitTypeArgument() {
219 }
220
221 /**
222 * Visits a type argument of the last visited class or inner class type.
223 *
224 * @param wildcard
225 * '+', '-' or '='.
226 * @return a non null visitor to visit the signature of the type argument.
227 */
228 public SignatureVisitor visitTypeArgument(char wildcard) {
229 return this;
230 }
231
232 /**
233 * Ends the visit of a signature corresponding to a class or interface type.
234 */
235 public void visitEnd() {
236 }
81 this.api = api;
82 }
83
84 /**
85 * Visits a formal type parameter.
86 *
87 * @param name the name of the formal parameter.
88 */
89 public void visitFormalTypeParameter(final String name) {}
90
91 /**
92 * Visits the class bound of the last visited formal type parameter.
93 *
94 * @return a non null visitor to visit the signature of the class bound.
95 */
96 public SignatureVisitor visitClassBound() {
97 return this;
98 }
99
100 /**
101 * Visits an interface bound of the last visited formal type parameter.
102 *
103 * @return a non null visitor to visit the signature of the interface bound.
104 */
105 public SignatureVisitor visitInterfaceBound() {
106 return this;
107 }
108
109 /**
110 * Visits the type of the super class.
111 *
112 * @return a non null visitor to visit the signature of the super class type.
113 */
114 public SignatureVisitor visitSuperclass() {
115 return this;
116 }
117
118 /**
119 * Visits the type of an interface implemented by the class.
120 *
121 * @return a non null visitor to visit the signature of the interface type.
122 */
123 public SignatureVisitor visitInterface() {
124 return this;
125 }
126
127 /**
128 * Visits the type of a method parameter.
129 *
130 * @return a non null visitor to visit the signature of the parameter type.
131 */
132 public SignatureVisitor visitParameterType() {
133 return this;
134 }
135
136 /**
137 * Visits the return type of the method.
138 *
139 * @return a non null visitor to visit the signature of the return type.
140 */
141 public SignatureVisitor visitReturnType() {
142 return this;
143 }
144
145 /**
146 * Visits the type of a method exception.
147 *
148 * @return a non null visitor to visit the signature of the exception type.
149 */
150 public SignatureVisitor visitExceptionType() {
151 return this;
152 }
153
154 /**
155 * Visits a signature corresponding to a primitive type.
156 *
157 * @param descriptor the descriptor of the primitive type, or 'V' for <tt>void</tt> .
158 */
159 public void visitBaseType(final char descriptor) {}
160
161 /**
162 * Visits a signature corresponding to a type variable.
163 *
164 * @param name the name of the type variable.
165 */
166 public void visitTypeVariable(final String name) {}
167
168 /**
169 * Visits a signature corresponding to an array type.
170 *
171 * @return a non null visitor to visit the signature of the array element type.
172 */
173 public SignatureVisitor visitArrayType() {
174 return this;
175 }
176
177 /**
178 * Starts the visit of a signature corresponding to a class or interface type.
179 *
180 * @param name the internal name of the class or interface.
181 */
182 public void visitClassType(final String name) {}
183
184 /**
185 * Visits an inner class.
186 *
187 * @param name the local name of the inner class in its enclosing class.
188 */
189 public void visitInnerClassType(final String name) {}
190
191 /** Visits an unbounded type argument of the last visited class or inner class type. */
192 public void visitTypeArgument() {}
193
194 /**
195 * Visits a type argument of the last visited class or inner class type.
196 *
197 * @param wildcard '+', '-' or '='.
198 * @return a non null visitor to visit the signature of the type argument.
199 */
200 public SignatureVisitor visitTypeArgument(final char wildcard) {
201 return this;
202 }
203
204 /** Ends the visit of a signature corresponding to a class or interface type. */
205 public void visitEnd() {}
237206 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
27 package org.eclipse.persistence.internal.libraries.asm.signature;
28
29 import org.eclipse.persistence.internal.libraries.asm.Opcodes;
30
31 /**
32 * A SignatureVisitor that generates signature literals, as defined in the Java Virtual Machine
33 * Specification (JVMS).
434 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 package org.eclipse.persistence.internal.libraries.asm.signature;
30
31 import org.eclipse.persistence.internal.libraries.asm.Opcodes;
32
33 /**
34 * A signature visitor that generates signatures in string format.
35 *
35 * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.9.1">JVMS
36 * 4.7.9.1</a>
3637 * @author Thomas Hallgren
3738 * @author Eric Bruneton
3839 */
3940 public class SignatureWriter extends SignatureVisitor {
4041
41 /**
42 * Builder used to construct the signature.
43 */
44 private final StringBuilder buf = new StringBuilder();
45
46 /**
47 * Indicates if the signature contains formal type parameters.
48 */
49 private boolean hasFormals;
50
51 /**
52 * Indicates if the signature contains method parameter types.
53 */
54 private boolean hasParameters;
55
56 /**
57 * Stack used to keep track of class types that have arguments. Each element
58 * of this stack is a boolean encoded in one bit. The top of the stack is
59 * the lowest order bit. Pushing false = *2, pushing true = *2+1, popping =
60 * /2.
61 */
62 private int argumentStack;
63
64 /**
65 * Constructs a new {@link SignatureWriter} object.
66 */
67 public SignatureWriter() {
68 super(Opcodes.ASM6);
69 }
70
71 // ------------------------------------------------------------------------
72 // Implementation of the SignatureVisitor interface
73 // ------------------------------------------------------------------------
74
75 @Override
76 public void visitFormalTypeParameter(final String name) {
77 if (!hasFormals) {
78 hasFormals = true;
79 buf.append('<');
80 }
81 buf.append(name);
82 buf.append(':');
83 }
84
85 @Override
86 public SignatureVisitor visitClassBound() {
87 return this;
88 }
89
90 @Override
91 public SignatureVisitor visitInterfaceBound() {
92 buf.append(':');
93 return this;
94 }
95
96 @Override
97 public SignatureVisitor visitSuperclass() {
98 endFormals();
99 return this;
100 }
101
102 @Override
103 public SignatureVisitor visitInterface() {
104 return this;
105 }
106
107 @Override
108 public SignatureVisitor visitParameterType() {
109 endFormals();
110 if (!hasParameters) {
111 hasParameters = true;
112 buf.append('(');
113 }
114 return this;
115 }
116
117 @Override
118 public SignatureVisitor visitReturnType() {
119 endFormals();
120 if (!hasParameters) {
121 buf.append('(');
122 }
123 buf.append(')');
124 return this;
125 }
126
127 @Override
128 public SignatureVisitor visitExceptionType() {
129 buf.append('^');
130 return this;
131 }
132
133 @Override
134 public void visitBaseType(final char descriptor) {
135 buf.append(descriptor);
136 }
137
138 @Override
139 public void visitTypeVariable(final String name) {
140 buf.append('T');
141 buf.append(name);
142 buf.append(';');
143 }
144
145 @Override
146 public SignatureVisitor visitArrayType() {
147 buf.append('[');
148 return this;
149 }
150
151 @Override
152 public void visitClassType(final String name) {
153 buf.append('L');
154 buf.append(name);
155 argumentStack *= 2;
156 }
157
158 @Override
159 public void visitInnerClassType(final String name) {
160 endArguments();
161 buf.append('.');
162 buf.append(name);
163 argumentStack *= 2;
164 }
165
166 @Override
167 public void visitTypeArgument() {
168 if (argumentStack % 2 == 0) {
169 ++argumentStack;
170 buf.append('<');
171 }
172 buf.append('*');
173 }
174
175 @Override
176 public SignatureVisitor visitTypeArgument(final char wildcard) {
177 if (argumentStack % 2 == 0) {
178 ++argumentStack;
179 buf.append('<');
180 }
181 if (wildcard != '=') {
182 buf.append(wildcard);
183 }
184 return this;
185 }
186
187 @Override
188 public void visitEnd() {
189 endArguments();
190 buf.append(';');
191 }
192
193 /**
194 * Returns the signature that was built by this signature writer.
195 *
196 * @return the signature that was built by this signature writer.
197 */
198 @Override
199 public String toString() {
200 return buf.toString();
201 }
202
203 // ------------------------------------------------------------------------
204 // Utility methods
205 // ------------------------------------------------------------------------
206
207 /**
208 * Ends the formal type parameters section of the signature.
209 */
210 private void endFormals() {
211 if (hasFormals) {
212 hasFormals = false;
213 buf.append('>');
214 }
215 }
216
217 /**
218 * Ends the type arguments of a class or inner class type.
219 */
220 private void endArguments() {
221 if (argumentStack % 2 != 0) {
222 buf.append('>');
223 }
224 argumentStack /= 2;
225 }
226 }
42 /** The builder used to construct the visited signature. */
43 private final StringBuilder stringBuilder = new StringBuilder();
44
45 /** Whether the visited signature contains formal type parameters. */
46 private boolean hasFormals;
47
48 /** Whether the visited signature contains method parameter types. */
49 private boolean hasParameters;
50
51 /**
52 * The stack used to keep track of class types that have arguments. Each element of this stack is
53 * a boolean encoded in one bit. The top of the stack is the least significant bit. Pushing false
54 * = *2, pushing true = *2+1, popping = /2.
55 *
56 * <p>Class type arguments must be surrounded with '&lt;' and '&gt;' and, because
57 *
58 * <ol>
59 * <li>class types can be nested (because type arguments can themselves be class types),
60 * <li>SignatureWriter always returns 'this' in each visit* method (to avoid allocating new
61 * SignatureWriter instances),
62 * </ol>
63 *
64 * we need a stack to properly balance these 'parentheses'. A new element is pushed on this stack
65 * for each new visited type, and popped when the visit of this type ends (either is visitEnd, or
66 * because visitInnerClassType is called).
67 */
68 private int argumentStack;
69
70 /** Constructs a new {@link SignatureWriter}. */
71 public SignatureWriter() {
72 super(Opcodes.ASM6);
73 }
74
75 // -----------------------------------------------------------------------------------------------
76 // Implementation of the SignatureVisitor interface
77 // -----------------------------------------------------------------------------------------------
78
79 @Override
80 public void visitFormalTypeParameter(final String name) {
81 if (!hasFormals) {
82 hasFormals = true;
83 stringBuilder.append('<');
84 }
85 stringBuilder.append(name);
86 stringBuilder.append(':');
87 }
88
89 @Override
90 public SignatureVisitor visitClassBound() {
91 return this;
92 }
93
94 @Override
95 public SignatureVisitor visitInterfaceBound() {
96 stringBuilder.append(':');
97 return this;
98 }
99
100 @Override
101 public SignatureVisitor visitSuperclass() {
102 endFormals();
103 return this;
104 }
105
106 @Override
107 public SignatureVisitor visitInterface() {
108 return this;
109 }
110
111 @Override
112 public SignatureVisitor visitParameterType() {
113 endFormals();
114 if (!hasParameters) {
115 hasParameters = true;
116 stringBuilder.append('(');
117 }
118 return this;
119 }
120
121 @Override
122 public SignatureVisitor visitReturnType() {
123 endFormals();
124 if (!hasParameters) {
125 stringBuilder.append('(');
126 }
127 stringBuilder.append(')');
128 return this;
129 }
130
131 @Override
132 public SignatureVisitor visitExceptionType() {
133 stringBuilder.append('^');
134 return this;
135 }
136
137 @Override
138 public void visitBaseType(final char descriptor) {
139 stringBuilder.append(descriptor);
140 }
141
142 @Override
143 public void visitTypeVariable(final String name) {
144 stringBuilder.append('T');
145 stringBuilder.append(name);
146 stringBuilder.append(';');
147 }
148
149 @Override
150 public SignatureVisitor visitArrayType() {
151 stringBuilder.append('[');
152 return this;
153 }
154
155 @Override
156 public void visitClassType(final String name) {
157 stringBuilder.append('L');
158 stringBuilder.append(name);
159 // Pushes 'false' on the stack, meaning that this type does not have type arguments (as far as
160 // we can tell at this point).
161 argumentStack *= 2;
162 }
163
164 @Override
165 public void visitInnerClassType(final String name) {
166 endArguments();
167 stringBuilder.append('.');
168 stringBuilder.append(name);
169 // Pushes 'false' on the stack, meaning that this type does not have type arguments (as far as
170 // we can tell at this point).
171 argumentStack *= 2;
172 }
173
174 @Override
175 public void visitTypeArgument() {
176 // If the top of the stack is 'false', this means we are visiting the first type argument of the
177 // currently visited type. We therefore need to append a '<', and to replace the top stack
178 // element with 'true' (meaning that the current type does have type arguments).
179 if (argumentStack % 2 == 0) {
180 argumentStack |= 1;
181 stringBuilder.append('<');
182 }
183 stringBuilder.append('*');
184 }
185
186 @Override
187 public SignatureVisitor visitTypeArgument(final char wildcard) {
188 // If the top of the stack is 'false', this means we are visiting the first type argument of the
189 // currently visited type. We therefore need to append a '<', and to replace the top stack
190 // element with 'true' (meaning that the current type does have type arguments).
191 if (argumentStack % 2 == 0) {
192 argumentStack |= 1;
193 stringBuilder.append('<');
194 }
195 if (wildcard != '=') {
196 stringBuilder.append(wildcard);
197 }
198 return this;
199 }
200
201 @Override
202 public void visitEnd() {
203 endArguments();
204 stringBuilder.append(';');
205 }
206
207 /**
208 * Returns the signature that was built by this signature writer.
209 *
210 * @return the signature that was built by this signature writer.
211 */
212 @Override
213 public String toString() {
214 return stringBuilder.toString();
215 }
216
217 // -----------------------------------------------------------------------------------------------
218 // Utility methods
219 // -----------------------------------------------------------------------------------------------
220
221 /** Ends the formal type parameters section of the signature. */
222 private void endFormals() {
223 if (hasFormals) {
224 hasFormals = false;
225 stringBuilder.append('>');
226 }
227 }
228
229 /** Ends the type arguments of a class or inner class type. */
230 private void endArguments() {
231 // If the top of the stack is 'true', this means that some type arguments have been visited for
232 // the type whose visit is now ending. We therefore need to append a '>', and to pop one element
233 // from the stack.
234 if (argumentStack % 2 == 1) {
235 stringBuilder.append('>');
236 }
237 argumentStack /= 2;
238 }
239 }
+0
-36
org/eclipse/persistence/internal/libraries/asm/signature/package.html less more
0 <html>
1 <!--
2 * ASM: a very small and fast Java bytecode manipulation framework
3 * Copyright (c) 2000-2011 INRIA, France Telecom
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the copyright holders nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
28 * THE POSSIBILITY OF SUCH DAMAGE.
29 -->
30 <body>
31 Provides support for type signatures.
32
33 @since ASM 2.0
34 </body>
35 </html>
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.tree;
3028
3129 import java.util.ArrayList;
3533 import org.eclipse.persistence.internal.libraries.asm.MethodVisitor;
3634
3735 /**
38 * A node that represents a bytecode instruction. <i>An instruction can appear
39 * at most once in at most one {@link InsnList} at a time</i>.
40 *
36 * A node that represents a bytecode instruction. <i>An instruction can appear at most once in at
37 * most one {@link InsnList} at a time</i>.
38 *
4139 * @author Eric Bruneton
4240 */
4341 public abstract class AbstractInsnNode {
4442
45 /**
46 * The type of {@link InsnNode} instructions.
47 */
48 public static final int INSN = 0;
49
50 /**
51 * The type of {@link IntInsnNode} instructions.
52 */
53 public static final int INT_INSN = 1;
54
55 /**
56 * The type of {@link VarInsnNode} instructions.
57 */
58 public static final int VAR_INSN = 2;
59
60 /**
61 * The type of {@link TypeInsnNode} instructions.
62 */
63 public static final int TYPE_INSN = 3;
64
65 /**
66 * The type of {@link FieldInsnNode} instructions.
67 */
68 public static final int FIELD_INSN = 4;
69
70 /**
71 * The type of {@link MethodInsnNode} instructions.
72 */
73 public static final int METHOD_INSN = 5;
74
75 /**
76 * The type of {@link InvokeDynamicInsnNode} instructions.
77 */
78 public static final int INVOKE_DYNAMIC_INSN = 6;
79
80 /**
81 * The type of {@link JumpInsnNode} instructions.
82 */
83 public static final int JUMP_INSN = 7;
84
85 /**
86 * The type of {@link LabelNode} "instructions".
87 */
88 public static final int LABEL = 8;
89
90 /**
91 * The type of {@link LdcInsnNode} instructions.
92 */
93 public static final int LDC_INSN = 9;
94
95 /**
96 * The type of {@link IincInsnNode} instructions.
97 */
98 public static final int IINC_INSN = 10;
99
100 /**
101 * The type of {@link TableSwitchInsnNode} instructions.
102 */
103 public static final int TABLESWITCH_INSN = 11;
104
105 /**
106 * The type of {@link LookupSwitchInsnNode} instructions.
107 */
108 public static final int LOOKUPSWITCH_INSN = 12;
109
110 /**
111 * The type of {@link MultiANewArrayInsnNode} instructions.
112 */
113 public static final int MULTIANEWARRAY_INSN = 13;
114
115 /**
116 * The type of {@link FrameNode} "instructions".
117 */
118 public static final int FRAME = 14;
119
120 /**
121 * The type of {@link LineNumberNode} "instructions".
122 */
123 public static final int LINE = 15;
124
125 /**
126 * The opcode of this instruction.
127 */
128 protected int opcode;
129
130 /**
131 * The runtime visible type annotations of this instruction. This field is
132 * only used for real instructions (i.e. not for labels, frames, or line
133 * number nodes). This list is a list of {@link TypeAnnotationNode} objects.
134 * May be <tt>null</tt>.
135 *
136 * @associates org.eclipse.persistence.internal.libraries.asm.tree.TypeAnnotationNode
137 * @label visible
138 */
139 public List<TypeAnnotationNode> visibleTypeAnnotations;
140
141 /**
142 * The runtime invisible type annotations of this instruction. This field is
143 * only used for real instructions (i.e. not for labels, frames, or line
144 * number nodes). This list is a list of {@link TypeAnnotationNode} objects.
145 * May be <tt>null</tt>.
146 *
147 * @associates org.eclipse.persistence.internal.libraries.asm.tree.TypeAnnotationNode
148 * @label invisible
149 */
150 public List<TypeAnnotationNode> invisibleTypeAnnotations;
151
152 /**
153 * Previous instruction in the list to which this instruction belongs.
154 */
155 AbstractInsnNode prev;
156
157 /**
158 * Next instruction in the list to which this instruction belongs.
159 */
160 AbstractInsnNode next;
161
162 /**
163 * Index of this instruction in the list to which it belongs. The value of
164 * this field is correct only when {@link InsnList#cache} is not null. A
165 * value of -1 indicates that this instruction does not belong to any
166 * {@link InsnList}.
167 */
168 int index;
169
170 /**
171 * Constructs a new {@link AbstractInsnNode}.
172 *
173 * @param opcode
174 * the opcode of the instruction to be constructed.
175 */
176 protected AbstractInsnNode(final int opcode) {
177 this.opcode = opcode;
178 this.index = -1;
179 }
180
181 /**
182 * Returns the opcode of this instruction.
183 *
184 * @return the opcode of this instruction.
185 */
186 public int getOpcode() {
187 return opcode;
188 }
189
190 /**
191 * Returns the type of this instruction.
192 *
193 * @return the type of this instruction, i.e. one the constants defined in
194 * this class.
195 */
196 public abstract int getType();
197
198 /**
199 * Returns the previous instruction in the list to which this instruction
200 * belongs, if any.
201 *
202 * @return the previous instruction in the list to which this instruction
203 * belongs, if any. May be <tt>null</tt>.
204 */
205 public AbstractInsnNode getPrevious() {
206 return prev;
207 }
208
209 /**
210 * Returns the next instruction in the list to which this instruction
211 * belongs, if any.
212 *
213 * @return the next instruction in the list to which this instruction
214 * belongs, if any. May be <tt>null</tt>.
215 */
216 public AbstractInsnNode getNext() {
217 return next;
218 }
219
220 /**
221 * Makes the given code visitor visit this instruction.
222 *
223 * @param cv
224 * a code visitor.
225 */
226 public abstract void accept(final MethodVisitor cv);
227
228 /**
229 * Makes the given visitor visit the annotations of this instruction.
230 *
231 * @param mv
232 * a method visitor.
233 */
234 protected final void acceptAnnotations(final MethodVisitor mv) {
235 int n = visibleTypeAnnotations == null ? 0 : visibleTypeAnnotations
236 .size();
237 for (int i = 0; i < n; ++i) {
238 TypeAnnotationNode an = visibleTypeAnnotations.get(i);
239 an.accept(mv.visitInsnAnnotation(an.typeRef, an.typePath, an.desc,
240 true));
241 }
242 n = invisibleTypeAnnotations == null ? 0 : invisibleTypeAnnotations
243 .size();
244 for (int i = 0; i < n; ++i) {
245 TypeAnnotationNode an = invisibleTypeAnnotations.get(i);
246 an.accept(mv.visitInsnAnnotation(an.typeRef, an.typePath, an.desc,
247 false));
248 }
249 }
250
251 /**
252 * Returns a copy of this instruction.
253 *
254 * @param labels
255 * a map from LabelNodes to cloned LabelNodes.
256 * @return a copy of this instruction. The returned instruction does not
257 * belong to any {@link InsnList}.
258 */
259 public abstract AbstractInsnNode clone(
260 final Map<LabelNode, LabelNode> labels);
261
262 /**
263 * Returns the clone of the given label.
264 *
265 * @param label
266 * a label.
267 * @param map
268 * a map from LabelNodes to cloned LabelNodes.
269 * @return the clone of the given label.
270 */
271 static LabelNode clone(final LabelNode label,
272 final Map<LabelNode, LabelNode> map) {
273 return map.get(label);
274 }
275
276 /**
277 * Returns the clones of the given labels.
278 *
279 * @param labels
280 * a list of labels.
281 * @param map
282 * a map from LabelNodes to cloned LabelNodes.
283 * @return the clones of the given labels.
284 */
285 static LabelNode[] clone(final List<LabelNode> labels,
286 final Map<LabelNode, LabelNode> map) {
287 LabelNode[] clones = new LabelNode[labels.size()];
288 for (int i = 0; i < clones.length; ++i) {
289 clones[i] = map.get(labels.get(i));
290 }
291 return clones;
292 }
293
294 /**
295 * Clones the annotations of the given instruction into this instruction.
296 *
297 * @param insn
298 * the source instruction.
299 * @return this instruction.
300 */
301 protected final AbstractInsnNode cloneAnnotations(
302 final AbstractInsnNode insn) {
303 if (insn.visibleTypeAnnotations != null) {
304 this.visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>();
305 for (int i = 0; i < insn.visibleTypeAnnotations.size(); ++i) {
306 TypeAnnotationNode src = insn.visibleTypeAnnotations.get(i);
307 TypeAnnotationNode ann = new TypeAnnotationNode(src.typeRef,
308 src.typePath, src.desc);
309 src.accept(ann);
310 this.visibleTypeAnnotations.add(ann);
311 }
312 }
313 if (insn.invisibleTypeAnnotations != null) {
314 this.invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>();
315 for (int i = 0; i < insn.invisibleTypeAnnotations.size(); ++i) {
316 TypeAnnotationNode src = insn.invisibleTypeAnnotations.get(i);
317 TypeAnnotationNode ann = new TypeAnnotationNode(src.typeRef,
318 src.typePath, src.desc);
319 src.accept(ann);
320 this.invisibleTypeAnnotations.add(ann);
321 }
322 }
323 return this;
324 }
43 /** The type of {@link InsnNode} instructions. */
44 public static final int INSN = 0;
45
46 /** The type of {@link IntInsnNode} instructions. */
47 public static final int INT_INSN = 1;
48
49 /** The type of {@link VarInsnNode} instructions. */
50 public static final int VAR_INSN = 2;
51
52 /** The type of {@link TypeInsnNode} instructions. */
53 public static final int TYPE_INSN = 3;
54
55 /** The type of {@link FieldInsnNode} instructions. */
56 public static final int FIELD_INSN = 4;
57
58 /** The type of {@link MethodInsnNode} instructions. */
59 public static final int METHOD_INSN = 5;
60
61 /** The type of {@link InvokeDynamicInsnNode} instructions. */
62 public static final int INVOKE_DYNAMIC_INSN = 6;
63
64 /** The type of {@link JumpInsnNode} instructions. */
65 public static final int JUMP_INSN = 7;
66
67 /** The type of {@link LabelNode} "instructions". */
68 public static final int LABEL = 8;
69
70 /** The type of {@link LdcInsnNode} instructions. */
71 public static final int LDC_INSN = 9;
72
73 /** The type of {@link IincInsnNode} instructions. */
74 public static final int IINC_INSN = 10;
75
76 /** The type of {@link TableSwitchInsnNode} instructions. */
77 public static final int TABLESWITCH_INSN = 11;
78
79 /** The type of {@link LookupSwitchInsnNode} instructions. */
80 public static final int LOOKUPSWITCH_INSN = 12;
81
82 /** The type of {@link MultiANewArrayInsnNode} instructions. */
83 public static final int MULTIANEWARRAY_INSN = 13;
84
85 /** The type of {@link FrameNode} "instructions". */
86 public static final int FRAME = 14;
87
88 /** The type of {@link LineNumberNode} "instructions". */
89 public static final int LINE = 15;
90
91 /** The opcode of this instruction. */
92 protected int opcode;
93
94 /**
95 * The runtime visible type annotations of this instruction. This field is only used for real
96 * instructions (i.e. not for labels, frames, or line number nodes). This list is a list of {@link
97 * TypeAnnotationNode} objects. May be <tt>null</tt>.
98 */
99 public List<TypeAnnotationNode> visibleTypeAnnotations;
100
101 /**
102 * The runtime invisible type annotations of this instruction. This field is only used for real
103 * instructions (i.e. not for labels, frames, or line number nodes). This list is a list of {@link
104 * TypeAnnotationNode} objects. May be <tt>null</tt>.
105 */
106 public List<TypeAnnotationNode> invisibleTypeAnnotations;
107
108 /** The previous instruction in the list to which this instruction belongs. */
109 AbstractInsnNode previousInsn;
110
111 /** The next instruction in the list to which this instruction belongs. */
112 AbstractInsnNode nextInsn;
113
114 /**
115 * The index of this instruction in the list to which it belongs. The value of this field is
116 * correct only when {@link InsnList#cache} is not null. A value of -1 indicates that this
117 * instruction does not belong to any {@link InsnList}.
118 */
119 int index;
120
121 /**
122 * Constructs a new {@link AbstractInsnNode}.
123 *
124 * @param opcode the opcode of the instruction to be constructed.
125 */
126 protected AbstractInsnNode(final int opcode) {
127 this.opcode = opcode;
128 this.index = -1;
129 }
130
131 /**
132 * Returns the opcode of this instruction.
133 *
134 * @return the opcode of this instruction.
135 */
136 public int getOpcode() {
137 return opcode;
138 }
139
140 /**
141 * Returns the type of this instruction.
142 *
143 * @return the type of this instruction, i.e. one the constants defined in this class.
144 */
145 public abstract int getType();
146
147 /**
148 * Returns the previous instruction in the list to which this instruction belongs, if any.
149 *
150 * @return the previous instruction in the list to which this instruction belongs, if any. May be
151 * <tt>null</tt>.
152 */
153 public AbstractInsnNode getPrevious() {
154 return previousInsn;
155 }
156
157 /**
158 * Returns the next instruction in the list to which this instruction belongs, if any.
159 *
160 * @return the next instruction in the list to which this instruction belongs, if any. May be
161 * <tt>null</tt>.
162 */
163 public AbstractInsnNode getNext() {
164 return nextInsn;
165 }
166
167 /**
168 * Makes the given method visitor visit this instruction.
169 *
170 * @param methodVisitor a method visitor.
171 */
172 public abstract void accept(MethodVisitor methodVisitor);
173
174 /**
175 * Makes the given visitor visit the annotations of this instruction.
176 *
177 * @param methodVisitor a method visitor.
178 */
179 protected final void acceptAnnotations(final MethodVisitor methodVisitor) {
180 if (visibleTypeAnnotations != null) {
181 for (int i = 0, n = visibleTypeAnnotations.size(); i < n; ++i) {
182 TypeAnnotationNode typeAnnotation = visibleTypeAnnotations.get(i);
183 typeAnnotation.accept(
184 methodVisitor.visitInsnAnnotation(
185 typeAnnotation.typeRef, typeAnnotation.typePath, typeAnnotation.desc, true));
186 }
187 }
188 if (invisibleTypeAnnotations != null) {
189 for (int i = 0, n = invisibleTypeAnnotations.size(); i < n; ++i) {
190 TypeAnnotationNode typeAnnotation = invisibleTypeAnnotations.get(i);
191 typeAnnotation.accept(
192 methodVisitor.visitInsnAnnotation(
193 typeAnnotation.typeRef, typeAnnotation.typePath, typeAnnotation.desc, false));
194 }
195 }
196 }
197
198 /**
199 * Returns a copy of this instruction.
200 *
201 * @param clonedLabels a map from LabelNodes to cloned LabelNodes.
202 * @return a copy of this instruction. The returned instruction does not belong to any {@link
203 * InsnList}.
204 */
205 public abstract AbstractInsnNode clone(Map<LabelNode, LabelNode> clonedLabels);
206
207 /**
208 * Returns the clone of the given label.
209 *
210 * @param label a label.
211 * @param clonedLabels a map from LabelNodes to cloned LabelNodes.
212 * @return the clone of the given label.
213 */
214 static LabelNode clone(final LabelNode label, final Map<LabelNode, LabelNode> clonedLabels) {
215 return clonedLabels.get(label);
216 }
217
218 /**
219 * Returns the clones of the given labels.
220 *
221 * @param labels a list of labels.
222 * @param clonedLabels a map from LabelNodes to cloned LabelNodes.
223 * @return the clones of the given labels.
224 */
225 static LabelNode[] clone(
226 final List<LabelNode> labels, final Map<LabelNode, LabelNode> clonedLabels) {
227 LabelNode[] clones = new LabelNode[labels.size()];
228 for (int i = 0, n = clones.length; i < n; ++i) {
229 clones[i] = clonedLabels.get(labels.get(i));
230 }
231 return clones;
232 }
233
234 /**
235 * Clones the annotations of the given instruction into this instruction.
236 *
237 * @param insnNode the source instruction.
238 * @return this instruction.
239 */
240 protected final AbstractInsnNode cloneAnnotations(final AbstractInsnNode insnNode) {
241 if (insnNode.visibleTypeAnnotations != null) {
242 this.visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>();
243 for (int i = 0, n = insnNode.visibleTypeAnnotations.size(); i < n; ++i) {
244 TypeAnnotationNode sourceAnnotation = insnNode.visibleTypeAnnotations.get(i);
245 TypeAnnotationNode cloneAnnotation =
246 new TypeAnnotationNode(
247 sourceAnnotation.typeRef, sourceAnnotation.typePath, sourceAnnotation.desc);
248 sourceAnnotation.accept(cloneAnnotation);
249 this.visibleTypeAnnotations.add(cloneAnnotation);
250 }
251 }
252 if (insnNode.invisibleTypeAnnotations != null) {
253 this.invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>();
254 for (int i = 0, n = insnNode.invisibleTypeAnnotations.size(); i < n; ++i) {
255 TypeAnnotationNode sourceAnnotation = insnNode.invisibleTypeAnnotations.get(i);
256 TypeAnnotationNode cloneAnnotation =
257 new TypeAnnotationNode(
258 sourceAnnotation.typeRef, sourceAnnotation.typePath, sourceAnnotation.desc);
259 sourceAnnotation.accept(cloneAnnotation);
260 this.invisibleTypeAnnotations.add(cloneAnnotation);
261 }
262 }
263 return this;
264 }
325265 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.tree;
3028
3129 import java.util.ArrayList;
3533 import org.eclipse.persistence.internal.libraries.asm.Opcodes;
3634
3735 /**
38 * A node that represents an annotationn.
39 *
36 * A node that represents an annotation.
37 *
4038 * @author Eric Bruneton
4139 */
4240 public class AnnotationNode extends AnnotationVisitor {
4341
44 /**
45 * The class descriptor of the annotation class.
46 */
47 public String desc;
48
49 /**
50 * The name value pairs of this annotation. Each name value pair is stored
51 * as two consecutive elements in the list. The name is a {@link String},
52 * and the value may be a {@link Byte}, {@link Boolean}, {@link Character},
53 * {@link Short}, {@link Integer}, {@link Long}, {@link Float},
54 * {@link Double}, {@link String} or {@link org.eclipse.persistence.internal.libraries.asm.Type}, or an
55 * two elements String array (for enumeration values), a
56 * {@link AnnotationNode}, or a {@link List} of values of one of the
57 * preceding types. The list may be <tt>null</tt> if there is no name value
58 * pair.
59 */
60 public List<Object> values;
61
62 /**
63 * Constructs a new {@link AnnotationNode}. <i>Subclasses must not use this
64 * constructor</i>. Instead, they must use the
65 * {@link #AnnotationNode(int, String)} version.
66 *
67 * @param desc
68 * the class descriptor of the annotation class.
69 * @throws IllegalStateException
70 * If a subclass calls this constructor.
71 */
72 public AnnotationNode(final String desc) {
73 this(Opcodes.ASM6, desc);
74 if (getClass() != AnnotationNode.class) {
75 throw new IllegalStateException();
42 /** The class descriptor of the annotation class. */
43 public String desc;
44
45 /**
46 * The name value pairs of this annotation. Each name value pair is stored as two consecutive
47 * elements in the list. The name is a {@link String}, and the value may be a {@link Byte}, {@link
48 * Boolean}, {@link Character}, {@link Short}, {@link Integer}, {@link Long}, {@link Float},
49 * {@link Double}, {@link String} or {@link org.eclipse.persistence.internal.libraries.asm.Type}, or a two elements String
50 * array (for enumeration values), an {@link AnnotationNode}, or a {@link List} of values of one
51 * of the preceding types. The list may be <tt>null</tt> if there is no name value pair.
52 */
53 public List<Object> values;
54
55 /**
56 * Constructs a new {@link AnnotationNode}. <i>Subclasses must not use this constructor</i>.
57 * Instead, they must use the {@link #AnnotationNode(int, String)} version.
58 *
59 * @param descriptor the class descriptor of the annotation class.
60 * @throws IllegalStateException If a subclass calls this constructor.
61 */
62 public AnnotationNode(final String descriptor) {
63 this(Opcodes.ASM6, descriptor);
64 if (getClass() != AnnotationNode.class) {
65 throw new IllegalStateException();
66 }
67 }
68
69 /**
70 * Constructs a new {@link AnnotationNode}.
71 *
72 * @param api the ASM API version implemented by this visitor. Must be one of {@link
73 * Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
74 * @param descriptor the class descriptor of the annotation class.
75 */
76 public AnnotationNode(final int api, final String descriptor) {
77 super(api);
78 this.desc = descriptor;
79 }
80
81 /**
82 * Constructs a new {@link AnnotationNode} to visit an array value.
83 *
84 * @param values where the visited values must be stored.
85 */
86 AnnotationNode(final List<Object> values) {
87 super(Opcodes.ASM6);
88 this.values = values;
89 }
90
91 // ------------------------------------------------------------------------
92 // Implementation of the AnnotationVisitor abstract class
93 // ------------------------------------------------------------------------
94
95 @Override
96 public void visit(final String name, final Object value) {
97 if (values == null) {
98 values = new ArrayList<Object>(this.desc != null ? 2 : 1);
99 }
100 if (this.desc != null) {
101 values.add(name);
102 }
103 if (value instanceof byte[]) {
104 values.add(Util.asArrayList((byte[]) value));
105 } else if (value instanceof boolean[]) {
106 values.add(Util.asArrayList((boolean[]) value));
107 } else if (value instanceof short[]) {
108 values.add(Util.asArrayList((short[]) value));
109 } else if (value instanceof char[]) {
110 values.add(Util.asArrayList((char[]) value));
111 } else if (value instanceof int[]) {
112 values.add(Util.asArrayList((int[]) value));
113 } else if (value instanceof long[]) {
114 values.add(Util.asArrayList((long[]) value));
115 } else if (value instanceof float[]) {
116 values.add(Util.asArrayList((float[]) value));
117 } else if (value instanceof double[]) {
118 values.add(Util.asArrayList((double[]) value));
119 } else {
120 values.add(value);
121 }
122 }
123
124 @Override
125 public void visitEnum(final String name, final String descriptor, final String value) {
126 if (values == null) {
127 values = new ArrayList<Object>(this.desc != null ? 2 : 1);
128 }
129 if (this.desc != null) {
130 values.add(name);
131 }
132 values.add(new String[] {descriptor, value});
133 }
134
135 @Override
136 public AnnotationVisitor visitAnnotation(final String name, final String descriptor) {
137 if (values == null) {
138 values = new ArrayList<Object>(this.desc != null ? 2 : 1);
139 }
140 if (this.desc != null) {
141 values.add(name);
142 }
143 AnnotationNode annotation = new AnnotationNode(descriptor);
144 values.add(annotation);
145 return annotation;
146 }
147
148 @Override
149 public AnnotationVisitor visitArray(final String name) {
150 if (values == null) {
151 values = new ArrayList<Object>(this.desc != null ? 2 : 1);
152 }
153 if (this.desc != null) {
154 values.add(name);
155 }
156 List<Object> array = new ArrayList<Object>();
157 values.add(array);
158 return new AnnotationNode(array);
159 }
160
161 @Override
162 public void visitEnd() {
163 // Nothing to do.
164 }
165
166 // ------------------------------------------------------------------------
167 // Accept methods
168 // ------------------------------------------------------------------------
169
170 /**
171 * Checks that this annotation node is compatible with the given ASM API version. This method
172 * checks that this node, and all its children recursively, do not contain elements that were
173 * introduced in more recent versions of the ASM API than the given version.
174 *
175 * @param api an ASM API version. Must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or
176 * {@link Opcodes#ASM6}.
177 */
178 public void check(final int api) {
179 // nothing to do
180 }
181
182 /**
183 * Makes the given visitor visit this annotation.
184 *
185 * @param annotationVisitor an annotation visitor. Maybe <tt>null</tt>.
186 */
187 public void accept(final AnnotationVisitor annotationVisitor) {
188 if (annotationVisitor != null) {
189 if (values != null) {
190 for (int i = 0, n = values.size(); i < n; i += 2) {
191 String name = (String) values.get(i);
192 Object value = values.get(i + 1);
193 accept(annotationVisitor, name, value);
76194 }
77 }
78
79 /**
80 * Constructs a new {@link AnnotationNode}.
81 *
82 * @param api
83 * the ASM API version implemented by this visitor. Must be one
84 * of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
85 * @param desc
86 * the class descriptor of the annotation class.
87 */
88 public AnnotationNode(final int api, final String desc) {
89 super(api);
90 this.desc = desc;
91 }
92
93 /**
94 * Constructs a new {@link AnnotationNode} to visit an array value.
95 *
96 * @param values
97 * where the visited values must be stored.
98 */
99 AnnotationNode(final List<Object> values) {
100 super(Opcodes.ASM6);
101 this.values = values;
102 }
103
104 // ------------------------------------------------------------------------
105 // Implementation of the AnnotationVisitor abstract class
106 // ------------------------------------------------------------------------
107
108 @Override
109 public void visit(final String name, final Object value) {
110 if (values == null) {
111 values = new ArrayList<Object>(this.desc != null ? 2 : 1);
195 }
196 annotationVisitor.visitEnd();
197 }
198 }
199
200 /**
201 * Makes the given visitor visit a given annotation value.
202 *
203 * @param annotationVisitor an annotation visitor. Maybe <tt>null</tt>.
204 * @param name the value name.
205 * @param value the actual value.
206 */
207 static void accept(
208 final AnnotationVisitor annotationVisitor, final String name, final Object value) {
209 if (annotationVisitor != null) {
210 if (value instanceof String[]) {
211 String[] typeValue = (String[]) value;
212 annotationVisitor.visitEnum(name, typeValue[0], typeValue[1]);
213 } else if (value instanceof AnnotationNode) {
214 AnnotationNode annotationValue = (AnnotationNode) value;
215 annotationValue.accept(annotationVisitor.visitAnnotation(name, annotationValue.desc));
216 } else if (value instanceof List) {
217 AnnotationVisitor arrayAnnotationVisitor = annotationVisitor.visitArray(name);
218 if (arrayAnnotationVisitor != null) {
219 List<?> arrayValue = (List<?>) value;
220 for (int i = 0, n = arrayValue.size(); i < n; ++i) {
221 accept(arrayAnnotationVisitor, null, arrayValue.get(i));
222 }
223 arrayAnnotationVisitor.visitEnd();
112224 }
113 if (this.desc != null) {
114 values.add(name);
115 }
116 values.add(value);
117 }
118
119 @Override
120 public void visitEnum(final String name, final String desc,
121 final String value) {
122 if (values == null) {
123 values = new ArrayList<Object>(this.desc != null ? 2 : 1);
124 }
125 if (this.desc != null) {
126 values.add(name);
127 }
128 values.add(new String[] { desc, value });
129 }
130
131 @Override
132 public AnnotationVisitor visitAnnotation(final String name,
133 final String desc) {
134 if (values == null) {
135 values = new ArrayList<Object>(this.desc != null ? 2 : 1);
136 }
137 if (this.desc != null) {
138 values.add(name);
139 }
140 AnnotationNode annotation = new AnnotationNode(desc);
141 values.add(annotation);
142 return annotation;
143 }
144
145 @Override
146 public AnnotationVisitor visitArray(final String name) {
147 if (values == null) {
148 values = new ArrayList<Object>(this.desc != null ? 2 : 1);
149 }
150 if (this.desc != null) {
151 values.add(name);
152 }
153 List<Object> array = new ArrayList<Object>();
154 values.add(array);
155 return new AnnotationNode(array);
156 }
157
158 @Override
159 public void visitEnd() {
160 }
161
162 // ------------------------------------------------------------------------
163 // Accept methods
164 // ------------------------------------------------------------------------
165
166 /**
167 * Checks that this annotation node is compatible with the given ASM API
168 * version. This methods checks that this node, and all its nodes
169 * recursively, do not contain elements that were introduced in more recent
170 * versions of the ASM API than the given version.
171 *
172 * @param api
173 * an ASM API version. Must be one of {@link Opcodes#ASM4},
174 * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
175 */
176 public void check(final int api) {
177 // nothing to do
178 }
179
180 /**
181 * Makes the given visitor visit this annotation.
182 *
183 * @param av
184 * an annotation visitor. Maybe <tt>null</tt>.
185 */
186 public void accept(final AnnotationVisitor av) {
187 if (av != null) {
188 if (values != null) {
189 for (int i = 0; i < values.size(); i += 2) {
190 String name = (String) values.get(i);
191 Object value = values.get(i + 1);
192 accept(av, name, value);
193 }
194 }
195 av.visitEnd();
196 }
197 }
198
199 /**
200 * Makes the given visitor visit a given annotation value.
201 *
202 * @param av
203 * an annotation visitor. Maybe <tt>null</tt>.
204 * @param name
205 * the value name.
206 * @param value
207 * the actual value.
208 */
209 static void accept(final AnnotationVisitor av, final String name,
210 final Object value) {
211 if (av != null) {
212 if (value instanceof String[]) {
213 String[] typeconst = (String[]) value;
214 av.visitEnum(name, typeconst[0], typeconst[1]);
215 } else if (value instanceof AnnotationNode) {
216 AnnotationNode an = (AnnotationNode) value;
217 an.accept(av.visitAnnotation(name, an.desc));
218 } else if (value instanceof List) {
219 AnnotationVisitor v = av.visitArray(name);
220 if (v != null) {
221 List<?> array = (List<?>) value;
222 for (int j = 0; j < array.size(); ++j) {
223 accept(v, null, array.get(j));
224 }
225 v.visitEnd();
226 }
227 } else {
228 av.visit(name, value);
229 }
230 }
231 }
225 } else {
226 annotationVisitor.visit(name, value);
227 }
228 }
229 }
232230 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.tree;
3028
3129 import java.util.ArrayList;
32 import java.util.Arrays;
3330 import java.util.List;
3431
3532 import org.eclipse.persistence.internal.libraries.asm.AnnotationVisitor;
4340
4441 /**
4542 * A node that represents a class.
46 *
43 *
4744 * @author Eric Bruneton
4845 */
4946 public class ClassNode extends ClassVisitor {
5047
51 /**
52 * The class version.
53 */
54 public int version;
55
56 /**
57 * The class's access flags (see {@link org.eclipse.persistence.internal.libraries.asm.Opcodes}). This
58 * field also indicates if the class is deprecated.
59 */
60 public int access;
61
62 /**
63 * The internal name of the class (see
64 * {@link org.eclipse.persistence.internal.libraries.asm.Type#getInternalName() getInternalName}).
65 */
66 public String name;
67
68 /**
69 * The signature of the class. May be <tt>null</tt>.
70 */
71 public String signature;
72
73 /**
74 * The internal of name of the super class (see
75 * {@link org.eclipse.persistence.internal.libraries.asm.Type#getInternalName() getInternalName}). For
76 * interfaces, the super class is {@link Object}. May be <tt>null</tt>, but
77 * only for the {@link Object} class.
78 */
79 public String superName;
80
81 /**
82 * The internal names of the class's interfaces (see
83 * {@link org.eclipse.persistence.internal.libraries.asm.Type#getInternalName() getInternalName}). This
84 * list is a list of {@link String} objects.
85 */
86 public List<String> interfaces;
87
88 /**
89 * The name of the source file from which this class was compiled. May be
90 * <tt>null</tt>.
91 */
92 public String sourceFile;
93
94 /**
95 * Debug information to compute the correspondence between source and
96 * compiled elements of the class. May be <tt>null</tt>.
97 */
98 public String sourceDebug;
99
100 /**
101 * Module information. May be <tt>null</tt>.
102 */
103 public ModuleNode module;
104
105 /**
106 * The internal name of the enclosing class of the class. May be
107 * <tt>null</tt>.
108 */
109 public String outerClass;
110
111 /**
112 * The name of the method that contains the class, or <tt>null</tt> if the
113 * class is not enclosed in a method.
114 */
115 public String outerMethod;
116
117 /**
118 * The descriptor of the method that contains the class, or <tt>null</tt> if
119 * the class is not enclosed in a method.
120 */
121 public String outerMethodDesc;
122
123 /**
124 * The runtime visible annotations of this class. This list is a list of
125 * {@link AnnotationNode} objects. May be <tt>null</tt>.
126 *
127 * @associates org.eclipse.persistence.internal.libraries.asm.tree.AnnotationNode
128 * @label visible
129 */
130 public List<AnnotationNode> visibleAnnotations;
131
132 /**
133 * The runtime invisible annotations of this class. This list is a list of
134 * {@link AnnotationNode} objects. May be <tt>null</tt>.
135 *
136 * @associates org.eclipse.persistence.internal.libraries.asm.tree.AnnotationNode
137 * @label invisible
138 */
139 public List<AnnotationNode> invisibleAnnotations;
140
141 /**
142 * The runtime visible type annotations of this class. This list is a list
143 * of {@link TypeAnnotationNode} objects. May be <tt>null</tt>.
144 *
145 * @associates org.eclipse.persistence.internal.libraries.asm.tree.TypeAnnotationNode
146 * @label visible
147 */
148 public List<TypeAnnotationNode> visibleTypeAnnotations;
149
150 /**
151 * The runtime invisible type annotations of this class. This list is a list
152 * of {@link TypeAnnotationNode} objects. May be <tt>null</tt>.
153 *
154 * @associates org.eclipse.persistence.internal.libraries.asm.tree.TypeAnnotationNode
155 * @label invisible
156 */
157 public List<TypeAnnotationNode> invisibleTypeAnnotations;
158
159 /**
160 * The non standard attributes of this class. This list is a list of
161 * {@link Attribute} objects. May be <tt>null</tt>.
162 *
163 * @associates org.eclipse.persistence.internal.libraries.asm.Attribute
164 */
165 public List<Attribute> attrs;
166
167 /**
168 * Informations about the inner classes of this class. This list is a list
169 * of {@link InnerClassNode} objects.
170 *
171 * @associates org.eclipse.persistence.internal.libraries.asm.tree.InnerClassNode
172 */
173 public List<InnerClassNode> innerClasses;
174
175 /**
176 * The fields of this class. This list is a list of {@link FieldNode}
177 * objects.
178 *
179 * @associates org.eclipse.persistence.internal.libraries.asm.tree.FieldNode
180 */
181 public List<FieldNode> fields;
182
183 /**
184 * The methods of this class. This list is a list of {@link MethodNode}
185 * objects.
186 *
187 * @associates org.eclipse.persistence.internal.libraries.asm.tree.MethodNode
188 */
189 public List<MethodNode> methods;
190
191 /**
192 * Constructs a new {@link ClassNode}. <i>Subclasses must not use this
193 * constructor</i>. Instead, they must use the {@link #ClassNode(int)}
194 * version.
195 *
196 * @throws IllegalStateException
197 * If a subclass calls this constructor.
198 */
199 public ClassNode() {
200 this(Opcodes.ASM6);
201 if (getClass() != ClassNode.class) {
202 throw new IllegalStateException();
203 }
204 }
205
206 /**
207 * Constructs a new {@link ClassNode}.
208 *
209 * @param api
210 * the ASM API version implemented by this visitor. Must be one
211 * of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
212 */
213 public ClassNode(final int api) {
214 super(api);
215 this.interfaces = new ArrayList<String>();
216 this.innerClasses = new ArrayList<InnerClassNode>();
217 this.fields = new ArrayList<FieldNode>();
218 this.methods = new ArrayList<MethodNode>();
219 }
220
221 // ------------------------------------------------------------------------
222 // Implementation of the ClassVisitor abstract class
223 // ------------------------------------------------------------------------
224
225 @Override
226 public void visit(final int version, final int access, final String name,
227 final String signature, final String superName,
228 final String[] interfaces) {
229 this.version = version;
230 this.access = access;
231 this.name = name;
232 this.signature = signature;
233 this.superName = superName;
234 if (interfaces != null) {
235 this.interfaces.addAll(Arrays.asList(interfaces));
236 }
237 }
238
239 @Override
240 public void visitSource(final String file, final String debug) {
241 sourceFile = file;
242 sourceDebug = debug;
243 }
244
245 @Override
246 public ModuleVisitor visitModule() {
247 return module = new ModuleNode();
248 }
249
250 @Override
251 public void visitOuterClass(final String owner, final String name,
252 final String desc) {
253 outerClass = owner;
254 outerMethod = name;
255 outerMethodDesc = desc;
256 }
257
258 @Override
259 public AnnotationVisitor visitAnnotation(final String desc,
260 final boolean visible) {
261 AnnotationNode an = new AnnotationNode(desc);
262 if (visible) {
263 if (visibleAnnotations == null) {
264 visibleAnnotations = new ArrayList<AnnotationNode>(1);
265 }
266 visibleAnnotations.add(an);
267 } else {
268 if (invisibleAnnotations == null) {
269 invisibleAnnotations = new ArrayList<AnnotationNode>(1);
270 }
271 invisibleAnnotations.add(an);
272 }
273 return an;
274 }
275
276 @Override
277 public AnnotationVisitor visitTypeAnnotation(int typeRef,
278 TypePath typePath, String desc, boolean visible) {
279 TypeAnnotationNode an = new TypeAnnotationNode(typeRef, typePath, desc);
280 if (visible) {
281 if (visibleTypeAnnotations == null) {
282 visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
283 }
284 visibleTypeAnnotations.add(an);
285 } else {
286 if (invisibleTypeAnnotations == null) {
287 invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
288 }
289 invisibleTypeAnnotations.add(an);
290 }
291 return an;
292 }
293
294 @Override
295 public void visitAttribute(final Attribute attr) {
296 if (attrs == null) {
297 attrs = new ArrayList<Attribute>(1);
298 }
299 attrs.add(attr);
300 }
301
302 @Override
303 public void visitInnerClass(final String name, final String outerName,
304 final String innerName, final int access) {
305 InnerClassNode icn = new InnerClassNode(name, outerName, innerName,
306 access);
307 innerClasses.add(icn);
308 }
309
310 @Override
311 public FieldVisitor visitField(final int access, final String name,
312 final String desc, final String signature, final Object value) {
313 FieldNode fn = new FieldNode(access, name, desc, signature, value);
314 fields.add(fn);
315 return fn;
316 }
317
318 @Override
319 public MethodVisitor visitMethod(final int access, final String name,
320 final String desc, final String signature, final String[] exceptions) {
321 MethodNode mn = new MethodNode(access, name, desc, signature,
322 exceptions);
323 methods.add(mn);
324 return mn;
325 }
326
327 @Override
328 public void visitEnd() {
329 }
330
331 // ------------------------------------------------------------------------
332 // Accept method
333 // ------------------------------------------------------------------------
334
335 /**
336 * Checks that this class node is compatible with the given ASM API version.
337 * This methods checks that this node, and all its nodes recursively, do not
338 * contain elements that were introduced in more recent versions of the ASM
339 * API than the given version.
340 *
341 * @param api
342 * an ASM API version. Must be one of {@link Opcodes#ASM4},
343 * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
344 */
345 public void check(final int api) {
346 if (api == Opcodes.ASM4) {
347 if (visibleTypeAnnotations != null
348 && visibleTypeAnnotations.size() > 0) {
349 throw new RuntimeException();
350 }
351 if (invisibleTypeAnnotations != null
352 && invisibleTypeAnnotations.size() > 0) {
353 throw new RuntimeException();
354 }
355 for (FieldNode f : fields) {
356 f.check(api);
357 }
358 for (MethodNode m : methods) {
359 m.check(api);
360 }
361 }
362 }
363
364 /**
365 * Makes the given class visitor visit this class.
366 *
367 * @param cv
368 * a class visitor.
369 */
370 public void accept(final ClassVisitor cv) {
371 // visits header
372 String[] interfaces = new String[this.interfaces.size()];
373 this.interfaces.toArray(interfaces);
374 cv.visit(version, access, name, signature, superName, interfaces);
375 // visits source
376 if (sourceFile != null || sourceDebug != null) {
377 cv.visitSource(sourceFile, sourceDebug);
378 }
379 // visits outer class
380 if (outerClass != null) {
381 cv.visitOuterClass(outerClass, outerMethod, outerMethodDesc);
382 }
383 // visits attributes
384 int i, n;
385 n = visibleAnnotations == null ? 0 : visibleAnnotations.size();
386 for (i = 0; i < n; ++i) {
387 AnnotationNode an = visibleAnnotations.get(i);
388 an.accept(cv.visitAnnotation(an.desc, true));
389 }
390 n = invisibleAnnotations == null ? 0 : invisibleAnnotations.size();
391 for (i = 0; i < n; ++i) {
392 AnnotationNode an = invisibleAnnotations.get(i);
393 an.accept(cv.visitAnnotation(an.desc, false));
394 }
395 n = visibleTypeAnnotations == null ? 0 : visibleTypeAnnotations.size();
396 for (i = 0; i < n; ++i) {
397 TypeAnnotationNode an = visibleTypeAnnotations.get(i);
398 an.accept(cv.visitTypeAnnotation(an.typeRef, an.typePath, an.desc,
399 true));
400 }
401 n = invisibleTypeAnnotations == null ? 0 : invisibleTypeAnnotations
402 .size();
403 for (i = 0; i < n; ++i) {
404 TypeAnnotationNode an = invisibleTypeAnnotations.get(i);
405 an.accept(cv.visitTypeAnnotation(an.typeRef, an.typePath, an.desc,
406 false));
407 }
408 n = attrs == null ? 0 : attrs.size();
409 for (i = 0; i < n; ++i) {
410 cv.visitAttribute(attrs.get(i));
411 }
412 // visits inner classes
413 for (i = 0; i < innerClasses.size(); ++i) {
414 innerClasses.get(i).accept(cv);
415 }
416 // visits fields
417 for (i = 0; i < fields.size(); ++i) {
418 fields.get(i).accept(cv);
419 }
420 // visits methods
421 for (i = 0; i < methods.size(); ++i) {
422 methods.get(i).accept(cv);
423 }
424 // visits end
425 cv.visitEnd();
426 }
48 /**
49 * The class version. The minor version is stored in the 16 most significant bits, and the major
50 * version in the 16 least significant bits.
51 */
52 public int version;
53
54 /**
55 * The class's access flags (see {@link org.eclipse.persistence.internal.libraries.asm.Opcodes}). This field also indicates if
56 * the class is deprecated.
57 */
58 public int access;
59
60 /** The internal name of this class (see {@link org.eclipse.persistence.internal.libraries.asm.Type#getInternalName}). */
61 public String name;
62
63 /** The signature of this class. May be <tt>null</tt>. */
64 public String signature;
65
66 /**
67 * The internal of name of the super class (see {@link org.eclipse.persistence.internal.libraries.asm.Type#getInternalName}).
68 * For interfaces, the super class is {@link Object}. May be <tt>null</tt>, but only for the
69 * {@link Object} class.
70 */
71 public String superName;
72
73 /**
74 * The internal names of the interfaces directly implemented by this class (see {@link
75 * org.eclipse.persistence.internal.libraries.asm.Type#getInternalName}).
76 */
77 public List<String> interfaces;
78
79 /** The name of the source file from which this class was compiled. May be <tt>null</tt>. */
80 public String sourceFile;
81
82 /**
83 * The correspondence between source and compiled elements of this class. May be <tt>null</tt>.
84 */
85 public String sourceDebug;
86
87 /** The module stored in this class. May be <tt>null</tt>. */
88 public ModuleNode module;
89
90 /** The internal name of the enclosing class of this class. May be <tt>null</tt>. */
91 public String outerClass;
92
93 /**
94 * The name of the method that contains this class, or <tt>null</tt> if this class is not enclosed
95 * in a method.
96 */
97 public String outerMethod;
98
99 /**
100 * The descriptor of the method that contains this class, or <tt>null</tt> if this class is not
101 * enclosed in a method.
102 */
103 public String outerMethodDesc;
104
105 /** The runtime visible annotations of this class. May be <tt>null</tt>. */
106 public List<AnnotationNode> visibleAnnotations;
107
108 /** The runtime invisible annotations of this class. May be <tt>null</tt>. */
109 public List<AnnotationNode> invisibleAnnotations;
110
111 /** The runtime visible type annotations of this class. May be <tt>null</tt>. */
112 public List<TypeAnnotationNode> visibleTypeAnnotations;
113
114 /** The runtime invisible type annotations of this class. May be <tt>null</tt>. */
115 public List<TypeAnnotationNode> invisibleTypeAnnotations;
116
117 /** The non standard attributes of this class. May be <tt>null</tt>. */
118 public List<Attribute> attrs;
119
120 /** The inner classes of this class. */
121 public List<InnerClassNode> innerClasses;
122
123 /** The fields of this class. */
124 public List<FieldNode> fields;
125
126 /** The methods of this class. */
127 public List<MethodNode> methods;
128
129 /**
130 * Constructs a new {@link ClassNode}. <i>Subclasses must not use this constructor</i>. Instead,
131 * they must use the {@link #ClassNode(int)} version.
132 *
133 * @throws IllegalStateException If a subclass calls this constructor.
134 */
135 public ClassNode() {
136 this(Opcodes.ASM6);
137 if (getClass() != ClassNode.class) {
138 throw new IllegalStateException();
139 }
140 }
141
142 /**
143 * Constructs a new {@link ClassNode}.
144 *
145 * @param api the ASM API version implemented by this visitor. Must be one of {@link
146 * Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
147 */
148 public ClassNode(final int api) {
149 super(api);
150 this.interfaces = new ArrayList<String>();
151 this.innerClasses = new ArrayList<InnerClassNode>();
152 this.fields = new ArrayList<FieldNode>();
153 this.methods = new ArrayList<MethodNode>();
154 }
155
156 // -----------------------------------------------------------------------------------------------
157 // Implementation of the ClassVisitor abstract class
158 // -----------------------------------------------------------------------------------------------
159
160 @Override
161 public void visit(
162 final int version,
163 final int access,
164 final String name,
165 final String signature,
166 final String superName,
167 final String[] interfaces) {
168 this.version = version;
169 this.access = access;
170 this.name = name;
171 this.signature = signature;
172 this.superName = superName;
173 this.interfaces = Util.asArrayList(interfaces);
174 }
175
176 @Override
177 public void visitSource(final String file, final String debug) {
178 sourceFile = file;
179 sourceDebug = debug;
180 }
181
182 @Override
183 public ModuleVisitor visitModule(final String name, final int access, final String version) {
184 module = new ModuleNode(name, access, version);
185 return module;
186 }
187
188 @Override
189 public void visitOuterClass(final String owner, final String name, final String descriptor) {
190 outerClass = owner;
191 outerMethod = name;
192 outerMethodDesc = descriptor;
193 }
194
195 @Override
196 public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
197 AnnotationNode annotation = new AnnotationNode(descriptor);
198 if (visible) {
199 if (visibleAnnotations == null) {
200 visibleAnnotations = new ArrayList<AnnotationNode>(1);
201 }
202 visibleAnnotations.add(annotation);
203 } else {
204 if (invisibleAnnotations == null) {
205 invisibleAnnotations = new ArrayList<AnnotationNode>(1);
206 }
207 invisibleAnnotations.add(annotation);
208 }
209 return annotation;
210 }
211
212 @Override
213 public AnnotationVisitor visitTypeAnnotation(
214 final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
215 TypeAnnotationNode typeAnnotation = new TypeAnnotationNode(typeRef, typePath, descriptor);
216 if (visible) {
217 if (visibleTypeAnnotations == null) {
218 visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
219 }
220 visibleTypeAnnotations.add(typeAnnotation);
221 } else {
222 if (invisibleTypeAnnotations == null) {
223 invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
224 }
225 invisibleTypeAnnotations.add(typeAnnotation);
226 }
227 return typeAnnotation;
228 }
229
230 @Override
231 public void visitAttribute(final Attribute attribute) {
232 if (attrs == null) {
233 attrs = new ArrayList<Attribute>(1);
234 }
235 attrs.add(attribute);
236 }
237
238 @Override
239 public void visitInnerClass(
240 final String name, final String outerName, final String innerName, final int access) {
241 InnerClassNode innerClass = new InnerClassNode(name, outerName, innerName, access);
242 innerClasses.add(innerClass);
243 }
244
245 @Override
246 public FieldVisitor visitField(
247 final int access,
248 final String name,
249 final String descriptor,
250 final String signature,
251 final Object value) {
252 FieldNode field = new FieldNode(access, name, descriptor, signature, value);
253 fields.add(field);
254 return field;
255 }
256
257 @Override
258 public MethodVisitor visitMethod(
259 final int access,
260 final String name,
261 final String descriptor,
262 final String signature,
263 final String[] exceptions) {
264 MethodNode method = new MethodNode(access, name, descriptor, signature, exceptions);
265 methods.add(method);
266 return method;
267 }
268
269 @Override
270 public void visitEnd() {
271 // Nothing to do.
272 }
273
274 // -----------------------------------------------------------------------------------------------
275 // Accept method
276 // -----------------------------------------------------------------------------------------------
277
278 /**
279 * Checks that this class node is compatible with the given ASM API version. This method checks
280 * that this node, and all its children recursively, do not contain elements that were introduced
281 * in more recent versions of the ASM API than the given version.
282 *
283 * @param api an ASM API version. Must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or
284 * {@link Opcodes#ASM6}.
285 */
286 public void check(final int api) {
287 if (api < Opcodes.ASM6 && module != null) {
288 throw new UnsupportedClassVersionException();
289 }
290 if (api < Opcodes.ASM5) {
291 if (visibleTypeAnnotations != null && !visibleTypeAnnotations.isEmpty()) {
292 throw new UnsupportedClassVersionException();
293 }
294 if (invisibleTypeAnnotations != null && !invisibleTypeAnnotations.isEmpty()) {
295 throw new UnsupportedClassVersionException();
296 }
297 }
298 // Check the annotations.
299 if (visibleAnnotations != null) {
300 for (int i = visibleAnnotations.size() - 1; i >= 0; --i) {
301 visibleAnnotations.get(i).check(api);
302 }
303 }
304 if (invisibleAnnotations != null) {
305 for (int i = invisibleAnnotations.size() - 1; i >= 0; --i) {
306 invisibleAnnotations.get(i).check(api);
307 }
308 }
309 if (visibleTypeAnnotations != null) {
310 for (int i = visibleTypeAnnotations.size() - 1; i >= 0; --i) {
311 visibleTypeAnnotations.get(i).check(api);
312 }
313 }
314 if (invisibleTypeAnnotations != null) {
315 for (int i = invisibleTypeAnnotations.size() - 1; i >= 0; --i) {
316 invisibleTypeAnnotations.get(i).check(api);
317 }
318 }
319 for (int i = fields.size() - 1; i >= 0; --i) {
320 fields.get(i).check(api);
321 }
322 for (int i = methods.size() - 1; i >= 0; --i) {
323 methods.get(i).check(api);
324 }
325 }
326
327 /**
328 * Makes the given class visitor visit this class.
329 *
330 * @param classVisitor a class visitor.
331 */
332 public void accept(final ClassVisitor classVisitor) {
333 // Visit the header.
334 String[] interfacesArray = new String[this.interfaces.size()];
335 this.interfaces.toArray(interfacesArray);
336 classVisitor.visit(version, access, name, signature, superName, interfacesArray);
337 // Visit the source.
338 if (sourceFile != null || sourceDebug != null) {
339 classVisitor.visitSource(sourceFile, sourceDebug);
340 }
341 // Visit the module.
342 if (module != null) {
343 module.accept(classVisitor);
344 }
345 // Visit the outer class.
346 if (outerClass != null) {
347 classVisitor.visitOuterClass(outerClass, outerMethod, outerMethodDesc);
348 }
349 // Visit the annotations.
350 if (visibleAnnotations != null) {
351 for (int i = 0, n = visibleAnnotations.size(); i < n; ++i) {
352 AnnotationNode annotation = visibleAnnotations.get(i);
353 annotation.accept(classVisitor.visitAnnotation(annotation.desc, true));
354 }
355 }
356 if (invisibleAnnotations != null) {
357 for (int i = 0, n = invisibleAnnotations.size(); i < n; ++i) {
358 AnnotationNode annotation = invisibleAnnotations.get(i);
359 annotation.accept(classVisitor.visitAnnotation(annotation.desc, false));
360 }
361 }
362 if (visibleTypeAnnotations != null) {
363 for (int i = 0, n = visibleTypeAnnotations.size(); i < n; ++i) {
364 TypeAnnotationNode typeAnnotation = visibleTypeAnnotations.get(i);
365 typeAnnotation.accept(
366 classVisitor.visitTypeAnnotation(
367 typeAnnotation.typeRef, typeAnnotation.typePath, typeAnnotation.desc, true));
368 }
369 }
370 if (invisibleTypeAnnotations != null) {
371 for (int i = 0, n = invisibleTypeAnnotations.size(); i < n; ++i) {
372 TypeAnnotationNode typeAnnotation = invisibleTypeAnnotations.get(i);
373 typeAnnotation.accept(
374 classVisitor.visitTypeAnnotation(
375 typeAnnotation.typeRef, typeAnnotation.typePath, typeAnnotation.desc, false));
376 }
377 }
378 // Visit the non standard attributes.
379 if (attrs != null) {
380 for (int i = 0, n = attrs.size(); i < n; ++i) {
381 classVisitor.visitAttribute(attrs.get(i));
382 }
383 }
384 // Visit the inner classes.
385 for (int i = 0, n = innerClasses.size(); i < n; ++i) {
386 innerClasses.get(i).accept(classVisitor);
387 }
388 // Visit the fields.
389 for (int i = 0, n = fields.size(); i < n; ++i) {
390 fields.get(i).accept(classVisitor);
391 }
392 // Visit the methods.
393 for (int i = 0, n = methods.size(); i < n; ++i) {
394 methods.get(i).accept(classVisitor);
395 }
396 classVisitor.visitEnd();
397 }
427398 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.tree;
3028
3129 import java.util.Map;
3331 import org.eclipse.persistence.internal.libraries.asm.MethodVisitor;
3432
3533 /**
36 * A node that represents a field instruction. A field instruction is an
37 * instruction that loads or stores the value of a field of an object.
38 *
34 * A node that represents a field instruction. A field instruction is an instruction that loads or
35 * stores the value of a field of an object.
36 *
3937 * @author Eric Bruneton
4038 */
4139 public class FieldInsnNode extends AbstractInsnNode {
4240
43 /**
44 * The internal name of the field's owner class (see
45 * {@link org.eclipse.persistence.internal.libraries.asm.Type#getInternalName() getInternalName}).
46 */
47 public String owner;
41 /**
42 * The internal name of the field's owner class (see {@link
43 * org.eclipse.persistence.internal.libraries.asm.Type#getInternalName}).
44 */
45 public String owner;
4846
49 /**
50 * The field's name.
51 */
52 public String name;
47 /** The field's name. */
48 public String name;
5349
54 /**
55 * The field's descriptor (see {@link org.eclipse.persistence.internal.libraries.asm.Type}).
56 */
57 public String desc;
50 /** The field's descriptor (see {@link org.eclipse.persistence.internal.libraries.asm.Type}). */
51 public String desc;
5852
59 /**
60 * Constructs a new {@link FieldInsnNode}.
61 *
62 * @param opcode
63 * the opcode of the type instruction to be constructed. This
64 * opcode must be GETSTATIC, PUTSTATIC, GETFIELD or PUTFIELD.
65 * @param owner
66 * the internal name of the field's owner class (see
67 * {@link org.eclipse.persistence.internal.libraries.asm.Type#getInternalName()
68 * getInternalName}).
69 * @param name
70 * the field's name.
71 * @param desc
72 * the field's descriptor (see {@link org.eclipse.persistence.internal.libraries.asm.Type}).
73 */
74 public FieldInsnNode(final int opcode, final String owner,
75 final String name, final String desc) {
76 super(opcode);
77 this.owner = owner;
78 this.name = name;
79 this.desc = desc;
80 }
53 /**
54 * Constructs a new {@link FieldInsnNode}.
55 *
56 * @param opcode the opcode of the type instruction to be constructed. This opcode must be
57 * GETSTATIC, PUTSTATIC, GETFIELD or PUTFIELD.
58 * @param owner the internal name of the field's owner class (see {@link
59 * org.eclipse.persistence.internal.libraries.asm.Type#getInternalName}).
60 * @param name the field's name.
61 * @param descriptor the field's descriptor (see {@link org.eclipse.persistence.internal.libraries.asm.Type}).
62 */
63 public FieldInsnNode(
64 final int opcode, final String owner, final String name, final String descriptor) {
65 super(opcode);
66 this.owner = owner;
67 this.name = name;
68 this.desc = descriptor;
69 }
8170
82 /**
83 * Sets the opcode of this instruction.
84 *
85 * @param opcode
86 * the new instruction opcode. This opcode must be GETSTATIC,
87 * PUTSTATIC, GETFIELD or PUTFIELD.
88 */
89 public void setOpcode(final int opcode) {
90 this.opcode = opcode;
91 }
71 /**
72 * Sets the opcode of this instruction.
73 *
74 * @param opcode the new instruction opcode. This opcode must be GETSTATIC, PUTSTATIC, GETFIELD or
75 * PUTFIELD.
76 */
77 public void setOpcode(final int opcode) {
78 this.opcode = opcode;
79 }
9280
93 @Override
94 public int getType() {
95 return FIELD_INSN;
96 }
81 @Override
82 public int getType() {
83 return FIELD_INSN;
84 }
9785
98 @Override
99 public void accept(final MethodVisitor mv) {
100 mv.visitFieldInsn(opcode, owner, name, desc);
101 acceptAnnotations(mv);
102 }
86 @Override
87 public void accept(final MethodVisitor methodVisitor) {
88 methodVisitor.visitFieldInsn(opcode, owner, name, desc);
89 acceptAnnotations(methodVisitor);
90 }
10391
104 @Override
105 public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
106 return new FieldInsnNode(opcode, owner, name, desc)
107 .cloneAnnotations(this);
108 }
92 @Override
93 public AbstractInsnNode clone(final Map<LabelNode, LabelNode> clonedLabels) {
94 return new FieldInsnNode(opcode, owner, name, desc).cloneAnnotations(this);
95 }
10996 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.tree;
3028
3129 import java.util.ArrayList;
4038
4139 /**
4240 * A node that represents a field.
43 *
41 *
4442 * @author Eric Bruneton
4543 */
4644 public class FieldNode extends FieldVisitor {
4745
48 /**
49 * The field's access flags (see {@link org.eclipse.persistence.internal.libraries.asm.Opcodes}). This
50 * field also indicates if the field is synthetic and/or deprecated.
51 */
52 public int access;
53
54 /**
55 * The field's name.
56 */
57 public String name;
58
59 /**
60 * The field's descriptor (see {@link org.eclipse.persistence.internal.libraries.asm.Type}).
61 */
62 public String desc;
63
64 /**
65 * The field's signature. May be <tt>null</tt>.
66 */
67 public String signature;
68
69 /**
70 * The field's initial value. This field, which may be <tt>null</tt> if the
71 * field does not have an initial value, must be an {@link Integer}, a
72 * {@link Float}, a {@link Long}, a {@link Double} or a {@link String}.
73 */
74 public Object value;
75
76 /**
77 * The runtime visible annotations of this field. This list is a list of
78 * {@link AnnotationNode} objects. May be <tt>null</tt>.
79 *
80 * @associates org.eclipse.persistence.internal.libraries.asm.tree.AnnotationNode
81 * @label visible
82 */
83 public List<AnnotationNode> visibleAnnotations;
84
85 /**
86 * The runtime invisible annotations of this field. This list is a list of
87 * {@link AnnotationNode} objects. May be <tt>null</tt>.
88 *
89 * @associates org.eclipse.persistence.internal.libraries.asm.tree.AnnotationNode
90 * @label invisible
91 */
92 public List<AnnotationNode> invisibleAnnotations;
93
94 /**
95 * The runtime visible type annotations of this field. This list is a list
96 * of {@link TypeAnnotationNode} objects. May be <tt>null</tt>.
97 *
98 * @associates org.eclipse.persistence.internal.libraries.asm.tree.TypeAnnotationNode
99 * @label visible
100 */
101 public List<TypeAnnotationNode> visibleTypeAnnotations;
102
103 /**
104 * The runtime invisible type annotations of this field. This list is a list
105 * of {@link TypeAnnotationNode} objects. May be <tt>null</tt>.
106 *
107 * @associates org.eclipse.persistence.internal.libraries.asm.tree.TypeAnnotationNode
108 * @label invisible
109 */
110 public List<TypeAnnotationNode> invisibleTypeAnnotations;
111
112 /**
113 * The non standard attributes of this field. This list is a list of
114 * {@link Attribute} objects. May be <tt>null</tt>.
115 *
116 * @associates org.eclipse.persistence.internal.libraries.asm.Attribute
117 */
118 public List<Attribute> attrs;
119
120 /**
121 * Constructs a new {@link FieldNode}. <i>Subclasses must not use this
122 * constructor</i>. Instead, they must use the
123 * {@link #FieldNode(int, int, String, String, String, Object)} version.
124 *
125 * @param access
126 * the field's access flags (see
127 * {@link org.eclipse.persistence.internal.libraries.asm.Opcodes}). This parameter also
128 * indicates if the field is synthetic and/or deprecated.
129 * @param name
130 * the field's name.
131 * @param desc
132 * the field's descriptor (see {@link org.eclipse.persistence.internal.libraries.asm.Type
133 * Type}).
134 * @param signature
135 * the field's signature.
136 * @param value
137 * the field's initial value. This parameter, which may be
138 * <tt>null</tt> if the field does not have an initial value,
139 * must be an {@link Integer}, a {@link Float}, a {@link Long}, a
140 * {@link Double} or a {@link String}.
141 * @throws IllegalStateException
142 * If a subclass calls this constructor.
143 */
144 public FieldNode(final int access, final String name, final String desc,
145 final String signature, final Object value) {
146 this(Opcodes.ASM6, access, name, desc, signature, value);
147 if (getClass() != FieldNode.class) {
148 throw new IllegalStateException();
149 }
150 }
151
152 /**
153 * Constructs a new {@link FieldNode}. <i>Subclasses must not use this
154 * constructor</i>.
155 *
156 * @param api
157 * the ASM API version implemented by this visitor. Must be one
158 * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
159 * @param access
160 * the field's access flags (see
161 * {@link org.eclipse.persistence.internal.libraries.asm.Opcodes}). This parameter also
162 * indicates if the field is synthetic and/or deprecated.
163 * @param name
164 * the field's name.
165 * @param desc
166 * the field's descriptor (see {@link org.eclipse.persistence.internal.libraries.asm.Type
167 * Type}).
168 * @param signature
169 * the field's signature.
170 * @param value
171 * the field's initial value. This parameter, which may be
172 * <tt>null</tt> if the field does not have an initial value,
173 * must be an {@link Integer}, a {@link Float}, a {@link Long}, a
174 * {@link Double} or a {@link String}.
175 */
176 public FieldNode(final int api, final int access, final String name,
177 final String desc, final String signature, final Object value) {
178 super(api);
179 this.access = access;
180 this.name = name;
181 this.desc = desc;
182 this.signature = signature;
183 this.value = value;
184 }
185
186 // ------------------------------------------------------------------------
187 // Implementation of the FieldVisitor abstract class
188 // ------------------------------------------------------------------------
189
190 @Override
191 public AnnotationVisitor visitAnnotation(final String desc,
192 final boolean visible) {
193 AnnotationNode an = new AnnotationNode(desc);
194 if (visible) {
195 if (visibleAnnotations == null) {
196 visibleAnnotations = new ArrayList<AnnotationNode>(1);
197 }
198 visibleAnnotations.add(an);
199 } else {
200 if (invisibleAnnotations == null) {
201 invisibleAnnotations = new ArrayList<AnnotationNode>(1);
202 }
203 invisibleAnnotations.add(an);
204 }
205 return an;
206 }
207
208 @Override
209 public AnnotationVisitor visitTypeAnnotation(int typeRef,
210 TypePath typePath, String desc, boolean visible) {
211 TypeAnnotationNode an = new TypeAnnotationNode(typeRef, typePath, desc);
212 if (visible) {
213 if (visibleTypeAnnotations == null) {
214 visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
215 }
216 visibleTypeAnnotations.add(an);
217 } else {
218 if (invisibleTypeAnnotations == null) {
219 invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
220 }
221 invisibleTypeAnnotations.add(an);
222 }
223 return an;
224 }
225
226 @Override
227 public void visitAttribute(final Attribute attr) {
228 if (attrs == null) {
229 attrs = new ArrayList<Attribute>(1);
230 }
231 attrs.add(attr);
232 }
233
234 @Override
235 public void visitEnd() {
236 }
237
238 // ------------------------------------------------------------------------
239 // Accept methods
240 // ------------------------------------------------------------------------
241
242 /**
243 * Checks that this field node is compatible with the given ASM API version.
244 * This methods checks that this node, and all its nodes recursively, do not
245 * contain elements that were introduced in more recent versions of the ASM
246 * API than the given version.
247 *
248 * @param api
249 * an ASM API version. Must be one of {@link Opcodes#ASM4},
250 * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
251 */
252 public void check(final int api) {
253 if (api == Opcodes.ASM4) {
254 if (visibleTypeAnnotations != null
255 && visibleTypeAnnotations.size() > 0) {
256 throw new RuntimeException();
257 }
258 if (invisibleTypeAnnotations != null
259 && invisibleTypeAnnotations.size() > 0) {
260 throw new RuntimeException();
261 }
262 }
263 }
264
265 /**
266 * Makes the given class visitor visit this field.
267 *
268 * @param cv
269 * a class visitor.
270 */
271 public void accept(final ClassVisitor cv) {
272 FieldVisitor fv = cv.visitField(access, name, desc, signature, value);
273 if (fv == null) {
274 return;
275 }
276 int i, n;
277 n = visibleAnnotations == null ? 0 : visibleAnnotations.size();
278 for (i = 0; i < n; ++i) {
279 AnnotationNode an = visibleAnnotations.get(i);
280 an.accept(fv.visitAnnotation(an.desc, true));
281 }
282 n = invisibleAnnotations == null ? 0 : invisibleAnnotations.size();
283 for (i = 0; i < n; ++i) {
284 AnnotationNode an = invisibleAnnotations.get(i);
285 an.accept(fv.visitAnnotation(an.desc, false));
286 }
287 n = visibleTypeAnnotations == null ? 0 : visibleTypeAnnotations.size();
288 for (i = 0; i < n; ++i) {
289 TypeAnnotationNode an = visibleTypeAnnotations.get(i);
290 an.accept(fv.visitTypeAnnotation(an.typeRef, an.typePath, an.desc,
291 true));
292 }
293 n = invisibleTypeAnnotations == null ? 0 : invisibleTypeAnnotations
294 .size();
295 for (i = 0; i < n; ++i) {
296 TypeAnnotationNode an = invisibleTypeAnnotations.get(i);
297 an.accept(fv.visitTypeAnnotation(an.typeRef, an.typePath, an.desc,
298 false));
299 }
300 n = attrs == null ? 0 : attrs.size();
301 for (i = 0; i < n; ++i) {
302 fv.visitAttribute(attrs.get(i));
303 }
304 fv.visitEnd();
305 }
46 /**
47 * The field's access flags (see {@link org.eclipse.persistence.internal.libraries.asm.Opcodes}). This field also indicates if
48 * the field is synthetic and/or deprecated.
49 */
50 public int access;
51
52 /** The field's name. */
53 public String name;
54
55 /** The field's descriptor (see {@link org.eclipse.persistence.internal.libraries.asm.Type}). */
56 public String desc;
57
58 /** The field's signature. May be <tt>null</tt>. */
59 public String signature;
60
61 /**
62 * The field's initial value. This field, which may be <tt>null</tt> if the field does not have an
63 * initial value, must be an {@link Integer}, a {@link Float}, a {@link Long}, a {@link Double} or
64 * a {@link String}.
65 */
66 public Object value;
67
68 /** The runtime visible annotations of this field. May be <tt>null</tt>. */
69 public List<AnnotationNode> visibleAnnotations;
70
71 /** The runtime invisible annotations of this field. May be <tt>null</tt>. */
72 public List<AnnotationNode> invisibleAnnotations;
73
74 /** The runtime visible type annotations of this field. May be <tt>null</tt>. */
75 public List<TypeAnnotationNode> visibleTypeAnnotations;
76
77 /** The runtime invisible type annotations of this field. May be <tt>null</tt>. */
78 public List<TypeAnnotationNode> invisibleTypeAnnotations;
79
80 /** The non standard attributes of this field. * May be <tt>null</tt>. */
81 public List<Attribute> attrs;
82
83 /**
84 * Constructs a new {@link FieldNode}. <i>Subclasses must not use this constructor</i>. Instead,
85 * they must use the {@link #FieldNode(int, int, String, String, String, Object)} version.
86 *
87 * @param access the field's access flags (see {@link org.eclipse.persistence.internal.libraries.asm.Opcodes}). This parameter
88 * also indicates if the field is synthetic and/or deprecated.
89 * @param name the field's name.
90 * @param descriptor the field's descriptor (see {@link org.eclipse.persistence.internal.libraries.asm.Type}).
91 * @param signature the field's signature.
92 * @param value the field's initial value. This parameter, which may be <tt>null</tt> if the field
93 * does not have an initial value, must be an {@link Integer}, a {@link Float}, a {@link
94 * Long}, a {@link Double} or a {@link String}.
95 * @throws IllegalStateException If a subclass calls this constructor.
96 */
97 public FieldNode(
98 final int access,
99 final String name,
100 final String descriptor,
101 final String signature,
102 final Object value) {
103 this(Opcodes.ASM6, access, name, descriptor, signature, value);
104 if (getClass() != FieldNode.class) {
105 throw new IllegalStateException();
106 }
107 }
108
109 /**
110 * Constructs a new {@link FieldNode}. <i>Subclasses must not use this constructor</i>.
111 *
112 * @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM4}
113 * or {@link Opcodes#ASM5}.
114 * @param access the field's access flags (see {@link org.eclipse.persistence.internal.libraries.asm.Opcodes}). This parameter
115 * also indicates if the field is synthetic and/or deprecated.
116 * @param name the field's name.
117 * @param descriptor the field's descriptor (see {@link org.eclipse.persistence.internal.libraries.asm.Type}).
118 * @param signature the field's signature.
119 * @param value the field's initial value. This parameter, which may be <tt>null</tt> if the field
120 * does not have an initial value, must be an {@link Integer}, a {@link Float}, a {@link
121 * Long}, a {@link Double} or a {@link String}.
122 */
123 public FieldNode(
124 final int api,
125 final int access,
126 final String name,
127 final String descriptor,
128 final String signature,
129 final Object value) {
130 super(api);
131 this.access = access;
132 this.name = name;
133 this.desc = descriptor;
134 this.signature = signature;
135 this.value = value;
136 }
137
138 // -----------------------------------------------------------------------------------------------
139 // Implementation of the FieldVisitor abstract class
140 // -----------------------------------------------------------------------------------------------
141
142 @Override
143 public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
144 AnnotationNode annotation = new AnnotationNode(descriptor);
145 if (visible) {
146 if (visibleAnnotations == null) {
147 visibleAnnotations = new ArrayList<AnnotationNode>(1);
148 }
149 visibleAnnotations.add(annotation);
150 } else {
151 if (invisibleAnnotations == null) {
152 invisibleAnnotations = new ArrayList<AnnotationNode>(1);
153 }
154 invisibleAnnotations.add(annotation);
155 }
156 return annotation;
157 }
158
159 @Override
160 public AnnotationVisitor visitTypeAnnotation(
161 final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
162 TypeAnnotationNode typeAnnotation = new TypeAnnotationNode(typeRef, typePath, descriptor);
163 if (visible) {
164 if (visibleTypeAnnotations == null) {
165 visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
166 }
167 visibleTypeAnnotations.add(typeAnnotation);
168 } else {
169 if (invisibleTypeAnnotations == null) {
170 invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
171 }
172 invisibleTypeAnnotations.add(typeAnnotation);
173 }
174 return typeAnnotation;
175 }
176
177 @Override
178 public void visitAttribute(final Attribute attribute) {
179 if (attrs == null) {
180 attrs = new ArrayList<Attribute>(1);
181 }
182 attrs.add(attribute);
183 }
184
185 @Override
186 public void visitEnd() {
187 // Nothing to do.
188 }
189
190 // -----------------------------------------------------------------------------------------------
191 // Accept methods
192 // -----------------------------------------------------------------------------------------------
193
194 /**
195 * Checks that this field node is compatible with the given ASM API version. This method checks
196 * that this node, and all its children recursively, do not contain elements that were introduced
197 * in more recent versions of the ASM API than the given version.
198 *
199 * @param api an ASM API version. Must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or
200 * {@link Opcodes#ASM6}.
201 */
202 public void check(final int api) {
203 if (api == Opcodes.ASM4) {
204 if (visibleTypeAnnotations != null && !visibleTypeAnnotations.isEmpty()) {
205 throw new UnsupportedClassVersionException();
206 }
207 if (invisibleTypeAnnotations != null && !invisibleTypeAnnotations.isEmpty()) {
208 throw new UnsupportedClassVersionException();
209 }
210 }
211 }
212
213 /**
214 * Makes the given class visitor visit this field.
215 *
216 * @param classVisitor a class visitor.
217 */
218 public void accept(final ClassVisitor classVisitor) {
219 FieldVisitor fieldVisitor = classVisitor.visitField(access, name, desc, signature, value);
220 if (fieldVisitor == null) {
221 return;
222 }
223 // Visit the annotations.
224 if (visibleAnnotations != null) {
225 for (int i = 0, n = visibleAnnotations.size(); i < n; ++i) {
226 AnnotationNode annotation = visibleAnnotations.get(i);
227 annotation.accept(fieldVisitor.visitAnnotation(annotation.desc, true));
228 }
229 }
230 if (invisibleAnnotations != null) {
231 for (int i = 0, n = invisibleAnnotations.size(); i < n; ++i) {
232 AnnotationNode annotation = invisibleAnnotations.get(i);
233 annotation.accept(fieldVisitor.visitAnnotation(annotation.desc, false));
234 }
235 }
236 if (visibleTypeAnnotations != null) {
237 for (int i = 0, n = visibleTypeAnnotations.size(); i < n; ++i) {
238 TypeAnnotationNode typeAnnotation = visibleTypeAnnotations.get(i);
239 typeAnnotation.accept(
240 fieldVisitor.visitTypeAnnotation(
241 typeAnnotation.typeRef, typeAnnotation.typePath, typeAnnotation.desc, true));
242 }
243 }
244 if (invisibleTypeAnnotations != null) {
245 for (int i = 0, n = invisibleTypeAnnotations.size(); i < n; ++i) {
246 TypeAnnotationNode typeAnnotation = invisibleTypeAnnotations.get(i);
247 typeAnnotation.accept(
248 fieldVisitor.visitTypeAnnotation(
249 typeAnnotation.typeRef, typeAnnotation.typePath, typeAnnotation.desc, false));
250 }
251 }
252 // Visit the non standard attributes.
253 if (attrs != null) {
254 for (int i = 0, n = attrs.size(); i < n; ++i) {
255 fieldVisitor.visitAttribute(attrs.get(i));
256 }
257 }
258 fieldVisitor.visitEnd();
259 }
306260 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.tree;
3028
3129 import java.util.ArrayList;
32 import java.util.Arrays;
3330 import java.util.List;
3431 import java.util.Map;
3532
3734 import org.eclipse.persistence.internal.libraries.asm.Opcodes;
3835
3936 /**
40 * A node that represents a stack map frame. These nodes are pseudo instruction
41 * nodes in order to be inserted in an instruction list. In fact these nodes
42 * must(*) be inserted <i>just before</i> any instruction node <b>i</b> that
43 * follows an unconditionnal branch instruction such as GOTO or THROW, that is
44 * the target of a jump instruction, or that starts an exception handler block.
45 * The stack map frame types must describe the values of the local variables and
46 * of the operand stack elements <i>just before</i> <b>i</b> is executed. <br>
37 * A node that represents a stack map frame. These nodes are pseudo instruction nodes in order to be
38 * inserted in an instruction list. In fact these nodes must(*) be inserted <i>just before</i> any
39 * instruction node <b>i</b> that follows an unconditionnal branch instruction such as GOTO or
40 * THROW, that is the target of a jump instruction, or that starts an exception handler block. The
41 * stack map frame types must describe the values of the local variables and of the operand stack
42 * elements <i>just before</i> <b>i</b> is executed. <br>
4743 * <br>
48 * (*) this is mandatory only for classes whose version is greater than or equal
49 * to {@link Opcodes#V1_6 V1_6}.
50 *
44 * (*) this is mandatory only for classes whose version is greater than or equal to {@link
45 * Opcodes#V1_6}.
46 *
5147 * @author Eric Bruneton
5248 */
5349 public class FrameNode extends AbstractInsnNode {
5450
55 /**
56 * The type of this frame. Must be {@link Opcodes#F_NEW} for expanded
57 * frames, or {@link Opcodes#F_FULL}, {@link Opcodes#F_APPEND},
58 * {@link Opcodes#F_CHOP}, {@link Opcodes#F_SAME} or
59 * {@link Opcodes#F_APPEND}, {@link Opcodes#F_SAME1} for compressed frames.
60 */
61 public int type;
51 /**
52 * The type of this frame. Must be {@link Opcodes#F_NEW} for expanded frames, or {@link
53 * Opcodes#F_FULL}, {@link Opcodes#F_APPEND}, {@link Opcodes#F_CHOP}, {@link Opcodes#F_SAME} or
54 * {@link Opcodes#F_APPEND}, {@link Opcodes#F_SAME1} for compressed frames.
55 */
56 public int type;
6257
63 /**
64 * The types of the local variables of this stack map frame. Elements of
65 * this list can be Integer, String or LabelNode objects (for primitive,
66 * reference and uninitialized types respectively - see
67 * {@link MethodVisitor}).
68 */
69 public List<Object> local;
58 /**
59 * The types of the local variables of this stack map frame. Elements of this list can be Integer,
60 * String or LabelNode objects (for primitive, reference and uninitialized types respectively -
61 * see {@link MethodVisitor}).
62 */
63 public List<Object> local;
7064
71 /**
72 * The types of the operand stack elements of this stack map frame. Elements
73 * of this list can be Integer, String or LabelNode objects (for primitive,
74 * reference and uninitialized types respectively - see
75 * {@link MethodVisitor}).
76 */
77 public List<Object> stack;
65 /**
66 * The types of the operand stack elements of this stack map frame. Elements of this list can be
67 * Integer, String or LabelNode objects (for primitive, reference and uninitialized types
68 * respectively - see {@link MethodVisitor}).
69 */
70 public List<Object> stack;
7871
79 private FrameNode() {
80 super(-1);
72 private FrameNode() {
73 super(-1);
74 }
75
76 /**
77 * Constructs a new {@link FrameNode}.
78 *
79 * @param type the type of this frame. Must be {@link Opcodes#F_NEW} for expanded frames, or
80 * {@link Opcodes#F_FULL}, {@link Opcodes#F_APPEND}, {@link Opcodes#F_CHOP}, {@link
81 * Opcodes#F_SAME} or {@link Opcodes#F_APPEND}, {@link Opcodes#F_SAME1} for compressed frames.
82 * @param nLocal number of local variables of this stack map frame.
83 * @param local the types of the local variables of this stack map frame. Elements of this list
84 * can be Integer, String or LabelNode objects (for primitive, reference and uninitialized
85 * types respectively - see {@link MethodVisitor}).
86 * @param nStack number of operand stack elements of this stack map frame.
87 * @param stack the types of the operand stack elements of this stack map frame. Elements of this
88 * list can be Integer, String or LabelNode objects (for primitive, reference and
89 * uninitialized types respectively - see {@link MethodVisitor}).
90 */
91 public FrameNode(
92 final int type,
93 final int nLocal,
94 final Object[] local,
95 final int nStack,
96 final Object[] stack) {
97 super(-1);
98 this.type = type;
99 switch (type) {
100 case Opcodes.F_NEW:
101 case Opcodes.F_FULL:
102 this.local = Util.asArrayList(nLocal, local);
103 this.stack = Util.asArrayList(nStack, stack);
104 break;
105 case Opcodes.F_APPEND:
106 this.local = Util.asArrayList(nLocal, local);
107 break;
108 case Opcodes.F_CHOP:
109 this.local = Util.asArrayList(nLocal);
110 break;
111 case Opcodes.F_SAME:
112 break;
113 case Opcodes.F_SAME1:
114 this.stack = Util.asArrayList(1, stack);
115 break;
116 default:
117 throw new IllegalArgumentException();
81118 }
119 }
82120
83 /**
84 * Constructs a new {@link FrameNode}.
85 *
86 * @param type
87 * the type of this frame. Must be {@link Opcodes#F_NEW} for
88 * expanded frames, or {@link Opcodes#F_FULL},
89 * {@link Opcodes#F_APPEND}, {@link Opcodes#F_CHOP},
90 * {@link Opcodes#F_SAME} or {@link Opcodes#F_APPEND},
91 * {@link Opcodes#F_SAME1} for compressed frames.
92 * @param nLocal
93 * number of local variables of this stack map frame.
94 * @param local
95 * the types of the local variables of this stack map frame.
96 * Elements of this list can be Integer, String or LabelNode
97 * objects (for primitive, reference and uninitialized types
98 * respectively - see {@link MethodVisitor}).
99 * @param nStack
100 * number of operand stack elements of this stack map frame.
101 * @param stack
102 * the types of the operand stack elements of this stack map
103 * frame. Elements of this list can be Integer, String or
104 * LabelNode objects (for primitive, reference and uninitialized
105 * types respectively - see {@link MethodVisitor}).
106 */
107 public FrameNode(final int type, final int nLocal, final Object[] local,
108 final int nStack, final Object[] stack) {
109 super(-1);
110 this.type = type;
111 switch (type) {
112 case Opcodes.F_NEW:
113 case Opcodes.F_FULL:
114 this.local = asList(nLocal, local);
115 this.stack = asList(nStack, stack);
116 break;
117 case Opcodes.F_APPEND:
118 this.local = asList(nLocal, local);
119 break;
120 case Opcodes.F_CHOP:
121 this.local = Arrays.asList(new Object[nLocal]);
122 break;
123 case Opcodes.F_SAME:
124 break;
125 case Opcodes.F_SAME1:
126 this.stack = asList(1, stack);
127 break;
121 @Override
122 public int getType() {
123 return FRAME;
124 }
125
126 @Override
127 public void accept(final MethodVisitor methodVisitor) {
128 switch (type) {
129 case Opcodes.F_NEW:
130 case Opcodes.F_FULL:
131 methodVisitor.visitFrame(type, local.size(), asArray(local), stack.size(), asArray(stack));
132 break;
133 case Opcodes.F_APPEND:
134 methodVisitor.visitFrame(type, local.size(), asArray(local), 0, null);
135 break;
136 case Opcodes.F_CHOP:
137 methodVisitor.visitFrame(type, local.size(), null, 0, null);
138 break;
139 case Opcodes.F_SAME:
140 methodVisitor.visitFrame(type, 0, null, 0, null);
141 break;
142 case Opcodes.F_SAME1:
143 methodVisitor.visitFrame(type, 0, null, 1, asArray(stack));
144 break;
145 default:
146 throw new IllegalArgumentException();
147 }
148 }
149
150 @Override
151 public AbstractInsnNode clone(final Map<LabelNode, LabelNode> clonedLabels) {
152 FrameNode clone = new FrameNode();
153 clone.type = type;
154 if (local != null) {
155 clone.local = new ArrayList<Object>();
156 for (int i = 0, n = local.size(); i < n; ++i) {
157 Object localElement = local.get(i);
158 if (localElement instanceof LabelNode) {
159 localElement = clonedLabels.get(localElement);
128160 }
161 clone.local.add(localElement);
162 }
129163 }
164 if (stack != null) {
165 clone.stack = new ArrayList<Object>();
166 for (int i = 0, n = stack.size(); i < n; ++i) {
167 Object stackElement = stack.get(i);
168 if (stackElement instanceof LabelNode) {
169 stackElement = clonedLabels.get(stackElement);
170 }
171 clone.stack.add(stackElement);
172 }
173 }
174 return clone;
175 }
130176
131 @Override
132 public int getType() {
133 return FRAME;
177 private static Object[] asArray(final List<Object> list) {
178 Object[] array = new Object[list.size()];
179 for (int i = 0, n = array.length; i < n; ++i) {
180 Object o = list.get(i);
181 if (o instanceof LabelNode) {
182 o = ((LabelNode) o).getLabel();
183 }
184 array[i] = o;
134185 }
135
136 /**
137 * Makes the given visitor visit this stack map frame.
138 *
139 * @param mv
140 * a method visitor.
141 */
142 @Override
143 public void accept(final MethodVisitor mv) {
144 switch (type) {
145 case Opcodes.F_NEW:
146 case Opcodes.F_FULL:
147 mv.visitFrame(type, local.size(), asArray(local), stack.size(),
148 asArray(stack));
149 break;
150 case Opcodes.F_APPEND:
151 mv.visitFrame(type, local.size(), asArray(local), 0, null);
152 break;
153 case Opcodes.F_CHOP:
154 mv.visitFrame(type, local.size(), null, 0, null);
155 break;
156 case Opcodes.F_SAME:
157 mv.visitFrame(type, 0, null, 0, null);
158 break;
159 case Opcodes.F_SAME1:
160 mv.visitFrame(type, 0, null, 1, asArray(stack));
161 break;
162 }
163 }
164
165 @Override
166 public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
167 FrameNode clone = new FrameNode();
168 clone.type = type;
169 if (local != null) {
170 clone.local = new ArrayList<Object>();
171 for (int i = 0; i < local.size(); ++i) {
172 Object l = local.get(i);
173 if (l instanceof LabelNode) {
174 l = labels.get(l);
175 }
176 clone.local.add(l);
177 }
178 }
179 if (stack != null) {
180 clone.stack = new ArrayList<Object>();
181 for (int i = 0; i < stack.size(); ++i) {
182 Object s = stack.get(i);
183 if (s instanceof LabelNode) {
184 s = labels.get(s);
185 }
186 clone.stack.add(s);
187 }
188 }
189 return clone;
190 }
191
192 // ------------------------------------------------------------------------
193
194 private static List<Object> asList(final int n, final Object[] o) {
195 return Arrays.asList(o).subList(0, n);
196 }
197
198 private static Object[] asArray(final List<Object> l) {
199 Object[] objs = new Object[l.size()];
200 for (int i = 0; i < objs.length; ++i) {
201 Object o = l.get(i);
202 if (o instanceof LabelNode) {
203 o = ((LabelNode) o).getLabel();
204 }
205 objs[i] = o;
206 }
207 return objs;
208 }
186 return array;
187 }
209188 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.tree;
3028
3129 import java.util.Map;
3533
3634 /**
3735 * A node that represents an IINC instruction.
38 *
36 *
3937 * @author Eric Bruneton
4038 */
4139 public class IincInsnNode extends AbstractInsnNode {
4240
43 /**
44 * Index of the local variable to be incremented.
45 */
46 public int var;
41 /** Index of the local variable to be incremented. */
42 public int var;
4743
48 /**
49 * Amount to increment the local variable by.
50 */
51 public int incr;
44 /** Amount to increment the local variable by. */
45 public int incr;
5246
53 /**
54 * Constructs a new {@link IincInsnNode}.
55 *
56 * @param var
57 * index of the local variable to be incremented.
58 * @param incr
59 * increment amount to increment the local variable by.
60 */
61 public IincInsnNode(final int var, final int incr) {
62 super(Opcodes.IINC);
63 this.var = var;
64 this.incr = incr;
65 }
47 /**
48 * Constructs a new {@link IincInsnNode}.
49 *
50 * @param var index of the local variable to be incremented.
51 * @param incr increment amount to increment the local variable by.
52 */
53 public IincInsnNode(final int var, final int incr) {
54 super(Opcodes.IINC);
55 this.var = var;
56 this.incr = incr;
57 }
6658
67 @Override
68 public int getType() {
69 return IINC_INSN;
70 }
59 @Override
60 public int getType() {
61 return IINC_INSN;
62 }
7163
72 @Override
73 public void accept(final MethodVisitor mv) {
74 mv.visitIincInsn(var, incr);
75 acceptAnnotations(mv);
76 }
64 @Override
65 public void accept(final MethodVisitor methodVisitor) {
66 methodVisitor.visitIincInsn(var, incr);
67 acceptAnnotations(methodVisitor);
68 }
7769
78 @Override
79 public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
80 return new IincInsnNode(var, incr).cloneAnnotations(this);
81 }
82 }
70 @Override
71 public AbstractInsnNode clone(final Map<LabelNode, LabelNode> clonedLabels) {
72 return new IincInsnNode(var, incr).cloneAnnotations(this);
73 }
74 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.tree;
3028
3129 import org.eclipse.persistence.internal.libraries.asm.ClassVisitor;
3230
3331 /**
3432 * A node that represents an inner class.
35 *
33 *
3634 * @author Eric Bruneton
3735 */
3836 public class InnerClassNode {
3937
40 /**
41 * The internal name of an inner class (see
42 * {@link org.eclipse.persistence.internal.libraries.asm.Type#getInternalName() getInternalName}).
43 */
44 public String name;
38 /** The internal name of an inner class (see {@link org.eclipse.persistence.internal.libraries.asm.Type#getInternalName()}). */
39 public String name;
4540
46 /**
47 * The internal name of the class to which the inner class belongs (see
48 * {@link org.eclipse.persistence.internal.libraries.asm.Type#getInternalName() getInternalName}). May be
49 * <tt>null</tt>.
50 */
51 public String outerName;
41 /**
42 * The internal name of the class to which the inner class belongs (see {@link
43 * org.eclipse.persistence.internal.libraries.asm.Type#getInternalName()}). May be <tt>null</tt>.
44 */
45 public String outerName;
5246
53 /**
54 * The (simple) name of the inner class inside its enclosing class. May be
55 * <tt>null</tt> for anonymous inner classes.
56 */
57 public String innerName;
47 /**
48 * The (simple) name of the inner class inside its enclosing class. May be <tt>null</tt> for
49 * anonymous inner classes.
50 */
51 public String innerName;
5852
59 /**
60 * The access flags of the inner class as originally declared in the
61 * enclosing class.
62 */
63 public int access;
53 /** The access flags of the inner class as originally declared in the enclosing class. */
54 public int access;
6455
65 /**
66 * Constructs a new {@link InnerClassNode}.
67 *
68 * @param name
69 * the internal name of an inner class (see
70 * {@link org.eclipse.persistence.internal.libraries.asm.Type#getInternalName()
71 * getInternalName}).
72 * @param outerName
73 * the internal name of the class to which the inner class
74 * belongs (see {@link org.eclipse.persistence.internal.libraries.asm.Type#getInternalName()
75 * getInternalName}). May be <tt>null</tt>.
76 * @param innerName
77 * the (simple) name of the inner class inside its enclosing
78 * class. May be <tt>null</tt> for anonymous inner classes.
79 * @param access
80 * the access flags of the inner class as originally declared in
81 * the enclosing class.
82 */
83 public InnerClassNode(final String name, final String outerName,
84 final String innerName, final int access) {
85 this.name = name;
86 this.outerName = outerName;
87 this.innerName = innerName;
88 this.access = access;
89 }
56 /**
57 * Constructs a new {@link InnerClassNode}.
58 *
59 * @param name the internal name of an inner class (see {@link
60 * org.eclipse.persistence.internal.libraries.asm.Type#getInternalName()}).
61 * @param outerName the internal name of the class to which the inner class belongs (see {@link
62 * org.eclipse.persistence.internal.libraries.asm.Type#getInternalName()}). May be <tt>null</tt>.
63 * @param innerName the (simple) name of the inner class inside its enclosing class. May be
64 * <tt>null</tt> for anonymous inner classes.
65 * @param access the access flags of the inner class as originally declared in the enclosing
66 * class.
67 */
68 public InnerClassNode(
69 final String name, final String outerName, final String innerName, final int access) {
70 this.name = name;
71 this.outerName = outerName;
72 this.innerName = innerName;
73 this.access = access;
74 }
9075
91 /**
92 * Makes the given class visitor visit this inner class.
93 *
94 * @param cv
95 * a class visitor.
96 */
97 public void accept(final ClassVisitor cv) {
98 cv.visitInnerClass(name, outerName, innerName, access);
99 }
76 /**
77 * Makes the given class visitor visit this inner class.
78 *
79 * @param classVisitor a class visitor.
80 */
81 public void accept(final ClassVisitor classVisitor) {
82 classVisitor.visitInnerClass(name, outerName, innerName, access);
83 }
10084 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.tree;
3028
3129 import java.util.ListIterator;
3432 import org.eclipse.persistence.internal.libraries.asm.MethodVisitor;
3533
3634 /**
37 * A doubly linked list of {@link AbstractInsnNode} objects. <i>This
38 * implementation is not thread safe</i>.
35 * A doubly linked list of {@link AbstractInsnNode} objects. <i>This implementation is not thread
36 * safe</i>.
3937 */
4038 public class InsnList {
4139
42 /**
43 * The number of instructions in this list.
44 */
45 private int size;
46
47 /**
48 * The first instruction in this list. May be <tt>null</tt>.
49 */
50 private AbstractInsnNode first;
51
52 /**
53 * The last instruction in this list. May be <tt>null</tt>.
54 */
55 private AbstractInsnNode last;
56
57 /**
58 * A cache of the instructions of this list. This cache is used to improve
59 * the performance of the {@link #get} method.
60 */
61 AbstractInsnNode[] cache;
62
63 /**
64 * Returns the number of instructions in this list.
65 *
66 * @return the number of instructions in this list.
67 */
68 public int size() {
69 return size;
70 }
71
72 /**
73 * Returns the first instruction in this list.
74 *
75 * @return the first instruction in this list, or <tt>null</tt> if the list
76 * is empty.
77 */
78 public AbstractInsnNode getFirst() {
79 return first;
80 }
81
82 /**
83 * Returns the last instruction in this list.
84 *
85 * @return the last instruction in this list, or <tt>null</tt> if the list
86 * is empty.
87 */
88 public AbstractInsnNode getLast() {
89 return last;
90 }
91
92 /**
93 * Returns the instruction whose index is given. This method builds a cache
94 * of the instructions in this list to avoid scanning the whole list each
95 * time it is called. Once the cache is built, this method run in constant
96 * time. This cache is invalidated by all the methods that modify the list.
97 *
98 * @param index
99 * the index of the instruction that must be returned.
100 * @return the instruction whose index is given.
101 * @throws IndexOutOfBoundsException
102 * if (index &lt; 0 || index &gt;= size()).
103 */
104 public AbstractInsnNode get(final int index) {
105 if (index < 0 || index >= size) {
106 throw new IndexOutOfBoundsException();
40 /** The number of instructions in this list. */
41 private int size;
42
43 /** The first instruction in this list. May be <tt>null</tt>. */
44 private AbstractInsnNode firstInsn;
45
46 /** The last instruction in this list. May be <tt>null</tt>. */
47 private AbstractInsnNode lastInsn;
48
49 /**
50 * A cache of the instructions of this list. This cache is used to improve the performance of the
51 * {@link #get} method.
52 */
53 AbstractInsnNode[] cache;
54
55 /**
56 * Returns the number of instructions in this list.
57 *
58 * @return the number of instructions in this list.
59 */
60 public int size() {
61 return size;
62 }
63
64 /**
65 * Returns the first instruction in this list.
66 *
67 * @return the first instruction in this list, or <tt>null</tt> if the list is empty.
68 */
69 public AbstractInsnNode getFirst() {
70 return firstInsn;
71 }
72
73 /**
74 * Returns the last instruction in this list.
75 *
76 * @return the last instruction in this list, or <tt>null</tt> if the list is empty.
77 */
78 public AbstractInsnNode getLast() {
79 return lastInsn;
80 }
81
82 /**
83 * Returns the instruction whose index is given. This method builds a cache of the instructions in
84 * this list to avoid scanning the whole list each time it is called. Once the cache is built,
85 * this method runs in constant time. This cache is invalidated by all the methods that modify the
86 * list.
87 *
88 * @param index the index of the instruction that must be returned.
89 * @return the instruction whose index is given.
90 * @throws IndexOutOfBoundsException if (index &lt; 0 || index &gt;= size()).
91 */
92 public AbstractInsnNode get(final int index) {
93 if (index < 0 || index >= size) {
94 throw new IndexOutOfBoundsException();
95 }
96 if (cache == null) {
97 cache = toArray();
98 }
99 return cache[index];
100 }
101
102 /**
103 * Returns <tt>true</tt> if the given instruction belongs to this list. This method always scans
104 * the instructions of this list until it finds the given instruction or reaches the end of the
105 * list.
106 *
107 * @param insnNode an instruction.
108 * @return <tt>true</tt> if the given instruction belongs to this list.
109 */
110 public boolean contains(final AbstractInsnNode insnNode) {
111 AbstractInsnNode currentInsn = firstInsn;
112 while (currentInsn != null && currentInsn != insnNode) {
113 currentInsn = currentInsn.nextInsn;
114 }
115 return currentInsn != null;
116 }
117
118 /**
119 * Returns the index of the given instruction in this list. This method builds a cache of the
120 * instruction indexes to avoid scanning the whole list each time it is called. Once the cache is
121 * built, this method run in constant time. The cache is invalidated by all the methods that
122 * modify the list.
123 *
124 * @param insnNode an instruction <i>of this list</i>.
125 * @return the index of the given instruction in this list. <i>The result of this method is
126 * undefined if the given instruction does not belong to this list</i>. Use {@link #contains }
127 * to test if an instruction belongs to an instruction list or not.
128 */
129 public int indexOf(final AbstractInsnNode insnNode) {
130 if (cache == null) {
131 cache = toArray();
132 }
133 return insnNode.index;
134 }
135
136 /**
137 * Makes the given visitor visit all the instructions in this list.
138 *
139 * @param methodVisitor the method visitor that must visit the instructions.
140 */
141 public void accept(final MethodVisitor methodVisitor) {
142 AbstractInsnNode currentInsn = firstInsn;
143 while (currentInsn != null) {
144 currentInsn.accept(methodVisitor);
145 currentInsn = currentInsn.nextInsn;
146 }
147 }
148
149 /**
150 * Returns an iterator over the instructions in this list.
151 *
152 * @return an iterator over the instructions in this list.
153 */
154 public ListIterator<AbstractInsnNode> iterator() {
155 return iterator(0);
156 }
157
158 /**
159 * Returns an iterator over the instructions in this list.
160 *
161 * @param index index of instruction for the iterator to start at.
162 * @return an iterator over the instructions in this list.
163 */
164 @SuppressWarnings("unchecked")
165 public ListIterator<AbstractInsnNode> iterator(final int index) {
166 return new InsnListIterator(index);
167 }
168
169 /**
170 * Returns an array containing all the instructions in this list.
171 *
172 * @return an array containing all the instructions in this list.
173 */
174 public AbstractInsnNode[] toArray() {
175 int currentInsnIndex = 0;
176 AbstractInsnNode currentInsn = firstInsn;
177 AbstractInsnNode[] insnNodeArray = new AbstractInsnNode[size];
178 while (currentInsn != null) {
179 insnNodeArray[currentInsnIndex] = currentInsn;
180 currentInsn.index = currentInsnIndex++;
181 currentInsn = currentInsn.nextInsn;
182 }
183 return insnNodeArray;
184 }
185
186 /**
187 * Replaces an instruction of this list with another instruction.
188 *
189 * @param oldInsnNode an instruction <i>of this list</i>.
190 * @param newInsnNode another instruction, <i>which must not belong to any {@link InsnList}</i>.
191 */
192 public void set(final AbstractInsnNode oldInsnNode, final AbstractInsnNode newInsnNode) {
193 AbstractInsnNode nextInsn = oldInsnNode.nextInsn;
194 newInsnNode.nextInsn = nextInsn;
195 if (nextInsn != null) {
196 nextInsn.previousInsn = newInsnNode;
197 } else {
198 lastInsn = newInsnNode;
199 }
200 AbstractInsnNode previousInsn = oldInsnNode.previousInsn;
201 newInsnNode.previousInsn = previousInsn;
202 if (previousInsn != null) {
203 previousInsn.nextInsn = newInsnNode;
204 } else {
205 firstInsn = newInsnNode;
206 }
207 if (cache != null) {
208 int index = oldInsnNode.index;
209 cache[index] = newInsnNode;
210 newInsnNode.index = index;
211 } else {
212 newInsnNode.index = 0; // newInnsnNode now belongs to an InsnList.
213 }
214 oldInsnNode.index = -1; // oldInsnNode no longer belongs to an InsnList.
215 oldInsnNode.previousInsn = null;
216 oldInsnNode.nextInsn = null;
217 }
218
219 /**
220 * Adds the given instruction to the end of this list.
221 *
222 * @param insnNode an instruction, <i>which must not belong to any {@link InsnList}</i>.
223 */
224 public void add(final AbstractInsnNode insnNode) {
225 ++size;
226 if (lastInsn == null) {
227 firstInsn = insnNode;
228 lastInsn = insnNode;
229 } else {
230 lastInsn.nextInsn = insnNode;
231 insnNode.previousInsn = lastInsn;
232 }
233 lastInsn = insnNode;
234 cache = null;
235 insnNode.index = 0; // insnNode now belongs to an InsnList.
236 }
237
238 /**
239 * Adds the given instructions to the end of this list.
240 *
241 * @param insnList an instruction list, which is cleared during the process. This list must be
242 * different from 'this'.
243 */
244 public void add(final InsnList insnList) {
245 if (insnList.size == 0) {
246 return;
247 }
248 size += insnList.size;
249 if (lastInsn == null) {
250 firstInsn = insnList.firstInsn;
251 lastInsn = insnList.lastInsn;
252 } else {
253 AbstractInsnNode firstInsnListElement = insnList.firstInsn;
254 lastInsn.nextInsn = firstInsnListElement;
255 firstInsnListElement.previousInsn = lastInsn;
256 lastInsn = insnList.lastInsn;
257 }
258 cache = null;
259 insnList.removeAll(false);
260 }
261
262 /**
263 * Inserts the given instruction at the beginning of this list.
264 *
265 * @param insnNode an instruction, <i>which must not belong to any {@link InsnList}</i>.
266 */
267 public void insert(final AbstractInsnNode insnNode) {
268 ++size;
269 if (firstInsn == null) {
270 firstInsn = insnNode;
271 lastInsn = insnNode;
272 } else {
273 firstInsn.previousInsn = insnNode;
274 insnNode.nextInsn = firstInsn;
275 }
276 firstInsn = insnNode;
277 cache = null;
278 insnNode.index = 0; // insnNode now belongs to an InsnList.
279 }
280
281 /**
282 * Inserts the given instructions at the beginning of this list.
283 *
284 * @param insnList an instruction list, which is cleared during the process. This list must be
285 * different from 'this'.
286 */
287 public void insert(final InsnList insnList) {
288 if (insnList.size == 0) {
289 return;
290 }
291 size += insnList.size;
292 if (firstInsn == null) {
293 firstInsn = insnList.firstInsn;
294 lastInsn = insnList.lastInsn;
295 } else {
296 AbstractInsnNode lastInsnListElement = insnList.lastInsn;
297 firstInsn.previousInsn = lastInsnListElement;
298 lastInsnListElement.nextInsn = firstInsn;
299 firstInsn = insnList.firstInsn;
300 }
301 cache = null;
302 insnList.removeAll(false);
303 }
304
305 /**
306 * Inserts the given instruction after the specified instruction.
307 *
308 * @param previousInsn an instruction <i>of this list</i> after which insnNode must be inserted.
309 * @param insnNode the instruction to be inserted, <i>which must not belong to any {@link
310 * InsnList}</i>.
311 */
312 public void insert(final AbstractInsnNode previousInsn, final AbstractInsnNode insnNode) {
313 ++size;
314 AbstractInsnNode nextInsn = previousInsn.nextInsn;
315 if (nextInsn == null) {
316 lastInsn = insnNode;
317 } else {
318 nextInsn.previousInsn = insnNode;
319 }
320 previousInsn.nextInsn = insnNode;
321 insnNode.nextInsn = nextInsn;
322 insnNode.previousInsn = previousInsn;
323 cache = null;
324 insnNode.index = 0; // insnNode now belongs to an InsnList.
325 }
326
327 /**
328 * Inserts the given instructions after the specified instruction.
329 *
330 * @param previousInsn an instruction <i>of this list</i> after which the instructions must be
331 * inserted.
332 * @param insnList the instruction list to be inserted, which is cleared during the process. This
333 * list must be different from 'this'.
334 */
335 public void insert(final AbstractInsnNode previousInsn, final InsnList insnList) {
336 if (insnList.size == 0) {
337 return;
338 }
339 size += insnList.size;
340 AbstractInsnNode firstInsnListElement = insnList.firstInsn;
341 AbstractInsnNode lastInsnListElement = insnList.lastInsn;
342 AbstractInsnNode nextInsn = previousInsn.nextInsn;
343 if (nextInsn == null) {
344 lastInsn = lastInsnListElement;
345 } else {
346 nextInsn.previousInsn = lastInsnListElement;
347 }
348 previousInsn.nextInsn = firstInsnListElement;
349 lastInsnListElement.nextInsn = nextInsn;
350 firstInsnListElement.previousInsn = previousInsn;
351 cache = null;
352 insnList.removeAll(false);
353 }
354
355 /**
356 * Inserts the given instruction before the specified instruction.
357 *
358 * @param nextInsn an instruction <i>of this list</i> before which insnNode must be inserted.
359 * @param insnNode the instruction to be inserted, <i>which must not belong to any {@link
360 * InsnList}</i>.
361 */
362 public void insertBefore(final AbstractInsnNode nextInsn, final AbstractInsnNode insnNode) {
363 ++size;
364 AbstractInsnNode previousInsn = nextInsn.previousInsn;
365 if (previousInsn == null) {
366 firstInsn = insnNode;
367 } else {
368 previousInsn.nextInsn = insnNode;
369 }
370 nextInsn.previousInsn = insnNode;
371 insnNode.nextInsn = nextInsn;
372 insnNode.previousInsn = previousInsn;
373 cache = null;
374 insnNode.index = 0; // insnNode now belongs to an InsnList.
375 }
376
377 /**
378 * Inserts the given instructions before the specified instruction.
379 *
380 * @param nextInsn an instruction <i>of this list</i> before which the instructions must be
381 * inserted.
382 * @param insnList the instruction list to be inserted, which is cleared during the process. This
383 * list must be different from 'this'.
384 */
385 public void insertBefore(final AbstractInsnNode nextInsn, final InsnList insnList) {
386 if (insnList.size == 0) {
387 return;
388 }
389 size += insnList.size;
390 AbstractInsnNode firstInsnListElement = insnList.firstInsn;
391 AbstractInsnNode lastInsnListElement = insnList.lastInsn;
392 AbstractInsnNode previousInsn = nextInsn.previousInsn;
393 if (previousInsn == null) {
394 firstInsn = firstInsnListElement;
395 } else {
396 previousInsn.nextInsn = firstInsnListElement;
397 }
398 nextInsn.previousInsn = lastInsnListElement;
399 lastInsnListElement.nextInsn = nextInsn;
400 firstInsnListElement.previousInsn = previousInsn;
401 cache = null;
402 insnList.removeAll(false);
403 }
404
405 /**
406 * Removes the given instruction from this list.
407 *
408 * @param insnNode the instruction <i>of this list</i> that must be removed.
409 */
410 public void remove(final AbstractInsnNode insnNode) {
411 --size;
412 AbstractInsnNode nextInsn = insnNode.nextInsn;
413 AbstractInsnNode previousInsn = insnNode.previousInsn;
414 if (nextInsn == null) {
415 if (previousInsn == null) {
416 firstInsn = null;
417 lastInsn = null;
418 } else {
419 previousInsn.nextInsn = null;
420 lastInsn = previousInsn;
421 }
422 } else {
423 if (previousInsn == null) {
424 firstInsn = nextInsn;
425 nextInsn.previousInsn = null;
426 } else {
427 previousInsn.nextInsn = nextInsn;
428 nextInsn.previousInsn = previousInsn;
429 }
430 }
431 cache = null;
432 insnNode.index = -1; // insnNode no longer belongs to an InsnList.
433 insnNode.previousInsn = null;
434 insnNode.nextInsn = null;
435 }
436
437 /**
438 * Removes all the instructions of this list.
439 *
440 * @param mark if the instructions must be marked as no longer belonging to any {@link InsnList}.
441 */
442 void removeAll(final boolean mark) {
443 if (mark) {
444 AbstractInsnNode currentInsn = firstInsn;
445 while (currentInsn != null) {
446 AbstractInsnNode next = currentInsn.nextInsn;
447 currentInsn.index = -1; // currentInsn no longer belongs to an InsnList.
448 currentInsn.previousInsn = null;
449 currentInsn.nextInsn = null;
450 currentInsn = next;
451 }
452 }
453 size = 0;
454 firstInsn = null;
455 lastInsn = null;
456 cache = null;
457 }
458
459 /** Removes all the instructions of this list. */
460 public void clear() {
461 removeAll(false);
462 }
463
464 /**
465 * Resets all the labels in the instruction list. This method should be called before reusing an
466 * instruction list between several <code>ClassWriter</code>s.
467 */
468 public void resetLabels() {
469 AbstractInsnNode currentInsn = firstInsn;
470 while (currentInsn != null) {
471 if (currentInsn instanceof LabelNode) {
472 ((LabelNode) currentInsn).resetLabel();
473 }
474 currentInsn = currentInsn.nextInsn;
475 }
476 }
477
478 // Note: this class is not generified because it would create bridges.
479 @SuppressWarnings("rawtypes")
480 private final class InsnListIterator implements ListIterator {
481
482 AbstractInsnNode nextInsn;
483
484 AbstractInsnNode previousInsn;
485
486 AbstractInsnNode remove;
487
488 InsnListIterator(final int index) {
489 if (index == size()) {
490 nextInsn = null;
491 previousInsn = getLast();
492 } else {
493 nextInsn = get(index);
494 previousInsn = nextInsn.previousInsn;
495 }
496 }
497
498 public boolean hasNext() {
499 return nextInsn != null;
500 }
501
502 public Object next() {
503 if (nextInsn == null) {
504 throw new NoSuchElementException();
505 }
506 AbstractInsnNode result = nextInsn;
507 previousInsn = result;
508 nextInsn = result.nextInsn;
509 remove = result;
510 return result;
511 }
512
513 public void remove() {
514 if (remove != null) {
515 if (remove == nextInsn) {
516 nextInsn = nextInsn.nextInsn;
517 } else {
518 previousInsn = previousInsn.previousInsn;
107519 }
108 if (cache == null) {
109 cache = toArray();
520 InsnList.this.remove(remove);
521 remove = null;
522 } else {
523 throw new IllegalStateException();
524 }
525 }
526
527 public boolean hasPrevious() {
528 return previousInsn != null;
529 }
530
531 public Object previous() {
532 AbstractInsnNode result = previousInsn;
533 nextInsn = result;
534 previousInsn = result.previousInsn;
535 remove = result;
536 return result;
537 }
538
539 public int nextIndex() {
540 if (nextInsn == null) {
541 return size();
542 }
543 if (cache == null) {
544 cache = toArray();
545 }
546 return nextInsn.index;
547 }
548
549 public int previousIndex() {
550 if (previousInsn == null) {
551 return -1;
552 }
553 if (cache == null) {
554 cache = toArray();
555 }
556 return previousInsn.index;
557 }
558
559 public void add(final Object o) {
560 if (nextInsn != null) {
561 InsnList.this.insertBefore(nextInsn, (AbstractInsnNode) o);
562 } else if (previousInsn != null) {
563 InsnList.this.insert(previousInsn, (AbstractInsnNode) o);
564 } else {
565 InsnList.this.add((AbstractInsnNode) o);
566 }
567 previousInsn = (AbstractInsnNode) o;
568 remove = null;
569 }
570
571 public void set(final Object o) {
572 if (remove != null) {
573 InsnList.this.set(remove, (AbstractInsnNode) o);
574 if (remove == previousInsn) {
575 previousInsn = (AbstractInsnNode) o;
576 } else {
577 nextInsn = (AbstractInsnNode) o;
110578 }
111 return cache[index];
112 }
113
114 /**
115 * Returns <tt>true</tt> if the given instruction belongs to this list. This
116 * method always scans the instructions of this list until it finds the
117 * given instruction or reaches the end of the list.
118 *
119 * @param insn
120 * an instruction.
121 * @return <tt>true</tt> if the given instruction belongs to this list.
122 */
123 public boolean contains(final AbstractInsnNode insn) {
124 AbstractInsnNode i = first;
125 while (i != null && i != insn) {
126 i = i.next;
127 }
128 return i != null;
129 }
130
131 /**
132 * Returns the index of the given instruction in this list. This method
133 * builds a cache of the instruction indexes to avoid scanning the whole
134 * list each time it is called. Once the cache is built, this method run in
135 * constant time. The cache is invalidated by all the methods that modify
136 * the list.
137 *
138 * @param insn
139 * an instruction <i>of this list</i>.
140 * @return the index of the given instruction in this list. <i>The result of
141 * this method is undefined if the given instruction does not belong
142 * to this list</i>. Use {@link #contains contains} to test if an
143 * instruction belongs to an instruction list or not.
144 */
145 public int indexOf(final AbstractInsnNode insn) {
146 if (cache == null) {
147 cache = toArray();
148 }
149 return insn.index;
150 }
151
152 /**
153 * Makes the given visitor visit all of the instructions in this list.
154 *
155 * @param mv
156 * the method visitor that must visit the instructions.
157 */
158 public void accept(final MethodVisitor mv) {
159 AbstractInsnNode insn = first;
160 while (insn != null) {
161 insn.accept(mv);
162 insn = insn.next;
163 }
164 }
165
166 /**
167 * Returns an iterator over the instructions in this list.
168 *
169 * @return an iterator over the instructions in this list.
170 */
171 public ListIterator<AbstractInsnNode> iterator() {
172 return iterator(0);
173 }
174
175 /**
176 * Returns an iterator over the instructions in this list.
177 *
178 * @param index
179 * index of instruction for the iterator to start at
180 *
181 * @return an iterator over the instructions in this list.
182 */
183 @SuppressWarnings("unchecked")
184 public ListIterator<AbstractInsnNode> iterator(int index) {
185 return new InsnListIterator(index);
186 }
187
188 /**
189 * Returns an array containing all of the instructions in this list.
190 *
191 * @return an array containing all of the instructions in this list.
192 */
193 public AbstractInsnNode[] toArray() {
194 int i = 0;
195 AbstractInsnNode elem = first;
196 AbstractInsnNode[] insns = new AbstractInsnNode[size];
197 while (elem != null) {
198 insns[i] = elem;
199 elem.index = i++;
200 elem = elem.next;
201 }
202 return insns;
203 }
204
205 /**
206 * Replaces an instruction of this list with another instruction.
207 *
208 * @param location
209 * an instruction <i>of this list</i>.
210 * @param insn
211 * another instruction, <i>which must not belong to any
212 * {@link InsnList}</i>.
213 */
214 public void set(final AbstractInsnNode location, final AbstractInsnNode insn) {
215 AbstractInsnNode next = location.next;
216 insn.next = next;
217 if (next != null) {
218 next.prev = insn;
219 } else {
220 last = insn;
221 }
222 AbstractInsnNode prev = location.prev;
223 insn.prev = prev;
224 if (prev != null) {
225 prev.next = insn;
226 } else {
227 first = insn;
228 }
229 if (cache != null) {
230 int index = location.index;
231 cache[index] = insn;
232 insn.index = index;
233 } else {
234 insn.index = 0; // insn now belongs to an InsnList
235 }
236 location.index = -1; // i no longer belongs to an InsnList
237 location.prev = null;
238 location.next = null;
239 }
240
241 /**
242 * Adds the given instruction to the end of this list.
243 *
244 * @param insn
245 * an instruction, <i>which must not belong to any
246 * {@link InsnList}</i>.
247 */
248 public void add(final AbstractInsnNode insn) {
249 ++size;
250 if (last == null) {
251 first = insn;
252 last = insn;
253 } else {
254 last.next = insn;
255 insn.prev = last;
256 }
257 last = insn;
258 cache = null;
259 insn.index = 0; // insn now belongs to an InsnList
260 }
261
262 /**
263 * Adds the given instructions to the end of this list.
264 *
265 * @param insns
266 * an instruction list, which is cleared during the process. This
267 * list must be different from 'this'.
268 */
269 public void add(final InsnList insns) {
270 if (insns.size == 0) {
271 return;
272 }
273 size += insns.size;
274 if (last == null) {
275 first = insns.first;
276 last = insns.last;
277 } else {
278 AbstractInsnNode elem = insns.first;
279 last.next = elem;
280 elem.prev = last;
281 last = insns.last;
282 }
283 cache = null;
284 insns.removeAll(false);
285 }
286
287 /**
288 * Inserts the given instruction at the begining of this list.
289 *
290 * @param insn
291 * an instruction, <i>which must not belong to any
292 * {@link InsnList}</i>.
293 */
294 public void insert(final AbstractInsnNode insn) {
295 ++size;
296 if (first == null) {
297 first = insn;
298 last = insn;
299 } else {
300 first.prev = insn;
301 insn.next = first;
302 }
303 first = insn;
304 cache = null;
305 insn.index = 0; // insn now belongs to an InsnList
306 }
307
308 /**
309 * Inserts the given instructions at the begining of this list.
310 *
311 * @param insns
312 * an instruction list, which is cleared during the process. This
313 * list must be different from 'this'.
314 */
315 public void insert(final InsnList insns) {
316 if (insns.size == 0) {
317 return;
318 }
319 size += insns.size;
320 if (first == null) {
321 first = insns.first;
322 last = insns.last;
323 } else {
324 AbstractInsnNode elem = insns.last;
325 first.prev = elem;
326 elem.next = first;
327 first = insns.first;
328 }
329 cache = null;
330 insns.removeAll(false);
331 }
332
333 /**
334 * Inserts the given instruction after the specified instruction.
335 *
336 * @param location
337 * an instruction <i>of this list</i> after which insn must be
338 * inserted.
339 * @param insn
340 * the instruction to be inserted, <i>which must not belong to
341 * any {@link InsnList}</i>.
342 */
343 public void insert(final AbstractInsnNode location,
344 final AbstractInsnNode insn) {
345 ++size;
346 AbstractInsnNode next = location.next;
347 if (next == null) {
348 last = insn;
349 } else {
350 next.prev = insn;
351 }
352 location.next = insn;
353 insn.next = next;
354 insn.prev = location;
355 cache = null;
356 insn.index = 0; // insn now belongs to an InsnList
357 }
358
359 /**
360 * Inserts the given instructions after the specified instruction.
361 *
362 * @param location
363 * an instruction <i>of this list</i> after which the
364 * instructions must be inserted.
365 * @param insns
366 * the instruction list to be inserted, which is cleared during
367 * the process. This list must be different from 'this'.
368 */
369 public void insert(final AbstractInsnNode location, final InsnList insns) {
370 if (insns.size == 0) {
371 return;
372 }
373 size += insns.size;
374 AbstractInsnNode ifirst = insns.first;
375 AbstractInsnNode ilast = insns.last;
376 AbstractInsnNode next = location.next;
377 if (next == null) {
378 last = ilast;
379 } else {
380 next.prev = ilast;
381 }
382 location.next = ifirst;
383 ilast.next = next;
384 ifirst.prev = location;
385 cache = null;
386 insns.removeAll(false);
387 }
388
389 /**
390 * Inserts the given instruction before the specified instruction.
391 *
392 * @param location
393 * an instruction <i>of this list</i> before which insn must be
394 * inserted.
395 * @param insn
396 * the instruction to be inserted, <i>which must not belong to
397 * any {@link InsnList}</i>.
398 */
399 public void insertBefore(final AbstractInsnNode location,
400 final AbstractInsnNode insn) {
401 ++size;
402 AbstractInsnNode prev = location.prev;
403 if (prev == null) {
404 first = insn;
405 } else {
406 prev.next = insn;
407 }
408 location.prev = insn;
409 insn.next = location;
410 insn.prev = prev;
411 cache = null;
412 insn.index = 0; // insn now belongs to an InsnList
413 }
414
415 /**
416 * Inserts the given instructions before the specified instruction.
417 *
418 * @param location
419 * an instruction <i>of this list</i> before which the
420 * instructions must be inserted.
421 * @param insns
422 * the instruction list to be inserted, which is cleared during
423 * the process. This list must be different from 'this'.
424 */
425 public void insertBefore(final AbstractInsnNode location,
426 final InsnList insns) {
427 if (insns.size == 0) {
428 return;
429 }
430 size += insns.size;
431 AbstractInsnNode ifirst = insns.first;
432 AbstractInsnNode ilast = insns.last;
433 AbstractInsnNode prev = location.prev;
434 if (prev == null) {
435 first = ifirst;
436 } else {
437 prev.next = ifirst;
438 }
439 location.prev = ilast;
440 ilast.next = location;
441 ifirst.prev = prev;
442 cache = null;
443 insns.removeAll(false);
444 }
445
446 /**
447 * Removes the given instruction from this list.
448 *
449 * @param insn
450 * the instruction <i>of this list</i> that must be removed.
451 */
452 public void remove(final AbstractInsnNode insn) {
453 --size;
454 AbstractInsnNode next = insn.next;
455 AbstractInsnNode prev = insn.prev;
456 if (next == null) {
457 if (prev == null) {
458 first = null;
459 last = null;
460 } else {
461 prev.next = null;
462 last = prev;
463 }
464 } else {
465 if (prev == null) {
466 first = next;
467 next.prev = null;
468 } else {
469 prev.next = next;
470 next.prev = prev;
471 }
472 }
473 cache = null;
474 insn.index = -1; // insn no longer belongs to an InsnList
475 insn.prev = null;
476 insn.next = null;
477 }
478
479 /**
480 * Removes all of the instructions of this list.
481 *
482 * @param mark
483 * if the instructions must be marked as no longer belonging to
484 * any {@link InsnList}.
485 */
486 void removeAll(final boolean mark) {
487 if (mark) {
488 AbstractInsnNode insn = first;
489 while (insn != null) {
490 AbstractInsnNode next = insn.next;
491 insn.index = -1; // insn no longer belongs to an InsnList
492 insn.prev = null;
493 insn.next = null;
494 insn = next;
495 }
496 }
497 size = 0;
498 first = null;
499 last = null;
500 cache = null;
501 }
502
503 /**
504 * Removes all of the instructions of this list.
505 */
506 public void clear() {
507 removeAll(false);
508 }
509
510 /**
511 * Reset all labels in the instruction list. This method should be called
512 * before reusing same instructions list between several
513 * <code>ClassWriter</code>s.
514 */
515 public void resetLabels() {
516 AbstractInsnNode insn = first;
517 while (insn != null) {
518 if (insn instanceof LabelNode) {
519 ((LabelNode) insn).resetLabel();
520 }
521 insn = insn.next;
522 }
523 }
524
525 // this class is not generified because it will create bridges
526 @SuppressWarnings("rawtypes")
527 private final class InsnListIterator implements ListIterator {
528
529 AbstractInsnNode next;
530
531 AbstractInsnNode prev;
532
533 AbstractInsnNode remove;
534
535 InsnListIterator(int index) {
536 if (index == size()) {
537 next = null;
538 prev = getLast();
539 } else {
540 next = get(index);
541 prev = next.prev;
542 }
543 }
544
545 public boolean hasNext() {
546 return next != null;
547 }
548
549 public Object next() {
550 if (next == null) {
551 throw new NoSuchElementException();
552 }
553 AbstractInsnNode result = next;
554 prev = result;
555 next = result.next;
556 remove = result;
557 return result;
558 }
559
560 public void remove() {
561 if (remove != null) {
562 if (remove == next) {
563 next = next.next;
564 } else {
565 prev = prev.prev;
566 }
567 InsnList.this.remove(remove);
568 remove = null;
569 } else {
570 throw new IllegalStateException();
571 }
572 }
573
574 public boolean hasPrevious() {
575 return prev != null;
576 }
577
578 public Object previous() {
579 AbstractInsnNode result = prev;
580 next = result;
581 prev = result.prev;
582 remove = result;
583 return result;
584 }
585
586 public int nextIndex() {
587 if (next == null) {
588 return size();
589 }
590 if (cache == null) {
591 cache = toArray();
592 }
593 return next.index;
594 }
595
596 public int previousIndex() {
597 if (prev == null) {
598 return -1;
599 }
600 if (cache == null) {
601 cache = toArray();
602 }
603 return prev.index;
604 }
605
606 public void add(Object o) {
607 if (next != null) {
608 InsnList.this.insertBefore(next, (AbstractInsnNode) o);
609 } else if (prev != null) {
610 InsnList.this.insert(prev, (AbstractInsnNode) o);
611 } else {
612 InsnList.this.add((AbstractInsnNode) o);
613 }
614 prev = (AbstractInsnNode) o;
615 remove = null;
616 }
617
618 public void set(Object o) {
619 if (remove != null) {
620 InsnList.this.set(remove, (AbstractInsnNode) o);
621 if (remove == prev) {
622 prev = (AbstractInsnNode) o;
623 } else {
624 next = (AbstractInsnNode) o;
625 }
626 } else {
627 throw new IllegalStateException();
628 }
629 }
630 }
579 } else {
580 throw new IllegalStateException();
581 }
582 }
583 }
631584 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.tree;
3028
3129 import java.util.Map;
3432
3533 /**
3634 * A node that represents a zero operand instruction.
37 *
35 *
3836 * @author Eric Bruneton
3937 */
4038 public class InsnNode extends AbstractInsnNode {
4139
42 /**
43 * Constructs a new {@link InsnNode}.
44 *
45 * @param opcode
46 * the opcode of the instruction to be constructed. This opcode
47 * must be NOP, ACONST_NULL, ICONST_M1, ICONST_0, ICONST_1,
48 * ICONST_2, ICONST_3, ICONST_4, ICONST_5, LCONST_0, LCONST_1,
49 * FCONST_0, FCONST_1, FCONST_2, DCONST_0, DCONST_1, IALOAD,
50 * LALOAD, FALOAD, DALOAD, AALOAD, BALOAD, CALOAD, SALOAD,
51 * IASTORE, LASTORE, FASTORE, DASTORE, AASTORE, BASTORE, CASTORE,
52 * SASTORE, POP, POP2, DUP, DUP_X1, DUP_X2, DUP2, DUP2_X1,
53 * DUP2_X2, SWAP, IADD, LADD, FADD, DADD, ISUB, LSUB, FSUB, DSUB,
54 * IMUL, LMUL, FMUL, DMUL, IDIV, LDIV, FDIV, DDIV, IREM, LREM,
55 * FREM, DREM, INEG, LNEG, FNEG, DNEG, ISHL, LSHL, ISHR, LSHR,
56 * IUSHR, LUSHR, IAND, LAND, IOR, LOR, IXOR, LXOR, I2L, I2F, I2D,
57 * L2I, L2F, L2D, F2I, F2L, F2D, D2I, D2L, D2F, I2B, I2C, I2S,
58 * LCMP, FCMPL, FCMPG, DCMPL, DCMPG, IRETURN, LRETURN, FRETURN,
59 * DRETURN, ARETURN, RETURN, ARRAYLENGTH, ATHROW, MONITORENTER,
60 * or MONITOREXIT.
61 */
62 public InsnNode(final int opcode) {
63 super(opcode);
64 }
40 /**
41 * Constructs a new {@link InsnNode}.
42 *
43 * @param opcode the opcode of the instruction to be constructed. This opcode must be NOP,
44 * ACONST_NULL, ICONST_M1, ICONST_0, ICONST_1, ICONST_2, ICONST_3, ICONST_4, ICONST_5,
45 * LCONST_0, LCONST_1, FCONST_0, FCONST_1, FCONST_2, DCONST_0, DCONST_1, IALOAD, LALOAD,
46 * FALOAD, DALOAD, AALOAD, BALOAD, CALOAD, SALOAD, IASTORE, LASTORE, FASTORE, DASTORE,
47 * AASTORE, BASTORE, CASTORE, SASTORE, POP, POP2, DUP, DUP_X1, DUP_X2, DUP2, DUP2_X1, DUP2_X2,
48 * SWAP, IADD, LADD, FADD, DADD, ISUB, LSUB, FSUB, DSUB, IMUL, LMUL, FMUL, DMUL, IDIV, LDIV,
49 * FDIV, DDIV, IREM, LREM, FREM, DREM, INEG, LNEG, FNEG, DNEG, ISHL, LSHL, ISHR, LSHR, IUSHR,
50 * LUSHR, IAND, LAND, IOR, LOR, IXOR, LXOR, I2L, I2F, I2D, L2I, L2F, L2D, F2I, F2L, F2D, D2I,
51 * D2L, D2F, I2B, I2C, I2S, LCMP, FCMPL, FCMPG, DCMPL, DCMPG, IRETURN, LRETURN, FRETURN,
52 * DRETURN, ARETURN, RETURN, ARRAYLENGTH, ATHROW, MONITORENTER, or MONITOREXIT.
53 */
54 public InsnNode(final int opcode) {
55 super(opcode);
56 }
6557
66 @Override
67 public int getType() {
68 return INSN;
69 }
58 @Override
59 public int getType() {
60 return INSN;
61 }
7062
71 /**
72 * Makes the given visitor visit this instruction.
73 *
74 * @param mv
75 * a method visitor.
76 */
77 @Override
78 public void accept(final MethodVisitor mv) {
79 mv.visitInsn(opcode);
80 acceptAnnotations(mv);
81 }
63 @Override
64 public void accept(final MethodVisitor methodVisitor) {
65 methodVisitor.visitInsn(opcode);
66 acceptAnnotations(methodVisitor);
67 }
8268
83 @Override
84 public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
85 return new InsnNode(opcode).cloneAnnotations(this);
86 }
69 @Override
70 public AbstractInsnNode clone(final Map<LabelNode, LabelNode> clonedLabels) {
71 return new InsnNode(opcode).cloneAnnotations(this);
72 }
8773 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.tree;
3028
3129 import java.util.Map;
3432
3533 /**
3634 * A node that represents an instruction with a single int operand.
37 *
35 *
3836 * @author Eric Bruneton
3937 */
4038 public class IntInsnNode extends AbstractInsnNode {
4139
42 /**
43 * The operand of this instruction.
44 */
45 public int operand;
40 /** The operand of this instruction. */
41 public int operand;
4642
47 /**
48 * Constructs a new {@link IntInsnNode}.
49 *
50 * @param opcode
51 * the opcode of the instruction to be constructed. This opcode
52 * must be BIPUSH, SIPUSH or NEWARRAY.
53 * @param operand
54 * the operand of the instruction to be constructed.
55 */
56 public IntInsnNode(final int opcode, final int operand) {
57 super(opcode);
58 this.operand = operand;
59 }
43 /**
44 * Constructs a new {@link IntInsnNode}.
45 *
46 * @param opcode the opcode of the instruction to be constructed. This opcode must be BIPUSH,
47 * SIPUSH or NEWARRAY.
48 * @param operand the operand of the instruction to be constructed.
49 */
50 public IntInsnNode(final int opcode, final int operand) {
51 super(opcode);
52 this.operand = operand;
53 }
6054
61 /**
62 * Sets the opcode of this instruction.
63 *
64 * @param opcode
65 * the new instruction opcode. This opcode must be BIPUSH, SIPUSH
66 * or NEWARRAY.
67 */
68 public void setOpcode(final int opcode) {
69 this.opcode = opcode;
70 }
55 /**
56 * Sets the opcode of this instruction.
57 *
58 * @param opcode the new instruction opcode. This opcode must be BIPUSH, SIPUSH or NEWARRAY.
59 */
60 public void setOpcode(final int opcode) {
61 this.opcode = opcode;
62 }
7163
72 @Override
73 public int getType() {
74 return INT_INSN;
75 }
64 @Override
65 public int getType() {
66 return INT_INSN;
67 }
7668
77 @Override
78 public void accept(final MethodVisitor mv) {
79 mv.visitIntInsn(opcode, operand);
80 acceptAnnotations(mv);
81 }
69 @Override
70 public void accept(final MethodVisitor methodVisitor) {
71 methodVisitor.visitIntInsn(opcode, operand);
72 acceptAnnotations(methodVisitor);
73 }
8274
83 @Override
84 public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
85 return new IntInsnNode(opcode, operand).cloneAnnotations(this);
86 }
75 @Override
76 public AbstractInsnNode clone(final Map<LabelNode, LabelNode> clonedLabels) {
77 return new IntInsnNode(opcode, operand).cloneAnnotations(this);
78 }
8779 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.tree;
3028
3129 import java.util.Map;
3634
3735 /**
3836 * A node that represents an invokedynamic instruction.
39 *
37 *
4038 * @author Remi Forax
4139 */
4240 public class InvokeDynamicInsnNode extends AbstractInsnNode {
4341
44 /**
45 * Invokedynamic name.
46 */
47 public String name;
42 /** The method's name. */
43 public String name;
4844
49 /**
50 * Invokedynamic descriptor.
51 */
52 public String desc;
45 /** The method's descriptor (see {@link org.eclipse.persistence.internal.libraries.asm.Type}). */
46 public String desc;
5347
54 /**
55 * Bootstrap method
56 */
57 public Handle bsm;
48 /** The bootstrap method. */
49 public Handle bsm;
5850
59 /**
60 * Bootstrap constant arguments
61 */
62 public Object[] bsmArgs;
51 /** The bootstrap method constant arguments. */
52 public Object[] bsmArgs;
6353
64 /**
65 * Constructs a new {@link InvokeDynamicInsnNode}.
66 *
67 * @param name
68 * invokedynamic name.
69 * @param desc
70 * invokedynamic descriptor (see {@link org.eclipse.persistence.internal.libraries.asm.Type}).
71 * @param bsm
72 * the bootstrap method.
73 * @param bsmArgs
74 * the boostrap constant arguments.
75 */
76 public InvokeDynamicInsnNode(final String name, final String desc,
77 final Handle bsm, final Object... bsmArgs) {
78 super(Opcodes.INVOKEDYNAMIC);
79 this.name = name;
80 this.desc = desc;
81 this.bsm = bsm;
82 this.bsmArgs = bsmArgs;
83 }
54 /**
55 * Constructs a new {@link InvokeDynamicInsnNode}.
56 *
57 * @param name the method's name.
58 * @param descriptor the method's descriptor (see {@link org.eclipse.persistence.internal.libraries.asm.Type}).
59 * @param bootstrapMethodHandle the bootstrap method.
60 * @param bootstrapMethodArguments the bootstrap method constant arguments. Each argument must be
61 * an {@link Integer}, {@link Float}, {@link Long}, {@link Double}, {@link String}, {@link
62 * org.eclipse.persistence.internal.libraries.asm.Type} or {@link Handle} value. This method is allowed to modify the
63 * content of the array so a caller should expect that this array may change.
64 */
65 public InvokeDynamicInsnNode(
66 final String name,
67 final String descriptor,
68 final Handle bootstrapMethodHandle,
69 final Object... bootstrapMethodArguments) {
70 super(Opcodes.INVOKEDYNAMIC);
71 this.name = name;
72 this.desc = descriptor;
73 this.bsm = bootstrapMethodHandle;
74 this.bsmArgs = bootstrapMethodArguments;
75 }
8476
85 @Override
86 public int getType() {
87 return INVOKE_DYNAMIC_INSN;
88 }
77 @Override
78 public int getType() {
79 return INVOKE_DYNAMIC_INSN;
80 }
8981
90 @Override
91 public void accept(final MethodVisitor mv) {
92 mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
93 acceptAnnotations(mv);
94 }
82 @Override
83 public void accept(final MethodVisitor methodVisitor) {
84 methodVisitor.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
85 acceptAnnotations(methodVisitor);
86 }
9587
96 @Override
97 public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
98 return new InvokeDynamicInsnNode(name, desc, bsm, bsmArgs)
99 .cloneAnnotations(this);
100 }
101 }
88 @Override
89 public AbstractInsnNode clone(final Map<LabelNode, LabelNode> clonedLabels) {
90 return new InvokeDynamicInsnNode(name, desc, bsm, bsmArgs).cloneAnnotations(this);
91 }
92 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.tree;
3028
3129 import java.util.Map;
3331 import org.eclipse.persistence.internal.libraries.asm.MethodVisitor;
3432
3533 /**
36 * A node that represents a jump instruction. A jump instruction is an
37 * instruction that may jump to another instruction.
38 *
34 * A node that represents a jump instruction. A jump instruction is an instruction that may jump to
35 * another instruction.
36 *
3937 * @author Eric Bruneton
4038 */
4139 public class JumpInsnNode extends AbstractInsnNode {
4240
43 /**
44 * The operand of this instruction. This operand is a label that designates
45 * the instruction to which this instruction may jump.
46 */
47 public LabelNode label;
41 /**
42 * The operand of this instruction. This operand is a label that designates the instruction to
43 * which this instruction may jump.
44 */
45 public LabelNode label;
4846
49 /**
50 * Constructs a new {@link JumpInsnNode}.
51 *
52 * @param opcode
53 * the opcode of the type instruction to be constructed. This
54 * opcode must be IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, IF_ICMPEQ,
55 * IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE,
56 * IF_ACMPEQ, IF_ACMPNE, GOTO, JSR, IFNULL or IFNONNULL.
57 * @param label
58 * the operand of the instruction to be constructed. This operand
59 * is a label that designates the instruction to which the jump
60 * instruction may jump.
61 */
62 public JumpInsnNode(final int opcode, final LabelNode label) {
63 super(opcode);
64 this.label = label;
65 }
47 /**
48 * Constructs a new {@link JumpInsnNode}.
49 *
50 * @param opcode the opcode of the type instruction to be constructed. This opcode must be IFEQ,
51 * IFNE, IFLT, IFGE, IFGT, IFLE, IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT,
52 * IF_ICMPLE, IF_ACMPEQ, IF_ACMPNE, GOTO, JSR, IFNULL or IFNONNULL.
53 * @param label the operand of the instruction to be constructed. This operand is a label that
54 * designates the instruction to which the jump instruction may jump.
55 */
56 public JumpInsnNode(final int opcode, final LabelNode label) {
57 super(opcode);
58 this.label = label;
59 }
6660
67 /**
68 * Sets the opcode of this instruction.
69 *
70 * @param opcode
71 * the new instruction opcode. This opcode must be IFEQ, IFNE,
72 * IFLT, IFGE, IFGT, IFLE, IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT,
73 * IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, IF_ACMPEQ, IF_ACMPNE, GOTO,
74 * JSR, IFNULL or IFNONNULL.
75 */
76 public void setOpcode(final int opcode) {
77 this.opcode = opcode;
78 }
61 /**
62 * Sets the opcode of this instruction.
63 *
64 * @param opcode the new instruction opcode. This opcode must be IFEQ, IFNE, IFLT, IFGE, IFGT,
65 * IFLE, IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, IF_ACMPEQ,
66 * IF_ACMPNE, GOTO, JSR, IFNULL or IFNONNULL.
67 */
68 public void setOpcode(final int opcode) {
69 this.opcode = opcode;
70 }
7971
80 @Override
81 public int getType() {
82 return JUMP_INSN;
83 }
72 @Override
73 public int getType() {
74 return JUMP_INSN;
75 }
8476
85 @Override
86 public void accept(final MethodVisitor mv) {
87 mv.visitJumpInsn(opcode, label.getLabel());
88 acceptAnnotations(mv);
89 }
77 @Override
78 public void accept(final MethodVisitor methodVisitor) {
79 methodVisitor.visitJumpInsn(opcode, label.getLabel());
80 acceptAnnotations(methodVisitor);
81 }
9082
91 @Override
92 public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
93 return new JumpInsnNode(opcode, clone(label, labels))
94 .cloneAnnotations(this);
95 }
83 @Override
84 public AbstractInsnNode clone(final Map<LabelNode, LabelNode> clonedLabels) {
85 return new JumpInsnNode(opcode, clone(label, clonedLabels)).cloneAnnotations(this);
86 }
9687 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.tree;
3028
3129 import java.util.Map;
3331 import org.eclipse.persistence.internal.libraries.asm.Label;
3432 import org.eclipse.persistence.internal.libraries.asm.MethodVisitor;
3533
36 /**
37 * An {@link AbstractInsnNode} that encapsulates a {@link Label}.
38 */
34 /** An {@link AbstractInsnNode} that encapsulates a {@link Label}. */
3935 public class LabelNode extends AbstractInsnNode {
4036
41 private Label label;
37 private Label value;
4238
43 public LabelNode() {
44 super(-1);
39 public LabelNode() {
40 super(-1);
41 }
42
43 public LabelNode(final Label label) {
44 super(-1);
45 this.value = label;
46 }
47
48 @Override
49 public int getType() {
50 return LABEL;
51 }
52
53 public Label getLabel() {
54 if (value == null) {
55 value = new Label();
4556 }
57 return value;
58 }
4659
47 public LabelNode(final Label label) {
48 super(-1);
49 this.label = label;
50 }
60 @Override
61 public void accept(final MethodVisitor methodVisitor) {
62 methodVisitor.visitLabel(getLabel());
63 }
5164
52 @Override
53 public int getType() {
54 return LABEL;
55 }
65 @Override
66 public AbstractInsnNode clone(final Map<LabelNode, LabelNode> clonedLabels) {
67 return clonedLabels.get(this);
68 }
5669
57 public Label getLabel() {
58 if (label == null) {
59 label = new Label();
60 }
61 return label;
62 }
63
64 @Override
65 public void accept(final MethodVisitor cv) {
66 cv.visitLabel(getLabel());
67 }
68
69 @Override
70 public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
71 return labels.get(this);
72 }
73
74 public void resetLabel() {
75 label = null;
76 }
77 }
70 public void resetLabel() {
71 value = null;
72 }
73 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.tree;
3028
3129 import java.util.Map;
3533
3634 /**
3735 * A node that represents an LDC instruction.
38 *
36 *
3937 * @author Eric Bruneton
4038 */
4139 public class LdcInsnNode extends AbstractInsnNode {
4240
43 /**
44 * The constant to be loaded on the stack. This parameter must be a non null
45 * {@link Integer}, a {@link Float}, a {@link Long}, a {@link Double}, a
46 * {@link String} or a {@link org.eclipse.persistence.internal.libraries.asm.Type}.
47 */
48 public Object cst;
41 /**
42 * The constant to be loaded on the stack. This parameter must be a non null {@link Integer}, a
43 * {@link Float}, a {@link Long}, a {@link Double}, a {@link String} or a {@link
44 * org.eclipse.persistence.internal.libraries.asm.Type}.
45 */
46 public Object cst;
4947
50 /**
51 * Constructs a new {@link LdcInsnNode}.
52 *
53 * @param cst
54 * the constant to be loaded on the stack. This parameter must be
55 * a non null {@link Integer}, a {@link Float}, a {@link Long}, a
56 * {@link Double} or a {@link String}.
57 */
58 public LdcInsnNode(final Object cst) {
59 super(Opcodes.LDC);
60 this.cst = cst;
61 }
48 /**
49 * Constructs a new {@link LdcInsnNode}.
50 *
51 * @param value the constant to be loaded on the stack. This parameter must be a non null {@link
52 * Integer}, a {@link Float}, a {@link Long}, a {@link Double} or a {@link String}.
53 */
54 public LdcInsnNode(final Object value) {
55 super(Opcodes.LDC);
56 this.cst = value;
57 }
6258
63 @Override
64 public int getType() {
65 return LDC_INSN;
66 }
59 @Override
60 public int getType() {
61 return LDC_INSN;
62 }
6763
68 @Override
69 public void accept(final MethodVisitor mv) {
70 mv.visitLdcInsn(cst);
71 acceptAnnotations(mv);
72 }
64 @Override
65 public void accept(final MethodVisitor methodVisitor) {
66 methodVisitor.visitLdcInsn(cst);
67 acceptAnnotations(methodVisitor);
68 }
7369
74 @Override
75 public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
76 return new LdcInsnNode(cst).cloneAnnotations(this);
77 }
78 }
70 @Override
71 public AbstractInsnNode clone(final Map<LabelNode, LabelNode> clonedLabels) {
72 return new LdcInsnNode(cst).cloneAnnotations(this);
73 }
74 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.tree;
3028
3129 import java.util.Map;
3331 import org.eclipse.persistence.internal.libraries.asm.MethodVisitor;
3432
3533 /**
36 * A node that represents a line number declaration. These nodes are pseudo
37 * instruction nodes in order to be inserted in an instruction list.
38 *
34 * A node that represents a line number declaration. These nodes are pseudo instruction nodes in
35 * order to be inserted in an instruction list.
36 *
3937 * @author Eric Bruneton
4038 */
4139 public class LineNumberNode extends AbstractInsnNode {
4240
43 /**
44 * A line number. This number refers to the source file from which the class
45 * was compiled.
46 */
47 public int line;
41 /** A line number. This number refers to the source file from which the class was compiled. */
42 public int line;
4843
49 /**
50 * The first instruction corresponding to this line number.
51 */
52 public LabelNode start;
44 /** The first instruction corresponding to this line number. */
45 public LabelNode start;
5346
54 /**
55 * Constructs a new {@link LineNumberNode}.
56 *
57 * @param line
58 * a line number. This number refers to the source file from
59 * which the class was compiled.
60 * @param start
61 * the first instruction corresponding to this line number.
62 */
63 public LineNumberNode(final int line, final LabelNode start) {
64 super(-1);
65 this.line = line;
66 this.start = start;
67 }
47 /**
48 * Constructs a new {@link LineNumberNode}.
49 *
50 * @param line a line number. This number refers to the source file from which the class was
51 * compiled.
52 * @param start the first instruction corresponding to this line number.
53 */
54 public LineNumberNode(final int line, final LabelNode start) {
55 super(-1);
56 this.line = line;
57 this.start = start;
58 }
6859
69 @Override
70 public int getType() {
71 return LINE;
72 }
60 @Override
61 public int getType() {
62 return LINE;
63 }
7364
74 @Override
75 public void accept(final MethodVisitor mv) {
76 mv.visitLineNumber(line, start.getLabel());
77 }
65 @Override
66 public void accept(final MethodVisitor methodVisitor) {
67 methodVisitor.visitLineNumber(line, start.getLabel());
68 }
7869
79 @Override
80 public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
81 return new LineNumberNode(line, clone(start, labels));
82 }
70 @Override
71 public AbstractInsnNode clone(final Map<LabelNode, LabelNode> clonedLabels) {
72 return new LineNumberNode(line, clone(start, clonedLabels));
73 }
8374 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 package org.eclipse.persistence.internal.libraries.asm.tree;
31
32 import java.util.ArrayList;
33 import java.util.Arrays;
34 import java.util.List;
35
36 import org.eclipse.persistence.internal.libraries.asm.Label;
37 import org.eclipse.persistence.internal.libraries.asm.MethodVisitor;
38 import org.eclipse.persistence.internal.libraries.asm.Opcodes;
39 import org.eclipse.persistence.internal.libraries.asm.TypePath;
40 import org.eclipse.persistence.internal.libraries.asm.TypeReference;
41
42 /**
43 * A node that represents a type annotation on a local or resource variable.
44 *
45 * @author Eric Bruneton
46 */
47 public class LocalVariableAnnotationNode extends TypeAnnotationNode {
48
49 /**
50 * The fist instructions corresponding to the continuous ranges that make
51 * the scope of this local variable (inclusive). Must not be <tt>null</tt>.
52 */
53 public List<LabelNode> start;
54
55 /**
56 * The last instructions corresponding to the continuous ranges that make
57 * the scope of this local variable (exclusive). This list must have the
58 * same size as the 'start' list. Must not be <tt>null</tt>.
59 */
60 public List<LabelNode> end;
61
62 /**
63 * The local variable's index in each range. This list must have the same
64 * size as the 'start' list. Must not be <tt>null</tt>.
65 */
66 public List<Integer> index;
67
68 /**
69 * Constructs a new {@link LocalVariableAnnotationNode}. <i>Subclasses must
70 * not use this constructor</i>. Instead, they must use the
71 * {@link #LocalVariableAnnotationNode(int, TypePath, LabelNode[], LabelNode[], int[], String)}
72 * version.
73 *
74 * @param typeRef
75 * a reference to the annotated type. See {@link TypeReference}.
76 * @param typePath
77 * the path to the annotated type argument, wildcard bound, array
78 * element type, or static inner type within 'typeRef'. May be
79 * <tt>null</tt> if the annotation targets 'typeRef' as a whole.
80 * @param start
81 * the fist instructions corresponding to the continuous ranges
82 * that make the scope of this local variable (inclusive).
83 * @param end
84 * the last instructions corresponding to the continuous ranges
85 * that make the scope of this local variable (exclusive). This
86 * array must have the same size as the 'start' array.
87 * @param index
88 * the local variable's index in each range. This array must have
89 * the same size as the 'start' array.
90 * @param desc
91 * the class descriptor of the annotation class.
92 */
93 public LocalVariableAnnotationNode(int typeRef, TypePath typePath,
94 LabelNode[] start, LabelNode[] end, int[] index, String desc) {
95 this(Opcodes.ASM6, typeRef, typePath, start, end, index, desc);
96 }
97
98 /**
99 * Constructs a new {@link LocalVariableAnnotationNode}.
100 *
101 * @param api
102 * the ASM API version implemented by this visitor. Must be one
103 * of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
104 * @param typeRef
105 * a reference to the annotated type. See {@link TypeReference}.
106 * @param start
107 * the fist instructions corresponding to the continuous ranges
108 * that make the scope of this local variable (inclusive).
109 * @param end
110 * the last instructions corresponding to the continuous ranges
111 * that make the scope of this local variable (exclusive). This
112 * array must have the same size as the 'start' array.
113 * @param index
114 * the local variable's index in each range. This array must have
115 * the same size as the 'start' array.
116 * @param typePath
117 * the path to the annotated type argument, wildcard bound, array
118 * element type, or static inner type within 'typeRef'. May be
119 * <tt>null</tt> if the annotation targets 'typeRef' as a whole.
120 * @param desc
121 * the class descriptor of the annotation class.
122 */
123 public LocalVariableAnnotationNode(int api, int typeRef, TypePath typePath,
124 LabelNode[] start, LabelNode[] end, int[] index, String desc) {
125 super(api, typeRef, typePath, desc);
126 this.start = new ArrayList<LabelNode>(start.length);
127 this.start.addAll(Arrays.asList(start));
128 this.end = new ArrayList<LabelNode>(end.length);
129 this.end.addAll(Arrays.asList(end));
130 this.index = new ArrayList<Integer>(index.length);
131 for (int i : index) {
132 this.index.add(i);
133 }
134 }
135
136 /**
137 * Makes the given visitor visit this type annotation.
138 *
139 * @param mv
140 * the visitor that must visit this annotation.
141 * @param visible
142 * <tt>true</tt> if the annotation is visible at runtime.
143 */
144 public void accept(final MethodVisitor mv, boolean visible) {
145 Label[] start = new Label[this.start.size()];
146 Label[] end = new Label[this.end.size()];
147 int[] index = new int[this.index.size()];
148 for (int i = 0; i < start.length; ++i) {
149 start[i] = this.start.get(i).getLabel();
150 end[i] = this.end.get(i).getLabel();
151 index[i] = this.index.get(i);
152 }
153 accept(mv.visitLocalVariableAnnotation(typeRef, typePath, start, end,
154 index, desc, true));
155 }
156 }
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
27
28 package org.eclipse.persistence.internal.libraries.asm.tree;
29
30 import java.util.List;
31
32 import org.eclipse.persistence.internal.libraries.asm.Label;
33 import org.eclipse.persistence.internal.libraries.asm.MethodVisitor;
34 import org.eclipse.persistence.internal.libraries.asm.Opcodes;
35 import org.eclipse.persistence.internal.libraries.asm.TypePath;
36
37 /**
38 * A node that represents a type annotation on a local or resource variable.
39 *
40 * @author Eric Bruneton
41 */
42 public class LocalVariableAnnotationNode extends TypeAnnotationNode {
43
44 /**
45 * The fist instructions corresponding to the continuous ranges that make the scope of this local
46 * variable (inclusive). Must not be <tt>null</tt>.
47 */
48 public List<LabelNode> start;
49
50 /**
51 * The last instructions corresponding to the continuous ranges that make the scope of this local
52 * variable (exclusive). This list must have the same size as the 'start' list. Must not be
53 * <tt>null</tt>.
54 */
55 public List<LabelNode> end;
56
57 /**
58 * The local variable's index in each range. This list must have the same size as the 'start'
59 * list. Must not be <tt>null</tt>.
60 */
61 public List<Integer> index;
62
63 /**
64 * Constructs a new {@link LocalVariableAnnotationNode}. <i>Subclasses must not use this
65 * constructor</i>. Instead, they must use the {@link #LocalVariableAnnotationNode(int, TypePath,
66 * LabelNode[], LabelNode[], int[], String)} version.
67 *
68 * @param typeRef a reference to the annotated type. See {@link org.eclipse.persistence.internal.libraries.asm.TypeReference}.
69 * @param typePath the path to the annotated type argument, wildcard bound, array element type, or
70 * static inner type within 'typeRef'. May be <tt>null</tt> if the annotation targets
71 * 'typeRef' as a whole.
72 * @param start the fist instructions corresponding to the continuous ranges that make the scope
73 * of this local variable (inclusive).
74 * @param end the last instructions corresponding to the continuous ranges that make the scope of
75 * this local variable (exclusive). This array must have the same size as the 'start' array.
76 * @param index the local variable's index in each range. This array must have the same size as
77 * the 'start' array.
78 * @param descriptor the class descriptor of the annotation class.
79 */
80 public LocalVariableAnnotationNode(
81 final int typeRef,
82 final TypePath typePath,
83 final LabelNode[] start,
84 final LabelNode[] end,
85 final int[] index,
86 final String descriptor) {
87 this(Opcodes.ASM6, typeRef, typePath, start, end, index, descriptor);
88 }
89
90 /**
91 * Constructs a new {@link LocalVariableAnnotationNode}.
92 *
93 * @param api the ASM API version implemented by this visitor. Must be one of {@link
94 * Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
95 * @param typeRef a reference to the annotated type. See {@link org.eclipse.persistence.internal.libraries.asm.TypeReference}.
96 * @param start the fist instructions corresponding to the continuous ranges that make the scope
97 * of this local variable (inclusive).
98 * @param end the last instructions corresponding to the continuous ranges that make the scope of
99 * this local variable (exclusive). This array must have the same size as the 'start' array.
100 * @param index the local variable's index in each range. This array must have the same size as
101 * the 'start' array.
102 * @param typePath the path to the annotated type argument, wildcard bound, array element type, or
103 * static inner type within 'typeRef'. May be <tt>null</tt> if the annotation targets
104 * 'typeRef' as a whole.
105 * @param descriptor the class descriptor of the annotation class.
106 */
107 public LocalVariableAnnotationNode(
108 final int api,
109 final int typeRef,
110 final TypePath typePath,
111 final LabelNode[] start,
112 final LabelNode[] end,
113 final int[] index,
114 final String descriptor) {
115 super(api, typeRef, typePath, descriptor);
116 this.start = Util.asArrayList(start);
117 this.end = Util.asArrayList(end);
118 this.index = Util.asArrayList(index);
119 }
120
121 /**
122 * Makes the given visitor visit this type annotation.
123 *
124 * @param methodVisitor the visitor that must visit this annotation.
125 * @param visible <tt>true</tt> if the annotation is visible at runtime.
126 */
127 public void accept(final MethodVisitor methodVisitor, final boolean visible) {
128 Label[] startLabels = new Label[this.start.size()];
129 Label[] endLabels = new Label[this.end.size()];
130 int[] indices = new int[this.index.size()];
131 for (int i = 0, n = startLabels.length; i < n; ++i) {
132 startLabels[i] = this.start.get(i).getLabel();
133 endLabels[i] = this.end.get(i).getLabel();
134 indices[i] = this.index.get(i);
135 }
136 accept(
137 methodVisitor.visitLocalVariableAnnotation(
138 typeRef, typePath, startLabels, endLabels, indices, desc, visible));
139 }
140 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.tree;
3028
3129 import org.eclipse.persistence.internal.libraries.asm.MethodVisitor;
3230
3331 /**
3432 * A node that represents a local variable declaration.
35 *
33 *
3634 * @author Eric Bruneton
3735 */
3836 public class LocalVariableNode {
3937
40 /**
41 * The name of a local variable.
42 */
43 public String name;
38 /** The name of a local variable. */
39 public String name;
4440
45 /**
46 * The type descriptor of this local variable.
47 */
48 public String desc;
41 /** The type descriptor of this local variable. */
42 public String desc;
4943
50 /**
51 * The signature of this local variable. May be <tt>null</tt>.
52 */
53 public String signature;
44 /** The signature of this local variable. May be <tt>null</tt>. */
45 public String signature;
5446
55 /**
56 * The first instruction corresponding to the scope of this local variable
57 * (inclusive).
58 */
59 public LabelNode start;
47 /** The first instruction corresponding to the scope of this local variable (inclusive). */
48 public LabelNode start;
6049
61 /**
62 * The last instruction corresponding to the scope of this local variable
63 * (exclusive).
64 */
65 public LabelNode end;
50 /** The last instruction corresponding to the scope of this local variable (exclusive). */
51 public LabelNode end;
6652
67 /**
68 * The local variable's index.
69 */
70 public int index;
53 /** The local variable's index. */
54 public int index;
7155
72 /**
73 * Constructs a new {@link LocalVariableNode}.
74 *
75 * @param name
76 * the name of a local variable.
77 * @param desc
78 * the type descriptor of this local variable.
79 * @param signature
80 * the signature of this local variable. May be <tt>null</tt>.
81 * @param start
82 * the first instruction corresponding to the scope of this local
83 * variable (inclusive).
84 * @param end
85 * the last instruction corresponding to the scope of this local
86 * variable (exclusive).
87 * @param index
88 * the local variable's index.
89 */
90 public LocalVariableNode(final String name, final String desc,
91 final String signature, final LabelNode start, final LabelNode end,
92 final int index) {
93 this.name = name;
94 this.desc = desc;
95 this.signature = signature;
96 this.start = start;
97 this.end = end;
98 this.index = index;
99 }
56 /**
57 * Constructs a new {@link LocalVariableNode}.
58 *
59 * @param name the name of a local variable.
60 * @param descriptor the type descriptor of this local variable.
61 * @param signature the signature of this local variable. May be <tt>null</tt>.
62 * @param start the first instruction corresponding to the scope of this local variable
63 * (inclusive).
64 * @param end the last instruction corresponding to the scope of this local variable (exclusive).
65 * @param index the local variable's index.
66 */
67 public LocalVariableNode(
68 final String name,
69 final String descriptor,
70 final String signature,
71 final LabelNode start,
72 final LabelNode end,
73 final int index) {
74 this.name = name;
75 this.desc = descriptor;
76 this.signature = signature;
77 this.start = start;
78 this.end = end;
79 this.index = index;
80 }
10081
101 /**
102 * Makes the given visitor visit this local variable declaration.
103 *
104 * @param mv
105 * a method visitor.
106 */
107 public void accept(final MethodVisitor mv) {
108 mv.visitLocalVariable(name, desc, signature, start.getLabel(),
109 end.getLabel(), index);
110 }
82 /**
83 * Makes the given visitor visit this local variable declaration.
84 *
85 * @param methodVisitor a method visitor.
86 */
87 public void accept(final MethodVisitor methodVisitor) {
88 methodVisitor.visitLocalVariable(
89 name, desc, signature, start.getLabel(), end.getLabel(), index);
90 }
11191 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.tree;
3028
31 import java.util.ArrayList;
32 import java.util.Arrays;
3329 import java.util.List;
3430 import java.util.Map;
3531
3935
4036 /**
4137 * A node that represents a LOOKUPSWITCH instruction.
42 *
38 *
4339 * @author Eric Bruneton
4440 */
4541 public class LookupSwitchInsnNode extends AbstractInsnNode {
4642
47 /**
48 * Beginning of the default handler block.
49 */
50 public LabelNode dflt;
43 /** Beginning of the default handler block. */
44 public LabelNode dflt;
5145
52 /**
53 * The values of the keys. This list is a list of {@link Integer} objects.
54 */
55 public List<Integer> keys;
46 /** The values of the keys. */
47 public List<Integer> keys;
5648
57 /**
58 * Beginnings of the handler blocks. This list is a list of
59 * {@link LabelNode} objects.
60 */
61 public List<LabelNode> labels;
49 /** Beginnings of the handler blocks. */
50 public List<LabelNode> labels;
6251
63 /**
64 * Constructs a new {@link LookupSwitchInsnNode}.
65 *
66 * @param dflt
67 * beginning of the default handler block.
68 * @param keys
69 * the values of the keys.
70 * @param labels
71 * beginnings of the handler blocks. <tt>labels[i]</tt> is the
72 * beginning of the handler block for the <tt>keys[i]</tt> key.
73 */
74 public LookupSwitchInsnNode(final LabelNode dflt, final int[] keys,
75 final LabelNode[] labels) {
76 super(Opcodes.LOOKUPSWITCH);
77 this.dflt = dflt;
78 this.keys = new ArrayList<Integer>(keys == null ? 0 : keys.length);
79 this.labels = new ArrayList<LabelNode>(labels == null ? 0
80 : labels.length);
81 if (keys != null) {
82 for (int i = 0; i < keys.length; ++i) {
83 this.keys.add(keys[i]);
84 }
85 }
86 if (labels != null) {
87 this.labels.addAll(Arrays.asList(labels));
88 }
52 /**
53 * Constructs a new {@link LookupSwitchInsnNode}.
54 *
55 * @param dflt beginning of the default handler block.
56 * @param keys the values of the keys.
57 * @param labels beginnings of the handler blocks. <tt>labels[i]</tt> is the beginning of the
58 * handler block for the <tt>keys[i]</tt> key.
59 */
60 public LookupSwitchInsnNode(final LabelNode dflt, final int[] keys, final LabelNode[] labels) {
61 super(Opcodes.LOOKUPSWITCH);
62 this.dflt = dflt;
63 this.keys = Util.asArrayList(keys);
64 this.labels = Util.asArrayList(labels);
65 }
66
67 @Override
68 public int getType() {
69 return LOOKUPSWITCH_INSN;
70 }
71
72 @Override
73 public void accept(final MethodVisitor methodVisitor) {
74 int[] keysArray = new int[this.keys.size()];
75 for (int i = 0, n = keysArray.length; i < n; ++i) {
76 keysArray[i] = this.keys.get(i).intValue();
8977 }
78 Label[] labelsArray = new Label[this.labels.size()];
79 for (int i = 0, n = labelsArray.length; i < n; ++i) {
80 labelsArray[i] = this.labels.get(i).getLabel();
81 }
82 methodVisitor.visitLookupSwitchInsn(dflt.getLabel(), keysArray, labelsArray);
83 acceptAnnotations(methodVisitor);
84 }
9085
91 @Override
92 public int getType() {
93 return LOOKUPSWITCH_INSN;
94 }
95
96 @Override
97 public void accept(final MethodVisitor mv) {
98 int[] keys = new int[this.keys.size()];
99 for (int i = 0; i < keys.length; ++i) {
100 keys[i] = this.keys.get(i).intValue();
101 }
102 Label[] labels = new Label[this.labels.size()];
103 for (int i = 0; i < labels.length; ++i) {
104 labels[i] = this.labels.get(i).getLabel();
105 }
106 mv.visitLookupSwitchInsn(dflt.getLabel(), keys, labels);
107 acceptAnnotations(mv);
108 }
109
110 @Override
111 public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
112 LookupSwitchInsnNode clone = new LookupSwitchInsnNode(clone(dflt,
113 labels), null, clone(this.labels, labels));
114 clone.keys.addAll(keys);
115 return clone.cloneAnnotations(this);
116 }
86 @Override
87 public AbstractInsnNode clone(final Map<LabelNode, LabelNode> clonedLabels) {
88 LookupSwitchInsnNode clone =
89 new LookupSwitchInsnNode(clone(dflt, clonedLabels), null, clone(labels, clonedLabels));
90 clone.keys.addAll(keys);
91 return clone.cloneAnnotations(this);
92 }
11793 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.tree;
3028
3129 import java.util.Map;
3432 import org.eclipse.persistence.internal.libraries.asm.Opcodes;
3533
3634 /**
37 * A node that represents a method instruction. A method instruction is an
38 * instruction that invokes a method.
39 *
35 * A node that represents a method instruction. A method instruction is an instruction that invokes
36 * a method.
37 *
4038 * @author Eric Bruneton
4139 */
4240 public class MethodInsnNode extends AbstractInsnNode {
4341
44 /**
45 * The internal name of the method's owner class (see
46 * {@link org.eclipse.persistence.internal.libraries.asm.Type#getInternalName() getInternalName}).
47 */
48 public String owner;
42 /**
43 * The internal name of the method's owner class (see {@link
44 * org.eclipse.persistence.internal.libraries.asm.Type#getInternalName()}).
45 */
46 public String owner;
4947
50 /**
51 * The method's name.
52 */
53 public String name;
48 /** The method's name. */
49 public String name;
5450
55 /**
56 * The method's descriptor (see {@link org.eclipse.persistence.internal.libraries.asm.Type}).
57 */
58 public String desc;
51 /** The method's descriptor (see {@link org.eclipse.persistence.internal.libraries.asm.Type}). */
52 public String desc;
5953
60 /**
61 * If the method's owner class if an interface.
62 */
63 public boolean itf;
54 /** Whether the method's owner class if an interface. */
55 public boolean itf;
6456
65 /**
66 * Constructs a new {@link MethodInsnNode}.
67 *
68 * @param opcode
69 * the opcode of the type instruction to be constructed. This
70 * opcode must be INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or
71 * INVOKEINTERFACE.
72 * @param owner
73 * the internal name of the method's owner class (see
74 * {@link org.eclipse.persistence.internal.libraries.asm.Type#getInternalName()
75 * getInternalName}).
76 * @param name
77 * the method's name.
78 * @param desc
79 * the method's descriptor (see {@link org.eclipse.persistence.internal.libraries.asm.Type}).
80 */
81 @Deprecated
82 public MethodInsnNode(final int opcode, final String owner,
83 final String name, final String desc) {
84 this(opcode, owner, name, desc, opcode == Opcodes.INVOKEINTERFACE);
85 }
57 /**
58 * Constructs a new {@link MethodInsnNode}.
59 *
60 * @param opcode the opcode of the type instruction to be constructed. This opcode must be
61 * INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or INVOKEINTERFACE.
62 * @param owner the internal name of the method's owner class (see {@link
63 * org.eclipse.persistence.internal.libraries.asm.Type#getInternalName()}).
64 * @param name the method's name.
65 * @param descriptor the method's descriptor (see {@link org.eclipse.persistence.internal.libraries.asm.Type}).
66 * @deprecated
67 */
68 @Deprecated
69 public MethodInsnNode(
70 final int opcode, final String owner, final String name, final String descriptor) {
71 this(opcode, owner, name, descriptor, opcode == Opcodes.INVOKEINTERFACE);
72 }
8673
87 /**
88 * Constructs a new {@link MethodInsnNode}.
89 *
90 * @param opcode
91 * the opcode of the type instruction to be constructed. This
92 * opcode must be INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or
93 * INVOKEINTERFACE.
94 * @param owner
95 * the internal name of the method's owner class (see
96 * {@link org.eclipse.persistence.internal.libraries.asm.Type#getInternalName()
97 * getInternalName}).
98 * @param name
99 * the method's name.
100 * @param desc
101 * the method's descriptor (see {@link org.eclipse.persistence.internal.libraries.asm.Type}).
102 * @param itf
103 * if the method's owner class is an interface.
104 */
105 public MethodInsnNode(final int opcode, final String owner,
106 final String name, final String desc, final boolean itf) {
107 super(opcode);
108 this.owner = owner;
109 this.name = name;
110 this.desc = desc;
111 this.itf = itf;
112 }
74 /**
75 * Constructs a new {@link MethodInsnNode}.
76 *
77 * @param opcode the opcode of the type instruction to be constructed. This opcode must be
78 * INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or INVOKEINTERFACE.
79 * @param owner the internal name of the method's owner class (see {@link
80 * org.eclipse.persistence.internal.libraries.asm.Type#getInternalName()}).
81 * @param name the method's name.
82 * @param descriptor the method's descriptor (see {@link org.eclipse.persistence.internal.libraries.asm.Type}).
83 * @param isInterface if the method's owner class is an interface.
84 */
85 public MethodInsnNode(
86 final int opcode,
87 final String owner,
88 final String name,
89 final String descriptor,
90 final boolean isInterface) {
91 super(opcode);
92 this.owner = owner;
93 this.name = name;
94 this.desc = descriptor;
95 this.itf = isInterface;
96 }
11397
114 /**
115 * Sets the opcode of this instruction.
116 *
117 * @param opcode
118 * the new instruction opcode. This opcode must be INVOKEVIRTUAL,
119 * INVOKESPECIAL, INVOKESTATIC or INVOKEINTERFACE.
120 */
121 public void setOpcode(final int opcode) {
122 this.opcode = opcode;
123 }
98 /**
99 * Sets the opcode of this instruction.
100 *
101 * @param opcode the new instruction opcode. This opcode must be INVOKEVIRTUAL, INVOKESPECIAL,
102 * INVOKESTATIC or INVOKEINTERFACE.
103 */
104 public void setOpcode(final int opcode) {
105 this.opcode = opcode;
106 }
124107
125 @Override
126 public int getType() {
127 return METHOD_INSN;
128 }
108 @Override
109 public int getType() {
110 return METHOD_INSN;
111 }
129112
130 @Override
131 public void accept(final MethodVisitor mv) {
132 mv.visitMethodInsn(opcode, owner, name, desc, itf);
133 acceptAnnotations(mv);
134 }
113 @Override
114 public void accept(final MethodVisitor methodVisitor) {
115 methodVisitor.visitMethodInsn(opcode, owner, name, desc, itf);
116 acceptAnnotations(methodVisitor);
117 }
135118
136 @Override
137 public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
138 return new MethodInsnNode(opcode, owner, name, desc, itf);
139 }
140 }
119 @Override
120 public AbstractInsnNode clone(final Map<LabelNode, LabelNode> clonedLabels) {
121 return new MethodInsnNode(opcode, owner, name, desc, itf).cloneAnnotations(this);
122 }
123 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.tree;
3028
3129 import java.util.ArrayList;
32 import java.util.Arrays;
3330 import java.util.List;
3431
3532 import org.eclipse.persistence.internal.libraries.asm.AnnotationVisitor;
4441
4542 /**
4643 * A node that represents a method.
47 *
44 *
4845 * @author Eric Bruneton
4946 */
5047 public class MethodNode extends MethodVisitor {
5148
52 /**
53 * The method's access flags (see {@link Opcodes}). This field also
54 * indicates if the method is synthetic and/or deprecated.
55 */
56 public int access;
57
58 /**
59 * The method's name.
60 */
61 public String name;
62
63 /**
64 * The method's descriptor (see {@link Type}).
65 */
66 public String desc;
67
68 /**
69 * The method's signature. May be <tt>null</tt>.
70 */
71 public String signature;
72
73 /**
74 * The internal names of the method's exception classes (see
75 * {@link Type#getInternalName() getInternalName}). This list is a list of
76 * {@link String} objects.
77 */
78 public List<String> exceptions;
79
80 /**
81 * The method parameter info (access flags and name)
82 */
83 public List<ParameterNode> parameters;
84
85 /**
86 * The runtime visible annotations of this method. This list is a list of
87 * {@link AnnotationNode} objects. May be <tt>null</tt>.
88 *
89 * @associates org.eclipse.persistence.internal.libraries.asm.tree.AnnotationNode
90 * @label visible
91 */
92 public List<AnnotationNode> visibleAnnotations;
93
94 /**
95 * The runtime invisible annotations of this method. This list is a list of
96 * {@link AnnotationNode} objects. May be <tt>null</tt>.
97 *
98 * @associates org.eclipse.persistence.internal.libraries.asm.tree.AnnotationNode
99 * @label invisible
100 */
101 public List<AnnotationNode> invisibleAnnotations;
102
103 /**
104 * The runtime visible type annotations of this method. This list is a list
105 * of {@link TypeAnnotationNode} objects. May be <tt>null</tt>.
106 *
107 * @associates org.eclipse.persistence.internal.libraries.asm.tree.TypeAnnotationNode
108 * @label visible
109 */
110 public List<TypeAnnotationNode> visibleTypeAnnotations;
111
112 /**
113 * The runtime invisible type annotations of this method. This list is a
114 * list of {@link TypeAnnotationNode} objects. May be <tt>null</tt>.
115 *
116 * @associates org.eclipse.persistence.internal.libraries.asm.tree.TypeAnnotationNode
117 * @label invisible
118 */
119 public List<TypeAnnotationNode> invisibleTypeAnnotations;
120
121 /**
122 * The non standard attributes of this method. This list is a list of
123 * {@link Attribute} objects. May be <tt>null</tt>.
124 *
125 * @associates org.eclipse.persistence.internal.libraries.asm.Attribute
126 */
127 public List<Attribute> attrs;
128
129 /**
130 * The default value of this annotation interface method. This field must be
131 * a {@link Byte}, {@link Boolean}, {@link Character}, {@link Short},
132 * {@link Integer}, {@link Long}, {@link Float}, {@link Double},
133 * {@link String} or {@link Type}, or an two elements String array (for
134 * enumeration values), a {@link AnnotationNode}, or a {@link List} of
135 * values of one of the preceding types. May be <tt>null</tt>.
136 */
137 public Object annotationDefault;
138
139 /**
140 * The runtime visible parameter annotations of this method. These lists are
141 * lists of {@link AnnotationNode} objects. May be <tt>null</tt>.
142 *
143 * @associates org.eclipse.persistence.internal.libraries.asm.tree.AnnotationNode
144 * @label invisible parameters
145 */
146 public List<AnnotationNode>[] visibleParameterAnnotations;
147
148 /**
149 * The runtime invisible parameter annotations of this method. These lists
150 * are lists of {@link AnnotationNode} objects. May be <tt>null</tt>.
151 *
152 * @associates org.eclipse.persistence.internal.libraries.asm.tree.AnnotationNode
153 * @label visible parameters
154 */
155 public List<AnnotationNode>[] invisibleParameterAnnotations;
156
157 /**
158 * The instructions of this method. This list is a list of
159 * {@link AbstractInsnNode} objects.
160 *
161 * @associates org.eclipse.persistence.internal.libraries.asm.tree.AbstractInsnNode
162 * @label instructions
163 */
164 public InsnList instructions;
165
166 /**
167 * The try catch blocks of this method. This list is a list of
168 * {@link TryCatchBlockNode} objects.
169 *
170 * @associates org.eclipse.persistence.internal.libraries.asm.tree.TryCatchBlockNode
171 */
172 public List<TryCatchBlockNode> tryCatchBlocks;
173
174 /**
175 * The maximum stack size of this method.
176 */
177 public int maxStack;
178
179 /**
180 * The maximum number of local variables of this method.
181 */
182 public int maxLocals;
183
184 /**
185 * The local variables of this method. This list is a list of
186 * {@link LocalVariableNode} objects. May be <tt>null</tt>
187 *
188 * @associates org.eclipse.persistence.internal.libraries.asm.tree.LocalVariableNode
189 */
190 public List<LocalVariableNode> localVariables;
191
192 /**
193 * The visible local variable annotations of this method. This list is a
194 * list of {@link LocalVariableAnnotationNode} objects. May be <tt>null</tt>
195 *
196 * @associates org.eclipse.persistence.internal.libraries.asm.tree.LocalVariableAnnotationNode
197 */
198 public List<LocalVariableAnnotationNode> visibleLocalVariableAnnotations;
199
200 /**
201 * The invisible local variable annotations of this method. This list is a
202 * list of {@link LocalVariableAnnotationNode} objects. May be <tt>null</tt>
203 *
204 * @associates org.eclipse.persistence.internal.libraries.asm.tree.LocalVariableAnnotationNode
205 */
206 public List<LocalVariableAnnotationNode> invisibleLocalVariableAnnotations;
207
208 /**
209 * If the accept method has been called on this object.
210 */
211 private boolean visited;
212
213 /**
214 * Constructs an uninitialized {@link MethodNode}. <i>Subclasses must not
215 * use this constructor</i>. Instead, they must use the
216 * {@link #MethodNode(int)} version.
217 *
218 * @throws IllegalStateException
219 * If a subclass calls this constructor.
220 */
221 public MethodNode() {
222 this(Opcodes.ASM6);
223 if (getClass() != MethodNode.class) {
224 throw new IllegalStateException();
225 }
226 }
227
228 /**
229 * Constructs an uninitialized {@link MethodNode}.
230 *
231 * @param api
232 * the ASM API version implemented by this visitor. Must be one
233 * of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
234 */
235 public MethodNode(final int api) {
236 super(api);
237 this.instructions = new InsnList();
238 }
239
240 /**
241 * Constructs a new {@link MethodNode}. <i>Subclasses must not use this
242 * constructor</i>. Instead, they must use the
243 * {@link #MethodNode(int, int, String, String, String, String[])} version.
244 *
245 * @param access
246 * the method's access flags (see {@link Opcodes}). This
247 * parameter also indicates if the method is synthetic and/or
248 * deprecated.
249 * @param name
250 * the method's name.
251 * @param desc
252 * the method's descriptor (see {@link Type}).
253 * @param signature
254 * the method's signature. May be <tt>null</tt>.
255 * @param exceptions
256 * the internal names of the method's exception classes (see
257 * {@link Type#getInternalName() getInternalName}). May be
258 * <tt>null</tt>.
259 * @throws IllegalStateException
260 * If a subclass calls this constructor.
261 */
262 public MethodNode(final int access, final String name, final String desc,
263 final String signature, final String[] exceptions) {
264 this(Opcodes.ASM6, access, name, desc, signature, exceptions);
265 if (getClass() != MethodNode.class) {
266 throw new IllegalStateException();
267 }
268 }
269
270 /**
271 * Constructs a new {@link MethodNode}.
272 *
273 * @param api
274 * the ASM API version implemented by this visitor. Must be one
275 * of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
276 * @param access
277 * the method's access flags (see {@link Opcodes}). This
278 * parameter also indicates if the method is synthetic and/or
279 * deprecated.
280 * @param name
281 * the method's name.
282 * @param desc
283 * the method's descriptor (see {@link Type}).
284 * @param signature
285 * the method's signature. May be <tt>null</tt>.
286 * @param exceptions
287 * the internal names of the method's exception classes (see
288 * {@link Type#getInternalName() getInternalName}). May be
289 * <tt>null</tt>.
290 */
291 public MethodNode(final int api, final int access, final String name,
292 final String desc, final String signature, final String[] exceptions) {
293 super(api);
294 this.access = access;
295 this.name = name;
296 this.desc = desc;
297 this.signature = signature;
298 this.exceptions = new ArrayList<String>(exceptions == null ? 0
299 : exceptions.length);
300 boolean isAbstract = (access & Opcodes.ACC_ABSTRACT) != 0;
301 if (!isAbstract) {
302 this.localVariables = new ArrayList<LocalVariableNode>(5);
303 }
304 this.tryCatchBlocks = new ArrayList<TryCatchBlockNode>();
305 if (exceptions != null) {
306 this.exceptions.addAll(Arrays.asList(exceptions));
307 }
308 this.instructions = new InsnList();
309 }
310
311 // ------------------------------------------------------------------------
312 // Implementation of the MethodVisitor abstract class
313 // ------------------------------------------------------------------------
314
315 @Override
316 public void visitParameter(String name, int access) {
317 if (parameters == null) {
318 parameters = new ArrayList<ParameterNode>(5);
319 }
320 parameters.add(new ParameterNode(name, access));
321 }
322
323 @Override
324 @SuppressWarnings("serial")
325 public AnnotationVisitor visitAnnotationDefault() {
326 return new AnnotationNode(new ArrayList<Object>(0) {
327 @Override
328 public boolean add(final Object o) {
329 annotationDefault = o;
330 return super.add(o);
331 }
49 /**
50 * The method's access flags (see {@link Opcodes}). This field also indicates if the method is
51 * synthetic and/or deprecated.
52 */
53 public int access;
54
55 /** The method's name. */
56 public String name;
57
58 /** The method's descriptor (see {@link Type}). */
59 public String desc;
60
61 /** The method's signature. May be <tt>null</tt>. */
62 public String signature;
63
64 /** The internal names of the method's exception classes (see {@link Type#getInternalName()}). */
65 public List<String> exceptions;
66
67 /** The method parameter info (access flags and name) */
68 public List<ParameterNode> parameters;
69
70 /** The runtime visible annotations of this method. May be <tt>null</tt>. */
71 public List<AnnotationNode> visibleAnnotations;
72
73 /** The runtime invisible annotations of this method. May be <tt>null</tt>. */
74 public List<AnnotationNode> invisibleAnnotations;
75
76 /** The runtime visible type annotations of this method. May be <tt>null</tt>. */
77 public List<TypeAnnotationNode> visibleTypeAnnotations;
78
79 /** The runtime invisible type annotations of this method. May be <tt>null</tt>. */
80 public List<TypeAnnotationNode> invisibleTypeAnnotations;
81
82 /** The non standard attributes of this method. May be <tt>null</tt>. */
83 public List<Attribute> attrs;
84
85 /**
86 * The default value of this annotation interface method. This field must be a {@link Byte},
87 * {@link Boolean}, {@link Character}, {@link Short}, {@link Integer}, {@link Long}, {@link
88 * Float}, {@link Double}, {@link String} or {@link Type}, or an two elements String array (for
89 * enumeration values), a {@link AnnotationNode}, or a {@link List} of values of one of the
90 * preceding types. May be <tt>null</tt>.
91 */
92 public Object annotationDefault;
93
94 /**
95 * The number of method parameters than can have runtime visible annotations. This number must be
96 * less or equal than the number of parameter types in the method descriptor (the default value 0
97 * indicates that all the parameters described in the method descriptor can have annotations). It
98 * can be strictly less when a method has synthetic parameters and when these parameters are
99 * ignored when computing parameter indices for the purpose of parameter annotations (see
100 * https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.18).
101 */
102 public int visibleAnnotableParameterCount;
103
104 /**
105 * The runtime visible parameter annotations of this method. These lists are lists of {@link
106 * AnnotationNode} objects. May be <tt>null</tt>.
107 */
108 public List<AnnotationNode>[] visibleParameterAnnotations;
109
110 /**
111 * The number of method parameters than can have runtime invisible annotations. This number must
112 * be less or equal than the number of parameter types in the method descriptor (the default value
113 * 0 indicates that all the parameters described in the method descriptor can have annotations).
114 * It can be strictly less when a method has synthetic parameters and when these parameters are
115 * ignored when computing parameter indices for the purpose of parameter annotations (see
116 * https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.18).
117 */
118 public int invisibleAnnotableParameterCount;
119
120 /**
121 * The runtime invisible parameter annotations of this method. These lists are lists of {@link
122 * AnnotationNode} objects. May be <tt>null</tt>.
123 */
124 public List<AnnotationNode>[] invisibleParameterAnnotations;
125
126 /** The instructions of this method. */
127 public InsnList instructions;
128
129 /** The try catch blocks of this method. */
130 public List<TryCatchBlockNode> tryCatchBlocks;
131
132 /** The maximum stack size of this method. */
133 public int maxStack;
134
135 /** The maximum number of local variables of this method. */
136 public int maxLocals;
137
138 /** The local variables of this method. May be <tt>null</tt> */
139 public List<LocalVariableNode> localVariables;
140
141 /** The visible local variable annotations of this method. May be <tt>null</tt> */
142 public List<LocalVariableAnnotationNode> visibleLocalVariableAnnotations;
143
144 /** The invisible local variable annotations of this method. May be <tt>null</tt> */
145 public List<LocalVariableAnnotationNode> invisibleLocalVariableAnnotations;
146
147 /** Whether the accept method has been called on this object. */
148 private boolean visited;
149
150 /**
151 * Constructs an uninitialized {@link MethodNode}. <i>Subclasses must not use this
152 * constructor</i>. Instead, they must use the {@link #MethodNode(int)} version.
153 *
154 * @throws IllegalStateException If a subclass calls this constructor.
155 */
156 public MethodNode() {
157 this(Opcodes.ASM6);
158 if (getClass() != MethodNode.class) {
159 throw new IllegalStateException();
160 }
161 }
162
163 /**
164 * Constructs an uninitialized {@link MethodNode}.
165 *
166 * @param api the ASM API version implemented by this visitor. Must be one of {@link
167 * Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
168 */
169 public MethodNode(final int api) {
170 super(api);
171 this.instructions = new InsnList();
172 }
173
174 /**
175 * Constructs a new {@link MethodNode}. <i>Subclasses must not use this constructor</i>. Instead,
176 * they must use the {@link #MethodNode(int, int, String, String, String, String[])} version.
177 *
178 * @param access the method's access flags (see {@link Opcodes}). This parameter also indicates if
179 * the method is synthetic and/or deprecated.
180 * @param name the method's name.
181 * @param descriptor the method's descriptor (see {@link Type}).
182 * @param signature the method's signature. May be <tt>null</tt>.
183 * @param exceptions the internal names of the method's exception classes (see {@link
184 * Type#getInternalName()}). May be <tt>null</tt>.
185 * @throws IllegalStateException If a subclass calls this constructor.
186 */
187 public MethodNode(
188 final int access,
189 final String name,
190 final String descriptor,
191 final String signature,
192 final String[] exceptions) {
193 this(Opcodes.ASM6, access, name, descriptor, signature, exceptions);
194 if (getClass() != MethodNode.class) {
195 throw new IllegalStateException();
196 }
197 }
198
199 /**
200 * Constructs a new {@link MethodNode}.
201 *
202 * @param api the ASM API version implemented by this visitor. Must be one of {@link
203 * Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
204 * @param access the method's access flags (see {@link Opcodes}). This parameter also indicates if
205 * the method is synthetic and/or deprecated.
206 * @param name the method's name.
207 * @param descriptor the method's descriptor (see {@link Type}).
208 * @param signature the method's signature. May be <tt>null</tt>.
209 * @param exceptions the internal names of the method's exception classes (see {@link
210 * Type#getInternalName()}). May be <tt>null</tt>.
211 */
212 public MethodNode(
213 final int api,
214 final int access,
215 final String name,
216 final String descriptor,
217 final String signature,
218 final String[] exceptions) {
219 super(api);
220 this.access = access;
221 this.name = name;
222 this.desc = descriptor;
223 this.signature = signature;
224 this.exceptions = Util.asArrayList(exceptions);
225 if ((access & Opcodes.ACC_ABSTRACT) == 0) {
226 this.localVariables = new ArrayList<LocalVariableNode>(5);
227 }
228 this.tryCatchBlocks = new ArrayList<TryCatchBlockNode>();
229 this.instructions = new InsnList();
230 }
231
232 // -----------------------------------------------------------------------------------------------
233 // Implementation of the MethodVisitor abstract class
234 // -----------------------------------------------------------------------------------------------
235
236 @Override
237 public void visitParameter(final String name, final int access) {
238 if (parameters == null) {
239 parameters = new ArrayList<ParameterNode>(5);
240 }
241 parameters.add(new ParameterNode(name, access));
242 }
243
244 @Override
245 @SuppressWarnings("serial")
246 public AnnotationVisitor visitAnnotationDefault() {
247 return new AnnotationNode(
248 new ArrayList<Object>(0) {
249 @Override
250 public boolean add(final Object o) {
251 annotationDefault = o;
252 return super.add(o);
253 }
332254 });
333 }
334
335 @Override
336 public AnnotationVisitor visitAnnotation(final String desc,
337 final boolean visible) {
338 AnnotationNode an = new AnnotationNode(desc);
339 if (visible) {
340 if (visibleAnnotations == null) {
341 visibleAnnotations = new ArrayList<AnnotationNode>(1);
342 }
343 visibleAnnotations.add(an);
344 } else {
345 if (invisibleAnnotations == null) {
346 invisibleAnnotations = new ArrayList<AnnotationNode>(1);
347 }
348 invisibleAnnotations.add(an);
349 }
350 return an;
351 }
352
353 @Override
354 public AnnotationVisitor visitTypeAnnotation(int typeRef,
355 TypePath typePath, String desc, boolean visible) {
356 TypeAnnotationNode an = new TypeAnnotationNode(typeRef, typePath, desc);
357 if (visible) {
358 if (visibleTypeAnnotations == null) {
359 visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
360 }
361 visibleTypeAnnotations.add(an);
362 } else {
363 if (invisibleTypeAnnotations == null) {
364 invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
365 }
366 invisibleTypeAnnotations.add(an);
367 }
368 return an;
369 }
370
371 @Override
372 @SuppressWarnings("unchecked")
373 public AnnotationVisitor visitParameterAnnotation(final int parameter,
374 final String desc, final boolean visible) {
375 AnnotationNode an = new AnnotationNode(desc);
376 if (visible) {
377 if (visibleParameterAnnotations == null) {
378 int params = Type.getArgumentTypes(this.desc).length;
379 visibleParameterAnnotations = (List<AnnotationNode>[]) new List<?>[params];
380 }
381 if (visibleParameterAnnotations[parameter] == null) {
382 visibleParameterAnnotations[parameter] = new ArrayList<AnnotationNode>(
383 1);
384 }
385 visibleParameterAnnotations[parameter].add(an);
386 } else {
387 if (invisibleParameterAnnotations == null) {
388 int params = Type.getArgumentTypes(this.desc).length;
389 invisibleParameterAnnotations = (List<AnnotationNode>[]) new List<?>[params];
390 }
391 if (invisibleParameterAnnotations[parameter] == null) {
392 invisibleParameterAnnotations[parameter] = new ArrayList<AnnotationNode>(
393 1);
394 }
395 invisibleParameterAnnotations[parameter].add(an);
396 }
397 return an;
398 }
399
400 @Override
401 public void visitAttribute(final Attribute attr) {
402 if (attrs == null) {
403 attrs = new ArrayList<Attribute>(1);
404 }
405 attrs.add(attr);
406 }
407
408 @Override
409 public void visitCode() {
410 }
411
412 @Override
413 public void visitFrame(final int type, final int nLocal,
414 final Object[] local, final int nStack, final Object[] stack) {
415 instructions.add(new FrameNode(type, nLocal, local == null ? null
416 : getLabelNodes(local), nStack, stack == null ? null
417 : getLabelNodes(stack)));
418 }
419
420 @Override
421 public void visitInsn(final int opcode) {
422 instructions.add(new InsnNode(opcode));
423 }
424
425 @Override
426 public void visitIntInsn(final int opcode, final int operand) {
427 instructions.add(new IntInsnNode(opcode, operand));
428 }
429
430 @Override
431 public void visitVarInsn(final int opcode, final int var) {
432 instructions.add(new VarInsnNode(opcode, var));
433 }
434
435 @Override
436 public void visitTypeInsn(final int opcode, final String type) {
437 instructions.add(new TypeInsnNode(opcode, type));
438 }
439
440 @Override
441 public void visitFieldInsn(final int opcode, final String owner,
442 final String name, final String desc) {
443 instructions.add(new FieldInsnNode(opcode, owner, name, desc));
444 }
445
446 @Deprecated
447 @Override
448 public void visitMethodInsn(int opcode, String owner, String name,
449 String desc) {
450 if (api >= Opcodes.ASM5) {
451 super.visitMethodInsn(opcode, owner, name, desc);
452 return;
453 }
454 instructions.add(new MethodInsnNode(opcode, owner, name, desc));
455 }
456
457 @Override
458 public void visitMethodInsn(int opcode, String owner, String name,
459 String desc, boolean itf) {
460 if (api < Opcodes.ASM5) {
461 super.visitMethodInsn(opcode, owner, name, desc, itf);
462 return;
463 }
464 instructions.add(new MethodInsnNode(opcode, owner, name, desc, itf));
465 }
466
467 @Override
468 public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
469 Object... bsmArgs) {
470 instructions.add(new InvokeDynamicInsnNode(name, desc, bsm, bsmArgs));
471 }
472
473 @Override
474 public void visitJumpInsn(final int opcode, final Label label) {
475 instructions.add(new JumpInsnNode(opcode, getLabelNode(label)));
476 }
477
478 @Override
479 public void visitLabel(final Label label) {
480 instructions.add(getLabelNode(label));
481 }
482
483 @Override
484 public void visitLdcInsn(final Object cst) {
485 instructions.add(new LdcInsnNode(cst));
486 }
487
488 @Override
489 public void visitIincInsn(final int var, final int increment) {
490 instructions.add(new IincInsnNode(var, increment));
491 }
492
493 @Override
494 public void visitTableSwitchInsn(final int min, final int max,
495 final Label dflt, final Label... labels) {
496 instructions.add(new TableSwitchInsnNode(min, max, getLabelNode(dflt),
497 getLabelNodes(labels)));
498 }
499
500 @Override
501 public void visitLookupSwitchInsn(final Label dflt, final int[] keys,
502 final Label[] labels) {
503 instructions.add(new LookupSwitchInsnNode(getLabelNode(dflt), keys,
504 getLabelNodes(labels)));
505 }
506
507 @Override
508 public void visitMultiANewArrayInsn(final String desc, final int dims) {
509 instructions.add(new MultiANewArrayInsnNode(desc, dims));
510 }
511
512 @Override
513 public AnnotationVisitor visitInsnAnnotation(int typeRef,
514 TypePath typePath, String desc, boolean visible) {
515 // Finds the last real instruction, i.e. the instruction targeted by
516 // this annotation.
517 AbstractInsnNode insn = instructions.getLast();
518 while (insn.getOpcode() == -1) {
519 insn = insn.getPrevious();
520 }
521 // Adds the annotation to this instruction.
522 TypeAnnotationNode an = new TypeAnnotationNode(typeRef, typePath, desc);
523 if (visible) {
524 if (insn.visibleTypeAnnotations == null) {
525 insn.visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(
526 1);
527 }
528 insn.visibleTypeAnnotations.add(an);
529 } else {
530 if (insn.invisibleTypeAnnotations == null) {
531 insn.invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(
532 1);
533 }
534 insn.invisibleTypeAnnotations.add(an);
535 }
536 return an;
537 }
538
539 @Override
540 public void visitTryCatchBlock(final Label start, final Label end,
541 final Label handler, final String type) {
542 tryCatchBlocks.add(new TryCatchBlockNode(getLabelNode(start),
543 getLabelNode(end), getLabelNode(handler), type));
544 }
545
546 @Override
547 public AnnotationVisitor visitTryCatchAnnotation(int typeRef,
548 TypePath typePath, String desc, boolean visible) {
549 TryCatchBlockNode tcb = tryCatchBlocks.get((typeRef & 0x00FFFF00) >> 8);
550 TypeAnnotationNode an = new TypeAnnotationNode(typeRef, typePath, desc);
551 if (visible) {
552 if (tcb.visibleTypeAnnotations == null) {
553 tcb.visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(
554 1);
555 }
556 tcb.visibleTypeAnnotations.add(an);
557 } else {
558 if (tcb.invisibleTypeAnnotations == null) {
559 tcb.invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(
560 1);
561 }
562 tcb.invisibleTypeAnnotations.add(an);
563 }
564 return an;
565 }
566
567 @Override
568 public void visitLocalVariable(final String name, final String desc,
569 final String signature, final Label start, final Label end,
570 final int index) {
571 localVariables.add(new LocalVariableNode(name, desc, signature,
572 getLabelNode(start), getLabelNode(end), index));
573 }
574
575 @Override
576 public AnnotationVisitor visitLocalVariableAnnotation(int typeRef,
577 TypePath typePath, Label[] start, Label[] end, int[] index,
578 String desc, boolean visible) {
579 LocalVariableAnnotationNode an = new LocalVariableAnnotationNode(
580 typeRef, typePath, getLabelNodes(start), getLabelNodes(end),
581 index, desc);
582 if (visible) {
583 if (visibleLocalVariableAnnotations == null) {
584 visibleLocalVariableAnnotations = new ArrayList<LocalVariableAnnotationNode>(
585 1);
586 }
587 visibleLocalVariableAnnotations.add(an);
588 } else {
589 if (invisibleLocalVariableAnnotations == null) {
590 invisibleLocalVariableAnnotations = new ArrayList<LocalVariableAnnotationNode>(
591 1);
592 }
593 invisibleLocalVariableAnnotations.add(an);
594 }
595 return an;
596 }
597
598 @Override
599 public void visitLineNumber(final int line, final Label start) {
600 instructions.add(new LineNumberNode(line, getLabelNode(start)));
601 }
602
603 @Override
604 public void visitMaxs(final int maxStack, final int maxLocals) {
605 this.maxStack = maxStack;
606 this.maxLocals = maxLocals;
607 }
608
609 @Override
610 public void visitEnd() {
611 }
612
613 /**
614 * Returns the LabelNode corresponding to the given Label. Creates a new
615 * LabelNode if necessary. The default implementation of this method uses
616 * the {@link Label#info} field to store associations between labels and
617 * label nodes.
618 *
619 * @param l
620 * a Label.
621 * @return the LabelNode corresponding to l.
622 */
623 protected LabelNode getLabelNode(final Label l) {
624 if (!(l.info instanceof LabelNode)) {
625 l.info = new LabelNode();
626 }
627 return (LabelNode) l.info;
628 }
629
630 private LabelNode[] getLabelNodes(final Label[] l) {
631 LabelNode[] nodes = new LabelNode[l.length];
632 for (int i = 0; i < l.length; ++i) {
633 nodes[i] = getLabelNode(l[i]);
634 }
635 return nodes;
636 }
637
638 private Object[] getLabelNodes(final Object[] objs) {
639 Object[] nodes = new Object[objs.length];
640 for (int i = 0; i < objs.length; ++i) {
641 Object o = objs[i];
642 if (o instanceof Label) {
643 o = getLabelNode((Label) o);
644 }
645 nodes[i] = o;
646 }
647 return nodes;
648 }
649
650 // ------------------------------------------------------------------------
651 // Accept method
652 // ------------------------------------------------------------------------
653
654 /**
655 * Checks that this method node is compatible with the given ASM API
656 * version. This methods checks that this node, and all its nodes
657 * recursively, do not contain elements that were introduced in more recent
658 * versions of the ASM API than the given version.
659 *
660 * @param api
661 * an ASM API version. Must be one of {@link Opcodes#ASM4},
662 * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
663 */
664 public void check(final int api) {
665 if (api == Opcodes.ASM4) {
666 if (visibleTypeAnnotations != null
667 && visibleTypeAnnotations.size() > 0) {
668 throw new RuntimeException();
669 }
670 if (invisibleTypeAnnotations != null
671 && invisibleTypeAnnotations.size() > 0) {
672 throw new RuntimeException();
673 }
674 int n = tryCatchBlocks == null ? 0 : tryCatchBlocks.size();
675 for (int i = 0; i < n; ++i) {
676 TryCatchBlockNode tcb = tryCatchBlocks.get(i);
677 if (tcb.visibleTypeAnnotations != null
678 && tcb.visibleTypeAnnotations.size() > 0) {
679 throw new RuntimeException();
680 }
681 if (tcb.invisibleTypeAnnotations != null
682 && tcb.invisibleTypeAnnotations.size() > 0) {
683 throw new RuntimeException();
684 }
685 }
686 for (int i = 0; i < instructions.size(); ++i) {
687 AbstractInsnNode insn = instructions.get(i);
688 if (insn.visibleTypeAnnotations != null
689 && insn.visibleTypeAnnotations.size() > 0) {
690 throw new RuntimeException();
691 }
692 if (insn.invisibleTypeAnnotations != null
693 && insn.invisibleTypeAnnotations.size() > 0) {
694 throw new RuntimeException();
695 }
696 if (insn instanceof MethodInsnNode) {
697 boolean itf = ((MethodInsnNode) insn).itf;
698 if (itf != (insn.opcode == Opcodes.INVOKEINTERFACE)) {
699 throw new RuntimeException();
700 }
701 }
702 }
703 if (visibleLocalVariableAnnotations != null
704 && visibleLocalVariableAnnotations.size() > 0) {
705 throw new RuntimeException();
706 }
707 if (invisibleLocalVariableAnnotations != null
708 && invisibleLocalVariableAnnotations.size() > 0) {
709 throw new RuntimeException();
710 }
711 }
712 }
713
714 /**
715 * Makes the given class visitor visit this method.
716 *
717 * @param cv
718 * a class visitor.
719 */
720 public void accept(final ClassVisitor cv) {
721 String[] exceptions = new String[this.exceptions.size()];
722 this.exceptions.toArray(exceptions);
723 MethodVisitor mv = cv.visitMethod(access, name, desc, signature,
724 exceptions);
725 if (mv != null) {
726 accept(mv);
727 }
728 }
729
730 /**
731 * Makes the given method visitor visit this method.
732 *
733 * @param mv
734 * a method visitor.
735 */
736 public void accept(final MethodVisitor mv) {
737 // visits the method parameters
738 int i, j, n;
739 n = parameters == null ? 0 : parameters.size();
740 for (i = 0; i < n; i++) {
741 ParameterNode parameter = parameters.get(i);
742 mv.visitParameter(parameter.name, parameter.access);
743 }
744 // visits the method attributes
745 if (annotationDefault != null) {
746 AnnotationVisitor av = mv.visitAnnotationDefault();
747 AnnotationNode.accept(av, null, annotationDefault);
748 if (av != null) {
749 av.visitEnd();
750 }
751 }
752 n = visibleAnnotations == null ? 0 : visibleAnnotations.size();
753 for (i = 0; i < n; ++i) {
754 AnnotationNode an = visibleAnnotations.get(i);
755 an.accept(mv.visitAnnotation(an.desc, true));
756 }
757 n = invisibleAnnotations == null ? 0 : invisibleAnnotations.size();
758 for (i = 0; i < n; ++i) {
759 AnnotationNode an = invisibleAnnotations.get(i);
760 an.accept(mv.visitAnnotation(an.desc, false));
761 }
762 n = visibleTypeAnnotations == null ? 0 : visibleTypeAnnotations.size();
763 for (i = 0; i < n; ++i) {
764 TypeAnnotationNode an = visibleTypeAnnotations.get(i);
765 an.accept(mv.visitTypeAnnotation(an.typeRef, an.typePath, an.desc,
766 true));
767 }
768 n = invisibleTypeAnnotations == null ? 0 : invisibleTypeAnnotations
769 .size();
770 for (i = 0; i < n; ++i) {
771 TypeAnnotationNode an = invisibleTypeAnnotations.get(i);
772 an.accept(mv.visitTypeAnnotation(an.typeRef, an.typePath, an.desc,
773 false));
774 }
775 n = visibleParameterAnnotations == null ? 0
776 : visibleParameterAnnotations.length;
777 for (i = 0; i < n; ++i) {
778 List<?> l = visibleParameterAnnotations[i];
779 if (l == null) {
780 continue;
781 }
782 for (j = 0; j < l.size(); ++j) {
783 AnnotationNode an = (AnnotationNode) l.get(j);
784 an.accept(mv.visitParameterAnnotation(i, an.desc, true));
785 }
786 }
787 n = invisibleParameterAnnotations == null ? 0
788 : invisibleParameterAnnotations.length;
789 for (i = 0; i < n; ++i) {
790 List<?> l = invisibleParameterAnnotations[i];
791 if (l == null) {
792 continue;
793 }
794 for (j = 0; j < l.size(); ++j) {
795 AnnotationNode an = (AnnotationNode) l.get(j);
796 an.accept(mv.visitParameterAnnotation(i, an.desc, false));
797 }
798 }
799 if (visited) {
800 instructions.resetLabels();
801 }
802 n = attrs == null ? 0 : attrs.size();
803 for (i = 0; i < n; ++i) {
804 mv.visitAttribute(attrs.get(i));
805 }
806 // visits the method's code
807 if (instructions.size() > 0) {
808 mv.visitCode();
809 // visits try catch blocks
810 n = tryCatchBlocks == null ? 0 : tryCatchBlocks.size();
811 for (i = 0; i < n; ++i) {
812 tryCatchBlocks.get(i).updateIndex(i);
813 tryCatchBlocks.get(i).accept(mv);
814 }
815 // visits instructions
816 instructions.accept(mv);
817 // visits local variables
818 n = localVariables == null ? 0 : localVariables.size();
819 for (i = 0; i < n; ++i) {
820 localVariables.get(i).accept(mv);
821 }
822 // visits local variable annotations
823 n = visibleLocalVariableAnnotations == null ? 0
824 : visibleLocalVariableAnnotations.size();
825 for (i = 0; i < n; ++i) {
826 visibleLocalVariableAnnotations.get(i).accept(mv, true);
827 }
828 n = invisibleLocalVariableAnnotations == null ? 0
829 : invisibleLocalVariableAnnotations.size();
830 for (i = 0; i < n; ++i) {
831 invisibleLocalVariableAnnotations.get(i).accept(mv, false);
832 }
833 // visits maxs
834 mv.visitMaxs(maxStack, maxLocals);
835 visited = true;
836 }
837 mv.visitEnd();
838 }
255 }
256
257 @Override
258 public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
259 AnnotationNode annotation = new AnnotationNode(descriptor);
260 if (visible) {
261 if (visibleAnnotations == null) {
262 visibleAnnotations = new ArrayList<AnnotationNode>(1);
263 }
264 visibleAnnotations.add(annotation);
265 } else {
266 if (invisibleAnnotations == null) {
267 invisibleAnnotations = new ArrayList<AnnotationNode>(1);
268 }
269 invisibleAnnotations.add(annotation);
270 }
271 return annotation;
272 }
273
274 @Override
275 public AnnotationVisitor visitTypeAnnotation(
276 final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
277 TypeAnnotationNode typeAnnotation = new TypeAnnotationNode(typeRef, typePath, descriptor);
278 if (visible) {
279 if (visibleTypeAnnotations == null) {
280 visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
281 }
282 visibleTypeAnnotations.add(typeAnnotation);
283 } else {
284 if (invisibleTypeAnnotations == null) {
285 invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
286 }
287 invisibleTypeAnnotations.add(typeAnnotation);
288 }
289 return typeAnnotation;
290 }
291
292 @Override
293 public void visitAnnotableParameterCount(final int parameterCount, final boolean visible) {
294 if (visible) {
295 visibleAnnotableParameterCount = parameterCount;
296 } else {
297 invisibleAnnotableParameterCount = parameterCount;
298 }
299 }
300
301 @Override
302 @SuppressWarnings("unchecked")
303 public AnnotationVisitor visitParameterAnnotation(
304 final int parameter, final String descriptor, final boolean visible) {
305 AnnotationNode annotation = new AnnotationNode(descriptor);
306 if (visible) {
307 if (visibleParameterAnnotations == null) {
308 int params = Type.getArgumentTypes(desc).length;
309 visibleParameterAnnotations = (List<AnnotationNode>[]) new List<?>[params];
310 }
311 if (visibleParameterAnnotations[parameter] == null) {
312 visibleParameterAnnotations[parameter] = new ArrayList<AnnotationNode>(1);
313 }
314 visibleParameterAnnotations[parameter].add(annotation);
315 } else {
316 if (invisibleParameterAnnotations == null) {
317 int params = Type.getArgumentTypes(desc).length;
318 invisibleParameterAnnotations = (List<AnnotationNode>[]) new List<?>[params];
319 }
320 if (invisibleParameterAnnotations[parameter] == null) {
321 invisibleParameterAnnotations[parameter] = new ArrayList<AnnotationNode>(1);
322 }
323 invisibleParameterAnnotations[parameter].add(annotation);
324 }
325 return annotation;
326 }
327
328 @Override
329 public void visitAttribute(final Attribute attribute) {
330 if (attrs == null) {
331 attrs = new ArrayList<Attribute>(1);
332 }
333 attrs.add(attribute);
334 }
335
336 @Override
337 public void visitCode() {
338 // Nothing to do.
339 }
340
341 @Override
342 public void visitFrame(
343 final int type,
344 final int nLocal,
345 final Object[] local,
346 final int nStack,
347 final Object[] stack) {
348 instructions.add(
349 new FrameNode(
350 type,
351 nLocal,
352 local == null ? null : getLabelNodes(local),
353 nStack,
354 stack == null ? null : getLabelNodes(stack)));
355 }
356
357 @Override
358 public void visitInsn(final int opcode) {
359 instructions.add(new InsnNode(opcode));
360 }
361
362 @Override
363 public void visitIntInsn(final int opcode, final int operand) {
364 instructions.add(new IntInsnNode(opcode, operand));
365 }
366
367 @Override
368 public void visitVarInsn(final int opcode, final int var) {
369 instructions.add(new VarInsnNode(opcode, var));
370 }
371
372 @Override
373 public void visitTypeInsn(final int opcode, final String type) {
374 instructions.add(new TypeInsnNode(opcode, type));
375 }
376
377 @Override
378 public void visitFieldInsn(
379 final int opcode, final String owner, final String name, final String descriptor) {
380 instructions.add(new FieldInsnNode(opcode, owner, name, descriptor));
381 }
382
383 /** @deprecated */
384 @Deprecated
385 @Override
386 public void visitMethodInsn(
387 final int opcode, final String owner, final String name, final String descriptor) {
388 if (api >= Opcodes.ASM5) {
389 super.visitMethodInsn(opcode, owner, name, descriptor);
390 return;
391 }
392 instructions.add(new MethodInsnNode(opcode, owner, name, descriptor));
393 }
394
395 @Override
396 public void visitMethodInsn(
397 final int opcode,
398 final String owner,
399 final String name,
400 final String descriptor,
401 final boolean isInterface) {
402 if (api < Opcodes.ASM5) {
403 super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
404 return;
405 }
406 instructions.add(new MethodInsnNode(opcode, owner, name, descriptor, isInterface));
407 }
408
409 @Override
410 public void visitInvokeDynamicInsn(
411 final String name,
412 final String descriptor,
413 final Handle bootstrapMethodHandle,
414 final Object... bootstrapMethodArguments) {
415 instructions.add(
416 new InvokeDynamicInsnNode(
417 name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments));
418 }
419
420 @Override
421 public void visitJumpInsn(final int opcode, final Label label) {
422 instructions.add(new JumpInsnNode(opcode, getLabelNode(label)));
423 }
424
425 @Override
426 public void visitLabel(final Label label) {
427 instructions.add(getLabelNode(label));
428 }
429
430 @Override
431 public void visitLdcInsn(final Object value) {
432 instructions.add(new LdcInsnNode(value));
433 }
434
435 @Override
436 public void visitIincInsn(final int var, final int increment) {
437 instructions.add(new IincInsnNode(var, increment));
438 }
439
440 @Override
441 public void visitTableSwitchInsn(
442 final int min, final int max, final Label dflt, final Label... labels) {
443 instructions.add(new TableSwitchInsnNode(min, max, getLabelNode(dflt), getLabelNodes(labels)));
444 }
445
446 @Override
447 public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) {
448 instructions.add(new LookupSwitchInsnNode(getLabelNode(dflt), keys, getLabelNodes(labels)));
449 }
450
451 @Override
452 public void visitMultiANewArrayInsn(final String descriptor, final int numDimensions) {
453 instructions.add(new MultiANewArrayInsnNode(descriptor, numDimensions));
454 }
455
456 @Override
457 public AnnotationVisitor visitInsnAnnotation(
458 final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
459 // Find the last real instruction, i.e. the instruction targeted by this annotation.
460 AbstractInsnNode currentInsn = instructions.getLast();
461 while (currentInsn.getOpcode() == -1) {
462 currentInsn = currentInsn.getPrevious();
463 }
464 // Add the annotation to this instruction.
465 TypeAnnotationNode typeAnnotation = new TypeAnnotationNode(typeRef, typePath, descriptor);
466 if (visible) {
467 if (currentInsn.visibleTypeAnnotations == null) {
468 currentInsn.visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
469 }
470 currentInsn.visibleTypeAnnotations.add(typeAnnotation);
471 } else {
472 if (currentInsn.invisibleTypeAnnotations == null) {
473 currentInsn.invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
474 }
475 currentInsn.invisibleTypeAnnotations.add(typeAnnotation);
476 }
477 return typeAnnotation;
478 }
479
480 @Override
481 public void visitTryCatchBlock(
482 final Label start, final Label end, final Label handler, final String type) {
483 tryCatchBlocks.add(
484 new TryCatchBlockNode(getLabelNode(start), getLabelNode(end), getLabelNode(handler), type));
485 }
486
487 @Override
488 public AnnotationVisitor visitTryCatchAnnotation(
489 final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
490 TryCatchBlockNode tryCatchBlock = tryCatchBlocks.get((typeRef & 0x00FFFF00) >> 8);
491 TypeAnnotationNode typeAnnotation = new TypeAnnotationNode(typeRef, typePath, descriptor);
492 if (visible) {
493 if (tryCatchBlock.visibleTypeAnnotations == null) {
494 tryCatchBlock.visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
495 }
496 tryCatchBlock.visibleTypeAnnotations.add(typeAnnotation);
497 } else {
498 if (tryCatchBlock.invisibleTypeAnnotations == null) {
499 tryCatchBlock.invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
500 }
501 tryCatchBlock.invisibleTypeAnnotations.add(typeAnnotation);
502 }
503 return typeAnnotation;
504 }
505
506 @Override
507 public void visitLocalVariable(
508 final String name,
509 final String descriptor,
510 final String signature,
511 final Label start,
512 final Label end,
513 final int index) {
514 localVariables.add(
515 new LocalVariableNode(
516 name, descriptor, signature, getLabelNode(start), getLabelNode(end), index));
517 }
518
519 @Override
520 public AnnotationVisitor visitLocalVariableAnnotation(
521 final int typeRef,
522 final TypePath typePath,
523 final Label[] start,
524 final Label[] end,
525 final int[] index,
526 final String descriptor,
527 final boolean visible) {
528 LocalVariableAnnotationNode localVariableAnnotation =
529 new LocalVariableAnnotationNode(
530 typeRef, typePath, getLabelNodes(start), getLabelNodes(end), index, descriptor);
531 if (visible) {
532 if (visibleLocalVariableAnnotations == null) {
533 visibleLocalVariableAnnotations = new ArrayList<LocalVariableAnnotationNode>(1);
534 }
535 visibleLocalVariableAnnotations.add(localVariableAnnotation);
536 } else {
537 if (invisibleLocalVariableAnnotations == null) {
538 invisibleLocalVariableAnnotations = new ArrayList<LocalVariableAnnotationNode>(1);
539 }
540 invisibleLocalVariableAnnotations.add(localVariableAnnotation);
541 }
542 return localVariableAnnotation;
543 }
544
545 @Override
546 public void visitLineNumber(final int line, final Label start) {
547 instructions.add(new LineNumberNode(line, getLabelNode(start)));
548 }
549
550 @Override
551 public void visitMaxs(final int maxStack, final int maxLocals) {
552 this.maxStack = maxStack;
553 this.maxLocals = maxLocals;
554 }
555
556 @Override
557 public void visitEnd() {
558 // Nothing to do.
559 }
560
561 /**
562 * Returns the LabelNode corresponding to the given Label. Creates a new LabelNode if necessary.
563 * The default implementation of this method uses the {@link Label#info} field to store
564 * associations between labels and label nodes.
565 *
566 * @param label a Label.
567 * @return the LabelNode corresponding to label.
568 */
569 protected LabelNode getLabelNode(final Label label) {
570 if (!(label.info instanceof LabelNode)) {
571 label.info = new LabelNode();
572 }
573 return (LabelNode) label.info;
574 }
575
576 private LabelNode[] getLabelNodes(final Label[] labels) {
577 LabelNode[] labelNodes = new LabelNode[labels.length];
578 for (int i = 0, n = labels.length; i < n; ++i) {
579 labelNodes[i] = getLabelNode(labels[i]);
580 }
581 return labelNodes;
582 }
583
584 private Object[] getLabelNodes(final Object[] objects) {
585 Object[] labelNodes = new Object[objects.length];
586 for (int i = 0, n = objects.length; i < n; ++i) {
587 Object o = objects[i];
588 if (o instanceof Label) {
589 o = getLabelNode((Label) o);
590 }
591 labelNodes[i] = o;
592 }
593 return labelNodes;
594 }
595
596 // -----------------------------------------------------------------------------------------------
597 // Accept method
598 // -----------------------------------------------------------------------------------------------
599
600 /**
601 * Checks that this method node is compatible with the given ASM API version. This method checks
602 * that this node, and all its children recursively, do not contain elements that were introduced
603 * in more recent versions of the ASM API than the given version.
604 *
605 * @param api an ASM API version. Must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or
606 * {@link Opcodes#ASM6}.
607 */
608 public void check(final int api) {
609 if (api == Opcodes.ASM4) {
610 if (parameters != null && !parameters.isEmpty()) {
611 throw new UnsupportedClassVersionException();
612 }
613 if (visibleTypeAnnotations != null && !visibleTypeAnnotations.isEmpty()) {
614 throw new UnsupportedClassVersionException();
615 }
616 if (invisibleTypeAnnotations != null && !invisibleTypeAnnotations.isEmpty()) {
617 throw new UnsupportedClassVersionException();
618 }
619 if (tryCatchBlocks != null) {
620 for (int i = tryCatchBlocks.size() - 1; i >= 0; --i) {
621 TryCatchBlockNode tryCatchBlock = tryCatchBlocks.get(i);
622 if (tryCatchBlock.visibleTypeAnnotations != null
623 && !tryCatchBlock.visibleTypeAnnotations.isEmpty()) {
624 throw new UnsupportedClassVersionException();
625 }
626 if (tryCatchBlock.invisibleTypeAnnotations != null
627 && !tryCatchBlock.invisibleTypeAnnotations.isEmpty()) {
628 throw new UnsupportedClassVersionException();
629 }
630 }
631 }
632 for (int i = instructions.size() - 1; i >= 0; --i) {
633 AbstractInsnNode insn = instructions.get(i);
634 if (insn.visibleTypeAnnotations != null && !insn.visibleTypeAnnotations.isEmpty()) {
635 throw new UnsupportedClassVersionException();
636 }
637 if (insn.invisibleTypeAnnotations != null && !insn.invisibleTypeAnnotations.isEmpty()) {
638 throw new UnsupportedClassVersionException();
639 }
640 if (insn instanceof MethodInsnNode) {
641 boolean isInterface = ((MethodInsnNode) insn).itf;
642 if (isInterface != (insn.opcode == Opcodes.INVOKEINTERFACE)) {
643 throw new UnsupportedClassVersionException();
644 }
645 } else if (insn instanceof LdcInsnNode) {
646 Object value = ((LdcInsnNode) insn).cst;
647 if (value instanceof Handle
648 || (value instanceof Type && ((Type) value).getSort() == Type.METHOD)) {
649 throw new UnsupportedClassVersionException();
650 }
651 }
652 }
653 if (visibleLocalVariableAnnotations != null && !visibleLocalVariableAnnotations.isEmpty()) {
654 throw new UnsupportedClassVersionException();
655 }
656 if (invisibleLocalVariableAnnotations != null
657 && !invisibleLocalVariableAnnotations.isEmpty()) {
658 throw new UnsupportedClassVersionException();
659 }
660 }
661 }
662
663 /**
664 * Makes the given class visitor visit this method.
665 *
666 * @param classVisitor a class visitor.
667 */
668 public void accept(final ClassVisitor classVisitor) {
669 String[] exceptionsArray = new String[this.exceptions.size()];
670 this.exceptions.toArray(exceptionsArray);
671 MethodVisitor methodVisitor =
672 classVisitor.visitMethod(access, name, desc, signature, exceptionsArray);
673 if (methodVisitor != null) {
674 accept(methodVisitor);
675 }
676 }
677
678 /**
679 * Makes the given method visitor visit this method.
680 *
681 * @param methodVisitor a method visitor.
682 */
683 public void accept(final MethodVisitor methodVisitor) {
684 // Visit the parameters.
685 if (parameters != null) {
686 for (int i = 0, n = parameters.size(); i < n; i++) {
687 parameters.get(i).accept(methodVisitor);
688 }
689 }
690 // Visit the annotations.
691 if (annotationDefault != null) {
692 AnnotationVisitor annotationVisitor = methodVisitor.visitAnnotationDefault();
693 AnnotationNode.accept(annotationVisitor, null, annotationDefault);
694 if (annotationVisitor != null) {
695 annotationVisitor.visitEnd();
696 }
697 }
698 if (visibleAnnotations != null) {
699 for (int i = 0, n = visibleAnnotations.size(); i < n; ++i) {
700 AnnotationNode annotation = visibleAnnotations.get(i);
701 annotation.accept(methodVisitor.visitAnnotation(annotation.desc, true));
702 }
703 }
704 if (invisibleAnnotations != null) {
705 for (int i = 0, n = invisibleAnnotations.size(); i < n; ++i) {
706 AnnotationNode annotation = invisibleAnnotations.get(i);
707 annotation.accept(methodVisitor.visitAnnotation(annotation.desc, false));
708 }
709 }
710 if (visibleTypeAnnotations != null) {
711 for (int i = 0, n = visibleTypeAnnotations.size(); i < n; ++i) {
712 TypeAnnotationNode typeAnnotation = visibleTypeAnnotations.get(i);
713 typeAnnotation.accept(
714 methodVisitor.visitTypeAnnotation(
715 typeAnnotation.typeRef, typeAnnotation.typePath, typeAnnotation.desc, true));
716 }
717 }
718 if (invisibleTypeAnnotations != null) {
719 for (int i = 0, n = invisibleTypeAnnotations.size(); i < n; ++i) {
720 TypeAnnotationNode typeAnnotation = invisibleTypeAnnotations.get(i);
721 typeAnnotation.accept(
722 methodVisitor.visitTypeAnnotation(
723 typeAnnotation.typeRef, typeAnnotation.typePath, typeAnnotation.desc, false));
724 }
725 }
726 if (visibleAnnotableParameterCount > 0) {
727 methodVisitor.visitAnnotableParameterCount(visibleAnnotableParameterCount, true);
728 }
729 if (visibleParameterAnnotations != null) {
730 for (int i = 0, n = visibleParameterAnnotations.length; i < n; ++i) {
731 List<AnnotationNode> parameterAnnotations = visibleParameterAnnotations[i];
732 if (parameterAnnotations == null) {
733 continue;
734 }
735 for (int j = 0, m = parameterAnnotations.size(); j < m; ++j) {
736 AnnotationNode annotation = parameterAnnotations.get(j);
737 annotation.accept(methodVisitor.visitParameterAnnotation(i, annotation.desc, true));
738 }
739 }
740 }
741 if (invisibleAnnotableParameterCount > 0) {
742 methodVisitor.visitAnnotableParameterCount(invisibleAnnotableParameterCount, false);
743 }
744 if (invisibleParameterAnnotations != null) {
745 for (int i = 0, n = invisibleParameterAnnotations.length; i < n; ++i) {
746 List<AnnotationNode> parameterAnnotations = invisibleParameterAnnotations[i];
747 if (parameterAnnotations == null) {
748 continue;
749 }
750 for (int j = 0, m = parameterAnnotations.size(); j < m; ++j) {
751 AnnotationNode annotation = parameterAnnotations.get(j);
752 annotation.accept(methodVisitor.visitParameterAnnotation(i, annotation.desc, false));
753 }
754 }
755 }
756 // Visit the non standard attributes.
757 if (visited) {
758 instructions.resetLabels();
759 }
760 if (attrs != null) {
761 for (int i = 0, n = attrs.size(); i < n; ++i) {
762 methodVisitor.visitAttribute(attrs.get(i));
763 }
764 }
765 // Visit the code.
766 if (instructions.size() > 0) {
767 methodVisitor.visitCode();
768 // Visits the try catch blocks.
769 if (tryCatchBlocks != null) {
770 for (int i = 0, n = tryCatchBlocks.size(); i < n; ++i) {
771 tryCatchBlocks.get(i).updateIndex(i);
772 tryCatchBlocks.get(i).accept(methodVisitor);
773 }
774 }
775 // Visit the instructions.
776 instructions.accept(methodVisitor);
777 // Visits the local variables.
778 if (localVariables != null) {
779 for (int i = 0, n = localVariables.size(); i < n; ++i) {
780 localVariables.get(i).accept(methodVisitor);
781 }
782 }
783 // Visits the local variable annotations.
784 if (visibleLocalVariableAnnotations != null) {
785 for (int i = 0, n = visibleLocalVariableAnnotations.size(); i < n; ++i) {
786 visibleLocalVariableAnnotations.get(i).accept(methodVisitor, true);
787 }
788 }
789 if (invisibleLocalVariableAnnotations != null) {
790 for (int i = 0, n = invisibleLocalVariableAnnotations.size(); i < n; ++i) {
791 invisibleLocalVariableAnnotations.get(i).accept(methodVisitor, false);
792 }
793 }
794 methodVisitor.visitMaxs(maxStack, maxLocals);
795 visited = true;
796 }
797 methodVisitor.visitEnd();
798 }
839799 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.tree;
3028
3129 import java.util.List;
3432
3533 /**
3634 * A node that represents an exported package with its name and the module that can access to it.
37 *
35 *
3836 * @author Remi Forax
3937 */
4038 public class ModuleExportNode {
41 /**
42 * The package name.
43 */
44 public String packaze;
4539
46 /**
47 * A list of modules that can access to this exported package.
48 * May be <tt>null</tt>.
49 */
50 public List<String> modules;
40 /** The internal name of the exported package. */
41 public String packaze;
5142
52 /**
53 * Constructs a new {@link ModuleExportNode}.
54 *
55 * @param packaze
56 * the parameter's name.
57 * @param modules
58 * a list of modules that can access to this exported package.
59 */
60 public ModuleExportNode(final String packaze, final List<String> modules) {
61 this.packaze = packaze;
62 this.modules = modules;
63 }
43 /**
44 * The access flags (see {@link org.eclipse.persistence.internal.libraries.asm.Opcodes}). Valid values are {@code
45 * ACC_SYNTHETIC} and {@code ACC_MANDATED}.
46 */
47 public int access;
6448
65 /**
66 * Makes the given module visitor visit this export declaration.
67 *
68 * @param mv
69 * a module visitor.
70 */
71 public void accept(final ModuleVisitor mv) {
72 mv.visitExport(packaze, (modules == null)? null: modules.toArray(new String[0]));
73 }
49 /**
50 * The list of modules that can access this exported package, specified with fully qualified names
51 * (using dots). May be <tt>null</tt>.
52 */
53 public List<String> modules;
54
55 /**
56 * Constructs a new {@link ModuleExportNode}.
57 *
58 * @param packaze the internal name of the exported package.
59 * @param access the package access flags, one or more of {@code ACC_SYNTHETIC} and {@code
60 * ACC_MANDATED}.
61 * @param modules a list of modules that can access this exported package, specified with fully
62 * qualified names (using dots).
63 */
64 public ModuleExportNode(final String packaze, final int access, final List<String> modules) {
65 this.packaze = packaze;
66 this.access = access;
67 this.modules = modules;
68 }
69
70 /**
71 * Makes the given module visitor visit this export declaration.
72 *
73 * @param moduleVisitor a module visitor.
74 */
75 public void accept(final ModuleVisitor moduleVisitor) {
76 moduleVisitor.visitExport(
77 packaze, access, modules == null ? null : modules.toArray(new String[modules.size()]));
78 }
7479 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.tree;
3028
3129 import java.util.ArrayList;
3735
3836 /**
3937 * A node that represents a module declaration.
40 *
38 *
4139 * @author Remi Forax
4240 */
4341 public class ModuleNode extends ModuleVisitor {
44 /**
45 * A list of modules can are required by the current module.
46 * May be <tt>null</tt>.
47 */
48 public List<ModuleRequireNode> requires;
49
50 /**
51 * A list of packages that are exported by the current module.
52 * May be <tt>null</tt>.
53 */
54 public List<ModuleExportNode> exports;
55
56 /**
57 * A list of classes in their internal forms that are used
58 * as a service by the current module. May be <tt>null</tt>.
59 */
60 public List<String> uses;
61
62 /**
63 * A list of services along with their implementations provided
64 * by the current module. May be <tt>null</tt>.
65 */
66 public List<ModuleProvideNode> provides;
67
68 public ModuleNode() {
69 super(Opcodes.ASM6);
70 }
71
72 public ModuleNode(final int api,
73 List<ModuleRequireNode> requires,
74 List<ModuleExportNode> exports,
75 List<String> uses,
76 List<ModuleProvideNode> provides) {
77 super(Opcodes.ASM6);
78 this.requires = requires;
79 this.exports = exports;
80 this.uses = uses;
81 this.provides = provides;
82 if (getClass() != ModuleNode.class) {
83 throw new IllegalStateException();
84 }
85 }
86
87 @Override
88 public void visitRequire(String module, int access) {
89 if (requires == null) {
90 requires = new ArrayList<ModuleRequireNode>(5);
91 }
92 requires.add(new ModuleRequireNode(module, access));
93 }
94
95 @Override
96 public void visitExport(String packaze, String... modules) {
97 if (exports == null) {
98 exports = new ArrayList<ModuleExportNode>(5);
99 }
100 List<String> moduleList = null;
101 if (modules != null) {
102 moduleList = new ArrayList<String>(modules.length);
103 for(int i = 0; i < modules.length; i++) {
104 moduleList.add(modules[i]);
105 }
106 }
107 exports.add(new ModuleExportNode(packaze, moduleList));
108 }
109
110 @Override
111 public void visitUse(String service) {
112 if (uses == null) {
113 uses = new ArrayList<String>(5);
114 }
115 uses.add(service);
116 }
117
118 @Override
119 public void visitProvide(String service, String impl) {
120 if (provides == null) {
121 provides = new ArrayList<ModuleProvideNode>(5);
122 }
123 provides.add(new ModuleProvideNode(service, impl));
124 }
125
126 @Override
127 public void visitEnd() {
128 }
129
130 public void accept(final ClassVisitor cv) {
131 ModuleVisitor mv = cv.visitModule();
132 if (mv == null) {
133 return;
134 }
135 if (requires != null) {
136 for(int i = 0; i < requires.size(); i++) {
137 requires.get(i).accept(mv);
138 }
139 }
140 if (exports != null) {
141 for(int i = 0; i < exports.size(); i++) {
142 exports.get(i).accept(mv);
143 }
144 }
145 if (uses != null) {
146 for(int i = 0; i < uses.size(); i++) {
147 mv.visitUse(uses.get(i));
148 }
149 }
150 if (provides != null) {
151 for(int i = 0; i < provides.size(); i++) {
152 provides.get(i).accept(mv);
153 }
154 }
155 }
42
43 /** The fully qualified name (using dots) of this module. */
44 public String name;
45
46 /**
47 * The module's access flags, among {@code ACC_OPEN}, {@code ACC_SYNTHETIC} and {@code
48 * ACC_MANDATED}.
49 */
50 public int access;
51
52 /** The version of this module. May be <tt>null</tt>. */
53 public String version;
54
55 /** The internal name of the main class of this module. May be <tt>null</tt>. */
56 public String mainClass;
57
58 /** The internal name of the packages declared by this module. May be <tt>null</tt>. */
59 public List<String> packages;
60
61 /** The dependencies of this module. May be <tt>null</tt>. */
62 public List<ModuleRequireNode> requires;
63
64 /** The packages exported by this module. May be <tt>null</tt>. */
65 public List<ModuleExportNode> exports;
66
67 /** The packages opened by this module. May be <tt>null</tt>. */
68 public List<ModuleOpenNode> opens;
69
70 /** The internal names of the services used by this module. May be <tt>null</tt>. */
71 public List<String> uses;
72
73 /** The services provided by this module. May be <tt>null</tt>. */
74 public List<ModuleProvideNode> provides;
75
76 /**
77 * Constructs a {@link ModuleNode}. <i>Subclasses must not use this constructor</i>. Instead, they
78 * must use the {@link #ModuleNode(int,String,int,String,List,List,List,List,List)} version.
79 *
80 * @param name the fully qualified name (using dots) of the module.
81 * @param access the module access flags, among {@code ACC_OPEN}, {@code ACC_SYNTHETIC} and {@code
82 * ACC_MANDATED}.
83 * @param version the module version, or <tt>null</tt>.
84 * @throws IllegalStateException If a subclass calls this constructor.
85 */
86 public ModuleNode(final String name, final int access, final String version) {
87 super(Opcodes.ASM6);
88 if (getClass() != ModuleNode.class) {
89 throw new IllegalStateException();
90 }
91 this.name = name;
92 this.access = access;
93 this.version = version;
94 }
95
96 // TODO(forax): why is there no 'mainClass' and 'packages' parameters in this constructor?
97 /**
98 * Constructs a {@link ModuleNode}.
99 *
100 * @param api the ASM API version implemented by this visitor. Must be {@link Opcodes#ASM6}.
101 * @param name the fully qualified name (using dots) of the module.
102 * @param access the module access flags, among {@code ACC_OPEN}, {@code ACC_SYNTHETIC} and {@code
103 * ACC_MANDATED}.
104 * @param version the module version, or <tt>null</tt>.
105 * @param requires The dependencies of this module. May be <tt>null</tt>.
106 * @param exports The packages exported by this module. May be <tt>null</tt>.
107 * @param opens The packages opened by this module. May be <tt>null</tt>.
108 * @param uses The internal names of the services used by this module. May be <tt>null</tt>.
109 * @param provides The services provided by this module. May be <tt>null</tt>.
110 */
111 public ModuleNode(
112 final int api,
113 final String name,
114 final int access,
115 final String version,
116 final List<ModuleRequireNode> requires,
117 final List<ModuleExportNode> exports,
118 final List<ModuleOpenNode> opens,
119 final List<String> uses,
120 final List<ModuleProvideNode> provides) {
121 super(api);
122 this.name = name;
123 this.access = access;
124 this.version = version;
125 this.requires = requires;
126 this.exports = exports;
127 this.opens = opens;
128 this.uses = uses;
129 this.provides = provides;
130 }
131
132 @Override
133 public void visitMainClass(final String mainClass) {
134 this.mainClass = mainClass;
135 }
136
137 @Override
138 public void visitPackage(final String packaze) {
139 if (packages == null) {
140 packages = new ArrayList<String>(5);
141 }
142 packages.add(packaze);
143 }
144
145 @Override
146 public void visitRequire(final String module, final int access, final String version) {
147 if (requires == null) {
148 requires = new ArrayList<ModuleRequireNode>(5);
149 }
150 requires.add(new ModuleRequireNode(module, access, version));
151 }
152
153 @Override
154 public void visitExport(final String packaze, final int access, final String... modules) {
155 if (exports == null) {
156 exports = new ArrayList<ModuleExportNode>(5);
157 }
158 exports.add(new ModuleExportNode(packaze, access, Util.asArrayList(modules)));
159 }
160
161 @Override
162 public void visitOpen(final String packaze, final int access, final String... modules) {
163 if (opens == null) {
164 opens = new ArrayList<ModuleOpenNode>(5);
165 }
166 opens.add(new ModuleOpenNode(packaze, access, Util.asArrayList(modules)));
167 }
168
169 @Override
170 public void visitUse(final String service) {
171 if (uses == null) {
172 uses = new ArrayList<String>(5);
173 }
174 uses.add(service);
175 }
176
177 @Override
178 public void visitProvide(final String service, final String... providers) {
179 if (provides == null) {
180 provides = new ArrayList<ModuleProvideNode>(5);
181 }
182 provides.add(new ModuleProvideNode(service, Util.asArrayList(providers)));
183 }
184
185 @Override
186 public void visitEnd() {
187 // Nothing to do.
188 }
189
190 public void accept(final ClassVisitor classVisitor) {
191 ModuleVisitor moduleVisitor = classVisitor.visitModule(name, access, version);
192 if (moduleVisitor == null) {
193 return;
194 }
195 if (mainClass != null) {
196 moduleVisitor.visitMainClass(mainClass);
197 }
198 if (packages != null) {
199 for (int i = 0, n = packages.size(); i < n; i++) {
200 moduleVisitor.visitPackage(packages.get(i));
201 }
202 }
203 if (requires != null) {
204 for (int i = 0, n = requires.size(); i < n; i++) {
205 requires.get(i).accept(moduleVisitor);
206 }
207 }
208 if (exports != null) {
209 for (int i = 0, n = exports.size(); i < n; i++) {
210 exports.get(i).accept(moduleVisitor);
211 }
212 }
213 if (opens != null) {
214 for (int i = 0, n = opens.size(); i < n; i++) {
215 opens.get(i).accept(moduleVisitor);
216 }
217 }
218 if (uses != null) {
219 for (int i = 0, n = uses.size(); i < n; i++) {
220 moduleVisitor.visitUse(uses.get(i));
221 }
222 }
223 if (provides != null) {
224 for (int i = 0, n = provides.size(); i < n; i++) {
225 provides.get(i).accept(moduleVisitor);
226 }
227 }
228 }
156229 }
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
27 package org.eclipse.persistence.internal.libraries.asm.tree;
28
29 import java.util.List;
30
31 import org.eclipse.persistence.internal.libraries.asm.ModuleVisitor;
32
33 /**
34 * A node that represents an opened package with its name and the module that can access it.
35 *
36 * @author Remi Forax
37 */
38 public class ModuleOpenNode {
39
40 /** The internal name of the opened package. */
41 public String packaze;
42
43 /**
44 * The access flag of the opened package, valid values are among {@code ACC_SYNTHETIC} and {@code
45 * ACC_MANDATED}.
46 */
47 public int access;
48
49 /**
50 * The fully qualified names (using dots) of the modules that can use deep reflection to the
51 * classes of the open package, or <tt>null</tt>.
52 */
53 public List<String> modules;
54
55 /**
56 * Constructs a new {@link ModuleOpenNode}.
57 *
58 * @param packaze the internal name of the opened package.
59 * @param access the access flag of the opened package, valid values are among {@code
60 * ACC_SYNTHETIC} and {@code ACC_MANDATED}.
61 * @param modules the fully qualified names (using dots) of the modules that can use deep
62 * reflection to the classes of the open package, or <tt>null</tt>.
63 */
64 public ModuleOpenNode(final String packaze, final int access, final List<String> modules) {
65 this.packaze = packaze;
66 this.access = access;
67 this.modules = modules;
68 }
69
70 /**
71 * Makes the given module visitor visit this opened package.
72 *
73 * @param moduleVisitor a module visitor.
74 */
75 public void accept(final ModuleVisitor moduleVisitor) {
76 moduleVisitor.visitOpen(
77 packaze, access, modules == null ? null : modules.toArray(new String[modules.size()]));
78 }
79 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.tree;
28
29 import java.util.List;
3030
3131 import org.eclipse.persistence.internal.libraries.asm.ModuleVisitor;
3232
3333 /**
3434 * A node that represents a service and its implementation provided by the current module.
35 *
35 *
3636 * @author Remi Forax
3737 */
3838 public class ModuleProvideNode {
39 /**
40 * The service name (in its internal form).
41 */
42 public String service;
4339
44 /**
45 * The implementation name (in its internal form).
46 */
47 public String impl;
40 /** The internal name of the service. */
41 public String service;
4842
49 /**
50 * Constructs a new {@link ModuleProvideNode}.
51 *
52 * @param service
53 * the service name (in its internal form).
54 * @param impl
55 * the implementation name (in its internal form).
56 */
57 public ModuleProvideNode(final String service, final String impl) {
58 this.service = service;
59 this.impl = impl;
60 }
43 /** The internal names of the implementations of the service (there is at least one provider). */
44 public List<String> providers;
6145
62 /**
63 * Makes the given module visitor visit this require declaration.
64 *
65 * @param mv
66 * a module visitor.
67 */
68 public void accept(final ModuleVisitor mv) {
69 mv.visitProvide(service, impl);
70 }
46 /**
47 * Constructs a new {@link ModuleProvideNode}.
48 *
49 * @param service the internal name of the service.
50 * @param providers the internal names of the implementations of the service (there is at least
51 * one provider).
52 */
53 public ModuleProvideNode(final String service, final List<String> providers) {
54 this.service = service;
55 this.providers = providers;
56 }
57
58 /**
59 * Makes the given module visitor visit this require declaration.
60 *
61 * @param moduleVisitor a module visitor.
62 */
63 public void accept(final ModuleVisitor moduleVisitor) {
64 moduleVisitor.visitProvide(service, providers.toArray(new String[providers.size()]));
65 }
7166 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.tree;
3028
3129 import org.eclipse.persistence.internal.libraries.asm.ModuleVisitor;
3230
3331 /**
3432 * A node that represents a required module with its name and access of a module descriptor.
35 *
33 *
3634 * @author Remi Forax
3735 */
3836 public class ModuleRequireNode {
39 /**
40 * The name of the required module.
41 */
42 public String module;
4337
44 /**
45 * The access flags (see {@link org.eclipse.persistence.internal.libraries.asm.Opcodes}).
46 * Valid values are <tt>ACC_PUBLIC</tt>, <tt>ACC_SYNTHETIC</tt> and
47 * <tt>ACC_MANDATED</tt>.
48 */
49 public int access;
38 /** The fully qualified name (using dots) of the dependence. */
39 public String module;
5040
51 /**
52 * Constructs a new {@link ModuleRequireNode}.
53 *
54 * @param module
55 * the name of the required module.
56 * @param access
57 * The access flags. Valid values are
58 * <tt>ACC_PUBLIC</tt>, <tt>ACC_SYNTHETIC</tt> or/and
59 * <tt>ACC_MANDATED</tt> (see {@link org.eclipse.persistence.internal.libraries.asm.Opcodes}).
60 */
61 public ModuleRequireNode(final String module, final int access) {
62 this.module = module;
63 this.access = access;
64 }
41 /**
42 * The access flag of the dependence among {@code ACC_TRANSITIVE}, {@code ACC_STATIC_PHASE},
43 * {@code ACC_SYNTHETIC} and {@code ACC_MANDATED}.
44 */
45 public int access;
6546
66 /**
67 * Makes the given module visitor visit this require declaration.
68 *
69 * @param mv
70 * a module visitor.
71 */
72 public void accept(final ModuleVisitor mv) {
73 mv.visitRequire(module, access);
74 }
47 /** The module version at compile time, or <tt>null</tt>. */
48 public String version;
49
50 /**
51 * Constructs a new {@link ModuleRequireNode}.
52 *
53 * @param module the fully qualified name (using dots) of the dependence.
54 * @param access the access flag of the dependence among {@code ACC_TRANSITIVE}, {@code
55 * ACC_STATIC_PHASE}, {@code ACC_SYNTHETIC} and {@code ACC_MANDATED}.
56 * @param version the module version at compile time, or <tt>null</tt>.
57 */
58 public ModuleRequireNode(final String module, final int access, final String version) {
59 this.module = module;
60 this.access = access;
61 this.version = version;
62 }
63
64 /**
65 * Makes the given module visitor visit this require directive.
66 *
67 * @param moduleVisitor a module visitor.
68 */
69 public void accept(final ModuleVisitor moduleVisitor) {
70 moduleVisitor.visitRequire(module, access, version);
71 }
7572 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.tree;
3028
3129 import java.util.Map;
3533
3634 /**
3735 * A node that represents a MULTIANEWARRAY instruction.
38 *
36 *
3937 * @author Eric Bruneton
4038 */
4139 public class MultiANewArrayInsnNode extends AbstractInsnNode {
4240
43 /**
44 * An array type descriptor (see {@link org.eclipse.persistence.internal.libraries.asm.Type}).
45 */
46 public String desc;
41 /** An array type descriptor (see {@link org.eclipse.persistence.internal.libraries.asm.Type}). */
42 public String desc;
4743
48 /**
49 * Number of dimensions of the array to allocate.
50 */
51 public int dims;
44 /** Number of dimensions of the array to allocate. */
45 public int dims;
5246
53 /**
54 * Constructs a new {@link MultiANewArrayInsnNode}.
55 *
56 * @param desc
57 * an array type descriptor (see {@link org.eclipse.persistence.internal.libraries.asm.Type}).
58 * @param dims
59 * number of dimensions of the array to allocate.
60 */
61 public MultiANewArrayInsnNode(final String desc, final int dims) {
62 super(Opcodes.MULTIANEWARRAY);
63 this.desc = desc;
64 this.dims = dims;
65 }
47 /**
48 * Constructs a new {@link MultiANewArrayInsnNode}.
49 *
50 * @param descriptor an array type descriptor (see {@link org.eclipse.persistence.internal.libraries.asm.Type}).
51 * @param numDimensions the number of dimensions of the array to allocate.
52 */
53 public MultiANewArrayInsnNode(final String descriptor, final int numDimensions) {
54 super(Opcodes.MULTIANEWARRAY);
55 this.desc = descriptor;
56 this.dims = numDimensions;
57 }
6658
67 @Override
68 public int getType() {
69 return MULTIANEWARRAY_INSN;
70 }
59 @Override
60 public int getType() {
61 return MULTIANEWARRAY_INSN;
62 }
7163
72 @Override
73 public void accept(final MethodVisitor mv) {
74 mv.visitMultiANewArrayInsn(desc, dims);
75 acceptAnnotations(mv);
76 }
64 @Override
65 public void accept(final MethodVisitor methodVisitor) {
66 methodVisitor.visitMultiANewArrayInsn(desc, dims);
67 acceptAnnotations(methodVisitor);
68 }
7769
78 @Override
79 public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
80 return new MultiANewArrayInsnNode(desc, dims).cloneAnnotations(this);
81 }
82
83 }
70 @Override
71 public AbstractInsnNode clone(final Map<LabelNode, LabelNode> clonedLabels) {
72 return new MultiANewArrayInsnNode(desc, dims).cloneAnnotations(this);
73 }
74 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.tree;
3028
3129 import org.eclipse.persistence.internal.libraries.asm.MethodVisitor;
3230
3331 /**
34 * A node that represents a parameter access and name.
35 *
32 * A node that represents a parameter of a method.
33 *
3634 * @author Remi Forax
3735 */
3836 public class ParameterNode {
39 /**
40 * The parameter's name.
41 */
42 public String name;
4337
44 /**
45 * The parameter's access flags (see {@link org.eclipse.persistence.internal.libraries.asm.Opcodes}).
46 * Valid values are <tt>ACC_FINAL</tt>, <tt>ACC_SYNTHETIC</tt> and
47 * <tt>ACC_MANDATED</tt>.
48 */
49 public int access;
38 /** The parameter's name. */
39 public String name;
5040
51 /**
52 * Constructs a new {@link ParameterNode}.
53 *
54 * @param access
55 * The parameter's access flags. Valid values are
56 * <tt>ACC_FINAL</tt>, <tt>ACC_SYNTHETIC</tt> or/and
57 * <tt>ACC_MANDATED</tt> (see {@link org.eclipse.persistence.internal.libraries.asm.Opcodes}).
58 * @param name
59 * the parameter's name.
60 */
61 public ParameterNode(final String name, final int access) {
62 this.name = name;
63 this.access = access;
64 }
41 /**
42 * The parameter's access flags (see {@link org.eclipse.persistence.internal.libraries.asm.Opcodes}). Valid values are
43 * <tt>ACC_FINAL</tt>, <tt>ACC_SYNTHETIC</tt> and <tt>ACC_MANDATED</tt>.
44 */
45 public int access;
6546
66 /**
67 * Makes the given visitor visit this parameter declaration.
68 *
69 * @param mv
70 * a method visitor.
71 */
72 public void accept(final MethodVisitor mv) {
73 mv.visitParameter(name, access);
74 }
47 /**
48 * Constructs a new {@link ParameterNode}.
49 *
50 * @param access The parameter's access flags. Valid values are <tt>ACC_FINAL</tt>,
51 * <tt>ACC_SYNTHETIC</tt> or/and <tt>ACC_MANDATED</tt> (see {@link
52 * org.eclipse.persistence.internal.libraries.asm.Opcodes}).
53 * @param name the parameter's name.
54 */
55 public ParameterNode(final String name, final int access) {
56 this.name = name;
57 this.access = access;
58 }
59
60 /**
61 * Makes the given visitor visit this parameter declaration.
62 *
63 * @param methodVisitor a method visitor.
64 */
65 public void accept(final MethodVisitor methodVisitor) {
66 methodVisitor.visitParameter(name, access);
67 }
7568 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.tree;
3028
31 import java.util.ArrayList;
32 import java.util.Arrays;
3329 import java.util.List;
3430 import java.util.Map;
3531
3935
4036 /**
4137 * A node that represents a TABLESWITCH instruction.
42 *
38 *
4339 * @author Eric Bruneton
4440 */
4541 public class TableSwitchInsnNode extends AbstractInsnNode {
4642
47 /**
48 * The minimum key value.
49 */
50 public int min;
43 /** The minimum key value. */
44 public int min;
5145
52 /**
53 * The maximum key value.
54 */
55 public int max;
46 /** The maximum key value. */
47 public int max;
5648
57 /**
58 * Beginning of the default handler block.
59 */
60 public LabelNode dflt;
49 /** Beginning of the default handler block. */
50 public LabelNode dflt;
6151
62 /**
63 * Beginnings of the handler blocks. This list is a list of
64 * {@link LabelNode} objects.
65 */
66 public List<LabelNode> labels;
52 /** Beginnings of the handler blocks. This list is a list of {@link LabelNode} objects. */
53 public List<LabelNode> labels;
6754
68 /**
69 * Constructs a new {@link TableSwitchInsnNode}.
70 *
71 * @param min
72 * the minimum key value.
73 * @param max
74 * the maximum key value.
75 * @param dflt
76 * beginning of the default handler block.
77 * @param labels
78 * beginnings of the handler blocks. <tt>labels[i]</tt> is the
79 * beginning of the handler block for the <tt>min + i</tt> key.
80 */
81 public TableSwitchInsnNode(final int min, final int max,
82 final LabelNode dflt, final LabelNode... labels) {
83 super(Opcodes.TABLESWITCH);
84 this.min = min;
85 this.max = max;
86 this.dflt = dflt;
87 this.labels = new ArrayList<LabelNode>();
88 if (labels != null) {
89 this.labels.addAll(Arrays.asList(labels));
90 }
55 /**
56 * Constructs a new {@link TableSwitchInsnNode}.
57 *
58 * @param min the minimum key value.
59 * @param max the maximum key value.
60 * @param dflt beginning of the default handler block.
61 * @param labels beginnings of the handler blocks. <tt>labels[i]</tt> is the beginning of the
62 * handler block for the <tt>min + i</tt> key.
63 */
64 public TableSwitchInsnNode(
65 final int min, final int max, final LabelNode dflt, final LabelNode... labels) {
66 super(Opcodes.TABLESWITCH);
67 this.min = min;
68 this.max = max;
69 this.dflt = dflt;
70 this.labels = Util.asArrayList(labels);
71 }
72
73 @Override
74 public int getType() {
75 return TABLESWITCH_INSN;
76 }
77
78 @Override
79 public void accept(final MethodVisitor methodVisitor) {
80 Label[] labelsArray = new Label[this.labels.size()];
81 for (int i = 0, n = labelsArray.length; i < n; ++i) {
82 labelsArray[i] = this.labels.get(i).getLabel();
9183 }
84 methodVisitor.visitTableSwitchInsn(min, max, dflt.getLabel(), labelsArray);
85 acceptAnnotations(methodVisitor);
86 }
9287
93 @Override
94 public int getType() {
95 return TABLESWITCH_INSN;
96 }
97
98 @Override
99 public void accept(final MethodVisitor mv) {
100 Label[] labels = new Label[this.labels.size()];
101 for (int i = 0; i < labels.length; ++i) {
102 labels[i] = this.labels.get(i).getLabel();
103 }
104 mv.visitTableSwitchInsn(min, max, dflt.getLabel(), labels);
105 acceptAnnotations(mv);
106 }
107
108 @Override
109 public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
110 return new TableSwitchInsnNode(min, max, clone(dflt, labels), clone(
111 this.labels, labels)).cloneAnnotations(this);
112 }
113 }
88 @Override
89 public AbstractInsnNode clone(final Map<LabelNode, LabelNode> clonedLabels) {
90 return new TableSwitchInsnNode(min, max, clone(dflt, clonedLabels), clone(labels, clonedLabels))
91 .cloneAnnotations(this);
92 }
93 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.tree;
3028
3129 import java.util.List;
3432
3533 /**
3634 * A node that represents a try catch block.
37 *
35 *
3836 * @author Eric Bruneton
3937 */
4038 public class TryCatchBlockNode {
4139
42 /**
43 * Beginning of the exception handler's scope (inclusive).
44 */
45 public LabelNode start;
40 /** The beginning of the exception handler's scope (inclusive). */
41 public LabelNode start;
4642
47 /**
48 * End of the exception handler's scope (exclusive).
49 */
50 public LabelNode end;
43 /** The end of the exception handler's scope (exclusive). */
44 public LabelNode end;
5145
52 /**
53 * Beginning of the exception handler's code.
54 */
55 public LabelNode handler;
46 /** The beginning of the exception handler's code. */
47 public LabelNode handler;
5648
57 /**
58 * Internal name of the type of exceptions handled by the handler. May be
59 * <tt>null</tt> to catch any exceptions (for "finally" blocks).
60 */
61 public String type;
49 /**
50 * The internal name of the type of exceptions handled by the handler. May be <tt>null</tt> to
51 * catch any exceptions (for "finally" blocks).
52 */
53 public String type;
6254
63 /**
64 * The runtime visible type annotations on the exception handler type. This
65 * list is a list of {@link TypeAnnotationNode} objects. May be
66 * <tt>null</tt>.
67 *
68 * @associates org.eclipse.persistence.internal.libraries.asm.tree.TypeAnnotationNode
69 * @label visible
70 */
71 public List<TypeAnnotationNode> visibleTypeAnnotations;
55 /** The runtime visible type annotations on the exception handler type. May be <tt>null</tt>. */
56 public List<TypeAnnotationNode> visibleTypeAnnotations;
7257
73 /**
74 * The runtime invisible type annotations on the exception handler type.
75 * This list is a list of {@link TypeAnnotationNode} objects. May be
76 * <tt>null</tt>.
77 *
78 * @associates org.eclipse.persistence.internal.libraries.asm.tree.TypeAnnotationNode
79 * @label invisible
80 */
81 public List<TypeAnnotationNode> invisibleTypeAnnotations;
58 /** The runtime invisible type annotations on the exception handler type. May be <tt>null</tt>. */
59 public List<TypeAnnotationNode> invisibleTypeAnnotations;
8260
83 /**
84 * Constructs a new {@link TryCatchBlockNode}.
85 *
86 * @param start
87 * beginning of the exception handler's scope (inclusive).
88 * @param end
89 * end of the exception handler's scope (exclusive).
90 * @param handler
91 * beginning of the exception handler's code.
92 * @param type
93 * internal name of the type of exceptions handled by the
94 * handler, or <tt>null</tt> to catch any exceptions (for
95 * "finally" blocks).
96 */
97 public TryCatchBlockNode(final LabelNode start, final LabelNode end,
98 final LabelNode handler, final String type) {
99 this.start = start;
100 this.end = end;
101 this.handler = handler;
102 this.type = type;
61 /**
62 * Constructs a new {@link TryCatchBlockNode}.
63 *
64 * @param start the beginning of the exception handler's scope (inclusive).
65 * @param end the end of the exception handler's scope (exclusive).
66 * @param handler the beginning of the exception handler's code.
67 * @param type the internal name of the type of exceptions handled by the handler, or
68 * <tt>null</tt> to catch any exceptions (for "finally" blocks).
69 */
70 public TryCatchBlockNode(
71 final LabelNode start, final LabelNode end, final LabelNode handler, final String type) {
72 this.start = start;
73 this.end = end;
74 this.handler = handler;
75 this.type = type;
76 }
77
78 /**
79 * Updates the index of this try catch block in the method's list of try catch block nodes. This
80 * index maybe stored in the 'target' field of the type annotations of this block.
81 *
82 * @param index the new index of this try catch block in the method's list of try catch block
83 * nodes.
84 */
85 public void updateIndex(final int index) {
86 int newTypeRef = 0x42000000 | (index << 8);
87 if (visibleTypeAnnotations != null) {
88 for (int i = 0, n = visibleTypeAnnotations.size(); i < n; ++i) {
89 visibleTypeAnnotations.get(i).typeRef = newTypeRef;
90 }
10391 }
92 if (invisibleTypeAnnotations != null) {
93 for (int i = 0, n = invisibleTypeAnnotations.size(); i < n; ++i) {
94 invisibleTypeAnnotations.get(i).typeRef = newTypeRef;
95 }
96 }
97 }
10498
105 /**
106 * Updates the index of this try catch block in the method's list of try
107 * catch block nodes. This index maybe stored in the 'target' field of the
108 * type annotations of this block.
109 *
110 * @param index
111 * the new index of this try catch block in the method's list of
112 * try catch block nodes.
113 */
114 public void updateIndex(final int index) {
115 int newTypeRef = 0x42000000 | (index << 8);
116 if (visibleTypeAnnotations != null) {
117 for (TypeAnnotationNode tan : visibleTypeAnnotations) {
118 tan.typeRef = newTypeRef;
119 }
120 }
121 if (invisibleTypeAnnotations != null) {
122 for (TypeAnnotationNode tan : invisibleTypeAnnotations) {
123 tan.typeRef = newTypeRef;
124 }
125 }
99 /**
100 * Makes the given visitor visit this try catch block.
101 *
102 * @param methodVisitor a method visitor.
103 */
104 public void accept(final MethodVisitor methodVisitor) {
105 methodVisitor.visitTryCatchBlock(
106 start.getLabel(), end.getLabel(), handler == null ? null : handler.getLabel(), type);
107 if (visibleTypeAnnotations != null) {
108 for (int i = 0, n = visibleTypeAnnotations.size(); i < n; ++i) {
109 TypeAnnotationNode typeAnnotation = visibleTypeAnnotations.get(i);
110 typeAnnotation.accept(
111 methodVisitor.visitTryCatchAnnotation(
112 typeAnnotation.typeRef, typeAnnotation.typePath, typeAnnotation.desc, true));
113 }
126114 }
127
128 /**
129 * Makes the given visitor visit this try catch block.
130 *
131 * @param mv
132 * a method visitor.
133 */
134 public void accept(final MethodVisitor mv) {
135 mv.visitTryCatchBlock(start.getLabel(), end.getLabel(),
136 handler == null ? null : handler.getLabel(), type);
137 int n = visibleTypeAnnotations == null ? 0 : visibleTypeAnnotations
138 .size();
139 for (int i = 0; i < n; ++i) {
140 TypeAnnotationNode an = visibleTypeAnnotations.get(i);
141 an.accept(mv.visitTryCatchAnnotation(an.typeRef, an.typePath,
142 an.desc, true));
143 }
144 n = invisibleTypeAnnotations == null ? 0 : invisibleTypeAnnotations
145 .size();
146 for (int i = 0; i < n; ++i) {
147 TypeAnnotationNode an = invisibleTypeAnnotations.get(i);
148 an.accept(mv.visitTryCatchAnnotation(an.typeRef, an.typePath,
149 an.desc, false));
150 }
115 if (invisibleTypeAnnotations != null) {
116 for (int i = 0, n = invisibleTypeAnnotations.size(); i < n; ++i) {
117 TypeAnnotationNode typeAnnotation = invisibleTypeAnnotations.get(i);
118 typeAnnotation.accept(
119 methodVisitor.visitTryCatchAnnotation(
120 typeAnnotation.typeRef, typeAnnotation.typePath, typeAnnotation.desc, false));
121 }
151122 }
123 }
152124 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 package org.eclipse.persistence.internal.libraries.asm.tree;
30
31 import org.eclipse.persistence.internal.libraries.asm.Opcodes;
32 import org.eclipse.persistence.internal.libraries.asm.TypePath;
33 import org.eclipse.persistence.internal.libraries.asm.TypeReference;
34
35 /**
36 * A node that represents a type annotationn.
37 *
38 * @author Eric Bruneton
39 */
40 public class TypeAnnotationNode extends AnnotationNode {
41
42 /**
43 * A reference to the annotated type. See {@link TypeReference}.
44 */
45 public int typeRef;
46
47 /**
48 * The path to the annotated type argument, wildcard bound, array element
49 * type, or static outer type within the referenced type. May be
50 * <tt>null</tt> if the annotation targets 'typeRef' as a whole.
51 */
52 public TypePath typePath;
53
54 /**
55 * Constructs a new {@link AnnotationNode}. <i>Subclasses must not use this
56 * constructor</i>. Instead, they must use the
57 * {@link #TypeAnnotationNode(int, int, TypePath, String)} version.
58 *
59 * @param typeRef
60 * a reference to the annotated type. See {@link TypeReference}.
61 * @param typePath
62 * the path to the annotated type argument, wildcard bound, array
63 * element type, or static inner type within 'typeRef'. May be
64 * <tt>null</tt> if the annotation targets 'typeRef' as a whole.
65 * @param desc
66 * the class descriptor of the annotation class.
67 * @throws IllegalStateException
68 * If a subclass calls this constructor.
69 */
70 public TypeAnnotationNode(final int typeRef, final TypePath typePath,
71 final String desc) {
72 this(Opcodes.ASM6, typeRef, typePath, desc);
73 if (getClass() != TypeAnnotationNode.class) {
74 throw new IllegalStateException();
75 }
76 }
77
78 /**
79 * Constructs a new {@link AnnotationNode}.
80 *
81 * @param api
82 * the ASM API version implemented by this visitor. Must be one
83 * of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
84 * @param typeRef
85 * a reference to the annotated type. See {@link TypeReference}.
86 * @param typePath
87 * the path to the annotated type argument, wildcard bound, array
88 * element type, or static inner type within 'typeRef'. May be
89 * <tt>null</tt> if the annotation targets 'typeRef' as a whole.
90 * @param desc
91 * the class descriptor of the annotation class.
92 */
93 public TypeAnnotationNode(final int api, final int typeRef,
94 final TypePath typePath, final String desc) {
95 super(api, desc);
96 this.typeRef = typeRef;
97 this.typePath = typePath;
98 }
99 }
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
27 package org.eclipse.persistence.internal.libraries.asm.tree;
28
29 import org.eclipse.persistence.internal.libraries.asm.Opcodes;
30 import org.eclipse.persistence.internal.libraries.asm.TypePath;
31
32 /**
33 * A node that represents a type annotation.
34 *
35 * @author Eric Bruneton
36 */
37 public class TypeAnnotationNode extends AnnotationNode {
38
39 /** A reference to the annotated type. See {@link org.eclipse.persistence.internal.libraries.asm.TypeReference}. */
40 public int typeRef;
41
42 /**
43 * The path to the annotated type argument, wildcard bound, array element type, or static outer
44 * type within the referenced type. May be <tt>null</tt> if the annotation targets 'typeRef' as a
45 * whole.
46 */
47 public TypePath typePath;
48
49 /**
50 * Constructs a new {@link AnnotationNode}. <i>Subclasses must not use this constructor</i>.
51 * Instead, they must use the {@link #TypeAnnotationNode(int, int, TypePath, String)} version.
52 *
53 * @param typeRef a reference to the annotated type. See {@link org.eclipse.persistence.internal.libraries.asm.TypeReference}.
54 * @param typePath the path to the annotated type argument, wildcard bound, array element type, or
55 * static inner type within 'typeRef'. May be <tt>null</tt> if the annotation targets
56 * 'typeRef' as a whole.
57 * @param descriptor the class descriptor of the annotation class.
58 * @throws IllegalStateException If a subclass calls this constructor.
59 */
60 public TypeAnnotationNode(final int typeRef, final TypePath typePath, final String descriptor) {
61 this(Opcodes.ASM6, typeRef, typePath, descriptor);
62 if (getClass() != TypeAnnotationNode.class) {
63 throw new IllegalStateException();
64 }
65 }
66
67 /**
68 * Constructs a new {@link AnnotationNode}.
69 *
70 * @param api the ASM API version implemented by this visitor. Must be one of {@link
71 * Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
72 * @param typeRef a reference to the annotated type. See {@link org.eclipse.persistence.internal.libraries.asm.TypeReference}.
73 * @param typePath the path to the annotated type argument, wildcard bound, array element type, or
74 * static inner type within 'typeRef'. May be <tt>null</tt> if the annotation targets
75 * 'typeRef' as a whole.
76 * @param descriptor the class descriptor of the annotation class.
77 */
78 public TypeAnnotationNode(
79 final int api, final int typeRef, final TypePath typePath, final String descriptor) {
80 super(api, descriptor);
81 this.typeRef = typeRef;
82 this.typePath = typePath;
83 }
84 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.tree;
3028
3129 import java.util.Map;
3331 import org.eclipse.persistence.internal.libraries.asm.MethodVisitor;
3432
3533 /**
36 * A node that represents a type instruction. A type instruction is an
37 * instruction that takes a type descriptor as parameter.
38 *
34 * A node that represents a type instruction. A type instruction is an instruction that takes a type
35 * descriptor as parameter.
36 *
3937 * @author Eric Bruneton
4038 */
4139 public class TypeInsnNode extends AbstractInsnNode {
4240
43 /**
44 * The operand of this instruction. This operand is an internal name (see
45 * {@link org.eclipse.persistence.internal.libraries.asm.Type}).
46 */
47 public String desc;
41 /**
42 * The operand of this instruction. This operand is an internal name (see {@link
43 * org.eclipse.persistence.internal.libraries.asm.Type}).
44 */
45 public String desc;
4846
49 /**
50 * Constructs a new {@link TypeInsnNode}.
51 *
52 * @param opcode
53 * the opcode of the type instruction to be constructed. This
54 * opcode must be NEW, ANEWARRAY, CHECKCAST or INSTANCEOF.
55 * @param desc
56 * the operand of the instruction to be constructed. This operand
57 * is an internal name (see {@link org.eclipse.persistence.internal.libraries.asm.Type}).
58 */
59 public TypeInsnNode(final int opcode, final String desc) {
60 super(opcode);
61 this.desc = desc;
62 }
47 /**
48 * Constructs a new {@link TypeInsnNode}.
49 *
50 * @param opcode the opcode of the type instruction to be constructed. This opcode must be NEW,
51 * ANEWARRAY, CHECKCAST or INSTANCEOF.
52 * @param descriptor the operand of the instruction to be constructed. This operand is an internal
53 * name (see {@link org.eclipse.persistence.internal.libraries.asm.Type}).
54 */
55 public TypeInsnNode(final int opcode, final String descriptor) {
56 super(opcode);
57 this.desc = descriptor;
58 }
6359
64 /**
65 * Sets the opcode of this instruction.
66 *
67 * @param opcode
68 * the new instruction opcode. This opcode must be NEW,
69 * ANEWARRAY, CHECKCAST or INSTANCEOF.
70 */
71 public void setOpcode(final int opcode) {
72 this.opcode = opcode;
73 }
60 /**
61 * Sets the opcode of this instruction.
62 *
63 * @param opcode the new instruction opcode. This opcode must be NEW, ANEWARRAY, CHECKCAST or
64 * INSTANCEOF.
65 */
66 public void setOpcode(final int opcode) {
67 this.opcode = opcode;
68 }
7469
75 @Override
76 public int getType() {
77 return TYPE_INSN;
78 }
70 @Override
71 public int getType() {
72 return TYPE_INSN;
73 }
7974
80 @Override
81 public void accept(final MethodVisitor mv) {
82 mv.visitTypeInsn(opcode, desc);
83 acceptAnnotations(mv);
84 }
75 @Override
76 public void accept(final MethodVisitor methodVisitor) {
77 methodVisitor.visitTypeInsn(opcode, desc);
78 acceptAnnotations(methodVisitor);
79 }
8580
86 @Override
87 public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
88 return new TypeInsnNode(opcode, desc).cloneAnnotations(this);
89 }
90 }
81 @Override
82 public AbstractInsnNode clone(final Map<LabelNode, LabelNode> clonedLabels) {
83 return new TypeInsnNode(opcode, desc).cloneAnnotations(this);
84 }
85 }
0 package org.eclipse.persistence.internal.libraries.asm.tree;
1
2 /**
3 * Exception thrown in {@link AnnotationNode#check}, {@link ClassNode#check}, {@link
4 * FieldNode#check} and {@link MethodNode#check} when these nodes (or their children, recursively)
5 * contain elements that were introduced in more recent versions of the ASM API than version passed
6 * to these methods.
7 *
8 * @author Eric Bruneton
9 */
10 public class UnsupportedClassVersionException extends RuntimeException {
11
12 private static final long serialVersionUID = -3502347765891805831L;
13 }
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
27 package org.eclipse.persistence.internal.libraries.asm.tree;
28
29 import java.util.ArrayList;
30 import java.util.List;
31
32 /**
33 * Utility methods to convert an array of primitive or object values to a mutable ArrayList, not
34 * baked by the array (unlike {@link java.util.Arrays#asList}).
35 *
36 * @author Eric Bruneton
37 */
38 final class Util {
39
40 private Util() {}
41
42 static <T> List<T> asArrayList(final int length) {
43 List<T> list = new ArrayList<T>(length);
44 for (int i = 0; i < length; ++i) {
45 list.add(null);
46 }
47 return list;
48 }
49
50 static <T> List<T> asArrayList(final T[] array) {
51 if (array == null) {
52 return new ArrayList<T>();
53 }
54 ArrayList<T> list = new ArrayList<T>(array.length);
55 for (T t : array) {
56 list.add(t);
57 }
58 return list;
59 }
60
61 static List<Byte> asArrayList(final byte[] byteArray) {
62 if (byteArray == null) {
63 return new ArrayList<Byte>();
64 }
65 ArrayList<Byte> byteList = new ArrayList<Byte>(byteArray.length);
66 for (byte b : byteArray) {
67 byteList.add(b);
68 }
69 return byteList;
70 }
71
72 static List<Boolean> asArrayList(final boolean[] booleanArray) {
73 if (booleanArray == null) {
74 return new ArrayList<Boolean>();
75 }
76 ArrayList<Boolean> booleanList = new ArrayList<Boolean>(booleanArray.length);
77 for (boolean b : booleanArray) {
78 booleanList.add(b);
79 }
80 return booleanList;
81 }
82
83 static List<Short> asArrayList(final short[] shortArray) {
84 if (shortArray == null) {
85 return new ArrayList<Short>();
86 }
87 ArrayList<Short> shortList = new ArrayList<Short>(shortArray.length);
88 for (short s : shortArray) {
89 shortList.add(s);
90 }
91 return shortList;
92 }
93
94 static List<Character> asArrayList(final char[] charArray) {
95 if (charArray == null) {
96 return new ArrayList<Character>();
97 }
98 ArrayList<Character> charList = new ArrayList<Character>(charArray.length);
99 for (char c : charArray) {
100 charList.add(c);
101 }
102 return charList;
103 }
104
105 static List<Integer> asArrayList(final int[] intArray) {
106 if (intArray == null) {
107 return new ArrayList<Integer>();
108 }
109 ArrayList<Integer> intList = new ArrayList<Integer>(intArray.length);
110 for (int i : intArray) {
111 intList.add(i);
112 }
113 return intList;
114 }
115
116 static List<Float> asArrayList(final float[] floatArray) {
117 if (floatArray == null) {
118 return new ArrayList<Float>();
119 }
120 ArrayList<Float> floatList = new ArrayList<Float>(floatArray.length);
121 for (float f : floatArray) {
122 floatList.add(f);
123 }
124 return floatList;
125 }
126
127 static List<Long> asArrayList(final long[] longArray) {
128 if (longArray == null) {
129 return new ArrayList<Long>();
130 }
131 ArrayList<Long> longList = new ArrayList<Long>(longArray.length);
132 for (long l : longArray) {
133 longList.add(l);
134 }
135 return longList;
136 }
137
138 static List<Double> asArrayList(final double[] doubleArray) {
139 if (doubleArray == null) {
140 return new ArrayList<Double>();
141 }
142 ArrayList<Double> doubleList = new ArrayList<Double>(doubleArray.length);
143 for (double d : doubleArray) {
144 doubleList.add(d);
145 }
146 return doubleList;
147 }
148
149 static <T> List<T> asArrayList(final int length, final T[] array) {
150 List<T> list = new ArrayList<T>(length);
151 for (int i = 0; i < length; ++i) {
152 list.add(array[i]);
153 }
154 return list;
155 }
156 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.tree;
3028
3129 import java.util.Map;
3331 import org.eclipse.persistence.internal.libraries.asm.MethodVisitor;
3432
3533 /**
36 * A node that represents a local variable instruction. A local variable
37 * instruction is an instruction that loads or stores the value of a local
38 * variable.
39 *
34 * A node that represents a local variable instruction. A local variable instruction is an
35 * instruction that loads or stores the value of a local variable.
36 *
4037 * @author Eric Bruneton
4138 */
4239 public class VarInsnNode extends AbstractInsnNode {
4340
44 /**
45 * The operand of this instruction. This operand is the index of a local
46 * variable.
47 */
48 public int var;
41 /** The operand of this instruction. This operand is the index of a local variable. */
42 public int var;
4943
50 /**
51 * Constructs a new {@link VarInsnNode}.
52 *
53 * @param opcode
54 * the opcode of the local variable instruction to be
55 * constructed. This opcode must be ILOAD, LLOAD, FLOAD, DLOAD,
56 * ALOAD, ISTORE, LSTORE, FSTORE, DSTORE, ASTORE or RET.
57 * @param var
58 * the operand of the instruction to be constructed. This operand
59 * is the index of a local variable.
60 */
61 public VarInsnNode(final int opcode, final int var) {
62 super(opcode);
63 this.var = var;
64 }
44 /**
45 * Constructs a new {@link VarInsnNode}.
46 *
47 * @param opcode the opcode of the local variable instruction to be constructed. This opcode must
48 * be ILOAD, LLOAD, FLOAD, DLOAD, ALOAD, ISTORE, LSTORE, FSTORE, DSTORE, ASTORE or RET.
49 * @param var the operand of the instruction to be constructed. This operand is the index of a
50 * local variable.
51 */
52 public VarInsnNode(final int opcode, final int var) {
53 super(opcode);
54 this.var = var;
55 }
6556
66 /**
67 * Sets the opcode of this instruction.
68 *
69 * @param opcode
70 * the new instruction opcode. This opcode must be ILOAD, LLOAD,
71 * FLOAD, DLOAD, ALOAD, ISTORE, LSTORE, FSTORE, DSTORE, ASTORE or
72 * RET.
73 */
74 public void setOpcode(final int opcode) {
75 this.opcode = opcode;
76 }
57 /**
58 * Sets the opcode of this instruction.
59 *
60 * @param opcode the new instruction opcode. This opcode must be ILOAD, LLOAD, FLOAD, DLOAD,
61 * ALOAD, ISTORE, LSTORE, FSTORE, DSTORE, ASTORE or RET.
62 */
63 public void setOpcode(final int opcode) {
64 this.opcode = opcode;
65 }
7766
78 @Override
79 public int getType() {
80 return VAR_INSN;
81 }
67 @Override
68 public int getType() {
69 return VAR_INSN;
70 }
8271
83 @Override
84 public void accept(final MethodVisitor mv) {
85 mv.visitVarInsn(opcode, var);
86 acceptAnnotations(mv);
87 }
72 @Override
73 public void accept(final MethodVisitor methodVisitor) {
74 methodVisitor.visitVarInsn(opcode, var);
75 acceptAnnotations(methodVisitor);
76 }
8877
89 @Override
90 public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
91 return new VarInsnNode(opcode, var).cloneAnnotations(this);
92 }
93 }
78 @Override
79 public AbstractInsnNode clone(final Map<LabelNode, LabelNode> clonedLabels) {
80 return new VarInsnNode(opcode, var).cloneAnnotations(this);
81 }
82 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.tree.analysis;
3028
3129 import java.util.ArrayList;
4745 import org.eclipse.persistence.internal.libraries.asm.tree.VarInsnNode;
4846
4947 /**
50 * A semantic bytecode analyzer. <i>This class does not fully check that JSR and
51 * RET instructions are valid.</i>
52 *
53 * @param <V>
54 * type of the Value used for the analysis.
55 *
48 * A semantic bytecode analyzer. <i>This class does not fully check that JSR and RET instructions
49 * are valid.</i>
50 *
51 * @param <V> type of the Value used for the analysis.
5652 * @author Eric Bruneton
5753 */
5854 public class Analyzer<V extends Value> implements Opcodes {
5955
60 private final Interpreter<V> interpreter;
61
62 private int n;
63
64 private InsnList insns;
65
66 private List<TryCatchBlockNode>[] handlers;
67
68 private Frame<V>[] frames;
69
70 private Subroutine[] subroutines;
71
72 private boolean[] queued;
73
74 private int[] queue;
75
76 private int top;
77
78 /**
79 * Constructs a new {@link Analyzer}.
80 *
81 * @param interpreter
82 * the interpreter to be used to symbolically interpret the
83 * bytecode instructions.
84 */
85 public Analyzer(final Interpreter<V> interpreter) {
86 this.interpreter = interpreter;
87 }
88
89 /**
90 * Analyzes the given method.
91 *
92 * @param owner
93 * the internal name of the class to which the method belongs.
94 * @param m
95 * the method to be analyzed.
96 * @return the symbolic state of the execution stack frame at each bytecode
97 * instruction of the method. The size of the returned array is
98 * equal to the number of instructions (and labels) of the method. A
99 * given frame is <tt>null</tt> if and only if the corresponding
100 * instruction cannot be reached (dead code).
101 * @throws AnalyzerException
102 * if a problem occurs during the analysis.
103 */
104 @SuppressWarnings("unchecked")
105 public Frame<V>[] analyze(final String owner, final MethodNode m)
106 throws AnalyzerException {
107 if ((m.access & (ACC_ABSTRACT | ACC_NATIVE)) != 0) {
108 frames = (Frame<V>[]) new Frame<?>[0];
109 return frames;
110 }
111 n = m.instructions.size();
112 insns = m.instructions;
113 handlers = (List<TryCatchBlockNode>[]) new List<?>[n];
114 frames = (Frame<V>[]) new Frame<?>[n];
115 subroutines = new Subroutine[n];
116 queued = new boolean[n];
117 queue = new int[n];
118 top = 0;
119
120 // computes exception handlers for each instruction
121 for (int i = 0; i < m.tryCatchBlocks.size(); ++i) {
122 TryCatchBlockNode tcb = m.tryCatchBlocks.get(i);
123 int begin = insns.indexOf(tcb.start);
124 int end = insns.indexOf(tcb.end);
125 for (int j = begin; j < end; ++j) {
126 List<TryCatchBlockNode> insnHandlers = handlers[j];
127 if (insnHandlers == null) {
128 insnHandlers = new ArrayList<TryCatchBlockNode>();
129 handlers[j] = insnHandlers;
56 /** The interpreter to use to symbolically interpret the bytecode instructions. */
57 private final Interpreter<V> interpreter;
58
59 /** The instructions of the currently analyzed method. */
60 private InsnList insnList;
61
62 /** The size of {@link #insnList}. */
63 private int insnListSize;
64
65 /** The exception handlers of the currently analyzed method (one list per instruction index). */
66 private List<TryCatchBlockNode>[] handlers;
67
68 /** The execution stack frames of the currently analyzed method (one per instruction index). */
69 private Frame<V>[] frames;
70
71 /** The subroutines of the currently analyzed method (one per instruction index). */
72 private Subroutine[] subroutines;
73
74 /** The instructions that remain to process (one boolean per instruction index). */
75 private boolean[] inInstructionsToProcess;
76
77 /** The indices of the instructions that remain to process in the currently analyzed method. */
78 private int[] instructionsToProcess;
79
80 /** The number of instructions that remain to process in the currently analyzed method. */
81 private int numInstructionsToProcess;
82
83 /**
84 * Constructs a new {@link Analyzer}.
85 *
86 * @param interpreter the interpreter to use to symbolically interpret the bytecode instructions.
87 */
88 public Analyzer(final Interpreter<V> interpreter) {
89 this.interpreter = interpreter;
90 }
91
92 /**
93 * Analyzes the given method.
94 *
95 * @param owner the internal name of the class to which 'method' belongs.
96 * @param method the method to be analyzed.
97 * @return the symbolic state of the execution stack frame at each bytecode instruction of the
98 * method. The size of the returned array is equal to the number of instructions (and labels)
99 * of the method. A given frame is <tt>null</tt> if and only if the corresponding instruction
100 * cannot be reached (dead code).
101 * @throws AnalyzerException if a problem occurs during the analysis.
102 */
103 @SuppressWarnings("unchecked")
104 public Frame<V>[] analyze(final String owner, final MethodNode method) throws AnalyzerException {
105 if ((method.access & (ACC_ABSTRACT | ACC_NATIVE)) != 0) {
106 frames = (Frame<V>[]) new Frame<?>[0];
107 return frames;
108 }
109 insnList = method.instructions;
110 insnListSize = insnList.size();
111 handlers = (List<TryCatchBlockNode>[]) new List<?>[insnListSize];
112 frames = (Frame<V>[]) new Frame<?>[insnListSize];
113 subroutines = new Subroutine[insnListSize];
114 inInstructionsToProcess = new boolean[insnListSize];
115 instructionsToProcess = new int[insnListSize];
116 numInstructionsToProcess = 0;
117
118 // For each exception handler, and each instruction within its range, record in 'handlers' the
119 // fact that execution can flow from this instruction to the exception handler.
120 for (int i = 0; i < method.tryCatchBlocks.size(); ++i) {
121 TryCatchBlockNode tryCatchBlock = method.tryCatchBlocks.get(i);
122 int startIndex = insnList.indexOf(tryCatchBlock.start);
123 int endIndex = insnList.indexOf(tryCatchBlock.end);
124 for (int j = startIndex; j < endIndex; ++j) {
125 List<TryCatchBlockNode> insnHandlers = handlers[j];
126 if (insnHandlers == null) {
127 insnHandlers = new ArrayList<TryCatchBlockNode>();
128 handlers[j] = insnHandlers;
129 }
130 insnHandlers.add(tryCatchBlock);
131 }
132 }
133
134 // For each instruction, compute the subroutine to which it belongs.
135 // Follow the main 'subroutine', and collect the jsr instructions to nested subroutines.
136 Subroutine main = new Subroutine(null, method.maxLocals, null);
137 List<AbstractInsnNode> jsrInsns = new ArrayList<AbstractInsnNode>();
138 findSubroutine(0, main, jsrInsns);
139 // Follow the nested subroutines, and collect their own nested subroutines, until all
140 // subroutines are found.
141 Map<LabelNode, Subroutine> jsrSubroutines = new HashMap<LabelNode, Subroutine>();
142 while (!jsrInsns.isEmpty()) {
143 JumpInsnNode jsrInsn = (JumpInsnNode) jsrInsns.remove(0);
144 Subroutine subroutine = jsrSubroutines.get(jsrInsn.label);
145 if (subroutine == null) {
146 subroutine = new Subroutine(jsrInsn.label, method.maxLocals, jsrInsn);
147 jsrSubroutines.put(jsrInsn.label, subroutine);
148 findSubroutine(insnList.indexOf(jsrInsn.label), subroutine, jsrInsns);
149 } else {
150 subroutine.callers.add(jsrInsn);
151 }
152 }
153 // Clear the main 'subroutine', which is not a real subroutine (and was used only as an
154 // intermediate step above to find the real ones).
155 for (int i = 0; i < insnListSize; ++i) {
156 if (subroutines[i] != null && subroutines[i].start == null) {
157 subroutines[i] = null;
158 }
159 }
160
161 // Initializes the data structures for the control flow analysis.
162 Frame<V> currentFrame = computeInitialFrame(owner, method);
163 merge(0, currentFrame, null);
164 init(owner, method);
165
166 // Control flow analysis.
167 while (numInstructionsToProcess > 0) {
168 // Get and remove one instruction from the list of instructions to process.
169 int insnIndex = instructionsToProcess[--numInstructionsToProcess];
170 Frame<V> oldFrame = frames[insnIndex];
171 Subroutine subroutine = subroutines[insnIndex];
172 inInstructionsToProcess[insnIndex] = false;
173
174 // Simulate the execution of this instruction.
175 AbstractInsnNode insnNode = null;
176 try {
177 insnNode = method.instructions.get(insnIndex);
178 int insnOpcode = insnNode.getOpcode();
179 int insnType = insnNode.getType();
180
181 if (insnType == AbstractInsnNode.LABEL
182 || insnType == AbstractInsnNode.LINE
183 || insnType == AbstractInsnNode.FRAME) {
184 merge(insnIndex + 1, oldFrame, subroutine);
185 newControlFlowEdge(insnIndex, insnIndex + 1);
186 } else {
187 currentFrame.init(oldFrame).execute(insnNode, interpreter);
188 subroutine = subroutine == null ? null : new Subroutine(subroutine);
189
190 if (insnNode instanceof JumpInsnNode) {
191 JumpInsnNode jumpInsn = (JumpInsnNode) insnNode;
192 if (insnOpcode != GOTO && insnOpcode != JSR) {
193 merge(insnIndex + 1, currentFrame, subroutine);
194 newControlFlowEdge(insnIndex, insnIndex + 1);
195 }
196 int jumpInsnIndex = insnList.indexOf(jumpInsn.label);
197 if (insnOpcode == JSR) {
198 merge(
199 jumpInsnIndex,
200 currentFrame,
201 new Subroutine(jumpInsn.label, method.maxLocals, jumpInsn));
202 } else {
203 merge(jumpInsnIndex, currentFrame, subroutine);
204 }
205 newControlFlowEdge(insnIndex, jumpInsnIndex);
206 } else if (insnNode instanceof LookupSwitchInsnNode) {
207 LookupSwitchInsnNode lookupSwitchInsn = (LookupSwitchInsnNode) insnNode;
208 int targetInsnIndex = insnList.indexOf(lookupSwitchInsn.dflt);
209 merge(targetInsnIndex, currentFrame, subroutine);
210 newControlFlowEdge(insnIndex, targetInsnIndex);
211 for (int i = 0; i < lookupSwitchInsn.labels.size(); ++i) {
212 targetInsnIndex = insnList.indexOf(lookupSwitchInsn.labels.get(i));
213 merge(targetInsnIndex, currentFrame, subroutine);
214 newControlFlowEdge(insnIndex, targetInsnIndex);
215 }
216 } else if (insnNode instanceof TableSwitchInsnNode) {
217 TableSwitchInsnNode tableSwitchInsn = (TableSwitchInsnNode) insnNode;
218 int targetInsnIndex = insnList.indexOf(tableSwitchInsn.dflt);
219 merge(targetInsnIndex, currentFrame, subroutine);
220 newControlFlowEdge(insnIndex, targetInsnIndex);
221 for (int i = 0; i < tableSwitchInsn.labels.size(); ++i) {
222 targetInsnIndex = insnList.indexOf(tableSwitchInsn.labels.get(i));
223 merge(targetInsnIndex, currentFrame, subroutine);
224 newControlFlowEdge(insnIndex, targetInsnIndex);
225 }
226 } else if (insnOpcode == RET) {
227 if (subroutine == null) {
228 throw new AnalyzerException(insnNode, "RET instruction outside of a sub routine");
229 }
230 for (int i = 0; i < subroutine.callers.size(); ++i) {
231 JumpInsnNode caller = subroutine.callers.get(i);
232 int jsrInsnIndex = insnList.indexOf(caller);
233 if (frames[jsrInsnIndex] != null) {
234 merge(
235 jsrInsnIndex + 1,
236 frames[jsrInsnIndex],
237 currentFrame,
238 subroutines[jsrInsnIndex],
239 subroutine.localsUsed);
240 newControlFlowEdge(insnIndex, jsrInsnIndex + 1);
241 }
242 }
243 } else if (insnOpcode != ATHROW && (insnOpcode < IRETURN || insnOpcode > RETURN)) {
244 if (subroutine != null) {
245 if (insnNode instanceof VarInsnNode) {
246 int var = ((VarInsnNode) insnNode).var;
247 subroutine.localsUsed[var] = true;
248 if (insnOpcode == LLOAD
249 || insnOpcode == DLOAD
250 || insnOpcode == LSTORE
251 || insnOpcode == DSTORE) {
252 subroutine.localsUsed[var + 1] = true;
130253 }
131 insnHandlers.add(tcb);
132 }
133 }
134
135 // computes the subroutine for each instruction:
136 Subroutine main = new Subroutine(null, m.maxLocals, null);
137 List<AbstractInsnNode> subroutineCalls = new ArrayList<AbstractInsnNode>();
138 Map<LabelNode, Subroutine> subroutineHeads = new HashMap<LabelNode, Subroutine>();
139 findSubroutine(0, main, subroutineCalls);
140 while (!subroutineCalls.isEmpty()) {
141 JumpInsnNode jsr = (JumpInsnNode) subroutineCalls.remove(0);
142 Subroutine sub = subroutineHeads.get(jsr.label);
143 if (sub == null) {
144 sub = new Subroutine(jsr.label, m.maxLocals, jsr);
145 subroutineHeads.put(jsr.label, sub);
146 findSubroutine(insns.indexOf(jsr.label), sub, subroutineCalls);
254 } else if (insnNode instanceof IincInsnNode) {
255 int var = ((IincInsnNode) insnNode).var;
256 subroutine.localsUsed[var] = true;
257 }
258 }
259 merge(insnIndex + 1, currentFrame, subroutine);
260 newControlFlowEdge(insnIndex, insnIndex + 1);
261 }
262 }
263
264 List<TryCatchBlockNode> insnHandlers = handlers[insnIndex];
265 if (insnHandlers != null) {
266 for (int i = 0; i < insnHandlers.size(); ++i) {
267 TryCatchBlockNode tryCatchBlock = insnHandlers.get(i);
268 Type catchType;
269 if (tryCatchBlock.type == null) {
270 catchType = Type.getObjectType("java/lang/Throwable");
147271 } else {
148 sub.callers.add(jsr);
149 }
150 }
151 for (int i = 0; i < n; ++i) {
152 if (subroutines[i] != null && subroutines[i].start == null) {
153 subroutines[i] = null;
154 }
155 }
156
157 // initializes the data structures for the control flow analysis
158 Frame<V> current = newFrame(m.maxLocals, m.maxStack);
159 Frame<V> handler = newFrame(m.maxLocals, m.maxStack);
160 current.setReturn(interpreter.newValue(Type.getReturnType(m.desc)));
161 Type[] args = Type.getArgumentTypes(m.desc);
162 int local = 0;
163 if ((m.access & ACC_STATIC) == 0) {
164 Type ctype = Type.getObjectType(owner);
165 current.setLocal(local++, interpreter.newValue(ctype));
166 }
167 for (int i = 0; i < args.length; ++i) {
168 current.setLocal(local++, interpreter.newValue(args[i]));
169 if (args[i].getSize() == 2) {
170 current.setLocal(local++, interpreter.newValue(null));
171 }
172 }
173 while (local < m.maxLocals) {
174 current.setLocal(local++, interpreter.newValue(null));
175 }
176 merge(0, current, null);
177
178 init(owner, m);
179
180 // control flow analysis
181 while (top > 0) {
182 int insn = queue[--top];
183 Frame<V> f = frames[insn];
184 Subroutine subroutine = subroutines[insn];
185 queued[insn] = false;
186
187 AbstractInsnNode insnNode = null;
188 try {
189 insnNode = m.instructions.get(insn);
190 int insnOpcode = insnNode.getOpcode();
191 int insnType = insnNode.getType();
192
193 if (insnType == AbstractInsnNode.LABEL
194 || insnType == AbstractInsnNode.LINE
195 || insnType == AbstractInsnNode.FRAME) {
196 merge(insn + 1, f, subroutine);
197 newControlFlowEdge(insn, insn + 1);
198 } else {
199 current.init(f).execute(insnNode, interpreter);
200 subroutine = subroutine == null ? null : subroutine.copy();
201
202 if (insnNode instanceof JumpInsnNode) {
203 JumpInsnNode j = (JumpInsnNode) insnNode;
204 if (insnOpcode != GOTO && insnOpcode != JSR) {
205 merge(insn + 1, current, subroutine);
206 newControlFlowEdge(insn, insn + 1);
207 }
208 int jump = insns.indexOf(j.label);
209 if (insnOpcode == JSR) {
210 merge(jump, current, new Subroutine(j.label,
211 m.maxLocals, j));
212 } else {
213 merge(jump, current, subroutine);
214 }
215 newControlFlowEdge(insn, jump);
216 } else if (insnNode instanceof LookupSwitchInsnNode) {
217 LookupSwitchInsnNode lsi = (LookupSwitchInsnNode) insnNode;
218 int jump = insns.indexOf(lsi.dflt);
219 merge(jump, current, subroutine);
220 newControlFlowEdge(insn, jump);
221 for (int j = 0; j < lsi.labels.size(); ++j) {
222 LabelNode label = lsi.labels.get(j);
223 jump = insns.indexOf(label);
224 merge(jump, current, subroutine);
225 newControlFlowEdge(insn, jump);
226 }
227 } else if (insnNode instanceof TableSwitchInsnNode) {
228 TableSwitchInsnNode tsi = (TableSwitchInsnNode) insnNode;
229 int jump = insns.indexOf(tsi.dflt);
230 merge(jump, current, subroutine);
231 newControlFlowEdge(insn, jump);
232 for (int j = 0; j < tsi.labels.size(); ++j) {
233 LabelNode label = tsi.labels.get(j);
234 jump = insns.indexOf(label);
235 merge(jump, current, subroutine);
236 newControlFlowEdge(insn, jump);
237 }
238 } else if (insnOpcode == RET) {
239 if (subroutine == null) {
240 throw new AnalyzerException(insnNode,
241 "RET instruction outside of a sub routine");
242 }
243 for (int i = 0; i < subroutine.callers.size(); ++i) {
244 JumpInsnNode caller = subroutine.callers.get(i);
245 int call = insns.indexOf(caller);
246 if (frames[call] != null) {
247 merge(call + 1, frames[call], current,
248 subroutines[call], subroutine.access);
249 newControlFlowEdge(insn, call + 1);
250 }
251 }
252 } else if (insnOpcode != ATHROW
253 && (insnOpcode < IRETURN || insnOpcode > RETURN)) {
254 if (subroutine != null) {
255 if (insnNode instanceof VarInsnNode) {
256 int var = ((VarInsnNode) insnNode).var;
257 subroutine.access[var] = true;
258 if (insnOpcode == LLOAD || insnOpcode == DLOAD
259 || insnOpcode == LSTORE
260 || insnOpcode == DSTORE) {
261 subroutine.access[var + 1] = true;
262 }
263 } else if (insnNode instanceof IincInsnNode) {
264 int var = ((IincInsnNode) insnNode).var;
265 subroutine.access[var] = true;
266 }
267 }
268 merge(insn + 1, current, subroutine);
269 newControlFlowEdge(insn, insn + 1);
270 }
271 }
272
273 List<TryCatchBlockNode> insnHandlers = handlers[insn];
274 if (insnHandlers != null) {
275 for (int i = 0; i < insnHandlers.size(); ++i) {
276 TryCatchBlockNode tcb = insnHandlers.get(i);
277 Type type;
278 if (tcb.type == null) {
279 type = Type.getObjectType("java/lang/Throwable");
280 } else {
281 type = Type.getObjectType(tcb.type);
282 }
283 int jump = insns.indexOf(tcb.handler);
284 if (newControlFlowExceptionEdge(insn, tcb)) {
285 handler.init(f);
286 handler.clearStack();
287 handler.push(interpreter.newValue(type));
288 merge(jump, handler, subroutine);
289 }
290 }
291 }
292 } catch (AnalyzerException e) {
293 throw new AnalyzerException(e.node, "Error at instruction "
294 + insn + ": " + e.getMessage(), e);
295 } catch (Exception e) {
296 throw new AnalyzerException(insnNode, "Error at instruction "
297 + insn + ": " + e.getMessage(), e);
298 }
299 }
300
301 return frames;
302 }
303
304 private void findSubroutine(int insn, final Subroutine sub,
305 final List<AbstractInsnNode> calls) throws AnalyzerException {
306 while (true) {
307 if (insn < 0 || insn >= n) {
308 throw new AnalyzerException(null,
309 "Execution can fall off end of the code");
310 }
311 if (subroutines[insn] != null) {
312 return;
313 }
314 subroutines[insn] = sub.copy();
315 AbstractInsnNode node = insns.get(insn);
316
317 // calls findSubroutine recursively on normal successors
318 if (node instanceof JumpInsnNode) {
319 if (node.getOpcode() == JSR) {
320 // do not follow a JSR, it leads to another subroutine!
321 calls.add(node);
322 } else {
323 JumpInsnNode jnode = (JumpInsnNode) node;
324 findSubroutine(insns.indexOf(jnode.label), sub, calls);
325 }
326 } else if (node instanceof TableSwitchInsnNode) {
327 TableSwitchInsnNode tsnode = (TableSwitchInsnNode) node;
328 findSubroutine(insns.indexOf(tsnode.dflt), sub, calls);
329 for (int i = tsnode.labels.size() - 1; i >= 0; --i) {
330 LabelNode l = tsnode.labels.get(i);
331 findSubroutine(insns.indexOf(l), sub, calls);
332 }
333 } else if (node instanceof LookupSwitchInsnNode) {
334 LookupSwitchInsnNode lsnode = (LookupSwitchInsnNode) node;
335 findSubroutine(insns.indexOf(lsnode.dflt), sub, calls);
336 for (int i = lsnode.labels.size() - 1; i >= 0; --i) {
337 LabelNode l = lsnode.labels.get(i);
338 findSubroutine(insns.indexOf(l), sub, calls);
339 }
340 }
341
342 // calls findSubroutine recursively on exception handler successors
343 List<TryCatchBlockNode> insnHandlers = handlers[insn];
344 if (insnHandlers != null) {
345 for (int i = 0; i < insnHandlers.size(); ++i) {
346 TryCatchBlockNode tcb = insnHandlers.get(i);
347 findSubroutine(insns.indexOf(tcb.handler), sub, calls);
348 }
349 }
350
351 // if insn does not falls through to the next instruction, return.
352 switch (node.getOpcode()) {
353 case GOTO:
354 case RET:
355 case TABLESWITCH:
356 case LOOKUPSWITCH:
357 case IRETURN:
358 case LRETURN:
359 case FRETURN:
360 case DRETURN:
361 case ARETURN:
362 case RETURN:
363 case ATHROW:
364 return;
365 }
366 insn++;
367 }
368 }
369
370 /**
371 * Returns the symbolic stack frame for each instruction of the last
372 * recently analyzed method.
373 *
374 * @return the symbolic state of the execution stack frame at each bytecode
375 * instruction of the method. The size of the returned array is
376 * equal to the number of instructions (and labels) of the method. A
377 * given frame is <tt>null</tt> if the corresponding instruction
378 * cannot be reached, or if an error occured during the analysis of
379 * the method.
380 */
381 public Frame<V>[] getFrames() {
382 return frames;
383 }
384
385 /**
386 * Returns the exception handlers for the given instruction.
387 *
388 * @param insn
389 * the index of an instruction of the last recently analyzed
390 * method.
391 * @return a list of {@link TryCatchBlockNode} objects.
392 */
393 public List<TryCatchBlockNode> getHandlers(final int insn) {
394 return handlers[insn];
395 }
396
397 /**
398 * Initializes this analyzer. This method is called just before the
399 * execution of control flow analysis loop in #analyze. The default
400 * implementation of this method does nothing.
401 *
402 * @param owner
403 * the internal name of the class to which the method belongs.
404 * @param m
405 * the method to be analyzed.
406 * @throws AnalyzerException
407 * if a problem occurs.
408 */
409 protected void init(String owner, MethodNode m) throws AnalyzerException {
410 }
411
412 /**
413 * Constructs a new frame with the given size.
414 *
415 * @param nLocals
416 * the maximum number of local variables of the frame.
417 * @param nStack
418 * the maximum stack size of the frame.
419 * @return the created frame.
420 */
421 protected Frame<V> newFrame(final int nLocals, final int nStack) {
422 return new Frame<V>(nLocals, nStack);
423 }
424
425 /**
426 * Constructs a new frame that is identical to the given frame.
427 *
428 * @param src
429 * a frame.
430 * @return the created frame.
431 */
432 protected Frame<V> newFrame(final Frame<? extends V> src) {
433 return new Frame<V>(src);
434 }
435
436 /**
437 * Creates a control flow graph edge. The default implementation of this
438 * method does nothing. It can be overriden in order to construct the
439 * control flow graph of a method (this method is called by the
440 * {@link #analyze analyze} method during its visit of the method's code).
441 *
442 * @param insn
443 * an instruction index.
444 * @param successor
445 * index of a successor instruction.
446 */
447 protected void newControlFlowEdge(final int insn, final int successor) {
448 }
449
450 /**
451 * Creates a control flow graph edge corresponding to an exception handler.
452 * The default implementation of this method does nothing. It can be
453 * overridden in order to construct the control flow graph of a method (this
454 * method is called by the {@link #analyze analyze} method during its visit
455 * of the method's code).
456 *
457 * @param insn
458 * an instruction index.
459 * @param successor
460 * index of a successor instruction.
461 * @return true if this edge must be considered in the data flow analysis
462 * performed by this analyzer, or false otherwise. The default
463 * implementation of this method always returns true.
464 */
465 protected boolean newControlFlowExceptionEdge(final int insn,
466 final int successor) {
467 return true;
468 }
469
470 /**
471 * Creates a control flow graph edge corresponding to an exception handler.
472 * The default implementation of this method delegates to
473 * {@link #newControlFlowExceptionEdge(int, int)
474 * newControlFlowExceptionEdge(int, int)}. It can be overridden in order to
475 * construct the control flow graph of a method (this method is called by
476 * the {@link #analyze analyze} method during its visit of the method's
477 * code).
478 *
479 * @param insn
480 * an instruction index.
481 * @param tcb
482 * TryCatchBlockNode corresponding to this edge.
483 * @return true if this edge must be considered in the data flow analysis
484 * performed by this analyzer, or false otherwise. The default
485 * implementation of this method delegates to
486 * {@link #newControlFlowExceptionEdge(int, int)
487 * newControlFlowExceptionEdge(int, int)}.
488 */
489 protected boolean newControlFlowExceptionEdge(final int insn,
490 final TryCatchBlockNode tcb) {
491 return newControlFlowExceptionEdge(insn, insns.indexOf(tcb.handler));
492 }
493
494 // -------------------------------------------------------------------------
495
496 private void merge(final int insn, final Frame<V> frame,
497 final Subroutine subroutine) throws AnalyzerException {
498 Frame<V> oldFrame = frames[insn];
499 Subroutine oldSubroutine = subroutines[insn];
500 boolean changes;
501
502 if (oldFrame == null) {
503 frames[insn] = newFrame(frame);
504 changes = true;
272 catchType = Type.getObjectType(tryCatchBlock.type);
273 }
274 if (newControlFlowExceptionEdge(insnIndex, tryCatchBlock)) {
275 Frame<V> handler = new Frame<V>(oldFrame);
276 handler.clearStack();
277 handler.push(interpreter.newValue(catchType));
278 merge(insnList.indexOf(tryCatchBlock.handler), handler, subroutine);
279 }
280 }
281 }
282 } catch (AnalyzerException e) {
283 throw new AnalyzerException(
284 e.node, "Error at instruction " + insnIndex + ": " + e.getMessage(), e);
285 } catch (Exception e) {
286 throw new AnalyzerException(
287 insnNode, "Error at instruction " + insnIndex + ": " + e.getMessage(), e);
288 }
289 }
290
291 return frames;
292 }
293
294 /**
295 * Follows the control flow graph of the currently analyzed method, starting at the given
296 * instruction index, and stores a copy of the given subroutine in {@link #subroutines} for each
297 * encountered instruction. Jumps to nested subroutines are <i>not</i> followed: instead, the
298 * corresponding instructions are put in the given list.
299 *
300 * @param insnIndex an instruction index.
301 * @param subroutine a subroutine.
302 * @param jsrInsns where the jsr instructions for nested subroutines must be put.
303 * @throws AnalyzerException if the control flow graph can fall off the end of the code.
304 */
305 private void findSubroutine(
306 final int insnIndex, final Subroutine subroutine, final List<AbstractInsnNode> jsrInsns)
307 throws AnalyzerException {
308 int currentInsnIndex = insnIndex;
309 while (true) {
310 if (currentInsnIndex < 0 || currentInsnIndex >= insnListSize) {
311 throw new AnalyzerException(null, "Execution can fall off the end of the code");
312 }
313 if (subroutines[currentInsnIndex] != null) {
314 return;
315 }
316 subroutines[currentInsnIndex] = new Subroutine(subroutine);
317 AbstractInsnNode currentInsn = insnList.get(currentInsnIndex);
318
319 // Call findSubroutine recursively on the normal successors of currentInsn.
320 if (currentInsn instanceof JumpInsnNode) {
321 if (currentInsn.getOpcode() == JSR) {
322 // Do not follow a jsr, it leads to another subroutine!
323 jsrInsns.add(currentInsn);
505324 } else {
506 changes = oldFrame.merge(frame, interpreter);
507 }
508
509 if (oldSubroutine == null) {
510 if (subroutine != null) {
511 subroutines[insn] = subroutine.copy();
512 changes = true;
513 }
514 } else {
515 if (subroutine != null) {
516 changes |= oldSubroutine.merge(subroutine);
517 }
518 }
519 if (changes && !queued[insn]) {
520 queued[insn] = true;
521 queue[top++] = insn;
522 }
523 }
524
525 private void merge(final int insn, final Frame<V> beforeJSR,
526 final Frame<V> afterRET, final Subroutine subroutineBeforeJSR,
527 final boolean[] access) throws AnalyzerException {
528 Frame<V> oldFrame = frames[insn];
529 Subroutine oldSubroutine = subroutines[insn];
530 boolean changes;
531
532 afterRET.merge(beforeJSR, access);
533
534 if (oldFrame == null) {
535 frames[insn] = newFrame(afterRET);
536 changes = true;
537 } else {
538 changes = oldFrame.merge(afterRET, interpreter);
539 }
540
541 if (oldSubroutine != null && subroutineBeforeJSR != null) {
542 changes |= oldSubroutine.merge(subroutineBeforeJSR);
543 }
544 if (changes && !queued[insn]) {
545 queued[insn] = true;
546 queue[top++] = insn;
547 }
548 }
325 JumpInsnNode jumpInsn = (JumpInsnNode) currentInsn;
326 findSubroutine(insnList.indexOf(jumpInsn.label), subroutine, jsrInsns);
327 }
328 } else if (currentInsn instanceof TableSwitchInsnNode) {
329 TableSwitchInsnNode tableSwitchInsn = (TableSwitchInsnNode) currentInsn;
330 findSubroutine(insnList.indexOf(tableSwitchInsn.dflt), subroutine, jsrInsns);
331 for (int i = tableSwitchInsn.labels.size() - 1; i >= 0; --i) {
332 LabelNode l = tableSwitchInsn.labels.get(i);
333 findSubroutine(insnList.indexOf(l), subroutine, jsrInsns);
334 }
335 } else if (currentInsn instanceof LookupSwitchInsnNode) {
336 LookupSwitchInsnNode lookupSwitchInsn = (LookupSwitchInsnNode) currentInsn;
337 findSubroutine(insnList.indexOf(lookupSwitchInsn.dflt), subroutine, jsrInsns);
338 for (int i = lookupSwitchInsn.labels.size() - 1; i >= 0; --i) {
339 LabelNode l = lookupSwitchInsn.labels.get(i);
340 findSubroutine(insnList.indexOf(l), subroutine, jsrInsns);
341 }
342 }
343
344 // Call findSubroutine recursively on the exception handler successors of currentInsn.
345 List<TryCatchBlockNode> insnHandlers = handlers[currentInsnIndex];
346 if (insnHandlers != null) {
347 for (int i = 0; i < insnHandlers.size(); ++i) {
348 TryCatchBlockNode tryCatchBlock = insnHandlers.get(i);
349 findSubroutine(insnList.indexOf(tryCatchBlock.handler), subroutine, jsrInsns);
350 }
351 }
352
353 // If currentInsn does not fall through to the next instruction, return.
354 switch (currentInsn.getOpcode()) {
355 case GOTO:
356 case RET:
357 case TABLESWITCH:
358 case LOOKUPSWITCH:
359 case IRETURN:
360 case LRETURN:
361 case FRETURN:
362 case DRETURN:
363 case ARETURN:
364 case RETURN:
365 case ATHROW:
366 return;
367 default:
368 break;
369 }
370 currentInsnIndex++;
371 }
372 }
373
374 /**
375 * Computes the initial execution stack frame of the given method.
376 *
377 * @param owner the internal name of the class to which 'method' belongs.
378 * @param method the method to be analyzed.
379 * @return the initial execution stack frame of the 'method'.
380 */
381 private Frame<V> computeInitialFrame(final String owner, final MethodNode method) {
382 Frame<V> frame = newFrame(method.maxLocals, method.maxStack);
383 int currentLocal = 0;
384 if ((method.access & ACC_STATIC) == 0) {
385 Type ownerType = Type.getObjectType(owner);
386 frame.setLocal(currentLocal++, interpreter.newValue(ownerType));
387 }
388 Type[] argumentTypes = Type.getArgumentTypes(method.desc);
389 for (int i = 0; i < argumentTypes.length; ++i) {
390 frame.setLocal(currentLocal++, interpreter.newValue(argumentTypes[i]));
391 if (argumentTypes[i].getSize() == 2) {
392 frame.setLocal(currentLocal++, interpreter.newValue(null));
393 }
394 }
395 while (currentLocal < method.maxLocals) {
396 frame.setLocal(currentLocal++, interpreter.newValue(null));
397 }
398 frame.setReturn(interpreter.newValue(Type.getReturnType(method.desc)));
399 return frame;
400 }
401
402 /**
403 * Returns the symbolic execution stack frame for each instruction of the last analyzed method.
404 *
405 * @return the symbolic state of the execution stack frame at each bytecode instruction of the
406 * method. The size of the returned array is equal to the number of instructions (and labels)
407 * of the method. A given frame is <tt>null</tt> if the corresponding instruction cannot be
408 * reached, or if an error occured during the analysis of the method.
409 */
410 public Frame<V>[] getFrames() {
411 return frames;
412 }
413
414 /**
415 * Returns the exception handlers for the given instruction.
416 *
417 * @param insnIndex the index of an instruction of the last analyzed method.
418 * @return a list of {@link TryCatchBlockNode} objects.
419 */
420 public List<TryCatchBlockNode> getHandlers(final int insnIndex) {
421 return handlers[insnIndex];
422 }
423
424 /**
425 * Initializes this analyzer. This method is called just before the execution of control flow
426 * analysis loop in #analyze. The default implementation of this method does nothing.
427 *
428 * @param owner the internal name of the class to which the method belongs.
429 * @param method the method to be analyzed.
430 * @throws AnalyzerException if a problem occurs.
431 */
432 protected void init(final String owner, final MethodNode method) throws AnalyzerException {
433 // Nothing to do.
434 }
435
436 /**
437 * Constructs a new frame with the given size.
438 *
439 * @param nLocals the maximum number of local variables of the frame.
440 * @param nStack the maximum stack size of the frame.
441 * @return the created frame.
442 */
443 protected Frame<V> newFrame(final int nLocals, final int nStack) {
444 return new Frame<V>(nLocals, nStack);
445 }
446
447 /**
448 * Constructs a copy of the given frame.
449 *
450 * @param frame a frame.
451 * @return the created frame.
452 */
453 protected Frame<V> newFrame(final Frame<? extends V> frame) {
454 return new Frame<V>(frame);
455 }
456
457 /**
458 * Creates a control flow graph edge. The default implementation of this method does nothing. It
459 * can be overriden in order to construct the control flow graph of a method (this method is
460 * called by the {@link #analyze} method during its visit of the method's code).
461 *
462 * @param insnIndex an instruction index.
463 * @param successorIndex index of a successor instruction.
464 */
465 protected void newControlFlowEdge(final int insnIndex, final int successorIndex) {
466 // Nothing to do.
467 }
468
469 /**
470 * Creates a control flow graph edge corresponding to an exception handler. The default
471 * implementation of this method does nothing. It can be overridden in order to construct the
472 * control flow graph of a method (this method is called by the {@link #analyze} method during its
473 * visit of the method's code).
474 *
475 * @param insnIndex an instruction index.
476 * @param successorIndex index of a successor instruction.
477 * @return true if this edge must be considered in the data flow analysis performed by this
478 * analyzer, or false otherwise. The default implementation of this method always returns
479 * true.
480 */
481 protected boolean newControlFlowExceptionEdge(final int insnIndex, final int successorIndex) {
482 return true;
483 }
484
485 /**
486 * Creates a control flow graph edge corresponding to an exception handler. The default
487 * implementation of this method delegates to {@link #newControlFlowExceptionEdge(int, int)}. It
488 * can be overridden in order to construct the control flow graph of a method (this method is
489 * called by the {@link #analyze} method during its visit of the method's code).
490 *
491 * @param insnIndex an instruction index.
492 * @param tryCatchBlock TryCatchBlockNode corresponding to this edge.
493 * @return true if this edge must be considered in the data flow analysis performed by this
494 * analyzer, or false otherwise. The default implementation of this method delegates to {@link
495 * #newControlFlowExceptionEdge(int, int)}.
496 */
497 protected boolean newControlFlowExceptionEdge(
498 final int insnIndex, final TryCatchBlockNode tryCatchBlock) {
499 return newControlFlowExceptionEdge(insnIndex, insnList.indexOf(tryCatchBlock.handler));
500 }
501
502 // -----------------------------------------------------------------------------------------------
503
504 /**
505 * Merges the given frame and subroutine into the frame and subroutines at the given instruction
506 * index. If the frame or the subroutine at the given instruction index changes as a result of
507 * this merge, the instruction index is added to the list of instructions to process (if it is not
508 * already the case).
509 *
510 * @param insnIndex an instruction index.
511 * @param frame a frame. This frame is left unchanged by this method.
512 * @param subroutine a subroutine. This subroutine is left unchanged by this method.
513 * @throws AnalyzerException if the frames have incompatible sizes.
514 */
515 private void merge(final int insnIndex, final Frame<V> frame, final Subroutine subroutine)
516 throws AnalyzerException {
517 boolean changed;
518 Frame<V> oldFrame = frames[insnIndex];
519 if (oldFrame == null) {
520 frames[insnIndex] = newFrame(frame);
521 changed = true;
522 } else {
523 changed = oldFrame.merge(frame, interpreter);
524 }
525 Subroutine oldSubroutine = subroutines[insnIndex];
526 if (oldSubroutine == null) {
527 if (subroutine != null) {
528 subroutines[insnIndex] = new Subroutine(subroutine);
529 changed = true;
530 }
531 } else {
532 if (subroutine != null) {
533 changed |= oldSubroutine.merge(subroutine);
534 }
535 }
536 if (changed && !inInstructionsToProcess[insnIndex]) {
537 inInstructionsToProcess[insnIndex] = true;
538 instructionsToProcess[numInstructionsToProcess++] = insnIndex;
539 }
540 }
541
542 /**
543 * Merges the given frame and subroutine into the frame and subroutines at the given instruction
544 * index (case of a RET instruction). If the frame or the subroutine at the given instruction
545 * index changes as a result of this merge, the instruction index is added to the list of
546 * instructions to process (if it is not already the case).
547 *
548 * @param insnIndex the index of an instruction immediately following a jsr instruction.
549 * @param frameBeforeJsr the execution stack frame before the jsr instruction. This frame is
550 * merged into 'frameAfterRet'.
551 * @param frameAfterRet the execution stack frame after a ret instruction of the subroutine. This
552 * frame is merged into the frame at 'insnIndex' (after it has itself been merge with
553 * 'frameBeforeJsr').
554 * @param subroutineBeforeJsr if the jsr is itself part of a subroutine (case of nested
555 * subroutine), the subroutine it belongs to.
556 * @param localsUsed the local variables read or written in the subroutine.
557 * @throws AnalyzerException if the frames have incompatible sizes.
558 */
559 private void merge(
560 final int insnIndex,
561 final Frame<V> frameBeforeJsr,
562 final Frame<V> frameAfterRet,
563 final Subroutine subroutineBeforeJsr,
564 final boolean[] localsUsed)
565 throws AnalyzerException {
566 frameAfterRet.merge(frameBeforeJsr, localsUsed);
567
568 boolean changed;
569 Frame<V> oldFrame = frames[insnIndex];
570 if (oldFrame == null) {
571 frames[insnIndex] = newFrame(frameAfterRet);
572 changed = true;
573 } else {
574 changed = oldFrame.merge(frameAfterRet, interpreter);
575 }
576 Subroutine oldSubroutine = subroutines[insnIndex];
577 if (oldSubroutine != null && subroutineBeforeJsr != null) {
578 changed |= oldSubroutine.merge(subroutineBeforeJsr);
579 }
580 if (changed && !inInstructionsToProcess[insnIndex]) {
581 inInstructionsToProcess[insnIndex] = true;
582 instructionsToProcess[numInstructionsToProcess++] = insnIndex;
583 }
584 }
549585 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.tree.analysis;
3028
3129 import org.eclipse.persistence.internal.libraries.asm.tree.AbstractInsnNode;
3230
3331 /**
34 * Thrown if a problem occurs during the analysis of a method.
35 *
32 * An exception thrown if a problem occurs during the analysis of a method.
33 *
3634 * @author Bing Ran
3735 * @author Eric Bruneton
3836 */
39 @SuppressWarnings("serial")
4037 public class AnalyzerException extends Exception {
4138
42 public final AbstractInsnNode node;
39 private static final long serialVersionUID = 3154190448018943333L;
40
41 /** The bytecode instruction where the analysis failed. */
42 public final transient AbstractInsnNode node;
4343
44 public AnalyzerException(final AbstractInsnNode node, final String msg) {
45 super(msg);
46 this.node = node;
47 }
44 /**
45 * Constructs a new {@link AnalyzerException}.
46 *
47 * @param insn the bytecode instruction where the analysis failed.
48 * @param message the reason why the analysis failed.
49 */
50 public AnalyzerException(final AbstractInsnNode insn, final String message) {
51 super(message);
52 this.node = insn;
53 }
4854
49 public AnalyzerException(final AbstractInsnNode node, final String msg,
50 final Throwable exception) {
51 super(msg, exception);
52 this.node = node;
53 }
55 /**
56 * Constructs a new {@link AnalyzerException}.
57 *
58 * @param insn the bytecode instruction where the analysis failed.
59 * @param message the reason why the analysis failed.
60 * @param cause the cause of the failure.
61 */
62 public AnalyzerException(
63 final AbstractInsnNode insn, final String message, final Throwable cause) {
64 super(message, cause);
65 this.node = insn;
66 }
5467
55 public AnalyzerException(final AbstractInsnNode node, final String msg,
56 final Object expected, final Value encountered) {
57 super((msg == null ? "Expected " : msg + ": expected ") + expected
58 + ", but found " + encountered);
59 this.node = node;
60 }
68 /**
69 * Constructs a new {@link AnalyzerException}.
70 *
71 * @param insn the bytecode instruction where the analysis failed.
72 * @param message the reason why the analysis failed.
73 * @param expected an expected value.
74 * @param actual the actual value, different from the expected one.
75 */
76 public AnalyzerException(
77 final AbstractInsnNode insn,
78 final String message,
79 final Object expected,
80 final Value actual) {
81 super(
82 (message == null ? "Expected " : message + ": expected ")
83 + expected
84 + ", but found "
85 + actual);
86 this.node = insn;
87 }
6188 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.tree.analysis;
3028
3129 import java.util.List;
4442
4543 /**
4644 * An {@link Interpreter} for {@link BasicValue} values.
47 *
45 *
4846 * @author Eric Bruneton
4947 * @author Bing Ran
5048 */
51 public class BasicInterpreter extends Interpreter<BasicValue> implements
52 Opcodes {
53
54 public BasicInterpreter() {
55 super(ASM6);
56 }
57
58 protected BasicInterpreter(final int api) {
59 super(api);
60 }
61
62 @Override
63 public BasicValue newValue(final Type type) {
64 if (type == null) {
65 return BasicValue.UNINITIALIZED_VALUE;
49 public class BasicInterpreter extends Interpreter<BasicValue> implements Opcodes {
50
51 /**
52 * Special type used for the <tt>null</tt> literal. This is an object reference type with
53 * descriptor 'Lnull;'.
54 */
55 public static final Type NULL_TYPE = Type.getObjectType("null");
56
57 /**
58 * Constructs a new {@link BasicInterpreter} for the latest ASM API version. <i>Subclasses must not
59 * use this constructor</i>. Instead, they must use the {@link #BasicInterpreter(int)} version.
60 */
61 public BasicInterpreter() {
62 super(ASM6);
63 if (getClass() != BasicInterpreter.class) {
64 throw new IllegalStateException();
65 }
66 }
67
68 /**
69 * Constructs a new {@link BasicInterpreter}.
70 *
71 * @param api the ASM API version supported by this interpreter. Must be one of {@link
72 * org.eclipse.persistence.internal.libraries.asm.Opcodes#ASM4}, {@link org.eclipse.persistence.internal.libraries.asm.Opcodes#ASM5} or {@link
73 * org.eclipse.persistence.internal.libraries.asm.Opcodes#ASM6}.
74 */
75 protected BasicInterpreter(final int api) {
76 super(api);
77 }
78
79 @Override
80 public BasicValue newValue(final Type type) {
81 if (type == null) {
82 return BasicValue.UNINITIALIZED_VALUE;
83 }
84 switch (type.getSort()) {
85 case Type.VOID:
86 return null;
87 case Type.BOOLEAN:
88 case Type.CHAR:
89 case Type.BYTE:
90 case Type.SHORT:
91 case Type.INT:
92 return BasicValue.INT_VALUE;
93 case Type.FLOAT:
94 return BasicValue.FLOAT_VALUE;
95 case Type.LONG:
96 return BasicValue.LONG_VALUE;
97 case Type.DOUBLE:
98 return BasicValue.DOUBLE_VALUE;
99 case Type.ARRAY:
100 case Type.OBJECT:
101 return BasicValue.REFERENCE_VALUE;
102 default:
103 throw new AssertionError();
104 }
105 }
106
107 @Override
108 public BasicValue newOperation(final AbstractInsnNode insn) throws AnalyzerException {
109 switch (insn.getOpcode()) {
110 case ACONST_NULL:
111 return newValue(NULL_TYPE);
112 case ICONST_M1:
113 case ICONST_0:
114 case ICONST_1:
115 case ICONST_2:
116 case ICONST_3:
117 case ICONST_4:
118 case ICONST_5:
119 return BasicValue.INT_VALUE;
120 case LCONST_0:
121 case LCONST_1:
122 return BasicValue.LONG_VALUE;
123 case FCONST_0:
124 case FCONST_1:
125 case FCONST_2:
126 return BasicValue.FLOAT_VALUE;
127 case DCONST_0:
128 case DCONST_1:
129 return BasicValue.DOUBLE_VALUE;
130 case BIPUSH:
131 case SIPUSH:
132 return BasicValue.INT_VALUE;
133 case LDC:
134 Object value = ((LdcInsnNode) insn).cst;
135 if (value instanceof Integer) {
136 return BasicValue.INT_VALUE;
137 } else if (value instanceof Float) {
138 return BasicValue.FLOAT_VALUE;
139 } else if (value instanceof Long) {
140 return BasicValue.LONG_VALUE;
141 } else if (value instanceof Double) {
142 return BasicValue.DOUBLE_VALUE;
143 } else if (value instanceof String) {
144 return newValue(Type.getObjectType("java/lang/String"));
145 } else if (value instanceof Type) {
146 int sort = ((Type) value).getSort();
147 if (sort == Type.OBJECT || sort == Type.ARRAY) {
148 return newValue(Type.getObjectType("java/lang/Class"));
149 } else if (sort == Type.METHOD) {
150 return newValue(Type.getObjectType("java/lang/invoke/MethodType"));
151 } else {
152 throw new AnalyzerException(insn, "Illegal LDC value " + value);
153 }
154 } else if (value instanceof Handle) {
155 return newValue(Type.getObjectType("java/lang/invoke/MethodHandle"));
156 } else {
157 throw new AnalyzerException(insn, "Illegal LDC value " + value);
66158 }
67 switch (type.getSort()) {
68 case Type.VOID:
69 return null;
70 case Type.BOOLEAN:
71 case Type.CHAR:
72 case Type.BYTE:
73 case Type.SHORT:
74 case Type.INT:
75 return BasicValue.INT_VALUE;
76 case Type.FLOAT:
77 return BasicValue.FLOAT_VALUE;
78 case Type.LONG:
79 return BasicValue.LONG_VALUE;
80 case Type.DOUBLE:
81 return BasicValue.DOUBLE_VALUE;
82 case Type.ARRAY:
83 case Type.OBJECT:
84 return BasicValue.REFERENCE_VALUE;
85 default:
86 throw new Error("Internal error");
159 case JSR:
160 return BasicValue.RETURNADDRESS_VALUE;
161 case GETSTATIC:
162 return newValue(Type.getType(((FieldInsnNode) insn).desc));
163 case NEW:
164 return newValue(Type.getObjectType(((TypeInsnNode) insn).desc));
165 default:
166 throw new AssertionError();
167 }
168 }
169
170 @Override
171 public BasicValue copyOperation(final AbstractInsnNode insn, final BasicValue value)
172 throws AnalyzerException {
173 return value;
174 }
175
176 @Override
177 public BasicValue unaryOperation(final AbstractInsnNode insn, final BasicValue value)
178 throws AnalyzerException {
179 switch (insn.getOpcode()) {
180 case INEG:
181 case IINC:
182 case L2I:
183 case F2I:
184 case D2I:
185 case I2B:
186 case I2C:
187 case I2S:
188 return BasicValue.INT_VALUE;
189 case FNEG:
190 case I2F:
191 case L2F:
192 case D2F:
193 return BasicValue.FLOAT_VALUE;
194 case LNEG:
195 case I2L:
196 case F2L:
197 case D2L:
198 return BasicValue.LONG_VALUE;
199 case DNEG:
200 case I2D:
201 case L2D:
202 case F2D:
203 return BasicValue.DOUBLE_VALUE;
204 case IFEQ:
205 case IFNE:
206 case IFLT:
207 case IFGE:
208 case IFGT:
209 case IFLE:
210 case TABLESWITCH:
211 case LOOKUPSWITCH:
212 case IRETURN:
213 case LRETURN:
214 case FRETURN:
215 case DRETURN:
216 case ARETURN:
217 case PUTSTATIC:
218 return null;
219 case GETFIELD:
220 return newValue(Type.getType(((FieldInsnNode) insn).desc));
221 case NEWARRAY:
222 switch (((IntInsnNode) insn).operand) {
223 case T_BOOLEAN:
224 return newValue(Type.getType("[Z"));
225 case T_CHAR:
226 return newValue(Type.getType("[C"));
227 case T_BYTE:
228 return newValue(Type.getType("[B"));
229 case T_SHORT:
230 return newValue(Type.getType("[S"));
231 case T_INT:
232 return newValue(Type.getType("[I"));
233 case T_FLOAT:
234 return newValue(Type.getType("[F"));
235 case T_DOUBLE:
236 return newValue(Type.getType("[D"));
237 case T_LONG:
238 return newValue(Type.getType("[J"));
239 default:
240 break;
87241 }
88 }
89
90 @Override
91 public BasicValue newOperation(final AbstractInsnNode insn)
92 throws AnalyzerException {
93 switch (insn.getOpcode()) {
94 case ACONST_NULL:
95 return newValue(Type.getObjectType("null"));
96 case ICONST_M1:
97 case ICONST_0:
98 case ICONST_1:
99 case ICONST_2:
100 case ICONST_3:
101 case ICONST_4:
102 case ICONST_5:
103 return BasicValue.INT_VALUE;
104 case LCONST_0:
105 case LCONST_1:
106 return BasicValue.LONG_VALUE;
107 case FCONST_0:
108 case FCONST_1:
109 case FCONST_2:
110 return BasicValue.FLOAT_VALUE;
111 case DCONST_0:
112 case DCONST_1:
113 return BasicValue.DOUBLE_VALUE;
114 case BIPUSH:
115 case SIPUSH:
116 return BasicValue.INT_VALUE;
117 case LDC:
118 Object cst = ((LdcInsnNode) insn).cst;
119 if (cst instanceof Integer) {
120 return BasicValue.INT_VALUE;
121 } else if (cst instanceof Float) {
122 return BasicValue.FLOAT_VALUE;
123 } else if (cst instanceof Long) {
124 return BasicValue.LONG_VALUE;
125 } else if (cst instanceof Double) {
126 return BasicValue.DOUBLE_VALUE;
127 } else if (cst instanceof String) {
128 return newValue(Type.getObjectType("java/lang/String"));
129 } else if (cst instanceof Type) {
130 int sort = ((Type) cst).getSort();
131 if (sort == Type.OBJECT || sort == Type.ARRAY) {
132 return newValue(Type.getObjectType("java/lang/Class"));
133 } else if (sort == Type.METHOD) {
134 return newValue(Type
135 .getObjectType("java/lang/invoke/MethodType"));
136 } else {
137 throw new IllegalArgumentException("Illegal LDC constant "
138 + cst);
139 }
140 } else if (cst instanceof Handle) {
141 return newValue(Type
142 .getObjectType("java/lang/invoke/MethodHandle"));
143 } else {
144 throw new IllegalArgumentException("Illegal LDC constant "
145 + cst);
146 }
147 case JSR:
148 return BasicValue.RETURNADDRESS_VALUE;
149 case GETSTATIC:
150 return newValue(Type.getType(((FieldInsnNode) insn).desc));
151 case NEW:
152 return newValue(Type.getObjectType(((TypeInsnNode) insn).desc));
153 default:
154 throw new Error("Internal error.");
155 }
156 }
157
158 @Override
159 public BasicValue copyOperation(final AbstractInsnNode insn,
160 final BasicValue value) throws AnalyzerException {
161 return value;
162 }
163
164 @Override
165 public BasicValue unaryOperation(final AbstractInsnNode insn,
166 final BasicValue value) throws AnalyzerException {
167 switch (insn.getOpcode()) {
168 case INEG:
169 case IINC:
170 case L2I:
171 case F2I:
172 case D2I:
173 case I2B:
174 case I2C:
175 case I2S:
176 return BasicValue.INT_VALUE;
177 case FNEG:
178 case I2F:
179 case L2F:
180 case D2F:
181 return BasicValue.FLOAT_VALUE;
182 case LNEG:
183 case I2L:
184 case F2L:
185 case D2L:
186 return BasicValue.LONG_VALUE;
187 case DNEG:
188 case I2D:
189 case L2D:
190 case F2D:
191 return BasicValue.DOUBLE_VALUE;
192 case IFEQ:
193 case IFNE:
194 case IFLT:
195 case IFGE:
196 case IFGT:
197 case IFLE:
198 case TABLESWITCH:
199 case LOOKUPSWITCH:
200 case IRETURN:
201 case LRETURN:
202 case FRETURN:
203 case DRETURN:
204 case ARETURN:
205 case PUTSTATIC:
206 return null;
207 case GETFIELD:
208 return newValue(Type.getType(((FieldInsnNode) insn).desc));
209 case NEWARRAY:
210 switch (((IntInsnNode) insn).operand) {
211 case T_BOOLEAN:
212 return newValue(Type.getType("[Z"));
213 case T_CHAR:
214 return newValue(Type.getType("[C"));
215 case T_BYTE:
216 return newValue(Type.getType("[B"));
217 case T_SHORT:
218 return newValue(Type.getType("[S"));
219 case T_INT:
220 return newValue(Type.getType("[I"));
221 case T_FLOAT:
222 return newValue(Type.getType("[F"));
223 case T_DOUBLE:
224 return newValue(Type.getType("[D"));
225 case T_LONG:
226 return newValue(Type.getType("[J"));
227 default:
228 throw new AnalyzerException(insn, "Invalid array type");
229 }
230 case ANEWARRAY:
231 String desc = ((TypeInsnNode) insn).desc;
232 return newValue(Type.getType("[" + Type.getObjectType(desc)));
233 case ARRAYLENGTH:
234 return BasicValue.INT_VALUE;
235 case ATHROW:
236 return null;
237 case CHECKCAST:
238 desc = ((TypeInsnNode) insn).desc;
239 return newValue(Type.getObjectType(desc));
240 case INSTANCEOF:
241 return BasicValue.INT_VALUE;
242 case MONITORENTER:
243 case MONITOREXIT:
244 case IFNULL:
245 case IFNONNULL:
246 return null;
247 default:
248 throw new Error("Internal error.");
249 }
250 }
251
252 @Override
253 public BasicValue binaryOperation(final AbstractInsnNode insn,
254 final BasicValue value1, final BasicValue value2)
255 throws AnalyzerException {
256 switch (insn.getOpcode()) {
257 case IALOAD:
258 case BALOAD:
259 case CALOAD:
260 case SALOAD:
261 case IADD:
262 case ISUB:
263 case IMUL:
264 case IDIV:
265 case IREM:
266 case ISHL:
267 case ISHR:
268 case IUSHR:
269 case IAND:
270 case IOR:
271 case IXOR:
272 return BasicValue.INT_VALUE;
273 case FALOAD:
274 case FADD:
275 case FSUB:
276 case FMUL:
277 case FDIV:
278 case FREM:
279 return BasicValue.FLOAT_VALUE;
280 case LALOAD:
281 case LADD:
282 case LSUB:
283 case LMUL:
284 case LDIV:
285 case LREM:
286 case LSHL:
287 case LSHR:
288 case LUSHR:
289 case LAND:
290 case LOR:
291 case LXOR:
292 return BasicValue.LONG_VALUE;
293 case DALOAD:
294 case DADD:
295 case DSUB:
296 case DMUL:
297 case DDIV:
298 case DREM:
299 return BasicValue.DOUBLE_VALUE;
300 case AALOAD:
301 return BasicValue.REFERENCE_VALUE;
302 case LCMP:
303 case FCMPL:
304 case FCMPG:
305 case DCMPL:
306 case DCMPG:
307 return BasicValue.INT_VALUE;
308 case IF_ICMPEQ:
309 case IF_ICMPNE:
310 case IF_ICMPLT:
311 case IF_ICMPGE:
312 case IF_ICMPGT:
313 case IF_ICMPLE:
314 case IF_ACMPEQ:
315 case IF_ACMPNE:
316 case PUTFIELD:
317 return null;
318 default:
319 throw new Error("Internal error.");
320 }
321 }
322
323 @Override
324 public BasicValue ternaryOperation(final AbstractInsnNode insn,
325 final BasicValue value1, final BasicValue value2,
326 final BasicValue value3) throws AnalyzerException {
327 return null;
328 }
329
330 @Override
331 public BasicValue naryOperation(final AbstractInsnNode insn,
332 final List<? extends BasicValue> values) throws AnalyzerException {
333 int opcode = insn.getOpcode();
334 if (opcode == MULTIANEWARRAY) {
335 return newValue(Type.getType(((MultiANewArrayInsnNode) insn).desc));
336 } else if (opcode == INVOKEDYNAMIC) {
337 return newValue(Type
338 .getReturnType(((InvokeDynamicInsnNode) insn).desc));
339 } else {
340 return newValue(Type.getReturnType(((MethodInsnNode) insn).desc));
341 }
342 }
343
344 @Override
345 public void returnOperation(final AbstractInsnNode insn,
346 final BasicValue value, final BasicValue expected)
347 throws AnalyzerException {
348 }
349
350 @Override
351 public BasicValue merge(final BasicValue v, final BasicValue w) {
352 if (!v.equals(w)) {
353 return BasicValue.UNINITIALIZED_VALUE;
354 }
355 return v;
356 }
242 throw new AnalyzerException(insn, "Invalid array type");
243 case ANEWARRAY:
244 return newValue(Type.getType("[" + Type.getObjectType(((TypeInsnNode) insn).desc)));
245 case ARRAYLENGTH:
246 return BasicValue.INT_VALUE;
247 case ATHROW:
248 return null;
249 case CHECKCAST:
250 return newValue(Type.getObjectType(((TypeInsnNode) insn).desc));
251 case INSTANCEOF:
252 return BasicValue.INT_VALUE;
253 case MONITORENTER:
254 case MONITOREXIT:
255 case IFNULL:
256 case IFNONNULL:
257 return null;
258 default:
259 throw new AssertionError();
260 }
261 }
262
263 @Override
264 public BasicValue binaryOperation(
265 final AbstractInsnNode insn, final BasicValue value1, final BasicValue value2)
266 throws AnalyzerException {
267 switch (insn.getOpcode()) {
268 case IALOAD:
269 case BALOAD:
270 case CALOAD:
271 case SALOAD:
272 case IADD:
273 case ISUB:
274 case IMUL:
275 case IDIV:
276 case IREM:
277 case ISHL:
278 case ISHR:
279 case IUSHR:
280 case IAND:
281 case IOR:
282 case IXOR:
283 return BasicValue.INT_VALUE;
284 case FALOAD:
285 case FADD:
286 case FSUB:
287 case FMUL:
288 case FDIV:
289 case FREM:
290 return BasicValue.FLOAT_VALUE;
291 case LALOAD:
292 case LADD:
293 case LSUB:
294 case LMUL:
295 case LDIV:
296 case LREM:
297 case LSHL:
298 case LSHR:
299 case LUSHR:
300 case LAND:
301 case LOR:
302 case LXOR:
303 return BasicValue.LONG_VALUE;
304 case DALOAD:
305 case DADD:
306 case DSUB:
307 case DMUL:
308 case DDIV:
309 case DREM:
310 return BasicValue.DOUBLE_VALUE;
311 case AALOAD:
312 return BasicValue.REFERENCE_VALUE;
313 case LCMP:
314 case FCMPL:
315 case FCMPG:
316 case DCMPL:
317 case DCMPG:
318 return BasicValue.INT_VALUE;
319 case IF_ICMPEQ:
320 case IF_ICMPNE:
321 case IF_ICMPLT:
322 case IF_ICMPGE:
323 case IF_ICMPGT:
324 case IF_ICMPLE:
325 case IF_ACMPEQ:
326 case IF_ACMPNE:
327 case PUTFIELD:
328 return null;
329 default:
330 throw new AssertionError();
331 }
332 }
333
334 @Override
335 public BasicValue ternaryOperation(
336 final AbstractInsnNode insn,
337 final BasicValue value1,
338 final BasicValue value2,
339 final BasicValue value3)
340 throws AnalyzerException {
341 return null;
342 }
343
344 @Override
345 public BasicValue naryOperation(
346 final AbstractInsnNode insn, final List<? extends BasicValue> values)
347 throws AnalyzerException {
348 int opcode = insn.getOpcode();
349 if (opcode == MULTIANEWARRAY) {
350 return newValue(Type.getType(((MultiANewArrayInsnNode) insn).desc));
351 } else if (opcode == INVOKEDYNAMIC) {
352 return newValue(Type.getReturnType(((InvokeDynamicInsnNode) insn).desc));
353 } else {
354 return newValue(Type.getReturnType(((MethodInsnNode) insn).desc));
355 }
356 }
357
358 @Override
359 public void returnOperation(
360 final AbstractInsnNode insn, final BasicValue value, final BasicValue expected)
361 throws AnalyzerException {
362 // Nothing to do.
363 }
364
365 @Override
366 public BasicValue merge(final BasicValue value1, final BasicValue value2) {
367 if (!value1.equals(value2)) {
368 return BasicValue.UNINITIALIZED_VALUE;
369 }
370 return value1;
371 }
357372 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.tree.analysis;
3028
3129 import org.eclipse.persistence.internal.libraries.asm.Type;
3230
3331 /**
34 * A {@link Value} that is represented by its type in a seven types type system.
35 * This type system distinguishes the UNINITIALZED, INT, FLOAT, LONG, DOUBLE,
36 * REFERENCE and RETURNADDRESS types.
37 *
32 * A {@link Value} that is represented with its type in a seven types type system. This type system
33 * distinguishes the UNINITIALZED, INT, FLOAT, LONG, DOUBLE, REFERENCE and RETURNADDRESS types.
34 *
3835 * @author Eric Bruneton
3936 */
4037 public class BasicValue implements Value {
4138
42 public static final BasicValue UNINITIALIZED_VALUE = new BasicValue(null);
39 /** An uninitialized value. */
40 public static final BasicValue UNINITIALIZED_VALUE = new BasicValue(null);
4341
44 public static final BasicValue INT_VALUE = new BasicValue(Type.INT_TYPE);
42 /** A byte, boolean, char, short, or int value. */
43 public static final BasicValue INT_VALUE = new BasicValue(Type.INT_TYPE);
4544
46 public static final BasicValue FLOAT_VALUE = new BasicValue(Type.FLOAT_TYPE);
45 /** A float value. */
46 public static final BasicValue FLOAT_VALUE = new BasicValue(Type.FLOAT_TYPE);
4747
48 public static final BasicValue LONG_VALUE = new BasicValue(Type.LONG_TYPE);
48 /** A long value. */
49 public static final BasicValue LONG_VALUE = new BasicValue(Type.LONG_TYPE);
4950
50 public static final BasicValue DOUBLE_VALUE = new BasicValue(
51 Type.DOUBLE_TYPE);
51 /** A double value. */
52 public static final BasicValue DOUBLE_VALUE = new BasicValue(Type.DOUBLE_TYPE);
5253
53 public static final BasicValue REFERENCE_VALUE = new BasicValue(
54 Type.getObjectType("java/lang/Object"));
54 /** An object or array reference value. */
55 public static final BasicValue REFERENCE_VALUE =
56 new BasicValue(Type.getObjectType("java/lang/Object"));
5557
56 public static final BasicValue RETURNADDRESS_VALUE = new BasicValue(
57 Type.VOID_TYPE);
58 /** A return address value (produced by a jsr instruction). */
59 public static final BasicValue RETURNADDRESS_VALUE = new BasicValue(Type.VOID_TYPE);
5860
59 private final Type type;
61 /** The {@link Type} of this value, or <tt>null</tt> for uninitialized values. */
62 private final Type type;
6063
61 public BasicValue(final Type type) {
62 this.type = type;
64 /**
65 * Constructs a new {@link BasicValue} of the given type.
66 *
67 * @param type the value type.
68 */
69 public BasicValue(final Type type) {
70 this.type = type;
71 }
72
73 /**
74 * Returns the {@link Type} of this value.
75 *
76 * @return the {@link Type} of this value.
77 */
78 public Type getType() {
79 return type;
80 }
81
82 public int getSize() {
83 return type == Type.LONG_TYPE || type == Type.DOUBLE_TYPE ? 2 : 1;
84 }
85
86 /**
87 * Returns whether this value corresponds to an object or array reference.
88 *
89 * @return whether this value corresponds to an object or array reference.
90 */
91 public boolean isReference() {
92 return type != null && (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY);
93 }
94
95 @Override
96 public boolean equals(final Object value) {
97 if (value == this) {
98 return true;
99 } else if (value instanceof BasicValue) {
100 if (type == null) {
101 return ((BasicValue) value).type == null;
102 } else {
103 return type.equals(((BasicValue) value).type);
104 }
105 } else {
106 return false;
63107 }
108 }
64109
65 public Type getType() {
66 return type;
110 @Override
111 public int hashCode() {
112 return type == null ? 0 : type.hashCode();
113 }
114
115 @Override
116 public String toString() {
117 if (this == UNINITIALIZED_VALUE) {
118 return ".";
119 } else if (this == RETURNADDRESS_VALUE) {
120 return "A";
121 } else if (this == REFERENCE_VALUE) {
122 return "R";
123 } else {
124 return type.getDescriptor();
67125 }
68
69 public int getSize() {
70 return type == Type.LONG_TYPE || type == Type.DOUBLE_TYPE ? 2 : 1;
71 }
72
73 public boolean isReference() {
74 return type != null
75 && (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY);
76 }
77
78 @Override
79 public boolean equals(final Object value) {
80 if (value == this) {
81 return true;
82 } else if (value instanceof BasicValue) {
83 if (type == null) {
84 return ((BasicValue) value).type == null;
85 } else {
86 return type.equals(((BasicValue) value).type);
87 }
88 } else {
89 return false;
90 }
91 }
92
93 @Override
94 public int hashCode() {
95 return type == null ? 0 : type.hashCode();
96 }
97
98 @Override
99 public String toString() {
100 if (this == UNINITIALIZED_VALUE) {
101 return ".";
102 } else if (this == RETURNADDRESS_VALUE) {
103 return "A";
104 } else if (this == REFERENCE_VALUE) {
105 return "R";
106 } else {
107 return type.getDescriptor();
108 }
109 }
126 }
110127 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.tree.analysis;
3028
3129 import java.util.List;
3735 import org.eclipse.persistence.internal.libraries.asm.tree.MethodInsnNode;
3836
3937 /**
40 * An extended {@link BasicInterpreter} that checks that bytecode instructions
41 * are correctly used.
42 *
38 * An extended {@link BasicInterpreter} that checks that bytecode instructions are correctly used.
39 *
4340 * @author Eric Bruneton
4441 * @author Bing Ran
4542 */
4643 public class BasicVerifier extends BasicInterpreter {
4744
48 public BasicVerifier() {
49 super(ASM6);
50 }
51
52 protected BasicVerifier(final int api) {
53 super(api);
54 }
55
56 @Override
57 public BasicValue copyOperation(final AbstractInsnNode insn,
58 final BasicValue value) throws AnalyzerException {
59 Value expected;
60 switch (insn.getOpcode()) {
61 case ILOAD:
62 case ISTORE:
63 expected = BasicValue.INT_VALUE;
64 break;
65 case FLOAD:
66 case FSTORE:
67 expected = BasicValue.FLOAT_VALUE;
68 break;
69 case LLOAD:
70 case LSTORE:
71 expected = BasicValue.LONG_VALUE;
72 break;
73 case DLOAD:
74 case DSTORE:
75 expected = BasicValue.DOUBLE_VALUE;
76 break;
77 case ALOAD:
78 if (!value.isReference()) {
79 throw new AnalyzerException(insn, null, "an object reference",
80 value);
81 }
82 return value;
83 case ASTORE:
84 if (!value.isReference()
85 && !BasicValue.RETURNADDRESS_VALUE.equals(value)) {
86 throw new AnalyzerException(insn, null,
87 "an object reference or a return address", value);
88 }
89 return value;
90 default:
91 return value;
92 }
93 if (!expected.equals(value)) {
94 throw new AnalyzerException(insn, null, expected, value);
45 /**
46 * Constructs a new {@link BasicVerifier} for the latest ASM API version. <i>Subclasses must not use
47 * this constructor</i>. Instead, they must use the {@link #BasicVerifier(int)} version.
48 */
49 public BasicVerifier() {
50 super(ASM6);
51 if (getClass() != BasicVerifier.class) {
52 throw new IllegalStateException();
53 }
54 }
55
56 /**
57 * Constructs a new {@link BasicVerifier}.
58 *
59 * @param api the ASM API version supported by this interpreter. Must be one of {@link
60 * org.eclipse.persistence.internal.libraries.asm.Opcodes#ASM4}, {@link org.eclipse.persistence.internal.libraries.asm.Opcodes#ASM5} or {@link
61 * org.eclipse.persistence.internal.libraries.asm.Opcodes#ASM6}.
62 */
63 protected BasicVerifier(final int api) {
64 super(api);
65 }
66
67 @Override
68 public BasicValue copyOperation(final AbstractInsnNode insn, final BasicValue value)
69 throws AnalyzerException {
70 Value expected;
71 switch (insn.getOpcode()) {
72 case ILOAD:
73 case ISTORE:
74 expected = BasicValue.INT_VALUE;
75 break;
76 case FLOAD:
77 case FSTORE:
78 expected = BasicValue.FLOAT_VALUE;
79 break;
80 case LLOAD:
81 case LSTORE:
82 expected = BasicValue.LONG_VALUE;
83 break;
84 case DLOAD:
85 case DSTORE:
86 expected = BasicValue.DOUBLE_VALUE;
87 break;
88 case ALOAD:
89 if (!value.isReference()) {
90 throw new AnalyzerException(insn, null, "an object reference", value);
9591 }
9692 return value;
97 }
98
99 @Override
100 public BasicValue unaryOperation(final AbstractInsnNode insn,
101 final BasicValue value) throws AnalyzerException {
102 BasicValue expected;
103 switch (insn.getOpcode()) {
104 case INEG:
105 case IINC:
106 case I2F:
107 case I2L:
108 case I2D:
109 case I2B:
110 case I2C:
111 case I2S:
112 case IFEQ:
113 case IFNE:
114 case IFLT:
115 case IFGE:
116 case IFGT:
117 case IFLE:
118 case TABLESWITCH:
119 case LOOKUPSWITCH:
120 case IRETURN:
121 case NEWARRAY:
122 case ANEWARRAY:
123 expected = BasicValue.INT_VALUE;
124 break;
125 case FNEG:
126 case F2I:
127 case F2L:
128 case F2D:
129 case FRETURN:
130 expected = BasicValue.FLOAT_VALUE;
131 break;
132 case LNEG:
133 case L2I:
134 case L2F:
135 case L2D:
136 case LRETURN:
137 expected = BasicValue.LONG_VALUE;
138 break;
139 case DNEG:
140 case D2I:
141 case D2F:
142 case D2L:
143 case DRETURN:
144 expected = BasicValue.DOUBLE_VALUE;
145 break;
146 case GETFIELD:
147 expected = newValue(Type
148 .getObjectType(((FieldInsnNode) insn).owner));
149 break;
150 case CHECKCAST:
151 if (!value.isReference()) {
152 throw new AnalyzerException(insn, null, "an object reference",
153 value);
154 }
155 return super.unaryOperation(insn, value);
156 case ARRAYLENGTH:
157 if (!isArrayValue(value)) {
158 throw new AnalyzerException(insn, null, "an array reference",
159 value);
160 }
161 return super.unaryOperation(insn, value);
162 case ARETURN:
163 case ATHROW:
164 case INSTANCEOF:
165 case MONITORENTER:
166 case MONITOREXIT:
167 case IFNULL:
168 case IFNONNULL:
169 if (!value.isReference()) {
170 throw new AnalyzerException(insn, null, "an object reference",
171 value);
172 }
173 return super.unaryOperation(insn, value);
174 case PUTSTATIC:
175 expected = newValue(Type.getType(((FieldInsnNode) insn).desc));
176 break;
177 default:
178 throw new Error("Internal error.");
179 }
180 if (!isSubTypeOf(value, expected)) {
181 throw new AnalyzerException(insn, null, expected, value);
93 case ASTORE:
94 if (!value.isReference() && !BasicValue.RETURNADDRESS_VALUE.equals(value)) {
95 throw new AnalyzerException(insn, null, "an object reference or a return address", value);
96 }
97 return value;
98 default:
99 return value;
100 }
101 if (!expected.equals(value)) {
102 throw new AnalyzerException(insn, null, expected, value);
103 }
104 return value;
105 }
106
107 @Override
108 public BasicValue unaryOperation(final AbstractInsnNode insn, final BasicValue value)
109 throws AnalyzerException {
110 BasicValue expected;
111 switch (insn.getOpcode()) {
112 case INEG:
113 case IINC:
114 case I2F:
115 case I2L:
116 case I2D:
117 case I2B:
118 case I2C:
119 case I2S:
120 case IFEQ:
121 case IFNE:
122 case IFLT:
123 case IFGE:
124 case IFGT:
125 case IFLE:
126 case TABLESWITCH:
127 case LOOKUPSWITCH:
128 case IRETURN:
129 case NEWARRAY:
130 case ANEWARRAY:
131 expected = BasicValue.INT_VALUE;
132 break;
133 case FNEG:
134 case F2I:
135 case F2L:
136 case F2D:
137 case FRETURN:
138 expected = BasicValue.FLOAT_VALUE;
139 break;
140 case LNEG:
141 case L2I:
142 case L2F:
143 case L2D:
144 case LRETURN:
145 expected = BasicValue.LONG_VALUE;
146 break;
147 case DNEG:
148 case D2I:
149 case D2F:
150 case D2L:
151 case DRETURN:
152 expected = BasicValue.DOUBLE_VALUE;
153 break;
154 case GETFIELD:
155 expected = newValue(Type.getObjectType(((FieldInsnNode) insn).owner));
156 break;
157 case ARRAYLENGTH:
158 if (!isArrayValue(value)) {
159 throw new AnalyzerException(insn, null, "an array reference", value);
182160 }
183161 return super.unaryOperation(insn, value);
184 }
185
186 @Override
187 public BasicValue binaryOperation(final AbstractInsnNode insn,
188 final BasicValue value1, final BasicValue value2)
189 throws AnalyzerException {
190 BasicValue expected1;
191 BasicValue expected2;
192 switch (insn.getOpcode()) {
193 case IALOAD:
194 expected1 = newValue(Type.getType("[I"));
195 expected2 = BasicValue.INT_VALUE;
196 break;
197 case BALOAD:
198 if (isSubTypeOf(value1, newValue(Type.getType("[Z")))) {
199 expected1 = newValue(Type.getType("[Z"));
200 } else {
201 expected1 = newValue(Type.getType("[B"));
202 }
203 expected2 = BasicValue.INT_VALUE;
204 break;
205 case CALOAD:
206 expected1 = newValue(Type.getType("[C"));
207 expected2 = BasicValue.INT_VALUE;
208 break;
209 case SALOAD:
210 expected1 = newValue(Type.getType("[S"));
211 expected2 = BasicValue.INT_VALUE;
212 break;
213 case LALOAD:
214 expected1 = newValue(Type.getType("[J"));
215 expected2 = BasicValue.INT_VALUE;
216 break;
217 case FALOAD:
218 expected1 = newValue(Type.getType("[F"));
219 expected2 = BasicValue.INT_VALUE;
220 break;
221 case DALOAD:
222 expected1 = newValue(Type.getType("[D"));
223 expected2 = BasicValue.INT_VALUE;
224 break;
225 case AALOAD:
226 expected1 = newValue(Type.getType("[Ljava/lang/Object;"));
227 expected2 = BasicValue.INT_VALUE;
228 break;
229 case IADD:
230 case ISUB:
231 case IMUL:
232 case IDIV:
233 case IREM:
234 case ISHL:
235 case ISHR:
236 case IUSHR:
237 case IAND:
238 case IOR:
239 case IXOR:
240 case IF_ICMPEQ:
241 case IF_ICMPNE:
242 case IF_ICMPLT:
243 case IF_ICMPGE:
244 case IF_ICMPGT:
245 case IF_ICMPLE:
246 expected1 = BasicValue.INT_VALUE;
247 expected2 = BasicValue.INT_VALUE;
248 break;
249 case FADD:
250 case FSUB:
251 case FMUL:
252 case FDIV:
253 case FREM:
254 case FCMPL:
255 case FCMPG:
256 expected1 = BasicValue.FLOAT_VALUE;
257 expected2 = BasicValue.FLOAT_VALUE;
258 break;
259 case LADD:
260 case LSUB:
261 case LMUL:
262 case LDIV:
263 case LREM:
264 case LAND:
265 case LOR:
266 case LXOR:
267 case LCMP:
268 expected1 = BasicValue.LONG_VALUE;
269 expected2 = BasicValue.LONG_VALUE;
270 break;
271 case LSHL:
272 case LSHR:
273 case LUSHR:
274 expected1 = BasicValue.LONG_VALUE;
275 expected2 = BasicValue.INT_VALUE;
276 break;
277 case DADD:
278 case DSUB:
279 case DMUL:
280 case DDIV:
281 case DREM:
282 case DCMPL:
283 case DCMPG:
284 expected1 = BasicValue.DOUBLE_VALUE;
285 expected2 = BasicValue.DOUBLE_VALUE;
286 break;
287 case IF_ACMPEQ:
288 case IF_ACMPNE:
289 expected1 = BasicValue.REFERENCE_VALUE;
290 expected2 = BasicValue.REFERENCE_VALUE;
291 break;
292 case PUTFIELD:
293 FieldInsnNode fin = (FieldInsnNode) insn;
294 expected1 = newValue(Type.getObjectType(fin.owner));
295 expected2 = newValue(Type.getType(fin.desc));
296 break;
297 default:
298 throw new Error("Internal error.");
299 }
300 if (!isSubTypeOf(value1, expected1)) {
301 throw new AnalyzerException(insn, "First argument", expected1,
302 value1);
303 } else if (!isSubTypeOf(value2, expected2)) {
304 throw new AnalyzerException(insn, "Second argument", expected2,
305 value2);
306 }
307 if (insn.getOpcode() == AALOAD) {
308 return getElementValue(value1);
162 case CHECKCAST:
163 case ARETURN:
164 case ATHROW:
165 case INSTANCEOF:
166 case MONITORENTER:
167 case MONITOREXIT:
168 case IFNULL:
169 case IFNONNULL:
170 if (!value.isReference()) {
171 throw new AnalyzerException(insn, null, "an object reference", value);
172 }
173 return super.unaryOperation(insn, value);
174 case PUTSTATIC:
175 expected = newValue(Type.getType(((FieldInsnNode) insn).desc));
176 break;
177 default:
178 throw new AssertionError();
179 }
180 if (!isSubTypeOf(value, expected)) {
181 throw new AnalyzerException(insn, null, expected, value);
182 }
183 return super.unaryOperation(insn, value);
184 }
185
186 @Override
187 public BasicValue binaryOperation(
188 final AbstractInsnNode insn, final BasicValue value1, final BasicValue value2)
189 throws AnalyzerException {
190 BasicValue expected1;
191 BasicValue expected2;
192 switch (insn.getOpcode()) {
193 case IALOAD:
194 expected1 = newValue(Type.getType("[I"));
195 expected2 = BasicValue.INT_VALUE;
196 break;
197 case BALOAD:
198 if (isSubTypeOf(value1, newValue(Type.getType("[Z")))) {
199 expected1 = newValue(Type.getType("[Z"));
309200 } else {
310 return super.binaryOperation(insn, value1, value2);
311 }
312 }
313
314 @Override
315 public BasicValue ternaryOperation(final AbstractInsnNode insn,
316 final BasicValue value1, final BasicValue value2,
317 final BasicValue value3) throws AnalyzerException {
318 BasicValue expected1;
319 BasicValue expected3;
320 switch (insn.getOpcode()) {
321 case IASTORE:
322 expected1 = newValue(Type.getType("[I"));
323 expected3 = BasicValue.INT_VALUE;
324 break;
325 case BASTORE:
326 if (isSubTypeOf(value1, newValue(Type.getType("[Z")))) {
327 expected1 = newValue(Type.getType("[Z"));
328 } else {
329 expected1 = newValue(Type.getType("[B"));
330 }
331 expected3 = BasicValue.INT_VALUE;
332 break;
333 case CASTORE:
334 expected1 = newValue(Type.getType("[C"));
335 expected3 = BasicValue.INT_VALUE;
336 break;
337 case SASTORE:
338 expected1 = newValue(Type.getType("[S"));
339 expected3 = BasicValue.INT_VALUE;
340 break;
341 case LASTORE:
342 expected1 = newValue(Type.getType("[J"));
343 expected3 = BasicValue.LONG_VALUE;
344 break;
345 case FASTORE:
346 expected1 = newValue(Type.getType("[F"));
347 expected3 = BasicValue.FLOAT_VALUE;
348 break;
349 case DASTORE:
350 expected1 = newValue(Type.getType("[D"));
351 expected3 = BasicValue.DOUBLE_VALUE;
352 break;
353 case AASTORE:
354 expected1 = value1;
355 expected3 = BasicValue.REFERENCE_VALUE;
356 break;
357 default:
358 throw new Error("Internal error.");
359 }
360 if (!isSubTypeOf(value1, expected1)) {
361 throw new AnalyzerException(insn, "First argument", "a "
362 + expected1 + " array reference", value1);
363 } else if (!BasicValue.INT_VALUE.equals(value2)) {
364 throw new AnalyzerException(insn, "Second argument",
365 BasicValue.INT_VALUE, value2);
366 } else if (!isSubTypeOf(value3, expected3)) {
367 throw new AnalyzerException(insn, "Third argument", expected3,
368 value3);
369 }
370 return null;
371 }
372
373 @Override
374 public BasicValue naryOperation(final AbstractInsnNode insn,
375 final List<? extends BasicValue> values) throws AnalyzerException {
376 int opcode = insn.getOpcode();
377 if (opcode == MULTIANEWARRAY) {
378 for (int i = 0; i < values.size(); ++i) {
379 if (!BasicValue.INT_VALUE.equals(values.get(i))) {
380 throw new AnalyzerException(insn, null,
381 BasicValue.INT_VALUE, values.get(i));
382 }
383 }
201 expected1 = newValue(Type.getType("[B"));
202 }
203 expected2 = BasicValue.INT_VALUE;
204 break;
205 case CALOAD:
206 expected1 = newValue(Type.getType("[C"));
207 expected2 = BasicValue.INT_VALUE;
208 break;
209 case SALOAD:
210 expected1 = newValue(Type.getType("[S"));
211 expected2 = BasicValue.INT_VALUE;
212 break;
213 case LALOAD:
214 expected1 = newValue(Type.getType("[J"));
215 expected2 = BasicValue.INT_VALUE;
216 break;
217 case FALOAD:
218 expected1 = newValue(Type.getType("[F"));
219 expected2 = BasicValue.INT_VALUE;
220 break;
221 case DALOAD:
222 expected1 = newValue(Type.getType("[D"));
223 expected2 = BasicValue.INT_VALUE;
224 break;
225 case AALOAD:
226 expected1 = newValue(Type.getType("[Ljava/lang/Object;"));
227 expected2 = BasicValue.INT_VALUE;
228 break;
229 case IADD:
230 case ISUB:
231 case IMUL:
232 case IDIV:
233 case IREM:
234 case ISHL:
235 case ISHR:
236 case IUSHR:
237 case IAND:
238 case IOR:
239 case IXOR:
240 case IF_ICMPEQ:
241 case IF_ICMPNE:
242 case IF_ICMPLT:
243 case IF_ICMPGE:
244 case IF_ICMPGT:
245 case IF_ICMPLE:
246 expected1 = BasicValue.INT_VALUE;
247 expected2 = BasicValue.INT_VALUE;
248 break;
249 case FADD:
250 case FSUB:
251 case FMUL:
252 case FDIV:
253 case FREM:
254 case FCMPL:
255 case FCMPG:
256 expected1 = BasicValue.FLOAT_VALUE;
257 expected2 = BasicValue.FLOAT_VALUE;
258 break;
259 case LADD:
260 case LSUB:
261 case LMUL:
262 case LDIV:
263 case LREM:
264 case LAND:
265 case LOR:
266 case LXOR:
267 case LCMP:
268 expected1 = BasicValue.LONG_VALUE;
269 expected2 = BasicValue.LONG_VALUE;
270 break;
271 case LSHL:
272 case LSHR:
273 case LUSHR:
274 expected1 = BasicValue.LONG_VALUE;
275 expected2 = BasicValue.INT_VALUE;
276 break;
277 case DADD:
278 case DSUB:
279 case DMUL:
280 case DDIV:
281 case DREM:
282 case DCMPL:
283 case DCMPG:
284 expected1 = BasicValue.DOUBLE_VALUE;
285 expected2 = BasicValue.DOUBLE_VALUE;
286 break;
287 case IF_ACMPEQ:
288 case IF_ACMPNE:
289 expected1 = BasicValue.REFERENCE_VALUE;
290 expected2 = BasicValue.REFERENCE_VALUE;
291 break;
292 case PUTFIELD:
293 FieldInsnNode fieldInsn = (FieldInsnNode) insn;
294 expected1 = newValue(Type.getObjectType(fieldInsn.owner));
295 expected2 = newValue(Type.getType(fieldInsn.desc));
296 break;
297 default:
298 throw new AssertionError();
299 }
300 if (!isSubTypeOf(value1, expected1)) {
301 throw new AnalyzerException(insn, "First argument", expected1, value1);
302 } else if (!isSubTypeOf(value2, expected2)) {
303 throw new AnalyzerException(insn, "Second argument", expected2, value2);
304 }
305 if (insn.getOpcode() == AALOAD) {
306 return getElementValue(value1);
307 } else {
308 return super.binaryOperation(insn, value1, value2);
309 }
310 }
311
312 @Override
313 public BasicValue ternaryOperation(
314 final AbstractInsnNode insn,
315 final BasicValue value1,
316 final BasicValue value2,
317 final BasicValue value3)
318 throws AnalyzerException {
319 BasicValue expected1;
320 BasicValue expected3;
321 switch (insn.getOpcode()) {
322 case IASTORE:
323 expected1 = newValue(Type.getType("[I"));
324 expected3 = BasicValue.INT_VALUE;
325 break;
326 case BASTORE:
327 if (isSubTypeOf(value1, newValue(Type.getType("[Z")))) {
328 expected1 = newValue(Type.getType("[Z"));
384329 } else {
385 int i = 0;
386 int j = 0;
387 if (opcode != INVOKESTATIC && opcode != INVOKEDYNAMIC) {
388 Type owner = Type.getObjectType(((MethodInsnNode) insn).owner);
389 if (!isSubTypeOf(values.get(i++), newValue(owner))) {
390 throw new AnalyzerException(insn, "Method owner",
391 newValue(owner), values.get(0));
392 }
393 }
394 String desc = (opcode == INVOKEDYNAMIC) ? ((InvokeDynamicInsnNode) insn).desc
395 : ((MethodInsnNode) insn).desc;
396 Type[] args = Type.getArgumentTypes(desc);
397 while (i < values.size()) {
398 BasicValue expected = newValue(args[j++]);
399 BasicValue encountered = values.get(i++);
400 if (!isSubTypeOf(encountered, expected)) {
401 throw new AnalyzerException(insn, "Argument " + j,
402 expected, encountered);
403 }
404 }
405 }
406 return super.naryOperation(insn, values);
407 }
408
409 @Override
410 public void returnOperation(final AbstractInsnNode insn,
411 final BasicValue value, final BasicValue expected)
412 throws AnalyzerException {
413 if (!isSubTypeOf(value, expected)) {
414 throw new AnalyzerException(insn, "Incompatible return type",
415 expected, value);
416 }
417 }
418
419 protected boolean isArrayValue(final BasicValue value) {
420 return value.isReference();
421 }
422
423 protected BasicValue getElementValue(final BasicValue objectArrayValue)
424 throws AnalyzerException {
425 return BasicValue.REFERENCE_VALUE;
426 }
427
428 protected boolean isSubTypeOf(final BasicValue value,
429 final BasicValue expected) {
430 return value.equals(expected);
431 }
330 expected1 = newValue(Type.getType("[B"));
331 }
332 expected3 = BasicValue.INT_VALUE;
333 break;
334 case CASTORE:
335 expected1 = newValue(Type.getType("[C"));
336 expected3 = BasicValue.INT_VALUE;
337 break;
338 case SASTORE:
339 expected1 = newValue(Type.getType("[S"));
340 expected3 = BasicValue.INT_VALUE;
341 break;
342 case LASTORE:
343 expected1 = newValue(Type.getType("[J"));
344 expected3 = BasicValue.LONG_VALUE;
345 break;
346 case FASTORE:
347 expected1 = newValue(Type.getType("[F"));
348 expected3 = BasicValue.FLOAT_VALUE;
349 break;
350 case DASTORE:
351 expected1 = newValue(Type.getType("[D"));
352 expected3 = BasicValue.DOUBLE_VALUE;
353 break;
354 case AASTORE:
355 expected1 = value1;
356 expected3 = BasicValue.REFERENCE_VALUE;
357 break;
358 default:
359 throw new AssertionError();
360 }
361 if (!isSubTypeOf(value1, expected1)) {
362 throw new AnalyzerException(
363 insn, "First argument", "a " + expected1 + " array reference", value1);
364 } else if (!BasicValue.INT_VALUE.equals(value2)) {
365 throw new AnalyzerException(insn, "Second argument", BasicValue.INT_VALUE, value2);
366 } else if (!isSubTypeOf(value3, expected3)) {
367 throw new AnalyzerException(insn, "Third argument", expected3, value3);
368 }
369 return null;
370 }
371
372 @Override
373 public BasicValue naryOperation(
374 final AbstractInsnNode insn, final List<? extends BasicValue> values)
375 throws AnalyzerException {
376 int opcode = insn.getOpcode();
377 if (opcode == MULTIANEWARRAY) {
378 for (int i = 0; i < values.size(); ++i) {
379 if (!BasicValue.INT_VALUE.equals(values.get(i))) {
380 throw new AnalyzerException(insn, null, BasicValue.INT_VALUE, values.get(i));
381 }
382 }
383 } else {
384 int i = 0;
385 int j = 0;
386 if (opcode != INVOKESTATIC && opcode != INVOKEDYNAMIC) {
387 Type owner = Type.getObjectType(((MethodInsnNode) insn).owner);
388 if (!isSubTypeOf(values.get(i++), newValue(owner))) {
389 throw new AnalyzerException(insn, "Method owner", newValue(owner), values.get(0));
390 }
391 }
392 String methodDescriptor =
393 (opcode == INVOKEDYNAMIC)
394 ? ((InvokeDynamicInsnNode) insn).desc
395 : ((MethodInsnNode) insn).desc;
396 Type[] args = Type.getArgumentTypes(methodDescriptor);
397 while (i < values.size()) {
398 BasicValue expected = newValue(args[j++]);
399 BasicValue actual = values.get(i++);
400 if (!isSubTypeOf(actual, expected)) {
401 throw new AnalyzerException(insn, "Argument " + j, expected, actual);
402 }
403 }
404 }
405 return super.naryOperation(insn, values);
406 }
407
408 @Override
409 public void returnOperation(
410 final AbstractInsnNode insn, final BasicValue value, final BasicValue expected)
411 throws AnalyzerException {
412 if (!isSubTypeOf(value, expected)) {
413 throw new AnalyzerException(insn, "Incompatible return type", expected, value);
414 }
415 }
416
417 /**
418 * Returns whether the given value corresponds to an array reference.
419 *
420 * @param value a value.
421 * @return whether 'value' corresponds to an array reference.
422 */
423 protected boolean isArrayValue(final BasicValue value) {
424 return value.isReference();
425 }
426
427 /**
428 * Returns the value corresponding to the type of the elements of the given array reference value.
429 *
430 * @param objectArrayValue a value corresponding to array of object (or array) references.
431 * @return the value corresponding to the type of the elements of 'objectArrayValue'.
432 * @throws AnalyzerException if objectArrayValue does not correspond to an array type.
433 */
434 protected BasicValue getElementValue(final BasicValue objectArrayValue) throws AnalyzerException {
435 return BasicValue.REFERENCE_VALUE;
436 }
437
438 /**
439 * Returns whether the type corresponding to the first argument is a subtype of the type
440 * corresponding to the second argument.
441 *
442 * @param value a value.
443 * @param expected another value.
444 * @return whether the type corresponding to 'value' is a subtype of the type corresponding to
445 * 'expected'.
446 */
447 protected boolean isSubTypeOf(final BasicValue value, final BasicValue expected) {
448 return value.equals(expected);
449 }
432450 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.tree.analysis;
3028
3129 import java.util.ArrayList;
4139 import org.eclipse.persistence.internal.libraries.asm.tree.VarInsnNode;
4240
4341 /**
44 * A symbolic execution stack frame. A stack frame contains a set of local
45 * variable slots, and an operand stack. Warning: long and double values are
46 * represented by <i>two</i> slots in local variables, and by <i>one</i> slot in
47 * the operand stack.
48 *
49 * @param <V>
50 * type of the Value used for the analysis.
51 *
42 * A symbolic execution stack frame. A stack frame contains a set of local variable slots, and an
43 * operand stack. Warning: long and double values are represented with <i>two</i> slots in local
44 * variables, and with <i>one</i> slot in the operand stack.
45 *
46 * @param <V> type of the Value used for the analysis.
5247 * @author Eric Bruneton
5348 */
5449 public class Frame<V extends Value> {
5550
56 /**
57 * The expected return type of the analyzed method, or <tt>null</tt> if the
58 * method returns void.
59 */
60 private V returnValue;
61
62 /**
63 * The local variables and operand stack of this frame.
64 */
65 private V[] values;
66
67 /**
68 * The number of local variables of this frame.
69 */
70 private int locals;
71
72 /**
73 * The number of elements in the operand stack.
74 */
75 private int top;
76
77 /**
78 * Constructs a new frame with the given size.
79 *
80 * @param nLocals
81 * the maximum number of local variables of the frame.
82 * @param nStack
83 * the maximum stack size of the frame.
84 */
85 @SuppressWarnings("unchecked")
86 public Frame(final int nLocals, final int nStack) {
87 this.values = (V[]) new Value[nLocals + nStack];
88 this.locals = nLocals;
89 }
90
91 /**
92 * Constructs a new frame that is identical to the given frame.
93 *
94 * @param src
95 * a frame.
96 */
97 public Frame(final Frame<? extends V> src) {
98 this(src.locals, src.values.length - src.locals);
99 init(src);
100 }
101
102 /**
103 * Copies the state of the given frame into this frame.
104 *
105 * @param src
106 * a frame.
107 * @return this frame.
108 */
109 public Frame<V> init(final Frame<? extends V> src) {
110 returnValue = src.returnValue;
111 System.arraycopy(src.values, 0, values, 0, values.length);
112 top = src.top;
113 return this;
114 }
115
116 /**
117 * Sets the expected return type of the analyzed method.
118 *
119 * @param v
120 * the expected return type of the analyzed method, or
121 * <tt>null</tt> if the method returns void.
122 */
123 public void setReturn(final V v) {
124 returnValue = v;
125 }
126
127 /**
128 * Returns the maximum number of local variables of this frame.
129 *
130 * @return the maximum number of local variables of this frame.
131 */
132 public int getLocals() {
133 return locals;
134 }
135
136 /**
137 * Returns the maximum stack size of this frame.
138 *
139 * @return the maximum stack size of this frame.
140 */
141 public int getMaxStackSize() {
142 return values.length - locals;
143 }
144
145 /**
146 * Returns the value of the given local variable.
147 *
148 * @param i
149 * a local variable index.
150 * @return the value of the given local variable.
151 * @throws IndexOutOfBoundsException
152 * if the variable does not exist.
153 */
154 public V getLocal(final int i) throws IndexOutOfBoundsException {
155 if (i >= locals) {
156 throw new IndexOutOfBoundsException(
157 "Trying to access an inexistant local variable");
158 }
159 return values[i];
160 }
161
162 /**
163 * Sets the value of the given local variable.
164 *
165 * @param i
166 * a local variable index.
167 * @param value
168 * the new value of this local variable.
169 * @throws IndexOutOfBoundsException
170 * if the variable does not exist.
171 */
172 public void setLocal(final int i, final V value)
173 throws IndexOutOfBoundsException {
174 if (i >= locals) {
175 throw new IndexOutOfBoundsException(
176 "Trying to access an inexistant local variable " + i);
177 }
178 values[i] = value;
179 }
180
181 /**
182 * Returns the number of values in the operand stack of this frame. Long and
183 * double values are treated as single values.
184 *
185 * @return the number of values in the operand stack of this frame.
186 */
187 public int getStackSize() {
188 return top;
189 }
190
191 /**
192 * Returns the value of the given operand stack slot.
193 *
194 * @param i
195 * the index of an operand stack slot.
196 * @return the value of the given operand stack slot.
197 * @throws IndexOutOfBoundsException
198 * if the operand stack slot does not exist.
199 */
200 public V getStack(final int i) throws IndexOutOfBoundsException {
201 return values[i + locals];
202 }
203
204 /**
205 * Clears the operand stack of this frame.
206 */
207 public void clearStack() {
208 top = 0;
209 }
210
211 /**
212 * Pops a value from the operand stack of this frame.
213 *
214 * @return the value that has been popped from the stack.
215 * @throws IndexOutOfBoundsException
216 * if the operand stack is empty.
217 */
218 public V pop() throws IndexOutOfBoundsException {
219 if (top == 0) {
220 throw new IndexOutOfBoundsException(
221 "Cannot pop operand off an empty stack.");
222 }
223 return values[--top + locals];
224 }
225
226 /**
227 * Pushes a value into the operand stack of this frame.
228 *
229 * @param value
230 * the value that must be pushed into the stack.
231 * @throws IndexOutOfBoundsException
232 * if the operand stack is full.
233 */
234 public void push(final V value) throws IndexOutOfBoundsException {
235 if (top + locals >= values.length) {
236 throw new IndexOutOfBoundsException(
237 "Insufficient maximum stack size.");
238 }
239 values[top++ + locals] = value;
240 }
241
242 public void execute(final AbstractInsnNode insn,
243 final Interpreter<V> interpreter) throws AnalyzerException {
244 V value1, value2, value3, value4;
245 List<V> values;
246 int var;
247
248 switch (insn.getOpcode()) {
249 case Opcodes.NOP:
250 break;
251 case Opcodes.ACONST_NULL:
252 case Opcodes.ICONST_M1:
253 case Opcodes.ICONST_0:
254 case Opcodes.ICONST_1:
255 case Opcodes.ICONST_2:
256 case Opcodes.ICONST_3:
257 case Opcodes.ICONST_4:
258 case Opcodes.ICONST_5:
259 case Opcodes.LCONST_0:
260 case Opcodes.LCONST_1:
261 case Opcodes.FCONST_0:
262 case Opcodes.FCONST_1:
263 case Opcodes.FCONST_2:
264 case Opcodes.DCONST_0:
265 case Opcodes.DCONST_1:
266 case Opcodes.BIPUSH:
267 case Opcodes.SIPUSH:
268 case Opcodes.LDC:
269 push(interpreter.newOperation(insn));
270 break;
271 case Opcodes.ILOAD:
272 case Opcodes.LLOAD:
273 case Opcodes.FLOAD:
274 case Opcodes.DLOAD:
275 case Opcodes.ALOAD:
276 push(interpreter.copyOperation(insn,
277 getLocal(((VarInsnNode) insn).var)));
278 break;
279 case Opcodes.IALOAD:
280 case Opcodes.LALOAD:
281 case Opcodes.FALOAD:
282 case Opcodes.DALOAD:
283 case Opcodes.AALOAD:
284 case Opcodes.BALOAD:
285 case Opcodes.CALOAD:
286 case Opcodes.SALOAD:
287 value2 = pop();
288 value1 = pop();
289 push(interpreter.binaryOperation(insn, value1, value2));
290 break;
291 case Opcodes.ISTORE:
292 case Opcodes.LSTORE:
293 case Opcodes.FSTORE:
294 case Opcodes.DSTORE:
295 case Opcodes.ASTORE:
296 value1 = interpreter.copyOperation(insn, pop());
297 var = ((VarInsnNode) insn).var;
298 setLocal(var, value1);
299 if (value1.getSize() == 2) {
300 setLocal(var + 1, interpreter.newValue(null));
51 /**
52 * The expected return type of the analyzed method, or <tt>null</tt> if the method returns void.
53 */
54 private V returnValue;
55
56 /**
57 * The local variables and the operand stack of this frame. The first {@link #nLocals} elements
58 * correspond to the local variables. The following {@link #nStack} elements correspond to the
59 * operand stack.
60 */
61 private V[] values;
62
63 /** The number of local variables of this frame. */
64 private int nLocals;
65
66 /** The number of elements in the operand stack. */
67 private int nStack;
68
69 /**
70 * Constructs a new frame with the given size.
71 *
72 * @param nLocals the maximum number of local variables of the frame.
73 * @param nStack the maximum stack size of the frame.
74 */
75 @SuppressWarnings("unchecked")
76 public Frame(final int nLocals, final int nStack) {
77 this.values = (V[]) new Value[nLocals + nStack];
78 this.nLocals = nLocals;
79 }
80
81 /**
82 * Constructs a copy of the given.
83 *
84 * @param frame a frame.
85 */
86 public Frame(final Frame<? extends V> frame) {
87 this(frame.nLocals, frame.values.length - frame.nLocals);
88 init(frame);
89 }
90
91 /**
92 * Copies the state of the given frame into this frame.
93 *
94 * @param frame a frame.
95 * @return this frame.
96 */
97 public Frame<V> init(final Frame<? extends V> frame) {
98 returnValue = frame.returnValue;
99 System.arraycopy(frame.values, 0, values, 0, values.length);
100 nStack = frame.nStack;
101 return this;
102 }
103
104 /**
105 * Sets the expected return type of the analyzed method.
106 *
107 * @param v the expected return type of the analyzed method, or <tt>null</tt> if the method
108 * returns void.
109 */
110 public void setReturn(final V v) {
111 returnValue = v;
112 }
113
114 /**
115 * Returns the maximum number of local variables of this frame.
116 *
117 * @return the maximum number of local variables of this frame.
118 */
119 public int getLocals() {
120 return nLocals;
121 }
122
123 /**
124 * Returns the maximum stack size of this frame.
125 *
126 * @return the maximum stack size of this frame.
127 */
128 public int getMaxStackSize() {
129 return values.length - nLocals;
130 }
131
132 /**
133 * Returns the value of the given local variable.
134 *
135 * @param index a local variable index.
136 * @return the value of the given local variable.
137 * @throws IndexOutOfBoundsException if the variable does not exist.
138 */
139 public V getLocal(final int index) {
140 if (index >= nLocals) {
141 throw new IndexOutOfBoundsException("Trying to access an inexistant local variable");
142 }
143 return values[index];
144 }
145
146 /**
147 * Sets the value of the given local variable.
148 *
149 * @param index a local variable index.
150 * @param value the new value of this local variable.
151 * @throws IndexOutOfBoundsException if the variable does not exist.
152 */
153 public void setLocal(final int index, final V value) {
154 if (index >= nLocals) {
155 throw new IndexOutOfBoundsException("Trying to access an inexistant local variable " + index);
156 }
157 values[index] = value;
158 }
159
160 /**
161 * Returns the number of values in the operand stack of this frame. Long and double values are
162 * treated as single values.
163 *
164 * @return the number of values in the operand stack of this frame.
165 */
166 public int getStackSize() {
167 return nStack;
168 }
169
170 /**
171 * Returns the value of the given operand stack slot.
172 *
173 * @param index the index of an operand stack slot.
174 * @return the value of the given operand stack slot.
175 * @throws IndexOutOfBoundsException if the operand stack slot does not exist.
176 */
177 public V getStack(final int index) {
178 return values[nLocals + index];
179 }
180
181 /** Clears the operand stack of this frame. */
182 public void clearStack() {
183 nStack = 0;
184 }
185
186 /**
187 * Pops a value from the operand stack of this frame.
188 *
189 * @return the value that has been popped from the stack.
190 * @throws IndexOutOfBoundsException if the operand stack is empty.
191 */
192 public V pop() {
193 if (nStack == 0) {
194 throw new IndexOutOfBoundsException("Cannot pop operand off an empty stack.");
195 }
196 return values[nLocals + (--nStack)];
197 }
198
199 /**
200 * Pushes a value into the operand stack of this frame.
201 *
202 * @param value the value that must be pushed into the stack.
203 * @throws IndexOutOfBoundsException if the operand stack is full.
204 */
205 public void push(final V value) {
206 if (nLocals + nStack >= values.length) {
207 throw new IndexOutOfBoundsException("Insufficient maximum stack size.");
208 }
209 values[nLocals + (nStack++)] = value;
210 }
211
212 /**
213 * Simulates the execution of the given instruction on this execution stack frame.
214 *
215 * @param insn the instruction to execute.
216 * @param interpreter the interpreter to use to compute values from other values.
217 * @throws AnalyzerException if the instruction cannot be executed on this execution frame (e.g. a
218 * POP on an empty operand stack).
219 */
220 public void execute(final AbstractInsnNode insn, final Interpreter<V> interpreter)
221 throws AnalyzerException {
222 V value1;
223 V value2;
224 V value3;
225 V value4;
226 int var;
227
228 switch (insn.getOpcode()) {
229 case Opcodes.NOP:
230 break;
231 case Opcodes.ACONST_NULL:
232 case Opcodes.ICONST_M1:
233 case Opcodes.ICONST_0:
234 case Opcodes.ICONST_1:
235 case Opcodes.ICONST_2:
236 case Opcodes.ICONST_3:
237 case Opcodes.ICONST_4:
238 case Opcodes.ICONST_5:
239 case Opcodes.LCONST_0:
240 case Opcodes.LCONST_1:
241 case Opcodes.FCONST_0:
242 case Opcodes.FCONST_1:
243 case Opcodes.FCONST_2:
244 case Opcodes.DCONST_0:
245 case Opcodes.DCONST_1:
246 case Opcodes.BIPUSH:
247 case Opcodes.SIPUSH:
248 case Opcodes.LDC:
249 push(interpreter.newOperation(insn));
250 break;
251 case Opcodes.ILOAD:
252 case Opcodes.LLOAD:
253 case Opcodes.FLOAD:
254 case Opcodes.DLOAD:
255 case Opcodes.ALOAD:
256 push(interpreter.copyOperation(insn, getLocal(((VarInsnNode) insn).var)));
257 break;
258 case Opcodes.ISTORE:
259 case Opcodes.LSTORE:
260 case Opcodes.FSTORE:
261 case Opcodes.DSTORE:
262 case Opcodes.ASTORE:
263 value1 = interpreter.copyOperation(insn, pop());
264 var = ((VarInsnNode) insn).var;
265 setLocal(var, value1);
266 if (value1.getSize() == 2) {
267 setLocal(var + 1, interpreter.newValue(null));
268 }
269 if (var > 0) {
270 Value local = getLocal(var - 1);
271 if (local != null && local.getSize() == 2) {
272 setLocal(var - 1, interpreter.newValue(null));
273 }
274 }
275 break;
276 case Opcodes.IASTORE:
277 case Opcodes.LASTORE:
278 case Opcodes.FASTORE:
279 case Opcodes.DASTORE:
280 case Opcodes.AASTORE:
281 case Opcodes.BASTORE:
282 case Opcodes.CASTORE:
283 case Opcodes.SASTORE:
284 value3 = pop();
285 value2 = pop();
286 value1 = pop();
287 interpreter.ternaryOperation(insn, value1, value2, value3);
288 break;
289 case Opcodes.POP:
290 if (pop().getSize() == 2) {
291 throw new AnalyzerException(insn, "Illegal use of POP");
292 }
293 break;
294 case Opcodes.POP2:
295 if (pop().getSize() == 1 && pop().getSize() != 1) {
296 throw new AnalyzerException(insn, "Illegal use of POP2");
297 }
298 break;
299 case Opcodes.DUP:
300 value1 = pop();
301 if (value1.getSize() != 1) {
302 throw new AnalyzerException(insn, "Illegal use of DUP");
303 }
304 push(value1);
305 push(interpreter.copyOperation(insn, value1));
306 break;
307 case Opcodes.DUP_X1:
308 value1 = pop();
309 value2 = pop();
310 if (value1.getSize() != 1 || value2.getSize() != 1) {
311 throw new AnalyzerException(insn, "Illegal use of DUP_X1");
312 }
313 push(interpreter.copyOperation(insn, value1));
314 push(value2);
315 push(value1);
316 break;
317 case Opcodes.DUP_X2:
318 value1 = pop();
319 if (value1.getSize() == 1) {
320 value2 = pop();
321 if (value2.getSize() == 1) {
322 value3 = pop();
323 if (value3.getSize() == 1) {
324 push(interpreter.copyOperation(insn, value1));
325 push(value3);
326 push(value2);
327 push(value1);
328 break;
301329 }
302 if (var > 0) {
303 Value local = getLocal(var - 1);
304 if (local != null && local.getSize() == 2) {
305 setLocal(var - 1, interpreter.newValue(null));
306 }
307 }
308 break;
309 case Opcodes.IASTORE:
310 case Opcodes.LASTORE:
311 case Opcodes.FASTORE:
312 case Opcodes.DASTORE:
313 case Opcodes.AASTORE:
314 case Opcodes.BASTORE:
315 case Opcodes.CASTORE:
316 case Opcodes.SASTORE:
317 value3 = pop();
318 value2 = pop();
319 value1 = pop();
320 interpreter.ternaryOperation(insn, value1, value2, value3);
321 break;
322 case Opcodes.POP:
323 if (pop().getSize() == 2) {
324 throw new AnalyzerException(insn, "Illegal use of POP");
325 }
326 break;
327 case Opcodes.POP2:
328 if (pop().getSize() == 1) {
329 if (pop().getSize() != 1) {
330 throw new AnalyzerException(insn, "Illegal use of POP2");
331 }
332 }
333 break;
334 case Opcodes.DUP:
335 value1 = pop();
336 if (value1.getSize() != 1) {
337 throw new AnalyzerException(insn, "Illegal use of DUP");
338 }
339 push(value1);
340 push(interpreter.copyOperation(insn, value1));
341 break;
342 case Opcodes.DUP_X1:
343 value1 = pop();
344 value2 = pop();
345 if (value1.getSize() != 1 || value2.getSize() != 1) {
346 throw new AnalyzerException(insn, "Illegal use of DUP_X1");
347 }
330 } else {
348331 push(interpreter.copyOperation(insn, value1));
349332 push(value2);
350333 push(value1);
351334 break;
352 case Opcodes.DUP_X2:
353 value1 = pop();
354 if (value1.getSize() == 1) {
355 value2 = pop();
356 if (value2.getSize() == 1) {
357 value3 = pop();
358 if (value3.getSize() == 1) {
359 push(interpreter.copyOperation(insn, value1));
360 push(value3);
361 push(value2);
362 push(value1);
363 break;
364 }
365 } else {
366 push(interpreter.copyOperation(insn, value1));
367 push(value2);
368 push(value1);
369 break;
370 }
371 }
372 throw new AnalyzerException(insn, "Illegal use of DUP_X2");
373 case Opcodes.DUP2:
374 value1 = pop();
375 if (value1.getSize() == 1) {
376 value2 = pop();
377 if (value2.getSize() == 1) {
378 push(value2);
379 push(value1);
380 push(interpreter.copyOperation(insn, value2));
381 push(interpreter.copyOperation(insn, value1));
382 break;
383 }
384 } else {
385 push(value1);
386 push(interpreter.copyOperation(insn, value1));
387 break;
388 }
389 throw new AnalyzerException(insn, "Illegal use of DUP2");
390 case Opcodes.DUP2_X1:
391 value1 = pop();
392 if (value1.getSize() == 1) {
393 value2 = pop();
394 if (value2.getSize() == 1) {
395 value3 = pop();
396 if (value3.getSize() == 1) {
397 push(interpreter.copyOperation(insn, value2));
398 push(interpreter.copyOperation(insn, value1));
399 push(value3);
400 push(value2);
401 push(value1);
402 break;
403 }
404 }
405 } else {
406 value2 = pop();
407 if (value2.getSize() == 1) {
408 push(interpreter.copyOperation(insn, value1));
409 push(value2);
410 push(value1);
411 break;
412 }
413 }
414 throw new AnalyzerException(insn, "Illegal use of DUP2_X1");
415 case Opcodes.DUP2_X2:
416 value1 = pop();
417 if (value1.getSize() == 1) {
418 value2 = pop();
419 if (value2.getSize() == 1) {
420 value3 = pop();
421 if (value3.getSize() == 1) {
422 value4 = pop();
423 if (value4.getSize() == 1) {
424 push(interpreter.copyOperation(insn, value2));
425 push(interpreter.copyOperation(insn, value1));
426 push(value4);
427 push(value3);
428 push(value2);
429 push(value1);
430 break;
431 }
432 } else {
433 push(interpreter.copyOperation(insn, value2));
434 push(interpreter.copyOperation(insn, value1));
435 push(value3);
436 push(value2);
437 push(value1);
438 break;
439 }
440 }
441 } else {
442 value2 = pop();
443 if (value2.getSize() == 1) {
444 value3 = pop();
445 if (value3.getSize() == 1) {
446 push(interpreter.copyOperation(insn, value1));
447 push(value3);
448 push(value2);
449 push(value1);
450 break;
451 }
452 } else {
453 push(interpreter.copyOperation(insn, value1));
454 push(value2);
455 push(value1);
456 break;
457 }
458 }
459 throw new AnalyzerException(insn, "Illegal use of DUP2_X2");
460 case Opcodes.SWAP:
461 value2 = pop();
462 value1 = pop();
463 if (value1.getSize() != 1 || value2.getSize() != 1) {
464 throw new AnalyzerException(insn, "Illegal use of SWAP");
465 }
335 }
336 }
337 throw new AnalyzerException(insn, "Illegal use of DUP_X2");
338 case Opcodes.DUP2:
339 value1 = pop();
340 if (value1.getSize() == 1) {
341 value2 = pop();
342 if (value2.getSize() == 1) {
343 push(value2);
344 push(value1);
466345 push(interpreter.copyOperation(insn, value2));
467346 push(interpreter.copyOperation(insn, value1));
468347 break;
469 case Opcodes.IADD:
470 case Opcodes.LADD:
471 case Opcodes.FADD:
472 case Opcodes.DADD:
473 case Opcodes.ISUB:
474 case Opcodes.LSUB:
475 case Opcodes.FSUB:
476 case Opcodes.DSUB:
477 case Opcodes.IMUL:
478 case Opcodes.LMUL:
479 case Opcodes.FMUL:
480 case Opcodes.DMUL:
481 case Opcodes.IDIV:
482 case Opcodes.LDIV:
483 case Opcodes.FDIV:
484 case Opcodes.DDIV:
485 case Opcodes.IREM:
486 case Opcodes.LREM:
487 case Opcodes.FREM:
488 case Opcodes.DREM:
489 value2 = pop();
490 value1 = pop();
491 push(interpreter.binaryOperation(insn, value1, value2));
348 }
349 } else {
350 push(value1);
351 push(interpreter.copyOperation(insn, value1));
352 break;
353 }
354 throw new AnalyzerException(insn, "Illegal use of DUP2");
355 case Opcodes.DUP2_X1:
356 value1 = pop();
357 if (value1.getSize() == 1) {
358 value2 = pop();
359 if (value2.getSize() == 1) {
360 value3 = pop();
361 if (value3.getSize() == 1) {
362 push(interpreter.copyOperation(insn, value2));
363 push(interpreter.copyOperation(insn, value1));
364 push(value3);
365 push(value2);
366 push(value1);
367 break;
368 }
369 }
370 } else {
371 value2 = pop();
372 if (value2.getSize() == 1) {
373 push(interpreter.copyOperation(insn, value1));
374 push(value2);
375 push(value1);
492376 break;
493 case Opcodes.INEG:
494 case Opcodes.LNEG:
495 case Opcodes.FNEG:
496 case Opcodes.DNEG:
497 push(interpreter.unaryOperation(insn, pop()));
377 }
378 }
379 throw new AnalyzerException(insn, "Illegal use of DUP2_X1");
380 case Opcodes.DUP2_X2:
381 value1 = pop();
382 if (value1.getSize() == 1) {
383 value2 = pop();
384 if (value2.getSize() == 1) {
385 value3 = pop();
386 if (value3.getSize() == 1) {
387 value4 = pop();
388 if (value4.getSize() == 1) {
389 push(interpreter.copyOperation(insn, value2));
390 push(interpreter.copyOperation(insn, value1));
391 push(value4);
392 push(value3);
393 push(value2);
394 push(value1);
395 break;
396 }
397 } else {
398 push(interpreter.copyOperation(insn, value2));
399 push(interpreter.copyOperation(insn, value1));
400 push(value3);
401 push(value2);
402 push(value1);
403 break;
404 }
405 }
406 } else {
407 value2 = pop();
408 if (value2.getSize() == 1) {
409 value3 = pop();
410 if (value3.getSize() == 1) {
411 push(interpreter.copyOperation(insn, value1));
412 push(value3);
413 push(value2);
414 push(value1);
415 break;
416 }
417 } else {
418 push(interpreter.copyOperation(insn, value1));
419 push(value2);
420 push(value1);
498421 break;
499 case Opcodes.ISHL:
500 case Opcodes.LSHL:
501 case Opcodes.ISHR:
502 case Opcodes.LSHR:
503 case Opcodes.IUSHR:
504 case Opcodes.LUSHR:
505 case Opcodes.IAND:
506 case Opcodes.LAND:
507 case Opcodes.IOR:
508 case Opcodes.LOR:
509 case Opcodes.IXOR:
510 case Opcodes.LXOR:
511 value2 = pop();
512 value1 = pop();
513 push(interpreter.binaryOperation(insn, value1, value2));
514 break;
515 case Opcodes.IINC:
516 var = ((IincInsnNode) insn).var;
517 setLocal(var, interpreter.unaryOperation(insn, getLocal(var)));
518 break;
519 case Opcodes.I2L:
520 case Opcodes.I2F:
521 case Opcodes.I2D:
522 case Opcodes.L2I:
523 case Opcodes.L2F:
524 case Opcodes.L2D:
525 case Opcodes.F2I:
526 case Opcodes.F2L:
527 case Opcodes.F2D:
528 case Opcodes.D2I:
529 case Opcodes.D2L:
530 case Opcodes.D2F:
531 case Opcodes.I2B:
532 case Opcodes.I2C:
533 case Opcodes.I2S:
534 push(interpreter.unaryOperation(insn, pop()));
535 break;
536 case Opcodes.LCMP:
537 case Opcodes.FCMPL:
538 case Opcodes.FCMPG:
539 case Opcodes.DCMPL:
540 case Opcodes.DCMPG:
541 value2 = pop();
542 value1 = pop();
543 push(interpreter.binaryOperation(insn, value1, value2));
544 break;
545 case Opcodes.IFEQ:
546 case Opcodes.IFNE:
547 case Opcodes.IFLT:
548 case Opcodes.IFGE:
549 case Opcodes.IFGT:
550 case Opcodes.IFLE:
551 interpreter.unaryOperation(insn, pop());
552 break;
553 case Opcodes.IF_ICMPEQ:
554 case Opcodes.IF_ICMPNE:
555 case Opcodes.IF_ICMPLT:
556 case Opcodes.IF_ICMPGE:
557 case Opcodes.IF_ICMPGT:
558 case Opcodes.IF_ICMPLE:
559 case Opcodes.IF_ACMPEQ:
560 case Opcodes.IF_ACMPNE:
561 value2 = pop();
562 value1 = pop();
563 interpreter.binaryOperation(insn, value1, value2);
564 break;
565 case Opcodes.GOTO:
566 break;
567 case Opcodes.JSR:
568 push(interpreter.newOperation(insn));
569 break;
570 case Opcodes.RET:
571 break;
572 case Opcodes.TABLESWITCH:
573 case Opcodes.LOOKUPSWITCH:
574 interpreter.unaryOperation(insn, pop());
575 break;
576 case Opcodes.IRETURN:
577 case Opcodes.LRETURN:
578 case Opcodes.FRETURN:
579 case Opcodes.DRETURN:
580 case Opcodes.ARETURN:
581 value1 = pop();
582 interpreter.unaryOperation(insn, value1);
583 interpreter.returnOperation(insn, value1, returnValue);
584 break;
585 case Opcodes.RETURN:
586 if (returnValue != null) {
587 throw new AnalyzerException(insn, "Incompatible return type");
588 }
589 break;
590 case Opcodes.GETSTATIC:
591 push(interpreter.newOperation(insn));
592 break;
593 case Opcodes.PUTSTATIC:
594 interpreter.unaryOperation(insn, pop());
595 break;
596 case Opcodes.GETFIELD:
597 push(interpreter.unaryOperation(insn, pop()));
598 break;
599 case Opcodes.PUTFIELD:
600 value2 = pop();
601 value1 = pop();
602 interpreter.binaryOperation(insn, value1, value2);
603 break;
604 case Opcodes.INVOKEVIRTUAL:
605 case Opcodes.INVOKESPECIAL:
606 case Opcodes.INVOKESTATIC:
607 case Opcodes.INVOKEINTERFACE: {
608 values = new ArrayList<V>();
609 String desc = ((MethodInsnNode) insn).desc;
610 for (int i = Type.getArgumentTypes(desc).length; i > 0; --i) {
611 values.add(0, pop());
612 }
613 if (insn.getOpcode() != Opcodes.INVOKESTATIC) {
614 values.add(0, pop());
615 }
616 if (Type.getReturnType(desc) == Type.VOID_TYPE) {
617 interpreter.naryOperation(insn, values);
618 } else {
619 push(interpreter.naryOperation(insn, values));
620 }
621 break;
622 }
623 case Opcodes.INVOKEDYNAMIC: {
624 values = new ArrayList<V>();
625 String desc = ((InvokeDynamicInsnNode) insn).desc;
626 for (int i = Type.getArgumentTypes(desc).length; i > 0; --i) {
627 values.add(0, pop());
628 }
629 if (Type.getReturnType(desc) == Type.VOID_TYPE) {
630 interpreter.naryOperation(insn, values);
631 } else {
632 push(interpreter.naryOperation(insn, values));
633 }
634 break;
635 }
636 case Opcodes.NEW:
637 push(interpreter.newOperation(insn));
638 break;
639 case Opcodes.NEWARRAY:
640 case Opcodes.ANEWARRAY:
641 case Opcodes.ARRAYLENGTH:
642 push(interpreter.unaryOperation(insn, pop()));
643 break;
644 case Opcodes.ATHROW:
645 interpreter.unaryOperation(insn, pop());
646 break;
647 case Opcodes.CHECKCAST:
648 case Opcodes.INSTANCEOF:
649 push(interpreter.unaryOperation(insn, pop()));
650 break;
651 case Opcodes.MONITORENTER:
652 case Opcodes.MONITOREXIT:
653 interpreter.unaryOperation(insn, pop());
654 break;
655 case Opcodes.MULTIANEWARRAY:
656 values = new ArrayList<V>();
657 for (int i = ((MultiANewArrayInsnNode) insn).dims; i > 0; --i) {
658 values.add(0, pop());
659 }
660 push(interpreter.naryOperation(insn, values));
661 break;
662 case Opcodes.IFNULL:
663 case Opcodes.IFNONNULL:
664 interpreter.unaryOperation(insn, pop());
665 break;
666 default:
667 throw new RuntimeException("Illegal opcode " + insn.getOpcode());
668 }
669 }
670
671 /**
672 * Merges this frame with the given frame.
673 *
674 * @param frame
675 * a frame.
676 * @param interpreter
677 * the interpreter used to merge values.
678 * @return <tt>true</tt> if this frame has been changed as a result of the
679 * merge operation, or <tt>false</tt> otherwise.
680 * @throws AnalyzerException
681 * if the frames have incompatible sizes.
682 */
683 public boolean merge(final Frame<? extends V> frame,
684 final Interpreter<V> interpreter) throws AnalyzerException {
685 if (top != frame.top) {
686 throw new AnalyzerException(null, "Incompatible stack heights");
687 }
688 boolean changes = false;
689 for (int i = 0; i < locals + top; ++i) {
690 V v = interpreter.merge(values[i], frame.values[i]);
691 if (!v.equals(values[i])) {
692 values[i] = v;
693 changes = true;
694 }
695 }
696 return changes;
697 }
698
699 /**
700 * Merges this frame with the given frame (case of a RET instruction).
701 *
702 * @param frame
703 * a frame
704 * @param access
705 * the local variables that have been accessed by the subroutine
706 * to which the RET instruction corresponds.
707 * @return <tt>true</tt> if this frame has been changed as a result of the
708 * merge operation, or <tt>false</tt> otherwise.
709 */
710 public boolean merge(final Frame<? extends V> frame, final boolean[] access) {
711 boolean changes = false;
712 for (int i = 0; i < locals; ++i) {
713 if (!access[i] && !values[i].equals(frame.values[i])) {
714 values[i] = frame.values[i];
715 changes = true;
716 }
717 }
718 return changes;
719 }
720
721 /**
722 * Returns a string representation of this frame.
723 *
724 * @return a string representation of this frame.
725 */
726 @Override
727 public String toString() {
728 StringBuilder sb = new StringBuilder();
729 for (int i = 0; i < getLocals(); ++i) {
730 sb.append(getLocal(i));
731 }
732 sb.append(' ');
733 for (int i = 0; i < getStackSize(); ++i) {
734 sb.append(getStack(i).toString());
735 }
736 return sb.toString();
737 }
422 }
423 }
424 throw new AnalyzerException(insn, "Illegal use of DUP2_X2");
425 case Opcodes.SWAP:
426 value2 = pop();
427 value1 = pop();
428 if (value1.getSize() != 1 || value2.getSize() != 1) {
429 throw new AnalyzerException(insn, "Illegal use of SWAP");
430 }
431 push(interpreter.copyOperation(insn, value2));
432 push(interpreter.copyOperation(insn, value1));
433 break;
434 case Opcodes.IALOAD:
435 case Opcodes.LALOAD:
436 case Opcodes.FALOAD:
437 case Opcodes.DALOAD:
438 case Opcodes.AALOAD:
439 case Opcodes.BALOAD:
440 case Opcodes.CALOAD:
441 case Opcodes.SALOAD:
442 case Opcodes.IADD:
443 case Opcodes.LADD:
444 case Opcodes.FADD:
445 case Opcodes.DADD:
446 case Opcodes.ISUB:
447 case Opcodes.LSUB:
448 case Opcodes.FSUB:
449 case Opcodes.DSUB:
450 case Opcodes.IMUL:
451 case Opcodes.LMUL:
452 case Opcodes.FMUL:
453 case Opcodes.DMUL:
454 case Opcodes.IDIV:
455 case Opcodes.LDIV:
456 case Opcodes.FDIV:
457 case Opcodes.DDIV:
458 case Opcodes.IREM:
459 case Opcodes.LREM:
460 case Opcodes.FREM:
461 case Opcodes.DREM:
462 case Opcodes.ISHL:
463 case Opcodes.LSHL:
464 case Opcodes.ISHR:
465 case Opcodes.LSHR:
466 case Opcodes.IUSHR:
467 case Opcodes.LUSHR:
468 case Opcodes.IAND:
469 case Opcodes.LAND:
470 case Opcodes.IOR:
471 case Opcodes.LOR:
472 case Opcodes.IXOR:
473 case Opcodes.LXOR:
474 case Opcodes.LCMP:
475 case Opcodes.FCMPL:
476 case Opcodes.FCMPG:
477 case Opcodes.DCMPL:
478 case Opcodes.DCMPG:
479 value2 = pop();
480 value1 = pop();
481 push(interpreter.binaryOperation(insn, value1, value2));
482 break;
483 case Opcodes.INEG:
484 case Opcodes.LNEG:
485 case Opcodes.FNEG:
486 case Opcodes.DNEG:
487 push(interpreter.unaryOperation(insn, pop()));
488 break;
489 case Opcodes.IINC:
490 var = ((IincInsnNode) insn).var;
491 setLocal(var, interpreter.unaryOperation(insn, getLocal(var)));
492 break;
493 case Opcodes.I2L:
494 case Opcodes.I2F:
495 case Opcodes.I2D:
496 case Opcodes.L2I:
497 case Opcodes.L2F:
498 case Opcodes.L2D:
499 case Opcodes.F2I:
500 case Opcodes.F2L:
501 case Opcodes.F2D:
502 case Opcodes.D2I:
503 case Opcodes.D2L:
504 case Opcodes.D2F:
505 case Opcodes.I2B:
506 case Opcodes.I2C:
507 case Opcodes.I2S:
508 push(interpreter.unaryOperation(insn, pop()));
509 break;
510 case Opcodes.IFEQ:
511 case Opcodes.IFNE:
512 case Opcodes.IFLT:
513 case Opcodes.IFGE:
514 case Opcodes.IFGT:
515 case Opcodes.IFLE:
516 interpreter.unaryOperation(insn, pop());
517 break;
518 case Opcodes.IF_ICMPEQ:
519 case Opcodes.IF_ICMPNE:
520 case Opcodes.IF_ICMPLT:
521 case Opcodes.IF_ICMPGE:
522 case Opcodes.IF_ICMPGT:
523 case Opcodes.IF_ICMPLE:
524 case Opcodes.IF_ACMPEQ:
525 case Opcodes.IF_ACMPNE:
526 case Opcodes.PUTFIELD:
527 value2 = pop();
528 value1 = pop();
529 interpreter.binaryOperation(insn, value1, value2);
530 break;
531 case Opcodes.GOTO:
532 break;
533 case Opcodes.JSR:
534 push(interpreter.newOperation(insn));
535 break;
536 case Opcodes.RET:
537 break;
538 case Opcodes.TABLESWITCH:
539 case Opcodes.LOOKUPSWITCH:
540 interpreter.unaryOperation(insn, pop());
541 break;
542 case Opcodes.IRETURN:
543 case Opcodes.LRETURN:
544 case Opcodes.FRETURN:
545 case Opcodes.DRETURN:
546 case Opcodes.ARETURN:
547 value1 = pop();
548 interpreter.unaryOperation(insn, value1);
549 interpreter.returnOperation(insn, value1, returnValue);
550 break;
551 case Opcodes.RETURN:
552 if (returnValue != null) {
553 throw new AnalyzerException(insn, "Incompatible return type");
554 }
555 break;
556 case Opcodes.GETSTATIC:
557 push(interpreter.newOperation(insn));
558 break;
559 case Opcodes.PUTSTATIC:
560 interpreter.unaryOperation(insn, pop());
561 break;
562 case Opcodes.GETFIELD:
563 push(interpreter.unaryOperation(insn, pop()));
564 break;
565 case Opcodes.INVOKEVIRTUAL:
566 case Opcodes.INVOKESPECIAL:
567 case Opcodes.INVOKESTATIC:
568 case Opcodes.INVOKEINTERFACE:
569 {
570 List<V> valueList = new ArrayList<V>();
571 String methodDescriptor = ((MethodInsnNode) insn).desc;
572 for (int i = Type.getArgumentTypes(methodDescriptor).length; i > 0; --i) {
573 valueList.add(0, pop());
574 }
575 if (insn.getOpcode() != Opcodes.INVOKESTATIC) {
576 valueList.add(0, pop());
577 }
578 if (Type.getReturnType(methodDescriptor) == Type.VOID_TYPE) {
579 interpreter.naryOperation(insn, valueList);
580 } else {
581 push(interpreter.naryOperation(insn, valueList));
582 }
583 break;
584 }
585 case Opcodes.INVOKEDYNAMIC:
586 {
587 List<V> valueList = new ArrayList<V>();
588 String methodDesccriptor = ((InvokeDynamicInsnNode) insn).desc;
589 for (int i = Type.getArgumentTypes(methodDesccriptor).length; i > 0; --i) {
590 valueList.add(0, pop());
591 }
592 if (Type.getReturnType(methodDesccriptor) == Type.VOID_TYPE) {
593 interpreter.naryOperation(insn, valueList);
594 } else {
595 push(interpreter.naryOperation(insn, valueList));
596 }
597 break;
598 }
599 case Opcodes.NEW:
600 push(interpreter.newOperation(insn));
601 break;
602 case Opcodes.NEWARRAY:
603 case Opcodes.ANEWARRAY:
604 case Opcodes.ARRAYLENGTH:
605 push(interpreter.unaryOperation(insn, pop()));
606 break;
607 case Opcodes.ATHROW:
608 interpreter.unaryOperation(insn, pop());
609 break;
610 case Opcodes.CHECKCAST:
611 case Opcodes.INSTANCEOF:
612 push(interpreter.unaryOperation(insn, pop()));
613 break;
614 case Opcodes.MONITORENTER:
615 case Opcodes.MONITOREXIT:
616 interpreter.unaryOperation(insn, pop());
617 break;
618 case Opcodes.MULTIANEWARRAY:
619 List<V> valueList = new ArrayList<V>();
620 for (int i = ((MultiANewArrayInsnNode) insn).dims; i > 0; --i) {
621 valueList.add(0, pop());
622 }
623 push(interpreter.naryOperation(insn, valueList));
624 break;
625 case Opcodes.IFNULL:
626 case Opcodes.IFNONNULL:
627 interpreter.unaryOperation(insn, pop());
628 break;
629 default:
630 throw new AnalyzerException(insn, "Illegal opcode " + insn.getOpcode());
631 }
632 }
633
634 /**
635 * Merges the given frame into this frame.
636 *
637 * @param frame a frame. This frame is left unchanged by this method.
638 * @param interpreter the interpreter used to merge values.
639 * @return <tt>true</tt> if this frame has been changed as a result of the merge operation, or
640 * <tt>false</tt> otherwise.
641 * @throws AnalyzerException if the frames have incompatible sizes.
642 */
643 public boolean merge(final Frame<? extends V> frame, final Interpreter<V> interpreter)
644 throws AnalyzerException {
645 if (nStack != frame.nStack) {
646 throw new AnalyzerException(null, "Incompatible stack heights");
647 }
648 boolean changed = false;
649 for (int i = 0; i < nLocals + nStack; ++i) {
650 V v = interpreter.merge(values[i], frame.values[i]);
651 if (!v.equals(values[i])) {
652 values[i] = v;
653 changed = true;
654 }
655 }
656 return changed;
657 }
658
659 /**
660 * Merges the given frame into this frame (case of a subroutine). The operand stacks are not
661 * merged, and only the local variables that have not been used by the subroutine are merged.
662 *
663 * @param frame a frame. This frame is left unchanged by this method.
664 * @param localsUsed the local variables that are read or written by the subroutine. The i-th
665 * element is true if and only if the local variable at index i is read or written by the
666 * subroutine.
667 * @return <tt>true</tt> if this frame has been changed as a result of the merge operation, or
668 * <tt>false</tt> otherwise.
669 */
670 public boolean merge(final Frame<? extends V> frame, final boolean[] localsUsed) {
671 boolean changed = false;
672 for (int i = 0; i < nLocals; ++i) {
673 if (!localsUsed[i] && !values[i].equals(frame.values[i])) {
674 values[i] = frame.values[i];
675 changed = true;
676 }
677 }
678 return changed;
679 }
680
681 /**
682 * Returns a string representation of this frame.
683 *
684 * @return a string representation of this frame.
685 */
686 @Override
687 public String toString() {
688 StringBuilder stringBuilder = new StringBuilder();
689 for (int i = 0; i < getLocals(); ++i) {
690 stringBuilder.append(getLocal(i));
691 }
692 stringBuilder.append(' ');
693 for (int i = 0; i < getStackSize(); ++i) {
694 stringBuilder.append(getStack(i).toString());
695 }
696 return stringBuilder.toString();
697 }
738698 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.tree.analysis;
3028
3129 import java.util.List;
3432 import org.eclipse.persistence.internal.libraries.asm.tree.AbstractInsnNode;
3533
3634 /**
37 * A semantic bytecode interpreter. More precisely, this interpreter only
38 * manages the computation of values from other values: it does not manage the
39 * transfer of values to or from the stack, and to or from the local variables.
40 * This separation allows a generic bytecode {@link Analyzer} to work with
41 * various semantic interpreters, without needing to duplicate the code to
42 * simulate the transfer of values.
43 *
44 * @param <V>
45 * type of the Value used for the analysis.
46 *
35 * A semantic bytecode interpreter. More precisely, this interpreter only manages the computation of
36 * values from other values: it does not manage the transfer of values to or from the stack, and to
37 * or from the local variables. This separation allows a generic bytecode {@link Analyzer} to work
38 * with various semantic interpreters, without needing to duplicate the code to simulate the
39 * transfer of values.
40 *
41 * @param <V> type of the Value used for the analysis.
4742 * @author Eric Bruneton
4843 */
4944 public abstract class Interpreter<V extends Value> {
5045
51 protected final int api;
46 /**
47 * The ASM API version supported by this interpreter. The value of this field must be one of
48 * {@link org.eclipse.persistence.internal.libraries.asm.Opcodes#ASM4}, {@link org.eclipse.persistence.internal.libraries.asm.Opcodes#ASM5} or {@link
49 * org.eclipse.persistence.internal.libraries.asm.Opcodes#ASM6}.
50 */
51 protected final int api;
5252
53 protected Interpreter(final int api) {
54 this.api = api;
55 }
53 /**
54 * Constructs a new {@link Interpreter}.
55 *
56 * @param api the ASM API version supported by this interpreter. Must be one of {@link
57 * org.eclipse.persistence.internal.libraries.asm.Opcodes#ASM4}, {@link org.eclipse.persistence.internal.libraries.asm.Opcodes#ASM5} or {@link
58 * org.eclipse.persistence.internal.libraries.asm.Opcodes#ASM6}.
59 */
60 protected Interpreter(final int api) {
61 this.api = api;
62 }
5663
57 /**
58 * Creates a new value that represents the given type.
59 *
60 * Called for method parameters (including <code>this</code>), exception
61 * handler variable and with <code>null</code> type for variables reserved
62 * by long and double types.
63 *
64 * @param type
65 * a primitive or reference type, or <tt>null</tt> to represent
66 * an uninitialized value.
67 * @return a value that represents the given type. The size of the returned
68 * value must be equal to the size of the given type.
69 */
70 public abstract V newValue(Type type);
64 /**
65 * Creates a new value that represents the given type.
66 *
67 * <p>Called for method parameters (including <code>this</code>), exception handler variable and
68 * with <code>null</code> type for variables reserved by long and double types.
69 *
70 * @param type a primitive or reference type, or <tt>null</tt> to represent an uninitialized
71 * value.
72 * @return a value that represents the given type. The size of the returned value must be equal to
73 * the size of the given type.
74 */
75 public abstract V newValue(Type type);
7176
72 /**
73 * Interprets a bytecode instruction without arguments. This method is
74 * called for the following opcodes:
75 *
76 * ACONST_NULL, ICONST_M1, ICONST_0, ICONST_1, ICONST_2, ICONST_3, ICONST_4,
77 * ICONST_5, LCONST_0, LCONST_1, FCONST_0, FCONST_1, FCONST_2, DCONST_0,
78 * DCONST_1, BIPUSH, SIPUSH, LDC, JSR, GETSTATIC, NEW
79 *
80 * @param insn
81 * the bytecode instruction to be interpreted.
82 * @return the result of the interpretation of the given instruction.
83 * @throws AnalyzerException
84 * if an error occured during the interpretation.
85 */
86 public abstract V newOperation(AbstractInsnNode insn)
87 throws AnalyzerException;
77 /**
78 * Interprets a bytecode instruction without arguments. This method is called for the following
79 * opcodes:
80 *
81 * <p>ACONST_NULL, ICONST_M1, ICONST_0, ICONST_1, ICONST_2, ICONST_3, ICONST_4, ICONST_5,
82 * LCONST_0, LCONST_1, FCONST_0, FCONST_1, FCONST_2, DCONST_0, DCONST_1, BIPUSH, SIPUSH, LDC, JSR,
83 * GETSTATIC, NEW
84 *
85 * @param insn the bytecode instruction to be interpreted.
86 * @return the result of the interpretation of the given instruction.
87 * @throws AnalyzerException if an error occured during the interpretation.
88 */
89 public abstract V newOperation(AbstractInsnNode insn) throws AnalyzerException;
8890
89 /**
90 * Interprets a bytecode instruction that moves a value on the stack or to
91 * or from local variables. This method is called for the following opcodes:
92 *
93 * ILOAD, LLOAD, FLOAD, DLOAD, ALOAD, ISTORE, LSTORE, FSTORE, DSTORE,
94 * ASTORE, DUP, DUP_X1, DUP_X2, DUP2, DUP2_X1, DUP2_X2, SWAP
95 *
96 * @param insn
97 * the bytecode instruction to be interpreted.
98 * @param value
99 * the value that must be moved by the instruction.
100 * @return the result of the interpretation of the given instruction. The
101 * returned value must be <tt>equal</tt> to the given value.
102 * @throws AnalyzerException
103 * if an error occured during the interpretation.
104 */
105 public abstract V copyOperation(AbstractInsnNode insn, V value)
106 throws AnalyzerException;
91 /**
92 * Interprets a bytecode instruction that moves a value on the stack or to or from local
93 * variables. This method is called for the following opcodes:
94 *
95 * <p>ILOAD, LLOAD, FLOAD, DLOAD, ALOAD, ISTORE, LSTORE, FSTORE, DSTORE, ASTORE, DUP, DUP_X1,
96 * DUP_X2, DUP2, DUP2_X1, DUP2_X2, SWAP
97 *
98 * @param insn the bytecode instruction to be interpreted.
99 * @param value the value that must be moved by the instruction.
100 * @return the result of the interpretation of the given instruction. The returned value must be
101 * <tt>equal</tt> to the given value.
102 * @throws AnalyzerException if an error occured during the interpretation.
103 */
104 public abstract V copyOperation(AbstractInsnNode insn, V value) throws AnalyzerException;
107105
108 /**
109 * Interprets a bytecode instruction with a single argument. This method is
110 * called for the following opcodes:
111 *
112 * INEG, LNEG, FNEG, DNEG, IINC, I2L, I2F, I2D, L2I, L2F, L2D, F2I, F2L,
113 * F2D, D2I, D2L, D2F, I2B, I2C, I2S, IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE,
114 * TABLESWITCH, LOOKUPSWITCH, IRETURN, LRETURN, FRETURN, DRETURN, ARETURN,
115 * PUTSTATIC, GETFIELD, NEWARRAY, ANEWARRAY, ARRAYLENGTH, ATHROW, CHECKCAST,
116 * INSTANCEOF, MONITORENTER, MONITOREXIT, IFNULL, IFNONNULL
117 *
118 * @param insn
119 * the bytecode instruction to be interpreted.
120 * @param value
121 * the argument of the instruction to be interpreted.
122 * @return the result of the interpretation of the given instruction.
123 * @throws AnalyzerException
124 * if an error occured during the interpretation.
125 */
126 public abstract V unaryOperation(AbstractInsnNode insn, V value)
127 throws AnalyzerException;
106 /**
107 * Interprets a bytecode instruction with a single argument. This method is called for the
108 * following opcodes:
109 *
110 * <p>INEG, LNEG, FNEG, DNEG, IINC, I2L, I2F, I2D, L2I, L2F, L2D, F2I, F2L, F2D, D2I, D2L, D2F,
111 * I2B, I2C, I2S, IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, TABLESWITCH, LOOKUPSWITCH, IRETURN, LRETURN,
112 * FRETURN, DRETURN, ARETURN, PUTSTATIC, GETFIELD, NEWARRAY, ANEWARRAY, ARRAYLENGTH, ATHROW,
113 * CHECKCAST, INSTANCEOF, MONITORENTER, MONITOREXIT, IFNULL, IFNONNULL
114 *
115 * @param insn the bytecode instruction to be interpreted.
116 * @param value the argument of the instruction to be interpreted.
117 * @return the result of the interpretation of the given instruction.
118 * @throws AnalyzerException if an error occured during the interpretation.
119 */
120 public abstract V unaryOperation(AbstractInsnNode insn, V value) throws AnalyzerException;
128121
129 /**
130 * Interprets a bytecode instruction with two arguments. This method is
131 * called for the following opcodes:
132 *
133 * IALOAD, LALOAD, FALOAD, DALOAD, AALOAD, BALOAD, CALOAD, SALOAD, IADD,
134 * LADD, FADD, DADD, ISUB, LSUB, FSUB, DSUB, IMUL, LMUL, FMUL, DMUL, IDIV,
135 * LDIV, FDIV, DDIV, IREM, LREM, FREM, DREM, ISHL, LSHL, ISHR, LSHR, IUSHR,
136 * LUSHR, IAND, LAND, IOR, LOR, IXOR, LXOR, LCMP, FCMPL, FCMPG, DCMPL,
137 * DCMPG, IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE,
138 * IF_ACMPEQ, IF_ACMPNE, PUTFIELD
139 *
140 * @param insn
141 * the bytecode instruction to be interpreted.
142 * @param value1
143 * the first argument of the instruction to be interpreted.
144 * @param value2
145 * the second argument of the instruction to be interpreted.
146 * @return the result of the interpretation of the given instruction.
147 * @throws AnalyzerException
148 * if an error occured during the interpretation.
149 */
150 public abstract V binaryOperation(AbstractInsnNode insn, V value1, V value2)
151 throws AnalyzerException;
122 /**
123 * Interprets a bytecode instruction with two arguments. This method is called for the following
124 * opcodes:
125 *
126 * <p>IALOAD, LALOAD, FALOAD, DALOAD, AALOAD, BALOAD, CALOAD, SALOAD, IADD, LADD, FADD, DADD,
127 * ISUB, LSUB, FSUB, DSUB, IMUL, LMUL, FMUL, DMUL, IDIV, LDIV, FDIV, DDIV, IREM, LREM, FREM, DREM,
128 * ISHL, LSHL, ISHR, LSHR, IUSHR, LUSHR, IAND, LAND, IOR, LOR, IXOR, LXOR, LCMP, FCMPL, FCMPG,
129 * DCMPL, DCMPG, IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, IF_ACMPEQ,
130 * IF_ACMPNE, PUTFIELD
131 *
132 * @param insn the bytecode instruction to be interpreted.
133 * @param value1 the first argument of the instruction to be interpreted.
134 * @param value2 the second argument of the instruction to be interpreted.
135 * @return the result of the interpretation of the given instruction.
136 * @throws AnalyzerException if an error occured during the interpretation.
137 */
138 public abstract V binaryOperation(AbstractInsnNode insn, V value1, V value2)
139 throws AnalyzerException;
152140
153 /**
154 * Interprets a bytecode instruction with three arguments. This method is
155 * called for the following opcodes:
156 *
157 * IASTORE, LASTORE, FASTORE, DASTORE, AASTORE, BASTORE, CASTORE, SASTORE
158 *
159 * @param insn
160 * the bytecode instruction to be interpreted.
161 * @param value1
162 * the first argument of the instruction to be interpreted.
163 * @param value2
164 * the second argument of the instruction to be interpreted.
165 * @param value3
166 * the third argument of the instruction to be interpreted.
167 * @return the result of the interpretation of the given instruction.
168 * @throws AnalyzerException
169 * if an error occured during the interpretation.
170 */
171 public abstract V ternaryOperation(AbstractInsnNode insn, V value1,
172 V value2, V value3) throws AnalyzerException;
141 /**
142 * Interprets a bytecode instruction with three arguments. This method is called for the following
143 * opcodes:
144 *
145 * <p>IASTORE, LASTORE, FASTORE, DASTORE, AASTORE, BASTORE, CASTORE, SASTORE
146 *
147 * @param insn the bytecode instruction to be interpreted.
148 * @param value1 the first argument of the instruction to be interpreted.
149 * @param value2 the second argument of the instruction to be interpreted.
150 * @param value3 the third argument of the instruction to be interpreted.
151 * @return the result of the interpretation of the given instruction.
152 * @throws AnalyzerException if an error occured during the interpretation.
153 */
154 public abstract V ternaryOperation(AbstractInsnNode insn, V value1, V value2, V value3)
155 throws AnalyzerException;
173156
174 /**
175 * Interprets a bytecode instruction with a variable number of arguments.
176 * This method is called for the following opcodes:
177 *
178 * INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC, INVOKEINTERFACE,
179 * MULTIANEWARRAY and INVOKEDYNAMIC
180 *
181 * @param insn
182 * the bytecode instruction to be interpreted.
183 * @param values
184 * the arguments of the instruction to be interpreted.
185 * @return the result of the interpretation of the given instruction.
186 * @throws AnalyzerException
187 * if an error occured during the interpretation.
188 */
189 public abstract V naryOperation(AbstractInsnNode insn,
190 List<? extends V> values) throws AnalyzerException;
157 /**
158 * Interprets a bytecode instruction with a variable number of arguments. This method is called
159 * for the following opcodes:
160 *
161 * <p>INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC, INVOKEINTERFACE, MULTIANEWARRAY and
162 * INVOKEDYNAMIC
163 *
164 * @param insn the bytecode instruction to be interpreted.
165 * @param values the arguments of the instruction to be interpreted.
166 * @return the result of the interpretation of the given instruction.
167 * @throws AnalyzerException if an error occured during the interpretation.
168 */
169 public abstract V naryOperation(AbstractInsnNode insn, List<? extends V> values)
170 throws AnalyzerException;
191171
192 /**
193 * Interprets a bytecode return instruction. This method is called for the
194 * following opcodes:
195 *
196 * IRETURN, LRETURN, FRETURN, DRETURN, ARETURN
197 *
198 * @param insn
199 * the bytecode instruction to be interpreted.
200 * @param value
201 * the argument of the instruction to be interpreted.
202 * @param expected
203 * the expected return type of the analyzed method.
204 * @throws AnalyzerException
205 * if an error occured during the interpretation.
206 */
207 public abstract void returnOperation(AbstractInsnNode insn, V value,
208 V expected) throws AnalyzerException;
172 /**
173 * Interprets a bytecode return instruction. This method is called for the following opcodes:
174 *
175 * <p>IRETURN, LRETURN, FRETURN, DRETURN, ARETURN
176 *
177 * @param insn the bytecode instruction to be interpreted.
178 * @param value the argument of the instruction to be interpreted.
179 * @param expected the expected return type of the analyzed method.
180 * @throws AnalyzerException if an error occured during the interpretation.
181 */
182 public abstract void returnOperation(AbstractInsnNode insn, V value, V expected)
183 throws AnalyzerException;
209184
210 /**
211 * Merges two values. The merge operation must return a value that
212 * represents both values (for instance, if the two values are two types,
213 * the merged value must be a common super type of the two types. If the two
214 * values are integer intervals, the merged value must be an interval that
215 * contains the previous ones. Likewise for other types of values).
216 *
217 * @param v
218 * a value.
219 * @param w
220 * another value.
221 * @return the merged value. If the merged value is equal to <tt>v</tt>,
222 * this method <i>must</i> return <tt>v</tt>.
223 */
224 public abstract V merge(V v, V w);
185 /**
186 * Merges two values. The merge operation must return a value that represents both values (for
187 * instance, if the two values are two types, the merged value must be a common super type of the
188 * two types. If the two values are integer intervals, the merged value must be an interval that
189 * contains the previous ones. Likewise for other types of values).
190 *
191 * @param value1 a value.
192 * @param value2 another value.
193 * @return the merged value. If the merged value is equal to <tt>value1</tt>, this method
194 * <i>must</i> return <tt>value1</tt>.
195 */
196 public abstract V merge(V value1, V value2);
225197 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
27 package org.eclipse.persistence.internal.libraries.asm.tree.analysis;
28
29 import java.util.List;
30
31 import org.eclipse.persistence.internal.libraries.asm.Type;
32
33 /**
34 * An extended {@link BasicVerifier} that performs more precise verifications. This verifier
35 * computes exact class types, instead of using a single "object reference" type (as done in {@link
36 * BasicVerifier}).
437 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 package org.eclipse.persistence.internal.libraries.asm.tree.analysis;
30
31 import java.util.List;
32
33 import org.eclipse.persistence.internal.libraries.asm.Type;
34
35 /**
36 * An extended {@link BasicVerifier} that performs more precise verifications.
37 * This verifier computes exact class types, instead of using a single "object
38 * reference" type (as done in the {@link BasicVerifier}).
39 *
4038 * @author Eric Bruneton
4139 * @author Bing Ran
4240 */
4341 public class SimpleVerifier extends BasicVerifier {
4442
45 /**
46 * The class that is verified.
47 */
48 private final Type currentClass;
49
50 /**
51 * The super class of the class that is verified.
52 */
53 private final Type currentSuperClass;
54
55 /**
56 * The interfaces implemented by the class that is verified.
57 */
58 private final List<Type> currentClassInterfaces;
59
60 /**
61 * If the class that is verified is an interface.
62 */
63 private final boolean isInterface;
64
65 /**
66 * The loader to use for referenced classes.
67 */
68 private ClassLoader loader = getClass().getClassLoader();
69
70 /**
71 * Constructs a new {@link SimpleVerifier}.
72 */
73 public SimpleVerifier() {
74 this(null, null, false);
75 }
76
77 /**
78 * Constructs a new {@link SimpleVerifier} to verify a specific class. This
79 * class will not be loaded into the JVM since it may be incorrect.
80 *
81 * @param currentClass
82 * the class that is verified.
83 * @param currentSuperClass
84 * the super class of the class that is verified.
85 * @param isInterface
86 * if the class that is verified is an interface.
87 */
88 public SimpleVerifier(final Type currentClass,
89 final Type currentSuperClass, final boolean isInterface) {
90 this(currentClass, currentSuperClass, null, isInterface);
91 }
92
93 /**
94 * Constructs a new {@link SimpleVerifier} to verify a specific class. This
95 * class will not be loaded into the JVM since it may be incorrect.
96 *
97 * @param currentClass
98 * the class that is verified.
99 * @param currentSuperClass
100 * the super class of the class that is verified.
101 * @param currentClassInterfaces
102 * the interfaces implemented by the class that is verified.
103 * @param isInterface
104 * if the class that is verified is an interface.
105 */
106 public SimpleVerifier(final Type currentClass,
107 final Type currentSuperClass,
108 final List<Type> currentClassInterfaces, final boolean isInterface) {
109 this(ASM6, currentClass, currentSuperClass, currentClassInterfaces,
110 isInterface);
111 }
112
113 protected SimpleVerifier(final int api, final Type currentClass,
114 final Type currentSuperClass,
115 final List<Type> currentClassInterfaces, final boolean isInterface) {
116 super(api);
117 this.currentClass = currentClass;
118 this.currentSuperClass = currentSuperClass;
119 this.currentClassInterfaces = currentClassInterfaces;
120 this.isInterface = isInterface;
121 }
122
123 /**
124 * Set the <code>ClassLoader</code> which will be used to load referenced
125 * classes. This is useful if you are verifying multiple interdependent
126 * classes.
127 *
128 * @param loader
129 * a <code>ClassLoader</code> to use
130 */
131 public void setClassLoader(final ClassLoader loader) {
132 this.loader = loader;
133 }
134
135 @Override
136 public BasicValue newValue(final Type type) {
137 if (type == null) {
138 return BasicValue.UNINITIALIZED_VALUE;
139 }
140
141 boolean isArray = type.getSort() == Type.ARRAY;
142 if (isArray) {
143 switch (type.getElementType().getSort()) {
144 case Type.BOOLEAN:
145 case Type.CHAR:
146 case Type.BYTE:
147 case Type.SHORT:
148 return new BasicValue(type);
149 }
150 }
151
152 BasicValue v = super.newValue(type);
153 if (BasicValue.REFERENCE_VALUE.equals(v)) {
154 if (isArray) {
155 v = newValue(type.getElementType());
156 String desc = v.getType().getDescriptor();
157 for (int i = 0; i < type.getDimensions(); ++i) {
158 desc = '[' + desc;
159 }
160 v = new BasicValue(Type.getType(desc));
161 } else {
162 v = new BasicValue(type);
163 }
164 }
165 return v;
166 }
167
168 @Override
169 protected boolean isArrayValue(final BasicValue value) {
170 Type t = value.getType();
171 return t != null
172 && ("Lnull;".equals(t.getDescriptor()) || t.getSort() == Type.ARRAY);
173 }
174
175 @Override
176 protected BasicValue getElementValue(final BasicValue objectArrayValue)
177 throws AnalyzerException {
178 Type arrayType = objectArrayValue.getType();
179 if (arrayType != null) {
180 if (arrayType.getSort() == Type.ARRAY) {
181 return newValue(Type.getType(arrayType.getDescriptor()
182 .substring(1)));
183 } else if ("Lnull;".equals(arrayType.getDescriptor())) {
184 return objectArrayValue;
185 }
186 }
187 throw new Error("Internal error");
188 }
189
190 @Override
191 protected boolean isSubTypeOf(final BasicValue value,
192 final BasicValue expected) {
193 Type expectedType = expected.getType();
194 Type type = value.getType();
195 switch (expectedType.getSort()) {
196 case Type.INT:
197 case Type.FLOAT:
198 case Type.LONG:
199 case Type.DOUBLE:
200 return type.equals(expectedType);
201 case Type.ARRAY:
202 case Type.OBJECT:
203 if ("Lnull;".equals(type.getDescriptor())) {
204 return true;
205 } else if (type.getSort() == Type.OBJECT
206 || type.getSort() == Type.ARRAY) {
207 return isAssignableFrom(expectedType, type);
208 } else {
209 return false;
210 }
43 /** The type of the class that is verified. */
44 private final Type currentClass;
45
46 /** The type of the super class of the class that is verified. */
47 private final Type currentSuperClass;
48
49 /** The types of the interfaces directly implemented by the class that is verified. */
50 private final List<Type> currentClassInterfaces;
51
52 /** Whether the class that is verified is an interface. */
53 private final boolean isInterface;
54
55 /** The loader to use to load the referenced classes. */
56 private ClassLoader loader = getClass().getClassLoader();
57
58 /**
59 * Constructs a new {@link SimpleVerifier}. <i>Subclasses must not use this constructor</i>.
60 * Instead, they must use the {@link #SimpleVerifier(int, Type, Type, List, boolean)} version.
61 */
62 public SimpleVerifier() {
63 this(null, null, false);
64 }
65
66 /**
67 * Constructs a new {@link SimpleVerifier} to verify a specific class. This class will not be
68 * loaded into the JVM since it may be incorrect. <i>Subclasses must not use this constructor</i>.
69 * Instead, they must use the {@link #SimpleVerifier(int, Type, Type, List, boolean)} version.
70 *
71 * @param currentClass the type of the class to be verified.
72 * @param currentSuperClass the type of the super class of the class to be verified.
73 * @param isInterface whether the class to be verifier is an interface.
74 */
75 public SimpleVerifier(
76 final Type currentClass, final Type currentSuperClass, final boolean isInterface) {
77 this(currentClass, currentSuperClass, null, isInterface);
78 }
79
80 /**
81 * Constructs a new {@link SimpleVerifier} to verify a specific class. This class will not be
82 * loaded into the JVM since it may be incorrect. <i>Subclasses must not use this constructor</i>.
83 * Instead, they must use the {@link #SimpleVerifier(int, Type, Type, List, boolean)} version.
84 *
85 * @param currentClass the type of the class to be verified.
86 * @param currentSuperClass the type of the super class of the class to be verified.
87 * @param currentClassInterfaces the types of the interfaces directly implemented by the class to
88 * be verified.
89 * @param isInterface whether the class to be verifier is an interface.
90 */
91 public SimpleVerifier(
92 final Type currentClass,
93 final Type currentSuperClass,
94 final List<Type> currentClassInterfaces,
95 final boolean isInterface) {
96 this(ASM6, currentClass, currentSuperClass, currentClassInterfaces, isInterface);
97 if (getClass() != SimpleVerifier.class) {
98 throw new IllegalStateException();
99 }
100 }
101
102 /**
103 * Constructs a new {@link SimpleVerifier} to verify a specific class. This class will not be
104 * loaded into the JVM since it may be incorrect.
105 *
106 * @param api the ASM API version supported by this verifier. Must be one of {@link
107 * org.eclipse.persistence.internal.libraries.asm.Opcodes#ASM4}, {@link org.eclipse.persistence.internal.libraries.asm.Opcodes#ASM5} or {@link
108 * org.eclipse.persistence.internal.libraries.asm.Opcodes#ASM6}.
109 * @param currentClass the type of the class to be verified.
110 * @param currentSuperClass the type of the super class of the class to be verified.
111 * @param currentClassInterfaces the types of the interfaces directly implemented by the class to
112 * be verified.
113 * @param isInterface whether the class to be verifier is an interface.
114 */
115 protected SimpleVerifier(
116 final int api,
117 final Type currentClass,
118 final Type currentSuperClass,
119 final List<Type> currentClassInterfaces,
120 final boolean isInterface) {
121 super(api);
122 this.currentClass = currentClass;
123 this.currentSuperClass = currentSuperClass;
124 this.currentClassInterfaces = currentClassInterfaces;
125 this.isInterface = isInterface;
126 }
127
128 /**
129 * Sets the <code>ClassLoader</code> to be used in {@link #getClass}.
130 *
131 * @param loader the <code>ClassLoader</code> to use.
132 */
133 public void setClassLoader(final ClassLoader loader) {
134 this.loader = loader;
135 }
136
137 @Override
138 public BasicValue newValue(final Type type) {
139 if (type == null) {
140 return BasicValue.UNINITIALIZED_VALUE;
141 }
142
143 boolean isArray = type.getSort() == Type.ARRAY;
144 if (isArray) {
145 switch (type.getElementType().getSort()) {
146 case Type.BOOLEAN:
147 case Type.CHAR:
148 case Type.BYTE:
149 case Type.SHORT:
150 return new BasicValue(type);
211151 default:
212 throw new Error("Internal error");
213 }
214 }
215
216 @Override
217 public BasicValue merge(final BasicValue v, final BasicValue w) {
218 if (!v.equals(w)) {
219 Type t = v.getType();
220 Type u = w.getType();
221 if (t != null
222 && (t.getSort() == Type.OBJECT || t.getSort() == Type.ARRAY)) {
223 if (u != null
224 && (u.getSort() == Type.OBJECT || u.getSort() == Type.ARRAY)) {
225 if ("Lnull;".equals(t.getDescriptor())) {
226 return w;
227 }
228 if ("Lnull;".equals(u.getDescriptor())) {
229 return v;
230 }
231 if (isAssignableFrom(t, u)) {
232 return v;
233 }
234 if (isAssignableFrom(u, t)) {
235 return w;
236 }
237 // TODO case of array classes of the same dimension
238 // TODO should we look also for a common super interface?
239 // problem: there may be several possible common super
240 // interfaces
241 do {
242 if (t == null || isInterface(t)) {
243 return BasicValue.REFERENCE_VALUE;
244 }
245 t = getSuperClass(t);
246 if (isAssignableFrom(t, u)) {
247 return newValue(t);
248 }
249 } while (true);
250 }
251 }
252 return BasicValue.UNINITIALIZED_VALUE;
253 }
254 return v;
255 }
256
257 protected boolean isInterface(final Type t) {
258 if (currentClass != null && t.equals(currentClass)) {
259 return isInterface;
260 }
261 return getClass(t).isInterface();
262 }
263
264 protected Type getSuperClass(final Type t) {
265 if (currentClass != null && t.equals(currentClass)) {
266 return currentSuperClass;
267 }
268 Class<?> c = getClass(t).getSuperclass();
269 return c == null ? null : Type.getType(c);
270 }
271
272 protected boolean isAssignableFrom(final Type t, final Type u) {
273 if (t.equals(u)) {
152 break;
153 }
154 }
155
156 BasicValue value = super.newValue(type);
157 if (BasicValue.REFERENCE_VALUE.equals(value)) {
158 if (isArray) {
159 value = newValue(type.getElementType());
160 StringBuilder descriptor = new StringBuilder();
161 for (int i = 0; i < type.getDimensions(); ++i) {
162 descriptor.append('[');
163 }
164 descriptor.append(value.getType().getDescriptor());
165 value = new BasicValue(Type.getType(descriptor.toString()));
166 } else {
167 value = new BasicValue(type);
168 }
169 }
170 return value;
171 }
172
173 @Override
174 protected boolean isArrayValue(final BasicValue value) {
175 Type type = value.getType();
176 return type != null && (type.getSort() == Type.ARRAY || type.equals(NULL_TYPE));
177 }
178
179 @Override
180 protected BasicValue getElementValue(final BasicValue objectArrayValue) throws AnalyzerException {
181 Type arrayType = objectArrayValue.getType();
182 if (arrayType != null) {
183 if (arrayType.getSort() == Type.ARRAY) {
184 return newValue(Type.getType(arrayType.getDescriptor().substring(1)));
185 } else if (arrayType.equals(NULL_TYPE)) {
186 return objectArrayValue;
187 }
188 }
189 throw new AssertionError();
190 }
191
192 @Override
193 protected boolean isSubTypeOf(final BasicValue value, final BasicValue expected) {
194 Type expectedType = expected.getType();
195 Type type = value.getType();
196 switch (expectedType.getSort()) {
197 case Type.INT:
198 case Type.FLOAT:
199 case Type.LONG:
200 case Type.DOUBLE:
201 return type.equals(expectedType);
202 case Type.ARRAY:
203 case Type.OBJECT:
204 if (type.equals(NULL_TYPE)) {
205 return true;
206 } else if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
207 return isAssignableFrom(expectedType, type);
208 } else {
209 return false;
210 }
211 default:
212 throw new AssertionError();
213 }
214 }
215
216 @Override
217 public BasicValue merge(final BasicValue value1, final BasicValue value2) {
218 if (!value1.equals(value2)) {
219 Type type1 = value1.getType();
220 Type type2 = value2.getType();
221 if (type1 != null
222 && (type1.getSort() == Type.OBJECT || type1.getSort() == Type.ARRAY)
223 && type2 != null
224 && (type2.getSort() == Type.OBJECT || type2.getSort() == Type.ARRAY)) {
225 if (type1.equals(NULL_TYPE)) {
226 return value2;
227 }
228 if (type2.equals(NULL_TYPE)) {
229 return value1;
230 }
231 if (isAssignableFrom(type1, type2)) {
232 return value1;
233 }
234 if (isAssignableFrom(type2, type1)) {
235 return value2;
236 }
237 int numDimensions = 0;
238 if (type1.getSort() == Type.ARRAY
239 && type2.getSort() == Type.ARRAY
240 && type1.getDimensions() == type2.getDimensions()
241 && type1.getElementType().getSort() == Type.OBJECT
242 && type2.getElementType().getSort() == Type.OBJECT) {
243 numDimensions = type1.getDimensions();
244 type1 = type1.getElementType();
245 type2 = type2.getElementType();
246 }
247 do {
248 if (type1 == null || isInterface(type1)) {
249 return newValue(Type.getObjectType("java/lang/Object"), numDimensions);
250 }
251 type1 = getSuperClass(type1);
252 if (isAssignableFrom(type1, type2)) {
253 return newValue(type1, numDimensions);
254 }
255 } while (true);
256 }
257 return BasicValue.UNINITIALIZED_VALUE;
258 }
259 return value1;
260 }
261
262 private BasicValue newValue(final Type type, final int dimensions) {
263 if (dimensions == 0) {
264 return newValue(type);
265 } else {
266 StringBuilder descriptor = new StringBuilder();
267 for (int i = 0; i < dimensions; ++i) {
268 descriptor.append('[');
269 }
270 descriptor.append(type.getDescriptor());
271 return newValue(Type.getType(descriptor.toString()));
272 }
273 }
274
275 /**
276 * Returns whether the given type corresponds to the type of an interface. The default
277 * implementation of this method loads the class and uses the reflection API to return its result
278 * (unless the given type corresponds to the class being verified).
279 *
280 * @param type a type.
281 * @return whether 'type' corresponds to an interface.
282 */
283 protected boolean isInterface(final Type type) {
284 if (currentClass != null && type.equals(currentClass)) {
285 return isInterface;
286 }
287 return getClass(type).isInterface();
288 }
289
290 /**
291 * Returns the type corresponding to the super class of the given type. The default implementation
292 * of this method loads the class and uses the reflection API to return its result (unless the
293 * given type corresponds to the class being verified).
294 *
295 * @param type a type.
296 * @return the type corresponding to the super class of 'type'.
297 */
298 protected Type getSuperClass(final Type type) {
299 if (currentClass != null && type.equals(currentClass)) {
300 return currentSuperClass;
301 }
302 Class<?> superClass = getClass(type).getSuperclass();
303 return superClass == null ? null : Type.getType(superClass);
304 }
305
306 /**
307 * Returns whether the class corresponding to the first argument is either the same as, or is a
308 * superclass or superinterface of the class corresponding to the second argument. The default
309 * implementation of this method loads the classes and uses the reflection API to return its
310 * result (unless the result can be computed from the class being verified, and the types of its
311 * super classes and implemented interfaces).
312 *
313 * @param type1 a type.
314 * @param type2 another type.
315 * @return whether the class corresponding to 'type1' is either the same as, or is a superclass or
316 * superinterface of the class corresponding to 'type2'.
317 */
318 protected boolean isAssignableFrom(final Type type1, final Type type2) {
319 if (type1.equals(type2)) {
320 return true;
321 }
322 if (currentClass != null && type1.equals(currentClass)) {
323 if (getSuperClass(type2) == null) {
324 return false;
325 } else {
326 if (isInterface) {
327 return type2.getSort() == Type.OBJECT || type2.getSort() == Type.ARRAY;
328 }
329 return isAssignableFrom(type1, getSuperClass(type2));
330 }
331 }
332 if (currentClass != null && type2.equals(currentClass)) {
333 if (isAssignableFrom(type1, currentSuperClass)) {
334 return true;
335 }
336 if (currentClassInterfaces != null) {
337 for (int i = 0; i < currentClassInterfaces.size(); ++i) {
338 Type currentClassInterface = currentClassInterfaces.get(i);
339 if (isAssignableFrom(type1, currentClassInterface)) {
274340 return true;
275 }
276 if (currentClass != null && t.equals(currentClass)) {
277 if (getSuperClass(u) == null) {
278 return false;
279 } else {
280 if (isInterface) {
281 return u.getSort() == Type.OBJECT
282 || u.getSort() == Type.ARRAY;
283 }
284 return isAssignableFrom(t, getSuperClass(u));
285 }
286 }
287 if (currentClass != null && u.equals(currentClass)) {
288 if (isAssignableFrom(t, currentSuperClass)) {
289 return true;
290 }
291 if (currentClassInterfaces != null) {
292 for (int i = 0; i < currentClassInterfaces.size(); ++i) {
293 Type v = currentClassInterfaces.get(i);
294 if (isAssignableFrom(t, v)) {
295 return true;
296 }
297 }
298 }
299 return false;
300 }
301 Class<?> tc = getClass(t);
302 if (tc.isInterface()) {
303 tc = Object.class;
304 }
305 return tc.isAssignableFrom(getClass(u));
306 }
307
308 protected Class<?> getClass(final Type t) {
309 try {
310 if (t.getSort() == Type.ARRAY) {
311 return Class.forName(t.getDescriptor().replace('/', '.'),
312 false, loader);
313 }
314 return Class.forName(t.getClassName(), false, loader);
315 } catch (ClassNotFoundException e) {
316 throw new RuntimeException(e.toString());
317 }
318 }
341 }
342 }
343 }
344 return false;
345 }
346 Class<?> class1 = getClass(type1);
347 if (class1.isInterface()) {
348 class1 = Object.class;
349 }
350 return class1.isAssignableFrom(getClass(type2));
351 }
352
353 /**
354 * Loads the class corresponding to the given type. The class is loaded with the class loader
355 * specified with {@link #setClassLoader}, or with the class loader of this class if no class
356 * loader was specified.
357 *
358 * @param type a type.
359 * @return the class corresponding to 'type'.
360 */
361 protected Class<?> getClass(final Type type) {
362 try {
363 if (type.getSort() == Type.ARRAY) {
364 return Class.forName(type.getDescriptor().replace('/', '.'), false, loader);
365 }
366 return Class.forName(type.getClassName(), false, loader);
367 } catch (ClassNotFoundException e) {
368 throw new TypeNotPresentException(e.toString(), e);
369 }
370 }
319371 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.tree.analysis;
3028
3129 import java.util.AbstractSet;
3533 import java.util.Set;
3634
3735 /**
38 * A set of at most two elements.
39 *
36 * An immutable set of at most two elements, optimized for speed compared to a generic set
37 * implementation.
38 *
4039 * @author Eric Bruneton
4140 */
42 class SmallSet<E> extends AbstractSet<E> implements Iterator<E> {
41 final class SmallSet<T> extends AbstractSet<T> {
4342
44 // if e1 is null, e2 must be null; otherwise e2 must be different from e1
43 /** The first element of this set, maybe <tt>null</tt>. */
44 private final T element1;
4545
46 E e1, e2;
46 /**
47 * The second element of this set, maybe <tt>null</tt>. If {@link #element1} is <tt>null</tt> then
48 * this field must be <tt>null</tt>, otherwise it must be different from {@link #element1}.
49 */
50 private final T element2;
4751
48 static final <T> Set<T> emptySet() {
49 return new SmallSet<T>(null, null);
52 // -----------------------------------------------------------------------------------------------
53 // Constructors
54 // -----------------------------------------------------------------------------------------------
55
56 /** Constructs an empty set. */
57 SmallSet() {
58 this.element1 = null;
59 this.element2 = null;
60 }
61
62 /**
63 * Constructs a set with exactly one element.
64 *
65 * @param element the unique set element.
66 */
67 SmallSet(final T element) {
68 this.element1 = element;
69 this.element2 = null;
70 }
71
72 /**
73 * Constructs a new {@link SmallSet}.
74 *
75 * @param element1 see {@link #element1}.
76 * @param element2 see {@link #element2}.
77 */
78 private SmallSet(final T element1, final T element2) {
79 this.element1 = element1;
80 this.element2 = element2;
81 }
82
83 // -----------------------------------------------------------------------------------------------
84 // Implementation of the inherited abstract methods
85 // -----------------------------------------------------------------------------------------------
86
87 @Override
88 public Iterator<T> iterator() {
89 return new IteratorImpl<T>(element1, element2);
90 }
91
92 static class IteratorImpl<T> implements Iterator<T> {
93
94 /** The next element to return in {@link #next}. Maybe <tt>null</tt>. */
95 private T firstElement;
96
97 /**
98 * The element to return in {@link #next}, after {@link #firstElement} is returned. If {@link
99 * #firstElement} is <tt>null</tt> then this field must be <tt>null</tt>, otherwise it must be
100 * different from {@link #firstElement}.
101 */
102 private T secondElement;
103
104 IteratorImpl(final T firstElement, final T secondElement) {
105 this.firstElement = firstElement;
106 this.secondElement = secondElement;
50107 }
51108
52 SmallSet(final E e1, final E e2) {
53 this.e1 = e1;
54 this.e2 = e2;
109 public boolean hasNext() {
110 return firstElement != null;
55111 }
56112
57 // -------------------------------------------------------------------------
58 // Implementation of inherited abstract methods
59 // -------------------------------------------------------------------------
60
61 @Override
62 public Iterator<E> iterator() {
63 return new SmallSet<E>(e1, e2);
113 public T next() {
114 if (firstElement == null) {
115 throw new NoSuchElementException();
116 }
117 T element = firstElement;
118 firstElement = secondElement;
119 secondElement = null;
120 return element;
64121 }
65122
66123 @Override
67 public int size() {
68 return e1 == null ? 0 : (e2 == null ? 1 : 2);
124 public void remove() {
125 throw new UnsupportedOperationException();
126 }
127 }
128
129 @Override
130 public int size() {
131 return element1 == null ? 0 : (element2 == null ? 1 : 2);
132 }
133
134 // -----------------------------------------------------------------------------------------------
135 // Utility methods
136 // -----------------------------------------------------------------------------------------------
137
138 /**
139 * Returns the union of this set and of the given set.
140 *
141 * @param otherSet another small set.
142 * @return the union of this set and of otherSet.
143 */
144 Set<T> union(final SmallSet<T> otherSet) {
145 // If the two sets are equal, return this set.
146 if ((otherSet.element1 == element1 && otherSet.element2 == element2)
147 || (otherSet.element1 == element2 && otherSet.element2 == element1)) {
148 return this;
149 }
150 // If one set is empty, return the other.
151 if (otherSet.element1 == null) {
152 return this;
153 }
154 if (element1 == null) {
155 return otherSet;
69156 }
70157
71 // -------------------------------------------------------------------------
72 // Implementation of the Iterator interface
73 // -------------------------------------------------------------------------
74
75 public boolean hasNext() {
76 return e1 != null;
158 // At this point we know that the two sets are non empty and are different.
159 // If otherSet contains exactly one element:
160 if (otherSet.element2 == null) {
161 // If this set also contains exactly one element, we have two distinct elements.
162 if (element2 == null) {
163 return new SmallSet<T>(element1, otherSet.element1);
164 }
165 // If otherSet is included in this set, return this set.
166 if (otherSet.element1 == element1 || otherSet.element1 == element2) {
167 return this;
168 }
169 }
170 // If this set contains exactly one element, then otherSet contains two elements (because of the
171 // above tests). Thus, if otherSet contains this set, return otherSet:
172 if (element2 == null && (element1 == otherSet.element1 || element1 == otherSet.element2)) {
173 return otherSet;
77174 }
78175
79 public E next() {
80 if (e1 == null) {
81 throw new NoSuchElementException();
82 }
83 E e = e1;
84 e1 = e2;
85 e2 = null;
86 return e;
176 // At this point we know that there are at least 3 distinct elements, so we need a generic set
177 // to store the result.
178 HashSet<T> result = new HashSet<T>(4);
179 result.add(element1);
180 if (element2 != null) {
181 result.add(element2);
87182 }
88
89 public void remove() {
183 result.add(otherSet.element1);
184 if (otherSet.element2 != null) {
185 result.add(otherSet.element2);
90186 }
91
92 // -------------------------------------------------------------------------
93 // Utility methods
94 // -------------------------------------------------------------------------
95
96 Set<E> union(final SmallSet<E> s) {
97 if ((s.e1 == e1 && s.e2 == e2) || (s.e1 == e2 && s.e2 == e1)) {
98 return this; // if the two sets are equal, return this
99 }
100 if (s.e1 == null) {
101 return this; // if s is empty, return this
102 }
103 if (e1 == null) {
104 return s; // if this is empty, return s
105 }
106 if (s.e2 == null) { // s contains exactly one element
107 if (e2 == null) {
108 return new SmallSet<E>(e1, s.e1); // necessarily e1 != s.e1
109 } else if (s.e1 == e1 || s.e1 == e2) { // s is included in this
110 return this;
111 }
112 }
113 if (e2 == null) { // this contains exactly one element
114 // if (s.e2 == null) { // cannot happen
115 // return new SmallSet(e1, s.e1); // necessarily e1 != s.e1
116 // } else
117 if (e1 == s.e1 || e1 == s.e2) { // this in included in s
118 return s;
119 }
120 }
121 // here we know that there are at least 3 distinct elements
122 HashSet<E> r = new HashSet<E>(4);
123 r.add(e1);
124 if (e2 != null) {
125 r.add(e2);
126 }
127 r.add(s.e1);
128 if (s.e2 != null) {
129 r.add(s.e2);
130 }
131 return r;
132 }
187 return result;
188 }
133189 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.tree.analysis;
3028
3129 import java.util.HashSet;
4240
4341 /**
4442 * An {@link Interpreter} for {@link SourceValue} values.
45 *
43 *
4644 * @author Eric Bruneton
4745 */
48 public class SourceInterpreter extends Interpreter<SourceValue> implements
49 Opcodes {
50
51 public SourceInterpreter() {
52 super(ASM6);
53 }
54
55 protected SourceInterpreter(final int api) {
56 super(api);
57 }
58
59 @Override
60 public SourceValue newValue(final Type type) {
61 if (type == Type.VOID_TYPE) {
62 return null;
63 }
64 return new SourceValue(type == null ? 1 : type.getSize());
65 }
66
67 @Override
68 public SourceValue newOperation(final AbstractInsnNode insn) {
69 int size;
70 switch (insn.getOpcode()) {
71 case LCONST_0:
72 case LCONST_1:
73 case DCONST_0:
74 case DCONST_1:
75 size = 2;
76 break;
77 case LDC:
78 Object cst = ((LdcInsnNode) insn).cst;
79 size = cst instanceof Long || cst instanceof Double ? 2 : 1;
80 break;
81 case GETSTATIC:
82 size = Type.getType(((FieldInsnNode) insn).desc).getSize();
83 break;
84 default:
85 size = 1;
86 }
87 return new SourceValue(size, insn);
88 }
89
90 @Override
91 public SourceValue copyOperation(final AbstractInsnNode insn,
92 final SourceValue value) {
93 return new SourceValue(value.getSize(), insn);
94 }
95
96 @Override
97 public SourceValue unaryOperation(final AbstractInsnNode insn,
98 final SourceValue value) {
99 int size;
100 switch (insn.getOpcode()) {
101 case LNEG:
102 case DNEG:
103 case I2L:
104 case I2D:
105 case L2D:
106 case F2L:
107 case F2D:
108 case D2L:
109 size = 2;
110 break;
111 case GETFIELD:
112 size = Type.getType(((FieldInsnNode) insn).desc).getSize();
113 break;
114 default:
115 size = 1;
116 }
117 return new SourceValue(size, insn);
118 }
119
120 @Override
121 public SourceValue binaryOperation(final AbstractInsnNode insn,
122 final SourceValue value1, final SourceValue value2) {
123 int size;
124 switch (insn.getOpcode()) {
125 case LALOAD:
126 case DALOAD:
127 case LADD:
128 case DADD:
129 case LSUB:
130 case DSUB:
131 case LMUL:
132 case DMUL:
133 case LDIV:
134 case DDIV:
135 case LREM:
136 case DREM:
137 case LSHL:
138 case LSHR:
139 case LUSHR:
140 case LAND:
141 case LOR:
142 case LXOR:
143 size = 2;
144 break;
145 default:
146 size = 1;
147 }
148 return new SourceValue(size, insn);
149 }
150
151 @Override
152 public SourceValue ternaryOperation(final AbstractInsnNode insn,
153 final SourceValue value1, final SourceValue value2,
154 final SourceValue value3) {
155 return new SourceValue(1, insn);
156 }
157
158 @Override
159 public SourceValue naryOperation(final AbstractInsnNode insn,
160 final List<? extends SourceValue> values) {
161 int size;
162 int opcode = insn.getOpcode();
163 if (opcode == MULTIANEWARRAY) {
164 size = 1;
165 } else {
166 String desc = (opcode == INVOKEDYNAMIC) ? ((InvokeDynamicInsnNode) insn).desc
167 : ((MethodInsnNode) insn).desc;
168 size = Type.getReturnType(desc).getSize();
169 }
170 return new SourceValue(size, insn);
171 }
172
173 @Override
174 public void returnOperation(final AbstractInsnNode insn,
175 final SourceValue value, final SourceValue expected) {
176 }
177
178 @Override
179 public SourceValue merge(final SourceValue d, final SourceValue w) {
180 if (d.insns instanceof SmallSet && w.insns instanceof SmallSet) {
181 Set<AbstractInsnNode> s = ((SmallSet<AbstractInsnNode>) d.insns)
182 .union((SmallSet<AbstractInsnNode>) w.insns);
183 if (s == d.insns && d.size == w.size) {
184 return d;
185 } else {
186 return new SourceValue(Math.min(d.size, w.size), s);
187 }
188 }
189 if (d.size != w.size || !d.insns.containsAll(w.insns)) {
190 HashSet<AbstractInsnNode> s = new HashSet<AbstractInsnNode>();
191 s.addAll(d.insns);
192 s.addAll(w.insns);
193 return new SourceValue(Math.min(d.size, w.size), s);
194 }
195 return d;
196 }
46 public class SourceInterpreter extends Interpreter<SourceValue> implements Opcodes {
47
48 /**
49 * Constructs a new {@link SourceInterpreter} for the latest ASM API version. <i>Subclasses must not
50 * use this constructor</i>. Instead, they must use the {@link #SourceInterpreter(int)} version.
51 */
52 public SourceInterpreter() {
53 super(ASM6);
54 if (getClass() != SourceInterpreter.class) {
55 throw new IllegalStateException();
56 }
57 }
58
59 /**
60 * Constructs a new {@link SourceInterpreter}.
61 *
62 * @param api the ASM API version supported by this interpreter. Must be one of {@link
63 * org.eclipse.persistence.internal.libraries.asm.Opcodes#ASM4}, {@link org.eclipse.persistence.internal.libraries.asm.Opcodes#ASM5} or {@link
64 * org.eclipse.persistence.internal.libraries.asm.Opcodes#ASM6}.
65 */
66 protected SourceInterpreter(final int api) {
67 super(api);
68 }
69
70 @Override
71 public SourceValue newValue(final Type type) {
72 if (type == Type.VOID_TYPE) {
73 return null;
74 }
75 return new SourceValue(type == null ? 1 : type.getSize());
76 }
77
78 @Override
79 public SourceValue newOperation(final AbstractInsnNode insn) {
80 int size;
81 switch (insn.getOpcode()) {
82 case LCONST_0:
83 case LCONST_1:
84 case DCONST_0:
85 case DCONST_1:
86 size = 2;
87 break;
88 case LDC:
89 Object value = ((LdcInsnNode) insn).cst;
90 size = value instanceof Long || value instanceof Double ? 2 : 1;
91 break;
92 case GETSTATIC:
93 size = Type.getType(((FieldInsnNode) insn).desc).getSize();
94 break;
95 default:
96 size = 1;
97 }
98 return new SourceValue(size, insn);
99 }
100
101 @Override
102 public SourceValue copyOperation(final AbstractInsnNode insn, final SourceValue value) {
103 return new SourceValue(value.getSize(), insn);
104 }
105
106 @Override
107 public SourceValue unaryOperation(final AbstractInsnNode insn, final SourceValue value) {
108 int size;
109 switch (insn.getOpcode()) {
110 case LNEG:
111 case DNEG:
112 case I2L:
113 case I2D:
114 case L2D:
115 case F2L:
116 case F2D:
117 case D2L:
118 size = 2;
119 break;
120 case GETFIELD:
121 size = Type.getType(((FieldInsnNode) insn).desc).getSize();
122 break;
123 default:
124 size = 1;
125 }
126 return new SourceValue(size, insn);
127 }
128
129 @Override
130 public SourceValue binaryOperation(
131 final AbstractInsnNode insn, final SourceValue value1, final SourceValue value2) {
132 int size;
133 switch (insn.getOpcode()) {
134 case LALOAD:
135 case DALOAD:
136 case LADD:
137 case DADD:
138 case LSUB:
139 case DSUB:
140 case LMUL:
141 case DMUL:
142 case LDIV:
143 case DDIV:
144 case LREM:
145 case DREM:
146 case LSHL:
147 case LSHR:
148 case LUSHR:
149 case LAND:
150 case LOR:
151 case LXOR:
152 size = 2;
153 break;
154 default:
155 size = 1;
156 }
157 return new SourceValue(size, insn);
158 }
159
160 @Override
161 public SourceValue ternaryOperation(
162 final AbstractInsnNode insn,
163 final SourceValue value1,
164 final SourceValue value2,
165 final SourceValue value3) {
166 return new SourceValue(1, insn);
167 }
168
169 @Override
170 public SourceValue naryOperation(
171 final AbstractInsnNode insn, final List<? extends SourceValue> values) {
172 int size;
173 int opcode = insn.getOpcode();
174 if (opcode == MULTIANEWARRAY) {
175 size = 1;
176 } else if (opcode == INVOKEDYNAMIC) {
177 size = Type.getReturnType(((InvokeDynamicInsnNode) insn).desc).getSize();
178 } else {
179 size = Type.getReturnType(((MethodInsnNode) insn).desc).getSize();
180 }
181 return new SourceValue(size, insn);
182 }
183
184 @Override
185 public void returnOperation(
186 final AbstractInsnNode insn, final SourceValue value, final SourceValue expected) {
187 // Nothing to do.
188 }
189
190 @Override
191 public SourceValue merge(final SourceValue value1, final SourceValue value2) {
192 if (value1.insns instanceof SmallSet && value2.insns instanceof SmallSet) {
193 Set<AbstractInsnNode> setUnion =
194 ((SmallSet<AbstractInsnNode>) value1.insns)
195 .union((SmallSet<AbstractInsnNode>) value2.insns);
196 if (setUnion == value1.insns && value1.size == value2.size) {
197 return value1;
198 } else {
199 return new SourceValue(Math.min(value1.size, value2.size), setUnion);
200 }
201 }
202 if (value1.size != value2.size || !value1.insns.containsAll(value2.insns)) {
203 HashSet<AbstractInsnNode> setUnion = new HashSet<AbstractInsnNode>();
204 setUnion.addAll(value1.insns);
205 setUnion.addAll(value2.insns);
206 return new SourceValue(Math.min(value1.size, value2.size), setUnion);
207 }
208 return value1;
209 }
197210 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.tree.analysis;
3028
3129 import java.util.Set;
3331 import org.eclipse.persistence.internal.libraries.asm.tree.AbstractInsnNode;
3432
3533 /**
36 * A {@link Value} that is represented by its type in a two types type system.
37 * This type system distinguishes the ONEWORD and TWOWORDS types.
38 *
34 * A {@link Value} which keeps track of the bytecode instructions that can produce it.
35 *
3936 * @author Eric Bruneton
4037 */
4138 public class SourceValue implements Value {
4239
43 /**
44 * The size of this value.
45 */
46 public final int size;
40 /**
41 * The size of this value, in 32 bits words. This size is 1 for byte, boolean, char, short, int,
42 * float, object and array types, and 2 for long and double.
43 */
44 public final int size;
4745
48 /**
49 * The instructions that can produce this value. For example, for the Java
50 * code below, the instructions that can produce the value of <tt>i</tt> at
51 * line 5 are the txo ISTORE instructions at line 1 and 3:
52 *
53 * <pre>
54 * 1: i = 0;
55 * 2: if (...) {
56 * 3: i = 1;
57 * 4: }
58 * 5: return i;
59 * </pre>
60 *
61 * This field is a set of {@link AbstractInsnNode} objects.
62 */
63 public final Set<AbstractInsnNode> insns;
46 /**
47 * The instructions that can produce this value. For example, for the Java code below, the
48 * instructions that can produce the value of <tt>i</tt> at line 5 are the two ISTORE instructions
49 * at line 1 and 3:
50 *
51 * <pre>
52 * 1: i = 0;
53 * 2: if (...) {
54 * 3: i = 1;
55 * 4: }
56 * 5: return i;
57 * </pre>
58 */
59 public final Set<AbstractInsnNode> insns;
6460
65 public SourceValue(final int size) {
66 this(size, SmallSet.<AbstractInsnNode> emptySet());
61 /**
62 * Constructs a new {@link SourceValue}.
63 *
64 * @param size the size of this value, in 32 bits words. This size is 1 for byte, boolean, char,
65 * short, int, float, object and array types, and 2 for long and double.
66 */
67 public SourceValue(final int size) {
68 this(size, new SmallSet<AbstractInsnNode>());
69 }
70
71 /**
72 * Constructs a new {@link SourceValue}.
73 *
74 * @param size the size of this value, in 32 bits words. This size is 1 for byte, boolean, char,
75 * short, int, float, object and array types, and 2 for long and double.
76 * @param insnNode an instruction that can produce this value.
77 */
78 public SourceValue(final int size, final AbstractInsnNode insnNode) {
79 this.size = size;
80 this.insns = new SmallSet<AbstractInsnNode>(insnNode);
81 }
82
83 /**
84 * Constructs a new {@link SourceValue}.
85 *
86 * @param size the size of this value, in 32 bits words. This size is 1 for byte, boolean, char,
87 * short, int, float, object and array types, and 2 for long and double.
88 * @param insnSet the instructions that can produce this value.
89 */
90 public SourceValue(final int size, final Set<AbstractInsnNode> insnSet) {
91 this.size = size;
92 this.insns = insnSet;
93 }
94
95 /**
96 * Returns the size of this value.
97 *
98 * @return the size of this value, in 32 bits words. This size is 1 for byte, boolean, char,
99 * short, int, float, object and array types, and 2 for long and double.
100 */
101 public int getSize() {
102 return size;
103 }
104
105 @Override
106 public boolean equals(final Object value) {
107 if (!(value instanceof SourceValue)) {
108 return false;
67109 }
110 SourceValue sourceValue = (SourceValue) value;
111 return size == sourceValue.size && insns.equals(sourceValue.insns);
112 }
68113
69 public SourceValue(final int size, final AbstractInsnNode insn) {
70 this.size = size;
71 this.insns = new SmallSet<AbstractInsnNode>(insn, null);
72 }
73
74 public SourceValue(final int size, final Set<AbstractInsnNode> insns) {
75 this.size = size;
76 this.insns = insns;
77 }
78
79 public int getSize() {
80 return size;
81 }
82
83 @Override
84 public boolean equals(final Object value) {
85 if (!(value instanceof SourceValue)) {
86 return false;
87 }
88 SourceValue v = (SourceValue) value;
89 return size == v.size && insns.equals(v.insns);
90 }
91
92 @Override
93 public int hashCode() {
94 return insns.hashCode();
95 }
114 @Override
115 public int hashCode() {
116 return insns.hashCode();
117 }
96118 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.tree.analysis;
3028
3129 import java.util.ArrayList;
3634
3735 /**
3836 * A method subroutine (corresponds to a JSR instruction).
39 *
37 *
4038 * @author Eric Bruneton
4139 */
42 class Subroutine {
40 final class Subroutine {
4341
44 LabelNode start;
42 /** The start of this subroutine. */
43 final LabelNode start;
4544
46 boolean[] access;
45 /**
46 * The local variables that are read or written by this subroutine. The i-th element is true if
47 * and only if the local variable at index i is read or written by this subroutine.
48 */
49 final boolean[] localsUsed;
4750
48 List<JumpInsnNode> callers;
51 /** The JSR instructions that jump to this subroutine. */
52 final List<JumpInsnNode> callers;
4953
50 private Subroutine() {
54 /**
55 * Constructs a new {@link Subroutine}.
56 *
57 * @param start the start of this subroutine.
58 * @param maxLocals the local variables that are read or written by this subroutine.
59 * @param caller a JSR instruction that jump to this subroutine.
60 */
61 Subroutine(final LabelNode start, final int maxLocals, final JumpInsnNode caller) {
62 this.start = start;
63 this.localsUsed = new boolean[maxLocals];
64 this.callers = new ArrayList<JumpInsnNode>();
65 callers.add(caller);
66 }
67
68 /**
69 * Constructs a copy of the given {@link Subroutine}.
70 *
71 * @param subroutine the subroutine to copy.
72 */
73 Subroutine(final Subroutine subroutine) {
74 this.start = subroutine.start;
75 this.localsUsed = new boolean[subroutine.localsUsed.length];
76 this.callers = new ArrayList<JumpInsnNode>(subroutine.callers);
77 System.arraycopy(subroutine.localsUsed, 0, this.localsUsed, 0, subroutine.localsUsed.length);
78 }
79
80 /**
81 * Merges the given subroutine into this subroutine. The local variables read or written by the
82 * given subroutine are marked as read or written by this one, and the callers of the given
83 * subroutine are added as callers of this one (if both have the same start).
84 *
85 * @param subroutine another subroutine. This subroutine is left unchanged by this method.
86 * @return whether this subroutine has been modified by this method.
87 */
88 public boolean merge(final Subroutine subroutine) {
89 boolean changed = false;
90 for (int i = 0; i < localsUsed.length; ++i) {
91 if (subroutine.localsUsed[i] && !localsUsed[i]) {
92 localsUsed[i] = true;
93 changed = true;
94 }
5195 }
52
53 Subroutine(final LabelNode start, final int maxLocals,
54 final JumpInsnNode caller) {
55 this.start = start;
56 this.access = new boolean[maxLocals];
57 this.callers = new ArrayList<JumpInsnNode>();
58 callers.add(caller);
96 if (subroutine.start == start) {
97 for (int i = 0; i < subroutine.callers.size(); ++i) {
98 JumpInsnNode caller = subroutine.callers.get(i);
99 if (!callers.contains(caller)) {
100 callers.add(caller);
101 changed = true;
102 }
103 }
59104 }
60
61 public Subroutine copy() {
62 Subroutine result = new Subroutine();
63 result.start = start;
64 result.access = new boolean[access.length];
65 System.arraycopy(access, 0, result.access, 0, access.length);
66 result.callers = new ArrayList<JumpInsnNode>(callers);
67 return result;
68 }
69
70 public boolean merge(final Subroutine subroutine) throws AnalyzerException {
71 boolean changes = false;
72 for (int i = 0; i < access.length; ++i) {
73 if (subroutine.access[i] && !access[i]) {
74 access[i] = true;
75 changes = true;
76 }
77 }
78 if (subroutine.start == start) {
79 for (int i = 0; i < subroutine.callers.size(); ++i) {
80 JumpInsnNode caller = subroutine.callers.get(i);
81 if (!callers.contains(caller)) {
82 callers.add(caller);
83 changes = true;
84 }
85 }
86 }
87 return changes;
88 }
89 }
105 return changed;
106 }
107 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.tree.analysis;
3028
3129 /**
32 * An immutable symbolic value for semantic interpretation of bytecode.
33 *
30 * An immutable symbolic value for the semantic interpretation of bytecode.
31 *
3432 * @author Eric Bruneton
3533 */
3634 public interface Value {
3735
38 /**
39 * Returns the size of this value in words.
40 *
41 * @return either 1 or 2.
42 */
43 int getSize();
36 /**
37 * Returns the size of this value in 32 bits words. This size should be 1 for byte, boolean, char,
38 * short, int, float, object and array types, and 2 for long and double.
39 *
40 * @return either 1 or 2.
41 */
42 int getSize();
4443 }
00 /**
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
1 * ASM: a very small and fast Java bytecode manipulation framework Copyright (c) 2000-2011 INRIA,
2 * France Telecom All rights reserved.
43 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
4 * <p>Redistribution and use in source and binary forms, with or without modification, are permitted
5 * provided that the following conditions are met: 1. Redistributions of source code must retain the
6 * above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions
7 * in binary form must reproduce the above copyright notice, this list of conditions and the
8 * following disclaimer in the documentation and/or other materials provided with the distribution.
9 * 3. Neither the name of the copyright holders nor the names of its contributors may be used to
10 * endorse or promote products derived from this software without specific prior written permission.
1611 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
12 * <p>THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
13 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
14 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
15 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
16 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
17 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
18 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
19 * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2820 */
2921 package org.eclipse.persistence.internal.libraries.asm.util;
3022
3325 import org.eclipse.persistence.internal.libraries.asm.Label;
3426
3527 /**
36 * An {@link org.eclipse.persistence.internal.libraries.asm.Attribute Attribute} that can print the ASM code
37 * to create an equivalent attribute.
38 *
28 * An {@link org.eclipse.persistence.internal.libraries.asm.Attribute} that can generate the ASM code to create an equivalent
29 * attribute.
30 *
3931 * @author Eugene Kuleshov
4032 */
4133 public interface ASMifiable {
4234
43 /**
44 * Prints the ASM code to create an attribute equal to this attribute.
45 *
46 * @param buf
47 * a buffer used for printing Java code.
48 * @param varName
49 * name of the variable in a printed code used to store attribute
50 * instance.
51 * @param labelNames
52 * map of label instances to their names.
53 */
54 void asmify(StringBuffer buf, String varName, Map<Label, String> labelNames);
35 /**
36 * Generates the ASM code to create an attribute equal to this attribute.
37 *
38 * @param outputBuffer where the generated code must be appended.
39 * @param visitorVariableName the name of the visitor variable in the produced code.
40 * @param labelNames the names of the labels in the generated code.
41 */
42 void asmify(StringBuffer outputBuffer, String visitorVariableName, Map<Label, String> labelNames);
5543 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.util;
3028
31 import java.io.FileInputStream;
32 import java.io.PrintWriter;
29 import java.io.IOException;
30 import java.util.Collections;
3331 import java.util.HashMap;
3432 import java.util.Map;
3533
3634 import org.eclipse.persistence.internal.libraries.asm.Attribute;
37 import org.eclipse.persistence.internal.libraries.asm.ClassReader;
3835 import org.eclipse.persistence.internal.libraries.asm.Handle;
3936 import org.eclipse.persistence.internal.libraries.asm.Label;
4037 import org.eclipse.persistence.internal.libraries.asm.Opcodes;
4340
4441 /**
4542 * A {@link Printer} that prints the ASM code to generate the classes if visits.
46 *
43 *
4744 * @author Eric Bruneton
4845 */
4946 public class ASMifier extends Printer {
5047
51 /**
52 * The name of the visitor variable in the produced code.
53 */
54 protected final String name;
55
56 /**
57 * Identifier of the annotation visitor variable in the produced code.
58 */
59 protected final int id;
60
61 /**
62 * The label names. This map associates String values to Label keys. It is
63 * used only in ASMifierMethodVisitor.
64 */
65 protected Map<Label, String> labelNames;
66
67 /**
68 * Pseudo access flag used to distinguish class access flags.
69 */
70 private static final int ACCESS_CLASS = 262144;
71
72 /**
73 * Pseudo access flag used to distinguish field access flags.
74 */
75 private static final int ACCESS_FIELD = 524288;
76
77 /**
78 * Pseudo access flag used to distinguish inner class flags.
79 */
80 private static final int ACCESS_INNER = 1048576;
81
82 /**
83 * Constructs a new {@link ASMifier}. <i>Subclasses must not use this
84 * constructor</i>. Instead, they must use the
85 * {@link #ASMifier(int, String, int)} version.
86 *
87 * @throws IllegalStateException
88 * If a subclass calls this constructor.
89 */
90 public ASMifier() {
91 this(Opcodes.ASM6, "cw", 0);
92 if (getClass() != ASMifier.class) {
93 throw new IllegalStateException();
48 /** A pseudo access flag used to distinguish class access flags. */
49 private static final int ACCESS_CLASS = 0x40000;
50
51 /** A pseudo access flag used to distinguish field access flags. */
52 private static final int ACCESS_FIELD = 0x80000;
53
54 /** A pseudo access flag used to distinguish inner class flags. */
55 private static final int ACCESS_INNER = 0x100000;
56
57 /** A pseudo access flag used to distinguish module requires / exports flags. */
58 private static final int ACCESS_MODULE = 0x200000;
59
60 private static final String ANNOTATION_VISITOR = "annotationVisitor";
61 private static final String ANNOTATION_VISITOR0 = "annotationVisitor0 = ";
62 private static final String NEW_OBJECT_ARRAY = ", new Object[] {";
63 private static final String END_ARRAY = " });\n";
64 private static final String END_PARAMETERS = ");\n\n";
65 private static final String VISIT_END = ".visitEnd();\n";
66
67 private static final Map<Integer, String> CLASS_VERSIONS;
68
69 static {
70 HashMap<Integer, String> classVersions = new HashMap<Integer, String>();
71 classVersions.put(Opcodes.V1_1, "V1_1");
72 classVersions.put(Opcodes.V1_2, "V1_2");
73 classVersions.put(Opcodes.V1_3, "V1_3");
74 classVersions.put(Opcodes.V1_4, "V1_4");
75 classVersions.put(Opcodes.V1_5, "V1_5");
76 classVersions.put(Opcodes.V1_6, "V1_6");
77 classVersions.put(Opcodes.V1_7, "V1_7");
78 classVersions.put(Opcodes.V1_8, "V1_8");
79 classVersions.put(Opcodes.V9, "V9");
80 classVersions.put(Opcodes.V10, "V10");
81 CLASS_VERSIONS = Collections.unmodifiableMap(classVersions);
82 }
83
84 /** The name of the visitor variable in the produced code. */
85 protected final String name;
86
87 /** The identifier of the annotation visitor variable in the produced code. */
88 protected final int id;
89
90 /** The name of the Label variables in the produced code. */
91 protected Map<Label, String> labelNames;
92
93 /**
94 * Constructs a new {@link ASMifier}. <i>Subclasses must not use this constructor</i>. Instead,
95 * they must use the {@link #ASMifier(int, String, int)} version.
96 *
97 * @throws IllegalStateException If a subclass calls this constructor.
98 */
99 public ASMifier() {
100 this(Opcodes.ASM6, "classWriter", 0);
101 if (getClass() != ASMifier.class) {
102 throw new IllegalStateException();
103 }
104 }
105
106 /**
107 * Constructs a new {@link ASMifier}.
108 *
109 * @param api the ASM API version implemented by this class. Must be one of {@link Opcodes#ASM4},
110 * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
111 * @param visitorVariableName the name of the visitor variable in the produced code.
112 * @param annotationVisitorId identifier of the annotation visitor variable in the produced code.
113 */
114 protected ASMifier(
115 final int api, final String visitorVariableName, final int annotationVisitorId) {
116 super(api);
117 this.name = visitorVariableName;
118 this.id = annotationVisitorId;
119 }
120
121 /**
122 * Prints the ASM source code to generate the given class to the standard output.
123 *
124 * <p>Usage: ASMifier [-debug] &lt;binary class name or class file name&gt;
125 *
126 * @param args the command line arguments.
127 * @throws IOException if the class cannot be found, or if an IOException occurs.
128 */
129 public static void main(final String[] args) throws IOException {
130 String usage =
131 "Prints the ASM code to generate the given class.\n"
132 + "Usage: ASMifier [-debug] <fully qualified class name or class file name>";
133 main(usage, new ASMifier(), args);
134 }
135
136 // -----------------------------------------------------------------------------------------------
137 // Classes
138 // -----------------------------------------------------------------------------------------------
139
140 @Override
141 public void visit(
142 final int version,
143 final int access,
144 final String name,
145 final String signature,
146 final String superName,
147 final String[] interfaces) {
148 String simpleName;
149 if (name == null) {
150 simpleName = "module-info";
151 } else {
152 int lastSlashIndex = name.lastIndexOf('/');
153 if (lastSlashIndex == -1) {
154 simpleName = name;
155 } else {
156 text.add("package asm." + name.substring(0, lastSlashIndex).replace('/', '.') + ";\n");
157 simpleName = name.substring(lastSlashIndex + 1).replace('-', '_');
158 }
159 }
160 text.add("import org.eclipse.persistence.internal.libraries.asm.AnnotationVisitor;\n");
161 text.add("import org.eclipse.persistence.internal.libraries.asm.Attribute;\n");
162 text.add("import org.eclipse.persistence.internal.libraries.asm.ClassReader;\n");
163 text.add("import org.eclipse.persistence.internal.libraries.asm.ClassWriter;\n");
164 text.add("import org.eclipse.persistence.internal.libraries.asm.FieldVisitor;\n");
165 text.add("import org.eclipse.persistence.internal.libraries.asm.Handle;\n");
166 text.add("import org.eclipse.persistence.internal.libraries.asm.Label;\n");
167 text.add("import org.eclipse.persistence.internal.libraries.asm.MethodVisitor;\n");
168 text.add("import org.eclipse.persistence.internal.libraries.asm.Opcodes;\n");
169 text.add("import org.eclipse.persistence.internal.libraries.asm.Type;\n");
170 text.add("import org.eclipse.persistence.internal.libraries.asm.TypePath;\n");
171 text.add("public class " + simpleName + "Dump implements Opcodes {\n\n");
172 text.add("public static byte[] dump () throws Exception {\n\n");
173 text.add("ClassWriter classWriter = new ClassWriter(0);\n");
174 text.add("FieldVisitor fieldVisitor;\n");
175 text.add("MethodVisitor methodVisitor;\n");
176 text.add("AnnotationVisitor annotationVisitor0;\n\n");
177
178 stringBuilder.setLength(0);
179 stringBuilder.append("classWriter.visit(");
180 String versionString = CLASS_VERSIONS.get(version);
181 if (versionString != null) {
182 stringBuilder.append(versionString);
183 } else {
184 stringBuilder.append(version);
185 }
186 stringBuilder.append(", ");
187 appendAccessFlags(access | ACCESS_CLASS);
188 stringBuilder.append(", ");
189 appendConstant(name);
190 stringBuilder.append(", ");
191 appendConstant(signature);
192 stringBuilder.append(", ");
193 appendConstant(superName);
194 stringBuilder.append(", ");
195 if (interfaces != null && interfaces.length > 0) {
196 stringBuilder.append("new String[] {");
197 for (int i = 0; i < interfaces.length; ++i) {
198 stringBuilder.append(i == 0 ? " " : ", ");
199 appendConstant(interfaces[i]);
200 }
201 stringBuilder.append(" }");
202 } else {
203 stringBuilder.append("null");
204 }
205 stringBuilder.append(END_PARAMETERS);
206 text.add(stringBuilder.toString());
207 }
208
209 @Override
210 public void visitSource(final String file, final String debug) {
211 stringBuilder.setLength(0);
212 stringBuilder.append("classWriter.visitSource(");
213 appendConstant(file);
214 stringBuilder.append(", ");
215 appendConstant(debug);
216 stringBuilder.append(END_PARAMETERS);
217 text.add(stringBuilder.toString());
218 }
219
220 @Override
221 public Printer visitModule(final String name, final int flags, final String version) {
222 stringBuilder.setLength(0);
223 stringBuilder.append("ModuleVisitor moduleVisitor = classWriter.visitModule(");
224 appendConstant(name);
225 stringBuilder.append(", ");
226 appendAccessFlags(flags | ACCESS_MODULE);
227 stringBuilder.append(", ");
228 appendConstant(version);
229 stringBuilder.append(END_PARAMETERS);
230 text.add(stringBuilder.toString());
231 ASMifier asmifier = createASMifier("moduleVisitor", 0);
232 text.add(asmifier.getText());
233 text.add("}\n");
234 return asmifier;
235 }
236
237 @Override
238 public void visitOuterClass(final String owner, final String name, final String descriptor) {
239 stringBuilder.setLength(0);
240 stringBuilder.append("classWriter.visitOuterClass(");
241 appendConstant(owner);
242 stringBuilder.append(", ");
243 appendConstant(name);
244 stringBuilder.append(", ");
245 appendConstant(descriptor);
246 stringBuilder.append(END_PARAMETERS);
247 text.add(stringBuilder.toString());
248 }
249
250 @Override
251 public ASMifier visitClassAnnotation(final String descriptor, final boolean visible) {
252 return visitAnnotation(descriptor, visible);
253 }
254
255 @Override
256 public ASMifier visitClassTypeAnnotation(
257 final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
258 return visitTypeAnnotation(typeRef, typePath, descriptor, visible);
259 }
260
261 @Override
262 public void visitClassAttribute(final Attribute attribute) {
263 visitAttribute(attribute);
264 }
265
266 @Override
267 public void visitInnerClass(
268 final String name, final String outerName, final String innerName, final int access) {
269 stringBuilder.setLength(0);
270 stringBuilder.append("classWriter.visitInnerClass(");
271 appendConstant(name);
272 stringBuilder.append(", ");
273 appendConstant(outerName);
274 stringBuilder.append(", ");
275 appendConstant(innerName);
276 stringBuilder.append(", ");
277 appendAccessFlags(access | ACCESS_INNER);
278 stringBuilder.append(END_PARAMETERS);
279 text.add(stringBuilder.toString());
280 }
281
282 @Override
283 public ASMifier visitField(
284 final int access,
285 final String name,
286 final String descriptor,
287 final String signature,
288 final Object value) {
289 stringBuilder.setLength(0);
290 stringBuilder.append("{\n");
291 stringBuilder.append("fieldVisitor = classWriter.visitField(");
292 appendAccessFlags(access | ACCESS_FIELD);
293 stringBuilder.append(", ");
294 appendConstant(name);
295 stringBuilder.append(", ");
296 appendConstant(descriptor);
297 stringBuilder.append(", ");
298 appendConstant(signature);
299 stringBuilder.append(", ");
300 appendConstant(value);
301 stringBuilder.append(");\n");
302 text.add(stringBuilder.toString());
303 ASMifier asmifier = createASMifier("fieldVisitor", 0);
304 text.add(asmifier.getText());
305 text.add("}\n");
306 return asmifier;
307 }
308
309 @Override
310 public ASMifier visitMethod(
311 final int access,
312 final String name,
313 final String descriptor,
314 final String signature,
315 final String[] exceptions) {
316 stringBuilder.setLength(0);
317 stringBuilder.append("{\n");
318 stringBuilder.append("methodVisitor = classWriter.visitMethod(");
319 appendAccessFlags(access);
320 stringBuilder.append(", ");
321 appendConstant(name);
322 stringBuilder.append(", ");
323 appendConstant(descriptor);
324 stringBuilder.append(", ");
325 appendConstant(signature);
326 stringBuilder.append(", ");
327 if (exceptions != null && exceptions.length > 0) {
328 stringBuilder.append("new String[] {");
329 for (int i = 0; i < exceptions.length; ++i) {
330 stringBuilder.append(i == 0 ? " " : ", ");
331 appendConstant(exceptions[i]);
332 }
333 stringBuilder.append(" }");
334 } else {
335 stringBuilder.append("null");
336 }
337 stringBuilder.append(");\n");
338 text.add(stringBuilder.toString());
339 ASMifier asmifier = createASMifier("methodVisitor", 0);
340 text.add(asmifier.getText());
341 text.add("}\n");
342 return asmifier;
343 }
344
345 @Override
346 public void visitClassEnd() {
347 text.add("classWriter.visitEnd();\n\n");
348 text.add("return classWriter.toByteArray();\n");
349 text.add("}\n");
350 text.add("}\n");
351 }
352
353 // -----------------------------------------------------------------------------------------------
354 // Modules
355 // -----------------------------------------------------------------------------------------------
356
357 @Override
358 public void visitMainClass(final String mainClass) {
359 stringBuilder.setLength(0);
360 stringBuilder.append("moduleVisitor.visitMainClass(");
361 appendConstant(mainClass);
362 stringBuilder.append(");\n");
363 text.add(stringBuilder.toString());
364 }
365
366 @Override
367 public void visitPackage(final String packaze) {
368 stringBuilder.setLength(0);
369 stringBuilder.append("moduleVisitor.visitPackage(");
370 appendConstant(packaze);
371 stringBuilder.append(");\n");
372 text.add(stringBuilder.toString());
373 }
374
375 @Override
376 public void visitRequire(final String module, final int access, final String version) {
377 stringBuilder.setLength(0);
378 stringBuilder.append("moduleVisitor.visitRequire(");
379 appendConstant(module);
380 stringBuilder.append(", ");
381 appendAccessFlags(access | ACCESS_MODULE);
382 stringBuilder.append(", ");
383 appendConstant(version);
384 stringBuilder.append(");\n");
385 text.add(stringBuilder.toString());
386 }
387
388 @Override
389 public void visitExport(final String packaze, final int access, final String... modules) {
390 stringBuilder.setLength(0);
391 stringBuilder.append("moduleVisitor.visitExport(");
392 appendConstant(packaze);
393 stringBuilder.append(", ");
394 appendAccessFlags(access | ACCESS_MODULE);
395 if (modules != null && modules.length > 0) {
396 stringBuilder.append(", new String[] {");
397 for (int i = 0; i < modules.length; ++i) {
398 stringBuilder.append(i == 0 ? " " : ", ");
399 appendConstant(modules[i]);
400 }
401 stringBuilder.append(" }");
402 }
403 stringBuilder.append(");\n");
404 text.add(stringBuilder.toString());
405 }
406
407 @Override
408 public void visitOpen(final String packaze, final int access, final String... modules) {
409 stringBuilder.setLength(0);
410 stringBuilder.append("moduleVisitor.visitOpen(");
411 appendConstant(packaze);
412 stringBuilder.append(", ");
413 appendAccessFlags(access | ACCESS_MODULE);
414 if (modules != null && modules.length > 0) {
415 stringBuilder.append(", new String[] {");
416 for (int i = 0; i < modules.length; ++i) {
417 stringBuilder.append(i == 0 ? " " : ", ");
418 appendConstant(modules[i]);
419 }
420 stringBuilder.append(" }");
421 }
422 stringBuilder.append(");\n");
423 text.add(stringBuilder.toString());
424 }
425
426 @Override
427 public void visitUse(final String service) {
428 stringBuilder.setLength(0);
429 stringBuilder.append("moduleVisitor.visitUse(");
430 appendConstant(service);
431 stringBuilder.append(");\n");
432 text.add(stringBuilder.toString());
433 }
434
435 @Override
436 public void visitProvide(final String service, final String... providers) {
437 stringBuilder.setLength(0);
438 stringBuilder.append("moduleVisitor.visitProvide(");
439 appendConstant(service);
440 stringBuilder.append(", new String[] {");
441 for (int i = 0; i < providers.length; ++i) {
442 stringBuilder.append(i == 0 ? " " : ", ");
443 appendConstant(providers[i]);
444 }
445 stringBuilder.append(END_ARRAY);
446 text.add(stringBuilder.toString());
447 }
448
449 @Override
450 public void visitModuleEnd() {
451 text.add("moduleVisitor.visitEnd();\n");
452 }
453
454 // -----------------------------------------------------------------------------------------------
455 // Annotations
456 // -----------------------------------------------------------------------------------------------
457
458 @Override
459 public void visit(final String name, final Object value) {
460 stringBuilder.setLength(0);
461 stringBuilder.append(ANNOTATION_VISITOR).append(id).append(".visit(");
462 appendConstant(name);
463 stringBuilder.append(", ");
464 appendConstant(value);
465 stringBuilder.append(");\n");
466 text.add(stringBuilder.toString());
467 }
468
469 @Override
470 public void visitEnum(final String name, final String descriptor, final String value) {
471 stringBuilder.setLength(0);
472 stringBuilder.append(ANNOTATION_VISITOR).append(id).append(".visitEnum(");
473 appendConstant(name);
474 stringBuilder.append(", ");
475 appendConstant(descriptor);
476 stringBuilder.append(", ");
477 appendConstant(value);
478 stringBuilder.append(");\n");
479 text.add(stringBuilder.toString());
480 }
481
482 @Override
483 public ASMifier visitAnnotation(final String name, final String descriptor) {
484 stringBuilder.setLength(0);
485 stringBuilder
486 .append("{\n")
487 .append("AnnotationVisitor annotationVisitor")
488 .append(id + 1)
489 .append(" = annotationVisitor");
490 stringBuilder.append(id).append(".visitAnnotation(");
491 appendConstant(name);
492 stringBuilder.append(", ");
493 appendConstant(descriptor);
494 stringBuilder.append(");\n");
495 text.add(stringBuilder.toString());
496 ASMifier asmifier = createASMifier(ANNOTATION_VISITOR, id + 1);
497 text.add(asmifier.getText());
498 text.add("}\n");
499 return asmifier;
500 }
501
502 @Override
503 public ASMifier visitArray(final String name) {
504 stringBuilder.setLength(0);
505 stringBuilder.append("{\n");
506 stringBuilder
507 .append("AnnotationVisitor annotationVisitor")
508 .append(id + 1)
509 .append(" = annotationVisitor");
510 stringBuilder.append(id).append(".visitArray(");
511 appendConstant(name);
512 stringBuilder.append(");\n");
513 text.add(stringBuilder.toString());
514 ASMifier asmifier = createASMifier(ANNOTATION_VISITOR, id + 1);
515 text.add(asmifier.getText());
516 text.add("}\n");
517 return asmifier;
518 }
519
520 @Override
521 public void visitAnnotationEnd() {
522 stringBuilder.setLength(0);
523 stringBuilder.append(ANNOTATION_VISITOR).append(id).append(VISIT_END);
524 text.add(stringBuilder.toString());
525 }
526
527 // -----------------------------------------------------------------------------------------------
528 // Fields
529 // -----------------------------------------------------------------------------------------------
530
531 @Override
532 public ASMifier visitFieldAnnotation(final String descriptor, final boolean visible) {
533 return visitAnnotation(descriptor, visible);
534 }
535
536 @Override
537 public ASMifier visitFieldTypeAnnotation(
538 final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
539 return visitTypeAnnotation(typeRef, typePath, descriptor, visible);
540 }
541
542 @Override
543 public void visitFieldAttribute(final Attribute attribute) {
544 visitAttribute(attribute);
545 }
546
547 @Override
548 public void visitFieldEnd() {
549 stringBuilder.setLength(0);
550 stringBuilder.append(name).append(VISIT_END);
551 text.add(stringBuilder.toString());
552 }
553
554 // -----------------------------------------------------------------------------------------------
555 // Methods
556 // -----------------------------------------------------------------------------------------------
557
558 @Override
559 public void visitParameter(final String parameterName, final int access) {
560 stringBuilder.setLength(0);
561 stringBuilder.append(name).append(".visitParameter(");
562 appendString(stringBuilder, parameterName);
563 stringBuilder.append(", ");
564 appendAccessFlags(access);
565 text.add(stringBuilder.append(");\n").toString());
566 }
567
568 @Override
569 public ASMifier visitAnnotationDefault() {
570 stringBuilder.setLength(0);
571 stringBuilder
572 .append("{\n")
573 .append(ANNOTATION_VISITOR0)
574 .append(name)
575 .append(".visitAnnotationDefault();\n");
576 text.add(stringBuilder.toString());
577 ASMifier asmifier = createASMifier(ANNOTATION_VISITOR, 0);
578 text.add(asmifier.getText());
579 text.add("}\n");
580 return asmifier;
581 }
582
583 @Override
584 public ASMifier visitMethodAnnotation(final String descriptor, final boolean visible) {
585 return visitAnnotation(descriptor, visible);
586 }
587
588 @Override
589 public ASMifier visitMethodTypeAnnotation(
590 final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
591 return visitTypeAnnotation(typeRef, typePath, descriptor, visible);
592 }
593
594 @Override
595 public ASMifier visitAnnotableParameterCount(final int parameterCount, final boolean visible) {
596 stringBuilder.setLength(0);
597 stringBuilder
598 .append(name)
599 .append(".visitAnnotableParameterCount(")
600 .append(parameterCount)
601 .append(", ")
602 .append(visible)
603 .append(");\n");
604 text.add(stringBuilder.toString());
605 return this;
606 }
607
608 @Override
609 public ASMifier visitParameterAnnotation(
610 final int parameter, final String descriptor, final boolean visible) {
611 stringBuilder.setLength(0);
612 stringBuilder
613 .append("{\n")
614 .append(ANNOTATION_VISITOR0)
615 .append(name)
616 .append(".visitParameterAnnotation(")
617 .append(parameter)
618 .append(", ");
619 appendConstant(descriptor);
620 stringBuilder.append(", ").append(visible).append(");\n");
621 text.add(stringBuilder.toString());
622 ASMifier asmifier = createASMifier(ANNOTATION_VISITOR, 0);
623 text.add(asmifier.getText());
624 text.add("}\n");
625 return asmifier;
626 }
627
628 @Override
629 public void visitMethodAttribute(final Attribute attribute) {
630 visitAttribute(attribute);
631 }
632
633 @Override
634 public void visitCode() {
635 text.add(name + ".visitCode();\n");
636 }
637
638 @Override
639 public void visitFrame(
640 final int type,
641 final int nLocal,
642 final Object[] local,
643 final int nStack,
644 final Object[] stack) {
645 stringBuilder.setLength(0);
646 switch (type) {
647 case Opcodes.F_NEW:
648 case Opcodes.F_FULL:
649 declareFrameTypes(nLocal, local);
650 declareFrameTypes(nStack, stack);
651 if (type == Opcodes.F_NEW) {
652 stringBuilder.append(name).append(".visitFrame(Opcodes.F_NEW, ");
653 } else {
654 stringBuilder.append(name).append(".visitFrame(Opcodes.F_FULL, ");
94655 }
95 }
96
97 /**
98 * Constructs a new {@link ASMifier}.
99 *
100 * @param api
101 * the ASM API version implemented by this class. Must be one of
102 * {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
103 * @param name
104 * the name of the visitor variable in the produced code.
105 * @param id
106 * identifier of the annotation visitor variable in the produced
107 * code.
108 */
109 protected ASMifier(final int api, final String name, final int id) {
110 super(api);
111 this.name = name;
112 this.id = id;
113 }
114
115 /**
116 * Prints the ASM source code to generate the given class to the standard
117 * output.
118 * <p>
119 * Usage: ASMifier [-debug] &lt;binary class name or class file name&gt;
120 *
121 * @param args
122 * the command line arguments.
123 *
124 * @throws Exception
125 * if the class cannot be found, or if an IO exception occurs.
126 */
127 public static void main(final String[] args) throws Exception {
128 int i = 0;
129 int flags = ClassReader.SKIP_DEBUG;
130
131 boolean ok = true;
132 if (args.length < 1 || args.length > 2) {
133 ok = false;
656 stringBuilder.append(nLocal).append(NEW_OBJECT_ARRAY);
657 appendFrameTypes(nLocal, local);
658 stringBuilder.append("}, ").append(nStack).append(NEW_OBJECT_ARRAY);
659 appendFrameTypes(nStack, stack);
660 stringBuilder.append('}');
661 break;
662 case Opcodes.F_APPEND:
663 declareFrameTypes(nLocal, local);
664 stringBuilder
665 .append(name)
666 .append(".visitFrame(Opcodes.F_APPEND,")
667 .append(nLocal)
668 .append(NEW_OBJECT_ARRAY);
669 appendFrameTypes(nLocal, local);
670 stringBuilder.append("}, 0, null");
671 break;
672 case Opcodes.F_CHOP:
673 stringBuilder
674 .append(name)
675 .append(".visitFrame(Opcodes.F_CHOP,")
676 .append(nLocal)
677 .append(", null, 0, null");
678 break;
679 case Opcodes.F_SAME:
680 stringBuilder.append(name).append(".visitFrame(Opcodes.F_SAME, 0, null, 0, null");
681 break;
682 case Opcodes.F_SAME1:
683 declareFrameTypes(1, stack);
684 stringBuilder
685 .append(name)
686 .append(".visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] {");
687 appendFrameTypes(1, stack);
688 stringBuilder.append('}');
689 break;
690 default:
691 throw new IllegalArgumentException();
692 }
693 stringBuilder.append(");\n");
694 text.add(stringBuilder.toString());
695 }
696
697 @Override
698 public void visitInsn(final int opcode) {
699 stringBuilder.setLength(0);
700 stringBuilder.append(name).append(".visitInsn(").append(OPCODES[opcode]).append(");\n");
701 text.add(stringBuilder.toString());
702 }
703
704 @Override
705 public void visitIntInsn(final int opcode, final int operand) {
706 stringBuilder.setLength(0);
707 stringBuilder
708 .append(name)
709 .append(".visitIntInsn(")
710 .append(OPCODES[opcode])
711 .append(", ")
712 .append(opcode == Opcodes.NEWARRAY ? TYPES[operand] : Integer.toString(operand))
713 .append(");\n");
714 text.add(stringBuilder.toString());
715 }
716
717 @Override
718 public void visitVarInsn(final int opcode, final int var) {
719 stringBuilder.setLength(0);
720 stringBuilder
721 .append(name)
722 .append(".visitVarInsn(")
723 .append(OPCODES[opcode])
724 .append(", ")
725 .append(var)
726 .append(");\n");
727 text.add(stringBuilder.toString());
728 }
729
730 @Override
731 public void visitTypeInsn(final int opcode, final String type) {
732 stringBuilder.setLength(0);
733 stringBuilder.append(name).append(".visitTypeInsn(").append(OPCODES[opcode]).append(", ");
734 appendConstant(type);
735 stringBuilder.append(");\n");
736 text.add(stringBuilder.toString());
737 }
738
739 @Override
740 public void visitFieldInsn(
741 final int opcode, final String owner, final String name, final String descriptor) {
742 stringBuilder.setLength(0);
743 stringBuilder.append(this.name).append(".visitFieldInsn(").append(OPCODES[opcode]).append(", ");
744 appendConstant(owner);
745 stringBuilder.append(", ");
746 appendConstant(name);
747 stringBuilder.append(", ");
748 appendConstant(descriptor);
749 stringBuilder.append(");\n");
750 text.add(stringBuilder.toString());
751 }
752
753 /** @deprecated */
754 @Deprecated
755 @Override
756 public void visitMethodInsn(
757 final int opcode, final String owner, final String name, final String descriptor) {
758 if (api >= Opcodes.ASM5) {
759 super.visitMethodInsn(opcode, owner, name, descriptor);
760 return;
761 }
762 doVisitMethodInsn(opcode, owner, name, descriptor, opcode == Opcodes.INVOKEINTERFACE);
763 }
764
765 @Override
766 public void visitMethodInsn(
767 final int opcode,
768 final String owner,
769 final String name,
770 final String descriptor,
771 final boolean isInterface) {
772 if (api < Opcodes.ASM5) {
773 super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
774 return;
775 }
776 doVisitMethodInsn(opcode, owner, name, descriptor, isInterface);
777 }
778
779 private void doVisitMethodInsn(
780 final int opcode,
781 final String owner,
782 final String name,
783 final String descriptor,
784 final boolean isInterface) {
785 stringBuilder.setLength(0);
786 stringBuilder
787 .append(this.name)
788 .append(".visitMethodInsn(")
789 .append(OPCODES[opcode])
790 .append(", ");
791 appendConstant(owner);
792 stringBuilder.append(", ");
793 appendConstant(name);
794 stringBuilder.append(", ");
795 appendConstant(descriptor);
796 stringBuilder.append(", ");
797 stringBuilder.append(isInterface ? "true" : "false");
798 stringBuilder.append(");\n");
799 text.add(stringBuilder.toString());
800 }
801
802 @Override
803 public void visitInvokeDynamicInsn(
804 final String name,
805 final String descriptor,
806 final Handle bootstrapMethodHandle,
807 final Object... bootstrapMethodArguments) {
808 stringBuilder.setLength(0);
809 stringBuilder.append(this.name).append(".visitInvokeDynamicInsn(");
810 appendConstant(name);
811 stringBuilder.append(", ");
812 appendConstant(descriptor);
813 stringBuilder.append(", ");
814 appendConstant(bootstrapMethodHandle);
815 stringBuilder.append(", new Object[]{");
816 for (int i = 0; i < bootstrapMethodArguments.length; ++i) {
817 appendConstant(bootstrapMethodArguments[i]);
818 if (i != bootstrapMethodArguments.length - 1) {
819 stringBuilder.append(", ");
820 }
821 }
822 stringBuilder.append("});\n");
823 text.add(stringBuilder.toString());
824 }
825
826 @Override
827 public void visitJumpInsn(final int opcode, final Label label) {
828 stringBuilder.setLength(0);
829 declareLabel(label);
830 stringBuilder.append(name).append(".visitJumpInsn(").append(OPCODES[opcode]).append(", ");
831 appendLabel(label);
832 stringBuilder.append(");\n");
833 text.add(stringBuilder.toString());
834 }
835
836 @Override
837 public void visitLabel(final Label label) {
838 stringBuilder.setLength(0);
839 declareLabel(label);
840 stringBuilder.append(name).append(".visitLabel(");
841 appendLabel(label);
842 stringBuilder.append(");\n");
843 text.add(stringBuilder.toString());
844 }
845
846 @Override
847 public void visitLdcInsn(final Object value) {
848 stringBuilder.setLength(0);
849 stringBuilder.append(name).append(".visitLdcInsn(");
850 appendConstant(value);
851 stringBuilder.append(");\n");
852 text.add(stringBuilder.toString());
853 }
854
855 @Override
856 public void visitIincInsn(final int var, final int increment) {
857 stringBuilder.setLength(0);
858 stringBuilder
859 .append(name)
860 .append(".visitIincInsn(")
861 .append(var)
862 .append(", ")
863 .append(increment)
864 .append(");\n");
865 text.add(stringBuilder.toString());
866 }
867
868 @Override
869 public void visitTableSwitchInsn(
870 final int min, final int max, final Label dflt, final Label... labels) {
871 stringBuilder.setLength(0);
872 for (int i = 0; i < labels.length; ++i) {
873 declareLabel(labels[i]);
874 }
875 declareLabel(dflt);
876
877 stringBuilder
878 .append(name)
879 .append(".visitTableSwitchInsn(")
880 .append(min)
881 .append(", ")
882 .append(max)
883 .append(", ");
884 appendLabel(dflt);
885 stringBuilder.append(", new Label[] {");
886 for (int i = 0; i < labels.length; ++i) {
887 stringBuilder.append(i == 0 ? " " : ", ");
888 appendLabel(labels[i]);
889 }
890 stringBuilder.append(END_ARRAY);
891 text.add(stringBuilder.toString());
892 }
893
894 @Override
895 public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) {
896 stringBuilder.setLength(0);
897 for (int i = 0; i < labels.length; ++i) {
898 declareLabel(labels[i]);
899 }
900 declareLabel(dflt);
901
902 stringBuilder.append(name).append(".visitLookupSwitchInsn(");
903 appendLabel(dflt);
904 stringBuilder.append(", new int[] {");
905 for (int i = 0; i < keys.length; ++i) {
906 stringBuilder.append(i == 0 ? " " : ", ").append(keys[i]);
907 }
908 stringBuilder.append(" }, new Label[] {");
909 for (int i = 0; i < labels.length; ++i) {
910 stringBuilder.append(i == 0 ? " " : ", ");
911 appendLabel(labels[i]);
912 }
913 stringBuilder.append(END_ARRAY);
914 text.add(stringBuilder.toString());
915 }
916
917 @Override
918 public void visitMultiANewArrayInsn(final String descriptor, final int numDimensions) {
919 stringBuilder.setLength(0);
920 stringBuilder.append(name).append(".visitMultiANewArrayInsn(");
921 appendConstant(descriptor);
922 stringBuilder.append(", ").append(numDimensions).append(");\n");
923 text.add(stringBuilder.toString());
924 }
925
926 @Override
927 public ASMifier visitInsnAnnotation(
928 final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
929 return visitTypeAnnotation("visitInsnAnnotation", typeRef, typePath, descriptor, visible);
930 }
931
932 @Override
933 public void visitTryCatchBlock(
934 final Label start, final Label end, final Label handler, final String type) {
935 stringBuilder.setLength(0);
936 declareLabel(start);
937 declareLabel(end);
938 declareLabel(handler);
939 stringBuilder.append(name).append(".visitTryCatchBlock(");
940 appendLabel(start);
941 stringBuilder.append(", ");
942 appendLabel(end);
943 stringBuilder.append(", ");
944 appendLabel(handler);
945 stringBuilder.append(", ");
946 appendConstant(type);
947 stringBuilder.append(");\n");
948 text.add(stringBuilder.toString());
949 }
950
951 @Override
952 public ASMifier visitTryCatchAnnotation(
953 final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
954 return visitTypeAnnotation("visitTryCatchAnnotation", typeRef, typePath, descriptor, visible);
955 }
956
957 @Override
958 public void visitLocalVariable(
959 final String name,
960 final String descriptor,
961 final String signature,
962 final Label start,
963 final Label end,
964 final int index) {
965 stringBuilder.setLength(0);
966 stringBuilder.append(this.name).append(".visitLocalVariable(");
967 appendConstant(name);
968 stringBuilder.append(", ");
969 appendConstant(descriptor);
970 stringBuilder.append(", ");
971 appendConstant(signature);
972 stringBuilder.append(", ");
973 appendLabel(start);
974 stringBuilder.append(", ");
975 appendLabel(end);
976 stringBuilder.append(", ").append(index).append(");\n");
977 text.add(stringBuilder.toString());
978 }
979
980 @Override
981 public Printer visitLocalVariableAnnotation(
982 final int typeRef,
983 final TypePath typePath,
984 final Label[] start,
985 final Label[] end,
986 final int[] index,
987 final String descriptor,
988 final boolean visible) {
989 stringBuilder.setLength(0);
990 stringBuilder
991 .append("{\n")
992 .append(ANNOTATION_VISITOR0)
993 .append(name)
994 .append(".visitLocalVariableAnnotation(")
995 .append(typeRef);
996 if (typePath == null) {
997 stringBuilder.append(", null, ");
998 } else {
999 stringBuilder.append(", TypePath.fromString(\"").append(typePath).append("\"), ");
1000 }
1001 stringBuilder.append("new Label[] {");
1002 for (int i = 0; i < start.length; ++i) {
1003 stringBuilder.append(i == 0 ? " " : ", ");
1004 appendLabel(start[i]);
1005 }
1006 stringBuilder.append(" }, new Label[] {");
1007 for (int i = 0; i < end.length; ++i) {
1008 stringBuilder.append(i == 0 ? " " : ", ");
1009 appendLabel(end[i]);
1010 }
1011 stringBuilder.append(" }, new int[] {");
1012 for (int i = 0; i < index.length; ++i) {
1013 stringBuilder.append(i == 0 ? " " : ", ").append(index[i]);
1014 }
1015 stringBuilder.append(" }, ");
1016 appendConstant(descriptor);
1017 stringBuilder.append(", ").append(visible).append(");\n");
1018 text.add(stringBuilder.toString());
1019 ASMifier asmifier = createASMifier(ANNOTATION_VISITOR, 0);
1020 text.add(asmifier.getText());
1021 text.add("}\n");
1022 return asmifier;
1023 }
1024
1025 @Override
1026 public void visitLineNumber(final int line, final Label start) {
1027 stringBuilder.setLength(0);
1028 stringBuilder.append(name).append(".visitLineNumber(").append(line).append(", ");
1029 appendLabel(start);
1030 stringBuilder.append(");\n");
1031 text.add(stringBuilder.toString());
1032 }
1033
1034 @Override
1035 public void visitMaxs(final int maxStack, final int maxLocals) {
1036 stringBuilder.setLength(0);
1037 stringBuilder
1038 .append(name)
1039 .append(".visitMaxs(")
1040 .append(maxStack)
1041 .append(", ")
1042 .append(maxLocals)
1043 .append(");\n");
1044 text.add(stringBuilder.toString());
1045 }
1046
1047 @Override
1048 public void visitMethodEnd() {
1049 stringBuilder.setLength(0);
1050 stringBuilder.append(name).append(VISIT_END);
1051 text.add(stringBuilder.toString());
1052 }
1053
1054 // -----------------------------------------------------------------------------------------------
1055 // Common methods
1056 // -----------------------------------------------------------------------------------------------
1057
1058 /**
1059 * Visits a class, field or method annotation.
1060 *
1061 * @param descriptor the class descriptor of the annotation class.
1062 * @param visible <tt>true</tt> if the annotation is visible at runtime.
1063 * @return a new {@link ASMifier} to visit the annotation values.
1064 */
1065 public ASMifier visitAnnotation(final String descriptor, final boolean visible) {
1066 stringBuilder.setLength(0);
1067 stringBuilder
1068 .append("{\n")
1069 .append(ANNOTATION_VISITOR0)
1070 .append(name)
1071 .append(".visitAnnotation(");
1072 appendConstant(descriptor);
1073 stringBuilder.append(", ").append(visible).append(");\n");
1074 text.add(stringBuilder.toString());
1075 ASMifier asmifier = createASMifier(ANNOTATION_VISITOR, 0);
1076 text.add(asmifier.getText());
1077 text.add("}\n");
1078 return asmifier;
1079 }
1080
1081 /**
1082 * Visits a class, field or method type annotation.
1083 *
1084 * @param typeRef a reference to the annotated type. The sort of this type reference must be
1085 * {@link org.eclipse.persistence.internal.libraries.asm.TypeReference#FIELD}. See {@link org.eclipse.persistence.internal.libraries.asm.TypeReference}.
1086 * @param typePath the path to the annotated type argument, wildcard bound, array element type, or
1087 * static inner type within 'typeRef'. May be <tt>null</tt> if the annotation targets
1088 * 'typeRef' as a whole.
1089 * @param descriptor the class descriptor of the annotation class.
1090 * @param visible <tt>true</tt> if the annotation is visible at runtime.
1091 * @return a new {@link ASMifier} to visit the annotation values.
1092 */
1093 public ASMifier visitTypeAnnotation(
1094 final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
1095 return visitTypeAnnotation("visitTypeAnnotation", typeRef, typePath, descriptor, visible);
1096 }
1097
1098 /**
1099 * Visits a class, field, method, instruction or try catch block type annotation.
1100 *
1101 * @param method the name of the visit method for this type of annotation.
1102 * @param typeRef a reference to the annotated type. The sort of this type reference must be
1103 * {@link org.eclipse.persistence.internal.libraries.asm.TypeReference#FIELD}. See {@link org.eclipse.persistence.internal.libraries.asm.TypeReference}.
1104 * @param typePath the path to the annotated type argument, wildcard bound, array element type, or
1105 * static inner type within 'typeRef'. May be <tt>null</tt> if the annotation targets
1106 * 'typeRef' as a whole.
1107 * @param descriptor the class descriptor of the annotation class.
1108 * @param visible <tt>true</tt> if the annotation is visible at runtime.
1109 * @return a new {@link ASMifier} to visit the annotation values.
1110 */
1111 public ASMifier visitTypeAnnotation(
1112 final String method,
1113 final int typeRef,
1114 final TypePath typePath,
1115 final String descriptor,
1116 final boolean visible) {
1117 stringBuilder.setLength(0);
1118 stringBuilder
1119 .append("{\n")
1120 .append(ANNOTATION_VISITOR0)
1121 .append(name)
1122 .append(".")
1123 .append(method)
1124 .append("(")
1125 .append(typeRef);
1126 if (typePath == null) {
1127 stringBuilder.append(", null, ");
1128 } else {
1129 stringBuilder.append(", TypePath.fromString(\"").append(typePath).append("\"), ");
1130 }
1131 appendConstant(descriptor);
1132 stringBuilder.append(", ").append(visible).append(");\n");
1133 text.add(stringBuilder.toString());
1134 ASMifier asmifier = createASMifier(ANNOTATION_VISITOR, 0);
1135 text.add(asmifier.getText());
1136 text.add("}\n");
1137 return asmifier;
1138 }
1139
1140 /**
1141 * Visit a class, field or method attribute.
1142 *
1143 * @param attribute an attribute.
1144 */
1145 public void visitAttribute(final Attribute attribute) {
1146 stringBuilder.setLength(0);
1147 stringBuilder.append("// ATTRIBUTE ").append(attribute.type).append('\n');
1148 if (attribute instanceof ASMifiable) {
1149 if (labelNames == null) {
1150 labelNames = new HashMap<Label, String>();
1151 }
1152 stringBuilder.append("{\n");
1153 StringBuffer stringBuffer = new StringBuffer();
1154 ((ASMifiable) attribute).asmify(stringBuffer, "attribute", labelNames);
1155 stringBuilder.append(stringBuffer.toString());
1156 stringBuilder.append(name).append(".visitAttribute(attribute);\n");
1157 stringBuilder.append("}\n");
1158 }
1159 text.add(stringBuilder.toString());
1160 }
1161
1162 // -----------------------------------------------------------------------------------------------
1163 // Utility methods
1164 // -----------------------------------------------------------------------------------------------
1165
1166 /**
1167 * Constructs a new {@link ASMifier}.
1168 *
1169 * @param visitorVariableName the name of the visitor variable in the produced code.
1170 * @param annotationVisitorId identifier of the annotation visitor variable in the produced code.
1171 * @return a new {@link ASMifier}.
1172 */
1173 protected ASMifier createASMifier(
1174 final String visitorVariableName, final int annotationVisitorId) {
1175 return new ASMifier(Opcodes.ASM6, visitorVariableName, annotationVisitorId);
1176 }
1177
1178 /**
1179 * Appends a string representation of the given access flags to {@link #stringBuilder}.
1180 *
1181 * @param accessFlags some access flags.
1182 */
1183 private void appendAccessFlags(final int accessFlags) {
1184 boolean isEmpty = true;
1185 if ((accessFlags & Opcodes.ACC_PUBLIC) != 0) {
1186 stringBuilder.append("ACC_PUBLIC");
1187 isEmpty = false;
1188 }
1189 if ((accessFlags & Opcodes.ACC_PRIVATE) != 0) {
1190 stringBuilder.append("ACC_PRIVATE");
1191 isEmpty = false;
1192 }
1193 if ((accessFlags & Opcodes.ACC_PROTECTED) != 0) {
1194 stringBuilder.append("ACC_PROTECTED");
1195 isEmpty = false;
1196 }
1197 if ((accessFlags & Opcodes.ACC_FINAL) != 0) {
1198 if (!isEmpty) {
1199 stringBuilder.append(" | ");
1200 }
1201 if ((accessFlags & ACCESS_MODULE) == 0) {
1202 stringBuilder.append("ACC_FINAL");
1203 } else {
1204 stringBuilder.append("ACC_TRANSITIVE");
1205 }
1206 isEmpty = false;
1207 }
1208 if ((accessFlags & Opcodes.ACC_STATIC) != 0) {
1209 if (!isEmpty) {
1210 stringBuilder.append(" | ");
1211 }
1212 stringBuilder.append("ACC_STATIC");
1213 isEmpty = false;
1214 }
1215 if ((accessFlags & (Opcodes.ACC_SYNCHRONIZED | Opcodes.ACC_SUPER | Opcodes.ACC_TRANSITIVE))
1216 != 0) {
1217 if (!isEmpty) {
1218 stringBuilder.append(" | ");
1219 }
1220 if ((accessFlags & ACCESS_CLASS) == 0) {
1221 if ((accessFlags & ACCESS_MODULE) == 0) {
1222 stringBuilder.append("ACC_SYNCHRONIZED");
1223 } else {
1224 stringBuilder.append("ACC_TRANSITIVE");
1341225 }
135 if (ok && "-debug".equals(args[0])) {
136 i = 1;
137 flags = 0;
138 if (args.length != 2) {
139 ok = false;
140 }
1226 } else {
1227 stringBuilder.append("ACC_SUPER");
1228 }
1229 isEmpty = false;
1230 }
1231 if ((accessFlags & (Opcodes.ACC_VOLATILE | Opcodes.ACC_BRIDGE | Opcodes.ACC_STATIC_PHASE))
1232 != 0) {
1233 if (!isEmpty) {
1234 stringBuilder.append(" | ");
1235 }
1236 if ((accessFlags & ACCESS_FIELD) == 0) {
1237 if ((accessFlags & ACCESS_MODULE) == 0) {
1238 stringBuilder.append("ACC_BRIDGE");
1239 } else {
1240 stringBuilder.append("ACC_STATIC_PHASE");
1411241 }
142 if (!ok) {
143 System.err
144 .println("Prints the ASM code to generate the given class.");
145 System.err.println("Usage: ASMifier [-debug] "
146 + "<fully qualified class name or class file name>");
147 return;
1242 } else {
1243 stringBuilder.append("ACC_VOLATILE");
1244 }
1245 isEmpty = false;
1246 }
1247 if ((accessFlags & Opcodes.ACC_VARARGS) != 0
1248 && (accessFlags & (ACCESS_CLASS | ACCESS_FIELD)) == 0) {
1249 if (!isEmpty) {
1250 stringBuilder.append(" | ");
1251 }
1252 stringBuilder.append("ACC_VARARGS");
1253 isEmpty = false;
1254 }
1255 if ((accessFlags & Opcodes.ACC_TRANSIENT) != 0 && (accessFlags & ACCESS_FIELD) != 0) {
1256 if (!isEmpty) {
1257 stringBuilder.append(" | ");
1258 }
1259 stringBuilder.append("ACC_TRANSIENT");
1260 isEmpty = false;
1261 }
1262 if ((accessFlags & Opcodes.ACC_NATIVE) != 0
1263 && (accessFlags & (ACCESS_CLASS | ACCESS_FIELD)) == 0) {
1264 if (!isEmpty) {
1265 stringBuilder.append(" | ");
1266 }
1267 stringBuilder.append("ACC_NATIVE");
1268 isEmpty = false;
1269 }
1270 if ((accessFlags & Opcodes.ACC_ENUM) != 0
1271 && (accessFlags & (ACCESS_CLASS | ACCESS_FIELD | ACCESS_INNER)) != 0) {
1272 if (!isEmpty) {
1273 stringBuilder.append(" | ");
1274 }
1275 stringBuilder.append("ACC_ENUM");
1276 isEmpty = false;
1277 }
1278 if ((accessFlags & Opcodes.ACC_ANNOTATION) != 0
1279 && (accessFlags & (ACCESS_CLASS | ACCESS_INNER)) != 0) {
1280 if (!isEmpty) {
1281 stringBuilder.append(" | ");
1282 }
1283 stringBuilder.append("ACC_ANNOTATION");
1284 isEmpty = false;
1285 }
1286 if ((accessFlags & Opcodes.ACC_ABSTRACT) != 0) {
1287 if (!isEmpty) {
1288 stringBuilder.append(" | ");
1289 }
1290 stringBuilder.append("ACC_ABSTRACT");
1291 isEmpty = false;
1292 }
1293 if ((accessFlags & Opcodes.ACC_INTERFACE) != 0) {
1294 if (!isEmpty) {
1295 stringBuilder.append(" | ");
1296 }
1297 stringBuilder.append("ACC_INTERFACE");
1298 isEmpty = false;
1299 }
1300 if ((accessFlags & Opcodes.ACC_STRICT) != 0) {
1301 if (!isEmpty) {
1302 stringBuilder.append(" | ");
1303 }
1304 stringBuilder.append("ACC_STRICT");
1305 isEmpty = false;
1306 }
1307 if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0) {
1308 if (!isEmpty) {
1309 stringBuilder.append(" | ");
1310 }
1311 stringBuilder.append("ACC_SYNTHETIC");
1312 isEmpty = false;
1313 }
1314 if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) {
1315 if (!isEmpty) {
1316 stringBuilder.append(" | ");
1317 }
1318 stringBuilder.append("ACC_DEPRECATED");
1319 isEmpty = false;
1320 }
1321 if ((accessFlags & (Opcodes.ACC_MANDATED | Opcodes.ACC_MODULE)) != 0) {
1322 if (!isEmpty) {
1323 stringBuilder.append(" | ");
1324 }
1325 if ((accessFlags & ACCESS_CLASS) == 0) {
1326 stringBuilder.append("ACC_MANDATED");
1327 } else {
1328 stringBuilder.append("ACC_MODULE");
1329 }
1330 isEmpty = false;
1331 }
1332 if (isEmpty) {
1333 stringBuilder.append('0');
1334 }
1335 }
1336
1337 /**
1338 * Appends a string representation of the given constant to {@link #stringBuilder}.
1339 *
1340 * @param value a {@link String}, {@link Type}, {@link Handle}, {@link Byte}, {@link Short},
1341 * {@link Character}, {@link Integer}, {@link Float}, {@link Long} or {@link Double} object,
1342 * or an array of primitive values. May be <tt>null</tt>.
1343 */
1344 protected void appendConstant(final Object value) {
1345 if (value == null) {
1346 stringBuilder.append("null");
1347 } else if (value instanceof String) {
1348 appendString(stringBuilder, (String) value);
1349 } else if (value instanceof Type) {
1350 stringBuilder.append("Type.getType(\"");
1351 stringBuilder.append(((Type) value).getDescriptor());
1352 stringBuilder.append("\")");
1353 } else if (value instanceof Handle) {
1354 stringBuilder.append("new Handle(");
1355 Handle handle = (Handle) value;
1356 stringBuilder.append("Opcodes.").append(HANDLE_TAG[handle.getTag()]).append(", \"");
1357 stringBuilder.append(handle.getOwner()).append("\", \"");
1358 stringBuilder.append(handle.getName()).append("\", \"");
1359 stringBuilder.append(handle.getDesc()).append("\", ");
1360 stringBuilder.append(handle.isInterface()).append(")");
1361 } else if (value instanceof Byte) {
1362 stringBuilder.append("new Byte((byte)").append(value).append(')');
1363 } else if (value instanceof Boolean) {
1364 stringBuilder.append(((Boolean) value).booleanValue() ? "Boolean.TRUE" : "Boolean.FALSE");
1365 } else if (value instanceof Short) {
1366 stringBuilder.append("new Short((short)").append(value).append(')');
1367 } else if (value instanceof Character) {
1368 stringBuilder
1369 .append("new Character((char)")
1370 .append((int) ((Character) value).charValue())
1371 .append(')');
1372 } else if (value instanceof Integer) {
1373 stringBuilder.append("new Integer(").append(value).append(')');
1374 } else if (value instanceof Float) {
1375 stringBuilder.append("new Float(\"").append(value).append("\")");
1376 } else if (value instanceof Long) {
1377 stringBuilder.append("new Long(").append(value).append("L)");
1378 } else if (value instanceof Double) {
1379 stringBuilder.append("new Double(\"").append(value).append("\")");
1380 } else if (value instanceof byte[]) {
1381 byte[] byteArray = (byte[]) value;
1382 stringBuilder.append("new byte[] {");
1383 for (int i = 0; i < byteArray.length; i++) {
1384 stringBuilder.append(i == 0 ? "" : ",").append(byteArray[i]);
1385 }
1386 stringBuilder.append('}');
1387 } else if (value instanceof boolean[]) {
1388 boolean[] booleanArray = (boolean[]) value;
1389 stringBuilder.append("new boolean[] {");
1390 for (int i = 0; i < booleanArray.length; i++) {
1391 stringBuilder.append(i == 0 ? "" : ",").append(booleanArray[i]);
1392 }
1393 stringBuilder.append('}');
1394 } else if (value instanceof short[]) {
1395 short[] shortArray = (short[]) value;
1396 stringBuilder.append("new short[] {");
1397 for (int i = 0; i < shortArray.length; i++) {
1398 stringBuilder.append(i == 0 ? "" : ",").append("(short)").append(shortArray[i]);
1399 }
1400 stringBuilder.append('}');
1401 } else if (value instanceof char[]) {
1402 char[] charArray = (char[]) value;
1403 stringBuilder.append("new char[] {");
1404 for (int i = 0; i < charArray.length; i++) {
1405 stringBuilder.append(i == 0 ? "" : ",").append("(char)").append((int) charArray[i]);
1406 }
1407 stringBuilder.append('}');
1408 } else if (value instanceof int[]) {
1409 int[] intArray = (int[]) value;
1410 stringBuilder.append("new int[] {");
1411 for (int i = 0; i < intArray.length; i++) {
1412 stringBuilder.append(i == 0 ? "" : ",").append(intArray[i]);
1413 }
1414 stringBuilder.append('}');
1415 } else if (value instanceof long[]) {
1416 long[] longArray = (long[]) value;
1417 stringBuilder.append("new long[] {");
1418 for (int i = 0; i < longArray.length; i++) {
1419 stringBuilder.append(i == 0 ? "" : ",").append(longArray[i]).append('L');
1420 }
1421 stringBuilder.append('}');
1422 } else if (value instanceof float[]) {
1423 float[] floatArray = (float[]) value;
1424 stringBuilder.append("new float[] {");
1425 for (int i = 0; i < floatArray.length; i++) {
1426 stringBuilder.append(i == 0 ? "" : ",").append(floatArray[i]).append('f');
1427 }
1428 stringBuilder.append('}');
1429 } else if (value instanceof double[]) {
1430 double[] doubleArray = (double[]) value;
1431 stringBuilder.append("new double[] {");
1432 for (int i = 0; i < doubleArray.length; i++) {
1433 stringBuilder.append(i == 0 ? "" : ",").append(doubleArray[i]).append('d');
1434 }
1435 stringBuilder.append('}');
1436 }
1437 }
1438
1439 /**
1440 * Calls {@link #declareLabel} for each label in the given stack map frame types.
1441 *
1442 * @param nTypes the number of stack map frame types in 'frameTypes'.
1443 * @param frameTypes an array of stack map frame types, in the format described in {@link
1444 * org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitFrame}.
1445 */
1446 private void declareFrameTypes(final int nTypes, final Object[] frameTypes) {
1447 for (int i = 0; i < nTypes; ++i) {
1448 if (frameTypes[i] instanceof Label) {
1449 declareLabel((Label) frameTypes[i]);
1450 }
1451 }
1452 }
1453
1454 /**
1455 * Appends the given stack map frame types to {@link #stringBuilder}.
1456 *
1457 * @param nTypes the number of stack map frame types in 'frameTypes'.
1458 * @param frameTypes an array of stack map frame types, in the format described in {@link
1459 * org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitFrame}.
1460 */
1461 private void appendFrameTypes(final int nTypes, final Object[] frameTypes) {
1462 for (int i = 0; i < nTypes; ++i) {
1463 if (i > 0) {
1464 stringBuilder.append(", ");
1465 }
1466 if (frameTypes[i] instanceof String) {
1467 appendConstant(frameTypes[i]);
1468 } else if (frameTypes[i] instanceof Integer) {
1469 switch (((Integer) frameTypes[i]).intValue()) {
1470 case 0:
1471 stringBuilder.append("Opcodes.TOP");
1472 break;
1473 case 1:
1474 stringBuilder.append("Opcodes.INTEGER");
1475 break;
1476 case 2:
1477 stringBuilder.append("Opcodes.FLOAT");
1478 break;
1479 case 3:
1480 stringBuilder.append("Opcodes.DOUBLE");
1481 break;
1482 case 4:
1483 stringBuilder.append("Opcodes.LONG");
1484 break;
1485 case 5:
1486 stringBuilder.append("Opcodes.NULL");
1487 break;
1488 case 6:
1489 stringBuilder.append("Opcodes.UNINITIALIZED_THIS");
1490 break;
1491 default:
1492 throw new IllegalArgumentException();
1481493 }
149 ClassReader cr;
150 if (args[i].endsWith(".class") || args[i].indexOf('\\') > -1
151 || args[i].indexOf('/') > -1) {
152 cr = new ClassReader(new FileInputStream(args[i]));
153 } else {
154 cr = new ClassReader(args[i]);
155 }
156 cr.accept(new TraceClassVisitor(null, new ASMifier(), new PrintWriter(
157 System.out)), flags);
158 }
159
160 // ------------------------------------------------------------------------
161 // Classes
162 // ------------------------------------------------------------------------
163
164 @Override
165 public void visit(final int version, final int access, final String name,
166 final String signature, final String superName,
167 final String[] interfaces) {
168 String simpleName;
169 int n = name.lastIndexOf('/');
170 if (n == -1) {
171 simpleName = name;
172 } else {
173 text.add("package asm." + name.substring(0, n).replace('/', '.')
174 + ";\n");
175 simpleName = name.substring(n + 1).replace('-', '_');
176 }
177 text.add("import java.util.*;\n");
178 text.add("import org.eclipse.persistence.internal.libraries.asm.*;\n");
179 text.add("public class " + simpleName + "Dump implements Opcodes {\n\n");
180 text.add("public static byte[] dump () throws Exception {\n\n");
181 text.add("ClassWriter cw = new ClassWriter(0);\n");
182 text.add("FieldVisitor fv;\n");
183 text.add("MethodVisitor mv;\n");
184 text.add("AnnotationVisitor av0;\n\n");
185
186 buf.setLength(0);
187 buf.append("cw.visit(");
188 switch (version) {
189 case Opcodes.V1_1:
190 buf.append("V1_1");
191 break;
192 case Opcodes.V1_2:
193 buf.append("V1_2");
194 break;
195 case Opcodes.V1_3:
196 buf.append("V1_3");
197 break;
198 case Opcodes.V1_4:
199 buf.append("V1_4");
200 break;
201 case Opcodes.V1_5:
202 buf.append("V1_5");
203 break;
204 case Opcodes.V1_6:
205 buf.append("V1_6");
206 break;
207 case Opcodes.V1_7:
208 buf.append("V1_7");
209 break;
210 case Opcodes.V1_8:
211 buf.append("V1_8");
212 break;
213 case Opcodes.V1_9:
214 buf.append("V1_9");
215 break;
216 default:
217 buf.append(version);
218 break;
219 }
220 buf.append(", ");
221 appendAccess(access | ACCESS_CLASS);
222 buf.append(", ");
223 appendConstant(name);
224 buf.append(", ");
225 appendConstant(signature);
226 buf.append(", ");
227 appendConstant(superName);
228 buf.append(", ");
229 if (interfaces != null && interfaces.length > 0) {
230 buf.append("new String[] {");
231 for (int i = 0; i < interfaces.length; ++i) {
232 buf.append(i == 0 ? " " : ", ");
233 appendConstant(interfaces[i]);
234 }
235 buf.append(" }");
236 } else {
237 buf.append("null");
238 }
239 buf.append(");\n\n");
240 text.add(buf.toString());
241 }
242
243 @Override
244 public void visitSource(final String file, final String debug) {
245 buf.setLength(0);
246 buf.append("cw.visitSource(");
247 appendConstant(file);
248 buf.append(", ");
249 appendConstant(debug);
250 buf.append(");\n\n");
251 text.add(buf.toString());
252 }
253
254 @Override
255 public Printer visitModule() {
256 ASMifier a = createASMifier("mdv", 0);
257 text.add("ModuleVisitor mdv = cw.visitModule();\n");
258 text.add(a.getText());
259 return a;
260 }
261
262 @Override
263 public void visitOuterClass(final String owner, final String name,
264 final String desc) {
265 buf.setLength(0);
266 buf.append("cw.visitOuterClass(");
267 appendConstant(owner);
268 buf.append(", ");
269 appendConstant(name);
270 buf.append(", ");
271 appendConstant(desc);
272 buf.append(");\n\n");
273 text.add(buf.toString());
274 }
275
276 @Override
277 public ASMifier visitClassAnnotation(final String desc,
278 final boolean visible) {
279 return visitAnnotation(desc, visible);
280 }
281
282 @Override
283 public ASMifier visitClassTypeAnnotation(final int typeRef,
284 final TypePath typePath, final String desc, final boolean visible) {
285 return visitTypeAnnotation(typeRef, typePath, desc, visible);
286 }
287
288 @Override
289 public void visitClassAttribute(final Attribute attr) {
290 visitAttribute(attr);
291 }
292
293 @Override
294 public void visitInnerClass(final String name, final String outerName,
295 final String innerName, final int access) {
296 buf.setLength(0);
297 buf.append("cw.visitInnerClass(");
298 appendConstant(name);
299 buf.append(", ");
300 appendConstant(outerName);
301 buf.append(", ");
302 appendConstant(innerName);
303 buf.append(", ");
304 appendAccess(access | ACCESS_INNER);
305 buf.append(");\n\n");
306 text.add(buf.toString());
307 }
308
309 @Override
310 public ASMifier visitField(final int access, final String name,
311 final String desc, final String signature, final Object value) {
312 buf.setLength(0);
313 buf.append("{\n");
314 buf.append("fv = cw.visitField(");
315 appendAccess(access | ACCESS_FIELD);
316 buf.append(", ");
317 appendConstant(name);
318 buf.append(", ");
319 appendConstant(desc);
320 buf.append(", ");
321 appendConstant(signature);
322 buf.append(", ");
323 appendConstant(value);
324 buf.append(");\n");
325 text.add(buf.toString());
326 ASMifier a = createASMifier("fv", 0);
327 text.add(a.getText());
328 text.add("}\n");
329 return a;
330 }
331
332 @Override
333 public ASMifier visitMethod(final int access, final String name,
334 final String desc, final String signature, final String[] exceptions) {
335 buf.setLength(0);
336 buf.append("{\n");
337 buf.append("mv = cw.visitMethod(");
338 appendAccess(access);
339 buf.append(", ");
340 appendConstant(name);
341 buf.append(", ");
342 appendConstant(desc);
343 buf.append(", ");
344 appendConstant(signature);
345 buf.append(", ");
346 if (exceptions != null && exceptions.length > 0) {
347 buf.append("new String[] {");
348 for (int i = 0; i < exceptions.length; ++i) {
349 buf.append(i == 0 ? " " : ", ");
350 appendConstant(exceptions[i]);
351 }
352 buf.append(" }");
353 } else {
354 buf.append("null");
355 }
356 buf.append(");\n");
357 text.add(buf.toString());
358 ASMifier a = createASMifier("mv", 0);
359 text.add(a.getText());
360 text.add("}\n");
361 return a;
362 }
363
364 @Override
365 public void visitClassEnd() {
366 text.add("cw.visitEnd();\n\n");
367 text.add("return cw.toByteArray();\n");
368 text.add("}\n");
369 text.add("}\n");
370 }
371
372 // ------------------------------------------------------------------------
373 // Module
374 // ------------------------------------------------------------------------
375
376 @Override
377 public void visitRequire(String module, int access) {
378 buf.setLength(0);
379 buf.append("mdv.visitRequire(");
380 appendConstant(buf, module);
381 buf.append(", ");
382 appendAccess(access);
383 buf.append(");\n");
384 text.add(buf.toString());
385 }
386
387 @Override
388 public void visitExport(String packaze, String... modules) {
389 buf.setLength(0);
390 buf.append("mdv.visitExport(");
391 appendConstant(buf, packaze);
392 if (modules != null && modules.length > 0) {
393 buf.append(", new String[] {");
394 for (int i = 0; i < modules.length; ++i) {
395 buf.append(i == 0 ? " " : ", ");
396 appendConstant(modules[i]);
397 }
398 buf.append(" }");
399 }
400 buf.append(");\n");
401 text.add(buf.toString());
402 }
403
404 @Override
405 public void visitUse(String service) {
406 buf.setLength(0);
407 buf.append("mdv.visitUse(");
408 appendConstant(buf, service);
409 buf.append(");\n");
410 text.add(buf.toString());
411 }
412
413 @Override
414 public void visitProvide(String service, String impl) {
415 buf.setLength(0);
416 buf.append("mdv.visitProvide(");
417 appendConstant(buf, service);
418 buf.append(", ");
419 appendConstant(buf, impl);
420 buf.append(");\n");
421 text.add(buf.toString());
422 }
423
424 @Override
425 public void visitModuleEnd() {
426 text.add("mdv.visitEnd();\n");
427 }
428
429
430 // ------------------------------------------------------------------------
431 // Annotations
432 // ------------------------------------------------------------------------
433
434 @Override
435 public void visit(final String name, final Object value) {
436 buf.setLength(0);
437 buf.append("av").append(id).append(".visit(");
438 appendConstant(buf, name);
439 buf.append(", ");
440 appendConstant(buf, value);
441 buf.append(");\n");
442 text.add(buf.toString());
443 }
444
445 @Override
446 public void visitEnum(final String name, final String desc,
447 final String value) {
448 buf.setLength(0);
449 buf.append("av").append(id).append(".visitEnum(");
450 appendConstant(buf, name);
451 buf.append(", ");
452 appendConstant(buf, desc);
453 buf.append(", ");
454 appendConstant(buf, value);
455 buf.append(");\n");
456 text.add(buf.toString());
457 }
458
459 @Override
460 public ASMifier visitAnnotation(final String name, final String desc) {
461 buf.setLength(0);
462 buf.append("{\n");
463 buf.append("AnnotationVisitor av").append(id + 1).append(" = av");
464 buf.append(id).append(".visitAnnotation(");
465 appendConstant(buf, name);
466 buf.append(", ");
467 appendConstant(buf, desc);
468 buf.append(");\n");
469 text.add(buf.toString());
470 ASMifier a = createASMifier("av", id + 1);
471 text.add(a.getText());
472 text.add("}\n");
473 return a;
474 }
475
476 @Override
477 public ASMifier visitArray(final String name) {
478 buf.setLength(0);
479 buf.append("{\n");
480 buf.append("AnnotationVisitor av").append(id + 1).append(" = av");
481 buf.append(id).append(".visitArray(");
482 appendConstant(buf, name);
483 buf.append(");\n");
484 text.add(buf.toString());
485 ASMifier a = createASMifier("av", id + 1);
486 text.add(a.getText());
487 text.add("}\n");
488 return a;
489 }
490
491 @Override
492 public void visitAnnotationEnd() {
493 buf.setLength(0);
494 buf.append("av").append(id).append(".visitEnd();\n");
495 text.add(buf.toString());
496 }
497
498 // ------------------------------------------------------------------------
499 // Fields
500 // ------------------------------------------------------------------------
501
502 @Override
503 public ASMifier visitFieldAnnotation(final String desc,
504 final boolean visible) {
505 return visitAnnotation(desc, visible);
506 }
507
508 @Override
509 public ASMifier visitFieldTypeAnnotation(final int typeRef,
510 final TypePath typePath, final String desc, final boolean visible) {
511 return visitTypeAnnotation(typeRef, typePath, desc, visible);
512 }
513
514 @Override
515 public void visitFieldAttribute(final Attribute attr) {
516 visitAttribute(attr);
517 }
518
519 @Override
520 public void visitFieldEnd() {
521 buf.setLength(0);
522 buf.append(name).append(".visitEnd();\n");
523 text.add(buf.toString());
524 }
525
526 // ------------------------------------------------------------------------
527 // Methods
528 // ------------------------------------------------------------------------
529
530 @Override
531 public void visitParameter(String parameterName, int access) {
532 buf.setLength(0);
533 buf.append(name).append(".visitParameter(");
534 appendString(buf, parameterName);
535 buf.append(", ");
536 appendAccess(access);
537 text.add(buf.append(");\n").toString());
538 }
539
540 @Override
541 public ASMifier visitAnnotationDefault() {
542 buf.setLength(0);
543 buf.append("{\n").append("av0 = ").append(name)
544 .append(".visitAnnotationDefault();\n");
545 text.add(buf.toString());
546 ASMifier a = createASMifier("av", 0);
547 text.add(a.getText());
548 text.add("}\n");
549 return a;
550 }
551
552 @Override
553 public ASMifier visitMethodAnnotation(final String desc,
554 final boolean visible) {
555 return visitAnnotation(desc, visible);
556 }
557
558 @Override
559 public ASMifier visitMethodTypeAnnotation(final int typeRef,
560 final TypePath typePath, final String desc, final boolean visible) {
561 return visitTypeAnnotation(typeRef, typePath, desc, visible);
562 }
563
564 @Override
565 public ASMifier visitParameterAnnotation(final int parameter,
566 final String desc, final boolean visible) {
567 buf.setLength(0);
568 buf.append("{\n").append("av0 = ").append(name)
569 .append(".visitParameterAnnotation(").append(parameter)
570 .append(", ");
571 appendConstant(desc);
572 buf.append(", ").append(visible).append(");\n");
573 text.add(buf.toString());
574 ASMifier a = createASMifier("av", 0);
575 text.add(a.getText());
576 text.add("}\n");
577 return a;
578 }
579
580 @Override
581 public void visitMethodAttribute(final Attribute attr) {
582 visitAttribute(attr);
583 }
584
585 @Override
586 public void visitCode() {
587 text.add(name + ".visitCode();\n");
588 }
589
590 @Override
591 public void visitFrame(final int type, final int nLocal,
592 final Object[] local, final int nStack, final Object[] stack) {
593 buf.setLength(0);
594 switch (type) {
595 case Opcodes.F_NEW:
596 case Opcodes.F_FULL:
597 declareFrameTypes(nLocal, local);
598 declareFrameTypes(nStack, stack);
599 if (type == Opcodes.F_NEW) {
600 buf.append(name).append(".visitFrame(Opcodes.F_NEW, ");
601 } else {
602 buf.append(name).append(".visitFrame(Opcodes.F_FULL, ");
603 }
604 buf.append(nLocal).append(", new Object[] {");
605 appendFrameTypes(nLocal, local);
606 buf.append("}, ").append(nStack).append(", new Object[] {");
607 appendFrameTypes(nStack, stack);
608 buf.append('}');
609 break;
610 case Opcodes.F_APPEND:
611 declareFrameTypes(nLocal, local);
612 buf.append(name).append(".visitFrame(Opcodes.F_APPEND,")
613 .append(nLocal).append(", new Object[] {");
614 appendFrameTypes(nLocal, local);
615 buf.append("}, 0, null");
616 break;
617 case Opcodes.F_CHOP:
618 buf.append(name).append(".visitFrame(Opcodes.F_CHOP,")
619 .append(nLocal).append(", null, 0, null");
620 break;
621 case Opcodes.F_SAME:
622 buf.append(name).append(
623 ".visitFrame(Opcodes.F_SAME, 0, null, 0, null");
624 break;
625 case Opcodes.F_SAME1:
626 declareFrameTypes(1, stack);
627 buf.append(name).append(
628 ".visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] {");
629 appendFrameTypes(1, stack);
630 buf.append('}');
631 break;
632 }
633 buf.append(");\n");
634 text.add(buf.toString());
635 }
636
637 @Override
638 public void visitInsn(final int opcode) {
639 buf.setLength(0);
640 buf.append(name).append(".visitInsn(").append(OPCODES[opcode])
641 .append(");\n");
642 text.add(buf.toString());
643 }
644
645 @Override
646 public void visitIntInsn(final int opcode, final int operand) {
647 buf.setLength(0);
648 buf.append(name)
649 .append(".visitIntInsn(")
650 .append(OPCODES[opcode])
651 .append(", ")
652 .append(opcode == Opcodes.NEWARRAY ? TYPES[operand] : Integer
653 .toString(operand)).append(");\n");
654 text.add(buf.toString());
655 }
656
657 @Override
658 public void visitVarInsn(final int opcode, final int var) {
659 buf.setLength(0);
660 buf.append(name).append(".visitVarInsn(").append(OPCODES[opcode])
661 .append(", ").append(var).append(");\n");
662 text.add(buf.toString());
663 }
664
665 @Override
666 public void visitTypeInsn(final int opcode, final String type) {
667 buf.setLength(0);
668 buf.append(name).append(".visitTypeInsn(").append(OPCODES[opcode])
669 .append(", ");
670 appendConstant(type);
671 buf.append(");\n");
672 text.add(buf.toString());
673 }
674
675 @Override
676 public void visitFieldInsn(final int opcode, final String owner,
677 final String name, final String desc) {
678 buf.setLength(0);
679 buf.append(this.name).append(".visitFieldInsn(")
680 .append(OPCODES[opcode]).append(", ");
681 appendConstant(owner);
682 buf.append(", ");
683 appendConstant(name);
684 buf.append(", ");
685 appendConstant(desc);
686 buf.append(");\n");
687 text.add(buf.toString());
688 }
689
690 @Deprecated
691 @Override
692 public void visitMethodInsn(final int opcode, final String owner,
693 final String name, final String desc) {
694 if (api >= Opcodes.ASM5) {
695 super.visitMethodInsn(opcode, owner, name, desc);
696 return;
697 }
698 doVisitMethodInsn(opcode, owner, name, desc,
699 opcode == Opcodes.INVOKEINTERFACE);
700 }
701
702 @Override
703 public void visitMethodInsn(final int opcode, final String owner,
704 final String name, final String desc, final boolean itf) {
705 if (api < Opcodes.ASM5) {
706 super.visitMethodInsn(opcode, owner, name, desc, itf);
707 return;
708 }
709 doVisitMethodInsn(opcode, owner, name, desc, itf);
710 }
711
712 private void doVisitMethodInsn(final int opcode, final String owner,
713 final String name, final String desc, final boolean itf) {
714 buf.setLength(0);
715 buf.append(this.name).append(".visitMethodInsn(")
716 .append(OPCODES[opcode]).append(", ");
717 appendConstant(owner);
718 buf.append(", ");
719 appendConstant(name);
720 buf.append(", ");
721 appendConstant(desc);
722 buf.append(", ");
723 buf.append(itf ? "true" : "false");
724 buf.append(");\n");
725 text.add(buf.toString());
726 }
727
728 @Override
729 public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
730 Object... bsmArgs) {
731 buf.setLength(0);
732 buf.append(this.name).append(".visitInvokeDynamicInsn(");
733 appendConstant(name);
734 buf.append(", ");
735 appendConstant(desc);
736 buf.append(", ");
737 appendConstant(bsm);
738 buf.append(", new Object[]{");
739 for (int i = 0; i < bsmArgs.length; ++i) {
740 appendConstant(bsmArgs[i]);
741 if (i != bsmArgs.length - 1) {
742 buf.append(", ");
743 }
744 }
745 buf.append("});\n");
746 text.add(buf.toString());
747 }
748
749 @Override
750 public void visitJumpInsn(final int opcode, final Label label) {
751 buf.setLength(0);
752 declareLabel(label);
753 buf.append(name).append(".visitJumpInsn(").append(OPCODES[opcode])
754 .append(", ");
755 appendLabel(label);
756 buf.append(");\n");
757 text.add(buf.toString());
758 }
759
760 @Override
761 public void visitLabel(final Label label) {
762 buf.setLength(0);
763 declareLabel(label);
764 buf.append(name).append(".visitLabel(");
765 appendLabel(label);
766 buf.append(");\n");
767 text.add(buf.toString());
768 }
769
770 @Override
771 public void visitLdcInsn(final Object cst) {
772 buf.setLength(0);
773 buf.append(name).append(".visitLdcInsn(");
774 appendConstant(cst);
775 buf.append(");\n");
776 text.add(buf.toString());
777 }
778
779 @Override
780 public void visitIincInsn(final int var, final int increment) {
781 buf.setLength(0);
782 buf.append(name).append(".visitIincInsn(").append(var).append(", ")
783 .append(increment).append(");\n");
784 text.add(buf.toString());
785 }
786
787 @Override
788 public void visitTableSwitchInsn(final int min, final int max,
789 final Label dflt, final Label... labels) {
790 buf.setLength(0);
791 for (int i = 0; i < labels.length; ++i) {
792 declareLabel(labels[i]);
793 }
794 declareLabel(dflt);
795
796 buf.append(name).append(".visitTableSwitchInsn(").append(min)
797 .append(", ").append(max).append(", ");
798 appendLabel(dflt);
799 buf.append(", new Label[] {");
800 for (int i = 0; i < labels.length; ++i) {
801 buf.append(i == 0 ? " " : ", ");
802 appendLabel(labels[i]);
803 }
804 buf.append(" });\n");
805 text.add(buf.toString());
806 }
807
808 @Override
809 public void visitLookupSwitchInsn(final Label dflt, final int[] keys,
810 final Label[] labels) {
811 buf.setLength(0);
812 for (int i = 0; i < labels.length; ++i) {
813 declareLabel(labels[i]);
814 }
815 declareLabel(dflt);
816
817 buf.append(name).append(".visitLookupSwitchInsn(");
818 appendLabel(dflt);
819 buf.append(", new int[] {");
820 for (int i = 0; i < keys.length; ++i) {
821 buf.append(i == 0 ? " " : ", ").append(keys[i]);
822 }
823 buf.append(" }, new Label[] {");
824 for (int i = 0; i < labels.length; ++i) {
825 buf.append(i == 0 ? " " : ", ");
826 appendLabel(labels[i]);
827 }
828 buf.append(" });\n");
829 text.add(buf.toString());
830 }
831
832 @Override
833 public void visitMultiANewArrayInsn(final String desc, final int dims) {
834 buf.setLength(0);
835 buf.append(name).append(".visitMultiANewArrayInsn(");
836 appendConstant(desc);
837 buf.append(", ").append(dims).append(");\n");
838 text.add(buf.toString());
839 }
840
841 @Override
842 public ASMifier visitInsnAnnotation(final int typeRef,
843 final TypePath typePath, final String desc, final boolean visible) {
844 return visitTypeAnnotation("visitInsnAnnotation", typeRef, typePath,
845 desc, visible);
846 }
847
848 @Override
849 public void visitTryCatchBlock(final Label start, final Label end,
850 final Label handler, final String type) {
851 buf.setLength(0);
852 declareLabel(start);
853 declareLabel(end);
854 declareLabel(handler);
855 buf.append(name).append(".visitTryCatchBlock(");
856 appendLabel(start);
857 buf.append(", ");
858 appendLabel(end);
859 buf.append(", ");
860 appendLabel(handler);
861 buf.append(", ");
862 appendConstant(type);
863 buf.append(");\n");
864 text.add(buf.toString());
865 }
866
867 @Override
868 public ASMifier visitTryCatchAnnotation(final int typeRef,
869 final TypePath typePath, final String desc, final boolean visible) {
870 return visitTypeAnnotation("visitTryCatchAnnotation", typeRef,
871 typePath, desc, visible);
872 }
873
874 @Override
875 public void visitLocalVariable(final String name, final String desc,
876 final String signature, final Label start, final Label end,
877 final int index) {
878 buf.setLength(0);
879 buf.append(this.name).append(".visitLocalVariable(");
880 appendConstant(name);
881 buf.append(", ");
882 appendConstant(desc);
883 buf.append(", ");
884 appendConstant(signature);
885 buf.append(", ");
886 appendLabel(start);
887 buf.append(", ");
888 appendLabel(end);
889 buf.append(", ").append(index).append(");\n");
890 text.add(buf.toString());
891 }
892
893 @Override
894 public Printer visitLocalVariableAnnotation(int typeRef, TypePath typePath,
895 Label[] start, Label[] end, int[] index, String desc,
896 boolean visible) {
897 buf.setLength(0);
898 buf.append("{\n").append("av0 = ").append(name)
899 .append(".visitLocalVariableAnnotation(");
900 buf.append(typeRef);
901 if (typePath == null) {
902 buf.append(", null, ");
903 } else {
904 buf.append(", TypePath.fromString(\"").append(typePath).append("\"), ");
905 }
906 buf.append("new Label[] {");
907 for (int i = 0; i < start.length; ++i) {
908 buf.append(i == 0 ? " " : ", ");
909 appendLabel(start[i]);
910 }
911 buf.append(" }, new Label[] {");
912 for (int i = 0; i < end.length; ++i) {
913 buf.append(i == 0 ? " " : ", ");
914 appendLabel(end[i]);
915 }
916 buf.append(" }, new int[] {");
917 for (int i = 0; i < index.length; ++i) {
918 buf.append(i == 0 ? " " : ", ").append(index[i]);
919 }
920 buf.append(" }, ");
921 appendConstant(desc);
922 buf.append(", ").append(visible).append(");\n");
923 text.add(buf.toString());
924 ASMifier a = createASMifier("av", 0);
925 text.add(a.getText());
926 text.add("}\n");
927 return a;
928 }
929
930 @Override
931 public void visitLineNumber(final int line, final Label start) {
932 buf.setLength(0);
933 buf.append(name).append(".visitLineNumber(").append(line).append(", ");
934 appendLabel(start);
935 buf.append(");\n");
936 text.add(buf.toString());
937 }
938
939 @Override
940 public void visitMaxs(final int maxStack, final int maxLocals) {
941 buf.setLength(0);
942 buf.append(name).append(".visitMaxs(").append(maxStack).append(", ")
943 .append(maxLocals).append(");\n");
944 text.add(buf.toString());
945 }
946
947 @Override
948 public void visitMethodEnd() {
949 buf.setLength(0);
950 buf.append(name).append(".visitEnd();\n");
951 text.add(buf.toString());
952 }
953
954 // ------------------------------------------------------------------------
955 // Common methods
956 // ------------------------------------------------------------------------
957
958 public ASMifier visitAnnotation(final String desc, final boolean visible) {
959 buf.setLength(0);
960 buf.append("{\n").append("av0 = ").append(name)
961 .append(".visitAnnotation(");
962 appendConstant(desc);
963 buf.append(", ").append(visible).append(");\n");
964 text.add(buf.toString());
965 ASMifier a = createASMifier("av", 0);
966 text.add(a.getText());
967 text.add("}\n");
968 return a;
969 }
970
971 public ASMifier visitTypeAnnotation(final int typeRef,
972 final TypePath typePath, final String desc, final boolean visible) {
973 return visitTypeAnnotation("visitTypeAnnotation", typeRef, typePath,
974 desc, visible);
975 }
976
977 public ASMifier visitTypeAnnotation(final String method, final int typeRef,
978 final TypePath typePath, final String desc, final boolean visible) {
979 buf.setLength(0);
980 buf.append("{\n").append("av0 = ").append(name).append(".")
981 .append(method).append("(");
982 buf.append(typeRef);
983 if (typePath == null) {
984 buf.append(", null, ");
985 } else {
986 buf.append(", TypePath.fromString(\"").append(typePath).append("\"), ");
987 }
988 appendConstant(desc);
989 buf.append(", ").append(visible).append(");\n");
990 text.add(buf.toString());
991 ASMifier a = createASMifier("av", 0);
992 text.add(a.getText());
993 text.add("}\n");
994 return a;
995 }
996
997 public void visitAttribute(final Attribute attr) {
998 buf.setLength(0);
999 buf.append("// ATTRIBUTE ").append(attr.type).append('\n');
1000 if (attr instanceof ASMifiable) {
1001 if (labelNames == null) {
1002 labelNames = new HashMap<Label, String>();
1003 }
1004 buf.append("{\n");
1005 ((ASMifiable) attr).asmify(buf, "attr", labelNames);
1006 buf.append(name).append(".visitAttribute(attr);\n");
1007 buf.append("}\n");
1008 }
1009 text.add(buf.toString());
1010 }
1011
1012 // ------------------------------------------------------------------------
1013 // Utility methods
1014 // ------------------------------------------------------------------------
1015
1016 protected ASMifier createASMifier(final String name, final int id) {
1017 return new ASMifier(Opcodes.ASM6, name, id);
1018 }
1019
1020 /**
1021 * Appends a string representation of the given access modifiers to
1022 * {@link #buf buf}.
1023 *
1024 * @param access
1025 * some access modifiers.
1026 */
1027 void appendAccess(final int access) {
1028 boolean first = true;
1029 if ((access & Opcodes.ACC_PUBLIC) != 0) {
1030 buf.append("ACC_PUBLIC");
1031 first = false;
1032 }
1033 if ((access & Opcodes.ACC_PRIVATE) != 0) {
1034 buf.append("ACC_PRIVATE");
1035 first = false;
1036 }
1037 if ((access & Opcodes.ACC_PROTECTED) != 0) {
1038 buf.append("ACC_PROTECTED");
1039 first = false;
1040 }
1041 if ((access & Opcodes.ACC_FINAL) != 0) {
1042 if (!first) {
1043 buf.append(" + ");
1044 }
1045 buf.append("ACC_FINAL");
1046 first = false;
1047 }
1048 if ((access & Opcodes.ACC_STATIC) != 0) {
1049 if (!first) {
1050 buf.append(" + ");
1051 }
1052 buf.append("ACC_STATIC");
1053 first = false;
1054 }
1055 if ((access & Opcodes.ACC_SYNCHRONIZED) != 0) {
1056 if (!first) {
1057 buf.append(" + ");
1058 }
1059 if ((access & ACCESS_CLASS) == 0) {
1060 buf.append("ACC_SYNCHRONIZED");
1061 } else {
1062 buf.append("ACC_SUPER");
1063 }
1064 first = false;
1065 }
1066 if ((access & Opcodes.ACC_VOLATILE) != 0
1067 && (access & ACCESS_FIELD) != 0) {
1068 if (!first) {
1069 buf.append(" + ");
1070 }
1071 buf.append("ACC_VOLATILE");
1072 first = false;
1073 }
1074 if ((access & Opcodes.ACC_BRIDGE) != 0 && (access & ACCESS_CLASS) == 0
1075 && (access & ACCESS_FIELD) == 0) {
1076 if (!first) {
1077 buf.append(" + ");
1078 }
1079 buf.append("ACC_BRIDGE");
1080 first = false;
1081 }
1082 if ((access & Opcodes.ACC_VARARGS) != 0 && (access & ACCESS_CLASS) == 0
1083 && (access & ACCESS_FIELD) == 0) {
1084 if (!first) {
1085 buf.append(" + ");
1086 }
1087 buf.append("ACC_VARARGS");
1088 first = false;
1089 }
1090 if ((access & Opcodes.ACC_TRANSIENT) != 0
1091 && (access & ACCESS_FIELD) != 0) {
1092 if (!first) {
1093 buf.append(" + ");
1094 }
1095 buf.append("ACC_TRANSIENT");
1096 first = false;
1097 }
1098 if ((access & Opcodes.ACC_NATIVE) != 0 && (access & ACCESS_CLASS) == 0
1099 && (access & ACCESS_FIELD) == 0) {
1100 if (!first) {
1101 buf.append(" + ");
1102 }
1103 buf.append("ACC_NATIVE");
1104 first = false;
1105 }
1106 if ((access & Opcodes.ACC_ENUM) != 0
1107 && ((access & ACCESS_CLASS) != 0
1108 || (access & ACCESS_FIELD) != 0 || (access & ACCESS_INNER) != 0)) {
1109 if (!first) {
1110 buf.append(" + ");
1111 }
1112 buf.append("ACC_ENUM");
1113 first = false;
1114 }
1115 if ((access & Opcodes.ACC_ANNOTATION) != 0
1116 && ((access & ACCESS_CLASS) != 0 || (access & ACCESS_INNER) != 0)) {
1117 if (!first) {
1118 buf.append(" + ");
1119 }
1120 buf.append("ACC_ANNOTATION");
1121 first = false;
1122 }
1123 if ((access & Opcodes.ACC_ABSTRACT) != 0) {
1124 if (!first) {
1125 buf.append(" + ");
1126 }
1127 buf.append("ACC_ABSTRACT");
1128 first = false;
1129 }
1130 if ((access & Opcodes.ACC_INTERFACE) != 0) {
1131 if (!first) {
1132 buf.append(" + ");
1133 }
1134 buf.append("ACC_INTERFACE");
1135 first = false;
1136 }
1137 if ((access & Opcodes.ACC_STRICT) != 0) {
1138 if (!first) {
1139 buf.append(" + ");
1140 }
1141 buf.append("ACC_STRICT");
1142 first = false;
1143 }
1144 if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
1145 if (!first) {
1146 buf.append(" + ");
1147 }
1148 buf.append("ACC_SYNTHETIC");
1149 first = false;
1150 }
1151 if ((access & Opcodes.ACC_DEPRECATED) != 0) {
1152 if (!first) {
1153 buf.append(" + ");
1154 }
1155 buf.append("ACC_DEPRECATED");
1156 first = false;
1157 }
1158 if ((access & (Opcodes.ACC_MANDATED|Opcodes.ACC_MODULE)) != 0) {
1159 if (!first) {
1160 buf.append(" + ");
1161 }
1162 if ((access & ACCESS_CLASS) == 0) {
1163 buf.append("ACC_MANDATED");
1164 } else {
1165 buf.append("ACC_MODULE");
1166 }
1167 first = false;
1168 }
1169 if (first) {
1170 buf.append('0');
1171 }
1172 }
1173
1174 /**
1175 * Appends a string representation of the given constant to the given
1176 * buffer.
1177 *
1178 * @param cst
1179 * an {@link Integer}, {@link Float}, {@link Long},
1180 * {@link Double} or {@link String} object. May be <tt>null</tt>.
1181 */
1182 protected void appendConstant(final Object cst) {
1183 appendConstant(buf, cst);
1184 }
1185
1186 /**
1187 * Appends a string representation of the given constant to the given
1188 * buffer.
1189 *
1190 * @param buf
1191 * a string buffer.
1192 * @param cst
1193 * an {@link Integer}, {@link Float}, {@link Long},
1194 * {@link Double} or {@link String} object. May be <tt>null</tt>.
1195 */
1196 static void appendConstant(final StringBuffer buf, final Object cst) {
1197 if (cst == null) {
1198 buf.append("null");
1199 } else if (cst instanceof String) {
1200 appendString(buf, (String) cst);
1201 } else if (cst instanceof Type) {
1202 buf.append("Type.getType(\"");
1203 buf.append(((Type) cst).getDescriptor());
1204 buf.append("\")");
1205 } else if (cst instanceof Handle) {
1206 buf.append("new Handle(");
1207 Handle h = (Handle) cst;
1208 buf.append("Opcodes.").append(HANDLE_TAG[h.getTag()])
1209 .append(", \"");
1210 buf.append(h.getOwner()).append("\", \"");
1211 buf.append(h.getName()).append("\", \"");
1212 buf.append(h.getDesc()).append("\")");
1213 } else if (cst instanceof Byte) {
1214 buf.append("new Byte((byte)").append(cst).append(')');
1215 } else if (cst instanceof Boolean) {
1216 buf.append(((Boolean) cst).booleanValue() ? "Boolean.TRUE"
1217 : "Boolean.FALSE");
1218 } else if (cst instanceof Short) {
1219 buf.append("new Short((short)").append(cst).append(')');
1220 } else if (cst instanceof Character) {
1221 int c = ((Character) cst).charValue();
1222 buf.append("new Character((char)").append(c).append(')');
1223 } else if (cst instanceof Integer) {
1224 buf.append("new Integer(").append(cst).append(')');
1225 } else if (cst instanceof Float) {
1226 buf.append("new Float(\"").append(cst).append("\")");
1227 } else if (cst instanceof Long) {
1228 buf.append("new Long(").append(cst).append("L)");
1229 } else if (cst instanceof Double) {
1230 buf.append("new Double(\"").append(cst).append("\")");
1231 } else if (cst instanceof byte[]) {
1232 byte[] v = (byte[]) cst;
1233 buf.append("new byte[] {");
1234 for (int i = 0; i < v.length; i++) {
1235 buf.append(i == 0 ? "" : ",").append(v[i]);
1236 }
1237 buf.append('}');
1238 } else if (cst instanceof boolean[]) {
1239 boolean[] v = (boolean[]) cst;
1240 buf.append("new boolean[] {");
1241 for (int i = 0; i < v.length; i++) {
1242 buf.append(i == 0 ? "" : ",").append(v[i]);
1243 }
1244 buf.append('}');
1245 } else if (cst instanceof short[]) {
1246 short[] v = (short[]) cst;
1247 buf.append("new short[] {");
1248 for (int i = 0; i < v.length; i++) {
1249 buf.append(i == 0 ? "" : ",").append("(short)").append(v[i]);
1250 }
1251 buf.append('}');
1252 } else if (cst instanceof char[]) {
1253 char[] v = (char[]) cst;
1254 buf.append("new char[] {");
1255 for (int i = 0; i < v.length; i++) {
1256 buf.append(i == 0 ? "" : ",").append("(char)")
1257 .append((int) v[i]);
1258 }
1259 buf.append('}');
1260 } else if (cst instanceof int[]) {
1261 int[] v = (int[]) cst;
1262 buf.append("new int[] {");
1263 for (int i = 0; i < v.length; i++) {
1264 buf.append(i == 0 ? "" : ",").append(v[i]);
1265 }
1266 buf.append('}');
1267 } else if (cst instanceof long[]) {
1268 long[] v = (long[]) cst;
1269 buf.append("new long[] {");
1270 for (int i = 0; i < v.length; i++) {
1271 buf.append(i == 0 ? "" : ",").append(v[i]).append('L');
1272 }
1273 buf.append('}');
1274 } else if (cst instanceof float[]) {
1275 float[] v = (float[]) cst;
1276 buf.append("new float[] {");
1277 for (int i = 0; i < v.length; i++) {
1278 buf.append(i == 0 ? "" : ",").append(v[i]).append('f');
1279 }
1280 buf.append('}');
1281 } else if (cst instanceof double[]) {
1282 double[] v = (double[]) cst;
1283 buf.append("new double[] {");
1284 for (int i = 0; i < v.length; i++) {
1285 buf.append(i == 0 ? "" : ",").append(v[i]).append('d');
1286 }
1287 buf.append('}');
1288 }
1289 }
1290
1291 private void declareFrameTypes(final int n, final Object[] o) {
1292 for (int i = 0; i < n; ++i) {
1293 if (o[i] instanceof Label) {
1294 declareLabel((Label) o[i]);
1295 }
1296 }
1297 }
1298
1299 private void appendFrameTypes(final int n, final Object[] o) {
1300 for (int i = 0; i < n; ++i) {
1301 if (i > 0) {
1302 buf.append(", ");
1303 }
1304 if (o[i] instanceof String) {
1305 appendConstant(o[i]);
1306 } else if (o[i] instanceof Integer) {
1307 switch (((Integer) o[i]).intValue()) {
1308 case 0:
1309 buf.append("Opcodes.TOP");
1310 break;
1311 case 1:
1312 buf.append("Opcodes.INTEGER");
1313 break;
1314 case 2:
1315 buf.append("Opcodes.FLOAT");
1316 break;
1317 case 3:
1318 buf.append("Opcodes.DOUBLE");
1319 break;
1320 case 4:
1321 buf.append("Opcodes.LONG");
1322 break;
1323 case 5:
1324 buf.append("Opcodes.NULL");
1325 break;
1326 case 6:
1327 buf.append("Opcodes.UNINITIALIZED_THIS");
1328 break;
1329 }
1330 } else {
1331 appendLabel((Label) o[i]);
1332 }
1333 }
1334 }
1335
1336 /**
1337 * Appends a declaration of the given label to {@link #buf buf}. This
1338 * declaration is of the form "Label lXXX = new Label();". Does nothing if
1339 * the given label has already been declared.
1340 *
1341 * @param l
1342 * a label.
1343 */
1344 protected void declareLabel(final Label l) {
1345 if (labelNames == null) {
1346 labelNames = new HashMap<Label, String>();
1347 }
1348 String name = labelNames.get(l);
1349 if (name == null) {
1350 name = "l" + labelNames.size();
1351 labelNames.put(l, name);
1352 buf.append("Label ").append(name).append(" = new Label();\n");
1353 }
1354 }
1355
1356 /**
1357 * Appends the name of the given label to {@link #buf buf}. The given label
1358 * <i>must</i> already have a name. One way to ensure this is to always call
1359 * {@link #declareLabel declared} before calling this method.
1360 *
1361 * @param l
1362 * a label.
1363 */
1364 protected void appendLabel(final Label l) {
1365 buf.append(labelNames.get(l));
1366 }
1494 } else {
1495 appendLabel((Label) frameTypes[i]);
1496 }
1497 }
1498 }
1499
1500 /**
1501 * Appends a declaration of the given label to {@link #stringBuilder}. This declaration is of the
1502 * form "Label labelXXX = new Label();". Does nothing if the given label has already been
1503 * declared.
1504 *
1505 * @param label a label.
1506 */
1507 protected void declareLabel(final Label label) {
1508 if (labelNames == null) {
1509 labelNames = new HashMap<Label, String>();
1510 }
1511 String labelName = labelNames.get(label);
1512 if (labelName == null) {
1513 labelName = "label" + labelNames.size();
1514 labelNames.put(label, labelName);
1515 stringBuilder.append("Label ").append(labelName).append(" = new Label();\n");
1516 }
1517 }
1518
1519 /**
1520 * Appends the name of the given label to {@link #stringBuilder}. The given label <i>must</i>
1521 * already have a name. One way to ensure this is to always call {@link #declareLabel} before
1522 * calling this method.
1523 *
1524 * @param label a label.
1525 */
1526 protected void appendLabel(final Label label) {
1527 stringBuilder.append(labelNames.get(label));
1528 }
13671529 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.util;
3028
3129 import org.eclipse.persistence.internal.libraries.asm.AnnotationVisitor;
3432
3533 /**
3634 * An {@link AnnotationVisitor} that checks that its methods are properly used.
37 *
35 *
3836 * @author Eric Bruneton
3937 */
4038 public class CheckAnnotationAdapter extends AnnotationVisitor {
4139
42 private final boolean named;
40 /**
41 * Whether the values of the visited annotation are named. AnnotationVisitor instances used for
42 * annotation default and annotation arrays use unnamed values.
43 */
44 private final boolean useNamedValue;
4345
44 private boolean end;
46 /** Whether the {@link #visitEnd} method has been called. */
47 private boolean visitEndCalled;
4548
46 public CheckAnnotationAdapter(final AnnotationVisitor av) {
47 this(av, true);
49 public CheckAnnotationAdapter(final AnnotationVisitor annotationVisitor) {
50 this(annotationVisitor, true);
51 }
52
53 CheckAnnotationAdapter(final AnnotationVisitor annotationVisitor, final boolean useNamedValues) {
54 super(Opcodes.ASM6, annotationVisitor);
55 this.useNamedValue = useNamedValues;
56 }
57
58 @Override
59 public void visit(final String name, final Object value) {
60 checkVisitEndNotCalled();
61 checkName(name);
62 if (!(value instanceof Byte
63 || value instanceof Boolean
64 || value instanceof Character
65 || value instanceof Short
66 || value instanceof Integer
67 || value instanceof Long
68 || value instanceof Float
69 || value instanceof Double
70 || value instanceof String
71 || value instanceof Type
72 || value instanceof byte[]
73 || value instanceof boolean[]
74 || value instanceof char[]
75 || value instanceof short[]
76 || value instanceof int[]
77 || value instanceof long[]
78 || value instanceof float[]
79 || value instanceof double[])) {
80 throw new IllegalArgumentException("Invalid annotation value");
4881 }
82 if (value instanceof Type && ((Type) value).getSort() == Type.METHOD) {
83 throw new IllegalArgumentException("Invalid annotation value");
84 }
85 super.visit(name, value);
86 }
4987
50 CheckAnnotationAdapter(final AnnotationVisitor av, final boolean named) {
51 super(Opcodes.ASM6, av);
52 this.named = named;
88 @Override
89 public void visitEnum(final String name, final String descriptor, final String value) {
90 checkVisitEndNotCalled();
91 checkName(name);
92 CheckMethodAdapter.checkDescriptor(descriptor, false);
93 if (value == null) {
94 throw new IllegalArgumentException("Invalid enum value");
5395 }
96 super.visitEnum(name, descriptor, value);
97 }
5498
55 @Override
56 public void visit(final String name, final Object value) {
57 checkEnd();
58 checkName(name);
59 if (!(value instanceof Byte || value instanceof Boolean
60 || value instanceof Character || value instanceof Short
61 || value instanceof Integer || value instanceof Long
62 || value instanceof Float || value instanceof Double
63 || value instanceof String || value instanceof Type
64 || value instanceof byte[] || value instanceof boolean[]
65 || value instanceof char[] || value instanceof short[]
66 || value instanceof int[] || value instanceof long[]
67 || value instanceof float[] || value instanceof double[])) {
68 throw new IllegalArgumentException("Invalid annotation value");
69 }
70 if (value instanceof Type) {
71 int sort = ((Type) value).getSort();
72 if (sort == Type.METHOD) {
73 throw new IllegalArgumentException("Invalid annotation value");
74 }
75 }
76 if (av != null) {
77 av.visit(name, value);
78 }
99 @Override
100 public AnnotationVisitor visitAnnotation(final String name, final String descriptor) {
101 checkVisitEndNotCalled();
102 checkName(name);
103 CheckMethodAdapter.checkDescriptor(descriptor, false);
104 return new CheckAnnotationAdapter(super.visitAnnotation(name, descriptor));
105 }
106
107 @Override
108 public AnnotationVisitor visitArray(final String name) {
109 checkVisitEndNotCalled();
110 checkName(name);
111 return new CheckAnnotationAdapter(super.visitArray(name), false);
112 }
113
114 @Override
115 public void visitEnd() {
116 checkVisitEndNotCalled();
117 visitEndCalled = true;
118 super.visitEnd();
119 }
120
121 private void checkName(final String name) {
122 if (useNamedValue && name == null) {
123 throw new IllegalArgumentException("Annotation value name must not be null");
79124 }
125 }
80126
81 @Override
82 public void visitEnum(final String name, final String desc,
83 final String value) {
84 checkEnd();
85 checkName(name);
86 CheckMethodAdapter.checkDesc(desc, false);
87 if (value == null) {
88 throw new IllegalArgumentException("Invalid enum value");
89 }
90 if (av != null) {
91 av.visitEnum(name, desc, value);
92 }
127 private void checkVisitEndNotCalled() {
128 if (visitEndCalled) {
129 throw new IllegalStateException("Cannot call a visit method after visitEnd has been called");
93130 }
94
95 @Override
96 public AnnotationVisitor visitAnnotation(final String name,
97 final String desc) {
98 checkEnd();
99 checkName(name);
100 CheckMethodAdapter.checkDesc(desc, false);
101 return new CheckAnnotationAdapter(av == null ? null
102 : av.visitAnnotation(name, desc));
103 }
104
105 @Override
106 public AnnotationVisitor visitArray(final String name) {
107 checkEnd();
108 checkName(name);
109 return new CheckAnnotationAdapter(av == null ? null
110 : av.visitArray(name), false);
111 }
112
113 @Override
114 public void visitEnd() {
115 checkEnd();
116 end = true;
117 if (av != null) {
118 av.visitEnd();
119 }
120 }
121
122 private void checkEnd() {
123 if (end) {
124 throw new IllegalStateException(
125 "Cannot call a visit method after visitEnd has been called");
126 }
127 }
128
129 private void checkName(final String name) {
130 if (named && name == null) {
131 throw new IllegalArgumentException(
132 "Annotation value name must not be null");
133 }
134 }
131 }
135132 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.util;
3028
3129 import java.io.FileInputStream;
30 import java.io.IOException;
3231 import java.io.PrintWriter;
3332 import java.util.ArrayList;
3433 import java.util.HashMap;
35 import java.util.Iterator;
3634 import java.util.List;
3735 import java.util.Map;
3836
5048 import org.eclipse.persistence.internal.libraries.asm.TypeReference;
5149 import org.eclipse.persistence.internal.libraries.asm.tree.ClassNode;
5250 import org.eclipse.persistence.internal.libraries.asm.tree.MethodNode;
51 import org.eclipse.persistence.internal.libraries.asm.tree.TryCatchBlockNode;
5352 import org.eclipse.persistence.internal.libraries.asm.tree.analysis.Analyzer;
5453 import org.eclipse.persistence.internal.libraries.asm.tree.analysis.BasicValue;
5554 import org.eclipse.persistence.internal.libraries.asm.tree.analysis.Frame;
5655 import org.eclipse.persistence.internal.libraries.asm.tree.analysis.SimpleVerifier;
5756
5857 /**
59 * A {@link ClassVisitor} that checks that its methods are properly used. More
60 * precisely this class adapter checks each method call individually, based
61 * <i>only</i> on its arguments, but does <i>not</i> check the <i>sequence</i>
62 * of method calls. For example, the invalid sequence
63 * <tt>visitField(ACC_PUBLIC, "i", "I", null)</tt> <tt>visitField(ACC_PUBLIC,
64 * "i", "D", null)</tt> will <i>not</i> be detected by this class adapter.
65 *
66 * <p>
67 * <code>CheckClassAdapter</code> can be also used to verify bytecode
68 * transformations in order to make sure transformed bytecode is sane. For
69 * example:
70 *
58 * A {@link ClassVisitor} that checks that its methods are properly used. More precisely this class
59 * adapter checks each method call individually, based <i>only</i> on its arguments, but does
60 * <i>not</i> check the <i>sequence</i> of method calls. For example, the invalid sequence
61 * <tt>visitField(ACC_PUBLIC, "i", "I", null)</tt> <tt>visitField(ACC_PUBLIC, "i", "D", null)</tt>
62 * will <i>not</i> be detected by this class adapter.
63 *
64 * <p><code>CheckClassAdapter</code> can be also used to verify bytecode transformations in order to
65 * make sure that the transformed bytecode is sane. For example:
66 *
7167 * <pre>
72 * InputStream is = ...; // get bytes for the source class
73 * ClassReader cr = new ClassReader(is);
74 * ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS);
75 * ClassVisitor cv = new <b>MyClassAdapter</b>(new CheckClassAdapter(cw));
76 * cr.accept(cv, 0);
77 *
78 * StringWriter sw = new StringWriter();
79 * PrintWriter pw = new PrintWriter(sw);
80 * CheckClassAdapter.verify(new ClassReader(cw.toByteArray()), false, pw);
81 * assertTrue(sw.toString(), sw.toString().length()==0);
68 * InputStream inputStream = ...; // get bytes for the source class
69 * ClassReader classReader = new ClassReader(inputStream);
70 * ClassWriter classWriter = new ClassWriter(classReader, ClassWriter.COMPUTE_MAXS);
71 * ClassVisitor classVisitor = new <b>MyClassAdapter</b>(new CheckClassAdapter(classWriter, true));
72 * classReader.accept(classVisitor, 0);
73 *
74 * StringWriter stringWriter = new StringWriter();
75 * PrintWriter printWriter = new PrintWriter(stringWriter);
76 * CheckClassAdapter.verify(new ClassReader(classWriter.toByteArray()), false, printWriter);
77 * assertTrue(stringWriter.toString().isEmpty());
8278 * </pre>
83 *
84 * Above code runs transformed bytecode trough the
85 * <code>CheckClassAdapter</code>. It won't be exactly the same verification as
86 * JVM does, but it run data flow analysis for the code of each method and
87 * checks that expectations are met for each method instruction.
88 *
89 * <p>
90 * If method bytecode has errors, assertion text will show the erroneous
91 * instruction number and dump of the failed method with information about
92 * locals and stack slot for each instruction. For example (format is -
93 * insnNumber locals : stack):
94 *
79 *
80 * The above code pass the transformed bytecode through a <code>CheckClassAdapter</code>, with data
81 * flow checks enabled. These checks are not exactly the same as the JVM verification, but provide
82 * some basic type checking for each method instruction. If the bytecode has errors, the output text
83 * shows the erroneous instruction number, and a dump of the failed method with information about
84 * the type of the local variables and of the operand stack slots for each instruction. For example
85 * (format is - insnNumber locals : stack):
86 *
9587 * <pre>
9688 * org.eclipse.persistence.internal.libraries.asm.tree.analysis.AnalyzerException: Error at instruction 71: Expected I, but found .
97 * at org.eclipse.persistence.internal.libraries.asm.tree.analysis.Analyzer.analyze(Analyzer.java:289)
98 * at org.eclipse.persistence.internal.libraries.asm.util.CheckClassAdapter.verify(CheckClassAdapter.java:135)
89 * at org.eclipse.persistence.internal.libraries.asm.tree.analysis.Analyzer.analyze(Analyzer.java:...)
90 * at org.eclipse.persistence.internal.libraries.asm.util.CheckClassAdapter.verify(CheckClassAdapter.java:...)
9991 * ...
10092 * remove()V
101 * 00000 LinkedBlockingQueue$Itr . . . . . . . . :
102 * ICONST_0
103 * 00001 LinkedBlockingQueue$Itr . . . . . . . . : I
104 * ISTORE 2
93 * 00000 LinkedBlockingQueue$Itr . . . . . . . . : ICONST_0
94 * 00001 LinkedBlockingQueue$Itr . . . . . . . . : I ISTORE 2
10595 * 00001 LinkedBlockingQueue$Itr <b>.</b> I . . . . . . :
10696 * ...
107 *
108 * 00071 LinkedBlockingQueue$Itr <b>.</b> I . . . . . . :
109 * ILOAD 1
110 * 00072 <b>?</b>
111 * INVOKESPECIAL java/lang/Integer.&lt;init&gt; (I)V
97 * 00071 LinkedBlockingQueue$Itr <b>.</b> I . . . . . . : ILOAD 1
98 * 00072 <b>?</b> INVOKESPECIAL java/lang/Integer.&lt;init&gt; (I)V
11299 * ...
113100 * </pre>
114 *
115 * In the above output you can see that variable 1 loaded by
116 * <code>ILOAD 1</code> instruction at position <code>00071</code> is not
117 * initialized. You can also see that at the beginning of the method (code
118 * inserted by the transformation) variable 2 is initialized.
119 *
120 * <p>
121 * Note that when used like that, <code>CheckClassAdapter.verify()</code> can
122 * trigger additional class loading, because it is using
123 * <code>SimpleVerifier</code>.
124 *
101 *
102 * The above output shows that the local variable 1, loaded by the <code>ILOAD 1</code> instruction
103 * at position <code>00071</code> is not initialized, whereas the local variable 2 is initialized
104 * and contains an int value.
105 *
125106 * @author Eric Bruneton
126107 */
127108 public class CheckClassAdapter extends ClassVisitor {
128109
129 /**
130 * The class version number.
131 */
132 private int version;
133
134 /**
135 * <tt>true</tt> if the visit method has been called.
136 */
137 private boolean start;
138
139 /**
140 * <tt>true</tt> if the visitSource method has been called.
141 */
142 private boolean source;
143
144 /**
145 * <tt>true</tt> if the visitOuterClass method has been called.
146 */
147 private boolean outer;
148
149 /**
150 * <tt>true</tt> if the visitEnd method has been called.
151 */
152 private boolean end;
153
154 /**
155 * The already visited labels. This map associate Integer values to Label
156 * keys.
157 */
158 private Map<Label, Integer> labels;
159
160 /**
161 * <tt>true</tt> if the method code must be checked with a BasicVerifier.
162 */
163 private boolean checkDataFlow;
164
165 /**
166 * Checks a given class.
167 * <p>
168 * Usage: CheckClassAdapter &lt;binary class name or class file name&gt;
169 *
170 * @param args
171 * the command line arguments.
172 *
173 * @throws Exception
174 * if the class cannot be found, or if an IO exception occurs.
175 */
176 public static void main(final String[] args) throws Exception {
177 if (args.length != 1) {
178 System.err.println("Verifies the given class.");
179 System.err.println("Usage: CheckClassAdapter "
180 + "<fully qualified class name or class file name>");
181 return;
110 private static final String ERROR_AT = ": error at index ";
111
112 /** Whether the bytecode must be checked with a BasicVerifier. */
113 private boolean checkDataFlow;
114
115 /** The class version number. */
116 private int version;
117
118 /** Whether the {@link #visit} method has been called. */
119 private boolean visitCalled;
120
121 /** Whether the {@link #visitModule} method has been called. */
122 private boolean visitModuleCalled;
123
124 /** Whether the {@link #visitSource} method has been called. */
125 private boolean visitSourceCalled;
126
127 /** Whether the {@link #visitOuterClass} method has been called. */
128 private boolean visitOuterClassCalled;
129
130 /** Whether the {@link #visitEnd} method has been called. */
131 private boolean visitEndCalled;
132
133 /** The index of the instruction designated by each visited label so far. */
134 private Map<Label, Integer> labelInsnIndices;
135
136 // -----------------------------------------------------------------------------------------------
137 // Static verification methods
138 // -----------------------------------------------------------------------------------------------
139
140 /**
141 * Checks the given class.
142 *
143 * <p>Usage: CheckClassAdapter &lt;binary class name or class file name&gt;
144 *
145 * @param args the command line arguments.
146 * @throws IOException if the class cannot be found, or if an IO exception occurs.
147 */
148 public static void main(final String[] args) throws IOException {
149 if (args.length != 1) {
150 System.err.println(
151 "Verifies the given class.\n"
152 + "Usage: CheckClassAdapter <fully qualified class name or class file name>");
153 return;
154 }
155
156 ClassReader classReader;
157 if (args[0].endsWith(".class")) {
158 classReader = new ClassReader(new FileInputStream(args[0]));
159 } else {
160 classReader = new ClassReader(args[0]);
161 }
162
163 verify(classReader, false, new PrintWriter(System.err));
164 }
165
166 /**
167 * Checks the given class.
168 *
169 * @param classReader the class to be checked.
170 * @param printResults whether to print the results of the bytecode verification.
171 * @param printWriter where the results (or the stack trace in case of error) must be printed.
172 */
173 public static void verify(
174 final ClassReader classReader, final boolean printResults, final PrintWriter printWriter) {
175 verify(classReader, null, printResults, printWriter);
176 }
177
178 /**
179 * Checks the given class.
180 *
181 * @param classReader the class to be checked.
182 * @param loader a <code>ClassLoader</code> which will be used to load referenced classes. May be
183 * <tt>null</tt>.
184 * @param printResults whether to print the results of the bytecode verification.
185 * @param printWriter where the results (or the stack trace in case of error) must be printed.
186 */
187 public static void verify(
188 final ClassReader classReader,
189 final ClassLoader loader,
190 final boolean printResults,
191 final PrintWriter printWriter) {
192 ClassNode classNode = new ClassNode();
193 classReader.accept(new CheckClassAdapter(classNode, false), ClassReader.SKIP_DEBUG);
194
195 Type syperType = classNode.superName == null ? null : Type.getObjectType(classNode.superName);
196 List<MethodNode> methods = classNode.methods;
197
198 List<Type> interfaces = new ArrayList<Type>();
199 for (String interfaceName : classNode.interfaces) {
200 interfaces.add(Type.getObjectType(interfaceName));
201 }
202
203 for (MethodNode method : methods) {
204 SimpleVerifier verifier =
205 new SimpleVerifier(
206 Type.getObjectType(classNode.name),
207 syperType,
208 interfaces,
209 (classNode.access & Opcodes.ACC_INTERFACE) != 0);
210 Analyzer<BasicValue> analyzer = new Analyzer<BasicValue>(verifier);
211 if (loader != null) {
212 verifier.setClassLoader(loader);
213 }
214 try {
215 analyzer.analyze(classNode.name, method);
216 } catch (Exception e) {
217 e.printStackTrace(printWriter);
218 }
219 if (printResults) {
220 printAnalyzerResult(method, analyzer, printWriter);
221 }
222 }
223 printWriter.flush();
224 }
225
226 static void printAnalyzerResult(
227 final MethodNode method, final Analyzer<BasicValue> analyzer, final PrintWriter printWriter) {
228 Textifier textifier = new Textifier();
229 TraceMethodVisitor traceMethodVisitor = new TraceMethodVisitor(textifier);
230
231 printWriter.println(method.name + method.desc);
232 for (int i = 0; i < method.instructions.size(); ++i) {
233 method.instructions.get(i).accept(traceMethodVisitor);
234
235 StringBuilder stringBuilder = new StringBuilder();
236 Frame<BasicValue> frame = analyzer.getFrames()[i];
237 if (frame == null) {
238 stringBuilder.append('?');
239 } else {
240 for (int j = 0; j < frame.getLocals(); ++j) {
241 stringBuilder.append(getUnqualifiedName(frame.getLocal(j).toString())).append(' ');
182242 }
183 ClassReader cr;
184 if (args[0].endsWith(".class")) {
185 cr = new ClassReader(new FileInputStream(args[0]));
186 } else {
187 cr = new ClassReader(args[0]);
243 stringBuilder.append(" : ");
244 for (int j = 0; j < frame.getStackSize(); ++j) {
245 stringBuilder.append(getUnqualifiedName(frame.getStack(j).toString())).append(' ');
188246 }
189
190 verify(cr, false, new PrintWriter(System.err));
191 }
192
193 /**
194 * Checks a given class.
195 *
196 * @param cr
197 * a <code>ClassReader</code> that contains bytecode for the
198 * analysis.
199 * @param loader
200 * a <code>ClassLoader</code> which will be used to load
201 * referenced classes. This is useful if you are verifiying
202 * multiple interdependent classes.
203 * @param dump
204 * true if bytecode should be printed out not only when errors
205 * are found.
206 * @param pw
207 * write where results going to be printed
208 */
209 public static void verify(final ClassReader cr, final ClassLoader loader,
210 final boolean dump, final PrintWriter pw) {
211 ClassNode cn = new ClassNode();
212 cr.accept(new CheckClassAdapter(cn, false), ClassReader.SKIP_DEBUG);
213
214 Type syperType = cn.superName == null ? null : Type
215 .getObjectType(cn.superName);
216 List<MethodNode> methods = cn.methods;
217
218 List<Type> interfaces = new ArrayList<Type>();
219 for (Iterator<String> i = cn.interfaces.iterator(); i.hasNext();) {
220 interfaces.add(Type.getObjectType(i.next()));
221 }
222
223 for (int i = 0; i < methods.size(); ++i) {
224 MethodNode method = methods.get(i);
225 SimpleVerifier verifier = new SimpleVerifier(
226 Type.getObjectType(cn.name), syperType, interfaces,
227 (cn.access & Opcodes.ACC_INTERFACE) != 0);
228 Analyzer<BasicValue> a = new Analyzer<BasicValue>(verifier);
229 if (loader != null) {
230 verifier.setClassLoader(loader);
231 }
232 try {
233 a.analyze(cn.name, method);
234 if (!dump) {
235 continue;
236 }
237 } catch (Exception e) {
238 e.printStackTrace(pw);
239 }
240 printAnalyzerResult(method, a, pw);
241 }
242 pw.flush();
243 }
244
245 /**
246 * Checks a given class
247 *
248 * @param cr
249 * a <code>ClassReader</code> that contains bytecode for the
250 * analysis.
251 * @param dump
252 * true if bytecode should be printed out not only when errors
253 * are found.
254 * @param pw
255 * write where results going to be printed
256 */
257 public static void verify(final ClassReader cr, final boolean dump,
258 final PrintWriter pw) {
259 verify(cr, null, dump, pw);
260 }
261
262 static void printAnalyzerResult(MethodNode method, Analyzer<BasicValue> a,
263 final PrintWriter pw) {
264 Frame<BasicValue>[] frames = a.getFrames();
265 Textifier t = new Textifier();
266 TraceMethodVisitor mv = new TraceMethodVisitor(t);
267
268 pw.println(method.name + method.desc);
269 for (int j = 0; j < method.instructions.size(); ++j) {
270 method.instructions.get(j).accept(mv);
271
272 StringBuilder sb = new StringBuilder();
273 Frame<BasicValue> f = frames[j];
274 if (f == null) {
275 sb.append('?');
276 } else {
277 for (int k = 0; k < f.getLocals(); ++k) {
278 sb.append(getShortName(f.getLocal(k).toString()))
279 .append(' ');
280 }
281 sb.append(" : ");
282 for (int k = 0; k < f.getStackSize(); ++k) {
283 sb.append(getShortName(f.getStack(k).toString()))
284 .append(' ');
285 }
286 }
287 while (sb.length() < method.maxStack + method.maxLocals + 1) {
288 sb.append(' ');
289 }
290 pw.print(Integer.toString(j + 100000).substring(1));
291 pw.print(" " + sb + " : " + t.text.get(t.text.size() - 1));
292 }
293 for (int j = 0; j < method.tryCatchBlocks.size(); ++j) {
294 method.tryCatchBlocks.get(j).accept(mv);
295 pw.print(" " + t.text.get(t.text.size() - 1));
296 }
297 pw.println();
298 }
299
300 private static String getShortName(final String name) {
301 int n = name.lastIndexOf('/');
302 int k = name.length();
303 if (name.charAt(k - 1) == ';') {
304 k--;
305 }
306 return n == -1 ? name : name.substring(n + 1, k);
307 }
308
309 /**
310 * Constructs a new {@link CheckClassAdapter}. <i>Subclasses must not use
311 * this constructor</i>. Instead, they must use the
312 * {@link #CheckClassAdapter(int, ClassVisitor, boolean)} version.
313 *
314 * @param cv
315 * the class visitor to which this adapter must delegate calls.
316 */
317 public CheckClassAdapter(final ClassVisitor cv) {
318 this(cv, true);
319 }
320
321 /**
322 * Constructs a new {@link CheckClassAdapter}. <i>Subclasses must not use
323 * this constructor</i>. Instead, they must use the
324 * {@link #CheckClassAdapter(int, ClassVisitor, boolean)} version.
325 *
326 * @param cv
327 * the class visitor to which this adapter must delegate calls.
328 * @param checkDataFlow
329 * <tt>true</tt> to perform basic data flow checks, or
330 * <tt>false</tt> to not perform any data flow check (see
331 * {@link CheckMethodAdapter}). This option requires valid
332 * maxLocals and maxStack values.
333 * @throws IllegalStateException
334 * If a subclass calls this constructor.
335 */
336 public CheckClassAdapter(final ClassVisitor cv, final boolean checkDataFlow) {
337 this(Opcodes.ASM6, cv, checkDataFlow);
338 if (getClass() != CheckClassAdapter.class) {
339 throw new IllegalStateException();
340 }
341 }
342
343 /**
344 * Constructs a new {@link CheckClassAdapter}.
345 *
346 * @param api
347 * the ASM API version implemented by this visitor. Must be one
348 * of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
349 * @param cv
350 * the class visitor to which this adapter must delegate calls.
351 * @param checkDataFlow
352 * <tt>true</tt> to perform basic data flow checks, or
353 * <tt>false</tt> to not perform any data flow check (see
354 * {@link CheckMethodAdapter}). This option requires valid
355 * maxLocals and maxStack values.
356 */
357 protected CheckClassAdapter(final int api, final ClassVisitor cv,
358 final boolean checkDataFlow) {
359 super(api, cv);
360 this.labels = new HashMap<Label, Integer>();
361 this.checkDataFlow = checkDataFlow;
362 }
363
364 // ------------------------------------------------------------------------
365 // Implementation of the ClassVisitor interface
366 // ------------------------------------------------------------------------
367
368 @Override
369 public void visit(final int version, final int access, final String name,
370 final String signature, final String superName,
371 final String[] interfaces) {
372 if (start) {
373 throw new IllegalStateException("visit must be called only once");
374 }
375 start = true;
376 checkState();
377 checkAccess(access, Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL
378 + Opcodes.ACC_SUPER + Opcodes.ACC_INTERFACE
379 + Opcodes.ACC_ABSTRACT + Opcodes.ACC_SYNTHETIC
380 + Opcodes.ACC_ANNOTATION + Opcodes.ACC_ENUM
381 + Opcodes.ACC_DEPRECATED + Opcodes.ACC_MODULE
382 + 0x40000); // ClassWriter.ACC_SYNTHETIC_ATTRIBUTE
383 if (name == null || !name.endsWith("package-info")) {
384 CheckMethodAdapter.checkInternalName(name, "class name");
385 }
386 if ("java/lang/Object".equals(name)) {
387 if (superName != null) {
388 throw new IllegalArgumentException(
389 "The super class name of the Object class must be 'null'");
390 }
391 } else {
392 CheckMethodAdapter.checkInternalName(superName, "super class name");
393 }
394 if (signature != null) {
395 checkClassSignature(signature);
396 }
397 if ((access & Opcodes.ACC_INTERFACE) != 0) {
398 if (!"java/lang/Object".equals(superName)) {
399 throw new IllegalArgumentException(
400 "The super class name of interfaces must be 'java/lang/Object'");
401 }
402 }
403 if (interfaces != null) {
404 for (int i = 0; i < interfaces.length; ++i) {
405 CheckMethodAdapter.checkInternalName(interfaces[i],
406 "interface name at index " + i);
407 }
408 }
409 this.version = version;
410 super.visit(version, access, name, signature, superName, interfaces);
411 }
412
413 @Override
414 public void visitSource(final String file, final String debug) {
415 checkState();
416 if (source) {
417 throw new IllegalStateException(
418 "visitSource can be called only once.");
419 }
420 source = true;
421 super.visitSource(file, debug);
422 }
423
424 @Override
425 public ModuleVisitor visitModule() {
426 return new CheckModuleAdapter(super.visitModule());
427 }
428
429 @Override
430 public void visitOuterClass(final String owner, final String name,
431 final String desc) {
432 checkState();
433 if (outer) {
434 throw new IllegalStateException(
435 "visitOuterClass can be called only once.");
436 }
437 outer = true;
438 if (owner == null) {
439 throw new IllegalArgumentException("Illegal outer class owner");
440 }
441 if (desc != null) {
442 CheckMethodAdapter.checkMethodDesc(desc);
443 }
444 super.visitOuterClass(owner, name, desc);
445 }
446
447 @Override
448 public void visitInnerClass(final String name, final String outerName,
449 final String innerName, final int access) {
450 checkState();
451 CheckMethodAdapter.checkInternalName(name, "class name");
452 if (outerName != null) {
453 CheckMethodAdapter.checkInternalName(outerName, "outer class name");
454 }
455 if (innerName != null) {
456 int start = 0;
457 while (start < innerName.length()
458 && Character.isDigit(innerName.charAt(start))) {
459 start++;
460 }
461 if (start == 0 || start < innerName.length()) {
462 CheckMethodAdapter.checkIdentifier(innerName, start, -1,
463 "inner class name");
464 }
465 }
466 checkAccess(access, Opcodes.ACC_PUBLIC + Opcodes.ACC_PRIVATE
467 + Opcodes.ACC_PROTECTED + Opcodes.ACC_STATIC
468 + Opcodes.ACC_FINAL + Opcodes.ACC_INTERFACE
469 + Opcodes.ACC_ABSTRACT + Opcodes.ACC_SYNTHETIC
470 + Opcodes.ACC_ANNOTATION + Opcodes.ACC_ENUM);
471 super.visitInnerClass(name, outerName, innerName, access);
472 }
473
474 @Override
475 public FieldVisitor visitField(final int access, final String name,
476 final String desc, final String signature, final Object value) {
477 checkState();
478 checkAccess(access, Opcodes.ACC_PUBLIC + Opcodes.ACC_PRIVATE
479 + Opcodes.ACC_PROTECTED + Opcodes.ACC_STATIC
480 + Opcodes.ACC_FINAL + Opcodes.ACC_VOLATILE
481 + Opcodes.ACC_TRANSIENT + Opcodes.ACC_SYNTHETIC
482 + Opcodes.ACC_ENUM + Opcodes.ACC_DEPRECATED + 0x40000); // ClassWriter.ACC_SYNTHETIC_ATTRIBUTE
483 CheckMethodAdapter.checkUnqualifiedName(version, name, "field name");
484 CheckMethodAdapter.checkDesc(desc, false);
485 if (signature != null) {
486 checkFieldSignature(signature);
487 }
488 if (value != null) {
489 CheckMethodAdapter.checkConstant(value);
490 }
491 FieldVisitor av = super
492 .visitField(access, name, desc, signature, value);
493 return new CheckFieldAdapter(av);
494 }
495
496 @Override
497 public MethodVisitor visitMethod(final int access, final String name,
498 final String desc, final String signature, final String[] exceptions) {
499 checkState();
500 checkAccess(access, Opcodes.ACC_PUBLIC + Opcodes.ACC_PRIVATE
501 + Opcodes.ACC_PROTECTED + Opcodes.ACC_STATIC
502 + Opcodes.ACC_FINAL + Opcodes.ACC_SYNCHRONIZED
503 + Opcodes.ACC_BRIDGE + Opcodes.ACC_VARARGS + Opcodes.ACC_NATIVE
504 + Opcodes.ACC_ABSTRACT + Opcodes.ACC_STRICT
505 + Opcodes.ACC_SYNTHETIC + Opcodes.ACC_DEPRECATED + 0x40000); // ClassWriter.ACC_SYNTHETIC_ATTRIBUTE
506 if (!"<init>".equals(name) && !"<clinit>".equals(name)) {
507 CheckMethodAdapter.checkMethodIdentifier(version, name,
508 "method name");
509 }
510 CheckMethodAdapter.checkMethodDesc(desc);
511 if (signature != null) {
512 checkMethodSignature(signature);
513 }
514 if (exceptions != null) {
515 for (int i = 0; i < exceptions.length; ++i) {
516 CheckMethodAdapter.checkInternalName(exceptions[i],
517 "exception name at index " + i);
518 }
519 }
520 CheckMethodAdapter cma;
521 if (checkDataFlow) {
522 cma = new CheckMethodAdapter(access, name, desc, super.visitMethod(
523 access, name, desc, signature, exceptions), labels);
524 } else {
525 cma = new CheckMethodAdapter(super.visitMethod(access, name, desc,
526 signature, exceptions), labels);
527 }
528 cma.version = version;
529 return cma;
530 }
531
532 @Override
533 public AnnotationVisitor visitAnnotation(final String desc,
534 final boolean visible) {
535 checkState();
536 CheckMethodAdapter.checkDesc(desc, false);
537 return new CheckAnnotationAdapter(super.visitAnnotation(desc, visible));
538 }
539
540 @Override
541 public AnnotationVisitor visitTypeAnnotation(final int typeRef,
542 final TypePath typePath, final String desc, final boolean visible) {
543 checkState();
544 int sort = typeRef >>> 24;
545 if (sort != TypeReference.CLASS_TYPE_PARAMETER
546 && sort != TypeReference.CLASS_TYPE_PARAMETER_BOUND
547 && sort != TypeReference.CLASS_EXTENDS) {
548 throw new IllegalArgumentException("Invalid type reference sort 0x"
549 + Integer.toHexString(sort));
550 }
551 checkTypeRefAndPath(typeRef, typePath);
552 CheckMethodAdapter.checkDesc(desc, false);
553 return new CheckAnnotationAdapter(super.visitTypeAnnotation(typeRef,
554 typePath, desc, visible));
555 }
556
557 @Override
558 public void visitAttribute(final Attribute attr) {
559 checkState();
560 if (attr == null) {
561 throw new IllegalArgumentException(
562 "Invalid attribute (must not be null)");
563 }
564 super.visitAttribute(attr);
565 }
566
567 @Override
568 public void visitEnd() {
569 checkState();
570 end = true;
571 super.visitEnd();
572 }
573
574 // ------------------------------------------------------------------------
575 // Utility methods
576 // ------------------------------------------------------------------------
577
578 /**
579 * Checks that the visit method has been called and that visitEnd has not
580 * been called.
581 */
582 private void checkState() {
583 if (!start) {
584 throw new IllegalStateException(
585 "Cannot visit member before visit has been called.");
586 }
587 if (end) {
588 throw new IllegalStateException(
589 "Cannot visit member after visitEnd has been called.");
590 }
591 }
592
593 /**
594 * Checks that the given access flags do not contain invalid flags. This
595 * method also checks that mutually incompatible flags are not set
596 * simultaneously.
597 *
598 * @param access
599 * the access flags to be checked
600 * @param possibleAccess
601 * the valid access flags.
602 */
603 static void checkAccess(final int access, final int possibleAccess) {
604 if ((access & ~possibleAccess) != 0) {
605 throw new IllegalArgumentException("Invalid access flags: "
606 + access);
607 }
608 int pub = (access & Opcodes.ACC_PUBLIC) == 0 ? 0 : 1;
609 int pri = (access & Opcodes.ACC_PRIVATE) == 0 ? 0 : 1;
610 int pro = (access & Opcodes.ACC_PROTECTED) == 0 ? 0 : 1;
611 if (pub + pri + pro > 1) {
612 throw new IllegalArgumentException(
613 "public private and protected are mutually exclusive: "
614 + access);
615 }
616 int fin = (access & Opcodes.ACC_FINAL) == 0 ? 0 : 1;
617 int abs = (access & Opcodes.ACC_ABSTRACT) == 0 ? 0 : 1;
618 if (fin + abs > 1) {
619 throw new IllegalArgumentException(
620 "final and abstract are mutually exclusive: " + access);
621 }
622 }
623
624 /**
625 * Checks a class signature.
626 *
627 * @param signature
628 * a string containing the signature that must be checked.
629 */
630 public static void checkClassSignature(final String signature) {
631 // ClassSignature:
632 // FormalTypeParameters? ClassTypeSignature ClassTypeSignature*
633
634 int pos = 0;
635 if (getChar(signature, 0) == '<') {
636 pos = checkFormalTypeParameters(signature, pos);
637 }
247 }
248 while (stringBuilder.length() < method.maxStack + method.maxLocals + 1) {
249 stringBuilder.append(' ');
250 }
251 printWriter.print(Integer.toString(i + 100000).substring(1));
252 printWriter.print(
253 " " + stringBuilder + " : " + textifier.text.get(textifier.text.size() - 1));
254 }
255 for (TryCatchBlockNode tryCatchBlock : method.tryCatchBlocks) {
256 tryCatchBlock.accept(traceMethodVisitor);
257 printWriter.print(" " + textifier.text.get(textifier.text.size() - 1));
258 }
259 printWriter.println();
260 }
261
262 private static String getUnqualifiedName(final String name) {
263 int lastSlashIndex = name.lastIndexOf('/');
264 if (lastSlashIndex == -1) {
265 return name;
266 } else {
267 int endIndex = name.length();
268 if (name.charAt(endIndex - 1) == ';') {
269 endIndex--;
270 }
271 return name.substring(lastSlashIndex + 1, endIndex);
272 }
273 }
274
275 // -----------------------------------------------------------------------------------------------
276 // Constructors
277 // -----------------------------------------------------------------------------------------------
278
279 /**
280 * Constructs a new {@link CheckClassAdapter}. <i>Subclasses must not use this constructor</i>.
281 * Instead, they must use the {@link #CheckClassAdapter(int, ClassVisitor, boolean)} version.
282 *
283 * @param classVisitor the class visitor to which this adapter must delegate calls.
284 */
285 public CheckClassAdapter(final ClassVisitor classVisitor) {
286 this(classVisitor, true);
287 }
288
289 /**
290 * Constructs a new {@link CheckClassAdapter}. <i>Subclasses must not use this constructor</i>.
291 * Instead, they must use the {@link #CheckClassAdapter(int, ClassVisitor, boolean)} version.
292 *
293 * @param classVisitor the class visitor to which this adapter must delegate calls.
294 * @param checkDataFlow whether to perform basic data flow checks. This option requires valid
295 * maxLocals and maxStack values.
296 * @throws IllegalStateException If a subclass calls this constructor.
297 */
298 public CheckClassAdapter(final ClassVisitor classVisitor, final boolean checkDataFlow) {
299 this(Opcodes.ASM6, classVisitor, checkDataFlow);
300 if (getClass() != CheckClassAdapter.class) {
301 throw new IllegalStateException();
302 }
303 }
304
305 /**
306 * Constructs a new {@link CheckClassAdapter}.
307 *
308 * @param api the ASM API version implemented by this visitor. Must be one of {@link
309 * Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
310 * @param classVisitor the class visitor to which this adapter must delegate calls.
311 * @param checkDataFlow <tt>true</tt> to perform basic data flow checks, or <tt>false</tt> to not
312 * perform any data flow check (see {@link CheckMethodAdapter}). This option requires valid
313 * maxLocals and maxStack values.
314 */
315 protected CheckClassAdapter(
316 final int api, final ClassVisitor classVisitor, final boolean checkDataFlow) {
317 super(api, classVisitor);
318 this.labelInsnIndices = new HashMap<Label, Integer>();
319 this.checkDataFlow = checkDataFlow;
320 }
321
322 // -----------------------------------------------------------------------------------------------
323 // Implementation of the ClassVisitor interface
324 // -----------------------------------------------------------------------------------------------
325
326 @Override
327 public void visit(
328 final int version,
329 final int access,
330 final String name,
331 final String signature,
332 final String superName,
333 final String[] interfaces) {
334 if (visitCalled) {
335 throw new IllegalStateException("visit must be called only once");
336 }
337 visitCalled = true;
338 checkState();
339 checkAccess(
340 access,
341 Opcodes.ACC_PUBLIC
342 | Opcodes.ACC_FINAL
343 | Opcodes.ACC_SUPER
344 | Opcodes.ACC_INTERFACE
345 | Opcodes.ACC_ABSTRACT
346 | Opcodes.ACC_SYNTHETIC
347 | Opcodes.ACC_ANNOTATION
348 | Opcodes.ACC_ENUM
349 | Opcodes.ACC_DEPRECATED
350 | Opcodes.ACC_MODULE);
351 if (name == null) {
352 throw new IllegalArgumentException("Illegal class name (null)");
353 }
354 if (!name.endsWith("package-info") && !name.endsWith("module-info")) {
355 CheckMethodAdapter.checkInternalName(name, "class name");
356 }
357 if ("java/lang/Object".equals(name)) {
358 if (superName != null) {
359 throw new IllegalArgumentException(
360 "The super class name of the Object class must be 'null'");
361 }
362 } else if (name.endsWith("module-info")) {
363 if (superName != null) {
364 throw new IllegalArgumentException(
365 "The super class name of a module-info class must be 'null'");
366 }
367 } else {
368 CheckMethodAdapter.checkInternalName(superName, "super class name");
369 }
370 if (signature != null) {
371 checkClassSignature(signature);
372 }
373 if ((access & Opcodes.ACC_INTERFACE) != 0 && !"java/lang/Object".equals(superName)) {
374 throw new IllegalArgumentException(
375 "The super class name of interfaces must be 'java/lang/Object'");
376 }
377 if (interfaces != null) {
378 for (int i = 0; i < interfaces.length; ++i) {
379 CheckMethodAdapter.checkInternalName(interfaces[i], "interface name at index " + i);
380 }
381 }
382 this.version = version;
383 super.visit(version, access, name, signature, superName, interfaces);
384 }
385
386 @Override
387 public void visitSource(final String file, final String debug) {
388 checkState();
389 if (visitSourceCalled) {
390 throw new IllegalStateException("visitSource can be called only once.");
391 }
392 visitSourceCalled = true;
393 super.visitSource(file, debug);
394 }
395
396 @Override
397 public ModuleVisitor visitModule(final String name, final int access, final String version) {
398 checkState();
399 if (visitModuleCalled) {
400 throw new IllegalStateException("visitModule can be called only once.");
401 }
402 visitModuleCalled = true;
403 checkFullyQualifiedName(name, "module name");
404 checkAccess(access, Opcodes.ACC_OPEN | Opcodes.ACC_SYNTHETIC | Opcodes.ACC_MANDATED);
405 CheckModuleAdapter checkModuleAdapter = new CheckModuleAdapter(
406 api, super.visitModule(name, access, version), (access & Opcodes.ACC_OPEN) != 0);
407 checkModuleAdapter.classVersion = this.version;
408 return checkModuleAdapter;
409 }
410
411 @Override
412 public void visitOuterClass(final String owner, final String name, final String descriptor) {
413 checkState();
414 if (visitOuterClassCalled) {
415 throw new IllegalStateException("visitOuterClass can be called only once.");
416 }
417 visitOuterClassCalled = true;
418 if (owner == null) {
419 throw new IllegalArgumentException("Illegal outer class owner");
420 }
421 if (descriptor != null) {
422 CheckMethodAdapter.checkMethodDescriptor(descriptor);
423 }
424 super.visitOuterClass(owner, name, descriptor);
425 }
426
427 @Override
428 public void visitInnerClass(
429 final String name, final String outerName, final String innerName, final int access) {
430 checkState();
431 CheckMethodAdapter.checkInternalName(name, "class name");
432 if (outerName != null) {
433 CheckMethodAdapter.checkInternalName(outerName, "outer class name");
434 }
435 if (innerName != null) {
436 int startIndex = 0;
437 while (startIndex < innerName.length() && Character.isDigit(innerName.charAt(startIndex))) {
438 startIndex++;
439 }
440 if (startIndex == 0 || startIndex < innerName.length()) {
441 CheckMethodAdapter.checkIdentifier(innerName, startIndex, -1, "inner class name");
442 }
443 }
444 checkAccess(
445 access,
446 Opcodes.ACC_PUBLIC
447 | Opcodes.ACC_PRIVATE
448 | Opcodes.ACC_PROTECTED
449 | Opcodes.ACC_STATIC
450 | Opcodes.ACC_FINAL
451 | Opcodes.ACC_INTERFACE
452 | Opcodes.ACC_ABSTRACT
453 | Opcodes.ACC_SYNTHETIC
454 | Opcodes.ACC_ANNOTATION
455 | Opcodes.ACC_ENUM);
456 super.visitInnerClass(name, outerName, innerName, access);
457 }
458
459 @Override
460 public FieldVisitor visitField(
461 final int access,
462 final String name,
463 final String descriptor,
464 final String signature,
465 final Object value) {
466 checkState();
467 checkAccess(
468 access,
469 Opcodes.ACC_PUBLIC
470 | Opcodes.ACC_PRIVATE
471 | Opcodes.ACC_PROTECTED
472 | Opcodes.ACC_STATIC
473 | Opcodes.ACC_FINAL
474 | Opcodes.ACC_VOLATILE
475 | Opcodes.ACC_TRANSIENT
476 | Opcodes.ACC_SYNTHETIC
477 | Opcodes.ACC_ENUM
478 | Opcodes.ACC_DEPRECATED);
479 CheckMethodAdapter.checkUnqualifiedName(version, name, "field name");
480 CheckMethodAdapter.checkDescriptor(descriptor, /* canBeVoid = */ false);
481 if (signature != null) {
482 checkFieldSignature(signature);
483 }
484 if (value != null) {
485 CheckMethodAdapter.checkConstant(value);
486 }
487 return new CheckFieldAdapter(api, super.visitField(access, name, descriptor, signature, value));
488 }
489
490 @Override
491 public MethodVisitor visitMethod(
492 final int access,
493 final String name,
494 final String descriptor,
495 final String signature,
496 final String[] exceptions) {
497 checkState();
498 checkAccess(
499 access,
500 Opcodes.ACC_PUBLIC
501 | Opcodes.ACC_PRIVATE
502 | Opcodes.ACC_PROTECTED
503 | Opcodes.ACC_STATIC
504 | Opcodes.ACC_FINAL
505 | Opcodes.ACC_SYNCHRONIZED
506 | Opcodes.ACC_BRIDGE
507 | Opcodes.ACC_VARARGS
508 | Opcodes.ACC_NATIVE
509 | Opcodes.ACC_ABSTRACT
510 | Opcodes.ACC_STRICT
511 | Opcodes.ACC_SYNTHETIC
512 | Opcodes.ACC_DEPRECATED);
513 if (!"<init>".equals(name) && !"<clinit>".equals(name)) {
514 CheckMethodAdapter.checkMethodIdentifier(version, name, "method name");
515 }
516 CheckMethodAdapter.checkMethodDescriptor(descriptor);
517 if (signature != null) {
518 checkMethodSignature(signature);
519 }
520 if (exceptions != null) {
521 for (int i = 0; i < exceptions.length; ++i) {
522 CheckMethodAdapter.checkInternalName(exceptions[i], "exception name at index " + i);
523 }
524 }
525 CheckMethodAdapter checkMethodAdapter;
526 if (checkDataFlow) {
527 checkMethodAdapter =
528 new CheckMethodAdapter(
529 api,
530 access,
531 name,
532 descriptor,
533 super.visitMethod(access, name, descriptor, signature, exceptions),
534 labelInsnIndices);
535 } else {
536 checkMethodAdapter =
537 new CheckMethodAdapter(
538 api,
539 super.visitMethod(access, name, descriptor, signature, exceptions),
540 labelInsnIndices);
541 }
542 checkMethodAdapter.version = version;
543 return checkMethodAdapter;
544 }
545
546 @Override
547 public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
548 checkState();
549 CheckMethodAdapter.checkDescriptor(descriptor, false);
550 return new CheckAnnotationAdapter(super.visitAnnotation(descriptor, visible));
551 }
552
553 @Override
554 public AnnotationVisitor visitTypeAnnotation(
555 final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
556 checkState();
557 int sort = new TypeReference(typeRef).getSort();
558 if (sort != TypeReference.CLASS_TYPE_PARAMETER
559 && sort != TypeReference.CLASS_TYPE_PARAMETER_BOUND
560 && sort != TypeReference.CLASS_EXTENDS) {
561 throw new IllegalArgumentException(
562 "Invalid type reference sort 0x" + Integer.toHexString(sort));
563 }
564 checkTypeRef(typeRef);
565 CheckMethodAdapter.checkDescriptor(descriptor, false);
566 return new CheckAnnotationAdapter(
567 super.visitTypeAnnotation(typeRef, typePath, descriptor, visible));
568 }
569
570 @Override
571 public void visitAttribute(final Attribute attribute) {
572 checkState();
573 if (attribute == null) {
574 throw new IllegalArgumentException("Invalid attribute (must not be null)");
575 }
576 super.visitAttribute(attribute);
577 }
578
579 @Override
580 public void visitEnd() {
581 checkState();
582 visitEndCalled = true;
583 super.visitEnd();
584 }
585
586 // -----------------------------------------------------------------------------------------------
587 // Utility methods
588 // -----------------------------------------------------------------------------------------------
589
590 /** Checks that the visit method has been called and that visitEnd has not been called. */
591 private void checkState() {
592 if (!visitCalled) {
593 throw new IllegalStateException("Cannot visit member before visit has been called.");
594 }
595 if (visitEndCalled) {
596 throw new IllegalStateException("Cannot visit member after visitEnd has been called.");
597 }
598 }
599
600 /**
601 * Checks that the given access flags do not contain invalid flags. This method also checks that
602 * mutually incompatible flags are not set simultaneously.
603 *
604 * @param access the access flags to be checked.
605 * @param possibleAccess the valid access flags.
606 */
607 static void checkAccess(final int access, final int possibleAccess) {
608 if ((access & ~possibleAccess) != 0) {
609 throw new IllegalArgumentException("Invalid access flags: " + access);
610 }
611 int publicProtectedPrivate = Opcodes.ACC_PUBLIC | Opcodes.ACC_PROTECTED | Opcodes.ACC_PRIVATE;
612 if (Integer.bitCount(access & publicProtectedPrivate) > 1) {
613 throw new IllegalArgumentException(
614 "public, protected and private are mutually exclusive: " + access);
615 }
616 if (Integer.bitCount(access & (Opcodes.ACC_FINAL | Opcodes.ACC_ABSTRACT)) > 1) {
617 throw new IllegalArgumentException("final and abstract are mutually exclusive: " + access);
618 }
619 }
620
621 /**
622 * Checks that the given name is a fully qualified name, using dots.
623 *
624 * @param name the name to be checked.
625 * @param source the source of 'name' (e.g 'module' for a module name).
626 */
627 static void checkFullyQualifiedName(final String name, final String source) {
628 try {
629 int startIndex = 0;
630 int dotIndex;
631 while ((dotIndex = name.indexOf('.', startIndex + 1)) != -1) {
632 CheckMethodAdapter.checkIdentifier(name, startIndex, dotIndex, null);
633 startIndex = dotIndex + 1;
634 }
635 CheckMethodAdapter.checkIdentifier(name, startIndex, name.length(), null);
636 } catch (IllegalArgumentException e) {
637 throw new IllegalArgumentException(
638 "Invalid " + source + " (must be a fully qualified name): " + name);
639 }
640 }
641
642 /**
643 * Checks a class signature.
644 *
645 * @param signature a string containing the signature that must be checked.
646 */
647 public static void checkClassSignature(final String signature) {
648 // From https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.9.1:
649 // ClassSignature:
650 // [TypeParameters] SuperclassSignature SuperinterfaceSignature*
651 // SuperclassSignature:
652 // ClassTypeSignature
653 // SuperinterfaceSignature:
654 // ClassTypeSignature
655 int pos = 0;
656 if (getChar(signature, 0) == '<') {
657 pos = checkTypeParameters(signature, pos);
658 }
659 pos = checkClassTypeSignature(signature, pos);
660 while (getChar(signature, pos) == 'L') {
661 pos = checkClassTypeSignature(signature, pos);
662 }
663 if (pos != signature.length()) {
664 throw new IllegalArgumentException(signature + ERROR_AT + pos);
665 }
666 }
667
668 /**
669 * Checks a method signature.
670 *
671 * @param signature a string containing the signature that must be checked.
672 */
673 public static void checkMethodSignature(final String signature) {
674 // From https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.9.1:
675 // MethodSignature:
676 // [TypeParameters] ( JavaTypeSignature* ) Result ThrowsSignature*
677 // Result:
678 // JavaTypeSignature
679 // VoidDescriptor
680 // ThrowsSignature:
681 // ^ ClassTypeSignature
682 // ^ TypeVariableSignature
683 int pos = 0;
684 if (getChar(signature, 0) == '<') {
685 pos = checkTypeParameters(signature, pos);
686 }
687 pos = checkChar('(', signature, pos);
688 while ("ZCBSIFJDL[T".indexOf(getChar(signature, pos)) != -1) {
689 pos = checkJavaTypeSignature(signature, pos);
690 }
691 pos = checkChar(')', signature, pos);
692 if (getChar(signature, pos) == 'V') {
693 ++pos;
694 } else {
695 pos = checkJavaTypeSignature(signature, pos);
696 }
697 while (getChar(signature, pos) == '^') {
698 ++pos;
699 if (getChar(signature, pos) == 'L') {
638700 pos = checkClassTypeSignature(signature, pos);
639 while (getChar(signature, pos) == 'L') {
640 pos = checkClassTypeSignature(signature, pos);
641 }
642 if (pos != signature.length()) {
643 throw new IllegalArgumentException(signature + ": error at index "
644 + pos);
645 }
646 }
647
648 /**
649 * Checks a method signature.
650 *
651 * @param signature
652 * a string containing the signature that must be checked.
653 */
654 public static void checkMethodSignature(final String signature) {
655 // MethodTypeSignature:
656 // FormalTypeParameters? ( TypeSignature* ) ( TypeSignature | V ) (
657 // ^ClassTypeSignature | ^TypeVariableSignature )*
658
659 int pos = 0;
660 if (getChar(signature, 0) == '<') {
661 pos = checkFormalTypeParameters(signature, pos);
662 }
663 pos = checkChar('(', signature, pos);
664 while ("ZCBSIFJDL[T".indexOf(getChar(signature, pos)) != -1) {
665 pos = checkTypeSignature(signature, pos);
666 }
667 pos = checkChar(')', signature, pos);
668 if (getChar(signature, pos) == 'V') {
669 ++pos;
670 } else {
671 pos = checkTypeSignature(signature, pos);
672 }
673 while (getChar(signature, pos) == '^') {
674 ++pos;
675 if (getChar(signature, pos) == 'L') {
676 pos = checkClassTypeSignature(signature, pos);
677 } else {
678 pos = checkTypeVariableSignature(signature, pos);
679 }
680 }
681 if (pos != signature.length()) {
682 throw new IllegalArgumentException(signature + ": error at index "
683 + pos);
684 }
685 }
686
687 /**
688 * Checks a field signature.
689 *
690 * @param signature
691 * a string containing the signature that must be checked.
692 */
693 public static void checkFieldSignature(final String signature) {
694 int pos = checkFieldTypeSignature(signature, 0);
695 if (pos != signature.length()) {
696 throw new IllegalArgumentException(signature + ": error at index "
697 + pos);
698 }
699 }
700
701 /**
702 * Checks the reference to a type in a type annotation.
703 *
704 * @param typeRef
705 * a reference to an annotated type.
706 * @param typePath
707 * the path to the annotated type argument, wildcard bound, array
708 * element type, or static inner type within 'typeRef'. May be
709 * <tt>null</tt> if the annotation targets 'typeRef' as a whole.
710 */
711 static void checkTypeRefAndPath(int typeRef, TypePath typePath) {
712 int mask = 0;
713 switch (typeRef >>> 24) {
714 case TypeReference.CLASS_TYPE_PARAMETER:
715 case TypeReference.METHOD_TYPE_PARAMETER:
716 case TypeReference.METHOD_FORMAL_PARAMETER:
717 mask = 0xFFFF0000;
718 break;
719 case TypeReference.FIELD:
720 case TypeReference.METHOD_RETURN:
721 case TypeReference.METHOD_RECEIVER:
722 case TypeReference.LOCAL_VARIABLE:
723 case TypeReference.RESOURCE_VARIABLE:
724 case TypeReference.INSTANCEOF:
725 case TypeReference.NEW:
726 case TypeReference.CONSTRUCTOR_REFERENCE:
727 case TypeReference.METHOD_REFERENCE:
728 mask = 0xFF000000;
729 break;
730 case TypeReference.CLASS_EXTENDS:
731 case TypeReference.CLASS_TYPE_PARAMETER_BOUND:
732 case TypeReference.METHOD_TYPE_PARAMETER_BOUND:
733 case TypeReference.THROWS:
734 case TypeReference.EXCEPTION_PARAMETER:
735 mask = 0xFFFFFF00;
736 break;
737 case TypeReference.CAST:
738 case TypeReference.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
739 case TypeReference.METHOD_INVOCATION_TYPE_ARGUMENT:
740 case TypeReference.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT:
741 case TypeReference.METHOD_REFERENCE_TYPE_ARGUMENT:
742 mask = 0xFF0000FF;
743 break;
744 default:
745 throw new IllegalArgumentException("Invalid type reference sort 0x"
746 + Integer.toHexString(typeRef >>> 24));
747 }
748 if ((typeRef & ~mask) != 0) {
749 throw new IllegalArgumentException("Invalid type reference 0x"
750 + Integer.toHexString(typeRef));
751 }
752 if (typePath != null) {
753 for (int i = 0; i < typePath.getLength(); ++i) {
754 int step = typePath.getStep(i);
755 if (step != TypePath.ARRAY_ELEMENT
756 && step != TypePath.INNER_TYPE
757 && step != TypePath.TYPE_ARGUMENT
758 && step != TypePath.WILDCARD_BOUND) {
759 throw new IllegalArgumentException(
760 "Invalid type path step " + i + " in " + typePath);
761 }
762 if (step != TypePath.TYPE_ARGUMENT
763 && typePath.getStepArgument(i) != 0) {
764 throw new IllegalArgumentException(
765 "Invalid type path step argument for step " + i
766 + " in " + typePath);
767 }
768 }
769 }
770 }
771
772 /**
773 * Checks the formal type parameters of a class or method signature.
774 *
775 * @param signature
776 * a string containing the signature that must be checked.
777 * @param pos
778 * index of first character to be checked.
779 * @return the index of the first character after the checked part.
780 */
781 private static int checkFormalTypeParameters(final String signature, int pos) {
782 // FormalTypeParameters:
783 // < FormalTypeParameter+ >
784
785 pos = checkChar('<', signature, pos);
786 pos = checkFormalTypeParameter(signature, pos);
787 while (getChar(signature, pos) != '>') {
788 pos = checkFormalTypeParameter(signature, pos);
789 }
701 } else {
702 pos = checkTypeVariableSignature(signature, pos);
703 }
704 }
705 if (pos != signature.length()) {
706 throw new IllegalArgumentException(signature + ERROR_AT + pos);
707 }
708 }
709
710 /**
711 * Checks a field signature.
712 *
713 * @param signature a string containing the signature that must be checked.
714 */
715 public static void checkFieldSignature(final String signature) {
716 // From https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.9.1:
717 // FieldSignature:
718 // ReferenceTypeSignature
719 int pos = checkReferenceTypeSignature(signature, 0);
720 if (pos != signature.length()) {
721 throw new IllegalArgumentException(signature + ERROR_AT + pos);
722 }
723 }
724
725 /**
726 * Checks the type parameters of a class or method signature.
727 *
728 * @param signature a string containing the signature that must be checked.
729 * @param startPos index of first character to be checked.
730 * @return the index of the first character after the checked part.
731 */
732 private static int checkTypeParameters(final String signature, final int startPos) {
733 // From https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.9.1:
734 // TypeParameters:
735 // < TypeParameter TypeParameter* >
736 int pos = startPos;
737 pos = checkChar('<', signature, pos);
738 pos = checkTypeParameter(signature, pos);
739 while (getChar(signature, pos) != '>') {
740 pos = checkTypeParameter(signature, pos);
741 }
742 return pos + 1;
743 }
744
745 /**
746 * Checks a type parameter of a class or method signature.
747 *
748 * @param signature a string containing the signature that must be checked.
749 * @param startPos index of first character to be checked.
750 * @return the index of the first character after the checked part.
751 */
752 private static int checkTypeParameter(final String signature, final int startPos) {
753 // From https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.9.1:
754 // TypeParameter:
755 // Identifier ClassBound InterfaceBound*
756 // ClassBound:
757 // : [ReferenceTypeSignature]
758 // InterfaceBound:
759 // : ReferenceTypeSignature
760 int pos = startPos;
761 pos = checkIdentifier(signature, pos);
762 pos = checkChar(':', signature, pos);
763 if ("L[T".indexOf(getChar(signature, pos)) != -1) {
764 pos = checkReferenceTypeSignature(signature, pos);
765 }
766 while (getChar(signature, pos) == ':') {
767 pos = checkReferenceTypeSignature(signature, pos + 1);
768 }
769 return pos;
770 }
771
772 /**
773 * Checks a reference type signature.
774 *
775 * @param signature a string containing the signature that must be checked.
776 * @param pos index of first character to be checked.
777 * @return the index of the first character after the checked part.
778 */
779 private static int checkReferenceTypeSignature(final String signature, final int pos) {
780 // From https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.9.1:
781 // ReferenceTypeSignature:
782 // ClassTypeSignature
783 // TypeVariableSignature
784 // ArrayTypeSignature
785 // ArrayTypeSignature:
786 // [ JavaTypeSignature
787 switch (getChar(signature, pos)) {
788 case 'L':
789 return checkClassTypeSignature(signature, pos);
790 case '[':
791 return checkJavaTypeSignature(signature, pos + 1);
792 default:
793 return checkTypeVariableSignature(signature, pos);
794 }
795 }
796
797 /**
798 * Checks a class type signature.
799 *
800 * @param signature a string containing the signature that must be checked.
801 * @param startPos index of first character to be checked.
802 * @return the index of the first character after the checked part.
803 */
804 private static int checkClassTypeSignature(final String signature, final int startPos) {
805 // From https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.9.1:
806 // ClassTypeSignature:
807 // L [PackageSpecifier] SimpleClassTypeSignature ClassTypeSignatureSuffix* ;
808 // PackageSpecifier:
809 // Identifier / PackageSpecifier*
810 // SimpleClassTypeSignature:
811 // Identifier [TypeArguments]
812 // ClassTypeSignatureSuffix:
813 // . SimpleClassTypeSignature
814 int pos = startPos;
815 pos = checkChar('L', signature, pos);
816 pos = checkIdentifier(signature, pos);
817 while (getChar(signature, pos) == '/') {
818 pos = checkIdentifier(signature, pos + 1);
819 }
820 if (getChar(signature, pos) == '<') {
821 pos = checkTypeArguments(signature, pos);
822 }
823 while (getChar(signature, pos) == '.') {
824 pos = checkIdentifier(signature, pos + 1);
825 if (getChar(signature, pos) == '<') {
826 pos = checkTypeArguments(signature, pos);
827 }
828 }
829 return checkChar(';', signature, pos);
830 }
831
832 /**
833 * Checks the type arguments in a class type signature.
834 *
835 * @param signature a string containing the signature that must be checked.
836 * @param startPos index of first character to be checked.
837 * @return the index of the first character after the checked part.
838 */
839 private static int checkTypeArguments(final String signature, final int startPos) {
840 // From https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.9.1:
841 // TypeArguments:
842 // < TypeArgument TypeArgument* >
843 int pos = startPos;
844 pos = checkChar('<', signature, pos);
845 pos = checkTypeArgument(signature, pos);
846 while (getChar(signature, pos) != '>') {
847 pos = checkTypeArgument(signature, pos);
848 }
849 return pos + 1;
850 }
851
852 /**
853 * Checks a type argument in a class type signature.
854 *
855 * @param signature a string containing the signature that must be checked.
856 * @param startPos index of first character to be checked.
857 * @return the index of the first character after the checked part.
858 */
859 private static int checkTypeArgument(final String signature, final int startPos) {
860 // From https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.9.1:
861 // TypeArgument:
862 // [WildcardIndicator] ReferenceTypeSignature
863 // *
864 // WildcardIndicator:
865 // +
866 // -
867 int pos = startPos;
868 char c = getChar(signature, pos);
869 if (c == '*') {
870 return pos + 1;
871 } else if (c == '+' || c == '-') {
872 pos++;
873 }
874 return checkReferenceTypeSignature(signature, pos);
875 }
876
877 /**
878 * Checks a type variable signature.
879 *
880 * @param signature a string containing the signature that must be checked.
881 * @param startPos index of first character to be checked.
882 * @return the index of the first character after the checked part.
883 */
884 private static int checkTypeVariableSignature(final String signature, final int startPos) {
885 // From https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.9.1:
886 // TypeVariableSignature:
887 // T Identifier ;
888 int pos = startPos;
889 pos = checkChar('T', signature, pos);
890 pos = checkIdentifier(signature, pos);
891 return checkChar(';', signature, pos);
892 }
893
894 /**
895 * Checks a Java type signature.
896 *
897 * @param signature a string containing the signature that must be checked.
898 * @param startPos index of first character to be checked.
899 * @return the index of the first character after the checked part.
900 */
901 private static int checkJavaTypeSignature(final String signature, final int startPos) {
902 // From https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.9.1:
903 // JavaTypeSignature:
904 // ReferenceTypeSignature
905 // BaseType
906 // BaseType:
907 // (one of)
908 // B C D F I J S Z
909 int pos = startPos;
910 switch (getChar(signature, pos)) {
911 case 'B':
912 case 'C':
913 case 'D':
914 case 'F':
915 case 'I':
916 case 'J':
917 case 'S':
918 case 'Z':
790919 return pos + 1;
791 }
792
793 /**
794 * Checks a formal type parameter of a class or method signature.
795 *
796 * @param signature
797 * a string containing the signature that must be checked.
798 * @param pos
799 * index of first character to be checked.
800 * @return the index of the first character after the checked part.
801 */
802 private static int checkFormalTypeParameter(final String signature, int pos) {
803 // FormalTypeParameter:
804 // Identifier : FieldTypeSignature? (: FieldTypeSignature)*
805
806 pos = checkIdentifier(signature, pos);
807 pos = checkChar(':', signature, pos);
808 if ("L[T".indexOf(getChar(signature, pos)) != -1) {
809 pos = checkFieldTypeSignature(signature, pos);
810 }
811 while (getChar(signature, pos) == ':') {
812 pos = checkFieldTypeSignature(signature, pos + 1);
813 }
814 return pos;
815 }
816
817 /**
818 * Checks a field type signature.
819 *
820 * @param signature
821 * a string containing the signature that must be checked.
822 * @param pos
823 * index of first character to be checked.
824 * @return the index of the first character after the checked part.
825 */
826 private static int checkFieldTypeSignature(final String signature, int pos) {
827 // FieldTypeSignature:
828 // ClassTypeSignature | ArrayTypeSignature | TypeVariableSignature
829 //
830 // ArrayTypeSignature:
831 // [ TypeSignature
832
833 switch (getChar(signature, pos)) {
834 case 'L':
835 return checkClassTypeSignature(signature, pos);
836 case '[':
837 return checkTypeSignature(signature, pos + 1);
838 default:
839 return checkTypeVariableSignature(signature, pos);
840 }
841 }
842
843 /**
844 * Checks a class type signature.
845 *
846 * @param signature
847 * a string containing the signature that must be checked.
848 * @param pos
849 * index of first character to be checked.
850 * @return the index of the first character after the checked part.
851 */
852 private static int checkClassTypeSignature(final String signature, int pos) {
853 // ClassTypeSignature:
854 // L Identifier ( / Identifier )* TypeArguments? ( . Identifier
855 // TypeArguments? )* ;
856
857 pos = checkChar('L', signature, pos);
858 pos = checkIdentifier(signature, pos);
859 while (getChar(signature, pos) == '/') {
860 pos = checkIdentifier(signature, pos + 1);
861 }
862 if (getChar(signature, pos) == '<') {
863 pos = checkTypeArguments(signature, pos);
864 }
865 while (getChar(signature, pos) == '.') {
866 pos = checkIdentifier(signature, pos + 1);
867 if (getChar(signature, pos) == '<') {
868 pos = checkTypeArguments(signature, pos);
869 }
870 }
871 return checkChar(';', signature, pos);
872 }
873
874 /**
875 * Checks the type arguments in a class type signature.
876 *
877 * @param signature
878 * a string containing the signature that must be checked.
879 * @param pos
880 * index of first character to be checked.
881 * @return the index of the first character after the checked part.
882 */
883 private static int checkTypeArguments(final String signature, int pos) {
884 // TypeArguments:
885 // < TypeArgument+ >
886
887 pos = checkChar('<', signature, pos);
888 pos = checkTypeArgument(signature, pos);
889 while (getChar(signature, pos) != '>') {
890 pos = checkTypeArgument(signature, pos);
891 }
892 return pos + 1;
893 }
894
895 /**
896 * Checks a type argument in a class type signature.
897 *
898 * @param signature
899 * a string containing the signature that must be checked.
900 * @param pos
901 * index of first character to be checked.
902 * @return the index of the first character after the checked part.
903 */
904 private static int checkTypeArgument(final String signature, int pos) {
905 // TypeArgument:
906 // * | ( ( + | - )? FieldTypeSignature )
907
908 char c = getChar(signature, pos);
909 if (c == '*') {
910 return pos + 1;
911 } else if (c == '+' || c == '-') {
912 pos++;
913 }
914 return checkFieldTypeSignature(signature, pos);
915 }
916
917 /**
918 * Checks a type variable signature.
919 *
920 * @param signature
921 * a string containing the signature that must be checked.
922 * @param pos
923 * index of first character to be checked.
924 * @return the index of the first character after the checked part.
925 */
926 private static int checkTypeVariableSignature(final String signature,
927 int pos) {
928 // TypeVariableSignature:
929 // T Identifier ;
930
931 pos = checkChar('T', signature, pos);
932 pos = checkIdentifier(signature, pos);
933 return checkChar(';', signature, pos);
934 }
935
936 /**
937 * Checks a type signature.
938 *
939 * @param signature
940 * a string containing the signature that must be checked.
941 * @param pos
942 * index of first character to be checked.
943 * @return the index of the first character after the checked part.
944 */
945 private static int checkTypeSignature(final String signature, int pos) {
946 // TypeSignature:
947 // Z | C | B | S | I | F | J | D | FieldTypeSignature
948
949 switch (getChar(signature, pos)) {
950 case 'Z':
951 case 'C':
952 case 'B':
953 case 'S':
954 case 'I':
955 case 'F':
956 case 'J':
957 case 'D':
958 return pos + 1;
959 default:
960 return checkFieldTypeSignature(signature, pos);
961 }
962 }
963
964 /**
965 * Checks an identifier.
966 *
967 * @param signature
968 * a string containing the signature that must be checked.
969 * @param pos
970 * index of first character to be checked.
971 * @return the index of the first character after the checked part.
972 */
973 private static int checkIdentifier(final String signature, int pos) {
974 if (!Character.isJavaIdentifierStart(getChar(signature, pos))) {
975 throw new IllegalArgumentException(signature
976 + ": identifier expected at index " + pos);
977 }
978 ++pos;
979 while (Character.isJavaIdentifierPart(getChar(signature, pos))) {
980 ++pos;
981 }
982 return pos;
983 }
984
985 /**
986 * Checks a single character.
987 *
988 * @param signature
989 * a string containing the signature that must be checked.
990 * @param pos
991 * index of first character to be checked.
992 * @return the index of the first character after the checked part.
993 */
994 private static int checkChar(final char c, final String signature, int pos) {
995 if (getChar(signature, pos) == c) {
996 return pos + 1;
997 }
998 throw new IllegalArgumentException(signature + ": '" + c
999 + "' expected at index " + pos);
1000 }
1001
1002 /**
1003 * Returns the signature car at the given index.
1004 *
1005 * @param signature
1006 * a signature.
1007 * @param pos
1008 * an index in signature.
1009 * @return the character at the given index, or 0 if there is no such
1010 * character.
1011 */
1012 private static char getChar(final String signature, int pos) {
1013 return pos < signature.length() ? signature.charAt(pos) : (char) 0;
1014 }
920 default:
921 return checkReferenceTypeSignature(signature, pos);
922 }
923 }
924
925 /**
926 * Checks an identifier.
927 *
928 * @param signature a string containing the signature that must be checked.
929 * @param startPos index of first character to be checked.
930 * @return the index of the first character after the checked part.
931 */
932 private static int checkIdentifier(final String signature, final int startPos) {
933 int pos = startPos;
934 if (!Character.isJavaIdentifierStart(getChar(signature, pos))) {
935 throw new IllegalArgumentException(signature + ": identifier expected at index " + pos);
936 }
937 ++pos;
938 while (Character.isJavaIdentifierPart(getChar(signature, pos))) {
939 ++pos;
940 }
941 return pos;
942 }
943
944 /**
945 * Checks a single character.
946 *
947 * @param c a character.
948 * @param signature a string containing the signature that must be checked.
949 * @param pos index of first character to be checked.
950 * @return the index of the first character after the checked part.
951 */
952 private static int checkChar(final char c, final String signature, final int pos) {
953 if (getChar(signature, pos) == c) {
954 return pos + 1;
955 }
956 throw new IllegalArgumentException(signature + ": '" + c + "' expected at index " + pos);
957 }
958
959 /**
960 * Returns the string character at the given index, or 0.
961 *
962 * @param string a string.
963 * @param pos an index in 'string'.
964 * @return the character at the given index, or 0 if there is no such character.
965 */
966 private static char getChar(final String string, final int pos) {
967 return pos < string.length() ? string.charAt(pos) : (char) 0;
968 }
969
970 /**
971 * Checks the reference to a type in a type annotation.
972 *
973 * @param typeRef a reference to an annotated type.
974 */
975 static void checkTypeRef(final int typeRef) {
976 int mask = 0;
977 switch (typeRef >>> 24) {
978 case TypeReference.CLASS_TYPE_PARAMETER:
979 case TypeReference.METHOD_TYPE_PARAMETER:
980 case TypeReference.METHOD_FORMAL_PARAMETER:
981 mask = 0xFFFF0000;
982 break;
983 case TypeReference.FIELD:
984 case TypeReference.METHOD_RETURN:
985 case TypeReference.METHOD_RECEIVER:
986 case TypeReference.LOCAL_VARIABLE:
987 case TypeReference.RESOURCE_VARIABLE:
988 case TypeReference.INSTANCEOF:
989 case TypeReference.NEW:
990 case TypeReference.CONSTRUCTOR_REFERENCE:
991 case TypeReference.METHOD_REFERENCE:
992 mask = 0xFF000000;
993 break;
994 case TypeReference.CLASS_EXTENDS:
995 case TypeReference.CLASS_TYPE_PARAMETER_BOUND:
996 case TypeReference.METHOD_TYPE_PARAMETER_BOUND:
997 case TypeReference.THROWS:
998 case TypeReference.EXCEPTION_PARAMETER:
999 mask = 0xFFFFFF00;
1000 break;
1001 case TypeReference.CAST:
1002 case TypeReference.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
1003 case TypeReference.METHOD_INVOCATION_TYPE_ARGUMENT:
1004 case TypeReference.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT:
1005 case TypeReference.METHOD_REFERENCE_TYPE_ARGUMENT:
1006 mask = 0xFF0000FF;
1007 break;
1008 default:
1009 throw new AssertionError();
1010 }
1011 if ((typeRef & ~mask) != 0) {
1012 throw new IllegalArgumentException(
1013 "Invalid type reference 0x" + Integer.toHexString(typeRef));
1014 }
1015 }
10151016 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.util;
3028
3129 import org.eclipse.persistence.internal.libraries.asm.AnnotationVisitor;
3735
3836 /**
3937 * A {@link FieldVisitor} that checks that its methods are properly used.
38 *
39 * @author Eric Bruneton
4040 */
4141 public class CheckFieldAdapter extends FieldVisitor {
4242
43 private boolean end;
43 /** Whether the {@link #visitEnd} method has been called. */
44 private boolean visitEndCalled;
4445
45 /**
46 * Constructs a new {@link CheckFieldAdapter}. <i>Subclasses must not use
47 * this constructor</i>. Instead, they must use the
48 * {@link #CheckFieldAdapter(int, FieldVisitor)} version.
49 *
50 * @param fv
51 * the field visitor to which this adapter must delegate calls.
52 * @throws IllegalStateException
53 * If a subclass calls this constructor.
54 */
55 public CheckFieldAdapter(final FieldVisitor fv) {
56 this(Opcodes.ASM6, fv);
57 if (getClass() != CheckFieldAdapter.class) {
58 throw new IllegalStateException();
59 }
46 /**
47 * Constructs a new {@link CheckFieldAdapter}. <i>Subclasses must not use this constructor</i>.
48 * Instead, they must use the {@link #CheckFieldAdapter(int, FieldVisitor)} version.
49 *
50 * @param fieldVisitor the field visitor to which this adapter must delegate calls.
51 * @throws IllegalStateException If a subclass calls this constructor.
52 */
53 public CheckFieldAdapter(final FieldVisitor fieldVisitor) {
54 this(Opcodes.ASM6, fieldVisitor);
55 if (getClass() != CheckFieldAdapter.class) {
56 throw new IllegalStateException();
6057 }
58 }
6159
62 /**
63 * Constructs a new {@link CheckFieldAdapter}.
64 *
65 * @param api
66 * the ASM API version implemented by this visitor. Must be one
67 * of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
68 * @param fv
69 * the field visitor to which this adapter must delegate calls.
70 */
71 protected CheckFieldAdapter(final int api, final FieldVisitor fv) {
72 super(api, fv);
60 /**
61 * Constructs a new {@link CheckFieldAdapter}.
62 *
63 * @param api the ASM API version implemented by this visitor. Must be one of {@link
64 * Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
65 * @param fieldVisitor the field visitor to which this adapter must delegate calls.
66 */
67 protected CheckFieldAdapter(final int api, final FieldVisitor fieldVisitor) {
68 super(api, fieldVisitor);
69 }
70
71 @Override
72 public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
73 checkVisitEndNotCalled();
74 CheckMethodAdapter.checkDescriptor(descriptor, false);
75 return new CheckAnnotationAdapter(super.visitAnnotation(descriptor, visible));
76 }
77
78 @Override
79 public AnnotationVisitor visitTypeAnnotation(
80 final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
81 checkVisitEndNotCalled();
82 int sort = new TypeReference(typeRef).getSort();
83 if (sort != TypeReference.FIELD) {
84 throw new IllegalArgumentException(
85 "Invalid type reference sort 0x" + Integer.toHexString(sort));
7386 }
87 CheckClassAdapter.checkTypeRef(typeRef);
88 CheckMethodAdapter.checkDescriptor(descriptor, false);
89 return new CheckAnnotationAdapter(
90 super.visitTypeAnnotation(typeRef, typePath, descriptor, visible));
91 }
7492
75 @Override
76 public AnnotationVisitor visitAnnotation(final String desc,
77 final boolean visible) {
78 checkEnd();
79 CheckMethodAdapter.checkDesc(desc, false);
80 return new CheckAnnotationAdapter(super.visitAnnotation(desc, visible));
93 @Override
94 public void visitAttribute(final Attribute attribute) {
95 checkVisitEndNotCalled();
96 if (attribute == null) {
97 throw new IllegalArgumentException("Invalid attribute (must not be null)");
8198 }
99 super.visitAttribute(attribute);
100 }
82101
83 @Override
84 public AnnotationVisitor visitTypeAnnotation(final int typeRef,
85 final TypePath typePath, final String desc, final boolean visible) {
86 checkEnd();
87 int sort = typeRef >>> 24;
88 if (sort != TypeReference.FIELD) {
89 throw new IllegalArgumentException("Invalid type reference sort 0x"
90 + Integer.toHexString(sort));
91 }
92 CheckClassAdapter.checkTypeRefAndPath(typeRef, typePath);
93 CheckMethodAdapter.checkDesc(desc, false);
94 return new CheckAnnotationAdapter(super.visitTypeAnnotation(typeRef,
95 typePath, desc, visible));
102 @Override
103 public void visitEnd() {
104 checkVisitEndNotCalled();
105 visitEndCalled = true;
106 super.visitEnd();
107 }
108
109 private void checkVisitEndNotCalled() {
110 if (visitEndCalled) {
111 throw new IllegalStateException("Cannot call a visit method after visitEnd has been called");
96112 }
97
98 @Override
99 public void visitAttribute(final Attribute attr) {
100 checkEnd();
101 if (attr == null) {
102 throw new IllegalArgumentException(
103 "Invalid attribute (must not be null)");
104 }
105 super.visitAttribute(attr);
106 }
107
108 @Override
109 public void visitEnd() {
110 checkEnd();
111 end = true;
112 super.visitEnd();
113 }
114
115 private void checkEnd() {
116 if (end) {
117 throw new IllegalStateException(
118 "Cannot call a visit method after visitEnd has been called");
119 }
120 }
113 }
121114 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.util;
3028
3129 import java.io.PrintWriter;
3230 import java.io.StringWriter;
33 import java.lang.reflect.Field;
3431 import java.util.ArrayList;
3532 import java.util.HashMap;
3633 import java.util.HashSet;
4946 import org.eclipse.persistence.internal.libraries.asm.TypeReference;
5047 import org.eclipse.persistence.internal.libraries.asm.tree.MethodNode;
5148 import org.eclipse.persistence.internal.libraries.asm.tree.analysis.Analyzer;
49 import org.eclipse.persistence.internal.libraries.asm.tree.analysis.AnalyzerException;
5250 import org.eclipse.persistence.internal.libraries.asm.tree.analysis.BasicValue;
5351 import org.eclipse.persistence.internal.libraries.asm.tree.analysis.BasicVerifier;
5452
5553 /**
56 * A {@link MethodVisitor} that checks that its methods are properly used. More
57 * precisely this method adapter checks each instruction individually, i.e.,
58 * each visit method checks some preconditions based <i>only</i> on its
59 * arguments - such as the fact that the given opcode is correct for a given
60 * visit method. This adapter can also perform some basic data flow checks (more
61 * precisely those that can be performed without the full class hierarchy - see
62 * {@link org.eclipse.persistence.internal.libraries.asm.tree.analysis.BasicVerifier}). For instance in a
63 * method whose signature is <tt>void m ()</tt>, the invalid instruction
64 * IRETURN, or the invalid sequence IADD L2I will be detected if the data flow
65 * checks are enabled. These checks are enabled by using the
66 * {@link #CheckMethodAdapter(int,String,String,MethodVisitor,Map)} constructor.
67 * They are not performed if any other constructor is used.
68 *
54 * A {@link MethodVisitor} that checks that its methods are properly used. More precisely this
55 * method adapter checks each instruction individually, i.e., each visit method checks some
56 * preconditions based <i>only</i> on its arguments - such as the fact that the given opcode is
57 * correct for a given visit method. This adapter can also perform some basic data flow checks (more
58 * precisely those that can be performed without the full class hierarchy - see {@link
59 * org.eclipse.persistence.internal.libraries.asm.tree.analysis.BasicVerifier}). For instance in a method whose signature is
60 * <tt>void m ()</tt>, the invalid instruction IRETURN, or the invalid sequence IADD L2I will be
61 * detected if the data flow checks are enabled. These checks are enabled by using the {@link
62 * #CheckMethodAdapter(int,String,String,MethodVisitor,Map)} constructor. They are not performed if
63 * any other constructor is used.
64 *
6965 * @author Eric Bruneton
7066 */
7167 public class CheckMethodAdapter extends MethodVisitor {
7268
73 /**
74 * The class version number.
75 */
76 public int version;
77
78 /**
79 * The access flags of the method.
80 */
81 private int access;
82
83 /**
84 * <tt>true</tt> if the visitCode method has been called.
85 */
86 private boolean startCode;
87
88 /**
89 * <tt>true</tt> if the visitMaxs method has been called.
90 */
91 private boolean endCode;
92
93 /**
94 * <tt>true</tt> if the visitEnd method has been called.
95 */
96 private boolean endMethod;
97
98 /**
99 * Number of visited instructions.
100 */
101 private int insnCount;
102
103 /**
104 * The already visited labels. This map associate Integer values to pseudo
105 * code offsets.
106 */
107 private final Map<Label, Integer> labels;
108
109 /**
110 * The labels used in this method. Every used label must be visited with
111 * visitLabel before the end of the method (i.e. should be in #labels).
112 */
113 private Set<Label> usedLabels;
114
115 /**
116 * Number of visited frames in expanded form.
117 */
118 private int expandedFrames;
119
120 /**
121 * Number of visited frames in compressed form.
122 */
123 private int compressedFrames;
124
125 /**
126 * Number of instructions before the last visited frame.
127 */
128 private int lastFrame = -1;
129
130 /**
131 * The exception handler ranges. Each pair of list element contains the
132 * start and end labels of an exception handler block.
133 */
134 private List<Label> handlers;
135
136 /**
137 * Code of the visit method to be used for each opcode.
138 */
139 private static final int[] TYPE;
140
141 /**
142 * The Label.status field.
143 */
144 private static Field labelStatusField;
145
146 static {
147 String s = "BBBBBBBBBBBBBBBBCCIAADDDDDAAAAAAAAAAAAAAAAAAAABBBBBBBBDD"
148 + "DDDAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
149 + "BBBBBBBBBBBBBBBBBBBJBBBBBBBBBBBBBBBBBBBBHHHHHHHHHHHHHHHHD"
150 + "KLBBBBBBFFFFGGGGAECEBBEEBBAMHHAA";
151 TYPE = new int[s.length()];
152 for (int i = 0; i < TYPE.length; ++i) {
153 TYPE[i] = s.charAt(i) - 'A' - 1;
69 /** The 'generic' instruction visit methods (i.e. those that take an opcode argument). */
70 private enum Method {
71 VISIT_INSN,
72 VISIT_INT_INSN,
73 VISIT_VAR_INSN,
74 VISIT_TYPE_INSN,
75 VISIT_FIELD_INSN,
76 VISIT_METHOD_INSN,
77 VISIT_JUMP_INSN
78 }
79
80 /** The method to use to visit each instruction. Only generic methods are represented here. */
81 private static final Method[] OPCODE_METHODS = {
82 Method.VISIT_INSN, // NOP
83 Method.VISIT_INSN, // ACONST_NULL
84 Method.VISIT_INSN, // ICONST_M1
85 Method.VISIT_INSN, // ICONST_0
86 Method.VISIT_INSN, // ICONST_1
87 Method.VISIT_INSN, // ICONST_2
88 Method.VISIT_INSN, // ICONST_3
89 Method.VISIT_INSN, // ICONST_4
90 Method.VISIT_INSN, // ICONST_5
91 Method.VISIT_INSN, // LCONST_0
92 Method.VISIT_INSN, // LCONST_1
93 Method.VISIT_INSN, // FCONST_0
94 Method.VISIT_INSN, // FCONST_1
95 Method.VISIT_INSN, // FCONST_2
96 Method.VISIT_INSN, // DCONST_0
97 Method.VISIT_INSN, // DCONST_1
98 Method.VISIT_INT_INSN, // BIPUSH
99 Method.VISIT_INT_INSN, // SIPUSH
100 null, // LDC
101 null, // LDC_W
102 null, // LDC2_W
103 Method.VISIT_VAR_INSN, // ILOAD
104 Method.VISIT_VAR_INSN, // LLOAD
105 Method.VISIT_VAR_INSN, // FLOAD
106 Method.VISIT_VAR_INSN, // DLOAD
107 Method.VISIT_VAR_INSN, // ALOAD
108 null, // ILOAD_0
109 null, // ILOAD_1
110 null, // ILOAD_2
111 null, // ILOAD_3
112 null, // LLOAD_0
113 null, // LLOAD_1
114 null, // LLOAD_2
115 null, // LLOAD_3
116 null, // FLOAD_0
117 null, // FLOAD_1
118 null, // FLOAD_2
119 null, // FLOAD_3
120 null, // DLOAD_0
121 null, // DLOAD_1
122 null, // DLOAD_2
123 null, // DLOAD_3
124 null, // ALOAD_0
125 null, // ALOAD_1
126 null, // ALOAD_2
127 null, // ALOAD_3
128 Method.VISIT_INSN, // IALOAD
129 Method.VISIT_INSN, // LALOAD
130 Method.VISIT_INSN, // FALOAD
131 Method.VISIT_INSN, // DALOAD
132 Method.VISIT_INSN, // AALOAD
133 Method.VISIT_INSN, // BALOAD
134 Method.VISIT_INSN, // CALOAD
135 Method.VISIT_INSN, // SALOAD
136 Method.VISIT_VAR_INSN, // ISTORE
137 Method.VISIT_VAR_INSN, // LSTORE
138 Method.VISIT_VAR_INSN, // FSTORE
139 Method.VISIT_VAR_INSN, // DSTORE
140 Method.VISIT_VAR_INSN, // ASTORE
141 null, // ISTORE_0
142 null, // ISTORE_1
143 null, // ISTORE_2
144 null, // ISTORE_3
145 null, // LSTORE_0
146 null, // LSTORE_1
147 null, // LSTORE_2
148 null, // LSTORE_3
149 null, // FSTORE_0
150 null, // FSTORE_1
151 null, // FSTORE_2
152 null, // FSTORE_3
153 null, // DSTORE_0
154 null, // DSTORE_1
155 null, // DSTORE_2
156 null, // DSTORE_3
157 null, // ASTORE_0
158 null, // ASTORE_1
159 null, // ASTORE_2
160 null, // ASTORE_3
161 Method.VISIT_INSN, // IASTORE
162 Method.VISIT_INSN, // LASTORE
163 Method.VISIT_INSN, // FASTORE
164 Method.VISIT_INSN, // DASTORE
165 Method.VISIT_INSN, // AASTORE
166 Method.VISIT_INSN, // BASTORE
167 Method.VISIT_INSN, // CASTORE
168 Method.VISIT_INSN, // SASTORE
169 Method.VISIT_INSN, // POP
170 Method.VISIT_INSN, // POP2
171 Method.VISIT_INSN, // DUP
172 Method.VISIT_INSN, // DUP_X1
173 Method.VISIT_INSN, // DUP_X2
174 Method.VISIT_INSN, // DUP2
175 Method.VISIT_INSN, // DUP2_X1
176 Method.VISIT_INSN, // DUP2_X2
177 Method.VISIT_INSN, // SWAP
178 Method.VISIT_INSN, // IADD
179 Method.VISIT_INSN, // LADD
180 Method.VISIT_INSN, // FADD
181 Method.VISIT_INSN, // DADD
182 Method.VISIT_INSN, // ISUB
183 Method.VISIT_INSN, // LSUB
184 Method.VISIT_INSN, // FSUB
185 Method.VISIT_INSN, // DSUB
186 Method.VISIT_INSN, // IMUL
187 Method.VISIT_INSN, // LMUL
188 Method.VISIT_INSN, // FMUL
189 Method.VISIT_INSN, // DMUL
190 Method.VISIT_INSN, // IDIV
191 Method.VISIT_INSN, // LDIV
192 Method.VISIT_INSN, // FDIV
193 Method.VISIT_INSN, // DDIV
194 Method.VISIT_INSN, // IREM
195 Method.VISIT_INSN, // LREM
196 Method.VISIT_INSN, // FREM
197 Method.VISIT_INSN, // DREM
198 Method.VISIT_INSN, // INEG
199 Method.VISIT_INSN, // LNEG
200 Method.VISIT_INSN, // FNEG
201 Method.VISIT_INSN, // DNEG
202 Method.VISIT_INSN, // ISHL
203 Method.VISIT_INSN, // LSHL
204 Method.VISIT_INSN, // ISHR
205 Method.VISIT_INSN, // LSHR
206 Method.VISIT_INSN, // IUSHR
207 Method.VISIT_INSN, // LUSHR
208 Method.VISIT_INSN, // IAND
209 Method.VISIT_INSN, // LAND
210 Method.VISIT_INSN, // IOR
211 Method.VISIT_INSN, // LOR
212 Method.VISIT_INSN, // IXOR
213 Method.VISIT_INSN, // LXOR
214 null, // IINC
215 Method.VISIT_INSN, // I2L
216 Method.VISIT_INSN, // I2F
217 Method.VISIT_INSN, // I2D
218 Method.VISIT_INSN, // L2I
219 Method.VISIT_INSN, // L2F
220 Method.VISIT_INSN, // L2D
221 Method.VISIT_INSN, // F2I
222 Method.VISIT_INSN, // F2L
223 Method.VISIT_INSN, // F2D
224 Method.VISIT_INSN, // D2I
225 Method.VISIT_INSN, // D2L
226 Method.VISIT_INSN, // D2F
227 Method.VISIT_INSN, // I2B
228 Method.VISIT_INSN, // I2C
229 Method.VISIT_INSN, // I2S
230 Method.VISIT_INSN, // LCMP
231 Method.VISIT_INSN, // FCMPL
232 Method.VISIT_INSN, // FCMPG
233 Method.VISIT_INSN, // DCMPL
234 Method.VISIT_INSN, // DCMPG
235 Method.VISIT_JUMP_INSN, // IFEQ
236 Method.VISIT_JUMP_INSN, // IFNE
237 Method.VISIT_JUMP_INSN, // IFLT
238 Method.VISIT_JUMP_INSN, // IFGE
239 Method.VISIT_JUMP_INSN, // IFGT
240 Method.VISIT_JUMP_INSN, // IFLE
241 Method.VISIT_JUMP_INSN, // IF_ICMPEQ
242 Method.VISIT_JUMP_INSN, // IF_ICMPNE
243 Method.VISIT_JUMP_INSN, // IF_ICMPLT
244 Method.VISIT_JUMP_INSN, // IF_ICMPGE
245 Method.VISIT_JUMP_INSN, // IF_ICMPGT
246 Method.VISIT_JUMP_INSN, // IF_ICMPLE
247 Method.VISIT_JUMP_INSN, // IF_ACMPEQ
248 Method.VISIT_JUMP_INSN, // IF_ACMPNE
249 Method.VISIT_JUMP_INSN, // GOTO
250 Method.VISIT_JUMP_INSN, // JSR
251 Method.VISIT_VAR_INSN, // RET
252 null, // TABLESWITCH
253 null, // LOOKUPSWITCH
254 Method.VISIT_INSN, // IRETURN
255 Method.VISIT_INSN, // LRETURN
256 Method.VISIT_INSN, // FRETURN
257 Method.VISIT_INSN, // DRETURN
258 Method.VISIT_INSN, // ARETURN
259 Method.VISIT_INSN, // RETURN
260 Method.VISIT_FIELD_INSN, // GETSTATIC
261 Method.VISIT_FIELD_INSN, // PUTSTATIC
262 Method.VISIT_FIELD_INSN, // GETFIELD
263 Method.VISIT_FIELD_INSN, // PUTFIELD
264 Method.VISIT_METHOD_INSN, // INVOKEVIRTUAL
265 Method.VISIT_METHOD_INSN, // INVOKESPECIAL
266 Method.VISIT_METHOD_INSN, // INVOKESTATIC
267 Method.VISIT_METHOD_INSN, // INVOKEINTERFACE
268 null, // INVOKEDYNAMIC
269 Method.VISIT_TYPE_INSN, // NEW
270 Method.VISIT_INT_INSN, // NEWARRAY
271 Method.VISIT_TYPE_INSN, // ANEWARRAY
272 Method.VISIT_INSN, // ARRAYLENGTH
273 Method.VISIT_INSN, // ATHROW
274 Method.VISIT_TYPE_INSN, // CHECKCAST
275 Method.VISIT_TYPE_INSN, // INSTANCEOF
276 Method.VISIT_INSN, // MONITORENTER
277 Method.VISIT_INSN, // MONITOREXIT
278 null, // WIDE
279 null, // MULTIANEWARRAY
280 Method.VISIT_JUMP_INSN, // IFNULL
281 Method.VISIT_JUMP_INSN // IFNONNULL
282 };
283
284 private static final String INVALID = "Invalid ";
285 private static final String INVALID_DESCRIPTOR = "Invalid descriptor: ";
286 private static final String INVALID_TYPE_REFERENCE = "Invalid type reference sort 0x";
287 private static final String INVALID_LOCAL_VARIABLE_INDEX = "Invalid local variable index";
288 private static final String MUST_NOT_BE_NULL_OR_EMPTY = " (must not be null or empty)";
289 private static final String START_LABEL = "start label";
290 private static final String END_LABEL = "end label";
291
292 /** The class version number. */
293 public int version;
294
295 /** The access flags of the visited method. */
296 private int access;
297
298 /**
299 * The number of method parameters that can have runtime visible annotations. 0 means that all the
300 * parameters from the method descriptor can have annotations.
301 */
302 private int visibleAnnotableParameterCount;
303
304 /**
305 * The number of method parameters that can have runtime invisible annotations. 0 means that all
306 * the parameters from the method descriptor can have annotations.
307 */
308 private int invisibleAnnotableParameterCount;
309
310 /** Whether the {@link #visitCode} method has been called. */
311 private boolean visitCodeCalled;
312
313 /** Whether the {@link #visitMaxs} method has been called. */
314 private boolean visitMaxCalled;
315
316 /** Whether the {@link #visitEnd} method has been called. */
317 private boolean visitEndCalled;
318
319 /** The number of visited instructions so far. */
320 private int insnCount;
321
322 /** The index of the instruction designated by each visited label. */
323 private final Map<Label, Integer> labelInsnIndices;
324
325 /** The labels referenced by the visited method. */
326 private Set<Label> referencedLabels;
327
328 /** The index of the instruction corresponding to the last visited stack map frame. */
329 private int lastFrameInsnIndex = -1;
330
331 /** The number of visited frames in expanded form. */
332 private int numExpandedFrames;
333
334 /** The number of visited frames in compressed form. */
335 private int numCompressedFrames;
336
337 /**
338 * The exception handler ranges. Each pair of list element contains the start and end labels of an
339 * exception handler block.
340 */
341 private List<Label> handlers;
342
343 /**
344 * Constructs a new {@link CheckMethodAdapter} object. This method adapter will not perform any
345 * data flow check (see {@link #CheckMethodAdapter(int,String,String,MethodVisitor,Map)}).
346 * <i>Subclasses must not use this constructor</i>. Instead, they must use the {@link
347 * #CheckMethodAdapter(int, MethodVisitor, Map)} version.
348 *
349 * @param methodvisitor the method visitor to which this adapter must delegate calls.
350 */
351 public CheckMethodAdapter(final MethodVisitor methodvisitor) {
352 this(methodvisitor, new HashMap<Label, Integer>());
353 }
354
355 /**
356 * Constructs a new {@link CheckMethodAdapter} object. This method adapter will not perform any
357 * data flow check (see {@link #CheckMethodAdapter(int,String,String,MethodVisitor,Map)}).
358 * <i>Subclasses must not use this constructor</i>. Instead, they must use the {@link
359 * #CheckMethodAdapter(int, MethodVisitor, Map)} version.
360 *
361 * @param methodVisitor the method visitor to which this adapter must delegate calls.
362 * @param labelInsnIndices the index of the instruction designated by each visited label so far
363 * (in other methods). This map is updated with the labels from the visited method.
364 * @throws IllegalStateException If a subclass calls this constructor.
365 */
366 public CheckMethodAdapter(
367 final MethodVisitor methodVisitor, final Map<Label, Integer> labelInsnIndices) {
368 this(Opcodes.ASM6, methodVisitor, labelInsnIndices);
369 if (getClass() != CheckMethodAdapter.class) {
370 throw new IllegalStateException();
371 }
372 }
373
374 /**
375 * Constructs a new {@link CheckMethodAdapter} object. This method adapter will not perform any
376 * data flow check (see {@link #CheckMethodAdapter(int,String,String,MethodVisitor,Map)}).
377 *
378 * @param api the ASM API version implemented by this CheckMethodAdapter. Must be one of {@link
379 * Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
380 * @param methodVisitor the method visitor to which this adapter must delegate calls.
381 * @param labelInsnIndices the index of the instruction designated by each visited label so far
382 * (in other methods). This map is updated with the labels from the visited method.
383 */
384 protected CheckMethodAdapter(
385 final int api,
386 final MethodVisitor methodVisitor,
387 final Map<Label, Integer> labelInsnIndices) {
388 super(api, methodVisitor);
389 this.labelInsnIndices = labelInsnIndices;
390 this.referencedLabels = new HashSet<Label>();
391 this.handlers = new ArrayList<Label>();
392 }
393
394 /**
395 * Constructs a new {@link CheckMethodAdapter} object. This method adapter will perform basic data
396 * flow checks. For instance in a method whose signature is <tt>void m ()</tt>, the invalid
397 * instruction IRETURN, or the invalid sequence IADD L2I will be detected. <i>Subclasses must not
398 * use this constructor</i>. Instead, they must use the {@link
399 * #CheckMethodAdapter(int,int,String,String,MethodVisitor,Map)} version.
400 *
401 * @param access the method's access flags.
402 * @param name the method's name.
403 * @param descriptor the method's descriptor (see {@link Type}).
404 * @param methodVisitor the method visitor to which this adapter must delegate calls.
405 * @param labelInsnIndices the index of the instruction designated by each visited label so far
406 * (in other methods). This map is updated with the labels from the visited method.
407 */
408 public CheckMethodAdapter(
409 final int access,
410 final String name,
411 final String descriptor,
412 final MethodVisitor methodVisitor,
413 final Map<Label, Integer> labelInsnIndices) {
414 this(Opcodes.ASM6, access, name, descriptor, methodVisitor, labelInsnIndices);
415 if (getClass() != CheckMethodAdapter.class) {
416 throw new IllegalStateException();
417 }
418 }
419
420 /**
421 * Constructs a new {@link CheckMethodAdapter} object. This method adapter will perform basic data
422 * flow checks. For instance in a method whose signature is <tt>void m ()</tt>, the invalid
423 * instruction IRETURN, or the invalid sequence IADD L2I will be detected.
424 *
425 * @param api the ASM API version implemented by this CheckMethodAdapter. Must be one of {@link
426 * Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
427 * @param access the method's access flags.
428 * @param name the method's name.
429 * @param descriptor the method's descriptor (see {@link Type}).
430 * @param methodVisitor the method visitor to which this adapter must delegate calls.
431 * @param labelInsnIndices the index of the instruction designated by each visited label so far
432 * (in other methods). This map is updated with the labels from the visited method.
433 */
434 protected CheckMethodAdapter(
435 final int api,
436 final int access,
437 final String name,
438 final String descriptor,
439 final MethodVisitor methodVisitor,
440 final Map<Label, Integer> labelInsnIndices) {
441 this(
442 api,
443 new MethodNode(api, access, name, descriptor, null, null) {
444 @Override
445 public void visitEnd() {
446 Analyzer<BasicValue> analyzer = new Analyzer<BasicValue>(new BasicVerifier());
447 try {
448 analyzer.analyze("dummy", this);
449 } catch (IndexOutOfBoundsException e) {
450 if (maxLocals == 0 && maxStack == 0) {
451 throw new IllegalArgumentException(
452 "Data flow checking option requires valid, non zero maxLocals and maxStack.");
453 }
454 throwError(analyzer, e);
455 } catch (AnalyzerException e) {
456 throwError(analyzer, e);
457 }
458 accept(methodVisitor);
459 }
460
461 private void throwError(final Analyzer<BasicValue> analyzer, final Exception e) {
462 StringWriter stringWriter = new StringWriter();
463 PrintWriter printWriter = new PrintWriter(stringWriter, true);
464 CheckClassAdapter.printAnalyzerResult(this, analyzer, printWriter);
465 printWriter.close();
466 throw new IllegalArgumentException(e.getMessage() + ' ' + stringWriter.toString(), e);
467 }
468 },
469 labelInsnIndices);
470 this.access = access;
471 }
472
473 @Override
474 public void visitParameter(final String name, final int access) {
475 if (name != null) {
476 checkUnqualifiedName(version, name, "name");
477 }
478 CheckClassAdapter.checkAccess(
479 access, Opcodes.ACC_FINAL + Opcodes.ACC_MANDATED + Opcodes.ACC_SYNTHETIC);
480 super.visitParameter(name, access);
481 }
482
483 @Override
484 public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
485 checkVisitEndNotCalled();
486 checkDescriptor(descriptor, false);
487 return new CheckAnnotationAdapter(super.visitAnnotation(descriptor, visible));
488 }
489
490 @Override
491 public AnnotationVisitor visitTypeAnnotation(
492 final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
493 checkVisitEndNotCalled();
494 int sort = new TypeReference(typeRef).getSort();
495 if (sort != TypeReference.METHOD_TYPE_PARAMETER
496 && sort != TypeReference.METHOD_TYPE_PARAMETER_BOUND
497 && sort != TypeReference.METHOD_RETURN
498 && sort != TypeReference.METHOD_RECEIVER
499 && sort != TypeReference.METHOD_FORMAL_PARAMETER
500 && sort != TypeReference.THROWS) {
501 throw new IllegalArgumentException(INVALID_TYPE_REFERENCE + Integer.toHexString(sort));
502 }
503 CheckClassAdapter.checkTypeRef(typeRef);
504 CheckMethodAdapter.checkDescriptor(descriptor, false);
505 return new CheckAnnotationAdapter(
506 super.visitTypeAnnotation(typeRef, typePath, descriptor, visible));
507 }
508
509 @Override
510 public AnnotationVisitor visitAnnotationDefault() {
511 checkVisitEndNotCalled();
512 return new CheckAnnotationAdapter(super.visitAnnotationDefault(), false);
513 }
514
515 @Override
516 public void visitAnnotableParameterCount(final int parameterCount, final boolean visible) {
517 checkVisitEndNotCalled();
518 if (visible) {
519 visibleAnnotableParameterCount = parameterCount;
520 } else {
521 invisibleAnnotableParameterCount = parameterCount;
522 }
523 super.visitAnnotableParameterCount(parameterCount, visible);
524 }
525
526 @Override
527 public AnnotationVisitor visitParameterAnnotation(
528 final int parameter, final String descriptor, final boolean visible) {
529 checkVisitEndNotCalled();
530 if ((visible
531 && visibleAnnotableParameterCount > 0
532 && parameter >= visibleAnnotableParameterCount)
533 || (!visible
534 && invisibleAnnotableParameterCount > 0
535 && parameter >= invisibleAnnotableParameterCount)) {
536 throw new IllegalArgumentException("Invalid parameter index");
537 }
538 checkDescriptor(descriptor, false);
539 return new CheckAnnotationAdapter(
540 super.visitParameterAnnotation(parameter, descriptor, visible));
541 }
542
543 @Override
544 public void visitAttribute(final Attribute attribute) {
545 checkVisitEndNotCalled();
546 if (attribute == null) {
547 throw new IllegalArgumentException("Invalid attribute (must not be null)");
548 }
549 super.visitAttribute(attribute);
550 }
551
552 @Override
553 public void visitCode() {
554 if ((access & Opcodes.ACC_ABSTRACT) != 0) {
555 throw new UnsupportedOperationException("Abstract methods cannot have code");
556 }
557 visitCodeCalled = true;
558 super.visitCode();
559 }
560
561 @Override
562 public void visitFrame(
563 final int type,
564 final int nLocal,
565 final Object[] local,
566 final int nStack,
567 final Object[] stack) {
568 if (insnCount == lastFrameInsnIndex) {
569 throw new IllegalStateException("At most one frame can be visited at a given code location.");
570 }
571 lastFrameInsnIndex = insnCount;
572 int mLocal;
573 int mStack;
574 switch (type) {
575 case Opcodes.F_NEW:
576 case Opcodes.F_FULL:
577 mLocal = Integer.MAX_VALUE;
578 mStack = Integer.MAX_VALUE;
579 break;
580
581 case Opcodes.F_SAME:
582 mLocal = 0;
583 mStack = 0;
584 break;
585
586 case Opcodes.F_SAME1:
587 mLocal = 0;
588 mStack = 1;
589 break;
590
591 case Opcodes.F_APPEND:
592 case Opcodes.F_CHOP:
593 mLocal = 3;
594 mStack = 0;
595 break;
596
597 default:
598 throw new IllegalArgumentException("Invalid frame type " + type);
599 }
600
601 if (nLocal > mLocal) {
602 throw new IllegalArgumentException("Invalid nLocal=" + nLocal + " for frame type " + type);
603 }
604 if (nStack > mStack) {
605 throw new IllegalArgumentException("Invalid nStack=" + nStack + " for frame type " + type);
606 }
607
608 if (type != Opcodes.F_CHOP) {
609 if (nLocal > 0 && (local == null || local.length < nLocal)) {
610 throw new IllegalArgumentException("Array local[] is shorter than nLocal");
611 }
612 for (int i = 0; i < nLocal; ++i) {
613 checkFrameValue(local[i]);
614 }
615 }
616 if (nStack > 0 && (stack == null || stack.length < nStack)) {
617 throw new IllegalArgumentException("Array stack[] is shorter than nStack");
618 }
619 for (int i = 0; i < nStack; ++i) {
620 checkFrameValue(stack[i]);
621 }
622 if (type == Opcodes.F_NEW) {
623 ++numExpandedFrames;
624 } else {
625 ++numCompressedFrames;
626 }
627 if (numExpandedFrames > 0 && numCompressedFrames > 0) {
628 throw new IllegalArgumentException("Expanded and compressed frames must not be mixed.");
629 }
630 super.visitFrame(type, nLocal, local, nStack, stack);
631 }
632
633 @Override
634 public void visitInsn(final int opcode) {
635 checkVisitCodeCalled();
636 checkVisitMaxsNotCalled();
637 checkOpcodeMethod(opcode, Method.VISIT_INSN);
638 super.visitInsn(opcode);
639 ++insnCount;
640 }
641
642 @Override
643 public void visitIntInsn(final int opcode, final int operand) {
644 checkVisitCodeCalled();
645 checkVisitMaxsNotCalled();
646 checkOpcodeMethod(opcode, Method.VISIT_INT_INSN);
647 switch (opcode) {
648 case Opcodes.BIPUSH:
649 checkSignedByte(operand, "Invalid operand");
650 break;
651 case Opcodes.SIPUSH:
652 checkSignedShort(operand, "Invalid operand");
653 break;
654 case Opcodes.NEWARRAY:
655 if (operand < Opcodes.T_BOOLEAN || operand > Opcodes.T_LONG) {
656 throw new IllegalArgumentException(
657 "Invalid operand (must be an array type code T_...): " + operand);
154658 }
155 }
156
157 // code to generate the above string
158 // public static void main (String[] args) {
159 // int[] TYPE = new int[] {
160 // 0, //NOP
161 // 0, //ACONST_NULL
162 // 0, //ICONST_M1
163 // 0, //ICONST_0
164 // 0, //ICONST_1
165 // 0, //ICONST_2
166 // 0, //ICONST_3
167 // 0, //ICONST_4
168 // 0, //ICONST_5
169 // 0, //LCONST_0
170 // 0, //LCONST_1
171 // 0, //FCONST_0
172 // 0, //FCONST_1
173 // 0, //FCONST_2
174 // 0, //DCONST_0
175 // 0, //DCONST_1
176 // 1, //BIPUSH
177 // 1, //SIPUSH
178 // 7, //LDC
179 // -1, //LDC_W
180 // -1, //LDC2_W
181 // 2, //ILOAD
182 // 2, //LLOAD
183 // 2, //FLOAD
184 // 2, //DLOAD
185 // 2, //ALOAD
186 // -1, //ILOAD_0
187 // -1, //ILOAD_1
188 // -1, //ILOAD_2
189 // -1, //ILOAD_3
190 // -1, //LLOAD_0
191 // -1, //LLOAD_1
192 // -1, //LLOAD_2
193 // -1, //LLOAD_3
194 // -1, //FLOAD_0
195 // -1, //FLOAD_1
196 // -1, //FLOAD_2
197 // -1, //FLOAD_3
198 // -1, //DLOAD_0
199 // -1, //DLOAD_1
200 // -1, //DLOAD_2
201 // -1, //DLOAD_3
202 // -1, //ALOAD_0
203 // -1, //ALOAD_1
204 // -1, //ALOAD_2
205 // -1, //ALOAD_3
206 // 0, //IALOAD
207 // 0, //LALOAD
208 // 0, //FALOAD
209 // 0, //DALOAD
210 // 0, //AALOAD
211 // 0, //BALOAD
212 // 0, //CALOAD
213 // 0, //SALOAD
214 // 2, //ISTORE
215 // 2, //LSTORE
216 // 2, //FSTORE
217 // 2, //DSTORE
218 // 2, //ASTORE
219 // -1, //ISTORE_0
220 // -1, //ISTORE_1
221 // -1, //ISTORE_2
222 // -1, //ISTORE_3
223 // -1, //LSTORE_0
224 // -1, //LSTORE_1
225 // -1, //LSTORE_2
226 // -1, //LSTORE_3
227 // -1, //FSTORE_0
228 // -1, //FSTORE_1
229 // -1, //FSTORE_2
230 // -1, //FSTORE_3
231 // -1, //DSTORE_0
232 // -1, //DSTORE_1
233 // -1, //DSTORE_2
234 // -1, //DSTORE_3
235 // -1, //ASTORE_0
236 // -1, //ASTORE_1
237 // -1, //ASTORE_2
238 // -1, //ASTORE_3
239 // 0, //IASTORE
240 // 0, //LASTORE
241 // 0, //FASTORE
242 // 0, //DASTORE
243 // 0, //AASTORE
244 // 0, //BASTORE
245 // 0, //CASTORE
246 // 0, //SASTORE
247 // 0, //POP
248 // 0, //POP2
249 // 0, //DUP
250 // 0, //DUP_X1
251 // 0, //DUP_X2
252 // 0, //DUP2
253 // 0, //DUP2_X1
254 // 0, //DUP2_X2
255 // 0, //SWAP
256 // 0, //IADD
257 // 0, //LADD
258 // 0, //FADD
259 // 0, //DADD
260 // 0, //ISUB
261 // 0, //LSUB
262 // 0, //FSUB
263 // 0, //DSUB
264 // 0, //IMUL
265 // 0, //LMUL
266 // 0, //FMUL
267 // 0, //DMUL
268 // 0, //IDIV
269 // 0, //LDIV
270 // 0, //FDIV
271 // 0, //DDIV
272 // 0, //IREM
273 // 0, //LREM
274 // 0, //FREM
275 // 0, //DREM
276 // 0, //INEG
277 // 0, //LNEG
278 // 0, //FNEG
279 // 0, //DNEG
280 // 0, //ISHL
281 // 0, //LSHL
282 // 0, //ISHR
283 // 0, //LSHR
284 // 0, //IUSHR
285 // 0, //LUSHR
286 // 0, //IAND
287 // 0, //LAND
288 // 0, //IOR
289 // 0, //LOR
290 // 0, //IXOR
291 // 0, //LXOR
292 // 8, //IINC
293 // 0, //I2L
294 // 0, //I2F
295 // 0, //I2D
296 // 0, //L2I
297 // 0, //L2F
298 // 0, //L2D
299 // 0, //F2I
300 // 0, //F2L
301 // 0, //F2D
302 // 0, //D2I
303 // 0, //D2L
304 // 0, //D2F
305 // 0, //I2B
306 // 0, //I2C
307 // 0, //I2S
308 // 0, //LCMP
309 // 0, //FCMPL
310 // 0, //FCMPG
311 // 0, //DCMPL
312 // 0, //DCMPG
313 // 6, //IFEQ
314 // 6, //IFNE
315 // 6, //IFLT
316 // 6, //IFGE
317 // 6, //IFGT
318 // 6, //IFLE
319 // 6, //IF_ICMPEQ
320 // 6, //IF_ICMPNE
321 // 6, //IF_ICMPLT
322 // 6, //IF_ICMPGE
323 // 6, //IF_ICMPGT
324 // 6, //IF_ICMPLE
325 // 6, //IF_ACMPEQ
326 // 6, //IF_ACMPNE
327 // 6, //GOTO
328 // 6, //JSR
329 // 2, //RET
330 // 9, //TABLESWITCH
331 // 10, //LOOKUPSWITCH
332 // 0, //IRETURN
333 // 0, //LRETURN
334 // 0, //FRETURN
335 // 0, //DRETURN
336 // 0, //ARETURN
337 // 0, //RETURN
338 // 4, //GETSTATIC
339 // 4, //PUTSTATIC
340 // 4, //GETFIELD
341 // 4, //PUTFIELD
342 // 5, //INVOKEVIRTUAL
343 // 5, //INVOKESPECIAL
344 // 5, //INVOKESTATIC
345 // 5, //INVOKEINTERFACE
346 // -1, //INVOKEDYNAMIC
347 // 3, //NEW
348 // 1, //NEWARRAY
349 // 3, //ANEWARRAY
350 // 0, //ARRAYLENGTH
351 // 0, //ATHROW
352 // 3, //CHECKCAST
353 // 3, //INSTANCEOF
354 // 0, //MONITORENTER
355 // 0, //MONITOREXIT
356 // -1, //WIDE
357 // 11, //MULTIANEWARRAY
358 // 6, //IFNULL
359 // 6, //IFNONNULL
360 // -1, //GOTO_W
361 // -1 //JSR_W
362 // };
363 // for (int i = 0; i < TYPE.length; ++i) {
364 // System.out.print((char)(TYPE[i] + 1 + 'A'));
365 // }
366 // System.out.println();
367 // }
368
369 /**
370 * Constructs a new {@link CheckMethodAdapter} object. This method adapter
371 * will not perform any data flow check (see
372 * {@link #CheckMethodAdapter(int,String,String,MethodVisitor,Map)}).
373 * <i>Subclasses must not use this constructor</i>. Instead, they must use
374 * the {@link #CheckMethodAdapter(int, MethodVisitor, Map)} version.
375 *
376 * @param mv
377 * the method visitor to which this adapter must delegate calls.
378 */
379 public CheckMethodAdapter(final MethodVisitor mv) {
380 this(mv, new HashMap<Label, Integer>());
381 }
382
383 /**
384 * Constructs a new {@link CheckMethodAdapter} object. This method adapter
385 * will not perform any data flow check (see
386 * {@link #CheckMethodAdapter(int,String,String,MethodVisitor,Map)}).
387 * <i>Subclasses must not use this constructor</i>. Instead, they must use
388 * the {@link #CheckMethodAdapter(int, MethodVisitor, Map)} version.
389 *
390 * @param mv
391 * the method visitor to which this adapter must delegate calls.
392 * @param labels
393 * a map of already visited labels (in other methods).
394 * @throws IllegalStateException
395 * If a subclass calls this constructor.
396 */
397 public CheckMethodAdapter(final MethodVisitor mv,
398 final Map<Label, Integer> labels) {
399 this(Opcodes.ASM6, mv, labels);
400 if (getClass() != CheckMethodAdapter.class) {
401 throw new IllegalStateException();
659 break;
660 default:
661 throw new AssertionError();
662 }
663 super.visitIntInsn(opcode, operand);
664 ++insnCount;
665 }
666
667 @Override
668 public void visitVarInsn(final int opcode, final int var) {
669 checkVisitCodeCalled();
670 checkVisitMaxsNotCalled();
671 checkOpcodeMethod(opcode, Method.VISIT_VAR_INSN);
672 checkUnsignedShort(var, INVALID_LOCAL_VARIABLE_INDEX);
673 super.visitVarInsn(opcode, var);
674 ++insnCount;
675 }
676
677 @Override
678 public void visitTypeInsn(final int opcode, final String type) {
679 checkVisitCodeCalled();
680 checkVisitMaxsNotCalled();
681 checkOpcodeMethod(opcode, Method.VISIT_TYPE_INSN);
682 checkInternalName(type, "type");
683 if (opcode == Opcodes.NEW && type.charAt(0) == '[') {
684 throw new IllegalArgumentException("NEW cannot be used to create arrays: " + type);
685 }
686 super.visitTypeInsn(opcode, type);
687 ++insnCount;
688 }
689
690 @Override
691 public void visitFieldInsn(
692 final int opcode, final String owner, final String name, final String descriptor) {
693 checkVisitCodeCalled();
694 checkVisitMaxsNotCalled();
695 checkOpcodeMethod(opcode, Method.VISIT_FIELD_INSN);
696 checkInternalName(owner, "owner");
697 checkUnqualifiedName(version, name, "name");
698 checkDescriptor(descriptor, false);
699 super.visitFieldInsn(opcode, owner, name, descriptor);
700 ++insnCount;
701 }
702
703 /** @deprecated */
704 @Deprecated
705 @Override
706 public void visitMethodInsn(
707 final int opcode, final String owner, final String name, final String descriptor) {
708 if (api >= Opcodes.ASM5) {
709 super.visitMethodInsn(opcode, owner, name, descriptor);
710 return;
711 }
712 doVisitMethodInsn(opcode, owner, name, descriptor, opcode == Opcodes.INVOKEINTERFACE);
713 }
714
715 @Override
716 public void visitMethodInsn(
717 final int opcode,
718 final String owner,
719 final String name,
720 final String descriptor,
721 final boolean isInterface) {
722 if (api < Opcodes.ASM5) {
723 super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
724 return;
725 }
726 doVisitMethodInsn(opcode, owner, name, descriptor, isInterface);
727 }
728
729 private void doVisitMethodInsn(
730 final int opcode,
731 final String owner,
732 final String name,
733 final String descriptor,
734 final boolean isInterface) {
735 checkVisitCodeCalled();
736 checkVisitMaxsNotCalled();
737 checkOpcodeMethod(opcode, Method.VISIT_METHOD_INSN);
738 if (opcode != Opcodes.INVOKESPECIAL || !"<init>".equals(name)) {
739 checkMethodIdentifier(version, name, "name");
740 }
741 checkInternalName(owner, "owner");
742 checkMethodDescriptor(descriptor);
743 if (opcode == Opcodes.INVOKEVIRTUAL && isInterface) {
744 throw new IllegalArgumentException("INVOKEVIRTUAL can't be used with interfaces");
745 }
746 if (opcode == Opcodes.INVOKEINTERFACE && !isInterface) {
747 throw new IllegalArgumentException("INVOKEINTERFACE can't be used with classes");
748 }
749 if (opcode == Opcodes.INVOKESPECIAL && isInterface && (version & 0xFFFF) < Opcodes.V1_8) {
750 throw new IllegalArgumentException(
751 "INVOKESPECIAL can't be used with interfaces prior to Java 8");
752 }
753
754 // Calling super.visitMethodInsn requires to call the correct version depending on this.api
755 // (otherwise infinite loops can occur). To simplify and to make it easier to automatically
756 // remove the backward compatibility code, we inline the code of the overridden method here.
757 if (mv != null) {
758 mv.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
759 }
760 ++insnCount;
761 }
762
763 @Override
764 public void visitInvokeDynamicInsn(
765 final String name,
766 final String descriptor,
767 final Handle bootstrapMethodHandle,
768 final Object... bootstrapMethodArguments) {
769 checkVisitCodeCalled();
770 checkVisitMaxsNotCalled();
771 checkMethodIdentifier(version, name, "name");
772 checkMethodDescriptor(descriptor);
773 if (bootstrapMethodHandle.getTag() != Opcodes.H_INVOKESTATIC
774 && bootstrapMethodHandle.getTag() != Opcodes.H_NEWINVOKESPECIAL) {
775 throw new IllegalArgumentException("invalid handle tag " + bootstrapMethodHandle.getTag());
776 }
777 for (int i = 0; i < bootstrapMethodArguments.length; i++) {
778 checkLdcConstant(bootstrapMethodArguments[i]);
779 }
780 super.visitInvokeDynamicInsn(name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments);
781 ++insnCount;
782 }
783
784 @Override
785 public void visitJumpInsn(final int opcode, final Label label) {
786 checkVisitCodeCalled();
787 checkVisitMaxsNotCalled();
788 checkOpcodeMethod(opcode, Method.VISIT_JUMP_INSN);
789 checkLabel(label, false, "label");
790 super.visitJumpInsn(opcode, label);
791 referencedLabels.add(label);
792 ++insnCount;
793 }
794
795 @Override
796 public void visitLabel(final Label label) {
797 checkVisitCodeCalled();
798 checkVisitMaxsNotCalled();
799 checkLabel(label, false, "label");
800 if (labelInsnIndices.get(label) != null) {
801 throw new IllegalArgumentException("Already visited label");
802 }
803 labelInsnIndices.put(label, insnCount);
804 super.visitLabel(label);
805 }
806
807 @Override
808 public void visitLdcInsn(final Object value) {
809 checkVisitCodeCalled();
810 checkVisitMaxsNotCalled();
811 checkLdcConstant(value);
812 super.visitLdcInsn(value);
813 ++insnCount;
814 }
815
816 @Override
817 public void visitIincInsn(final int var, final int increment) {
818 checkVisitCodeCalled();
819 checkVisitMaxsNotCalled();
820 checkUnsignedShort(var, INVALID_LOCAL_VARIABLE_INDEX);
821 checkSignedShort(increment, "Invalid increment");
822 super.visitIincInsn(var, increment);
823 ++insnCount;
824 }
825
826 @Override
827 public void visitTableSwitchInsn(
828 final int min, final int max, final Label dflt, final Label... labels) {
829 checkVisitCodeCalled();
830 checkVisitMaxsNotCalled();
831 if (max < min) {
832 throw new IllegalArgumentException(
833 "Max = " + max + " must be greater than or equal to min = " + min);
834 }
835 checkLabel(dflt, false, "default label");
836 if (labels == null || labels.length != max - min + 1) {
837 throw new IllegalArgumentException("There must be max - min + 1 labels");
838 }
839 for (int i = 0; i < labels.length; ++i) {
840 checkLabel(labels[i], false, "label at index " + i);
841 }
842 super.visitTableSwitchInsn(min, max, dflt, labels);
843 for (int i = 0; i < labels.length; ++i) {
844 referencedLabels.add(labels[i]);
845 }
846 ++insnCount;
847 }
848
849 @Override
850 public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) {
851 checkVisitMaxsNotCalled();
852 checkVisitCodeCalled();
853 checkLabel(dflt, false, "default label");
854 if (keys == null || labels == null || keys.length != labels.length) {
855 throw new IllegalArgumentException("There must be the same number of keys and labels");
856 }
857 for (int i = 0; i < labels.length; ++i) {
858 checkLabel(labels[i], false, "label at index " + i);
859 }
860 super.visitLookupSwitchInsn(dflt, keys, labels);
861 referencedLabels.add(dflt);
862 for (int i = 0; i < labels.length; ++i) {
863 referencedLabels.add(labels[i]);
864 }
865 ++insnCount;
866 }
867
868 @Override
869 public void visitMultiANewArrayInsn(final String descriptor, final int numDimensions) {
870 checkVisitCodeCalled();
871 checkVisitMaxsNotCalled();
872 checkDescriptor(descriptor, false);
873 if (descriptor.charAt(0) != '[') {
874 throw new IllegalArgumentException(
875 "Invalid descriptor (must be an array type descriptor): " + descriptor);
876 }
877 if (numDimensions < 1) {
878 throw new IllegalArgumentException(
879 "Invalid dimensions (must be greater than 0): " + numDimensions);
880 }
881 if (numDimensions > descriptor.lastIndexOf('[') + 1) {
882 throw new IllegalArgumentException(
883 "Invalid dimensions (must not be greater than numDimensions(descriptor)): "
884 + numDimensions);
885 }
886 super.visitMultiANewArrayInsn(descriptor, numDimensions);
887 ++insnCount;
888 }
889
890 @Override
891 public AnnotationVisitor visitInsnAnnotation(
892 final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
893 checkVisitCodeCalled();
894 checkVisitMaxsNotCalled();
895 int sort = new TypeReference(typeRef).getSort();
896 if (sort != TypeReference.INSTANCEOF
897 && sort != TypeReference.NEW
898 && sort != TypeReference.CONSTRUCTOR_REFERENCE
899 && sort != TypeReference.METHOD_REFERENCE
900 && sort != TypeReference.CAST
901 && sort != TypeReference.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
902 && sort != TypeReference.METHOD_INVOCATION_TYPE_ARGUMENT
903 && sort != TypeReference.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
904 && sort != TypeReference.METHOD_REFERENCE_TYPE_ARGUMENT) {
905 throw new IllegalArgumentException(INVALID_TYPE_REFERENCE + Integer.toHexString(sort));
906 }
907 CheckClassAdapter.checkTypeRef(typeRef);
908 CheckMethodAdapter.checkDescriptor(descriptor, false);
909 return new CheckAnnotationAdapter(
910 super.visitInsnAnnotation(typeRef, typePath, descriptor, visible));
911 }
912
913 @Override
914 public void visitTryCatchBlock(
915 final Label start, final Label end, final Label handler, final String type) {
916 checkVisitCodeCalled();
917 checkVisitMaxsNotCalled();
918 checkLabel(start, false, START_LABEL);
919 checkLabel(end, false, END_LABEL);
920 checkLabel(handler, false, "handler label");
921 if (labelInsnIndices.get(start) != null
922 || labelInsnIndices.get(end) != null
923 || labelInsnIndices.get(handler) != null) {
924 throw new IllegalStateException("Try catch blocks must be visited before their labels");
925 }
926 if (type != null) {
927 checkInternalName(type, "type");
928 }
929 super.visitTryCatchBlock(start, end, handler, type);
930 handlers.add(start);
931 handlers.add(end);
932 }
933
934 @Override
935 public AnnotationVisitor visitTryCatchAnnotation(
936 final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
937 checkVisitCodeCalled();
938 checkVisitMaxsNotCalled();
939 int sort = new TypeReference(typeRef).getSort();
940 if (sort != TypeReference.EXCEPTION_PARAMETER) {
941 throw new IllegalArgumentException(INVALID_TYPE_REFERENCE + Integer.toHexString(sort));
942 }
943 CheckClassAdapter.checkTypeRef(typeRef);
944 CheckMethodAdapter.checkDescriptor(descriptor, false);
945 return new CheckAnnotationAdapter(
946 super.visitTryCatchAnnotation(typeRef, typePath, descriptor, visible));
947 }
948
949 @Override
950 public void visitLocalVariable(
951 final String name,
952 final String descriptor,
953 final String signature,
954 final Label start,
955 final Label end,
956 final int index) {
957 checkVisitCodeCalled();
958 checkVisitMaxsNotCalled();
959 checkUnqualifiedName(version, name, "name");
960 checkDescriptor(descriptor, false);
961 checkLabel(start, true, START_LABEL);
962 checkLabel(end, true, END_LABEL);
963 checkUnsignedShort(index, INVALID_LOCAL_VARIABLE_INDEX);
964 int startInsnIndex = labelInsnIndices.get(start).intValue();
965 int endInsnIndex = labelInsnIndices.get(end).intValue();
966 if (endInsnIndex < startInsnIndex) {
967 throw new IllegalArgumentException(
968 "Invalid start and end labels (end must be greater than start)");
969 }
970 super.visitLocalVariable(name, descriptor, signature, start, end, index);
971 }
972
973 @Override
974 public AnnotationVisitor visitLocalVariableAnnotation(
975 final int typeRef,
976 final TypePath typePath,
977 final Label[] start,
978 final Label[] end,
979 final int[] index,
980 final String descriptor,
981 final boolean visible) {
982 checkVisitCodeCalled();
983 checkVisitMaxsNotCalled();
984 int sort = new TypeReference(typeRef).getSort();
985 if (sort != TypeReference.LOCAL_VARIABLE && sort != TypeReference.RESOURCE_VARIABLE) {
986 throw new IllegalArgumentException(INVALID_TYPE_REFERENCE + Integer.toHexString(sort));
987 }
988 CheckClassAdapter.checkTypeRef(typeRef);
989 checkDescriptor(descriptor, false);
990 if (start == null
991 || end == null
992 || index == null
993 || end.length != start.length
994 || index.length != start.length) {
995 throw new IllegalArgumentException(
996 "Invalid start, end and index arrays (must be non null and of identical length");
997 }
998 for (int i = 0; i < start.length; ++i) {
999 checkLabel(start[i], true, START_LABEL);
1000 checkLabel(end[i], true, END_LABEL);
1001 checkUnsignedShort(index[i], INVALID_LOCAL_VARIABLE_INDEX);
1002 int startInsnIndex = labelInsnIndices.get(start[i]).intValue();
1003 int endInsnIndex = labelInsnIndices.get(end[i]).intValue();
1004 if (endInsnIndex < startInsnIndex) {
1005 throw new IllegalArgumentException(
1006 "Invalid start and end labels (end must be greater than start)");
1007 }
1008 }
1009 return super.visitLocalVariableAnnotation(
1010 typeRef, typePath, start, end, index, descriptor, visible);
1011 }
1012
1013 @Override
1014 public void visitLineNumber(final int line, final Label start) {
1015 checkVisitCodeCalled();
1016 checkVisitMaxsNotCalled();
1017 checkUnsignedShort(line, "Invalid line number");
1018 checkLabel(start, true, START_LABEL);
1019 super.visitLineNumber(line, start);
1020 }
1021
1022 @Override
1023 public void visitMaxs(final int maxStack, final int maxLocals) {
1024 checkVisitCodeCalled();
1025 checkVisitMaxsNotCalled();
1026 visitMaxCalled = true;
1027 for (Label l : referencedLabels) {
1028 if (labelInsnIndices.get(l) == null) {
1029 throw new IllegalStateException("Undefined label used");
1030 }
1031 }
1032 for (int i = 0; i < handlers.size(); i += 2) {
1033 Integer startInsnIndex = labelInsnIndices.get(handlers.get(i));
1034 Integer endInsnIndex = labelInsnIndices.get(handlers.get(i + 1));
1035 if (startInsnIndex == null || endInsnIndex == null) {
1036 throw new IllegalStateException("Undefined try catch block labels");
1037 }
1038 if (endInsnIndex.intValue() <= startInsnIndex.intValue()) {
1039 throw new IllegalStateException("Emty try catch block handler range");
1040 }
1041 }
1042 checkUnsignedShort(maxStack, "Invalid max stack");
1043 checkUnsignedShort(maxLocals, "Invalid max locals");
1044 super.visitMaxs(maxStack, maxLocals);
1045 }
1046
1047 @Override
1048 public void visitEnd() {
1049 checkVisitEndNotCalled();
1050 visitEndCalled = true;
1051 super.visitEnd();
1052 }
1053
1054 // -----------------------------------------------------------------------------------------------
1055 // Utility methods
1056 // -----------------------------------------------------------------------------------------------
1057
1058 /** Checks that the {@link #visitCode} method has been called. */
1059 private void checkVisitCodeCalled() {
1060 if (!visitCodeCalled) {
1061 throw new IllegalStateException(
1062 "Cannot visit instructions before visitCode has been called.");
1063 }
1064 }
1065
1066 /** Checks that the {@link #visitMaxs} method has not been called. */
1067 private void checkVisitMaxsNotCalled() {
1068 if (visitMaxCalled) {
1069 throw new IllegalStateException("Cannot visit instructions after visitMaxs has been called.");
1070 }
1071 }
1072
1073 /** Checks that the {@link #visitEnd} method has not been called. */
1074 private void checkVisitEndNotCalled() {
1075 if (visitEndCalled) {
1076 throw new IllegalStateException("Cannot visit elements after visitEnd has been called.");
1077 }
1078 }
1079
1080 /**
1081 * Checks a stack frame value.
1082 *
1083 * @param value the value to be checked.
1084 */
1085 private void checkFrameValue(final Object value) {
1086 if (value == Opcodes.TOP
1087 || value == Opcodes.INTEGER
1088 || value == Opcodes.FLOAT
1089 || value == Opcodes.LONG
1090 || value == Opcodes.DOUBLE
1091 || value == Opcodes.NULL
1092 || value == Opcodes.UNINITIALIZED_THIS) {
1093 return;
1094 } else if (value instanceof String) {
1095 checkInternalName((String) value, "Invalid stack frame value");
1096 } else if (value instanceof Label) {
1097 referencedLabels.add((Label) value);
1098 } else {
1099 throw new IllegalArgumentException("Invalid stack frame value: " + value);
1100 }
1101 }
1102
1103 /**
1104 * Checks that the method to visit the given opcode is equal to the given method.
1105 *
1106 * @param opcode the opcode to be checked.
1107 * @param method the expected visit method.
1108 */
1109 private static void checkOpcodeMethod(final int opcode, final Method method) {
1110 if (opcode < Opcodes.NOP || opcode > Opcodes.IFNONNULL || OPCODE_METHODS[opcode] != method) {
1111 throw new IllegalArgumentException("Invalid opcode: " + opcode);
1112 }
1113 }
1114
1115 /**
1116 * Checks that the given value is a signed byte.
1117 *
1118 * @param value the value to be checked.
1119 * @param message the message to use in case of error.
1120 */
1121 private static void checkSignedByte(final int value, final String message) {
1122 if (value < Byte.MIN_VALUE || value > Byte.MAX_VALUE) {
1123 throw new IllegalArgumentException(message + " (must be a signed byte): " + value);
1124 }
1125 }
1126
1127 /**
1128 * Checks that the given value is a signed short.
1129 *
1130 * @param value the value to be checked.
1131 * @param message the message to use in case of error.
1132 */
1133 private static void checkSignedShort(final int value, final String message) {
1134 if (value < Short.MIN_VALUE || value > Short.MAX_VALUE) {
1135 throw new IllegalArgumentException(message + " (must be a signed short): " + value);
1136 }
1137 }
1138
1139 /**
1140 * Checks that the given value is an unsigned short.
1141 *
1142 * @param value the value to be checked.
1143 * @param message the message to use in case of error.
1144 */
1145 private static void checkUnsignedShort(final int value, final String message) {
1146 if (value < 0 || value > 65535) {
1147 throw new IllegalArgumentException(message + " (must be an unsigned short): " + value);
1148 }
1149 }
1150
1151 /**
1152 * Checks that the given value is an {@link Integer}, {@link Float}, {@link Long}, {@link Double}
1153 * or {@link String} value.
1154 *
1155 * @param value the value to be checked.
1156 */
1157 static void checkConstant(final Object value) {
1158 if (!(value instanceof Integer)
1159 && !(value instanceof Float)
1160 && !(value instanceof Long)
1161 && !(value instanceof Double)
1162 && !(value instanceof String)) {
1163 throw new IllegalArgumentException("Invalid constant: " + value);
1164 }
1165 }
1166
1167 /**
1168 * Checks that the given value is a valid operand for the LDC instruction.
1169 *
1170 * @param value the value to be checked.
1171 */
1172 private void checkLdcConstant(final Object value) {
1173 if (value instanceof Type) {
1174 int sort = ((Type) value).getSort();
1175 if (sort != Type.OBJECT && sort != Type.ARRAY && sort != Type.METHOD) {
1176 throw new IllegalArgumentException("Illegal LDC constant value");
1177 }
1178 if (sort != Type.METHOD && (version & 0xFFFF) < Opcodes.V1_5) {
1179 throw new IllegalArgumentException("ldc of a constant class requires at least version 1.5");
1180 }
1181 if (sort == Type.METHOD && (version & 0xFFFF) < Opcodes.V1_7) {
1182 throw new IllegalArgumentException("ldc of a method type requires at least version 1.7");
1183 }
1184 } else if (value instanceof Handle) {
1185 if ((version & 0xFFFF) < Opcodes.V1_7) {
1186 throw new IllegalArgumentException("ldc of a handle requires at least version 1.7");
1187 }
1188 int tag = ((Handle) value).getTag();
1189 if (tag < Opcodes.H_GETFIELD || tag > Opcodes.H_INVOKEINTERFACE) {
1190 throw new IllegalArgumentException("invalid handle tag " + tag);
1191 }
1192 } else {
1193 checkConstant(value);
1194 }
1195 }
1196
1197 /**
1198 * Checks that the given string is a valid unqualified name.
1199 *
1200 * @param version the class version.
1201 * @param name the string to be checked.
1202 * @param message the message to use in case of error.
1203 */
1204 static void checkUnqualifiedName(final int version, final String name, final String message) {
1205 if ((version & 0xFFFF) < Opcodes.V1_5) {
1206 checkIdentifier(name, message);
1207 } else {
1208 for (int i = 0; i < name.length(); ++i) {
1209 if (".;[/".indexOf(name.charAt(i)) != -1) {
1210 throw new IllegalArgumentException(
1211 INVALID + message + " (must be a valid unqualified name): " + name);
4021212 }
403 }
404
405 /**
406 * Constructs a new {@link CheckMethodAdapter} object. This method adapter
407 * will not perform any data flow check (see
408 * {@link #CheckMethodAdapter(int,String,String,MethodVisitor,Map)}).
409 *
410 * @param api
411 * the ASM API version implemented by this CheckMethodAdapter.
412 * Must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5}
413 * or {@link Opcodes#ASM6}.
414 * @param mv
415 * the method visitor to which this adapter must delegate calls.
416 * @param labels
417 * a map of already visited labels (in other methods).
418 */
419 protected CheckMethodAdapter(final int api, final MethodVisitor mv,
420 final Map<Label, Integer> labels) {
421 super(api, mv);
422 this.labels = labels;
423 this.usedLabels = new HashSet<Label>();
424 this.handlers = new ArrayList<Label>();
425 }
426
427 /**
428 * Constructs a new {@link CheckMethodAdapter} object. This method adapter
429 * will perform basic data flow checks. For instance in a method whose
430 * signature is <tt>void m ()</tt>, the invalid instruction IRETURN, or the
431 * invalid sequence IADD L2I will be detected.
432 *
433 * @param access
434 * the method's access flags.
435 * @param name
436 * the method's name.
437 * @param desc
438 * the method's descriptor (see {@link Type Type}).
439 * @param cmv
440 * the method visitor to which this adapter must delegate calls.
441 * @param labels
442 * a map of already visited labels (in other methods).
443 */
444 public CheckMethodAdapter(final int access, final String name,
445 final String desc, final MethodVisitor cmv,
446 final Map<Label, Integer> labels) {
447 this(new MethodNode(Opcodes.ASM5, access, name, desc, null, null) {
448 @Override
449 public void visitEnd() {
450 Analyzer<BasicValue> a = new Analyzer<BasicValue>(
451 new BasicVerifier());
452 try {
453 a.analyze("dummy", this);
454 } catch (Exception e) {
455 if (e instanceof IndexOutOfBoundsException
456 && maxLocals == 0 && maxStack == 0) {
457 throw new RuntimeException(
458 "Data flow checking option requires valid, non zero maxLocals and maxStack values.");
459 }
460 e.printStackTrace();
461 StringWriter sw = new StringWriter();
462 PrintWriter pw = new PrintWriter(sw, true);
463 CheckClassAdapter.printAnalyzerResult(this, a, pw);
464 pw.close();
465 throw new RuntimeException(e.getMessage() + ' '
466 + sw.toString());
467 }
468 accept(cmv);
469 }
470 }, labels);
471 this.access = access;
472 }
473
474 @Override
475 public void visitParameter(String name, int access) {
476 if (name != null) {
477 checkUnqualifiedName(version, name, "name");
1213 }
1214 }
1215 }
1216
1217 /**
1218 * Checks that the given string is a valid Java identifier.
1219 *
1220 * @param name the string to be checked.
1221 * @param message the message to use in case of error.
1222 */
1223 private static void checkIdentifier(final String name, final String message) {
1224 checkIdentifier(name, 0, -1, message);
1225 }
1226
1227 /**
1228 * Checks that the given substring is a valid Java identifier.
1229 *
1230 * @param name the string to be checked.
1231 * @param startPos the index of the first character of the identifier (inclusive).
1232 * @param endPos the index of the last character of the identifier (exclusive). -1 is equivalent
1233 * to <tt>name.length()</tt> if name is not <tt>null</tt>.
1234 * @param message the message to use in case of error.
1235 */
1236 static void checkIdentifier(
1237 final String name, final int startPos, final int endPos, final String message) {
1238 if (name == null || (endPos == -1 ? name.length() <= startPos : endPos <= startPos)) {
1239 throw new IllegalArgumentException(INVALID + message + MUST_NOT_BE_NULL_OR_EMPTY);
1240 }
1241 int max = endPos == -1 ? name.length() : endPos;
1242 for (int i = startPos; i < max; i = name.offsetByCodePoints(i, 1)) {
1243 if (i == startPos
1244 ? !Character.isJavaIdentifierStart(name.codePointAt(i))
1245 : !Character.isJavaIdentifierPart(name.codePointAt(i))) {
1246 throw new IllegalArgumentException(
1247 INVALID + message + " (must be a valid Java identifier): " + name);
1248 }
1249 }
1250 }
1251
1252 /**
1253 * Checks that the given string is a valid Java identifier.
1254 *
1255 * @param version the class version.
1256 * @param name the string to be checked.
1257 * @param message the message to use in case of error.
1258 */
1259 static void checkMethodIdentifier(final int version, final String name, final String message) {
1260 if (name == null || name.length() == 0) {
1261 throw new IllegalArgumentException(INVALID + message + MUST_NOT_BE_NULL_OR_EMPTY);
1262 }
1263 if ((version & 0xFFFF) >= Opcodes.V1_5) {
1264 for (int i = 0; i < name.length(); ++i) {
1265 if (".;[/<>".indexOf(name.charAt(i)) != -1) {
1266 throw new IllegalArgumentException(
1267 INVALID + message + " (must be a valid unqualified name): " + name);
4781268 }
479 CheckClassAdapter.checkAccess(access, Opcodes.ACC_FINAL
480 + Opcodes.ACC_MANDATED + Opcodes.ACC_SYNTHETIC);
481 super.visitParameter(name, access);
482 }
483
484 @Override
485 public AnnotationVisitor visitAnnotation(final String desc,
486 final boolean visible) {
487 checkEndMethod();
488 checkDesc(desc, false);
489 return new CheckAnnotationAdapter(super.visitAnnotation(desc, visible));
490 }
491
492 @Override
493 public AnnotationVisitor visitTypeAnnotation(final int typeRef,
494 final TypePath typePath, final String desc, final boolean visible) {
495 checkEndMethod();
496 int sort = typeRef >>> 24;
497 if (sort != TypeReference.METHOD_TYPE_PARAMETER
498 && sort != TypeReference.METHOD_TYPE_PARAMETER_BOUND
499 && sort != TypeReference.METHOD_RETURN
500 && sort != TypeReference.METHOD_RECEIVER
501 && sort != TypeReference.METHOD_FORMAL_PARAMETER
502 && sort != TypeReference.THROWS) {
503 throw new IllegalArgumentException("Invalid type reference sort 0x"
504 + Integer.toHexString(sort));
1269 }
1270 return;
1271 }
1272 for (int i = 0; i < name.length(); i = name.offsetByCodePoints(i, 1)) {
1273 if (i == 0
1274 ? !Character.isJavaIdentifierStart(name.codePointAt(i))
1275 : !Character.isJavaIdentifierPart(name.codePointAt(i))) {
1276 throw new IllegalArgumentException(
1277 INVALID
1278 + message
1279 + " (must be a '<init>', '<clinit>' or a valid Java identifier): "
1280 + name);
1281 }
1282 }
1283 }
1284
1285 /**
1286 * Checks that the given string is a valid internal class name or array type descriptor.
1287 *
1288 * @param name the string to be checked.
1289 * @param message the message to use in case of error.
1290 */
1291 static void checkInternalName(final String name, final String message) {
1292 if (name == null || name.length() == 0) {
1293 throw new IllegalArgumentException(INVALID + message + MUST_NOT_BE_NULL_OR_EMPTY);
1294 }
1295 if (name.charAt(0) == '[') {
1296 checkDescriptor(name, false);
1297 } else {
1298 checkInternalClassName(name, message);
1299 }
1300 }
1301
1302 /**
1303 * Checks that the given string is a valid internal class name.
1304 *
1305 * @param name the string to be checked.
1306 * @param message the message to use in case of error.
1307 */
1308 private static void checkInternalClassName(final String name, final String message) {
1309 try {
1310 int startIndex = 0;
1311 int slashIndex;
1312 while ((slashIndex = name.indexOf('/', startIndex + 1)) != -1) {
1313 CheckMethodAdapter.checkIdentifier(name, startIndex, slashIndex, null);
1314 startIndex = slashIndex + 1;
1315 }
1316 CheckMethodAdapter.checkIdentifier(name, startIndex, name.length(), null);
1317 } catch (IllegalArgumentException e) {
1318 throw new IllegalArgumentException(
1319 INVALID + message + " (must be an internal class name): " + name);
1320 }
1321 }
1322
1323 /**
1324 * Checks that the given string is a valid type descriptor.
1325 *
1326 * @param descriptor the string to be checked.
1327 * @param canBeVoid <tt>true</tt> if <tt>V</tt> can be considered valid.
1328 */
1329 static void checkDescriptor(final String descriptor, final boolean canBeVoid) {
1330 int endPos = checkDescriptor(descriptor, 0, canBeVoid);
1331 if (endPos != descriptor.length()) {
1332 throw new IllegalArgumentException(INVALID_DESCRIPTOR + descriptor);
1333 }
1334 }
1335
1336 /**
1337 * Checks that a the given substring is a valid type descriptor.
1338 *
1339 * @param descriptor the string to be checked.
1340 * @param startPos the index of the first character of the type descriptor (inclusive).
1341 * @param canBeVoid whether <tt>V</tt> can be considered valid.
1342 * @return the index of the last character of the type descriptor, plus one.
1343 */
1344 private static int checkDescriptor(
1345 final String descriptor, final int startPos, final boolean canBeVoid) {
1346 if (descriptor == null || startPos >= descriptor.length()) {
1347 throw new IllegalArgumentException("Invalid type descriptor (must not be null or empty)");
1348 }
1349 switch (descriptor.charAt(startPos)) {
1350 case 'V':
1351 if (canBeVoid) {
1352 return startPos + 1;
1353 } else {
1354 throw new IllegalArgumentException(INVALID_DESCRIPTOR + descriptor);
5051355 }
506 CheckClassAdapter.checkTypeRefAndPath(typeRef, typePath);
507 CheckMethodAdapter.checkDesc(desc, false);
508 return new CheckAnnotationAdapter(super.visitTypeAnnotation(typeRef,
509 typePath, desc, visible));
510 }
511
512 @Override
513 public AnnotationVisitor visitAnnotationDefault() {
514 checkEndMethod();
515 return new CheckAnnotationAdapter(super.visitAnnotationDefault(), false);
516 }
517
518 @Override
519 public AnnotationVisitor visitParameterAnnotation(final int parameter,
520 final String desc, final boolean visible) {
521 checkEndMethod();
522 checkDesc(desc, false);
523 return new CheckAnnotationAdapter(super.visitParameterAnnotation(
524 parameter, desc, visible));
525 }
526
527 @Override
528 public void visitAttribute(final Attribute attr) {
529 checkEndMethod();
530 if (attr == null) {
531 throw new IllegalArgumentException(
532 "Invalid attribute (must not be null)");
1356 case 'Z':
1357 case 'C':
1358 case 'B':
1359 case 'S':
1360 case 'I':
1361 case 'F':
1362 case 'J':
1363 case 'D':
1364 return startPos + 1;
1365 case '[':
1366 int pos = startPos + 1;
1367 while (pos < descriptor.length() && descriptor.charAt(pos) == '[') {
1368 ++pos;
5331369 }
534 super.visitAttribute(attr);
535 }
536
537 @Override
538 public void visitCode() {
539 if ((access & Opcodes.ACC_ABSTRACT) != 0) {
540 throw new RuntimeException("Abstract methods cannot have code");
1370 if (pos < descriptor.length()) {
1371 return checkDescriptor(descriptor, pos, false);
1372 } else {
1373 throw new IllegalArgumentException(INVALID_DESCRIPTOR + descriptor);
5411374 }
542 startCode = true;
543 super.visitCode();
544 }
545
546 @Override
547 public void visitFrame(final int type, final int nLocal,
548 final Object[] local, final int nStack, final Object[] stack) {
549 if (insnCount == lastFrame) {
550 throw new IllegalStateException(
551 "At most one frame can be visited at a given code location.");
1375 case 'L':
1376 int endPos = descriptor.indexOf(';', startPos);
1377 if (startPos == -1 || endPos - startPos < 2) {
1378 throw new IllegalArgumentException(INVALID_DESCRIPTOR + descriptor);
5521379 }
553 lastFrame = insnCount;
554 int mLocal;
555 int mStack;
556 switch (type) {
557 case Opcodes.F_NEW:
558 case Opcodes.F_FULL:
559 mLocal = Integer.MAX_VALUE;
560 mStack = Integer.MAX_VALUE;
561 break;
562
563 case Opcodes.F_SAME:
564 mLocal = 0;
565 mStack = 0;
566 break;
567
568 case Opcodes.F_SAME1:
569 mLocal = 0;
570 mStack = 1;
571 break;
572
573 case Opcodes.F_APPEND:
574 case Opcodes.F_CHOP:
575 mLocal = 3;
576 mStack = 0;
577 break;
578
579 default:
580 throw new IllegalArgumentException("Invalid frame type " + type);
1380 try {
1381 checkInternalClassName(descriptor.substring(startPos + 1, endPos), null);
1382 } catch (IllegalArgumentException unused) {
1383 throw new IllegalArgumentException(INVALID_DESCRIPTOR + descriptor);
5811384 }
582
583 if (nLocal > mLocal) {
584 throw new IllegalArgumentException("Invalid nLocal=" + nLocal
585 + " for frame type " + type);
1385 return endPos + 1;
1386 default:
1387 throw new IllegalArgumentException(INVALID_DESCRIPTOR + descriptor);
1388 }
1389 }
1390
1391 /**
1392 * Checks that the given string is a valid method descriptor.
1393 *
1394 * @param descriptor the string to be checked.
1395 */
1396 static void checkMethodDescriptor(final String descriptor) {
1397 if (descriptor == null || descriptor.length() == 0) {
1398 throw new IllegalArgumentException("Invalid method descriptor (must not be null or empty)");
1399 }
1400 if (descriptor.charAt(0) != '(' || descriptor.length() < 3) {
1401 throw new IllegalArgumentException(INVALID_DESCRIPTOR + descriptor);
1402 }
1403 int pos = 1;
1404 if (descriptor.charAt(pos) != ')') {
1405 do {
1406 if (descriptor.charAt(pos) == 'V') {
1407 throw new IllegalArgumentException(INVALID_DESCRIPTOR + descriptor);
5861408 }
587 if (nStack > mStack) {
588 throw new IllegalArgumentException("Invalid nStack=" + nStack
589 + " for frame type " + type);
590 }
591
592 if (type != Opcodes.F_CHOP) {
593 if (nLocal > 0 && (local == null || local.length < nLocal)) {
594 throw new IllegalArgumentException(
595 "Array local[] is shorter than nLocal");
596 }
597 for (int i = 0; i < nLocal; ++i) {
598 checkFrameValue(local[i]);
599 }
600 }
601 if (nStack > 0 && (stack == null || stack.length < nStack)) {
602 throw new IllegalArgumentException(
603 "Array stack[] is shorter than nStack");
604 }
605 for (int i = 0; i < nStack; ++i) {
606 checkFrameValue(stack[i]);
607 }
608 if (type == Opcodes.F_NEW) {
609 ++expandedFrames;
610 } else {
611 ++compressedFrames;
612 }
613 if (expandedFrames > 0 && compressedFrames > 0) {
614 throw new RuntimeException(
615 "Expanded and compressed frames must not be mixed.");
616 }
617 super.visitFrame(type, nLocal, local, nStack, stack);
618 }
619
620 @Override
621 public void visitInsn(final int opcode) {
622 checkStartCode();
623 checkEndCode();
624 checkOpcode(opcode, 0);
625 super.visitInsn(opcode);
626 ++insnCount;
627 }
628
629 @Override
630 public void visitIntInsn(final int opcode, final int operand) {
631 checkStartCode();
632 checkEndCode();
633 checkOpcode(opcode, 1);
634 switch (opcode) {
635 case Opcodes.BIPUSH:
636 checkSignedByte(operand, "Invalid operand");
637 break;
638 case Opcodes.SIPUSH:
639 checkSignedShort(operand, "Invalid operand");
640 break;
641 // case Constants.NEWARRAY:
642 default:
643 if (operand < Opcodes.T_BOOLEAN || operand > Opcodes.T_LONG) {
644 throw new IllegalArgumentException(
645 "Invalid operand (must be an array type code T_...): "
646 + operand);
647 }
648 }
649 super.visitIntInsn(opcode, operand);
650 ++insnCount;
651 }
652
653 @Override
654 public void visitVarInsn(final int opcode, final int var) {
655 checkStartCode();
656 checkEndCode();
657 checkOpcode(opcode, 2);
658 checkUnsignedShort(var, "Invalid variable index");
659 super.visitVarInsn(opcode, var);
660 ++insnCount;
661 }
662
663 @Override
664 public void visitTypeInsn(final int opcode, final String type) {
665 checkStartCode();
666 checkEndCode();
667 checkOpcode(opcode, 3);
668 checkInternalName(type, "type");
669 if (opcode == Opcodes.NEW && type.charAt(0) == '[') {
670 throw new IllegalArgumentException(
671 "NEW cannot be used to create arrays: " + type);
672 }
673 super.visitTypeInsn(opcode, type);
674 ++insnCount;
675 }
676
677 @Override
678 public void visitFieldInsn(final int opcode, final String owner,
679 final String name, final String desc) {
680 checkStartCode();
681 checkEndCode();
682 checkOpcode(opcode, 4);
683 checkInternalName(owner, "owner");
684 checkUnqualifiedName(version, name, "name");
685 checkDesc(desc, false);
686 super.visitFieldInsn(opcode, owner, name, desc);
687 ++insnCount;
688 }
689
690 @Deprecated
691 @Override
692 public void visitMethodInsn(int opcode, String owner, String name,
693 String desc) {
694 if (api >= Opcodes.ASM5) {
695 super.visitMethodInsn(opcode, owner, name, desc);
696 return;
697 }
698 doVisitMethodInsn(opcode, owner, name, desc,
699 opcode == Opcodes.INVOKEINTERFACE);
700 }
701
702 @Override
703 public void visitMethodInsn(int opcode, String owner, String name,
704 String desc, boolean itf) {
705 if (api < Opcodes.ASM5) {
706 super.visitMethodInsn(opcode, owner, name, desc, itf);
707 return;
708 }
709 doVisitMethodInsn(opcode, owner, name, desc, itf);
710 }
711
712 private void doVisitMethodInsn(int opcode, final String owner,
713 final String name, final String desc, final boolean itf) {
714 checkStartCode();
715 checkEndCode();
716 checkOpcode(opcode, 5);
717 if (opcode != Opcodes.INVOKESPECIAL || !"<init>".equals(name)) {
718 checkMethodIdentifier(version, name, "name");
719 }
720 checkInternalName(owner, "owner");
721 checkMethodDesc(desc);
722 if (opcode == Opcodes.INVOKEVIRTUAL && itf) {
723 throw new IllegalArgumentException(
724 "INVOKEVIRTUAL can't be used with interfaces");
725 }
726 if (opcode == Opcodes.INVOKEINTERFACE && !itf) {
727 throw new IllegalArgumentException(
728 "INVOKEINTERFACE can't be used with classes");
729 }
730 // Calling super.visitMethodInsn requires to call the correct version
731 // depending on this.api (otherwise infinite loops can occur). To
732 // simplify and to make it easier to automatically remove the backward
733 // compatibility code, we inline the code of the overridden method here.
734 if (mv != null) {
735 mv.visitMethodInsn(opcode, owner, name, desc, itf);
736 }
737 ++insnCount;
738 }
739
740 @Override
741 public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
742 Object... bsmArgs) {
743 checkStartCode();
744 checkEndCode();
745 checkMethodIdentifier(version, name, "name");
746 checkMethodDesc(desc);
747 if (bsm.getTag() != Opcodes.H_INVOKESTATIC
748 && bsm.getTag() != Opcodes.H_NEWINVOKESPECIAL) {
749 throw new IllegalArgumentException("invalid handle tag "
750 + bsm.getTag());
751 }
752 for (int i = 0; i < bsmArgs.length; i++) {
753 checkLDCConstant(bsmArgs[i]);
754 }
755 super.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
756 ++insnCount;
757 }
758
759 @Override
760 public void visitJumpInsn(final int opcode, final Label label) {
761 checkStartCode();
762 checkEndCode();
763 checkOpcode(opcode, 6);
764 checkLabel(label, false, "label");
765 checkNonDebugLabel(label);
766 super.visitJumpInsn(opcode, label);
767 usedLabels.add(label);
768 ++insnCount;
769 }
770
771 @Override
772 public void visitLabel(final Label label) {
773 checkStartCode();
774 checkEndCode();
775 checkLabel(label, false, "label");
776 if (labels.get(label) != null) {
777 throw new IllegalArgumentException("Already visited label");
778 }
779 labels.put(label, insnCount);
780 super.visitLabel(label);
781 }
782
783 @Override
784 public void visitLdcInsn(final Object cst) {
785 checkStartCode();
786 checkEndCode();
787 checkLDCConstant(cst);
788 super.visitLdcInsn(cst);
789 ++insnCount;
790 }
791
792 @Override
793 public void visitIincInsn(final int var, final int increment) {
794 checkStartCode();
795 checkEndCode();
796 checkUnsignedShort(var, "Invalid variable index");
797 checkSignedShort(increment, "Invalid increment");
798 super.visitIincInsn(var, increment);
799 ++insnCount;
800 }
801
802 @Override
803 public void visitTableSwitchInsn(final int min, final int max,
804 final Label dflt, final Label... labels) {
805 checkStartCode();
806 checkEndCode();
807 if (max < min) {
808 throw new IllegalArgumentException("Max = " + max
809 + " must be greater than or equal to min = " + min);
810 }
811 checkLabel(dflt, false, "default label");
812 checkNonDebugLabel(dflt);
813 if (labels == null || labels.length != max - min + 1) {
814 throw new IllegalArgumentException(
815 "There must be max - min + 1 labels");
816 }
817 for (int i = 0; i < labels.length; ++i) {
818 checkLabel(labels[i], false, "label at index " + i);
819 checkNonDebugLabel(labels[i]);
820 }
821 super.visitTableSwitchInsn(min, max, dflt, labels);
822 for (int i = 0; i < labels.length; ++i) {
823 usedLabels.add(labels[i]);
824 }
825 ++insnCount;
826 }
827
828 @Override
829 public void visitLookupSwitchInsn(final Label dflt, final int[] keys,
830 final Label[] labels) {
831 checkEndCode();
832 checkStartCode();
833 checkLabel(dflt, false, "default label");
834 checkNonDebugLabel(dflt);
835 if (keys == null || labels == null || keys.length != labels.length) {
836 throw new IllegalArgumentException(
837 "There must be the same number of keys and labels");
838 }
839 for (int i = 0; i < labels.length; ++i) {
840 checkLabel(labels[i], false, "label at index " + i);
841 checkNonDebugLabel(labels[i]);
842 }
843 super.visitLookupSwitchInsn(dflt, keys, labels);
844 usedLabels.add(dflt);
845 for (int i = 0; i < labels.length; ++i) {
846 usedLabels.add(labels[i]);
847 }
848 ++insnCount;
849 }
850
851 @Override
852 public void visitMultiANewArrayInsn(final String desc, final int dims) {
853 checkStartCode();
854 checkEndCode();
855 checkDesc(desc, false);
856 if (desc.charAt(0) != '[') {
857 throw new IllegalArgumentException(
858 "Invalid descriptor (must be an array type descriptor): "
859 + desc);
860 }
861 if (dims < 1) {
862 throw new IllegalArgumentException(
863 "Invalid dimensions (must be greater than 0): " + dims);
864 }
865 if (dims > desc.lastIndexOf('[') + 1) {
866 throw new IllegalArgumentException(
867 "Invalid dimensions (must not be greater than dims(desc)): "
868 + dims);
869 }
870 super.visitMultiANewArrayInsn(desc, dims);
871 ++insnCount;
872 }
873
874 @Override
875 public AnnotationVisitor visitInsnAnnotation(final int typeRef,
876 final TypePath typePath, final String desc, final boolean visible) {
877 checkStartCode();
878 checkEndCode();
879 int sort = typeRef >>> 24;
880 if (sort != TypeReference.INSTANCEOF && sort != TypeReference.NEW
881 && sort != TypeReference.CONSTRUCTOR_REFERENCE
882 && sort != TypeReference.METHOD_REFERENCE
883 && sort != TypeReference.CAST
884 && sort != TypeReference.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
885 && sort != TypeReference.METHOD_INVOCATION_TYPE_ARGUMENT
886 && sort != TypeReference.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
887 && sort != TypeReference.METHOD_REFERENCE_TYPE_ARGUMENT) {
888 throw new IllegalArgumentException("Invalid type reference sort 0x"
889 + Integer.toHexString(sort));
890 }
891 CheckClassAdapter.checkTypeRefAndPath(typeRef, typePath);
892 CheckMethodAdapter.checkDesc(desc, false);
893 return new CheckAnnotationAdapter(super.visitInsnAnnotation(typeRef,
894 typePath, desc, visible));
895 }
896
897 @Override
898 public void visitTryCatchBlock(final Label start, final Label end,
899 final Label handler, final String type) {
900 checkStartCode();
901 checkEndCode();
902 checkLabel(start, false, "start label");
903 checkLabel(end, false, "end label");
904 checkLabel(handler, false, "handler label");
905 checkNonDebugLabel(start);
906 checkNonDebugLabel(end);
907 checkNonDebugLabel(handler);
908 if (labels.get(start) != null || labels.get(end) != null
909 || labels.get(handler) != null) {
910 throw new IllegalStateException(
911 "Try catch blocks must be visited before their labels");
912 }
913 if (type != null) {
914 checkInternalName(type, "type");
915 }
916 super.visitTryCatchBlock(start, end, handler, type);
917 handlers.add(start);
918 handlers.add(end);
919 }
920
921 @Override
922 public AnnotationVisitor visitTryCatchAnnotation(final int typeRef,
923 final TypePath typePath, final String desc, final boolean visible) {
924 checkStartCode();
925 checkEndCode();
926 int sort = typeRef >>> 24;
927 if (sort != TypeReference.EXCEPTION_PARAMETER) {
928 throw new IllegalArgumentException("Invalid type reference sort 0x"
929 + Integer.toHexString(sort));
930 }
931 CheckClassAdapter.checkTypeRefAndPath(typeRef, typePath);
932 CheckMethodAdapter.checkDesc(desc, false);
933 return new CheckAnnotationAdapter(super.visitTryCatchAnnotation(
934 typeRef, typePath, desc, visible));
935 }
936
937 @Override
938 public void visitLocalVariable(final String name, final String desc,
939 final String signature, final Label start, final Label end,
940 final int index) {
941 checkStartCode();
942 checkEndCode();
943 checkUnqualifiedName(version, name, "name");
944 checkDesc(desc, false);
945 checkLabel(start, true, "start label");
946 checkLabel(end, true, "end label");
947 checkUnsignedShort(index, "Invalid variable index");
948 int s = labels.get(start).intValue();
949 int e = labels.get(end).intValue();
950 if (e < s) {
951 throw new IllegalArgumentException(
952 "Invalid start and end labels (end must be greater than start)");
953 }
954 super.visitLocalVariable(name, desc, signature, start, end, index);
955 }
956
957 @Override
958 public AnnotationVisitor visitLocalVariableAnnotation(int typeRef,
959 TypePath typePath, Label[] start, Label[] end, int[] index,
960 String desc, boolean visible) {
961 checkStartCode();
962 checkEndCode();
963 int sort = typeRef >>> 24;
964 if (sort != TypeReference.LOCAL_VARIABLE
965 && sort != TypeReference.RESOURCE_VARIABLE) {
966 throw new IllegalArgumentException("Invalid type reference sort 0x"
967 + Integer.toHexString(sort));
968 }
969 CheckClassAdapter.checkTypeRefAndPath(typeRef, typePath);
970 checkDesc(desc, false);
971 if (start == null || end == null || index == null
972 || end.length != start.length || index.length != start.length) {
973 throw new IllegalArgumentException(
974 "Invalid start, end and index arrays (must be non null and of identical length");
975 }
976 for (int i = 0; i < start.length; ++i) {
977 checkLabel(start[i], true, "start label");
978 checkLabel(end[i], true, "end label");
979 checkUnsignedShort(index[i], "Invalid variable index");
980 int s = labels.get(start[i]).intValue();
981 int e = labels.get(end[i]).intValue();
982 if (e < s) {
983 throw new IllegalArgumentException(
984 "Invalid start and end labels (end must be greater than start)");
985 }
986 }
987 return super.visitLocalVariableAnnotation(typeRef, typePath, start,
988 end, index, desc, visible);
989 }
990
991 @Override
992 public void visitLineNumber(final int line, final Label start) {
993 checkStartCode();
994 checkEndCode();
995 checkUnsignedShort(line, "Invalid line number");
996 checkLabel(start, true, "start label");
997 super.visitLineNumber(line, start);
998 }
999
1000 @Override
1001 public void visitMaxs(final int maxStack, final int maxLocals) {
1002 checkStartCode();
1003 checkEndCode();
1004 endCode = true;
1005 for (Label l : usedLabels) {
1006 if (labels.get(l) == null) {
1007 throw new IllegalStateException("Undefined label used");
1008 }
1009 }
1010 for (int i = 0; i < handlers.size();) {
1011 Integer start = labels.get(handlers.get(i++));
1012 Integer end = labels.get(handlers.get(i++));
1013 if (start == null || end == null) {
1014 throw new IllegalStateException(
1015 "Undefined try catch block labels");
1016 }
1017 if (end.intValue() <= start.intValue()) {
1018 throw new IllegalStateException(
1019 "Emty try catch block handler range");
1020 }
1021 }
1022 checkUnsignedShort(maxStack, "Invalid max stack");
1023 checkUnsignedShort(maxLocals, "Invalid max locals");
1024 super.visitMaxs(maxStack, maxLocals);
1025 }
1026
1027 @Override
1028 public void visitEnd() {
1029 checkEndMethod();
1030 endMethod = true;
1031 super.visitEnd();
1032 }
1033
1034 // -------------------------------------------------------------------------
1035
1036 /**
1037 * Checks that the visitCode method has been called.
1038 */
1039 void checkStartCode() {
1040 if (!startCode) {
1041 throw new IllegalStateException(
1042 "Cannot visit instructions before visitCode has been called.");
1043 }
1044 }
1045
1046 /**
1047 * Checks that the visitMaxs method has not been called.
1048 */
1049 void checkEndCode() {
1050 if (endCode) {
1051 throw new IllegalStateException(
1052 "Cannot visit instructions after visitMaxs has been called.");
1053 }
1054 }
1055
1056 /**
1057 * Checks that the visitEnd method has not been called.
1058 */
1059 void checkEndMethod() {
1060 if (endMethod) {
1061 throw new IllegalStateException(
1062 "Cannot visit elements after visitEnd has been called.");
1063 }
1064 }
1065
1066 /**
1067 * Checks a stack frame value.
1068 *
1069 * @param value
1070 * the value to be checked.
1071 */
1072 void checkFrameValue(final Object value) {
1073 if (value == Opcodes.TOP || value == Opcodes.INTEGER
1074 || value == Opcodes.FLOAT || value == Opcodes.LONG
1075 || value == Opcodes.DOUBLE || value == Opcodes.NULL
1076 || value == Opcodes.UNINITIALIZED_THIS) {
1077 return;
1078 }
1079 if (value instanceof String) {
1080 checkInternalName((String) value, "Invalid stack frame value");
1081 return;
1082 }
1083 if (!(value instanceof Label)) {
1084 throw new IllegalArgumentException("Invalid stack frame value: "
1085 + value);
1086 } else {
1087 usedLabels.add((Label) value);
1088 }
1089 }
1090
1091 /**
1092 * Checks that the type of the given opcode is equal to the given type.
1093 *
1094 * @param opcode
1095 * the opcode to be checked.
1096 * @param type
1097 * the expected opcode type.
1098 */
1099 static void checkOpcode(final int opcode, final int type) {
1100 if (opcode < 0 || opcode > 199 || TYPE[opcode] != type) {
1101 throw new IllegalArgumentException("Invalid opcode: " + opcode);
1102 }
1103 }
1104
1105 /**
1106 * Checks that the given value is a signed byte.
1107 *
1108 * @param value
1109 * the value to be checked.
1110 * @param msg
1111 * an message to be used in case of error.
1112 */
1113 static void checkSignedByte(final int value, final String msg) {
1114 if (value < Byte.MIN_VALUE || value > Byte.MAX_VALUE) {
1115 throw new IllegalArgumentException(msg
1116 + " (must be a signed byte): " + value);
1117 }
1118 }
1119
1120 /**
1121 * Checks that the given value is a signed short.
1122 *
1123 * @param value
1124 * the value to be checked.
1125 * @param msg
1126 * an message to be used in case of error.
1127 */
1128 static void checkSignedShort(final int value, final String msg) {
1129 if (value < Short.MIN_VALUE || value > Short.MAX_VALUE) {
1130 throw new IllegalArgumentException(msg
1131 + " (must be a signed short): " + value);
1132 }
1133 }
1134
1135 /**
1136 * Checks that the given value is an unsigned short.
1137 *
1138 * @param value
1139 * the value to be checked.
1140 * @param msg
1141 * an message to be used in case of error.
1142 */
1143 static void checkUnsignedShort(final int value, final String msg) {
1144 if (value < 0 || value > 65535) {
1145 throw new IllegalArgumentException(msg
1146 + " (must be an unsigned short): " + value);
1147 }
1148 }
1149
1150 /**
1151 * Checks that the given value is an {@link Integer}, a{@link Float}, a
1152 * {@link Long}, a {@link Double} or a {@link String}.
1153 *
1154 * @param cst
1155 * the value to be checked.
1156 */
1157 static void checkConstant(final Object cst) {
1158 if (!(cst instanceof Integer) && !(cst instanceof Float)
1159 && !(cst instanceof Long) && !(cst instanceof Double)
1160 && !(cst instanceof String)) {
1161 throw new IllegalArgumentException("Invalid constant: " + cst);
1162 }
1163 }
1164
1165 void checkLDCConstant(final Object cst) {
1166 if (cst instanceof Type) {
1167 int s = ((Type) cst).getSort();
1168 if (s != Type.OBJECT && s != Type.ARRAY && s != Type.METHOD) {
1169 throw new IllegalArgumentException("Illegal LDC constant value");
1170 }
1171 if (s != Type.METHOD && (version & 0xFFFF) < Opcodes.V1_5) {
1172 throw new IllegalArgumentException(
1173 "ldc of a constant class requires at least version 1.5");
1174 }
1175 if (s == Type.METHOD && (version & 0xFFFF) < Opcodes.V1_7) {
1176 throw new IllegalArgumentException(
1177 "ldc of a method type requires at least version 1.7");
1178 }
1179 } else if (cst instanceof Handle) {
1180 if ((version & 0xFFFF) < Opcodes.V1_7) {
1181 throw new IllegalArgumentException(
1182 "ldc of a handle requires at least version 1.7");
1183 }
1184 int tag = ((Handle) cst).getTag();
1185 if (tag < Opcodes.H_GETFIELD || tag > Opcodes.H_INVOKEINTERFACE) {
1186 throw new IllegalArgumentException("invalid handle tag " + tag);
1187 }
1188 } else {
1189 checkConstant(cst);
1190 }
1191 }
1192
1193 /**
1194 * Checks that the given string is a valid unqualified name.
1195 *
1196 * @param version
1197 * the class version.
1198 * @param name
1199 * the string to be checked.
1200 * @param msg
1201 * a message to be used in case of error.
1202 */
1203 static void checkUnqualifiedName(int version, final String name,
1204 final String msg) {
1205 if ((version & 0xFFFF) < Opcodes.V1_5) {
1206 checkIdentifier(name, msg);
1207 } else {
1208 for (int i = 0; i < name.length(); ++i) {
1209 if (".;[/".indexOf(name.charAt(i)) != -1) {
1210 throw new IllegalArgumentException("Invalid " + msg
1211 + " (must be a valid unqualified name): " + name);
1212 }
1213 }
1214 }
1215 }
1216
1217 /**
1218 * Checks that the given string is a valid Java identifier.
1219 *
1220 * @param name
1221 * the string to be checked.
1222 * @param msg
1223 * a message to be used in case of error.
1224 */
1225 static void checkIdentifier(final String name, final String msg) {
1226 checkIdentifier(name, 0, -1, msg);
1227 }
1228
1229 /**
1230 * Checks that the given substring is a valid Java identifier.
1231 *
1232 * @param name
1233 * the string to be checked.
1234 * @param start
1235 * index of the first character of the identifier (inclusive).
1236 * @param end
1237 * index of the last character of the identifier (exclusive). -1
1238 * is equivalent to <tt>name.length()</tt> if name is not
1239 * <tt>null</tt>.
1240 * @param msg
1241 * a message to be used in case of error.
1242 */
1243 static void checkIdentifier(final String name, final int start,
1244 final int end, final String msg) {
1245 if (name == null || (end == -1 ? name.length() <= start : end <= start)) {
1246 throw new IllegalArgumentException("Invalid " + msg
1247 + " (must not be null or empty)");
1248 }
1249 if (!Character.isJavaIdentifierStart(name.charAt(start))) {
1250 throw new IllegalArgumentException("Invalid " + msg
1251 + " (must be a valid Java identifier): " + name);
1252 }
1253 int max = end == -1 ? name.length() : end;
1254 for (int i = start + 1; i < max; ++i) {
1255 if (!Character.isJavaIdentifierPart(name.charAt(i))) {
1256 throw new IllegalArgumentException("Invalid " + msg
1257 + " (must be a valid Java identifier): " + name);
1258 }
1259 }
1260 }
1261
1262 /**
1263 * Checks that the given string is a valid Java identifier.
1264 *
1265 * @param version
1266 * the class version.
1267 * @param name
1268 * the string to be checked.
1269 * @param msg
1270 * a message to be used in case of error.
1271 */
1272 static void checkMethodIdentifier(int version, final String name,
1273 final String msg) {
1274 if (name == null || name.length() == 0) {
1275 throw new IllegalArgumentException("Invalid " + msg
1276 + " (must not be null or empty)");
1277 }
1278 if ((version & 0xFFFF) >= Opcodes.V1_5) {
1279 for (int i = 0; i < name.length(); ++i) {
1280 if (".;[/<>".indexOf(name.charAt(i)) != -1) {
1281 throw new IllegalArgumentException("Invalid " + msg
1282 + " (must be a valid unqualified name): " + name);
1283 }
1284 }
1285 return;
1286 }
1287 if (!Character.isJavaIdentifierStart(name.charAt(0))) {
1288 throw new IllegalArgumentException(
1289 "Invalid "
1290 + msg
1291 + " (must be a '<init>', '<clinit>' or a valid Java identifier): "
1292 + name);
1293 }
1294 for (int i = 1; i < name.length(); ++i) {
1295 if (!Character.isJavaIdentifierPart(name.charAt(i))) {
1296 throw new IllegalArgumentException(
1297 "Invalid "
1298 + msg
1299 + " (must be '<init>' or '<clinit>' or a valid Java identifier): "
1300 + name);
1301 }
1302 }
1303 }
1304
1305 /**
1306 * Checks that the given string is a valid internal class name.
1307 *
1308 * @param name
1309 * the string to be checked.
1310 * @param msg
1311 * a message to be used in case of error.
1312 */
1313 static void checkInternalName(final String name, final String msg) {
1314 if (name == null || name.length() == 0) {
1315 throw new IllegalArgumentException("Invalid " + msg
1316 + " (must not be null or empty)");
1317 }
1318 if (name.charAt(0) == '[') {
1319 checkDesc(name, false);
1320 } else {
1321 checkInternalName(name, 0, -1, msg);
1322 }
1323 }
1324
1325 /**
1326 * Checks that the given substring is a valid internal class name.
1327 *
1328 * @param name
1329 * the string to be checked.
1330 * @param start
1331 * index of the first character of the identifier (inclusive).
1332 * @param end
1333 * index of the last character of the identifier (exclusive). -1
1334 * is equivalent to <tt>name.length()</tt> if name is not
1335 * <tt>null</tt>.
1336 * @param msg
1337 * a message to be used in case of error.
1338 */
1339 static void checkInternalName(final String name, final int start,
1340 final int end, final String msg) {
1341 int max = end == -1 ? name.length() : end;
1342 try {
1343 int begin = start;
1344 int slash;
1345 do {
1346 slash = name.indexOf('/', begin + 1);
1347 if (slash == -1 || slash > max) {
1348 slash = max;
1349 }
1350 checkIdentifier(name, begin, slash, null);
1351 begin = slash + 1;
1352 } while (slash != max);
1353 } catch (IllegalArgumentException unused) {
1354 throw new IllegalArgumentException(
1355 "Invalid "
1356 + msg
1357 + " (must be a fully qualified class name in internal form): "
1358 + name);
1359 }
1360 }
1361
1362 /**
1363 * Checks that the given string is a valid type descriptor.
1364 *
1365 * @param desc
1366 * the string to be checked.
1367 * @param canBeVoid
1368 * <tt>true</tt> if <tt>V</tt> can be considered valid.
1369 */
1370 static void checkDesc(final String desc, final boolean canBeVoid) {
1371 int end = checkDesc(desc, 0, canBeVoid);
1372 if (end != desc.length()) {
1373 throw new IllegalArgumentException("Invalid descriptor: " + desc);
1374 }
1375 }
1376
1377 /**
1378 * Checks that a the given substring is a valid type descriptor.
1379 *
1380 * @param desc
1381 * the string to be checked.
1382 * @param start
1383 * index of the first character of the identifier (inclusive).
1384 * @param canBeVoid
1385 * <tt>true</tt> if <tt>V</tt> can be considered valid.
1386 * @return the index of the last character of the type decriptor, plus one.
1387 */
1388 static int checkDesc(final String desc, final int start,
1389 final boolean canBeVoid) {
1390 if (desc == null || start >= desc.length()) {
1391 throw new IllegalArgumentException(
1392 "Invalid type descriptor (must not be null or empty)");
1393 }
1394 int index;
1395 switch (desc.charAt(start)) {
1396 case 'V':
1397 if (canBeVoid) {
1398 return start + 1;
1399 } else {
1400 throw new IllegalArgumentException("Invalid descriptor: "
1401 + desc);
1402 }
1403 case 'Z':
1404 case 'C':
1405 case 'B':
1406 case 'S':
1407 case 'I':
1408 case 'F':
1409 case 'J':
1410 case 'D':
1411 return start + 1;
1412 case '[':
1413 index = start + 1;
1414 while (index < desc.length() && desc.charAt(index) == '[') {
1415 ++index;
1416 }
1417 if (index < desc.length()) {
1418 return checkDesc(desc, index, false);
1419 } else {
1420 throw new IllegalArgumentException("Invalid descriptor: "
1421 + desc);
1422 }
1423 case 'L':
1424 index = desc.indexOf(';', start);
1425 if (index == -1 || index - start < 2) {
1426 throw new IllegalArgumentException("Invalid descriptor: "
1427 + desc);
1428 }
1429 try {
1430 checkInternalName(desc, start + 1, index, null);
1431 } catch (IllegalArgumentException unused) {
1432 throw new IllegalArgumentException("Invalid descriptor: "
1433 + desc);
1434 }
1435 return index + 1;
1436 default:
1437 throw new IllegalArgumentException("Invalid descriptor: " + desc);
1438 }
1439 }
1440
1441 /**
1442 * Checks that the given string is a valid method descriptor.
1443 *
1444 * @param desc
1445 * the string to be checked.
1446 */
1447 static void checkMethodDesc(final String desc) {
1448 if (desc == null || desc.length() == 0) {
1449 throw new IllegalArgumentException(
1450 "Invalid method descriptor (must not be null or empty)");
1451 }
1452 if (desc.charAt(0) != '(' || desc.length() < 3) {
1453 throw new IllegalArgumentException("Invalid descriptor: " + desc);
1454 }
1455 int start = 1;
1456 if (desc.charAt(start) != ')') {
1457 do {
1458 if (desc.charAt(start) == 'V') {
1459 throw new IllegalArgumentException("Invalid descriptor: "
1460 + desc);
1461 }
1462 start = checkDesc(desc, start, false);
1463 } while (start < desc.length() && desc.charAt(start) != ')');
1464 }
1465 start = checkDesc(desc, start + 1, true);
1466 if (start != desc.length()) {
1467 throw new IllegalArgumentException("Invalid descriptor: " + desc);
1468 }
1469 }
1470
1471 /**
1472 * Checks that the given label is not null. This method can also check that
1473 * the label has been visited.
1474 *
1475 * @param label
1476 * the label to be checked.
1477 * @param checkVisited
1478 * <tt>true</tt> to check that the label has been visited.
1479 * @param msg
1480 * a message to be used in case of error.
1481 */
1482 void checkLabel(final Label label, final boolean checkVisited,
1483 final String msg) {
1484 if (label == null) {
1485 throw new IllegalArgumentException("Invalid " + msg
1486 + " (must not be null)");
1487 }
1488 if (checkVisited && labels.get(label) == null) {
1489 throw new IllegalArgumentException("Invalid " + msg
1490 + " (must be visited first)");
1491 }
1492 }
1493
1494 /**
1495 * Checks that the given label is not a label used only for debug purposes.
1496 *
1497 * @param label
1498 * the label to be checked.
1499 */
1500 private static void checkNonDebugLabel(final Label label) {
1501 Field f = getLabelStatusField();
1502 int status = 0;
1503 try {
1504 status = f == null ? 0 : ((Integer) f.get(label)).intValue();
1505 } catch (IllegalAccessException e) {
1506 throw new Error("Internal error");
1507 }
1508 if ((status & 0x01) != 0) {
1509 throw new IllegalArgumentException(
1510 "Labels used for debug info cannot be reused for control flow");
1511 }
1512 }
1513
1514 /**
1515 * Returns the Field object corresponding to the Label.status field.
1516 *
1517 * @return the Field object corresponding to the Label.status field.
1518 */
1519 private static Field getLabelStatusField() {
1520 if (labelStatusField == null) {
1521 labelStatusField = getLabelField("a");
1522 if (labelStatusField == null) {
1523 labelStatusField = getLabelField("status");
1524 }
1525 }
1526 return labelStatusField;
1527 }
1528
1529 /**
1530 * Returns the field of the Label class whose name is given.
1531 *
1532 * @param name
1533 * a field name.
1534 * @return the field of the Label class whose name is given, or null.
1535 */
1536 private static Field getLabelField(final String name) {
1537 try {
1538 Field f = Label.class.getDeclaredField(name);
1539 f.setAccessible(true);
1540 return f;
1541 } catch (NoSuchFieldException e) {
1542 return null;
1543 }
1544 }
1409 pos = checkDescriptor(descriptor, pos, false);
1410 } while (pos < descriptor.length() && descriptor.charAt(pos) != ')');
1411 }
1412 pos = checkDescriptor(descriptor, pos + 1, true);
1413 if (pos != descriptor.length()) {
1414 throw new IllegalArgumentException(INVALID_DESCRIPTOR + descriptor);
1415 }
1416 }
1417
1418 /**
1419 * Checks that the given label is not null. This method can also check that the label has been
1420 * visited.
1421 *
1422 * @param label the label to be checked.
1423 * @param checkVisited whether to check that the label has been visited.
1424 * @param message the message to use in case of error.
1425 */
1426 private void checkLabel(final Label label, final boolean checkVisited, final String message) {
1427 if (label == null) {
1428 throw new IllegalArgumentException(INVALID + message + " (must not be null)");
1429 }
1430 if (checkVisited && labelInsnIndices.get(label) == null) {
1431 throw new IllegalArgumentException(INVALID + message + " (must be visited first)");
1432 }
1433 }
15451434 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.util;
28
29 import java.util.HashSet;
3030
3131 import org.eclipse.persistence.internal.libraries.asm.ModuleVisitor;
3232 import org.eclipse.persistence.internal.libraries.asm.Opcodes;
3333
3434 /**
35 * A {@link ModuleVisitor} that checks that its methods are properly used.
36 *
3537 * @author Remi Forax
3638 */
37 public final class CheckModuleAdapter extends ModuleVisitor {
38 private boolean end;
39 public class CheckModuleAdapter extends ModuleVisitor {
40 /** Whether the visited module is open. */
41 private final boolean isOpen;
3942
40 public CheckModuleAdapter(final ModuleVisitor mv) {
41 super(Opcodes.ASM6, mv);
43 /** The fully qualified names of the dependencies of the visited module. */
44 private final HashSet<String> requiredModules = new HashSet<String>();
45
46 /** The internal names of the packages exported by the visited module. */
47 private final HashSet<String> exportedPackages = new HashSet<String>();
48
49 /** The internal names of the packages opened by the visited module. */
50 private final HashSet<String> openedPackages = new HashSet<String>();
51
52 /** The internal names of the services used by the visited module. */
53 private final HashSet<String> usedServices = new HashSet<String>();
54
55 /** The internal names of the services provided by the visited module. */
56 private final HashSet<String> providedServices = new HashSet<String>();
57
58 /** The class version number. */
59 int classVersion;
60
61 /** Whether the {@link #visitEnd} method has been called. */
62 private boolean visitEndCalled;
63
64 /**
65 * Constructs a new {@link CheckModuleAdapter}. <i>Subclasses must not use this constructor</i>.
66 * Instead, they must use the {@link #CheckModuleAdapter(int, ModuleVisitor, boolean)} version.
67 *
68 * @param moduleVisitor the module visitor to which this adapter must delegate calls.
69 * @param isOpen whether the visited module is open. Open modules have their {@link
70 * Opcodes#ACC_OPEN} access flag set in {@link org.eclipse.persistence.internal.libraries.asm.ClassVisitor#visitModule}.
71 * @throws IllegalStateException If a subclass calls this constructor.
72 */
73 public CheckModuleAdapter(final ModuleVisitor moduleVisitor, final boolean isOpen) {
74 this(Opcodes.ASM6, moduleVisitor, isOpen);
75 if (getClass() != CheckModuleAdapter.class) {
76 throw new IllegalStateException();
4277 }
78 }
4379
44 @Override
45 public void visitRequire(String module, int access) {
46 checkEnd();
47 if (module == null) {
48 throw new IllegalArgumentException("require cannot be null");
49 }
50 super.visitRequire(module, access);
80 /**
81 * Constructs a new {@link CheckModuleAdapter}.
82 *
83 * @param api the ASM API version implemented by this visitor. Must be one of {@link
84 * Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
85 * @param moduleVisitor the module visitor to which this adapter must delegate calls.
86 * @param isOpen whether the visited module is open. Open modules have their {@link
87 * Opcodes#ACC_OPEN} access flag set in {@link org.eclipse.persistence.internal.libraries.asm.ClassVisitor#visitModule}.
88 */
89 protected CheckModuleAdapter(
90 final int api, final ModuleVisitor moduleVisitor, final boolean isOpen) {
91 super(api, moduleVisitor);
92 this.isOpen = isOpen;
93 }
94
95 @Override
96 public void visitMainClass(final String mainClass) {
97 CheckMethodAdapter.checkInternalName(mainClass, "module main class");
98 super.visitMainClass(mainClass);
99 }
100
101 @Override
102 public void visitPackage(final String packaze) {
103 CheckMethodAdapter.checkInternalName(packaze, "module package");
104 super.visitPackage(packaze);
105 }
106
107 @Override
108 public void visitRequire(final String module, final int access, final String version) {
109 checkVisitEndNotCalled();
110 CheckClassAdapter.checkFullyQualifiedName(module, "required module");
111 checkNameNotAlreadyDeclared(module, requiredModules, "Modules requires");
112 CheckClassAdapter.checkAccess(
113 access,
114 Opcodes.ACC_STATIC_PHASE
115 | Opcodes.ACC_TRANSITIVE
116 | Opcodes.ACC_SYNTHETIC
117 | Opcodes.ACC_MANDATED);
118 if (classVersion >= Opcodes.V10 && module.equals("java.base") &&
119 (access & (Opcodes.ACC_STATIC_PHASE | Opcodes.ACC_TRANSITIVE)) != 0) {
120 throw new IllegalArgumentException("Invalid access flags: " + access +
121 " java.base can not be declared ACC_TRANSITIVE or ACC_STATIC_PHASE");
51122 }
52
53 @Override
54 public void visitExport(String packaze, String... modules) {
55 checkEnd();
56 if (packaze == null) {
57 throw new IllegalArgumentException("require cannot be null");
58 }
59 if (modules != null) {
60 for(int i = 0; i < modules.length; i++) {
61 if (modules[i] == null) {
62 throw new IllegalArgumentException("to at index " + i + " cannot be null");
63 }
64 }
65 }
66 super.visitExport(packaze, modules);
123 super.visitRequire(module, access, version);
124 }
125
126 @Override
127 public void visitExport(final String packaze, final int access, final String... modules) {
128 checkVisitEndNotCalled();
129 CheckMethodAdapter.checkInternalName(packaze, "package name");
130 checkNameNotAlreadyDeclared(packaze, exportedPackages, "Module exports");
131 CheckClassAdapter.checkAccess(access, Opcodes.ACC_SYNTHETIC | Opcodes.ACC_MANDATED);
132 if (modules != null) {
133 for (String module : modules) {
134 CheckClassAdapter.checkFullyQualifiedName(module, "module export to");
135 }
67136 }
68
69 @Override
70 public void visitUse(String service) {
71 checkEnd();
72 CheckMethodAdapter.checkInternalName(service, "service");
73 super.visitUse(service);
137 super.visitExport(packaze, access, modules);
138 }
139
140 @Override
141 public void visitOpen(final String packaze, final int access, final String... modules) {
142 checkVisitEndNotCalled();
143 if (isOpen) {
144 throw new UnsupportedOperationException("An open module can not use open directive");
74145 }
75
76 @Override
77 public void visitProvide(String service, String impl) {
78 checkEnd();
79 CheckMethodAdapter.checkInternalName(service, "service");
80 CheckMethodAdapter.checkInternalName(impl, "impl");
81 super.visitProvide(service, impl);
146 CheckMethodAdapter.checkInternalName(packaze, "package name");
147 checkNameNotAlreadyDeclared(packaze, openedPackages, "Module opens");
148 CheckClassAdapter.checkAccess(access, Opcodes.ACC_SYNTHETIC | Opcodes.ACC_MANDATED);
149 if (modules != null) {
150 for (String module : modules) {
151 CheckClassAdapter.checkFullyQualifiedName(module, "module open to");
152 }
82153 }
83
84 @Override
85 public void visitEnd() {
86 checkEnd();
87 end = true;
88 super.visitEnd();
154 super.visitOpen(packaze, access, modules);
155 }
156
157 @Override
158 public void visitUse(final String service) {
159 checkVisitEndNotCalled();
160 CheckMethodAdapter.checkInternalName(service, "service");
161 checkNameNotAlreadyDeclared(service, usedServices, "Module uses");
162 super.visitUse(service);
163 }
164
165 @Override
166 public void visitProvide(final String service, final String... providers) {
167 checkVisitEndNotCalled();
168 CheckMethodAdapter.checkInternalName(service, "service");
169 checkNameNotAlreadyDeclared(service, providedServices, "Module provides");
170 if (providers == null || providers.length == 0) {
171 throw new IllegalArgumentException("Providers cannot be null or empty");
89172 }
173 for (String provider : providers) {
174 CheckMethodAdapter.checkInternalName(provider, "provider");
175 }
176 super.visitProvide(service, providers);
177 }
90178
91 private void checkEnd() {
92 if (end) {
93 throw new IllegalStateException(
94 "Cannot call a visit method after visitEnd has been called");
95 }
179 @Override
180 public void visitEnd() {
181 checkVisitEndNotCalled();
182 visitEndCalled = true;
183 super.visitEnd();
184 }
185
186 private static void checkNameNotAlreadyDeclared(
187 final String name, final HashSet<String> declaredNames, final String message) {
188 if (!declaredNames.add(name)) {
189 throw new IllegalArgumentException(message + " " + name + " already declared");
96190 }
191 }
192
193 private void checkVisitEndNotCalled() {
194 if (visitEndCalled) {
195 throw new IllegalStateException("Cannot call a visit method after visitEnd has been called");
196 }
197 }
97198 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.util;
28
29 import java.util.EnumSet;
3030
3131 import org.eclipse.persistence.internal.libraries.asm.Opcodes;
3232 import org.eclipse.persistence.internal.libraries.asm.signature.SignatureVisitor;
3333
3434 /**
3535 * A {@link SignatureVisitor} that checks that its methods are properly used.
36 *
36 *
3737 * @author Eric Bruneton
3838 */
3939 public class CheckSignatureAdapter extends SignatureVisitor {
4040
41 /**
42 * Type to be used to check class signatures. See
43 * {@link #CheckSignatureAdapter(int, SignatureVisitor)
44 * CheckSignatureAdapter}.
45 */
46 public static final int CLASS_SIGNATURE = 0;
47
48 /**
49 * Type to be used to check method signatures. See
50 * {@link #CheckSignatureAdapter(int, SignatureVisitor)
51 * CheckSignatureAdapter}.
52 */
53 public static final int METHOD_SIGNATURE = 1;
54
55 /**
56 * Type to be used to check type signatures.See
57 * {@link #CheckSignatureAdapter(int, SignatureVisitor)
58 * CheckSignatureAdapter}.
59 */
60 public static final int TYPE_SIGNATURE = 2;
61
62 private static final int EMPTY = 1;
63
64 private static final int FORMAL = 2;
65
66 private static final int BOUND = 4;
67
68 private static final int SUPER = 8;
69
70 private static final int PARAM = 16;
71
72 private static final int RETURN = 32;
73
74 private static final int SIMPLE_TYPE = 64;
75
76 private static final int CLASS_TYPE = 128;
77
78 private static final int END = 256;
79
80 /**
81 * Type of the signature to be checked.
82 */
83 private final int type;
84
85 /**
86 * State of the automaton used to check the order of method calls.
87 */
88 private int state;
89
90 /**
91 * <tt>true</tt> if the checked type signature can be 'V'.
92 */
93 private boolean canBeVoid;
94
95 /**
96 * The visitor to which this adapter must delegate calls. May be
97 * <tt>null</tt>.
98 */
99 private final SignatureVisitor sv;
100
101 /**
102 * Creates a new {@link CheckSignatureAdapter} object. <i>Subclasses must
103 * not use this constructor</i>. Instead, they must use the
104 * {@link #CheckSignatureAdapter(int, int, SignatureVisitor)} version.
105 *
106 * @param type
107 * the type of signature to be checked. See
108 * {@link #CLASS_SIGNATURE}, {@link #METHOD_SIGNATURE} and
109 * {@link #TYPE_SIGNATURE}.
110 * @param sv
111 * the visitor to which this adapter must delegate calls. May be
112 * <tt>null</tt>.
113 */
114 public CheckSignatureAdapter(final int type, final SignatureVisitor sv) {
115 this(Opcodes.ASM6, type, sv);
116 }
117
118 /**
119 * Creates a new {@link CheckSignatureAdapter} object.
120 *
121 * @param api
122 * the ASM API version implemented by this visitor. Must be one
123 * of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
124 * @param type
125 * the type of signature to be checked. See
126 * {@link #CLASS_SIGNATURE}, {@link #METHOD_SIGNATURE} and
127 * {@link #TYPE_SIGNATURE}.
128 * @param sv
129 * the visitor to which this adapter must delegate calls. May be
130 * <tt>null</tt>.
131 */
132 protected CheckSignatureAdapter(final int api, final int type,
133 final SignatureVisitor sv) {
134 super(api);
135 this.type = type;
136 this.state = EMPTY;
137 this.sv = sv;
138 }
139
140 // class and method signatures
141
142 @Override
143 public void visitFormalTypeParameter(final String name) {
144 if (type == TYPE_SIGNATURE
145 || (state != EMPTY && state != FORMAL && state != BOUND)) {
146 throw new IllegalStateException();
147 }
148 CheckMethodAdapter.checkIdentifier(name, "formal type parameter");
149 state = FORMAL;
150 if (sv != null) {
151 sv.visitFormalTypeParameter(name);
152 }
153 }
154
155 @Override
156 public SignatureVisitor visitClassBound() {
157 if (state != FORMAL) {
158 throw new IllegalStateException();
159 }
160 state = BOUND;
161 SignatureVisitor v = sv == null ? null : sv.visitClassBound();
162 return new CheckSignatureAdapter(TYPE_SIGNATURE, v);
163 }
164
165 @Override
166 public SignatureVisitor visitInterfaceBound() {
167 if (state != FORMAL && state != BOUND) {
168 throw new IllegalArgumentException();
169 }
170 SignatureVisitor v = sv == null ? null : sv.visitInterfaceBound();
171 return new CheckSignatureAdapter(TYPE_SIGNATURE, v);
172 }
173
174 // class signatures
175
176 @Override
177 public SignatureVisitor visitSuperclass() {
178 if (type != CLASS_SIGNATURE || (state & (EMPTY | FORMAL | BOUND)) == 0) {
179 throw new IllegalArgumentException();
180 }
181 state = SUPER;
182 SignatureVisitor v = sv == null ? null : sv.visitSuperclass();
183 return new CheckSignatureAdapter(TYPE_SIGNATURE, v);
184 }
185
186 @Override
187 public SignatureVisitor visitInterface() {
188 if (state != SUPER) {
189 throw new IllegalStateException();
190 }
191 SignatureVisitor v = sv == null ? null : sv.visitInterface();
192 return new CheckSignatureAdapter(TYPE_SIGNATURE, v);
193 }
194
195 // method signatures
196
197 @Override
198 public SignatureVisitor visitParameterType() {
199 if (type != METHOD_SIGNATURE
200 || (state & (EMPTY | FORMAL | BOUND | PARAM)) == 0) {
201 throw new IllegalArgumentException();
202 }
203 state = PARAM;
204 SignatureVisitor v = sv == null ? null : sv.visitParameterType();
205 return new CheckSignatureAdapter(TYPE_SIGNATURE, v);
206 }
207
208 @Override
209 public SignatureVisitor visitReturnType() {
210 if (type != METHOD_SIGNATURE
211 || (state & (EMPTY | FORMAL | BOUND | PARAM)) == 0) {
212 throw new IllegalArgumentException();
213 }
214 state = RETURN;
215 SignatureVisitor v = sv == null ? null : sv.visitReturnType();
216 CheckSignatureAdapter cv = new CheckSignatureAdapter(TYPE_SIGNATURE, v);
217 cv.canBeVoid = true;
218 return cv;
219 }
220
221 @Override
222 public SignatureVisitor visitExceptionType() {
223 if (state != RETURN) {
224 throw new IllegalStateException();
225 }
226 SignatureVisitor v = sv == null ? null : sv.visitExceptionType();
227 return new CheckSignatureAdapter(TYPE_SIGNATURE, v);
228 }
229
230 // type signatures
231
232 @Override
233 public void visitBaseType(final char descriptor) {
234 if (type != TYPE_SIGNATURE || state != EMPTY) {
235 throw new IllegalStateException();
236 }
237 if (descriptor == 'V') {
238 if (!canBeVoid) {
239 throw new IllegalArgumentException();
240 }
241 } else {
242 if ("ZCBSIFJD".indexOf(descriptor) == -1) {
243 throw new IllegalArgumentException();
244 }
245 }
246 state = SIMPLE_TYPE;
247 if (sv != null) {
248 sv.visitBaseType(descriptor);
249 }
250 }
251
252 @Override
253 public void visitTypeVariable(final String name) {
254 if (type != TYPE_SIGNATURE || state != EMPTY) {
255 throw new IllegalStateException();
256 }
257 CheckMethodAdapter.checkIdentifier(name, "type variable");
258 state = SIMPLE_TYPE;
259 if (sv != null) {
260 sv.visitTypeVariable(name);
261 }
262 }
263
264 @Override
265 public SignatureVisitor visitArrayType() {
266 if (type != TYPE_SIGNATURE || state != EMPTY) {
267 throw new IllegalStateException();
268 }
269 state = SIMPLE_TYPE;
270 SignatureVisitor v = sv == null ? null : sv.visitArrayType();
271 return new CheckSignatureAdapter(TYPE_SIGNATURE, v);
272 }
273
274 @Override
275 public void visitClassType(final String name) {
276 if (type != TYPE_SIGNATURE || state != EMPTY) {
277 throw new IllegalStateException();
278 }
279 CheckMethodAdapter.checkInternalName(name, "class name");
280 state = CLASS_TYPE;
281 if (sv != null) {
282 sv.visitClassType(name);
283 }
284 }
285
286 @Override
287 public void visitInnerClassType(final String name) {
288 if (state != CLASS_TYPE) {
289 throw new IllegalStateException();
290 }
291 CheckMethodAdapter.checkIdentifier(name, "inner class name");
292 if (sv != null) {
293 sv.visitInnerClassType(name);
294 }
295 }
296
297 @Override
298 public void visitTypeArgument() {
299 if (state != CLASS_TYPE) {
300 throw new IllegalStateException();
301 }
302 if (sv != null) {
303 sv.visitTypeArgument();
304 }
305 }
306
307 @Override
308 public SignatureVisitor visitTypeArgument(final char wildcard) {
309 if (state != CLASS_TYPE) {
310 throw new IllegalStateException();
311 }
312 if ("+-=".indexOf(wildcard) == -1) {
313 throw new IllegalArgumentException();
314 }
315 SignatureVisitor v = sv == null ? null : sv.visitTypeArgument(wildcard);
316 return new CheckSignatureAdapter(TYPE_SIGNATURE, v);
317 }
318
319 @Override
320 public void visitEnd() {
321 if (state != CLASS_TYPE) {
322 throw new IllegalStateException();
323 }
324 state = END;
325 if (sv != null) {
326 sv.visitEnd();
327 }
328 }
41 /**
42 * Type to be used to check class signatures. See {@link #CheckSignatureAdapter(int,
43 * SignatureVisitor)}.
44 */
45 public static final int CLASS_SIGNATURE = 0;
46
47 /**
48 * Type to be used to check method signatures. See {@link #CheckSignatureAdapter(int,
49 * SignatureVisitor)}.
50 */
51 public static final int METHOD_SIGNATURE = 1;
52
53 /**
54 * Type to be used to check type signatures.See {@link #CheckSignatureAdapter(int,
55 * SignatureVisitor)}.
56 */
57 public static final int TYPE_SIGNATURE = 2;
58
59 /** The valid automaton states for a {@link #visitFormalTypeParameter} method call. */
60 private static final EnumSet<State> VISIT_FORMAL_TYPE_PARAMETER_STATES =
61 EnumSet.of(State.EMPTY, State.FORMAL, State.BOUND);
62
63 /** The valid automaton states for a {@link #visitClassBound} method call. */
64 private static final EnumSet<State> VISIT_CLASS_BOUND_STATES = EnumSet.of(State.FORMAL);
65
66 /** The valid automaton states for a {@link #visitInterfaceBound} method call. */
67 private static final EnumSet<State> VISIT_INTERFACE_BOUND_STATES =
68 EnumSet.of(State.FORMAL, State.BOUND);
69
70 /** The valid automaton states for a {@link #visitSuperclass} method call. */
71 private static final EnumSet<State> VISIT_SUPER_CLASS_STATES =
72 EnumSet.of(State.EMPTY, State.FORMAL, State.BOUND);
73
74 /** The valid automaton states for a {@link #visitInterface} method call. */
75 private static final EnumSet<State> VISIT_INTERFACE_STATES = EnumSet.of(State.SUPER);
76
77 /** The valid automaton states for a {@link #visitParameterType} method call. */
78 private static final EnumSet<State> VISIT_PARAMETER_TYPE_STATES =
79 EnumSet.of(State.EMPTY, State.FORMAL, State.BOUND, State.PARAM);
80
81 /** The valid automaton states for a {@link #visitReturnType} method call. */
82 private static final EnumSet<State> VISIT_RETURN_TYPE_STATES =
83 EnumSet.of(State.EMPTY, State.FORMAL, State.BOUND, State.PARAM);
84
85 /** The valid automaton states for a {@link #visitExceptionType} method call. */
86 private static final EnumSet<State> VISIT_EXCEPTION_TYPE_STATES = EnumSet.of(State.RETURN);
87
88 /** The possible states of the automaton used to check the order of method calls. */
89 private enum State {
90 EMPTY,
91 FORMAL,
92 BOUND,
93 SUPER,
94 PARAM,
95 RETURN,
96 SIMPLE_TYPE,
97 CLASS_TYPE,
98 END;
99 }
100
101 private static final String INVALID = "Invalid ";
102
103 /** The type of the visited signature. */
104 private final int type;
105
106 /** The current state of the automaton used to check the order of method calls. */
107 private State state;
108
109 /** Whether the visited signature can be 'V'. */
110 private boolean canBeVoid;
111
112 /** The visitor to which this adapter must delegate calls. May be <tt>null</tt>. */
113 private final SignatureVisitor signatureVisitor;
114
115 /**
116 * Constructs a new {@link CheckSignatureAdapter}. <i>Subclasses must not use this
117 * constructor</i>. Instead, they must use the {@link #CheckSignatureAdapter(int, int,
118 * SignatureVisitor)} version.
119 *
120 * @param type the type of signature to be checked. See {@link #CLASS_SIGNATURE}, {@link
121 * #METHOD_SIGNATURE} and {@link #TYPE_SIGNATURE}.
122 * @param signatureVisitor the visitor to which this adapter must delegate calls. May be
123 * <tt>null</tt>.
124 */
125 public CheckSignatureAdapter(final int type, final SignatureVisitor signatureVisitor) {
126 this(Opcodes.ASM6, type, signatureVisitor);
127 }
128
129 /**
130 * Constructs a new {@link CheckSignatureAdapter}.
131 *
132 * @param api the ASM API version implemented by this visitor. Must be one of {@link
133 * Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
134 * @param type the type of signature to be checked. See {@link #CLASS_SIGNATURE}, {@link
135 * #METHOD_SIGNATURE} and {@link #TYPE_SIGNATURE}.
136 * @param signatureVisitor the visitor to which this adapter must delegate calls. May be
137 * <tt>null</tt>.
138 */
139 protected CheckSignatureAdapter(
140 final int api, final int type, final SignatureVisitor signatureVisitor) {
141 super(api);
142 this.type = type;
143 this.state = State.EMPTY;
144 this.signatureVisitor = signatureVisitor;
145 }
146
147 // class and method signatures
148
149 @Override
150 public void visitFormalTypeParameter(final String name) {
151 if (type == TYPE_SIGNATURE || !VISIT_FORMAL_TYPE_PARAMETER_STATES.contains(state)) {
152 throw new IllegalStateException();
153 }
154 checkIdentifier(name, "formal type parameter");
155 state = State.FORMAL;
156 if (signatureVisitor != null) {
157 signatureVisitor.visitFormalTypeParameter(name);
158 }
159 }
160
161 @Override
162 public SignatureVisitor visitClassBound() {
163 if (type == TYPE_SIGNATURE || !VISIT_CLASS_BOUND_STATES.contains(state)) {
164 throw new IllegalStateException();
165 }
166 state = State.BOUND;
167 return new CheckSignatureAdapter(
168 TYPE_SIGNATURE, signatureVisitor == null ? null : signatureVisitor.visitClassBound());
169 }
170
171 @Override
172 public SignatureVisitor visitInterfaceBound() {
173 if (type == TYPE_SIGNATURE || !VISIT_INTERFACE_BOUND_STATES.contains(state)) {
174 throw new IllegalArgumentException();
175 }
176 return new CheckSignatureAdapter(
177 TYPE_SIGNATURE, signatureVisitor == null ? null : signatureVisitor.visitInterfaceBound());
178 }
179
180 // class signatures
181
182 @Override
183 public SignatureVisitor visitSuperclass() {
184 if (type != CLASS_SIGNATURE || !VISIT_SUPER_CLASS_STATES.contains(state)) {
185 throw new IllegalArgumentException();
186 }
187 state = State.SUPER;
188 return new CheckSignatureAdapter(
189 TYPE_SIGNATURE, signatureVisitor == null ? null : signatureVisitor.visitSuperclass());
190 }
191
192 @Override
193 public SignatureVisitor visitInterface() {
194 if (type != CLASS_SIGNATURE || !VISIT_INTERFACE_STATES.contains(state)) {
195 throw new IllegalStateException();
196 }
197 return new CheckSignatureAdapter(
198 TYPE_SIGNATURE, signatureVisitor == null ? null : signatureVisitor.visitInterface());
199 }
200
201 // method signatures
202
203 @Override
204 public SignatureVisitor visitParameterType() {
205 if (type != METHOD_SIGNATURE || !VISIT_PARAMETER_TYPE_STATES.contains(state)) {
206 throw new IllegalArgumentException();
207 }
208 state = State.PARAM;
209 return new CheckSignatureAdapter(
210 TYPE_SIGNATURE, signatureVisitor == null ? null : signatureVisitor.visitParameterType());
211 }
212
213 @Override
214 public SignatureVisitor visitReturnType() {
215 if (type != METHOD_SIGNATURE || !VISIT_RETURN_TYPE_STATES.contains(state)) {
216 throw new IllegalArgumentException();
217 }
218 state = State.RETURN;
219 CheckSignatureAdapter checkSignatureAdapter =
220 new CheckSignatureAdapter(
221 TYPE_SIGNATURE, signatureVisitor == null ? null : signatureVisitor.visitReturnType());
222 checkSignatureAdapter.canBeVoid = true;
223 return checkSignatureAdapter;
224 }
225
226 @Override
227 public SignatureVisitor visitExceptionType() {
228 if (type != METHOD_SIGNATURE || !VISIT_EXCEPTION_TYPE_STATES.contains(state)) {
229 throw new IllegalStateException();
230 }
231 return new CheckSignatureAdapter(
232 TYPE_SIGNATURE, signatureVisitor == null ? null : signatureVisitor.visitExceptionType());
233 }
234
235 // type signatures
236
237 @Override
238 public void visitBaseType(final char descriptor) {
239 if (type != TYPE_SIGNATURE || state != State.EMPTY) {
240 throw new IllegalStateException();
241 }
242 if (descriptor == 'V') {
243 if (!canBeVoid) {
244 throw new IllegalArgumentException();
245 }
246 } else {
247 if ("ZCBSIFJD".indexOf(descriptor) == -1) {
248 throw new IllegalArgumentException();
249 }
250 }
251 state = State.SIMPLE_TYPE;
252 if (signatureVisitor != null) {
253 signatureVisitor.visitBaseType(descriptor);
254 }
255 }
256
257 @Override
258 public void visitTypeVariable(final String name) {
259 if (type != TYPE_SIGNATURE || state != State.EMPTY) {
260 throw new IllegalStateException();
261 }
262 checkIdentifier(name, "type variable");
263 state = State.SIMPLE_TYPE;
264 if (signatureVisitor != null) {
265 signatureVisitor.visitTypeVariable(name);
266 }
267 }
268
269 @Override
270 public SignatureVisitor visitArrayType() {
271 if (type != TYPE_SIGNATURE || state != State.EMPTY) {
272 throw new IllegalStateException();
273 }
274 state = State.SIMPLE_TYPE;
275 return new CheckSignatureAdapter(
276 TYPE_SIGNATURE, signatureVisitor == null ? null : signatureVisitor.visitArrayType());
277 }
278
279 @Override
280 public void visitClassType(final String name) {
281 if (type != TYPE_SIGNATURE || state != State.EMPTY) {
282 throw new IllegalStateException();
283 }
284 checkClassName(name, "class name");
285 state = State.CLASS_TYPE;
286 if (signatureVisitor != null) {
287 signatureVisitor.visitClassType(name);
288 }
289 }
290
291 @Override
292 public void visitInnerClassType(final String name) {
293 if (state != State.CLASS_TYPE) {
294 throw new IllegalStateException();
295 }
296 checkIdentifier(name, "inner class name");
297 if (signatureVisitor != null) {
298 signatureVisitor.visitInnerClassType(name);
299 }
300 }
301
302 @Override
303 public void visitTypeArgument() {
304 if (state != State.CLASS_TYPE) {
305 throw new IllegalStateException();
306 }
307 if (signatureVisitor != null) {
308 signatureVisitor.visitTypeArgument();
309 }
310 }
311
312 @Override
313 public SignatureVisitor visitTypeArgument(final char wildcard) {
314 if (state != State.CLASS_TYPE) {
315 throw new IllegalStateException();
316 }
317 if ("+-=".indexOf(wildcard) == -1) {
318 throw new IllegalArgumentException();
319 }
320 return new CheckSignatureAdapter(
321 TYPE_SIGNATURE,
322 signatureVisitor == null ? null : signatureVisitor.visitTypeArgument(wildcard));
323 }
324
325 @Override
326 public void visitEnd() {
327 if (state != State.CLASS_TYPE) {
328 throw new IllegalStateException();
329 }
330 state = State.END;
331 if (signatureVisitor != null) {
332 signatureVisitor.visitEnd();
333 }
334 }
335
336 private void checkClassName(final String name, final String message) {
337 if (name == null || name.length() == 0) {
338 throw new IllegalArgumentException(INVALID + message + " (must not be null or empty)");
339 }
340 for (int i = 0; i < name.length(); ++i) {
341 if (".;[<>:".indexOf(name.charAt(i)) != -1) {
342 throw new IllegalArgumentException(
343 INVALID + message + " (must not contain . ; [ < > or :): " + name);
344 }
345 }
346 }
347
348 private void checkIdentifier(final String name, final String message) {
349 if (name == null || name.length() == 0) {
350 throw new IllegalArgumentException(INVALID + message + " (must not be null or empty)");
351 }
352 for (int i = 0; i < name.length(); ++i) {
353 if (".;[/<>:".indexOf(name.charAt(i)) != -1) {
354 throw new IllegalArgumentException(
355 INVALID + message + " (must not contain . ; [ / < > or :): " + name);
356 }
357 }
358 }
329359 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.util;
3028
29 import java.io.FileInputStream;
30 import java.io.IOException;
3131 import java.io.PrintWriter;
3232 import java.util.ArrayList;
3333 import java.util.List;
3434
3535 import org.eclipse.persistence.internal.libraries.asm.Attribute;
36 import org.eclipse.persistence.internal.libraries.asm.ClassReader;
3637 import org.eclipse.persistence.internal.libraries.asm.Handle;
3738 import org.eclipse.persistence.internal.libraries.asm.Label;
3839 import org.eclipse.persistence.internal.libraries.asm.Opcodes;
4041
4142 /**
4243 * An abstract converter from visit events to text.
43 *
44 *
4445 * @author Eric Bruneton
4546 */
4647 public abstract class Printer {
4748
48 /**
49 * The names of the Java Virtual Machine opcodes.
50 */
51 public static final String[] OPCODES;
52
53 /**
54 * The names of the for <code>operand</code> parameter values of the
55 * {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitIntInsn} method when
56 * <code>opcode</code> is <code>NEWARRAY</code>.
57 */
58 public static final String[] TYPES;
59
60 /**
61 * The names of the <code>tag</code> field values for
62 * {@link org.eclipse.persistence.internal.libraries.asm.Handle}.
63 */
64 public static final String[] HANDLE_TAG;
65
66 static {
67 String s = "NOP,ACONST_NULL,ICONST_M1,ICONST_0,ICONST_1,ICONST_2,"
68 + "ICONST_3,ICONST_4,ICONST_5,LCONST_0,LCONST_1,FCONST_0,"
69 + "FCONST_1,FCONST_2,DCONST_0,DCONST_1,BIPUSH,SIPUSH,LDC,,,"
70 + "ILOAD,LLOAD,FLOAD,DLOAD,ALOAD,,,,,,,,,,,,,,,,,,,,,IALOAD,"
71 + "LALOAD,FALOAD,DALOAD,AALOAD,BALOAD,CALOAD,SALOAD,ISTORE,"
72 + "LSTORE,FSTORE,DSTORE,ASTORE,,,,,,,,,,,,,,,,,,,,,IASTORE,"
73 + "LASTORE,FASTORE,DASTORE,AASTORE,BASTORE,CASTORE,SASTORE,POP,"
74 + "POP2,DUP,DUP_X1,DUP_X2,DUP2,DUP2_X1,DUP2_X2,SWAP,IADD,LADD,"
75 + "FADD,DADD,ISUB,LSUB,FSUB,DSUB,IMUL,LMUL,FMUL,DMUL,IDIV,LDIV,"
76 + "FDIV,DDIV,IREM,LREM,FREM,DREM,INEG,LNEG,FNEG,DNEG,ISHL,LSHL,"
77 + "ISHR,LSHR,IUSHR,LUSHR,IAND,LAND,IOR,LOR,IXOR,LXOR,IINC,I2L,"
78 + "I2F,I2D,L2I,L2F,L2D,F2I,F2L,F2D,D2I,D2L,D2F,I2B,I2C,I2S,LCMP,"
79 + "FCMPL,FCMPG,DCMPL,DCMPG,IFEQ,IFNE,IFLT,IFGE,IFGT,IFLE,"
80 + "IF_ICMPEQ,IF_ICMPNE,IF_ICMPLT,IF_ICMPGE,IF_ICMPGT,IF_ICMPLE,"
81 + "IF_ACMPEQ,IF_ACMPNE,GOTO,JSR,RET,TABLESWITCH,LOOKUPSWITCH,"
82 + "IRETURN,LRETURN,FRETURN,DRETURN,ARETURN,RETURN,GETSTATIC,"
83 + "PUTSTATIC,GETFIELD,PUTFIELD,INVOKEVIRTUAL,INVOKESPECIAL,"
84 + "INVOKESTATIC,INVOKEINTERFACE,INVOKEDYNAMIC,NEW,NEWARRAY,"
85 + "ANEWARRAY,ARRAYLENGTH,ATHROW,CHECKCAST,INSTANCEOF,"
86 + "MONITORENTER,MONITOREXIT,,MULTIANEWARRAY,IFNULL,IFNONNULL,";
87 OPCODES = new String[200];
88 int i = 0;
89 int j = 0;
90 int l;
91 while ((l = s.indexOf(',', j)) > 0) {
92 OPCODES[i++] = j + 1 == l ? null : s.substring(j, l);
93 j = l + 1;
49 /** The names of the Java Virtual Machine opcodes. */
50 public static final String[] OPCODES = {
51 "NOP", // 0 (0x0)
52 "ACONST_NULL", // 1 (0x1)
53 "ICONST_M1", // 2 (0x2)
54 "ICONST_0", // 3 (0x3)
55 "ICONST_1", // 4 (0x4)
56 "ICONST_2", // 5 (0x5)
57 "ICONST_3", // 6 (0x6)
58 "ICONST_4", // 7 (0x7)
59 "ICONST_5", // 8 (0x8)
60 "LCONST_0", // 9 (0x9)
61 "LCONST_1", // 10 (0xa)
62 "FCONST_0", // 11 (0xb)
63 "FCONST_1", // 12 (0xc)
64 "FCONST_2", // 13 (0xd)
65 "DCONST_0", // 14 (0xe)
66 "DCONST_1", // 15 (0xf)
67 "BIPUSH", // 16 (0x10)
68 "SIPUSH", // 17 (0x11)
69 "LDC", // 18 (0x12)
70 "LDC_W", // 19 (0x13)
71 "LDC2_W", // 20 (0x14)
72 "ILOAD", // 21 (0x15)
73 "LLOAD", // 22 (0x16)
74 "FLOAD", // 23 (0x17)
75 "DLOAD", // 24 (0x18)
76 "ALOAD", // 25 (0x19)
77 "ILOAD_0", // 26 (0x1a)
78 "ILOAD_1", // 27 (0x1b)
79 "ILOAD_2", // 28 (0x1c)
80 "ILOAD_3", // 29 (0x1d)
81 "LLOAD_0", // 30 (0x1e)
82 "LLOAD_1", // 31 (0x1f)
83 "LLOAD_2", // 32 (0x20)
84 "LLOAD_3", // 33 (0x21)
85 "FLOAD_0", // 34 (0x22)
86 "FLOAD_1", // 35 (0x23)
87 "FLOAD_2", // 36 (0x24)
88 "FLOAD_3", // 37 (0x25)
89 "DLOAD_0", // 38 (0x26)
90 "DLOAD_1", // 39 (0x27)
91 "DLOAD_2", // 40 (0x28)
92 "DLOAD_3", // 41 (0x29)
93 "ALOAD_0", // 42 (0x2a)
94 "ALOAD_1", // 43 (0x2b)
95 "ALOAD_2", // 44 (0x2c)
96 "ALOAD_3", // 45 (0x2d)
97 "IALOAD", // 46 (0x2e)
98 "LALOAD", // 47 (0x2f)
99 "FALOAD", // 48 (0x30)
100 "DALOAD", // 49 (0x31)
101 "AALOAD", // 50 (0x32)
102 "BALOAD", // 51 (0x33)
103 "CALOAD", // 52 (0x34)
104 "SALOAD", // 53 (0x35)
105 "ISTORE", // 54 (0x36)
106 "LSTORE", // 55 (0x37)
107 "FSTORE", // 56 (0x38)
108 "DSTORE", // 57 (0x39)
109 "ASTORE", // 58 (0x3a)
110 "ISTORE_0", // 59 (0x3b)
111 "ISTORE_1", // 60 (0x3c)
112 "ISTORE_2", // 61 (0x3d)
113 "ISTORE_3", // 62 (0x3e)
114 "LSTORE_0", // 63 (0x3f)
115 "LSTORE_1", // 64 (0x40)
116 "LSTORE_2", // 65 (0x41)
117 "LSTORE_3", // 66 (0x42)
118 "FSTORE_0", // 67 (0x43)
119 "FSTORE_1", // 68 (0x44)
120 "FSTORE_2", // 69 (0x45)
121 "FSTORE_3", // 70 (0x46)
122 "DSTORE_0", // 71 (0x47)
123 "DSTORE_1", // 72 (0x48)
124 "DSTORE_2", // 73 (0x49)
125 "DSTORE_3", // 74 (0x4a)
126 "ASTORE_0", // 75 (0x4b)
127 "ASTORE_1", // 76 (0x4c)
128 "ASTORE_2", // 77 (0x4d)
129 "ASTORE_3", // 78 (0x4e)
130 "IASTORE", // 79 (0x4f)
131 "LASTORE", // 80 (0x50)
132 "FASTORE", // 81 (0x51)
133 "DASTORE", // 82 (0x52)
134 "AASTORE", // 83 (0x53)
135 "BASTORE", // 84 (0x54)
136 "CASTORE", // 85 (0x55)
137 "SASTORE", // 86 (0x56)
138 "POP", // 87 (0x57)
139 "POP2", // 88 (0x58)
140 "DUP", // 89 (0x59)
141 "DUP_X1", // 90 (0x5a)
142 "DUP_X2", // 91 (0x5b)
143 "DUP2", // 92 (0x5c)
144 "DUP2_X1", // 93 (0x5d)
145 "DUP2_X2", // 94 (0x5e)
146 "SWAP", // 95 (0x5f)
147 "IADD", // 96 (0x60)
148 "LADD", // 97 (0x61)
149 "FADD", // 98 (0x62)
150 "DADD", // 99 (0x63)
151 "ISUB", // 100 (0x64)
152 "LSUB", // 101 (0x65)
153 "FSUB", // 102 (0x66)
154 "DSUB", // 103 (0x67)
155 "IMUL", // 104 (0x68)
156 "LMUL", // 105 (0x69)
157 "FMUL", // 106 (0x6a)
158 "DMUL", // 107 (0x6b)
159 "IDIV", // 108 (0x6c)
160 "LDIV", // 109 (0x6d)
161 "FDIV", // 110 (0x6e)
162 "DDIV", // 111 (0x6f)
163 "IREM", // 112 (0x70)
164 "LREM", // 113 (0x71)
165 "FREM", // 114 (0x72)
166 "DREM", // 115 (0x73)
167 "INEG", // 116 (0x74)
168 "LNEG", // 117 (0x75)
169 "FNEG", // 118 (0x76)
170 "DNEG", // 119 (0x77)
171 "ISHL", // 120 (0x78)
172 "LSHL", // 121 (0x79)
173 "ISHR", // 122 (0x7a)
174 "LSHR", // 123 (0x7b)
175 "IUSHR", // 124 (0x7c)
176 "LUSHR", // 125 (0x7d)
177 "IAND", // 126 (0x7e)
178 "LAND", // 127 (0x7f)
179 "IOR", // 128 (0x80)
180 "LOR", // 129 (0x81)
181 "IXOR", // 130 (0x82)
182 "LXOR", // 131 (0x83)
183 "IINC", // 132 (0x84)
184 "I2L", // 133 (0x85)
185 "I2F", // 134 (0x86)
186 "I2D", // 135 (0x87)
187 "L2I", // 136 (0x88)
188 "L2F", // 137 (0x89)
189 "L2D", // 138 (0x8a)
190 "F2I", // 139 (0x8b)
191 "F2L", // 140 (0x8c)
192 "F2D", // 141 (0x8d)
193 "D2I", // 142 (0x8e)
194 "D2L", // 143 (0x8f)
195 "D2F", // 144 (0x90)
196 "I2B", // 145 (0x91)
197 "I2C", // 146 (0x92)
198 "I2S", // 147 (0x93)
199 "LCMP", // 148 (0x94)
200 "FCMPL", // 149 (0x95)
201 "FCMPG", // 150 (0x96)
202 "DCMPL", // 151 (0x97)
203 "DCMPG", // 152 (0x98)
204 "IFEQ", // 153 (0x99)
205 "IFNE", // 154 (0x9a)
206 "IFLT", // 155 (0x9b)
207 "IFGE", // 156 (0x9c)
208 "IFGT", // 157 (0x9d)
209 "IFLE", // 158 (0x9e)
210 "IF_ICMPEQ", // 159 (0x9f)
211 "IF_ICMPNE", // 160 (0xa0)
212 "IF_ICMPLT", // 161 (0xa1)
213 "IF_ICMPGE", // 162 (0xa2)
214 "IF_ICMPGT", // 163 (0xa3)
215 "IF_ICMPLE", // 164 (0xa4)
216 "IF_ACMPEQ", // 165 (0xa5)
217 "IF_ACMPNE", // 166 (0xa6)
218 "GOTO", // 167 (0xa7)
219 "JSR", // 168 (0xa8)
220 "RET", // 169 (0xa9)
221 "TABLESWITCH", // 170 (0xaa)
222 "LOOKUPSWITCH", // 171 (0xab)
223 "IRETURN", // 172 (0xac)
224 "LRETURN", // 173 (0xad)
225 "FRETURN", // 174 (0xae)
226 "DRETURN", // 175 (0xaf)
227 "ARETURN", // 176 (0xb0)
228 "RETURN", // 177 (0xb1)
229 "GETSTATIC", // 178 (0xb2)
230 "PUTSTATIC", // 179 (0xb3)
231 "GETFIELD", // 180 (0xb4)
232 "PUTFIELD", // 181 (0xb5)
233 "INVOKEVIRTUAL", // 182 (0xb6)
234 "INVOKESPECIAL", // 183 (0xb7)
235 "INVOKESTATIC", // 184 (0xb8)
236 "INVOKEINTERFACE", // 185 (0xb9)
237 "INVOKEDYNAMIC", // 186 (0xba)
238 "NEW", // 187 (0xbb)
239 "NEWARRAY", // 188 (0xbc)
240 "ANEWARRAY", // 189 (0xbd)
241 "ARRAYLENGTH", // 190 (0xbe)
242 "ATHROW", // 191 (0xbf)
243 "CHECKCAST", // 192 (0xc0)
244 "INSTANCEOF", // 193 (0xc1)
245 "MONITORENTER", // 194 (0xc2)
246 "MONITOREXIT", // 195 (0xc3)
247 "WIDE", // 196 (0xc4)
248 "MULTIANEWARRAY", // 197 (0xc5)
249 "IFNULL", // 198 (0xc6)
250 "IFNONNULL" // 199 (0xc7)
251 };
252
253 /**
254 * The names of the {@code operand} values of the {@link
255 * org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitIntInsn} method when {@code opcode} is {@code NEWARRAY}.
256 */
257 public static final String[] TYPES = {
258 "",
259 "",
260 "",
261 "",
262 "T_BOOLEAN",
263 "T_CHAR",
264 "T_FLOAT",
265 "T_DOUBLE",
266 "T_BYTE",
267 "T_SHORT",
268 "T_INT",
269 "T_LONG"
270 };
271
272 /** The names of the {@code tag} field values for {@link org.eclipse.persistence.internal.libraries.asm.Handle}. */
273 public static final String[] HANDLE_TAG = {
274 "",
275 "H_GETFIELD",
276 "H_GETSTATIC",
277 "H_PUTFIELD",
278 "H_PUTSTATIC",
279 "H_INVOKEVIRTUAL",
280 "H_INVOKESTATIC",
281 "H_INVOKESPECIAL",
282 "H_NEWINVOKESPECIAL",
283 "H_INVOKEINTERFACE"
284 };
285
286 /** Message of the UnsupportedOperationException thrown by methods which must be overridden. */
287 private static final String UNSUPPORTED_OPERATION = "Must be overridden";
288
289 /**
290 * The ASM API version implemented by this class. The value of this field must be one of {@link
291 * Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
292 */
293 protected final int api;
294
295 /**
296 * A buffer that can be used to create strings.
297 *
298 * @deprecated
299 */
300 @Deprecated protected final StringBuffer buf;
301
302 /** The builder used to build strings in the various visit methods. */
303 protected final StringBuilder stringBuilder;
304
305 /**
306 * The text to be printed. Since the code of methods is not necessarily visited in sequential
307 * order, one method after the other, but can be interlaced (some instructions from method one,
308 * then some instructions from method two, then some instructions from method one again...), it is
309 * not possible to print the visited instructions directly to a sequential stream. A class is
310 * therefore printed in a two steps process: a string tree is constructed during the visit, and
311 * printed to a sequential stream at the end of the visit. This string tree is stored in this
312 * field, as a string list that can contain other string lists, which can themselves contain other
313 * string lists, and so on.
314 */
315 public final List<Object> text;
316
317 // -----------------------------------------------------------------------------------------------
318 // Constructor
319 // -----------------------------------------------------------------------------------------------
320
321 /**
322 * Constructs a new {@link Printer}.
323 *
324 * @param api the ASM API version implemented by this printer. Must be one of {@link
325 * Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
326 */
327 protected Printer(final int api) {
328 this.api = api;
329 this.buf = null;
330 this.stringBuilder = new StringBuilder();
331 this.text = new ArrayList<Object>();
332 }
333
334 // -----------------------------------------------------------------------------------------------
335 // Classes
336 // -----------------------------------------------------------------------------------------------
337
338 /**
339 * Class header. See {@link org.eclipse.persistence.internal.libraries.asm.ClassVisitor#visit}.
340 *
341 * @param version the class version. The minor version is stored in the 16 most significant bits,
342 * and the major version in the 16 least significant bits.
343 * @param access the class's access flags (see {@link Opcodes}). This parameter also indicates if
344 * the class is deprecated.
345 * @param name the internal name of the class (see {@link
346 * org.eclipse.persistence.internal.libraries.asm.Type#getInternalName()}).
347 * @param signature the signature of this class. May be <tt>null</tt> if the class is not a
348 * generic one, and does not extend or implement generic classes or interfaces.
349 * @param superName the internal of name of the super class (see {@link
350 * org.eclipse.persistence.internal.libraries.asm.Type#getInternalName()}). For interfaces, the super class is {@link
351 * Object}. May be <tt>null</tt>, but only for the {@link Object} class.
352 * @param interfaces the internal names of the class's interfaces (see {@link
353 * org.eclipse.persistence.internal.libraries.asm.Type#getInternalName()}). May be <tt>null</tt>.
354 */
355 public abstract void visit(
356 int version,
357 int access,
358 String name,
359 String signature,
360 String superName,
361 String[] interfaces);
362
363 /**
364 * Class source. See {@link org.eclipse.persistence.internal.libraries.asm.ClassVisitor#visitSource}.
365 *
366 * @param source the name of the source file from which the class was compiled. May be
367 * <tt>null</tt>.
368 * @param debug additional debug information to compute the correspondence between source and
369 * compiled elements of the class. May be <tt>null</tt>.
370 */
371 public abstract void visitSource(String source, String debug);
372
373 /**
374 * Module. See {@link org.eclipse.persistence.internal.libraries.asm.ClassVisitor#visitModule}.
375 *
376 * @param name the fully qualified name (using dots) of the module.
377 * @param access the module access flags, among {@code ACC_OPEN}, {@code ACC_SYNTHETIC} and {@code
378 * ACC_MANDATED}.
379 * @param version the module version, or <tt>null</tt>.
380 * @return the printer.
381 */
382 public Printer visitModule(final String name, final int access, final String version) {
383 throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
384 }
385
386 /**
387 * Class outer class. See {@link org.eclipse.persistence.internal.libraries.asm.ClassVisitor#visitOuterClass}.
388 *
389 * @param owner internal name of the enclosing class of the class.
390 * @param name the name of the method that contains the class, or <tt>null</tt> if the class is
391 * not enclosed in a method of its enclosing class.
392 * @param descriptor the descriptor of the method that contains the class, or <tt>null</tt> if the
393 * class is not enclosed in a method of its enclosing class.
394 */
395 public abstract void visitOuterClass(String owner, String name, String descriptor);
396
397 /**
398 * Class annotation. See {@link org.eclipse.persistence.internal.libraries.asm.ClassVisitor#visitAnnotation}.
399 *
400 * @param descriptor the class descriptor of the annotation class.
401 * @param visible <tt>true</tt> if the annotation is visible at runtime.
402 * @return the printer.
403 */
404 public abstract Printer visitClassAnnotation(String descriptor, boolean visible);
405
406 /**
407 * Class type annotation. See {@link org.eclipse.persistence.internal.libraries.asm.ClassVisitor#visitTypeAnnotation}.
408 *
409 * @param typeRef a reference to the annotated type. The sort of this type reference must be
410 * {@link org.eclipse.persistence.internal.libraries.asm.TypeReference#CLASS_TYPE_PARAMETER}, {@link
411 * org.eclipse.persistence.internal.libraries.asm.TypeReference#CLASS_TYPE_PARAMETER_BOUND} or {@link
412 * org.eclipse.persistence.internal.libraries.asm.TypeReference#CLASS_EXTENDS}. See {@link
413 * org.eclipse.persistence.internal.libraries.asm.TypeReference}.
414 * @param typePath the path to the annotated type argument, wildcard bound, array element type, or
415 * static inner type within 'typeRef'. May be <tt>null</tt> if the annotation targets
416 * 'typeRef' as a whole.
417 * @param descriptor the class descriptor of the annotation class.
418 * @param visible <tt>true</tt> if the annotation is visible at runtime.
419 * @return the printer.
420 */
421 public Printer visitClassTypeAnnotation(
422 final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
423 throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
424 }
425
426 /**
427 * Class attribute. See {@link org.eclipse.persistence.internal.libraries.asm.ClassVisitor#visitAttribute}.
428 *
429 * @param attribute an attribute.
430 */
431 public abstract void visitClassAttribute(Attribute attribute);
432
433 /**
434 * Class inner name. See {@link org.eclipse.persistence.internal.libraries.asm.ClassVisitor#visitInnerClass}.
435 *
436 * @param name the internal name of an inner class (see {@link
437 * org.eclipse.persistence.internal.libraries.asm.Type#getInternalName()}).
438 * @param outerName the internal name of the class to which the inner class belongs (see {@link
439 * org.eclipse.persistence.internal.libraries.asm.Type#getInternalName()}). May be <tt>null</tt> for not member classes.
440 * @param innerName the (simple) name of the inner class inside its enclosing class. May be
441 * <tt>null</tt> for anonymous inner classes.
442 * @param access the access flags of the inner class as originally declared in the enclosing
443 * class.
444 */
445 public abstract void visitInnerClass(String name, String outerName, String innerName, int access);
446
447 /**
448 * Class field. See {@link org.eclipse.persistence.internal.libraries.asm.ClassVisitor#visitField}.
449 *
450 * @param access the field's access flags (see {@link Opcodes}). This parameter also indicates if
451 * the field is synthetic and/or deprecated.
452 * @param name the field's name.
453 * @param descriptor the field's descriptor (see {@link org.eclipse.persistence.internal.libraries.asm.Type}).
454 * @param signature the field's signature. May be <tt>null</tt> if the field's type does not use
455 * generic types.
456 * @param value the field's initial value. This parameter, which may be <tt>null</tt> if the field
457 * does not have an initial value, must be an {@link Integer}, a {@link Float}, a {@link
458 * Long}, a {@link Double} or a {@link String} (for <tt>int</tt>, <tt>float</tt>,
459 * <tt>long</tt> or <tt>String</tt> fields respectively). <i>This parameter is only used for
460 * static fields</i>. Its value is ignored for non static fields, which must be initialized
461 * through bytecode instructions in constructors or methods.
462 * @return the printer.
463 */
464 public abstract Printer visitField(
465 int access, String name, String descriptor, String signature, Object value);
466
467 /**
468 * Class method. See {@link org.eclipse.persistence.internal.libraries.asm.ClassVisitor#visitMethod}.
469 *
470 * @param access the method's access flags (see {@link Opcodes}). This parameter also indicates if
471 * the method is synthetic and/or deprecated.
472 * @param name the method's name.
473 * @param descriptor the method's descriptor (see {@link org.eclipse.persistence.internal.libraries.asm.Type}).
474 * @param signature the method's signature. May be <tt>null</tt> if the method parameters, return
475 * type and exceptions do not use generic types.
476 * @param exceptions the internal names of the method's exception classes (see {@link
477 * org.eclipse.persistence.internal.libraries.asm.Type#getInternalName()}). May be <tt>null</tt>.
478 * @return the printer.
479 */
480 public abstract Printer visitMethod(
481 int access, String name, String descriptor, String signature, String[] exceptions);
482
483 /** Class end. See {@link org.eclipse.persistence.internal.libraries.asm.ClassVisitor#visitEnd}. */
484 public abstract void visitClassEnd();
485
486 // -----------------------------------------------------------------------------------------------
487 // Modules
488 // -----------------------------------------------------------------------------------------------
489
490 /**
491 * Module main class. See {@link org.eclipse.persistence.internal.libraries.asm.ModuleVisitor#visitMainClass}.
492 *
493 * @param mainClass the internal name of the main class of the current module.
494 */
495 public void visitMainClass(final String mainClass) {
496 throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
497 }
498
499 /**
500 * Module package. See {@link org.eclipse.persistence.internal.libraries.asm.ModuleVisitor#visitPackage}.
501 *
502 * @param packaze the internal name of a package.
503 */
504 public void visitPackage(final String packaze) {
505 throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
506 }
507
508 /**
509 * Module require. See {@link org.eclipse.persistence.internal.libraries.asm.ModuleVisitor#visitRequire}.
510 *
511 * @param module the fully qualified name (using dots) of the dependence.
512 * @param access the access flag of the dependence among {@code ACC_TRANSITIVE}, {@code
513 * ACC_STATIC_PHASE}, {@code ACC_SYNTHETIC} and {@code ACC_MANDATED}.
514 * @param version the module version at compile time, or <tt>null</tt>.
515 */
516 public void visitRequire(final String module, final int access, final String version) {
517 throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
518 }
519
520 /**
521 * Module export. See {@link org.eclipse.persistence.internal.libraries.asm.ModuleVisitor#visitExport}.
522 *
523 * @param packaze the internal name of the exported package.
524 * @param access the access flag of the exported package, valid values are among {@code
525 * ACC_SYNTHETIC} and {@code ACC_MANDATED}.
526 * @param modules the fully qualified names (using dots) of the modules that can access the public
527 * classes of the exported package, or <tt>null</tt>.
528 */
529 public void visitExport(final String packaze, final int access, final String... modules) {
530 throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
531 }
532
533 /**
534 * Module open. See {@link org.eclipse.persistence.internal.libraries.asm.ModuleVisitor#visitOpen}.
535 *
536 * @param packaze the internal name of the opened package.
537 * @param access the access flag of the opened package, valid values are among {@code
538 * ACC_SYNTHETIC} and {@code ACC_MANDATED}.
539 * @param modules the fully qualified names (using dots) of the modules that can use deep
540 * reflection to the classes of the open package, or <tt>null</tt>.
541 */
542 public void visitOpen(final String packaze, final int access, final String... modules) {
543 throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
544 }
545
546 /**
547 * Module use. See {@link org.eclipse.persistence.internal.libraries.asm.ModuleVisitor#visitUse}.
548 *
549 * @param service the internal name of the service.
550 */
551 public void visitUse(final String service) {
552 throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
553 }
554
555 /**
556 * Module provide. See {@link org.eclipse.persistence.internal.libraries.asm.ModuleVisitor#visitProvide}.
557 *
558 * @param service the internal name of the service.
559 * @param providers the internal names of the implementations of the service (there is at least
560 * one provider).
561 */
562 public void visitProvide(final String service, final String... providers) {
563 throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
564 }
565
566 /** Module end. See {@link org.eclipse.persistence.internal.libraries.asm.ModuleVisitor#visitEnd}. */
567 public void visitModuleEnd() {
568 throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
569 }
570
571 // -----------------------------------------------------------------------------------------------
572 // Annotations
573 // -----------------------------------------------------------------------------------------------
574
575 /**
576 * Annotation value. See {@link org.eclipse.persistence.internal.libraries.asm.AnnotationVisitor#visit}.
577 *
578 * @param name the value name.
579 * @param value the actual value, whose type must be {@link Byte}, {@link Boolean}, {@link
580 * Character}, {@link Short}, {@link Integer} , {@link Long}, {@link Float}, {@link Double},
581 * {@link String} or {@link org.eclipse.persistence.internal.libraries.asm.Type} of {@link org.eclipse.persistence.internal.libraries.asm.Type#OBJECT}
582 * or {@link org.eclipse.persistence.internal.libraries.asm.Type#ARRAY} sort. This value can also be an array of byte,
583 * boolean, short, char, int, long, float or double values (this is equivalent to using {@link
584 * #visitArray} and visiting each array element in turn, but is more convenient).
585 */
586 public abstract void visit(String name, Object value);
587
588 /**
589 * Annotation enum value. See {@link org.eclipse.persistence.internal.libraries.asm.AnnotationVisitor#visitEnum}.
590 *
591 * @param name the value name.
592 * @param descriptor the class descriptor of the enumeration class.
593 * @param value the actual enumeration value.
594 */
595 public abstract void visitEnum(String name, String descriptor, String value);
596
597 /**
598 * Nested annotation value. See {@link org.eclipse.persistence.internal.libraries.asm.AnnotationVisitor#visitAnnotation}.
599 *
600 * @param name the value name.
601 * @param descriptor the class descriptor of the nested annotation class.
602 * @return the printer.
603 */
604 public abstract Printer visitAnnotation(String name, String descriptor);
605
606 /**
607 * Annotation array value. See {@link org.eclipse.persistence.internal.libraries.asm.AnnotationVisitor#visitArray}.
608 *
609 * @param name the value name.
610 * @return the printer.
611 */
612 public abstract Printer visitArray(String name);
613
614 /** Annotation end. See {@link org.eclipse.persistence.internal.libraries.asm.AnnotationVisitor#visitEnd}. */
615 public abstract void visitAnnotationEnd();
616
617 // -----------------------------------------------------------------------------------------------
618 // Fields
619 // -----------------------------------------------------------------------------------------------
620
621 /**
622 * Field annotation. See {@link org.eclipse.persistence.internal.libraries.asm.FieldVisitor#visitAnnotation}.
623 *
624 * @param descriptor the class descriptor of the annotation class.
625 * @param visible <tt>true</tt> if the annotation is visible at runtime.
626 * @return the printer.
627 */
628 public abstract Printer visitFieldAnnotation(String descriptor, boolean visible);
629
630 /**
631 * Field type annotation. See {@link org.eclipse.persistence.internal.libraries.asm.FieldVisitor#visitTypeAnnotation}.
632 *
633 * @param typeRef a reference to the annotated type. The sort of this type reference must be
634 * {@link org.eclipse.persistence.internal.libraries.asm.TypeReference#FIELD}. See {@link org.eclipse.persistence.internal.libraries.asm.TypeReference}.
635 * @param typePath the path to the annotated type argument, wildcard bound, array element type, or
636 * static inner type within 'typeRef'. May be <tt>null</tt> if the annotation targets
637 * 'typeRef' as a whole.
638 * @param descriptor the class descriptor of the annotation class.
639 * @param visible <tt>true</tt> if the annotation is visible at runtime.
640 * @return the printer.
641 */
642 public Printer visitFieldTypeAnnotation(
643 final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
644 throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
645 }
646
647 /**
648 * Field attribute. See {@link org.eclipse.persistence.internal.libraries.asm.FieldVisitor#visitAttribute}.
649 *
650 * @param attribute an attribute.
651 */
652 public abstract void visitFieldAttribute(Attribute attribute);
653
654 /** Field end. See {@link org.eclipse.persistence.internal.libraries.asm.FieldVisitor#visitEnd}. */
655 public abstract void visitFieldEnd();
656
657 // -----------------------------------------------------------------------------------------------
658 // Methods
659 // -----------------------------------------------------------------------------------------------
660
661 /**
662 * Method parameter. See {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitParameter(String, int)}.
663 *
664 * @param name parameter name or null if none is provided.
665 * @param access the parameter's access flags, only <tt>ACC_FINAL</tt>, <tt>ACC_SYNTHETIC</tt>
666 * or/and <tt>ACC_MANDATED</tt> are allowed (see {@link Opcodes}).
667 */
668 public void visitParameter(final String name, final int access) {
669 throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
670 }
671
672 /**
673 * Method default annotation. See {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitAnnotationDefault}.
674 *
675 * @return the printer.
676 */
677 public abstract Printer visitAnnotationDefault();
678
679 /**
680 * Method annotation. See {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitAnnotation}.
681 *
682 * @param descriptor the class descriptor of the annotation class.
683 * @param visible <tt>true</tt> if the annotation is visible at runtime.
684 * @return the printer.
685 */
686 public abstract Printer visitMethodAnnotation(String descriptor, boolean visible);
687
688 /**
689 * Method type annotation. See {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitTypeAnnotation}.
690 *
691 * @param typeRef a reference to the annotated type. The sort of this type reference must be
692 * {@link org.eclipse.persistence.internal.libraries.asm.TypeReference#METHOD_TYPE_PARAMETER}, {@link
693 * org.eclipse.persistence.internal.libraries.asm.TypeReference#METHOD_TYPE_PARAMETER_BOUND}, {@link
694 * org.eclipse.persistence.internal.libraries.asm.TypeReference#METHOD_RETURN}, {@link
695 * org.eclipse.persistence.internal.libraries.asm.TypeReference#METHOD_RECEIVER}, {@link
696 * org.eclipse.persistence.internal.libraries.asm.TypeReference#METHOD_FORMAL_PARAMETER} or {@link
697 * org.eclipse.persistence.internal.libraries.asm.TypeReference#THROWS}. See {@link org.eclipse.persistence.internal.libraries.asm.TypeReference}.
698 * @param typePath the path to the annotated type argument, wildcard bound, array element type, or
699 * static inner type within 'typeRef'. May be <tt>null</tt> if the annotation targets
700 * 'typeRef' as a whole.
701 * @param descriptor the class descriptor of the annotation class.
702 * @param visible <tt>true</tt> if the annotation is visible at runtime.
703 * @return the printer.
704 */
705 public Printer visitMethodTypeAnnotation(
706 final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
707 throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
708 }
709
710 /**
711 * Number of method parameters that can have annotations. See {@link
712 * org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitAnnotableParameterCount}.
713 *
714 * @param parameterCount the number of method parameters than can have annotations. This number
715 * must be less or equal than the number of parameter types in the method descriptor. It can
716 * be strictly less when a method has synthetic parameters and when these parameters are
717 * ignored when computing parameter indices for the purpose of parameter annotations (see
718 * https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.18).
719 * @param visible <tt>true</tt> to define the number of method parameters that can have
720 * annotations visible at runtime, <tt>false</tt> to define the number of method parameters
721 * that can have annotations invisible at runtime.
722 * @return the printer.
723 */
724 public Printer visitAnnotableParameterCount(final int parameterCount, final boolean visible) {
725 throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
726 }
727
728 /**
729 * Method parameter annotation. See {@link
730 * org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitParameterAnnotation}.
731 *
732 * @param parameter the parameter index. This index must be strictly smaller than the number of
733 * parameters in the method descriptor, and strictly smaller than the parameter count
734 * specified in {@link #visitAnnotableParameterCount}. Important note: <i>a parameter index i
735 * is not required to correspond to the i'th parameter descriptor in the method
736 * descriptor</i>, in particular in case of synthetic parameters (see
737 * https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.18).
738 * @param descriptor the class descriptor of the annotation class.
739 * @param visible <tt>true</tt> if the annotation is visible at runtime.
740 * @return the printer.
741 */
742 public abstract Printer visitParameterAnnotation(
743 int parameter, String descriptor, boolean visible);
744
745 /**
746 * Method attribute. See {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitAttribute}.
747 *
748 * @param attribute an attribute.
749 */
750 public abstract void visitMethodAttribute(Attribute attribute);
751
752 /** Method start. See {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitCode}. */
753 public abstract void visitCode();
754
755 /**
756 * Method stack frame. See {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitFrame}.
757 *
758 * @param type the type of this stack map frame. Must be {@link Opcodes#F_NEW} for expanded
759 * frames, or {@link Opcodes#F_FULL}, {@link Opcodes#F_APPEND}, {@link Opcodes#F_CHOP}, {@link
760 * Opcodes#F_SAME} or {@link Opcodes#F_APPEND}, {@link Opcodes#F_SAME1} for compressed frames.
761 * @param nLocal the number of local variables in the visited frame.
762 * @param local the local variable types in this frame. This array must not be modified. Primitive
763 * types are represented by {@link Opcodes#TOP}, {@link Opcodes#INTEGER}, {@link
764 * Opcodes#FLOAT}, {@link Opcodes#LONG}, {@link Opcodes#DOUBLE}, {@link Opcodes#NULL} or
765 * {@link Opcodes#UNINITIALIZED_THIS} (long and double are represented by a single element).
766 * Reference types are represented by String objects (representing internal names), and
767 * uninitialized types by Label objects (this label designates the NEW instruction that
768 * created this uninitialized value).
769 * @param nStack the number of operand stack elements in the visited frame.
770 * @param stack the operand stack types in this frame. This array must not be modified. Its
771 * content has the same format as the "local" array.
772 */
773 public abstract void visitFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack);
774
775 /**
776 * Method instruction. See {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitInsn}
777 *
778 * @param opcode the opcode of the instruction to be visited. This opcode is either NOP,
779 * ACONST_NULL, ICONST_M1, ICONST_0, ICONST_1, ICONST_2, ICONST_3, ICONST_4, ICONST_5,
780 * LCONST_0, LCONST_1, FCONST_0, FCONST_1, FCONST_2, DCONST_0, DCONST_1, IALOAD, LALOAD,
781 * FALOAD, DALOAD, AALOAD, BALOAD, CALOAD, SALOAD, IASTORE, LASTORE, FASTORE, DASTORE,
782 * AASTORE, BASTORE, CASTORE, SASTORE, POP, POP2, DUP, DUP_X1, DUP_X2, DUP2, DUP2_X1, DUP2_X2,
783 * SWAP, IADD, LADD, FADD, DADD, ISUB, LSUB, FSUB, DSUB, IMUL, LMUL, FMUL, DMUL, IDIV, LDIV,
784 * FDIV, DDIV, IREM, LREM, FREM, DREM, INEG, LNEG, FNEG, DNEG, ISHL, LSHL, ISHR, LSHR, IUSHR,
785 * LUSHR, IAND, LAND, IOR, LOR, IXOR, LXOR, I2L, I2F, I2D, L2I, L2F, L2D, F2I, F2L, F2D, D2I,
786 * D2L, D2F, I2B, I2C, I2S, LCMP, FCMPL, FCMPG, DCMPL, DCMPG, IRETURN, LRETURN, FRETURN,
787 * DRETURN, ARETURN, RETURN, ARRAYLENGTH, ATHROW, MONITORENTER, or MONITOREXIT.
788 */
789 public abstract void visitInsn(int opcode);
790
791 /**
792 * Method instruction. See {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitIntInsn}.
793 *
794 * @param opcode the opcode of the instruction to be visited. This opcode is either BIPUSH, SIPUSH
795 * or NEWARRAY.
796 * @param operand the operand of the instruction to be visited.<br>
797 * When opcode is BIPUSH, operand value should be between Byte.MIN_VALUE and Byte.MAX_VALUE.
798 * <br>
799 * When opcode is SIPUSH, operand value should be between Short.MIN_VALUE and Short.MAX_VALUE.
800 * <br>
801 * When opcode is NEWARRAY, operand value should be one of {@link Opcodes#T_BOOLEAN}, {@link
802 * Opcodes#T_CHAR}, {@link Opcodes#T_FLOAT}, {@link Opcodes#T_DOUBLE}, {@link Opcodes#T_BYTE},
803 * {@link Opcodes#T_SHORT}, {@link Opcodes#T_INT} or {@link Opcodes#T_LONG}.
804 */
805 public abstract void visitIntInsn(int opcode, int operand);
806
807 /**
808 * Method instruction. See {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitVarInsn}.
809 *
810 * @param opcode the opcode of the local variable instruction to be visited. This opcode is either
811 * ILOAD, LLOAD, FLOAD, DLOAD, ALOAD, ISTORE, LSTORE, FSTORE, DSTORE, ASTORE or RET.
812 * @param var the operand of the instruction to be visited. This operand is the index of a local
813 * variable.
814 */
815 public abstract void visitVarInsn(int opcode, int var);
816
817 /**
818 * Method instruction. See {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitTypeInsn}.
819 *
820 * @param opcode the opcode of the type instruction to be visited. This opcode is either NEW,
821 * ANEWARRAY, CHECKCAST or INSTANCEOF.
822 * @param type the operand of the instruction to be visited. This operand must be the internal
823 * name of an object or array class (see {@link org.eclipse.persistence.internal.libraries.asm.Type#getInternalName()}).
824 */
825 public abstract void visitTypeInsn(int opcode, String type);
826
827 /**
828 * Method instruction. See {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitFieldInsn}.
829 *
830 * @param opcode the opcode of the type instruction to be visited. This opcode is either
831 * GETSTATIC, PUTSTATIC, GETFIELD or PUTFIELD.
832 * @param owner the internal name of the field's owner class (see {@link
833 * org.eclipse.persistence.internal.libraries.asm.Type#getInternalName()}).
834 * @param name the field's name.
835 * @param descriptor the field's descriptor (see {@link org.eclipse.persistence.internal.libraries.asm.Type}).
836 */
837 public abstract void visitFieldInsn(int opcode, String owner, String name, String descriptor);
838
839 /**
840 * Method instruction. See {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitMethodInsn}.
841 *
842 * @param opcode the opcode of the type instruction to be visited. This opcode is either
843 * INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or INVOKEINTERFACE.
844 * @param owner the internal name of the method's owner class (see {@link
845 * org.eclipse.persistence.internal.libraries.asm.Type#getInternalName()}).
846 * @param name the method's name.
847 * @param descriptor the method's descriptor (see {@link org.eclipse.persistence.internal.libraries.asm.Type}).
848 * @deprecated
849 */
850 @Deprecated
851 public void visitMethodInsn(
852 final int opcode, final String owner, final String name, final String descriptor) {
853 if (api >= Opcodes.ASM5) {
854 boolean isInterface = opcode == Opcodes.INVOKEINTERFACE;
855 visitMethodInsn(opcode, owner, name, descriptor, isInterface);
856 return;
857 }
858 throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
859 }
860
861 /**
862 * Method instruction. See {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitMethodInsn}.
863 *
864 * @param opcode the opcode of the type instruction to be visited. This opcode is either
865 * INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or INVOKEINTERFACE.
866 * @param owner the internal name of the method's owner class (see {@link
867 * org.eclipse.persistence.internal.libraries.asm.Type#getInternalName()}).
868 * @param name the method's name.
869 * @param descriptor the method's descriptor (see {@link org.eclipse.persistence.internal.libraries.asm.Type}).
870 * @param isInterface if the method's owner class is an interface.
871 */
872 public void visitMethodInsn(
873 final int opcode,
874 final String owner,
875 final String name,
876 final String descriptor,
877 final boolean isInterface) {
878 if (api < Opcodes.ASM5) {
879 if (isInterface != (opcode == Opcodes.INVOKEINTERFACE)) {
880 throw new IllegalArgumentException("INVOKESPECIAL/STATIC on interfaces require ASM 5");
881 }
882 visitMethodInsn(opcode, owner, name, descriptor);
883 return;
884 }
885 throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
886 }
887
888 /**
889 * Method instruction. See {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitInvokeDynamicInsn}.
890 *
891 * @param name the method's name.
892 * @param descriptor the method's descriptor (see {@link org.eclipse.persistence.internal.libraries.asm.Type}).
893 * @param bootstrapMethodHandle the bootstrap method.
894 * @param bootstrapMethodArguments the bootstrap method constant arguments. Each argument must be
895 * an {@link Integer}, {@link Float}, {@link Long}, {@link Double}, {@link String}, {@link
896 * org.eclipse.persistence.internal.libraries.asm.Type} or {@link Handle} value. This method is allowed to modify the
897 * content of the array so a caller should expect that this array may change.
898 */
899 public abstract void visitInvokeDynamicInsn(
900 String name,
901 String descriptor,
902 Handle bootstrapMethodHandle,
903 Object... bootstrapMethodArguments);
904
905 /**
906 * Method jump instruction. See {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitJumpInsn}.
907 *
908 * @param opcode the opcode of the type instruction to be visited. This opcode is either IFEQ,
909 * IFNE, IFLT, IFGE, IFGT, IFLE, IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT,
910 * IF_ICMPLE, IF_ACMPEQ, IF_ACMPNE, GOTO, JSR, IFNULL or IFNONNULL.
911 * @param label the operand of the instruction to be visited. This operand is a label that
912 * designates the instruction to which the jump instruction may jump.
913 */
914 public abstract void visitJumpInsn(int opcode, Label label);
915
916 /**
917 * Method label. See {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitLabel}.
918 *
919 * @param label a {@link Label} object.
920 */
921 public abstract void visitLabel(Label label);
922
923 /**
924 * Method instruction. See {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitLdcInsn}.
925 *
926 * @param value the constant to be loaded on the stack. This parameter must be a non null {@link
927 * Integer}, a {@link Float}, a {@link Long}, a {@link Double}, a {@link String}, a {@link
928 * org.eclipse.persistence.internal.libraries.asm.Type} of OBJECT or ARRAY sort for <tt>.class</tt> constants, for classes
929 * whose version is 49.0, a {@link org.eclipse.persistence.internal.libraries.asm.Type} of METHOD sort or a {@link Handle}
930 * for MethodType and MethodHandle constants, for classes whose version is 51.0.
931 */
932 public abstract void visitLdcInsn(Object value);
933
934 /**
935 * Method instruction. See {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitIincInsn}.
936 *
937 * @param var index of the local variable to be incremented.
938 * @param increment amount to increment the local variable by.
939 */
940 public abstract void visitIincInsn(int var, int increment);
941
942 /**
943 * Method instruction. See {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitTableSwitchInsn}.
944 *
945 * @param min the minimum key value.
946 * @param max the maximum key value.
947 * @param dflt beginning of the default handler block.
948 * @param labels beginnings of the handler blocks. <tt>labels[i]</tt> is the beginning of the
949 * handler block for the <tt>min + i</tt> key.
950 */
951 public abstract void visitTableSwitchInsn(int min, int max, Label dflt, Label... labels);
952
953 /**
954 * Method instruction. See {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitLookupSwitchInsn}.
955 *
956 * @param dflt beginning of the default handler block.
957 * @param keys the values of the keys.
958 * @param labels beginnings of the handler blocks. <tt>labels[i]</tt> is the beginning of the
959 * handler block for the <tt>keys[i]</tt> key.
960 */
961 public abstract void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels);
962
963 /**
964 * Method instruction. See {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitMultiANewArrayInsn}.
965 *
966 * @param descriptor an array type descriptor (see {@link org.eclipse.persistence.internal.libraries.asm.Type}).
967 * @param numDimensions the number of dimensions of the array to allocate.
968 */
969 public abstract void visitMultiANewArrayInsn(String descriptor, int numDimensions);
970
971 /**
972 * Instruction type annotation. See {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitInsnAnnotation}.
973 *
974 * @param typeRef a reference to the annotated type. The sort of this type reference must be
975 * {@link org.eclipse.persistence.internal.libraries.asm.TypeReference#INSTANCEOF}, {@link
976 * org.eclipse.persistence.internal.libraries.asm.TypeReference#NEW}, {@link
977 * org.eclipse.persistence.internal.libraries.asm.TypeReference#CONSTRUCTOR_REFERENCE}, {@link
978 * org.eclipse.persistence.internal.libraries.asm.TypeReference#METHOD_REFERENCE}, {@link
979 * org.eclipse.persistence.internal.libraries.asm.TypeReference#CAST}, {@link
980 * org.eclipse.persistence.internal.libraries.asm.TypeReference#CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, {@link
981 * org.eclipse.persistence.internal.libraries.asm.TypeReference#METHOD_INVOCATION_TYPE_ARGUMENT}, {@link
982 * org.eclipse.persistence.internal.libraries.asm.TypeReference#CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or {@link
983 * org.eclipse.persistence.internal.libraries.asm.TypeReference#METHOD_REFERENCE_TYPE_ARGUMENT}. See {@link
984 * org.eclipse.persistence.internal.libraries.asm.TypeReference}.
985 * @param typePath the path to the annotated type argument, wildcard bound, array element type, or
986 * static inner type within 'typeRef'. May be <tt>null</tt> if the annotation targets
987 * 'typeRef' as a whole.
988 * @param descriptor the class descriptor of the annotation class.
989 * @param visible <tt>true</tt> if the annotation is visible at runtime.
990 * @return the printer.
991 */
992 public Printer visitInsnAnnotation(
993 final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
994 throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
995 }
996
997 /**
998 * Method exception handler. See {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitTryCatchBlock}.
999 *
1000 * @param start the beginning of the exception handler's scope (inclusive).
1001 * @param end the end of the exception handler's scope (exclusive).
1002 * @param handler the beginning of the exception handler's code.
1003 * @param type the internal name of the type of exceptions handled by the handler, or
1004 * <tt>null</tt> to catch any exceptions (for "finally" blocks).
1005 */
1006 public abstract void visitTryCatchBlock(Label start, Label end, Label handler, String type);
1007
1008 /**
1009 * Try catch block type annotation. See {@link
1010 * org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitTryCatchAnnotation}.
1011 *
1012 * @param typeRef a reference to the annotated type. The sort of this type reference must be
1013 * {@link org.eclipse.persistence.internal.libraries.asm.TypeReference#EXCEPTION_PARAMETER}. See {@link
1014 * org.eclipse.persistence.internal.libraries.asm.TypeReference}.
1015 * @param typePath the path to the annotated type argument, wildcard bound, array element type, or
1016 * static inner type within 'typeRef'. May be <tt>null</tt> if the annotation targets
1017 * 'typeRef' as a whole.
1018 * @param descriptor the class descriptor of the annotation class.
1019 * @param visible <tt>true</tt> if the annotation is visible at runtime.
1020 * @return the printer.
1021 */
1022 public Printer visitTryCatchAnnotation(
1023 final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
1024 throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
1025 }
1026
1027 /**
1028 * Method debug info. See {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitLocalVariable}.
1029 *
1030 * @param name the name of a local variable.
1031 * @param descriptor the type descriptor of this local variable.
1032 * @param signature the type signature of this local variable. May be <tt>null</tt> if the local
1033 * variable type does not use generic types.
1034 * @param start the first instruction corresponding to the scope of this local variable
1035 * (inclusive).
1036 * @param end the last instruction corresponding to the scope of this local variable (exclusive).
1037 * @param index the local variable's index.
1038 */
1039 public abstract void visitLocalVariable(
1040 String name, String descriptor, String signature, Label start, Label end, int index);
1041
1042 /**
1043 * Local variable type annotation. See {@link
1044 * org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitTryCatchAnnotation}.
1045 *
1046 * @param typeRef a reference to the annotated type. The sort of this type reference must be
1047 * {@link org.eclipse.persistence.internal.libraries.asm.TypeReference#LOCAL_VARIABLE} or {@link
1048 * org.eclipse.persistence.internal.libraries.asm.TypeReference#RESOURCE_VARIABLE}. See {@link
1049 * org.eclipse.persistence.internal.libraries.asm.TypeReference}.
1050 * @param typePath the path to the annotated type argument, wildcard bound, array element type, or
1051 * static inner type within 'typeRef'. May be <tt>null</tt> if the annotation targets
1052 * 'typeRef' as a whole.
1053 * @param start the fist instructions corresponding to the continuous ranges that make the scope
1054 * of this local variable (inclusive).
1055 * @param end the last instructions corresponding to the continuous ranges that make the scope of
1056 * this local variable (exclusive). This array must have the same size as the 'start' array.
1057 * @param index the local variable's index in each range. This array must have the same size as
1058 * the 'start' array.
1059 * @param descriptor the class descriptor of the annotation class.
1060 * @param visible <tt>true</tt> if the annotation is visible at runtime.
1061 * @return the printer.
1062 */
1063 public Printer visitLocalVariableAnnotation(
1064 final int typeRef,
1065 final TypePath typePath,
1066 final Label[] start,
1067 final Label[] end,
1068 final int[] index,
1069 final String descriptor,
1070 final boolean visible) {
1071 throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
1072 }
1073
1074 /**
1075 * Method debug info. See {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitLineNumber}.
1076 *
1077 * @param line a line number. This number refers to the source file from which the class was
1078 * compiled.
1079 * @param start the first instruction corresponding to this line number.
1080 */
1081 public abstract void visitLineNumber(int line, Label start);
1082
1083 /**
1084 * Method max stack and max locals. See {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitMaxs}.
1085 *
1086 * @param maxStack maximum stack size of the method.
1087 * @param maxLocals maximum number of local variables for the method.
1088 */
1089 public abstract void visitMaxs(int maxStack, int maxLocals);
1090
1091 /** Method end. See {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitEnd}. */
1092 public abstract void visitMethodEnd();
1093
1094 // -----------------------------------------------------------------------------------------------
1095 // Print and utility methods
1096 // -----------------------------------------------------------------------------------------------
1097
1098 /**
1099 * Returns the text constructed by this visitor.
1100 *
1101 * @return the text constructed by this visitor. See {@link #text}.
1102 */
1103 public List<Object> getText() {
1104 return text;
1105 }
1106
1107 /**
1108 * Prints the text constructed by this visitor.
1109 *
1110 * @param printWriter the print writer to be used.
1111 */
1112 public void print(final PrintWriter printWriter) {
1113 printList(printWriter, text);
1114 }
1115
1116 /**
1117 * Prints the given string tree.
1118 *
1119 * @param printWriter the writer to be used to print the tree.
1120 * @param list a string tree, i.e., a string list that can contain other string lists, and so on
1121 * recursively.
1122 */
1123 static void printList(final PrintWriter printWriter, final List<?> list) {
1124 for (Object o : list) {
1125 if (o instanceof List) {
1126 printList(printWriter, (List<?>) o);
1127 } else {
1128 printWriter.print(o.toString());
1129 }
1130 }
1131 }
1132
1133 /**
1134 * Appends a quoted string to the given string buffer.
1135 *
1136 * @param stringBuffer the buffer where the string must be added.
1137 * @param string the string to be added.
1138 * @deprecated
1139 */
1140 @Deprecated
1141 public static void appendString(final StringBuffer stringBuffer, final String string) {
1142 StringBuilder stringBuilder = new StringBuilder();
1143 appendString(stringBuilder, string);
1144 stringBuffer.append(stringBuilder.toString());
1145 }
1146
1147 /**
1148 * Appends a quoted string to the given string builder.
1149 *
1150 * @param stringBuilder the buffer where the string must be added.
1151 * @param string the string to be added.
1152 */
1153 public static void appendString(final StringBuilder stringBuilder, final String string) {
1154 stringBuilder.append('\"');
1155 for (int i = 0; i < string.length(); ++i) {
1156 char c = string.charAt(i);
1157 if (c == '\n') {
1158 stringBuilder.append("\\n");
1159 } else if (c == '\r') {
1160 stringBuilder.append("\\r");
1161 } else if (c == '\\') {
1162 stringBuilder.append("\\\\");
1163 } else if (c == '"') {
1164 stringBuilder.append("\\\"");
1165 } else if (c < 0x20 || c > 0x7f) {
1166 stringBuilder.append("\\u");
1167 if (c < 0x10) {
1168 stringBuilder.append("000");
1169 } else if (c < 0x100) {
1170 stringBuilder.append("00");
1171 } else if (c < 0x1000) {
1172 stringBuilder.append('0');
941173 }
95
96 s = "T_BOOLEAN,T_CHAR,T_FLOAT,T_DOUBLE,T_BYTE,T_SHORT,T_INT,T_LONG,";
97 TYPES = new String[12];
98 j = 0;
99 i = 4;
100 while ((l = s.indexOf(',', j)) > 0) {
101 TYPES[i++] = s.substring(j, l);
102 j = l + 1;
103 }
104
105 s = "H_GETFIELD,H_GETSTATIC,H_PUTFIELD,H_PUTSTATIC,"
106 + "H_INVOKEVIRTUAL,H_INVOKESTATIC,H_INVOKESPECIAL,"
107 + "H_NEWINVOKESPECIAL,H_INVOKEINTERFACE,";
108 HANDLE_TAG = new String[10];
109 j = 0;
110 i = 1;
111 while ((l = s.indexOf(',', j)) > 0) {
112 HANDLE_TAG[i++] = s.substring(j, l);
113 j = l + 1;
114 }
1174 stringBuilder.append(Integer.toString(c, 16));
1175 } else {
1176 stringBuilder.append(c);
1177 }
1151178 }
116
117 /**
118 * The ASM API version implemented by this class. The value of this field
119 * must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
120 */
121 protected final int api;
122
123 /**
124 * A buffer that can be used to create strings.
125 */
126 protected final StringBuffer buf;
127
128 /**
129 * The text to be printed. Since the code of methods is not necessarily
130 * visited in sequential order, one method after the other, but can be
131 * interlaced (some instructions from method one, then some instructions
132 * from method two, then some instructions from method one again...), it is
133 * not possible to print the visited instructions directly to a sequential
134 * stream. A class is therefore printed in a two steps process: a string
135 * tree is constructed during the visit, and printed to a sequential stream
136 * at the end of the visit. This string tree is stored in this field, as a
137 * string list that can contain other string lists, which can themselves
138 * contain other string lists, and so on.
139 */
140 public final List<Object> text;
141
142 /**
143 * Constructs a new {@link Printer}.
144 *
145 * @param api
146 * the ASM API version implemented by this printer. Must be one
147 * of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
148 */
149 protected Printer(final int api) {
150 this.api = api;
151 this.buf = new StringBuffer();
152 this.text = new ArrayList<Object>();
1179 stringBuilder.append('\"');
1180 }
1181
1182 /**
1183 * Prints a the given class to the standard output.
1184 *
1185 * <p>Command line arguments: [-debug] &lt;binary class name or class file name &gt;
1186 *
1187 * @param usage the help message to show when command line arguments are incorrect.
1188 * @param printer the printer to convert the class into text.
1189 * @param args the command line arguments.
1190 * @throws IOException if the class cannot be found, or if an IOException occurs.
1191 */
1192 static void main(final String usage, final Printer printer, final String[] args)
1193 throws IOException {
1194 if (args.length < 1 || args.length > 2 || (args[0].equals("-debug") && args.length != 2)) {
1195 System.err.println(usage);
1196 return;
1531197 }
1541198
155 /**
156 * Class header.
157 * See {@link org.eclipse.persistence.internal.libraries.asm.ClassVisitor#visit}.
158 *
159 * @param version
160 * the class version.
161 * @param access
162 * the class's access flags (see {@link Opcodes}). This parameter
163 * also indicates if the class is deprecated.
164 * @param name
165 * the internal name of the class (see
166 * {@link org.eclipse.persistence.internal.libraries.asm.Type#getInternalName() getInternalName}).
167 * @param signature
168 * the signature of this class. May be <tt>null</tt> if the class
169 * is not a generic one, and does not extend or implement generic
170 * classes or interfaces.
171 * @param superName
172 * the internal of name of the super class (see
173 * {@link org.eclipse.persistence.internal.libraries.asm.Type#getInternalName() getInternalName}).
174 * For interfaces, the super class is {@link Object}. May be
175 * <tt>null</tt>, but only for the {@link Object} class.
176 * @param interfaces
177 * the internal names of the class's interfaces (see
178 * {@link org.eclipse.persistence.internal.libraries.asm.Type#getInternalName() getInternalName}).
179 * May be <tt>null</tt>.
180 */
181 public abstract void visit(final int version, final int access,
182 final String name, final String signature, final String superName,
183 final String[] interfaces);
184
185 /**
186 * Class source.
187 * See {@link org.eclipse.persistence.internal.libraries.asm.ClassVisitor#visitSource}.
188 *
189 * @param source
190 * the name of the source file from which the class was compiled.
191 * May be <tt>null</tt>.
192 * @param debug
193 * additional debug information to compute the correspondance
194 * between source and compiled elements of the class. May be
195 * <tt>null</tt>.
196 */
197 public abstract void visitSource(final String source, final String debug);
198
199
200 public Printer visitModule() {
201 throw new RuntimeException("Must be overriden");
1199 TraceClassVisitor traceClassVisitor =
1200 new TraceClassVisitor(null, printer, new PrintWriter(System.out));
1201
1202 String className;
1203 int parsingOptions;
1204 if (args[0].equals("-debug")) {
1205 className = args[1];
1206 parsingOptions = ClassReader.SKIP_DEBUG;
1207 } else {
1208 className = args[0];
1209 parsingOptions = 0;
2021210 }
203
204 /**
205 * Class outer class.
206 * See {@link org.eclipse.persistence.internal.libraries.asm.ClassVisitor#visitOuterClass}.
207 *
208 * Visits the enclosing class of the class. This method must be called only
209 * if the class has an enclosing class.
210 *
211 * @param owner
212 * internal name of the enclosing class of the class.
213 * @param name
214 * the name of the method that contains the class, or
215 * <tt>null</tt> if the class is not enclosed in a method of its
216 * enclosing class.
217 * @param desc
218 * the descriptor of the method that contains the class, or
219 * <tt>null</tt> if the class is not enclosed in a method of its
220 * enclosing class.
221 */
222 public abstract void visitOuterClass(final String owner, final String name,
223 final String desc);
224
225 /**
226 * Class annotation.
227 * See {@link org.eclipse.persistence.internal.libraries.asm.ClassVisitor#visitAnnotation}.
228 *
229 * @param desc
230 * the class descriptor of the annotation class.
231 * @param visible
232 * <tt>true</tt> if the annotation is visible at runtime.
233 * @return the printer
234 */
235 public abstract Printer visitClassAnnotation(final String desc,
236 final boolean visible);
237
238 /**
239 * Class type annotation.
240 * See {@link org.eclipse.persistence.internal.libraries.asm.ClassVisitor#visitTypeAnnotation}.
241 *
242 * @param typeRef
243 * a reference to the annotated type. The sort of this type
244 * reference must be
245 * {@link org.eclipse.persistence.internal.libraries.asm.TypeReference#CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER},
246 * {@link org.eclipse.persistence.internal.libraries.asm.TypeReference#CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND}
247 * or {@link org.eclipse.persistence.internal.libraries.asm.TypeReference#CLASS_EXTENDS CLASS_EXTENDS}.
248 * See {@link org.eclipse.persistence.internal.libraries.asm.TypeReference}.
249 * @param typePath
250 * the path to the annotated type argument, wildcard bound, array
251 * element type, or static inner type within 'typeRef'. May be
252 * <tt>null</tt> if the annotation targets 'typeRef' as a whole.
253 * @param desc
254 * the class descriptor of the annotation class.
255 * @param visible
256 * <tt>true</tt> if the annotation is visible at runtime.
257 * @return the printer
258 */
259 public Printer visitClassTypeAnnotation(final int typeRef,
260 final TypePath typePath, final String desc, final boolean visible) {
261 throw new RuntimeException("Must be overriden");
1211
1212 if (className.endsWith(".class")
1213 || className.indexOf('\\') != -1
1214 || className.indexOf('/') != -1) {
1215 new ClassReader(new FileInputStream(className)).accept(traceClassVisitor, parsingOptions);
1216 } else {
1217 new ClassReader(className).accept(traceClassVisitor, parsingOptions);
2621218 }
263
264 /**
265 * Class attribute.
266 * See {@link org.eclipse.persistence.internal.libraries.asm.ClassVisitor#visitAttribute}.
267 *
268 * @param attr
269 * an attribute.
270 */
271 public abstract void visitClassAttribute(final Attribute attr);
272
273 /**
274 * Class inner name.
275 * See {@link org.eclipse.persistence.internal.libraries.asm.ClassVisitor#visitInnerClass}.
276 *
277 * @param name
278 * the internal name of an inner class (see
279 * {@link org.eclipse.persistence.internal.libraries.asm.Type#getInternalName() getInternalName}).
280 * @param outerName
281 * the internal name of the class to which the inner class
282 * belongs (see {@link org.eclipse.persistence.internal.libraries.asm.Type#getInternalName() getInternalName}).
283 * May be <tt>null</tt> for not member classes.
284 * @param innerName
285 * the (simple) name of the inner class inside its enclosing
286 * class. May be <tt>null</tt> for anonymous inner classes.
287 * @param access
288 * the access flags of the inner class as originally declared in
289 * the enclosing class.
290 */
291 public abstract void visitInnerClass(final String name,
292 final String outerName, final String innerName, final int access);
293
294 /**
295 * Class field.
296 * See {@link org.eclipse.persistence.internal.libraries.asm.ClassVisitor#visitField}.
297 *
298 * @param access
299 * the field's access flags (see {@link Opcodes}). This parameter
300 * also indicates if the field is synthetic and/or deprecated.
301 * @param name
302 * the field's name.
303 * @param desc
304 * the field's descriptor (see {@link org.eclipse.persistence.internal.libraries.asm.Type Type}).
305 * @param signature
306 * the field's signature. May be <tt>null</tt> if the field's
307 * type does not use generic types.
308 * @param value
309 * the field's initial value. This parameter, which may be
310 * <tt>null</tt> if the field does not have an initial value,
311 * must be an {@link Integer}, a {@link Float}, a {@link Long}, a
312 * {@link Double} or a {@link String} (for <tt>int</tt>,
313 * <tt>float</tt>, <tt>long</tt> or <tt>String</tt> fields
314 * respectively). <i>This parameter is only used for static
315 * fields</i>. Its value is ignored for non static fields, which
316 * must be initialized through bytecode instructions in
317 * constructors or methods.
318 * @return the printer
319 */
320 public abstract Printer visitField(final int access, final String name,
321 final String desc, final String signature, final Object value);
322
323 /**
324 * Class method.
325 * See {@link org.eclipse.persistence.internal.libraries.asm.ClassVisitor#visitMethod}.
326 *
327 * @param access
328 * the method's access flags (see {@link Opcodes}). This
329 * parameter also indicates if the method is synthetic and/or
330 * deprecated.
331 * @param name
332 * the method's name.
333 * @param desc
334 * the method's descriptor (see {@link org.eclipse.persistence.internal.libraries.asm.Type Type}).
335 * @param signature
336 * the method's signature. May be <tt>null</tt> if the method
337 * parameters, return type and exceptions do not use generic
338 * types.
339 * @param exceptions
340 * the internal names of the method's exception classes (see
341 * {@link org.eclipse.persistence.internal.libraries.asm.Type#getInternalName() getInternalName}). May be
342 * <tt>null</tt>.
343 * @return the printer
344 */
345 public abstract Printer visitMethod(final int access, final String name,
346 final String desc, final String signature, final String[] exceptions);
347
348 /**
349 * Class end. See {@link org.eclipse.persistence.internal.libraries.asm.ClassVisitor#visitEnd}.
350 */
351 public abstract void visitClassEnd();
352
353 // ------------------------------------------------------------------------
354 // Module
355 // ------------------------------------------------------------------------
356
357 public void visitRequire(String module, int access) {
358 throw new RuntimeException("Must be overriden");
359 }
360
361 public void visitExport(String packaze, String... modules) {
362 throw new RuntimeException("Must be overriden");
363 }
364
365 public void visitUse(String service) {
366 throw new RuntimeException("Must be overriden");
367 }
368
369 public void visitProvide(String service, String impl) {
370 throw new RuntimeException("Must be overriden");
371 }
372
373 /**
374 * Module end. See {@link org.eclipse.persistence.internal.libraries.asm.ModuleVisitor#visitEnd}.
375 */
376 public void visitModuleEnd() {
377 throw new RuntimeException("Must be overriden");
378 }
379
380 // ------------------------------------------------------------------------
381 // Annotations
382 // ------------------------------------------------------------------------
383
384 /**
385 * Annotation value.
386 * See {@link org.eclipse.persistence.internal.libraries.asm.AnnotationVisitor#visit}.
387 *
388 * @param name
389 * the value name.
390 * @param value
391 * the actual value, whose type must be {@link Byte},
392 * {@link Boolean}, {@link Character}, {@link Short},
393 * {@link Integer} , {@link Long}, {@link Float}, {@link Double},
394 * {@link String} or {@link org.eclipse.persistence.internal.libraries.asm.Type}
395 * or OBJECT or ARRAY sort.
396 * This value can also be an array of byte, boolean, short, char, int,
397 * long, float or double values (this is equivalent to using
398 * {@link #visitArray visitArray} and visiting each array element
399 * in turn, but is more convenient).
400 */
401 public abstract void visit(final String name, final Object value);
402
403 /**
404 * Annotation enum value.
405 * See {@link org.eclipse.persistence.internal.libraries.asm.AnnotationVisitor#visitEnum}.
406 *
407 * Visits an enumeration value of the annotation.
408 *
409 * @param name
410 * the value name.
411 * @param desc
412 * the class descriptor of the enumeration class.
413 * @param value
414 * the actual enumeration value.
415 */
416 public abstract void visitEnum(final String name, final String desc,
417 final String value);
418
419 /**
420 * Nested annotation value.
421 * See {@link org.eclipse.persistence.internal.libraries.asm.AnnotationVisitor#visitAnnotation}.
422 *
423 * @param name
424 * the value name.
425 * @param desc
426 * the class descriptor of the nested annotation class.
427 * @return the printer
428 */
429 public abstract Printer visitAnnotation(final String name, final String desc);
430
431 /**
432 * Annotation array value.
433 * See {@link org.eclipse.persistence.internal.libraries.asm.AnnotationVisitor#visitArray}.
434 *
435 * Visits an array value of the annotation. Note that arrays of primitive
436 * types (such as byte, boolean, short, char, int, long, float or double)
437 * can be passed as value to {@link #visit visit}. This is what
438 * {@link org.eclipse.persistence.internal.libraries.asm.ClassReader} does.
439 *
440 * @param name
441 * the value name.
442 * @return the printer
443 */
444 public abstract Printer visitArray(final String name);
445
446 /**
447 * Annotation end. See {@link org.eclipse.persistence.internal.libraries.asm.AnnotationVisitor#visitEnd}.
448 */
449 public abstract void visitAnnotationEnd();
450
451 // ------------------------------------------------------------------------
452 // Fields
453 // ------------------------------------------------------------------------
454
455 /**
456 * Field annotation.
457 * See {@link org.eclipse.persistence.internal.libraries.asm.FieldVisitor#visitAnnotation}.
458 *
459 * @param desc
460 * the class descriptor of the annotation class.
461 * @param visible
462 * <tt>true</tt> if the annotation is visible at runtime.
463 * @return the printer
464 */
465 public abstract Printer visitFieldAnnotation(final String desc,
466 final boolean visible);
467
468 /**
469 * Field type annotation.
470 * See {@link org.eclipse.persistence.internal.libraries.asm.FieldVisitor#visitTypeAnnotation}.
471 *
472 * @param typeRef
473 * a reference to the annotated type. The sort of this type
474 * reference must be {@link org.eclipse.persistence.internal.libraries.asm.TypeReference#FIELD FIELD}.
475 * See {@link org.eclipse.persistence.internal.libraries.asm.TypeReference}.
476 * @param typePath
477 * the path to the annotated type argument, wildcard bound, array
478 * element type, or static inner type within 'typeRef'. May be
479 * <tt>null</tt> if the annotation targets 'typeRef' as a whole.
480 * @param desc
481 * the class descriptor of the annotation class.
482 * @param visible
483 * <tt>true</tt> if the annotation is visible at runtime.
484 * @return the printer
485 */
486 public Printer visitFieldTypeAnnotation(final int typeRef,
487 final TypePath typePath, final String desc, final boolean visible) {
488 throw new RuntimeException("Must be overriden");
489 }
490
491 /**
492 * Field attribute.
493 * See {@link org.eclipse.persistence.internal.libraries.asm.FieldVisitor#visitAttribute}.
494 *
495 * @param attr
496 * an attribute.
497 */
498 public abstract void visitFieldAttribute(final Attribute attr);
499
500 /**
501 * Field end.
502 * See {@link org.eclipse.persistence.internal.libraries.asm.FieldVisitor#visitEnd}.
503 */
504 public abstract void visitFieldEnd();
505
506 // ------------------------------------------------------------------------
507 // Methods
508 // ------------------------------------------------------------------------
509
510 /**
511 * Method parameter.
512 * See {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitParameter(String, int)}.
513 *
514 * @param name
515 * parameter name or null if none is provided.
516 * @param access
517 * the parameter's access flags, only <tt>ACC_FINAL</tt>,
518 * <tt>ACC_SYNTHETIC</tt> or/and <tt>ACC_MANDATED</tt> are
519 * allowed (see {@link Opcodes}).
520 */
521 public void visitParameter(String name, int access) {
522 throw new RuntimeException("Must be overriden");
523 }
524
525 /**
526 * Method default annotation.
527 * See {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitAnnotationDefault}.
528 *
529 * @return the printer
530 */
531 public abstract Printer visitAnnotationDefault();
532
533 /**
534 * Method annotation.
535 * See {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitAnnotation}.
536 *
537 * @param desc
538 * the class descriptor of the annotation class.
539 * @param visible
540 * <tt>true</tt> if the annotation is visible at runtime.
541 * @return the printer
542 */
543 public abstract Printer visitMethodAnnotation(final String desc,
544 final boolean visible);
545
546 /**
547 * Method type annotation.
548 * See {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitTypeAnnotation}.
549 *
550 * @param typeRef
551 * a reference to the annotated type. The sort of this type
552 * reference must be {@link org.eclipse.persistence.internal.libraries.asm.TypeReference#FIELD FIELD}.
553 * See {@link org.eclipse.persistence.internal.libraries.asm.TypeReference}.
554 * @param typePath
555 * the path to the annotated type argument, wildcard bound, array
556 * element type, or static inner type within 'typeRef'. May be
557 * <tt>null</tt> if the annotation targets 'typeRef' as a whole.
558 * @param desc
559 * the class descriptor of the annotation class.
560 * @param visible
561 * <tt>true</tt> if the annotation is visible at runtime.
562 * @return the printer
563 */
564 public Printer visitMethodTypeAnnotation(final int typeRef,
565 final TypePath typePath, final String desc, final boolean visible) {
566 throw new RuntimeException("Must be overriden");
567 }
568
569 /**
570 * Method parameter annotation.
571 * See {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitParameterAnnotation}.
572 *
573 * @param parameter
574 * the parameter index.
575 * @param desc
576 * the class descriptor of the annotation class.
577 * @param visible
578 * <tt>true</tt> if the annotation is visible at runtime.
579 * @return the printer
580 */
581 public abstract Printer visitParameterAnnotation(final int parameter,
582 final String desc, final boolean visible);
583
584 /**
585 * Method attribute.
586 * See {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitAttribute}.
587 *
588 * @param attr
589 * an attribute.
590 */
591 public abstract void visitMethodAttribute(final Attribute attr);
592
593 /**
594 * Method start.
595 * See {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitCode}.
596 */
597 public abstract void visitCode();
598
599 /**
600 * Method stack frame.
601 * See {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitFrame}.
602 *
603 * Visits the current state of the local variables and operand stack
604 * elements. This method must(*) be called <i>just before</i> any
605 * instruction <b>i</b> that follows an unconditional branch instruction
606 * such as GOTO or THROW, that is the target of a jump instruction, or that
607 * starts an exception handler block. The visited types must describe the
608 * values of the local variables and of the operand stack elements <i>just
609 * before</i> <b>i</b> is executed.<br>
610 * <br>
611 * (*) this is mandatory only for classes whose version is greater than or
612 * equal to {@link Opcodes#V1_6 V1_6}. <br>
613 * <br>
614 * The frames of a method must be given either in expanded form, or in
615 * compressed form (all frames must use the same format, i.e. you must not
616 * mix expanded and compressed frames within a single method):
617 * <ul>
618 * <li>In expanded form, all frames must have the F_NEW type.</li>
619 * <li>In compressed form, frames are basically "deltas" from the state of
620 * the previous frame:
621 * <ul>
622 * <li>{@link Opcodes#F_SAME} representing frame with exactly the same
623 * locals as the previous frame and with the empty stack.</li>
624 * <li>{@link Opcodes#F_SAME1} representing frame with exactly the same
625 * locals as the previous frame and with single value on the stack (
626 * <code>nStack</code> is 1 and <code>stack[0]</code> contains value for the
627 * type of the stack item).</li>
628 * <li>{@link Opcodes#F_APPEND} representing frame with current locals are
629 * the same as the locals in the previous frame, except that additional
630 * locals are defined (<code>nLocal</code> is 1, 2 or 3 and
631 * <code>local</code> elements contains values representing added types).</li>
632 * <li>{@link Opcodes#F_CHOP} representing frame with current locals are the
633 * same as the locals in the previous frame, except that the last 1-3 locals
634 * are absent and with the empty stack (<code>nLocals</code> is 1, 2 or 3).</li>
635 * <li>{@link Opcodes#F_FULL} representing complete frame data.</li>
636 * </ul>
637 * </li>
638 * </ul>
639 * <br>
640 * In both cases the first frame, corresponding to the method's parameters
641 * and access flags, is implicit and must not be visited. Also, it is
642 * illegal to visit two or more frames for the same code location (i.e., at
643 * least one instruction must be visited between two calls to visitFrame).
644 *
645 * @param type
646 * the type of this stack map frame. Must be
647 * {@link Opcodes#F_NEW} for expanded frames, or
648 * {@link Opcodes#F_FULL}, {@link Opcodes#F_APPEND},
649 * {@link Opcodes#F_CHOP}, {@link Opcodes#F_SAME} or
650 * {@link Opcodes#F_APPEND}, {@link Opcodes#F_SAME1} for
651 * compressed frames.
652 * @param nLocal
653 * the number of local variables in the visited frame.
654 * @param local
655 * the local variable types in this frame. This array must not be
656 * modified. Primitive types are represented by
657 * {@link Opcodes#TOP}, {@link Opcodes#INTEGER},
658 * {@link Opcodes#FLOAT}, {@link Opcodes#LONG},
659 * {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or
660 * {@link Opcodes#UNINITIALIZED_THIS} (long and double are
661 * represented by a single element). Reference types are
662 * represented by String objects (representing internal names),
663 * and uninitialized types by Label objects (this label
664 * designates the NEW instruction that created this uninitialized
665 * value).
666 * @param nStack
667 * the number of operand stack elements in the visited frame.
668 * @param stack
669 * the operand stack types in this frame. This array must not be
670 * modified. Its content has the same format as the "local"
671 * array.
672 * @throws IllegalStateException
673 * if a frame is visited just after another one, without any
674 * instruction between the two (unless this frame is a
675 * Opcodes#F_SAME frame, in which case it is silently ignored).
676 */
677 public abstract void visitFrame(final int type, final int nLocal,
678 final Object[] local, final int nStack, final Object[] stack);
679
680 /**
681 * Method instruction.
682 * See {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitInsn}
683 *
684 * @param opcode
685 * the opcode of the instruction to be visited. This opcode is
686 * either NOP, ACONST_NULL, ICONST_M1, ICONST_0, ICONST_1,
687 * ICONST_2, ICONST_3, ICONST_4, ICONST_5, LCONST_0, LCONST_1,
688 * FCONST_0, FCONST_1, FCONST_2, DCONST_0, DCONST_1, IALOAD,
689 * LALOAD, FALOAD, DALOAD, AALOAD, BALOAD, CALOAD, SALOAD,
690 * IASTORE, LASTORE, FASTORE, DASTORE, AASTORE, BASTORE, CASTORE,
691 * SASTORE, POP, POP2, DUP, DUP_X1, DUP_X2, DUP2, DUP2_X1,
692 * DUP2_X2, SWAP, IADD, LADD, FADD, DADD, ISUB, LSUB, FSUB, DSUB,
693 * IMUL, LMUL, FMUL, DMUL, IDIV, LDIV, FDIV, DDIV, IREM, LREM,
694 * FREM, DREM, INEG, LNEG, FNEG, DNEG, ISHL, LSHL, ISHR, LSHR,
695 * IUSHR, LUSHR, IAND, LAND, IOR, LOR, IXOR, LXOR, I2L, I2F, I2D,
696 * L2I, L2F, L2D, F2I, F2L, F2D, D2I, D2L, D2F, I2B, I2C, I2S,
697 * LCMP, FCMPL, FCMPG, DCMPL, DCMPG, IRETURN, LRETURN, FRETURN,
698 * DRETURN, ARETURN, RETURN, ARRAYLENGTH, ATHROW, MONITORENTER,
699 * or MONITOREXIT.
700 */
701 public abstract void visitInsn(final int opcode);
702
703 /**
704 * Method instruction.
705 * See {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitIntInsn}.
706 *
707 * @param opcode
708 * the opcode of the instruction to be visited. This opcode is
709 * either BIPUSH, SIPUSH or NEWARRAY.
710 * @param operand
711 * the operand of the instruction to be visited.<br>
712 * When opcode is BIPUSH, operand value should be between
713 * Byte.MIN_VALUE and Byte.MAX_VALUE.<br>
714 * When opcode is SIPUSH, operand value should be between
715 * Short.MIN_VALUE and Short.MAX_VALUE.<br>
716 * When opcode is NEWARRAY, operand value should be one of
717 * {@link Opcodes#T_BOOLEAN}, {@link Opcodes#T_CHAR},
718 * {@link Opcodes#T_FLOAT}, {@link Opcodes#T_DOUBLE},
719 * {@link Opcodes#T_BYTE}, {@link Opcodes#T_SHORT},
720 * {@link Opcodes#T_INT} or {@link Opcodes#T_LONG}.
721 */
722 public abstract void visitIntInsn(final int opcode, final int operand);
723
724 /**
725 * Method instruction.
726 * See {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitVarInsn}.
727 *
728 * @param opcode
729 * the opcode of the local variable instruction to be visited.
730 * This opcode is either ILOAD, LLOAD, FLOAD, DLOAD, ALOAD,
731 * ISTORE, LSTORE, FSTORE, DSTORE, ASTORE or RET.
732 * @param var
733 * the operand of the instruction to be visited. This operand is
734 * the index of a local variable.
735 */
736 public abstract void visitVarInsn(final int opcode, final int var);
737
738 /**
739 * Method instruction.
740 * See {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitTypeInsn}.
741 *
742 /**
743 * Visits a type instruction. A type instruction is an instruction that
744 * takes the internal name of a class as parameter.
745 *
746 * @param opcode
747 * the opcode of the type instruction to be visited. This opcode
748 * is either NEW, ANEWARRAY, CHECKCAST or INSTANCEOF.
749 * @param type
750 * the operand of the instruction to be visited. This operand
751 * must be the internal name of an object or array class (see
752 * {@link org.eclipse.persistence.internal.libraries.asm.Type#getInternalName() getInternalName}).
753 */
754 public abstract void visitTypeInsn(final int opcode, final String type);
755
756 /**
757 * Method instruction.
758 * See {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitFieldInsn}.
759 *
760 * @param opcode
761 * the opcode of the type instruction to be visited. This opcode
762 * is either GETSTATIC, PUTSTATIC, GETFIELD or PUTFIELD.
763 * @param owner
764 * the internal name of the field's owner class (see
765 * {@link org.eclipse.persistence.internal.libraries.asm.Type#getInternalName() getInternalName}).
766 * @param name
767 * the field's name.
768 * @param desc
769 * the field's descriptor (see {@link org.eclipse.persistence.internal.libraries.asm.Type Type}).
770 */
771 public abstract void visitFieldInsn(final int opcode, final String owner,
772 final String name, final String desc);
773
774 /**
775 * Method instruction.
776 * See {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitMethodInsn}.
777 *
778 * @param opcode
779 * the opcode of the type instruction to be visited. This opcode
780 * is either INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or
781 * INVOKEINTERFACE.
782 * @param owner
783 * the internal name of the method's owner class (see
784 * {@link org.eclipse.persistence.internal.libraries.asm.Type#getInternalName() getInternalName}).
785 * @param name
786 * the method's name.
787 * @param desc
788 * the method's descriptor (see {@link org.eclipse.persistence.internal.libraries.asm.Type Type}).
789 */
790 @Deprecated
791 public void visitMethodInsn(final int opcode, final String owner,
792 final String name, final String desc) {
793 if (api >= Opcodes.ASM5) {
794 boolean itf = opcode == Opcodes.INVOKEINTERFACE;
795 visitMethodInsn(opcode, owner, name, desc, itf);
796 return;
797 }
798 throw new RuntimeException("Must be overriden");
799 }
800
801 /**
802 * Method instruction.
803 * See {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitMethodInsn}.
804 *
805 * @param opcode
806 * the opcode of the type instruction to be visited. This opcode
807 * is either INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or
808 * INVOKEINTERFACE.
809 * @param owner
810 * the internal name of the method's owner class (see
811 * {@link org.eclipse.persistence.internal.libraries.asm.Type#getInternalName() getInternalName}).
812 * @param name
813 * the method's name.
814 * @param desc
815 * the method's descriptor (see {@link org.eclipse.persistence.internal.libraries.asm.Type Type}).
816 * @param itf
817 * if the method's owner class is an interface.
818 */
819 public void visitMethodInsn(final int opcode, final String owner,
820 final String name, final String desc, final boolean itf) {
821 if (api < Opcodes.ASM5) {
822 if (itf != (opcode == Opcodes.INVOKEINTERFACE)) {
823 throw new IllegalArgumentException(
824 "INVOKESPECIAL/STATIC on interfaces require ASM 5");
825 }
826 visitMethodInsn(opcode, owner, name, desc);
827 return;
828 }
829 throw new RuntimeException("Must be overriden");
830 }
831
832 /**
833 * Method instruction.
834 * See {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitInvokeDynamicInsn}.
835 *
836 * Visits an invokedynamic instruction.
837 *
838 * @param name
839 * the method's name.
840 * @param desc
841 * the method's descriptor (see {@link org.eclipse.persistence.internal.libraries.asm.Type Type}).
842 * @param bsm
843 * the bootstrap method.
844 * @param bsmArgs
845 * the bootstrap method constant arguments. Each argument must be
846 * an {@link Integer}, {@link Float}, {@link Long},
847 * {@link Double}, {@link String}, {@link org.eclipse.persistence.internal.libraries.asm.Type} or {@link Handle}
848 * value. This method is allowed to modify the content of the
849 * array so a caller should expect that this array may change.
850 */
851 public abstract void visitInvokeDynamicInsn(String name, String desc,
852 Handle bsm, Object... bsmArgs);
853
854 /**
855 * Method jump instruction.
856 * See {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitJumpInsn}.
857 *
858 * @param opcode
859 * the opcode of the type instruction to be visited. This opcode
860 * is either IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, IF_ICMPEQ,
861 * IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE,
862 * IF_ACMPEQ, IF_ACMPNE, GOTO, JSR, IFNULL or IFNONNULL.
863 * @param label
864 * the operand of the instruction to be visited. This operand is
865 * a label that designates the instruction to which the jump
866 * instruction may jump.
867 */
868 public abstract void visitJumpInsn(final int opcode, final Label label);
869
870 /**
871 * Method label.
872 * See {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitLabel}.
873 *
874 * @param label
875 * a {@link Label Label} object.
876 */
877 public abstract void visitLabel(final Label label);
878
879 /**
880 * Method instruction.
881 * See {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitLdcInsn}.
882 *
883 * Visits a LDC instruction. Note that new constant types may be added in
884 * future versions of the Java Virtual Machine. To easily detect new
885 * constant types, implementations of this method should check for
886 * unexpected constant types, like this:
887 *
888 * <pre>
889 * if (cst instanceof Integer) {
890 * // ...
891 * } else if (cst instanceof Float) {
892 * // ...
893 * } else if (cst instanceof Long) {
894 * // ...
895 * } else if (cst instanceof Double) {
896 * // ...
897 * } else if (cst instanceof String) {
898 * // ...
899 * } else if (cst instanceof Type) {
900 * int sort = ((Type) cst).getSort();
901 * if (sort == Type.OBJECT) {
902 * // ...
903 * } else if (sort == Type.ARRAY) {
904 * // ...
905 * } else if (sort == Type.METHOD) {
906 * // ...
907 * } else {
908 * // throw an exception
909 * }
910 * } else if (cst instanceof Handle) {
911 * // ...
912 * } else {
913 * // throw an exception
914 * }
915 * </pre>
916 *
917 * @param cst
918 * the constant to be loaded on the stack. This parameter must be
919 * a non null {@link Integer}, a {@link Float}, a {@link Long}, a
920 * {@link Double}, a {@link String}, a {@link org.eclipse.persistence.internal.libraries.asm.Type}
921 * of OBJECT or ARRAY sort for <tt>.class</tt> constants, for classes whose
922 * version is 49.0, a {@link org.eclipse.persistence.internal.libraries.asm.Type} of METHOD sort or a
923 * {@link Handle} for MethodType and MethodHandle constants, for
924 * classes whose version is 51.0.
925 */
926 public abstract void visitLdcInsn(final Object cst);
927
928 /**
929 * Method instruction.
930 * See {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitIincInsn}.
931 *
932 * @param var
933 * index of the local variable to be incremented.
934 * @param increment
935 * amount to increment the local variable by.
936 */
937 public abstract void visitIincInsn(final int var, final int increment);
938
939 /**
940 * Method instruction.
941 * See {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitTableSwitchInsn}.
942 *
943 * @param min
944 * the minimum key value.
945 * @param max
946 * the maximum key value.
947 * @param dflt
948 * beginning of the default handler block.
949 * @param labels
950 * beginnings of the handler blocks. <tt>labels[i]</tt> is the
951 * beginning of the handler block for the <tt>min + i</tt> key.
952 */
953 public abstract void visitTableSwitchInsn(final int min, final int max,
954 final Label dflt, final Label... labels);
955
956 /**
957 * Method instruction.
958 * See {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitLookupSwitchInsn}.
959 *
960 * @param dflt
961 * beginning of the default handler block.
962 * @param keys
963 * the values of the keys.
964 * @param labels
965 * beginnings of the handler blocks. <tt>labels[i]</tt> is the
966 * beginning of the handler block for the <tt>keys[i]</tt> key.
967 */
968 public abstract void visitLookupSwitchInsn(final Label dflt,
969 final int[] keys, final Label[] labels);
970
971 /**
972 * Method instruction.
973 * See {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitMultiANewArrayInsn}.
974 *
975 * @param desc
976 * an array type descriptor (see {@link org.eclipse.persistence.internal.libraries.asm.Type Type}).
977 * @param dims
978 * number of dimensions of the array to allocate.
979 */
980 public abstract void visitMultiANewArrayInsn(final String desc,
981 final int dims);
982
983 /**
984 * Instruction type annotation.
985 * See {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitInsnAnnotation}.
986 *
987 * @param typeRef
988 * a reference to the annotated type. The sort of this type
989 * reference must be {@link org.eclipse.persistence.internal.libraries.asm.TypeReference#INSTANCEOF INSTANCEOF},
990 * {@link org.eclipse.persistence.internal.libraries.asm.TypeReference#NEW NEW},
991 * {@link org.eclipse.persistence.internal.libraries.asm.TypeReference#CONSTRUCTOR_REFERENCE CONSTRUCTOR_REFERENCE},
992 * {@link org.eclipse.persistence.internal.libraries.asm.TypeReference#METHOD_REFERENCE METHOD_REFERENCE},
993 * {@link org.eclipse.persistence.internal.libraries.asm.TypeReference#CAST CAST},
994 * {@link org.eclipse.persistence.internal.libraries.asm.TypeReference#CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT},
995 * {@link org.eclipse.persistence.internal.libraries.asm.TypeReference#METHOD_INVOCATION_TYPE_ARGUMENT METHOD_INVOCATION_TYPE_ARGUMENT},
996 * {@link org.eclipse.persistence.internal.libraries.asm.TypeReference#CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT},
997 * or {@link org.eclipse.persistence.internal.libraries.asm.TypeReference#METHOD_REFERENCE_TYPE_ARGUMENT METHOD_REFERENCE_TYPE_ARGUMENT}.
998 * See {@link org.eclipse.persistence.internal.libraries.asm.TypeReference}.
999 * @param typePath
1000 * the path to the annotated type argument, wildcard bound, array
1001 * element type, or static inner type within 'typeRef'. May be
1002 * <tt>null</tt> if the annotation targets 'typeRef' as a whole.
1003 * @param desc
1004 * the class descriptor of the annotation class.
1005 * @param visible
1006 * <tt>true</tt> if the annotation is visible at runtime.
1007 * @return the printer
1008 */
1009 public Printer visitInsnAnnotation(final int typeRef,
1010 final TypePath typePath, final String desc, final boolean visible) {
1011 throw new RuntimeException("Must be overriden");
1012 }
1013
1014 /**
1015 * Method exception handler.
1016 * See {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitTryCatchBlock}.
1017 *
1018 * @param start
1019 * beginning of the exception handler's scope (inclusive).
1020 * @param end
1021 * end of the exception handler's scope (exclusive).
1022 * @param handler
1023 * beginning of the exception handler's code.
1024 * @param type
1025 * internal name of the type of exceptions handled by the
1026 * handler, or <tt>null</tt> to catch any exceptions (for
1027 * "finally" blocks).
1028 * @throws IllegalArgumentException
1029 * if one of the labels has already been visited by this visitor
1030 * (by the {@link #visitLabel visitLabel} method).
1031 */
1032 public abstract void visitTryCatchBlock(final Label start, final Label end,
1033 final Label handler, final String type);
1034
1035 /**
1036 * Try catch block type annotation.
1037 * See {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitTryCatchAnnotation}.
1038 *
1039 * @param typeRef
1040 * a reference to the annotated type. The sort of this type
1041 * reference must be {@link org.eclipse.persistence.internal.libraries.asm.TypeReference#EXCEPTION_PARAMETER
1042 * EXCEPTION_PARAMETER}.
1043 * See {@link org.eclipse.persistence.internal.libraries.asm.TypeReference}.
1044 * @param typePath
1045 * the path to the annotated type argument, wildcard bound, array
1046 * element type, or static inner type within 'typeRef'. May be
1047 * <tt>null</tt> if the annotation targets 'typeRef' as a whole.
1048 * @param desc
1049 * the class descriptor of the annotation class.
1050 * @param visible
1051 * <tt>true</tt> if the annotation is visible at runtime.
1052 * @return the printer
1053 */
1054 public Printer visitTryCatchAnnotation(final int typeRef,
1055 final TypePath typePath, final String desc, final boolean visible) {
1056 throw new RuntimeException("Must be overriden");
1057 }
1058
1059 /**
1060 * Method debug info.
1061 * See {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitLocalVariable}.
1062 *
1063 * @param name
1064 * the name of a local variable.
1065 * @param desc
1066 * the type descriptor of this local variable.
1067 * @param signature
1068 * the type signature of this local variable. May be
1069 * <tt>null</tt> if the local variable type does not use generic
1070 * types.
1071 * @param start
1072 * the first instruction corresponding to the scope of this local
1073 * variable (inclusive).
1074 * @param end
1075 * the last instruction corresponding to the scope of this local
1076 * variable (exclusive).
1077 * @param index
1078 * the local variable's index.
1079 * @throws IllegalArgumentException
1080 * if one of the labels has not already been visited by this
1081 * visitor (by the {@link #visitLabel visitLabel} method).
1082 */
1083 public abstract void visitLocalVariable(final String name,
1084 final String desc, final String signature, final Label start,
1085 final Label end, final int index);
1086
1087 /**
1088 * Local variable type annotation.
1089 * See {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitTryCatchAnnotation}.
1090 *
1091 * @param typeRef
1092 * a reference to the annotated type. The sort of this type
1093 * reference must be {@link org.eclipse.persistence.internal.libraries.asm.TypeReference#LOCAL_VARIABLE
1094 * LOCAL_VARIABLE} or {@link org.eclipse.persistence.internal.libraries.asm.TypeReference#RESOURCE_VARIABLE
1095 * RESOURCE_VARIABLE}.
1096 * See {@link org.eclipse.persistence.internal.libraries.asm.TypeReference}.
1097 * @param typePath
1098 * the path to the annotated type argument, wildcard bound, array
1099 * element type, or static inner type within 'typeRef'. May be
1100 * <tt>null</tt> if the annotation targets 'typeRef' as a whole.
1101 * @param start
1102 * the fist instructions corresponding to the continuous ranges
1103 * that make the scope of this local variable (inclusive).
1104 * @param end
1105 * the last instructions corresponding to the continuous ranges
1106 * that make the scope of this local variable (exclusive). This
1107 * array must have the same size as the 'start' array.
1108 * @param index
1109 * the local variable's index in each range. This array must have
1110 * the same size as the 'start' array.
1111 * @param desc
1112 * the class descriptor of the annotation class.
1113 * @param visible
1114 * <tt>true</tt> if the annotation is visible at runtime.
1115 * @return the printer
1116 */
1117 public Printer visitLocalVariableAnnotation(final int typeRef,
1118 final TypePath typePath, final Label[] start, final Label[] end,
1119 final int[] index, final String desc, final boolean visible) {
1120 throw new RuntimeException("Must be overriden");
1121 }
1122
1123 /**
1124 * Method debug info.
1125 * See {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitLineNumber}.
1126 *
1127 * @param line
1128 * a line number. This number refers to the source file from
1129 * which the class was compiled.
1130 * @param start
1131 * the first instruction corresponding to this line number.
1132 * @throws IllegalArgumentException
1133 * if <tt>start</tt> has not already been visited by this
1134 * visitor (by the {@link #visitLabel visitLabel} method).
1135 */
1136 public abstract void visitLineNumber(final int line, final Label start);
1137
1138 /**
1139 * Method max stack and max locals.
1140 * See {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitMaxs}.
1141 *
1142 * @param maxStack
1143 * maximum stack size of the method.
1144 * @param maxLocals
1145 * maximum number of local variables for the method.
1146 */
1147 public abstract void visitMaxs(final int maxStack, final int maxLocals);
1148
1149 /**
1150 * Method end.
1151 * See {@link org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitEnd}.
1152 */
1153 public abstract void visitMethodEnd();
1154
1155 /**
1156 * Returns the text constructed by this visitor.
1157 *
1158 * @return the text constructed by this visitor.
1159 */
1160 public List<Object> getText() {
1161 return text;
1162 }
1163
1164 /**
1165 * Prints the text constructed by this visitor.
1166 *
1167 * @param pw
1168 * the print writer to be used.
1169 */
1170 public void print(final PrintWriter pw) {
1171 printList(pw, text);
1172 }
1173
1174 /**
1175 * Appends a quoted string to a given buffer.
1176 *
1177 * @param buf
1178 * the buffer where the string must be added.
1179 * @param s
1180 * the string to be added.
1181 */
1182 public static void appendString(final StringBuffer buf, final String s) {
1183 buf.append('\"');
1184 for (int i = 0; i < s.length(); ++i) {
1185 char c = s.charAt(i);
1186 if (c == '\n') {
1187 buf.append("\\n");
1188 } else if (c == '\r') {
1189 buf.append("\\r");
1190 } else if (c == '\\') {
1191 buf.append("\\\\");
1192 } else if (c == '"') {
1193 buf.append("\\\"");
1194 } else if (c < 0x20 || c > 0x7f) {
1195 buf.append("\\u");
1196 if (c < 0x10) {
1197 buf.append("000");
1198 } else if (c < 0x100) {
1199 buf.append("00");
1200 } else if (c < 0x1000) {
1201 buf.append('0');
1202 }
1203 buf.append(Integer.toString(c, 16));
1204 } else {
1205 buf.append(c);
1206 }
1207 }
1208 buf.append('\"');
1209 }
1210
1211 /**
1212 * Prints the given string tree.
1213 *
1214 * @param pw
1215 * the writer to be used to print the tree.
1216 * @param l
1217 * a string tree, i.e., a string list that can contain other
1218 * string lists, and so on recursively.
1219 */
1220 static void printList(final PrintWriter pw, final List<?> l) {
1221 for (int i = 0; i < l.size(); ++i) {
1222 Object o = l.get(i);
1223 if (o instanceof List) {
1224 printList(pw, (List<?>) o);
1225 } else {
1226 pw.print(o.toString());
1227 }
1228 }
1229 }
1230 }
1219 }
1220 }
00 /**
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
1 * ASM: a very small and fast Java bytecode manipulation framework Copyright (c) 2000-2011 INRIA,
2 * France Telecom All rights reserved.
43 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
4 * <p>Redistribution and use in source and binary forms, with or without modification, are permitted
5 * provided that the following conditions are met: 1. Redistributions of source code must retain the
6 * above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions
7 * in binary form must reproduce the above copyright notice, this list of conditions and the
8 * following disclaimer in the documentation and/or other materials provided with the distribution.
9 * 3. Neither the name of the copyright holders nor the names of its contributors may be used to
10 * endorse or promote products derived from this software without specific prior written permission.
1611 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
12 * <p>THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
13 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
14 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
15 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
16 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
17 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
18 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
19 * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2820 */
2921 package org.eclipse.persistence.internal.libraries.asm.util;
3022
3325 import org.eclipse.persistence.internal.libraries.asm.Label;
3426
3527 /**
36 * An {@link org.eclipse.persistence.internal.libraries.asm.Attribute Attribute} that can print a readable
37 * representation of itself.
38 *
39 * Implementations should construct readable output from an attribute data
40 * structure. Such representation could be used in unit test assertions.
41 *
28 * An {@link org.eclipse.persistence.internal.libraries.asm.Attribute} that can print a readable representation of itself.
29 *
4230 * @author Eugene Kuleshov
4331 */
4432 public interface Textifiable {
4533
46 /**
47 * Build a human readable representation of this attribute.
48 *
49 * @param buf
50 * a buffer used for printing Java code.
51 * @param labelNames
52 * map of label instances to their names.
53 */
54 void textify(StringBuffer buf, Map<Label, String> labelNames);
34 /**
35 * Generates a human readable representation of this attribute.
36 *
37 * @param outputBuffer where the human representation of this attribute must be appended.
38 * @param labelNames the human readable names of the labels.
39 */
40 void textify(StringBuffer outputBuffer, Map<Label, String> labelNames);
5541 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.util;
3028
31 import java.io.FileInputStream;
32 import java.io.PrintWriter;
29 import java.io.IOException;
3330 import java.util.HashMap;
3431 import java.util.Map;
3532
3633 import org.eclipse.persistence.internal.libraries.asm.Attribute;
37 import org.eclipse.persistence.internal.libraries.asm.ClassReader;
3834 import org.eclipse.persistence.internal.libraries.asm.Handle;
3935 import org.eclipse.persistence.internal.libraries.asm.Label;
4036 import org.eclipse.persistence.internal.libraries.asm.Opcodes;
5046 */
5147 public class Textifier extends Printer {
5248
53 /**
54 * Constant used in {@link #appendDescriptor appendDescriptor} for internal
55 * type names in bytecode notation.
56 */
57 public static final int INTERNAL_NAME = 0;
58
59 /**
60 * Constant used in {@link #appendDescriptor appendDescriptor} for field
61 * descriptors, formatted in bytecode notation
62 */
63 public static final int FIELD_DESCRIPTOR = 1;
64
65 /**
66 * Constant used in {@link #appendDescriptor appendDescriptor} for field
67 * signatures, formatted in bytecode notation
68 */
69 public static final int FIELD_SIGNATURE = 2;
70
71 /**
72 * Constant used in {@link #appendDescriptor appendDescriptor} for method
73 * descriptors, formatted in bytecode notation
74 */
75 public static final int METHOD_DESCRIPTOR = 3;
76
77 /**
78 * Constant used in {@link #appendDescriptor appendDescriptor} for method
79 * signatures, formatted in bytecode notation
80 */
81 public static final int METHOD_SIGNATURE = 4;
82
83 /**
84 * Constant used in {@link #appendDescriptor appendDescriptor} for class
85 * signatures, formatted in bytecode notation
86 */
87 public static final int CLASS_SIGNATURE = 5;
88
89 /**
90 * Constant used in {@link #appendDescriptor appendDescriptor} for field or
91 * method return value signatures, formatted in default Java notation
92 * (non-bytecode)
93 */
94 public static final int TYPE_DECLARATION = 6;
95
96 /**
97 * Constant used in {@link #appendDescriptor appendDescriptor} for class
98 * signatures, formatted in default Java notation (non-bytecode)
99 */
100 public static final int CLASS_DECLARATION = 7;
101
102 /**
103 * Constant used in {@link #appendDescriptor appendDescriptor} for method
104 * parameter signatures, formatted in default Java notation (non-bytecode)
105 */
106 public static final int PARAMETERS_DECLARATION = 8;
107
108 /**
109 * Constant used in {@link #appendDescriptor appendDescriptor} for handle
110 * descriptors, formatted in bytecode notation
111 */
112 public static final int HANDLE_DESCRIPTOR = 9;
113
114 /**
115 * Tab for class members.
116 */
117 protected String tab = " ";
118
119 /**
120 * Tab for bytecode instructions.
121 */
122 protected String tab2 = " ";
123
124 /**
125 * Tab for table and lookup switch instructions.
126 */
127 protected String tab3 = " ";
128
129 /**
130 * Tab for labels.
131 */
132 protected String ltab = " ";
133
134 /**
135 * The label names. This map associate String values to Label keys.
136 */
137 protected Map<Label, String> labelNames;
138
139 /**
140 * Class access flags
141 */
142 private int access;
143
144 private int valueNumber = 0;
145
146 /**
147 * Constructs a new {@link Textifier}. <i>Subclasses must not use this
148 * constructor</i>. Instead, they must use the {@link #Textifier(int)}
149 * version.
150 *
151 * @throws IllegalStateException
152 * If a subclass calls this constructor.
153 */
154 public Textifier() {
155 this(Opcodes.ASM6);
156 if (getClass() != Textifier.class) {
157 throw new IllegalStateException();
49 /** The type of internal names. See {@link #appendDescriptor}. */
50 public static final int INTERNAL_NAME = 0;
51
52 /** The type of field descriptors. See {@link #appendDescriptor}. */
53 public static final int FIELD_DESCRIPTOR = 1;
54
55 /** The type of field signatures. See {@link #appendDescriptor}. */
56 public static final int FIELD_SIGNATURE = 2;
57
58 /** The type of method descriptors. See {@link #appendDescriptor}. */
59 public static final int METHOD_DESCRIPTOR = 3;
60
61 /** The type of method signatures. See {@link #appendDescriptor}. */
62 public static final int METHOD_SIGNATURE = 4;
63
64 /** The type of class signatures. See {@link #appendDescriptor}. */
65 public static final int CLASS_SIGNATURE = 5;
66
67 /** @deprecated */
68 @Deprecated public static final int TYPE_DECLARATION = 6;
69
70 /** @deprecated */
71 @Deprecated public static final int CLASS_DECLARATION = 7;
72
73 /** @deprecated */
74 @Deprecated public static final int PARAMETERS_DECLARATION = 8;
75
76 /** The type of method handle descriptors. See {@link #appendDescriptor}. */
77 public static final int HANDLE_DESCRIPTOR = 9;
78
79 private static final String CLASS_SUFFIX = ".class";
80 private static final String DEPRECATED = "// DEPRECATED\n";
81 private static final String INVISIBLE = " // invisible\n";
82
83 /** The indentation of class members at depth level 1 (e.g. fields, methods). */
84 protected String tab = " ";
85
86 /** The indentation of class elements at depth level 2 (e.g. bytecode instructions in methods). */
87 protected String tab2 = " ";
88
89 /** The indentation of class elements at depth level 3 (e.g. switch cases in methods). */
90 protected String tab3 = " ";
91
92 /** The indentation of labels. */
93 protected String ltab = " ";
94
95 /** The names of the labels. */
96 protected Map<Label, String> labelNames;
97
98 /** The access flags of the visited class. */
99 private int access;
100
101 /** The number of annotation values visited so far. */
102 private int numAnnotationValues;
103
104 /**
105 * Constructs a new {@link Textifier}. <i>Subclasses must not use this constructor</i>. Instead,
106 * they must use the {@link #Textifier(int)} version.
107 *
108 * @throws IllegalStateException If a subclass calls this constructor.
109 */
110 public Textifier() {
111 this(Opcodes.ASM6);
112 if (getClass() != Textifier.class) {
113 throw new IllegalStateException();
114 }
115 }
116
117 /**
118 * Constructs a new {@link Textifier}.
119 *
120 * @param api the ASM API version implemented by this visitor. Must be one of {@link
121 * Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
122 */
123 protected Textifier(final int api) {
124 super(api);
125 }
126
127 /**
128 * Prints a disassembled view of the given class to the standard output.
129 *
130 * <p>Usage: Textifier [-debug] &lt;binary class name or class file name &gt;
131 *
132 * @param args the command line arguments.
133 * @throws IOException if the class cannot be found, or if an IOException occurs.
134 */
135 public static void main(final String[] args) throws IOException {
136 String usage =
137 "Prints a disassembled view of the given class.\n"
138 + "Usage: Textifier [-debug] <fully qualified class name or class file name>";
139 main(usage, new Textifier(), args);
140 }
141
142 // -----------------------------------------------------------------------------------------------
143 // Classes
144 // -----------------------------------------------------------------------------------------------
145
146 @Override
147 public void visit(
148 final int version,
149 final int access,
150 final String name,
151 final String signature,
152 final String superName,
153 final String[] interfaces) {
154 if ((access & Opcodes.ACC_MODULE) != 0) {
155 // Modules are printed in visitModule.
156 return;
157 }
158 this.access = access;
159 int majorVersion = version & 0xFFFF;
160 int minorVersion = version >>> 16;
161 stringBuilder.setLength(0);
162 stringBuilder
163 .append("// class version ")
164 .append(majorVersion)
165 .append('.')
166 .append(minorVersion)
167 .append(" (")
168 .append(version)
169 .append(")\n");
170 if ((access & Opcodes.ACC_DEPRECATED) != 0) {
171 stringBuilder.append(DEPRECATED);
172 }
173 appendRawAccess(access);
174
175 appendDescriptor(CLASS_SIGNATURE, signature);
176 if (signature != null) {
177 appendJavaDeclaration(signature);
178 }
179
180 appendAccess(access & ~(Opcodes.ACC_SUPER | Opcodes.ACC_MODULE));
181 if ((access & Opcodes.ACC_ANNOTATION) != 0) {
182 stringBuilder.append("@interface ");
183 } else if ((access & Opcodes.ACC_INTERFACE) != 0) {
184 stringBuilder.append("interface ");
185 } else if ((access & Opcodes.ACC_ENUM) == 0) {
186 stringBuilder.append("class ");
187 }
188 appendDescriptor(INTERNAL_NAME, name);
189
190 if (superName != null && !"java/lang/Object".equals(superName)) {
191 stringBuilder.append(" extends ");
192 appendDescriptor(INTERNAL_NAME, superName);
193 stringBuilder.append(' ');
194 }
195 if (interfaces != null && interfaces.length > 0) {
196 stringBuilder.append(" implements ");
197 for (int i = 0; i < interfaces.length; ++i) {
198 appendDescriptor(INTERNAL_NAME, interfaces[i]);
199 stringBuilder.append(' ');
200 }
201 }
202 stringBuilder.append(" {\n\n");
203
204 text.add(stringBuilder.toString());
205 }
206
207 @Override
208 public void visitSource(final String file, final String debug) {
209 stringBuilder.setLength(0);
210 if (file != null) {
211 stringBuilder.append(tab).append("// compiled from: ").append(file).append('\n');
212 }
213 if (debug != null) {
214 stringBuilder.append(tab).append("// debug info: ").append(debug).append('\n');
215 }
216 if (stringBuilder.length() > 0) {
217 text.add(stringBuilder.toString());
218 }
219 }
220
221 @Override
222 public Printer visitModule(final String name, final int access, final String version) {
223 stringBuilder.setLength(0);
224 if ((access & Opcodes.ACC_OPEN) != 0) {
225 stringBuilder.append("open ");
226 }
227 stringBuilder
228 .append("module ")
229 .append(name)
230 .append(" { ")
231 .append(version == null ? "" : "// " + version)
232 .append("\n\n");
233 text.add(stringBuilder.toString());
234 return addNewTextifier(null);
235 }
236
237 @Override
238 public void visitOuterClass(final String owner, final String name, final String descriptor) {
239 stringBuilder.setLength(0);
240 stringBuilder.append(tab).append("OUTERCLASS ");
241 appendDescriptor(INTERNAL_NAME, owner);
242 stringBuilder.append(' ');
243 if (name != null) {
244 stringBuilder.append(name).append(' ');
245 }
246 appendDescriptor(METHOD_DESCRIPTOR, descriptor);
247 stringBuilder.append('\n');
248 text.add(stringBuilder.toString());
249 }
250
251 @Override
252 public Textifier visitClassAnnotation(final String descriptor, final boolean visible) {
253 text.add("\n");
254 return visitAnnotation(descriptor, visible);
255 }
256
257 @Override
258 public Printer visitClassTypeAnnotation(
259 final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
260 text.add("\n");
261 return visitTypeAnnotation(typeRef, typePath, descriptor, visible);
262 }
263
264 @Override
265 public void visitClassAttribute(final Attribute attribute) {
266 text.add("\n");
267 visitAttribute(attribute);
268 }
269
270 @Override
271 public void visitInnerClass(
272 final String name, final String outerName, final String innerName, final int access) {
273 stringBuilder.setLength(0);
274 stringBuilder.append(tab);
275 appendRawAccess(access & ~Opcodes.ACC_SUPER);
276 stringBuilder.append(tab);
277 appendAccess(access);
278 stringBuilder.append("INNERCLASS ");
279 appendDescriptor(INTERNAL_NAME, name);
280 stringBuilder.append(' ');
281 appendDescriptor(INTERNAL_NAME, outerName);
282 stringBuilder.append(' ');
283 appendDescriptor(INTERNAL_NAME, innerName);
284 stringBuilder.append('\n');
285 text.add(stringBuilder.toString());
286 }
287
288 @Override
289 public Textifier visitField(
290 final int access,
291 final String name,
292 final String descriptor,
293 final String signature,
294 final Object value) {
295 stringBuilder.setLength(0);
296 stringBuilder.append('\n');
297 if ((access & Opcodes.ACC_DEPRECATED) != 0) {
298 stringBuilder.append(tab).append(DEPRECATED);
299 }
300 stringBuilder.append(tab);
301 appendRawAccess(access);
302 if (signature != null) {
303 stringBuilder.append(tab);
304 appendDescriptor(FIELD_SIGNATURE, signature);
305 stringBuilder.append(tab);
306 appendJavaDeclaration(signature);
307 }
308
309 stringBuilder.append(tab);
310 appendAccess(access);
311
312 appendDescriptor(FIELD_DESCRIPTOR, descriptor);
313 stringBuilder.append(' ').append(name);
314 if (value != null) {
315 stringBuilder.append(" = ");
316 if (value instanceof String) {
317 stringBuilder.append('\"').append(value).append('\"');
318 } else {
319 stringBuilder.append(value);
320 }
321 }
322
323 stringBuilder.append('\n');
324 text.add(stringBuilder.toString());
325 return addNewTextifier(null);
326 }
327
328 @Override
329 public Textifier visitMethod(
330 final int access,
331 final String name,
332 final String descriptor,
333 final String signature,
334 final String[] exceptions) {
335 stringBuilder.setLength(0);
336 stringBuilder.append('\n');
337 if ((access & Opcodes.ACC_DEPRECATED) != 0) {
338 stringBuilder.append(tab).append(DEPRECATED);
339 }
340 stringBuilder.append(tab);
341 appendRawAccess(access);
342
343 if (signature != null) {
344 stringBuilder.append(tab);
345 appendDescriptor(METHOD_SIGNATURE, signature);
346 stringBuilder.append(tab);
347 appendJavaDeclaration(signature);
348 }
349
350 stringBuilder.append(tab);
351 appendAccess(access & ~(Opcodes.ACC_VOLATILE | Opcodes.ACC_TRANSIENT));
352 if ((access & Opcodes.ACC_NATIVE) != 0) {
353 stringBuilder.append("native ");
354 }
355 if ((access & Opcodes.ACC_VARARGS) != 0) {
356 stringBuilder.append("varargs ");
357 }
358 if ((access & Opcodes.ACC_BRIDGE) != 0) {
359 stringBuilder.append("bridge ");
360 }
361 if ((this.access & Opcodes.ACC_INTERFACE) != 0
362 && (access & (Opcodes.ACC_ABSTRACT | Opcodes.ACC_STATIC)) == 0) {
363 stringBuilder.append("default ");
364 }
365
366 stringBuilder.append(name);
367 appendDescriptor(METHOD_DESCRIPTOR, descriptor);
368 if (exceptions != null && exceptions.length > 0) {
369 stringBuilder.append(" throws ");
370 for (int i = 0; i < exceptions.length; ++i) {
371 appendDescriptor(INTERNAL_NAME, exceptions[i]);
372 stringBuilder.append(' ');
373 }
374 }
375
376 stringBuilder.append('\n');
377 text.add(stringBuilder.toString());
378 return addNewTextifier(null);
379 }
380
381 @Override
382 public void visitClassEnd() {
383 text.add("}\n");
384 }
385
386 // -----------------------------------------------------------------------------------------------
387 // Modules
388 // -----------------------------------------------------------------------------------------------
389
390 @Override
391 public void visitMainClass(final String mainClass) {
392 stringBuilder.setLength(0);
393 stringBuilder.append(" // main class ").append(mainClass).append('\n');
394 text.add(stringBuilder.toString());
395 }
396
397 @Override
398 public void visitPackage(final String packaze) {
399 stringBuilder.setLength(0);
400 stringBuilder.append(" // package ").append(packaze).append('\n');
401 text.add(stringBuilder.toString());
402 }
403
404 @Override
405 public void visitRequire(final String require, final int access, final String version) {
406 stringBuilder.setLength(0);
407 stringBuilder.append(tab).append("requires ");
408 if ((access & Opcodes.ACC_TRANSITIVE) != 0) {
409 stringBuilder.append("transitive ");
410 }
411 if ((access & Opcodes.ACC_STATIC_PHASE) != 0) {
412 stringBuilder.append("static ");
413 }
414 stringBuilder.append(require).append(';');
415 appendRawAccess(access);
416 if (version != null) {
417 stringBuilder.append(" // version ").append(version).append('\n');
418 }
419 text.add(stringBuilder.toString());
420 }
421
422 @Override
423 public void visitExport(final String export, final int access, final String... modules) {
424 stringBuilder.setLength(0);
425 stringBuilder.append(tab).append("exports ");
426 stringBuilder.append(export);
427 if (modules != null && modules.length > 0) {
428 stringBuilder.append(" to");
429 } else {
430 stringBuilder.append(';');
431 }
432 appendRawAccess(access);
433 if (modules != null && modules.length > 0) {
434 for (int i = 0; i < modules.length; ++i) {
435 stringBuilder.append(tab2).append(modules[i]);
436 stringBuilder.append(i != modules.length - 1 ? ",\n" : ";\n");
437 }
438 }
439 text.add(stringBuilder.toString());
440 }
441
442 @Override
443 public void visitOpen(final String export, final int access, final String... modules) {
444 stringBuilder.setLength(0);
445 stringBuilder.append(tab).append("opens ");
446 stringBuilder.append(export);
447 if (modules != null && modules.length > 0) {
448 stringBuilder.append(" to");
449 } else {
450 stringBuilder.append(';');
451 }
452 appendRawAccess(access);
453 if (modules != null && modules.length > 0) {
454 for (int i = 0; i < modules.length; ++i) {
455 stringBuilder.append(tab2).append(modules[i]);
456 stringBuilder.append(i != modules.length - 1 ? ",\n" : ";\n");
457 }
458 }
459 text.add(stringBuilder.toString());
460 }
461
462 @Override
463 public void visitUse(final String use) {
464 stringBuilder.setLength(0);
465 stringBuilder.append(tab).append("uses ");
466 appendDescriptor(INTERNAL_NAME, use);
467 stringBuilder.append(";\n");
468 text.add(stringBuilder.toString());
469 }
470
471 @Override
472 public void visitProvide(final String provide, final String... providers) {
473 stringBuilder.setLength(0);
474 stringBuilder.append(tab).append("provides ");
475 appendDescriptor(INTERNAL_NAME, provide);
476 stringBuilder.append(" with\n");
477 for (int i = 0; i < providers.length; ++i) {
478 stringBuilder.append(tab2);
479 appendDescriptor(INTERNAL_NAME, providers[i]);
480 stringBuilder.append(i != providers.length - 1 ? ",\n" : ";\n");
481 }
482 text.add(stringBuilder.toString());
483 }
484
485 @Override
486 public void visitModuleEnd() {
487 // Nothing to do.
488 }
489
490 // -----------------------------------------------------------------------------------------------
491 // Annotations
492 // -----------------------------------------------------------------------------------------------
493
494 @Override
495 public void visit(final String name, final Object value) {
496 visitAnnotationValue(name);
497 if (value instanceof String) {
498 visitString((String) value);
499 } else if (value instanceof Type) {
500 visitType((Type) value);
501 } else if (value instanceof Byte) {
502 visitByte(((Byte) value).byteValue());
503 } else if (value instanceof Boolean) {
504 visitBoolean(((Boolean) value).booleanValue());
505 } else if (value instanceof Short) {
506 visitShort(((Short) value).shortValue());
507 } else if (value instanceof Character) {
508 visitChar(((Character) value).charValue());
509 } else if (value instanceof Integer) {
510 visitInt(((Integer) value).intValue());
511 } else if (value instanceof Float) {
512 visitFloat(((Float) value).floatValue());
513 } else if (value instanceof Long) {
514 visitLong(((Long) value).longValue());
515 } else if (value instanceof Double) {
516 visitDouble(((Double) value).doubleValue());
517 } else if (value.getClass().isArray()) {
518 stringBuilder.append('{');
519 if (value instanceof byte[]) {
520 byte[] byteArray = (byte[]) value;
521 for (int i = 0; i < byteArray.length; i++) {
522 maybeAppendComma(i);
523 visitByte(byteArray[i]);
158524 }
159 }
160
161 /**
162 * Constructs a new {@link Textifier}.
163 *
164 * @param api
165 * the ASM API version implemented by this visitor. Must be one
166 * of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
167 */
168 protected Textifier(final int api) {
169 super(api);
170 }
171
172 /**
173 * Prints a disassembled view of the given class to the standard output.
174 * <p>
175 * Usage: Textifier [-debug] &lt;binary class name or class file name &gt;
176 *
177 * @param args
178 * the command line arguments.
179 *
180 * @throws Exception
181 * if the class cannot be found, or if an IO exception occurs.
182 */
183 public static void main(final String[] args) throws Exception {
184 int i = 0;
185 int flags = ClassReader.SKIP_DEBUG;
186
187 boolean ok = true;
188 if (args.length < 1 || args.length > 2) {
189 ok = false;
525 } else if (value instanceof boolean[]) {
526 boolean[] booleanArray = (boolean[]) value;
527 for (int i = 0; i < booleanArray.length; i++) {
528 maybeAppendComma(i);
529 visitBoolean(booleanArray[i]);
190530 }
191 if (ok && "-debug".equals(args[0])) {
192 i = 1;
193 flags = 0;
194 if (args.length != 2) {
195 ok = false;
196 }
531 } else if (value instanceof short[]) {
532 short[] shortArray = (short[]) value;
533 for (int i = 0; i < shortArray.length; i++) {
534 maybeAppendComma(i);
535 visitShort(shortArray[i]);
197536 }
198 if (!ok) {
199 System.err
200 .println("Prints a disassembled view of the given class.");
201 System.err.println("Usage: Textifier [-debug] "
202 + "<fully qualified class name or class file name>");
203 return;
537 } else if (value instanceof char[]) {
538 char[] charArray = (char[]) value;
539 for (int i = 0; i < charArray.length; i++) {
540 maybeAppendComma(i);
541 visitChar(charArray[i]);
204542 }
205 ClassReader cr;
206 if (args[i].endsWith(".class") || args[i].indexOf('\\') > -1
207 || args[i].indexOf('/') > -1) {
208 cr = new ClassReader(new FileInputStream(args[i]));
543 } else if (value instanceof int[]) {
544 int[] intArray = (int[]) value;
545 for (int i = 0; i < intArray.length; i++) {
546 maybeAppendComma(i);
547 visitInt(intArray[i]);
548 }
549 } else if (value instanceof long[]) {
550 long[] longArray = (long[]) value;
551 for (int i = 0; i < longArray.length; i++) {
552 maybeAppendComma(i);
553 visitLong(longArray[i]);
554 }
555 } else if (value instanceof float[]) {
556 float[] floatArray = (float[]) value;
557 for (int i = 0; i < floatArray.length; i++) {
558 maybeAppendComma(i);
559 visitFloat(floatArray[i]);
560 }
561 } else if (value instanceof double[]) {
562 double[] doubleArray = (double[]) value;
563 for (int i = 0; i < doubleArray.length; i++) {
564 maybeAppendComma(i);
565 visitDouble(doubleArray[i]);
566 }
567 }
568 stringBuilder.append('}');
569 }
570 text.add(stringBuilder.toString());
571 }
572
573 private void visitInt(final int value) {
574 stringBuilder.append(value);
575 }
576
577 private void visitLong(final long value) {
578 stringBuilder.append(value).append('L');
579 }
580
581 private void visitFloat(final float value) {
582 stringBuilder.append(value).append('F');
583 }
584
585 private void visitDouble(final double value) {
586 stringBuilder.append(value).append('D');
587 }
588
589 private void visitChar(final char value) {
590 stringBuilder.append("(char)").append((int) value);
591 }
592
593 private void visitShort(final short value) {
594 stringBuilder.append("(short)").append(value);
595 }
596
597 private void visitByte(final byte value) {
598 stringBuilder.append("(byte)").append(value);
599 }
600
601 private void visitBoolean(final boolean value) {
602 stringBuilder.append(value);
603 }
604
605 private void visitString(final String value) {
606 appendString(stringBuilder, value);
607 }
608
609 private void visitType(final Type value) {
610 stringBuilder.append(value.getClassName()).append(CLASS_SUFFIX);
611 }
612
613 @Override
614 public void visitEnum(final String name, final String descriptor, final String value) {
615 visitAnnotationValue(name);
616 appendDescriptor(FIELD_DESCRIPTOR, descriptor);
617 stringBuilder.append('.').append(value);
618 text.add(stringBuilder.toString());
619 }
620
621 @Override
622 public Textifier visitAnnotation(final String name, final String descriptor) {
623 visitAnnotationValue(name);
624 stringBuilder.append('@');
625 appendDescriptor(FIELD_DESCRIPTOR, descriptor);
626 stringBuilder.append('(');
627 text.add(stringBuilder.toString());
628 return addNewTextifier(")");
629 }
630
631 @Override
632 public Textifier visitArray(final String name) {
633 visitAnnotationValue(name);
634 stringBuilder.append('{');
635 text.add(stringBuilder.toString());
636 return addNewTextifier("}");
637 }
638
639 @Override
640 public void visitAnnotationEnd() {
641 // Nothing to do.
642 }
643
644 private void visitAnnotationValue(final String name) {
645 stringBuilder.setLength(0);
646 maybeAppendComma(numAnnotationValues++);
647 if (name != null) {
648 stringBuilder.append(name).append('=');
649 }
650 }
651
652 // -----------------------------------------------------------------------------------------------
653 // Fields
654 // -----------------------------------------------------------------------------------------------
655
656 @Override
657 public Textifier visitFieldAnnotation(final String descriptor, final boolean visible) {
658 return visitAnnotation(descriptor, visible);
659 }
660
661 @Override
662 public Printer visitFieldTypeAnnotation(
663 final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
664 return visitTypeAnnotation(typeRef, typePath, descriptor, visible);
665 }
666
667 @Override
668 public void visitFieldAttribute(final Attribute attribute) {
669 visitAttribute(attribute);
670 }
671
672 @Override
673 public void visitFieldEnd() {
674 // Nothing to do.
675 }
676
677 // -----------------------------------------------------------------------------------------------
678 // Methods
679 // -----------------------------------------------------------------------------------------------
680
681 @Override
682 public void visitParameter(final String name, final int access) {
683 stringBuilder.setLength(0);
684 stringBuilder.append(tab2).append("// parameter ");
685 appendAccess(access);
686 stringBuilder.append(' ').append((name == null) ? "<no name>" : name).append('\n');
687 text.add(stringBuilder.toString());
688 }
689
690 @Override
691 public Textifier visitAnnotationDefault() {
692 text.add(tab2 + "default=");
693 return addNewTextifier("\n");
694 }
695
696 @Override
697 public Textifier visitMethodAnnotation(final String descriptor, final boolean visible) {
698 return visitAnnotation(descriptor, visible);
699 }
700
701 @Override
702 public Printer visitMethodTypeAnnotation(
703 final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
704 return visitTypeAnnotation(typeRef, typePath, descriptor, visible);
705 }
706
707 @Override
708 public Textifier visitAnnotableParameterCount(final int parameterCount, final boolean visible) {
709 stringBuilder.setLength(0);
710 stringBuilder.append(tab2).append("// annotable parameter count: ");
711 stringBuilder.append(parameterCount);
712 stringBuilder.append(visible ? " (visible)\n" : " (invisible)\n");
713 text.add(stringBuilder.toString());
714 return this;
715 }
716
717 @Override
718 public Textifier visitParameterAnnotation(
719 final int parameter, final String descriptor, final boolean visible) {
720 stringBuilder.setLength(0);
721 stringBuilder.append(tab2).append('@');
722 appendDescriptor(FIELD_DESCRIPTOR, descriptor);
723 stringBuilder.append('(');
724 text.add(stringBuilder.toString());
725
726 stringBuilder.setLength(0);
727 stringBuilder
728 .append(visible ? ") // parameter " : ") // invisible, parameter ")
729 .append(parameter)
730 .append('\n');
731 return addNewTextifier(stringBuilder.toString());
732 }
733
734 @Override
735 public void visitMethodAttribute(final Attribute attribute) {
736 stringBuilder.setLength(0);
737 stringBuilder.append(tab).append("ATTRIBUTE ");
738 appendDescriptor(-1, attribute.type);
739
740 if (attribute instanceof Textifiable) {
741 StringBuffer stringBuffer = new StringBuffer();
742 ((Textifiable) attribute).textify(stringBuffer, labelNames);
743 stringBuilder.append(stringBuffer.toString());
744 } else {
745 stringBuilder.append(" : unknown\n");
746 }
747
748 text.add(stringBuilder.toString());
749 }
750
751 @Override
752 public void visitCode() {
753 // Nothing to do.
754 }
755
756 @Override
757 public void visitFrame(
758 final int type,
759 final int nLocal,
760 final Object[] local,
761 final int nStack,
762 final Object[] stack) {
763 stringBuilder.setLength(0);
764 stringBuilder.append(ltab);
765 stringBuilder.append("FRAME ");
766 switch (type) {
767 case Opcodes.F_NEW:
768 case Opcodes.F_FULL:
769 stringBuilder.append("FULL [");
770 appendFrameTypes(nLocal, local);
771 stringBuilder.append("] [");
772 appendFrameTypes(nStack, stack);
773 stringBuilder.append(']');
774 break;
775 case Opcodes.F_APPEND:
776 stringBuilder.append("APPEND [");
777 appendFrameTypes(nLocal, local);
778 stringBuilder.append(']');
779 break;
780 case Opcodes.F_CHOP:
781 stringBuilder.append("CHOP ").append(nLocal);
782 break;
783 case Opcodes.F_SAME:
784 stringBuilder.append("SAME");
785 break;
786 case Opcodes.F_SAME1:
787 stringBuilder.append("SAME1 ");
788 appendFrameTypes(1, stack);
789 break;
790 default:
791 throw new IllegalArgumentException();
792 }
793 stringBuilder.append('\n');
794 text.add(stringBuilder.toString());
795 }
796
797 @Override
798 public void visitInsn(final int opcode) {
799 stringBuilder.setLength(0);
800 stringBuilder.append(tab2).append(OPCODES[opcode]).append('\n');
801 text.add(stringBuilder.toString());
802 }
803
804 @Override
805 public void visitIntInsn(final int opcode, final int operand) {
806 stringBuilder.setLength(0);
807 stringBuilder
808 .append(tab2)
809 .append(OPCODES[opcode])
810 .append(' ')
811 .append(opcode == Opcodes.NEWARRAY ? TYPES[operand] : Integer.toString(operand))
812 .append('\n');
813 text.add(stringBuilder.toString());
814 }
815
816 @Override
817 public void visitVarInsn(final int opcode, final int var) {
818 stringBuilder.setLength(0);
819 stringBuilder.append(tab2).append(OPCODES[opcode]).append(' ').append(var).append('\n');
820 text.add(stringBuilder.toString());
821 }
822
823 @Override
824 public void visitTypeInsn(final int opcode, final String type) {
825 stringBuilder.setLength(0);
826 stringBuilder.append(tab2).append(OPCODES[opcode]).append(' ');
827 appendDescriptor(INTERNAL_NAME, type);
828 stringBuilder.append('\n');
829 text.add(stringBuilder.toString());
830 }
831
832 @Override
833 public void visitFieldInsn(
834 final int opcode, final String owner, final String name, final String descriptor) {
835 stringBuilder.setLength(0);
836 stringBuilder.append(tab2).append(OPCODES[opcode]).append(' ');
837 appendDescriptor(INTERNAL_NAME, owner);
838 stringBuilder.append('.').append(name).append(" : ");
839 appendDescriptor(FIELD_DESCRIPTOR, descriptor);
840 stringBuilder.append('\n');
841 text.add(stringBuilder.toString());
842 }
843
844 /** @deprecated */
845 @Deprecated
846 @Override
847 public void visitMethodInsn(
848 final int opcode, final String owner, final String name, final String descriptor) {
849 if (api >= Opcodes.ASM5) {
850 super.visitMethodInsn(opcode, owner, name, descriptor);
851 return;
852 }
853 doVisitMethodInsn(opcode, owner, name, descriptor, opcode == Opcodes.INVOKEINTERFACE);
854 }
855
856 @Override
857 public void visitMethodInsn(
858 final int opcode,
859 final String owner,
860 final String name,
861 final String descriptor,
862 final boolean isInterface) {
863 if (api < Opcodes.ASM5) {
864 super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
865 return;
866 }
867 doVisitMethodInsn(opcode, owner, name, descriptor, isInterface);
868 }
869
870 private void doVisitMethodInsn(
871 final int opcode,
872 final String owner,
873 final String name,
874 final String descriptor,
875 final boolean isInterface) {
876 stringBuilder.setLength(0);
877 stringBuilder.append(tab2).append(OPCODES[opcode]).append(' ');
878 appendDescriptor(INTERNAL_NAME, owner);
879 stringBuilder.append('.').append(name).append(' ');
880 appendDescriptor(METHOD_DESCRIPTOR, descriptor);
881 if (isInterface) {
882 stringBuilder.append(" (itf)");
883 }
884 stringBuilder.append('\n');
885 text.add(stringBuilder.toString());
886 }
887
888 @Override
889 public void visitInvokeDynamicInsn(
890 final String name,
891 final String descriptor,
892 final Handle bootstrapMethodHandle,
893 final Object... bootstrapMethodArguments) {
894 stringBuilder.setLength(0);
895 stringBuilder.append(tab2).append("INVOKEDYNAMIC").append(' ');
896 stringBuilder.append(name);
897 appendDescriptor(METHOD_DESCRIPTOR, descriptor);
898 stringBuilder.append(" [");
899 stringBuilder.append('\n');
900 stringBuilder.append(tab3);
901 appendHandle(bootstrapMethodHandle);
902 stringBuilder.append('\n');
903 stringBuilder.append(tab3).append("// arguments:");
904 if (bootstrapMethodArguments.length == 0) {
905 stringBuilder.append(" none");
906 } else {
907 stringBuilder.append('\n');
908 for (int i = 0; i < bootstrapMethodArguments.length; i++) {
909 stringBuilder.append(tab3);
910 Object value = bootstrapMethodArguments[i];
911 if (value instanceof String) {
912 Printer.appendString(stringBuilder, (String) value);
913 } else if (value instanceof Type) {
914 Type type = (Type) value;
915 if (type.getSort() == Type.METHOD) {
916 appendDescriptor(METHOD_DESCRIPTOR, type.getDescriptor());
917 } else {
918 visitType(type);
919 }
920 } else if (value instanceof Handle) {
921 appendHandle((Handle) value);
209922 } else {
210 cr = new ClassReader(args[i]);
923 stringBuilder.append(value);
211924 }
212 cr.accept(new TraceClassVisitor(new PrintWriter(System.out)), flags);
213 }
214
215 // ------------------------------------------------------------------------
216 // Classes
217 // ------------------------------------------------------------------------
218
219 @Override
220 public void visit(final int version, final int access, final String name,
221 final String signature, final String superName,
222 final String[] interfaces) {
223 this.access = access;
224 int major = version & 0xFFFF;
225 int minor = version >>> 16;
226 buf.setLength(0);
227 buf.append("// class version ").append(major).append('.').append(minor)
228 .append(" (").append(version).append(")\n");
229 if ((access & Opcodes.ACC_DEPRECATED) != 0) {
230 buf.append("// DEPRECATED\n");
925 stringBuilder.append(", \n");
926 }
927 stringBuilder.setLength(stringBuilder.length() - 3);
928 }
929 stringBuilder.append('\n');
930 stringBuilder.append(tab2).append("]\n");
931 text.add(stringBuilder.toString());
932 }
933
934 @Override
935 public void visitJumpInsn(final int opcode, final Label label) {
936 stringBuilder.setLength(0);
937 stringBuilder.append(tab2).append(OPCODES[opcode]).append(' ');
938 appendLabel(label);
939 stringBuilder.append('\n');
940 text.add(stringBuilder.toString());
941 }
942
943 @Override
944 public void visitLabel(final Label label) {
945 stringBuilder.setLength(0);
946 stringBuilder.append(ltab);
947 appendLabel(label);
948 stringBuilder.append('\n');
949 text.add(stringBuilder.toString());
950 }
951
952 @Override
953 public void visitLdcInsn(final Object value) {
954 stringBuilder.setLength(0);
955 stringBuilder.append(tab2).append("LDC ");
956 if (value instanceof String) {
957 Printer.appendString(stringBuilder, (String) value);
958 } else if (value instanceof Type) {
959 stringBuilder.append(((Type) value).getDescriptor()).append(CLASS_SUFFIX);
960 } else {
961 stringBuilder.append(value);
962 }
963 stringBuilder.append('\n');
964 text.add(stringBuilder.toString());
965 }
966
967 @Override
968 public void visitIincInsn(final int var, final int increment) {
969 stringBuilder.setLength(0);
970 stringBuilder
971 .append(tab2)
972 .append("IINC ")
973 .append(var)
974 .append(' ')
975 .append(increment)
976 .append('\n');
977 text.add(stringBuilder.toString());
978 }
979
980 @Override
981 public void visitTableSwitchInsn(
982 final int min, final int max, final Label dflt, final Label... labels) {
983 stringBuilder.setLength(0);
984 stringBuilder.append(tab2).append("TABLESWITCH\n");
985 for (int i = 0; i < labels.length; ++i) {
986 stringBuilder.append(tab3).append(min + i).append(": ");
987 appendLabel(labels[i]);
988 stringBuilder.append('\n');
989 }
990 stringBuilder.append(tab3).append("default: ");
991 appendLabel(dflt);
992 stringBuilder.append('\n');
993 text.add(stringBuilder.toString());
994 }
995
996 @Override
997 public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) {
998 stringBuilder.setLength(0);
999 stringBuilder.append(tab2).append("LOOKUPSWITCH\n");
1000 for (int i = 0; i < labels.length; ++i) {
1001 stringBuilder.append(tab3).append(keys[i]).append(": ");
1002 appendLabel(labels[i]);
1003 stringBuilder.append('\n');
1004 }
1005 stringBuilder.append(tab3).append("default: ");
1006 appendLabel(dflt);
1007 stringBuilder.append('\n');
1008 text.add(stringBuilder.toString());
1009 }
1010
1011 @Override
1012 public void visitMultiANewArrayInsn(final String descriptor, final int numDimensions) {
1013 stringBuilder.setLength(0);
1014 stringBuilder.append(tab2).append("MULTIANEWARRAY ");
1015 appendDescriptor(FIELD_DESCRIPTOR, descriptor);
1016 stringBuilder.append(' ').append(numDimensions).append('\n');
1017 text.add(stringBuilder.toString());
1018 }
1019
1020 @Override
1021 public Printer visitInsnAnnotation(
1022 final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
1023 return visitTypeAnnotation(typeRef, typePath, descriptor, visible);
1024 }
1025
1026 @Override
1027 public void visitTryCatchBlock(
1028 final Label start, final Label end, final Label handler, final String type) {
1029 stringBuilder.setLength(0);
1030 stringBuilder.append(tab2).append("TRYCATCHBLOCK ");
1031 appendLabel(start);
1032 stringBuilder.append(' ');
1033 appendLabel(end);
1034 stringBuilder.append(' ');
1035 appendLabel(handler);
1036 stringBuilder.append(' ');
1037 appendDescriptor(INTERNAL_NAME, type);
1038 stringBuilder.append('\n');
1039 text.add(stringBuilder.toString());
1040 }
1041
1042 @Override
1043 public Printer visitTryCatchAnnotation(
1044 final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
1045 stringBuilder.setLength(0);
1046 stringBuilder.append(tab2).append("TRYCATCHBLOCK @");
1047 appendDescriptor(FIELD_DESCRIPTOR, descriptor);
1048 stringBuilder.append('(');
1049 text.add(stringBuilder.toString());
1050
1051 stringBuilder.setLength(0);
1052 stringBuilder.append(") : ");
1053 appendTypeReference(typeRef);
1054 stringBuilder.append(", ").append(typePath);
1055 stringBuilder.append(visible ? "\n" : INVISIBLE);
1056 return addNewTextifier(stringBuilder.toString());
1057 }
1058
1059 @Override
1060 public void visitLocalVariable(
1061 final String name,
1062 final String descriptor,
1063 final String signature,
1064 final Label start,
1065 final Label end,
1066 final int index) {
1067 stringBuilder.setLength(0);
1068 stringBuilder.append(tab2).append("LOCALVARIABLE ").append(name).append(' ');
1069 appendDescriptor(FIELD_DESCRIPTOR, descriptor);
1070 stringBuilder.append(' ');
1071 appendLabel(start);
1072 stringBuilder.append(' ');
1073 appendLabel(end);
1074 stringBuilder.append(' ').append(index).append('\n');
1075
1076 if (signature != null) {
1077 stringBuilder.append(tab2);
1078 appendDescriptor(FIELD_SIGNATURE, signature);
1079 stringBuilder.append(tab2);
1080 appendJavaDeclaration(signature);
1081 }
1082 text.add(stringBuilder.toString());
1083 }
1084
1085 @Override
1086 public Printer visitLocalVariableAnnotation(
1087 final int typeRef,
1088 final TypePath typePath,
1089 final Label[] start,
1090 final Label[] end,
1091 final int[] index,
1092 final String descriptor,
1093 final boolean visible) {
1094 stringBuilder.setLength(0);
1095 stringBuilder.append(tab2).append("LOCALVARIABLE @");
1096 appendDescriptor(FIELD_DESCRIPTOR, descriptor);
1097 stringBuilder.append('(');
1098 text.add(stringBuilder.toString());
1099
1100 stringBuilder.setLength(0);
1101 stringBuilder.append(") : ");
1102 appendTypeReference(typeRef);
1103 stringBuilder.append(", ").append(typePath);
1104 for (int i = 0; i < start.length; ++i) {
1105 stringBuilder.append(" [ ");
1106 appendLabel(start[i]);
1107 stringBuilder.append(" - ");
1108 appendLabel(end[i]);
1109 stringBuilder.append(" - ").append(index[i]).append(" ]");
1110 }
1111 stringBuilder.append(visible ? "\n" : INVISIBLE);
1112 return addNewTextifier(stringBuilder.toString());
1113 }
1114
1115 @Override
1116 public void visitLineNumber(final int line, final Label start) {
1117 stringBuilder.setLength(0);
1118 stringBuilder.append(tab2).append("LINENUMBER ").append(line).append(' ');
1119 appendLabel(start);
1120 stringBuilder.append('\n');
1121 text.add(stringBuilder.toString());
1122 }
1123
1124 @Override
1125 public void visitMaxs(final int maxStack, final int maxLocals) {
1126 stringBuilder.setLength(0);
1127 stringBuilder.append(tab2).append("MAXSTACK = ").append(maxStack).append('\n');
1128 text.add(stringBuilder.toString());
1129
1130 stringBuilder.setLength(0);
1131 stringBuilder.append(tab2).append("MAXLOCALS = ").append(maxLocals).append('\n');
1132 text.add(stringBuilder.toString());
1133 }
1134
1135 @Override
1136 public void visitMethodEnd() {
1137 // Nothing to do.
1138 }
1139
1140 // -----------------------------------------------------------------------------------------------
1141 // Common methods
1142 // -----------------------------------------------------------------------------------------------
1143
1144 /**
1145 * Prints a disassembled view of the given annotation.
1146 *
1147 * @param descriptor the class descriptor of the annotation class.
1148 * @param visible <tt>true</tt> if the annotation is visible at runtime.
1149 * @return a visitor to visit the annotation values.
1150 */
1151 public Textifier visitAnnotation(final String descriptor, final boolean visible) {
1152 stringBuilder.setLength(0);
1153 stringBuilder.append(tab).append('@');
1154 appendDescriptor(FIELD_DESCRIPTOR, descriptor);
1155 stringBuilder.append('(');
1156 text.add(stringBuilder.toString());
1157 return addNewTextifier(visible ? ")\n" : ") // invisible\n");
1158 }
1159
1160 /**
1161 * Prints a disassembled view of the given type annotation.
1162 *
1163 * @param typeRef a reference to the annotated type. See {@link TypeReference}.
1164 * @param typePath the path to the annotated type argument, wildcard bound, array element type, or
1165 * static inner type within 'typeRef'. May be <tt>null</tt> if the annotation targets
1166 * 'typeRef' as a whole.
1167 * @param descriptor the class descriptor of the annotation class.
1168 * @param visible <tt>true</tt> if the annotation is visible at runtime.
1169 * @return a visitor to visit the annotation values.
1170 */
1171 public Textifier visitTypeAnnotation(
1172 final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
1173 stringBuilder.setLength(0);
1174 stringBuilder.append(tab).append('@');
1175 appendDescriptor(FIELD_DESCRIPTOR, descriptor);
1176 stringBuilder.append('(');
1177 text.add(stringBuilder.toString());
1178
1179 stringBuilder.setLength(0);
1180 stringBuilder.append(") : ");
1181 appendTypeReference(typeRef);
1182 stringBuilder.append(", ").append(typePath);
1183 stringBuilder.append(visible ? "\n" : INVISIBLE);
1184 return addNewTextifier(stringBuilder.toString());
1185 }
1186
1187 /**
1188 * Prints a disassembled view of the given attribute.
1189 *
1190 * @param attribute an attribute.
1191 */
1192 public void visitAttribute(final Attribute attribute) {
1193 stringBuilder.setLength(0);
1194 stringBuilder.append(tab).append("ATTRIBUTE ");
1195 appendDescriptor(-1, attribute.type);
1196
1197 if (attribute instanceof Textifiable) {
1198 StringBuffer stringBuffer = new StringBuffer();
1199 ((Textifiable) attribute).textify(stringBuffer, null);
1200 stringBuilder.append(stringBuffer.toString());
1201 } else {
1202 stringBuilder.append(" : unknown\n");
1203 }
1204
1205 text.add(stringBuilder.toString());
1206 }
1207
1208 // -----------------------------------------------------------------------------------------------
1209 // Utility methods
1210 // -----------------------------------------------------------------------------------------------
1211
1212 /**
1213 * Appends a string representation of the given access flags to {@link #stringBuilder}.
1214 *
1215 * @param accessFlags some access flags.
1216 */
1217 private void appendAccess(final int accessFlags) {
1218 if ((accessFlags & Opcodes.ACC_PUBLIC) != 0) {
1219 stringBuilder.append("public ");
1220 }
1221 if ((accessFlags & Opcodes.ACC_PRIVATE) != 0) {
1222 stringBuilder.append("private ");
1223 }
1224 if ((accessFlags & Opcodes.ACC_PROTECTED) != 0) {
1225 stringBuilder.append("protected ");
1226 }
1227 if ((accessFlags & Opcodes.ACC_FINAL) != 0) {
1228 stringBuilder.append("final ");
1229 }
1230 if ((accessFlags & Opcodes.ACC_STATIC) != 0) {
1231 stringBuilder.append("static ");
1232 }
1233 if ((accessFlags & Opcodes.ACC_SYNCHRONIZED) != 0) {
1234 stringBuilder.append("synchronized ");
1235 }
1236 if ((accessFlags & Opcodes.ACC_VOLATILE) != 0) {
1237 stringBuilder.append("volatile ");
1238 }
1239 if ((accessFlags & Opcodes.ACC_TRANSIENT) != 0) {
1240 stringBuilder.append("transient ");
1241 }
1242 if ((accessFlags & Opcodes.ACC_ABSTRACT) != 0) {
1243 stringBuilder.append("abstract ");
1244 }
1245 if ((accessFlags & Opcodes.ACC_STRICT) != 0) {
1246 stringBuilder.append("strictfp ");
1247 }
1248 if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0) {
1249 stringBuilder.append("synthetic ");
1250 }
1251 if ((accessFlags & Opcodes.ACC_MANDATED) != 0) {
1252 stringBuilder.append("mandated ");
1253 }
1254 if ((accessFlags & Opcodes.ACC_ENUM) != 0) {
1255 stringBuilder.append("enum ");
1256 }
1257 }
1258
1259 /**
1260 * Appends the hexadecimal value of the given access flags to {@link #stringBuilder}.
1261 *
1262 * @param accessFlags some access flags.
1263 */
1264 private void appendRawAccess(final int accessFlags) {
1265 stringBuilder
1266 .append("// access flags 0x")
1267 .append(Integer.toHexString(accessFlags).toUpperCase())
1268 .append('\n');
1269 }
1270
1271 /**
1272 * Appends an internal name, a type descriptor or a type signature to {@link #stringBuilder}.
1273 *
1274 * @param type the type of 'value'. Must be one of {@link #INTERNAL_NAME}, {@link
1275 * #FIELD_DESCRIPTOR}, {@link #FIELD_SIGNATURE}, {@link #METHOD_DESCRIPTOR}, {@link
1276 * #METHOD_SIGNATURE}, {@link #CLASS_SIGNATURE}, {@link #TYPE_DECLARATION}, {@link
1277 * #CLASS_DECLARATION}, {@link #PARAMETERS_DECLARATION} of {@link #HANDLE_DESCRIPTOR}.
1278 * @param value an internal name, type descriptor or a type signature. May be <tt>null</tt>.
1279 */
1280 protected void appendDescriptor(final int type, final String value) {
1281 if (type == CLASS_SIGNATURE || type == FIELD_SIGNATURE || type == METHOD_SIGNATURE) {
1282 if (value != null) {
1283 stringBuilder.append("// signature ").append(value).append('\n');
1284 }
1285 } else {
1286 stringBuilder.append(value);
1287 }
1288 }
1289
1290 /**
1291 * Appends the Java generic type declaration corresponding to the given signature.
1292 *
1293 * @param signature a class, field or method signature.
1294 */
1295 private void appendJavaDeclaration(final String signature) {
1296 TraceSignatureVisitor traceSignatureVisitor = new TraceSignatureVisitor(access);
1297 new SignatureReader(signature).accept(traceSignatureVisitor);
1298 stringBuilder.append("// declaration: ");
1299 if (traceSignatureVisitor.getReturnType() != null) {
1300 stringBuilder.append(traceSignatureVisitor.getReturnType());
1301 stringBuilder.append(' ');
1302 }
1303 stringBuilder.append(traceSignatureVisitor.getDeclaration());
1304 if (traceSignatureVisitor.getExceptions() != null) {
1305 stringBuilder.append(" throws ").append(traceSignatureVisitor.getExceptions());
1306 }
1307 stringBuilder.append('\n');
1308 }
1309
1310 /**
1311 * Appends the name of the given label to {@link #stringBuilder}. Constructs a new label name if
1312 * the given label does not yet have one.
1313 *
1314 * @param label a label.
1315 */
1316 protected void appendLabel(final Label label) {
1317 if (labelNames == null) {
1318 labelNames = new HashMap<Label, String>();
1319 }
1320 String name = labelNames.get(label);
1321 if (name == null) {
1322 name = "L" + labelNames.size();
1323 labelNames.put(label, name);
1324 }
1325 stringBuilder.append(name);
1326 }
1327
1328 /**
1329 * Appends a string representation of the given handle to {@link #stringBuilder}.
1330 *
1331 * @param handle a handle.
1332 */
1333 protected void appendHandle(final Handle handle) {
1334 int tag = handle.getTag();
1335 stringBuilder.append("// handle kind 0x").append(Integer.toHexString(tag)).append(" : ");
1336 boolean isMethodHandle = false;
1337 switch (tag) {
1338 case Opcodes.H_GETFIELD:
1339 stringBuilder.append("GETFIELD");
1340 break;
1341 case Opcodes.H_GETSTATIC:
1342 stringBuilder.append("GETSTATIC");
1343 break;
1344 case Opcodes.H_PUTFIELD:
1345 stringBuilder.append("PUTFIELD");
1346 break;
1347 case Opcodes.H_PUTSTATIC:
1348 stringBuilder.append("PUTSTATIC");
1349 break;
1350 case Opcodes.H_INVOKEINTERFACE:
1351 stringBuilder.append("INVOKEINTERFACE");
1352 isMethodHandle = true;
1353 break;
1354 case Opcodes.H_INVOKESPECIAL:
1355 stringBuilder.append("INVOKESPECIAL");
1356 isMethodHandle = true;
1357 break;
1358 case Opcodes.H_INVOKESTATIC:
1359 stringBuilder.append("INVOKESTATIC");
1360 isMethodHandle = true;
1361 break;
1362 case Opcodes.H_INVOKEVIRTUAL:
1363 stringBuilder.append("INVOKEVIRTUAL");
1364 isMethodHandle = true;
1365 break;
1366 case Opcodes.H_NEWINVOKESPECIAL:
1367 stringBuilder.append("NEWINVOKESPECIAL");
1368 isMethodHandle = true;
1369 break;
1370 default:
1371 throw new IllegalArgumentException();
1372 }
1373 stringBuilder.append('\n');
1374 stringBuilder.append(tab3);
1375 appendDescriptor(INTERNAL_NAME, handle.getOwner());
1376 stringBuilder.append('.');
1377 stringBuilder.append(handle.getName());
1378 if (!isMethodHandle) {
1379 stringBuilder.append('(');
1380 }
1381 appendDescriptor(HANDLE_DESCRIPTOR, handle.getDesc());
1382 if (!isMethodHandle) {
1383 stringBuilder.append(')');
1384 }
1385 if (handle.isInterface()) {
1386 stringBuilder.append(" itf");
1387 }
1388 }
1389
1390 /**
1391 * Appends a comma to {@link #stringBuilder} if the given number is strictly positive.
1392 *
1393 * @param numValues a number of 'values visited so far', for instance the number of annotation
1394 * values visited so far in an annotation visitor.
1395 */
1396 private void maybeAppendComma(final int numValues) {
1397 if (numValues > 0) {
1398 stringBuilder.append(", ");
1399 }
1400 }
1401
1402 /**
1403 * Appends a string representation of the given type reference to {@link #stringBuilder}.
1404 *
1405 * @param typeRef a type reference. See {@link TypeReference}.
1406 */
1407 private void appendTypeReference(final int typeRef) {
1408 TypeReference typeReference = new TypeReference(typeRef);
1409 switch (typeReference.getSort()) {
1410 case TypeReference.CLASS_TYPE_PARAMETER:
1411 stringBuilder.append("CLASS_TYPE_PARAMETER ").append(typeReference.getTypeParameterIndex());
1412 break;
1413 case TypeReference.METHOD_TYPE_PARAMETER:
1414 stringBuilder
1415 .append("METHOD_TYPE_PARAMETER ")
1416 .append(typeReference.getTypeParameterIndex());
1417 break;
1418 case TypeReference.CLASS_EXTENDS:
1419 stringBuilder.append("CLASS_EXTENDS ").append(typeReference.getSuperTypeIndex());
1420 break;
1421 case TypeReference.CLASS_TYPE_PARAMETER_BOUND:
1422 stringBuilder
1423 .append("CLASS_TYPE_PARAMETER_BOUND ")
1424 .append(typeReference.getTypeParameterIndex())
1425 .append(", ")
1426 .append(typeReference.getTypeParameterBoundIndex());
1427 break;
1428 case TypeReference.METHOD_TYPE_PARAMETER_BOUND:
1429 stringBuilder
1430 .append("METHOD_TYPE_PARAMETER_BOUND ")
1431 .append(typeReference.getTypeParameterIndex())
1432 .append(", ")
1433 .append(typeReference.getTypeParameterBoundIndex());
1434 break;
1435 case TypeReference.FIELD:
1436 stringBuilder.append("FIELD");
1437 break;
1438 case TypeReference.METHOD_RETURN:
1439 stringBuilder.append("METHOD_RETURN");
1440 break;
1441 case TypeReference.METHOD_RECEIVER:
1442 stringBuilder.append("METHOD_RECEIVER");
1443 break;
1444 case TypeReference.METHOD_FORMAL_PARAMETER:
1445 stringBuilder
1446 .append("METHOD_FORMAL_PARAMETER ")
1447 .append(typeReference.getFormalParameterIndex());
1448 break;
1449 case TypeReference.THROWS:
1450 stringBuilder.append("THROWS ").append(typeReference.getExceptionIndex());
1451 break;
1452 case TypeReference.LOCAL_VARIABLE:
1453 stringBuilder.append("LOCAL_VARIABLE");
1454 break;
1455 case TypeReference.RESOURCE_VARIABLE:
1456 stringBuilder.append("RESOURCE_VARIABLE");
1457 break;
1458 case TypeReference.EXCEPTION_PARAMETER:
1459 stringBuilder.append("EXCEPTION_PARAMETER ").append(typeReference.getTryCatchBlockIndex());
1460 break;
1461 case TypeReference.INSTANCEOF:
1462 stringBuilder.append("INSTANCEOF");
1463 break;
1464 case TypeReference.NEW:
1465 stringBuilder.append("NEW");
1466 break;
1467 case TypeReference.CONSTRUCTOR_REFERENCE:
1468 stringBuilder.append("CONSTRUCTOR_REFERENCE");
1469 break;
1470 case TypeReference.METHOD_REFERENCE:
1471 stringBuilder.append("METHOD_REFERENCE");
1472 break;
1473 case TypeReference.CAST:
1474 stringBuilder.append("CAST ").append(typeReference.getTypeArgumentIndex());
1475 break;
1476 case TypeReference.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
1477 stringBuilder
1478 .append("CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT ")
1479 .append(typeReference.getTypeArgumentIndex());
1480 break;
1481 case TypeReference.METHOD_INVOCATION_TYPE_ARGUMENT:
1482 stringBuilder
1483 .append("METHOD_INVOCATION_TYPE_ARGUMENT ")
1484 .append(typeReference.getTypeArgumentIndex());
1485 break;
1486 case TypeReference.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT:
1487 stringBuilder
1488 .append("CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT ")
1489 .append(typeReference.getTypeArgumentIndex());
1490 break;
1491 case TypeReference.METHOD_REFERENCE_TYPE_ARGUMENT:
1492 stringBuilder
1493 .append("METHOD_REFERENCE_TYPE_ARGUMENT ")
1494 .append(typeReference.getTypeArgumentIndex());
1495 break;
1496 default:
1497 throw new IllegalArgumentException();
1498 }
1499 }
1500
1501 /**
1502 * Appends the given stack map frame types to {@link #stringBuilder}.
1503 *
1504 * @param nTypes the number of stack map frame types in 'frameTypes'.
1505 * @param frameTypes an array of stack map frame types, in the format described in {@link
1506 * org.eclipse.persistence.internal.libraries.asm.MethodVisitor#visitFrame}.
1507 */
1508 private void appendFrameTypes(final int nTypes, final Object[] frameTypes) {
1509 for (int i = 0; i < nTypes; ++i) {
1510 if (i > 0) {
1511 stringBuilder.append(' ');
1512 }
1513 if (frameTypes[i] instanceof String) {
1514 String descriptor = (String) frameTypes[i];
1515 if (descriptor.startsWith("[")) {
1516 appendDescriptor(FIELD_DESCRIPTOR, descriptor);
1517 } else {
1518 appendDescriptor(INTERNAL_NAME, descriptor);
2311519 }
232 buf.append("// access flags 0x")
233 .append(Integer.toHexString(access).toUpperCase()).append('\n');
234
235 appendDescriptor(CLASS_SIGNATURE, signature);
236 if (signature != null) {
237 TraceSignatureVisitor sv = new TraceSignatureVisitor(access);
238 SignatureReader r = new SignatureReader(signature);
239 r.accept(sv);
240 buf.append("// declaration: ").append(name)
241 .append(sv.getDeclaration()).append('\n');
1520 } else if (frameTypes[i] instanceof Integer) {
1521 switch (((Integer) frameTypes[i]).intValue()) {
1522 case 0:
1523 appendDescriptor(FIELD_DESCRIPTOR, "T");
1524 break;
1525 case 1:
1526 appendDescriptor(FIELD_DESCRIPTOR, "I");
1527 break;
1528 case 2:
1529 appendDescriptor(FIELD_DESCRIPTOR, "F");
1530 break;
1531 case 3:
1532 appendDescriptor(FIELD_DESCRIPTOR, "D");
1533 break;
1534 case 4:
1535 appendDescriptor(FIELD_DESCRIPTOR, "J");
1536 break;
1537 case 5:
1538 appendDescriptor(FIELD_DESCRIPTOR, "N");
1539 break;
1540 case 6:
1541 appendDescriptor(FIELD_DESCRIPTOR, "U");
1542 break;
1543 default:
1544 throw new IllegalArgumentException();
2421545 }
243
244 String internalName = name;
245 appendAccess(access & ~(Opcodes.ACC_SUPER|Opcodes.ACC_MODULE));
246 if ((access & Opcodes.ACC_ANNOTATION) != 0) {
247 buf.append("@interface ");
248 } else if ((access & Opcodes.ACC_INTERFACE) != 0) {
249 buf.append("interface ");
250 } else if ((access & Opcodes.ACC_MODULE) != 0) {
251 buf.append("module ");
252 internalName = name.substring(0, name.length() - "/module-info".length());
253 } else if ((access & Opcodes.ACC_ENUM) == 0) {
254 buf.append("class ");
255 }
256 appendDescriptor(INTERNAL_NAME, internalName);
257
258 if (superName != null && !"java/lang/Object".equals(superName)) {
259 buf.append(" extends ");
260 appendDescriptor(INTERNAL_NAME, superName);
261 buf.append(' ');
262 }
263 if (interfaces != null && interfaces.length > 0) {
264 buf.append(" implements ");
265 for (int i = 0; i < interfaces.length; ++i) {
266 appendDescriptor(INTERNAL_NAME, interfaces[i]);
267 buf.append(' ');
268 }
269 }
270 buf.append(" {\n\n");
271
272 text.add(buf.toString());
273 }
274
275 @Override
276 public void visitSource(final String file, final String debug) {
277 buf.setLength(0);
278 if (file != null) {
279 buf.append(tab).append("// compiled from: ").append(file)
280 .append('\n');
281 }
282 if (debug != null) {
283 buf.append(tab).append("// debug info: ").append(debug)
284 .append('\n');
285 }
286 if (buf.length() > 0) {
287 text.add(buf.toString());
288 }
289 }
290
291 @Override
292 public Printer visitModule() {
293 Textifier t = createTextifier();
294 text.add(t.getText());
295 return t;
296 }
297
298 @Override
299 public void visitOuterClass(final String owner, final String name,
300 final String desc) {
301 buf.setLength(0);
302 buf.append(tab).append("OUTERCLASS ");
303 appendDescriptor(INTERNAL_NAME, owner);
304 buf.append(' ');
305 if (name != null) {
306 buf.append(name).append(' ');
307 }
308 appendDescriptor(METHOD_DESCRIPTOR, desc);
309 buf.append('\n');
310 text.add(buf.toString());
311 }
312
313 @Override
314 public Textifier visitClassAnnotation(final String desc,
315 final boolean visible) {
316 text.add("\n");
317 return visitAnnotation(desc, visible);
318 }
319
320 @Override
321 public Textifier visitClassTypeAnnotation(int typeRef, TypePath typePath,
322 String desc, boolean visible) {
323 text.add("\n");
324 return visitTypeAnnotation(typeRef, typePath, desc, visible);
325 }
326
327 @Override
328 public void visitClassAttribute(final Attribute attr) {
329 text.add("\n");
330 visitAttribute(attr);
331 }
332
333 @Override
334 public void visitInnerClass(final String name, final String outerName,
335 final String innerName, final int access) {
336 buf.setLength(0);
337 buf.append(tab).append("// access flags 0x");
338 buf.append(
339 Integer.toHexString(access & ~Opcodes.ACC_SUPER).toUpperCase())
340 .append('\n');
341 buf.append(tab);
342 appendAccess(access);
343 buf.append("INNERCLASS ");
344 appendDescriptor(INTERNAL_NAME, name);
345 buf.append(' ');
346 appendDescriptor(INTERNAL_NAME, outerName);
347 buf.append(' ');
348 appendDescriptor(INTERNAL_NAME, innerName);
349 buf.append('\n');
350 text.add(buf.toString());
351 }
352
353 @Override
354 public Textifier visitField(final int access, final String name,
355 final String desc, final String signature, final Object value) {
356 buf.setLength(0);
357 buf.append('\n');
358 if ((access & Opcodes.ACC_DEPRECATED) != 0) {
359 buf.append(tab).append("// DEPRECATED\n");
360 }
361 buf.append(tab).append("// access flags 0x")
362 .append(Integer.toHexString(access).toUpperCase()).append('\n');
363 if (signature != null) {
364 buf.append(tab);
365 appendDescriptor(FIELD_SIGNATURE, signature);
366
367 TraceSignatureVisitor sv = new TraceSignatureVisitor(0);
368 SignatureReader r = new SignatureReader(signature);
369 r.acceptType(sv);
370 buf.append(tab).append("// declaration: ")
371 .append(sv.getDeclaration()).append('\n');
372 }
373
374 buf.append(tab);
375 appendAccess(access);
376
377 appendDescriptor(FIELD_DESCRIPTOR, desc);
378 buf.append(' ').append(name);
379 if (value != null) {
380 buf.append(" = ");
381 if (value instanceof String) {
382 buf.append('\"').append(value).append('\"');
383 } else {
384 buf.append(value);
385 }
386 }
387
388 buf.append('\n');
389 text.add(buf.toString());
390
391 Textifier t = createTextifier();
392 text.add(t.getText());
393 return t;
394 }
395
396 @Override
397 public Textifier visitMethod(final int access, final String name,
398 final String desc, final String signature, final String[] exceptions) {
399 buf.setLength(0);
400 buf.append('\n');
401 if ((access & Opcodes.ACC_DEPRECATED) != 0) {
402 buf.append(tab).append("// DEPRECATED\n");
403 }
404 buf.append(tab).append("// access flags 0x")
405 .append(Integer.toHexString(access).toUpperCase()).append('\n');
406
407 if (signature != null) {
408 buf.append(tab);
409 appendDescriptor(METHOD_SIGNATURE, signature);
410
411 TraceSignatureVisitor v = new TraceSignatureVisitor(0);
412 SignatureReader r = new SignatureReader(signature);
413 r.accept(v);
414 String genericDecl = v.getDeclaration();
415 String genericReturn = v.getReturnType();
416 String genericExceptions = v.getExceptions();
417
418 buf.append(tab).append("// declaration: ").append(genericReturn)
419 .append(' ').append(name).append(genericDecl);
420 if (genericExceptions != null) {
421 buf.append(" throws ").append(genericExceptions);
422 }
423 buf.append('\n');
424 }
425
426 buf.append(tab);
427 appendAccess(access & ~Opcodes.ACC_VOLATILE);
428 if ((access & Opcodes.ACC_NATIVE) != 0) {
429 buf.append("native ");
430 }
431 if ((access & Opcodes.ACC_VARARGS) != 0) {
432 buf.append("varargs ");
433 }
434 if ((access & Opcodes.ACC_BRIDGE) != 0) {
435 buf.append("bridge ");
436 }
437 if ((this.access & Opcodes.ACC_INTERFACE) != 0
438 && (access & Opcodes.ACC_ABSTRACT) == 0
439 && (access & Opcodes.ACC_STATIC) == 0) {
440 buf.append("default ");
441 }
442
443 buf.append(name);
444 appendDescriptor(METHOD_DESCRIPTOR, desc);
445 if (exceptions != null && exceptions.length > 0) {
446 buf.append(" throws ");
447 for (int i = 0; i < exceptions.length; ++i) {
448 appendDescriptor(INTERNAL_NAME, exceptions[i]);
449 buf.append(' ');
450 }
451 }
452
453 buf.append('\n');
454 text.add(buf.toString());
455
456 Textifier t = createTextifier();
457 text.add(t.getText());
458 return t;
459 }
460
461 @Override
462 public void visitClassEnd() {
463 text.add("}\n");
464 }
465
466 // ------------------------------------------------------------------------
467 // Module
468 // ------------------------------------------------------------------------
469
470 @Override
471 public void visitRequire(String require, int access) {
472 buf.setLength(0);
473 buf.append(tab).append("requires ");
474 if ((access & Opcodes.ACC_PUBLIC) != 0) {
475 buf.append("public ");
476 }
477 buf.append(require)
478 .append("; // access flags 0x")
479 .append(Integer.toHexString(access).toUpperCase())
480 .append('\n');
481 text.add(buf.toString());
482 }
483
484 @Override
485 public void visitExport(String export, String... tos) {
486 buf.setLength(0);
487 buf.append(tab).append("exports ").append(export);
488 if (tos != null && tos.length > 0) {
489 buf.append(" to\n");
490 for (int i = 0; i < tos.length; ++i) {
491 buf.append(tab2).append(tos[i]);
492 buf.append(i != tos.length - 1 ? ",\n": "");
493 }
494 }
495 buf.append(";\n");
496 text.add(buf.toString());
497 }
498
499 @Override
500 public void visitUse(String use) {
501 buf.setLength(0);
502 buf.append(tab).append("uses ");
503 appendDescriptor(INTERNAL_NAME, use);
504 buf.append(";\n");
505 text.add(buf.toString());
506 }
507
508 @Override
509 public void visitProvide(String provide, String with) {
510 buf.setLength(0);
511 buf.append(tab).append("provides ");
512 appendDescriptor(INTERNAL_NAME, provide);
513 buf.append(" with\n").append(tab2);
514 appendDescriptor(INTERNAL_NAME, with);
515 buf.append(";\n");
516 text.add(buf.toString());
517 }
518
519 @Override
520 public void visitModuleEnd() {
521 // empty
522 }
523
524 // ------------------------------------------------------------------------
525 // Annotations
526 // ------------------------------------------------------------------------
527
528 @Override
529 public void visit(final String name, final Object value) {
530 buf.setLength(0);
531 appendComa(valueNumber++);
532
533 if (name != null) {
534 buf.append(name).append('=');
535 }
536
537 if (value instanceof String) {
538 visitString((String) value);
539 } else if (value instanceof Type) {
540 visitType((Type) value);
541 } else if (value instanceof Byte) {
542 visitByte(((Byte) value).byteValue());
543 } else if (value instanceof Boolean) {
544 visitBoolean(((Boolean) value).booleanValue());
545 } else if (value instanceof Short) {
546 visitShort(((Short) value).shortValue());
547 } else if (value instanceof Character) {
548 visitChar(((Character) value).charValue());
549 } else if (value instanceof Integer) {
550 visitInt(((Integer) value).intValue());
551 } else if (value instanceof Float) {
552 visitFloat(((Float) value).floatValue());
553 } else if (value instanceof Long) {
554 visitLong(((Long) value).longValue());
555 } else if (value instanceof Double) {
556 visitDouble(((Double) value).doubleValue());
557 } else if (value.getClass().isArray()) {
558 buf.append('{');
559 if (value instanceof byte[]) {
560 byte[] v = (byte[]) value;
561 for (int i = 0; i < v.length; i++) {
562 appendComa(i);
563 visitByte(v[i]);
564 }
565 } else if (value instanceof boolean[]) {
566 boolean[] v = (boolean[]) value;
567 for (int i = 0; i < v.length; i++) {
568 appendComa(i);
569 visitBoolean(v[i]);
570 }
571 } else if (value instanceof short[]) {
572 short[] v = (short[]) value;
573 for (int i = 0; i < v.length; i++) {
574 appendComa(i);
575 visitShort(v[i]);
576 }
577 } else if (value instanceof char[]) {
578 char[] v = (char[]) value;
579 for (int i = 0; i < v.length; i++) {
580 appendComa(i);
581 visitChar(v[i]);
582 }
583 } else if (value instanceof int[]) {
584 int[] v = (int[]) value;
585 for (int i = 0; i < v.length; i++) {
586 appendComa(i);
587 visitInt(v[i]);
588 }
589 } else if (value instanceof long[]) {
590 long[] v = (long[]) value;
591 for (int i = 0; i < v.length; i++) {
592 appendComa(i);
593 visitLong(v[i]);
594 }
595 } else if (value instanceof float[]) {
596 float[] v = (float[]) value;
597 for (int i = 0; i < v.length; i++) {
598 appendComa(i);
599 visitFloat(v[i]);
600 }
601 } else if (value instanceof double[]) {
602 double[] v = (double[]) value;
603 for (int i = 0; i < v.length; i++) {
604 appendComa(i);
605 visitDouble(v[i]);
606 }
607 }
608 buf.append('}');
609 }
610
611 text.add(buf.toString());
612 }
613
614 private void visitInt(final int value) {
615 buf.append(value);
616 }
617
618 private void visitLong(final long value) {
619 buf.append(value).append('L');
620 }
621
622 private void visitFloat(final float value) {
623 buf.append(value).append('F');
624 }
625
626 private void visitDouble(final double value) {
627 buf.append(value).append('D');
628 }
629
630 private void visitChar(final char value) {
631 buf.append("(char)").append((int) value);
632 }
633
634 private void visitShort(final short value) {
635 buf.append("(short)").append(value);
636 }
637
638 private void visitByte(final byte value) {
639 buf.append("(byte)").append(value);
640 }
641
642 private void visitBoolean(final boolean value) {
643 buf.append(value);
644 }
645
646 private void visitString(final String value) {
647 appendString(buf, value);
648 }
649
650 private void visitType(final Type value) {
651 buf.append(value.getClassName()).append(".class");
652 }
653
654 @Override
655 public void visitEnum(final String name, final String desc,
656 final String value) {
657 buf.setLength(0);
658 appendComa(valueNumber++);
659 if (name != null) {
660 buf.append(name).append('=');
661 }
662 appendDescriptor(FIELD_DESCRIPTOR, desc);
663 buf.append('.').append(value);
664 text.add(buf.toString());
665 }
666
667 @Override
668 public Textifier visitAnnotation(final String name, final String desc) {
669 buf.setLength(0);
670 appendComa(valueNumber++);
671 if (name != null) {
672 buf.append(name).append('=');
673 }
674 buf.append('@');
675 appendDescriptor(FIELD_DESCRIPTOR, desc);
676 buf.append('(');
677 text.add(buf.toString());
678 Textifier t = createTextifier();
679 text.add(t.getText());
680 text.add(")");
681 return t;
682 }
683
684 @Override
685 public Textifier visitArray(final String name) {
686 buf.setLength(0);
687 appendComa(valueNumber++);
688 if (name != null) {
689 buf.append(name).append('=');
690 }
691 buf.append('{');
692 text.add(buf.toString());
693 Textifier t = createTextifier();
694 text.add(t.getText());
695 text.add("}");
696 return t;
697 }
698
699 @Override
700 public void visitAnnotationEnd() {
701 }
702
703 // ------------------------------------------------------------------------
704 // Fields
705 // ------------------------------------------------------------------------
706
707 @Override
708 public Textifier visitFieldAnnotation(final String desc,
709 final boolean visible) {
710 return visitAnnotation(desc, visible);
711 }
712
713 @Override
714 public Textifier visitFieldTypeAnnotation(int typeRef, TypePath typePath,
715 String desc, boolean visible) {
716 return visitTypeAnnotation(typeRef, typePath, desc, visible);
717 }
718
719 @Override
720 public void visitFieldAttribute(final Attribute attr) {
721 visitAttribute(attr);
722 }
723
724 @Override
725 public void visitFieldEnd() {
726 }
727
728 // ------------------------------------------------------------------------
729 // Methods
730 // ------------------------------------------------------------------------
731
732 @Override
733 public void visitParameter(final String name, final int access) {
734 buf.setLength(0);
735 buf.append(tab2).append("// parameter ");
736 appendAccess(access);
737 buf.append(' ').append((name == null) ? "<no name>" : name)
738 .append('\n');
739 text.add(buf.toString());
740 }
741
742 @Override
743 public Textifier visitAnnotationDefault() {
744 text.add(tab2 + "default=");
745 Textifier t = createTextifier();
746 text.add(t.getText());
747 text.add("\n");
748 return t;
749 }
750
751 @Override
752 public Textifier visitMethodAnnotation(final String desc,
753 final boolean visible) {
754 return visitAnnotation(desc, visible);
755 }
756
757 @Override
758 public Textifier visitMethodTypeAnnotation(int typeRef, TypePath typePath,
759 String desc, boolean visible) {
760 return visitTypeAnnotation(typeRef, typePath, desc, visible);
761 }
762
763 @Override
764 public Textifier visitParameterAnnotation(final int parameter,
765 final String desc, final boolean visible) {
766 buf.setLength(0);
767 buf.append(tab2).append('@');
768 appendDescriptor(FIELD_DESCRIPTOR, desc);
769 buf.append('(');
770 text.add(buf.toString());
771 Textifier t = createTextifier();
772 text.add(t.getText());
773 text.add(visible ? ") // parameter " : ") // invisible, parameter ");
774 text.add(parameter);
775 text.add("\n");
776 return t;
777 }
778
779 @Override
780 public void visitMethodAttribute(final Attribute attr) {
781 buf.setLength(0);
782 buf.append(tab).append("ATTRIBUTE ");
783 appendDescriptor(-1, attr.type);
784
785 if (attr instanceof Textifiable) {
786 ((Textifiable) attr).textify(buf, labelNames);
787 } else {
788 buf.append(" : unknown\n");
789 }
790
791 text.add(buf.toString());
792 }
793
794 @Override
795 public void visitCode() {
796 }
797
798 @Override
799 public void visitFrame(final int type, final int nLocal,
800 final Object[] local, final int nStack, final Object[] stack) {
801 buf.setLength(0);
802 buf.append(ltab);
803 buf.append("FRAME ");
804 switch (type) {
805 case Opcodes.F_NEW:
806 case Opcodes.F_FULL:
807 buf.append("FULL [");
808 appendFrameTypes(nLocal, local);
809 buf.append("] [");
810 appendFrameTypes(nStack, stack);
811 buf.append(']');
812 break;
813 case Opcodes.F_APPEND:
814 buf.append("APPEND [");
815 appendFrameTypes(nLocal, local);
816 buf.append(']');
817 break;
818 case Opcodes.F_CHOP:
819 buf.append("CHOP ").append(nLocal);
820 break;
821 case Opcodes.F_SAME:
822 buf.append("SAME");
823 break;
824 case Opcodes.F_SAME1:
825 buf.append("SAME1 ");
826 appendFrameTypes(1, stack);
827 break;
828 }
829 buf.append('\n');
830 text.add(buf.toString());
831 }
832
833 @Override
834 public void visitInsn(final int opcode) {
835 buf.setLength(0);
836 buf.append(tab2).append(OPCODES[opcode]).append('\n');
837 text.add(buf.toString());
838 }
839
840 @Override
841 public void visitIntInsn(final int opcode, final int operand) {
842 buf.setLength(0);
843 buf.append(tab2)
844 .append(OPCODES[opcode])
845 .append(' ')
846 .append(opcode == Opcodes.NEWARRAY ? TYPES[operand] : Integer
847 .toString(operand)).append('\n');
848 text.add(buf.toString());
849 }
850
851 @Override
852 public void visitVarInsn(final int opcode, final int var) {
853 buf.setLength(0);
854 buf.append(tab2).append(OPCODES[opcode]).append(' ').append(var)
855 .append('\n');
856 text.add(buf.toString());
857 }
858
859 @Override
860 public void visitTypeInsn(final int opcode, final String type) {
861 buf.setLength(0);
862 buf.append(tab2).append(OPCODES[opcode]).append(' ');
863 appendDescriptor(INTERNAL_NAME, type);
864 buf.append('\n');
865 text.add(buf.toString());
866 }
867
868 @Override
869 public void visitFieldInsn(final int opcode, final String owner,
870 final String name, final String desc) {
871 buf.setLength(0);
872 buf.append(tab2).append(OPCODES[opcode]).append(' ');
873 appendDescriptor(INTERNAL_NAME, owner);
874 buf.append('.').append(name).append(" : ");
875 appendDescriptor(FIELD_DESCRIPTOR, desc);
876 buf.append('\n');
877 text.add(buf.toString());
878 }
879
880 @Deprecated
881 @Override
882 public void visitMethodInsn(final int opcode, final String owner,
883 final String name, final String desc) {
884 if (api >= Opcodes.ASM5) {
885 super.visitMethodInsn(opcode, owner, name, desc);
886 return;
887 }
888 doVisitMethodInsn(opcode, owner, name, desc,
889 opcode == Opcodes.INVOKEINTERFACE);
890 }
891
892 @Override
893 public void visitMethodInsn(final int opcode, final String owner,
894 final String name, final String desc, final boolean itf) {
895 if (api < Opcodes.ASM5) {
896 super.visitMethodInsn(opcode, owner, name, desc, itf);
897 return;
898 }
899 doVisitMethodInsn(opcode, owner, name, desc, itf);
900 }
901
902 private void doVisitMethodInsn(final int opcode, final String owner,
903 final String name, final String desc, final boolean itf) {
904 buf.setLength(0);
905 buf.append(tab2).append(OPCODES[opcode]).append(' ');
906 appendDescriptor(INTERNAL_NAME, owner);
907 buf.append('.').append(name).append(' ');
908 appendDescriptor(METHOD_DESCRIPTOR, desc);
909 buf.append('\n');
910 text.add(buf.toString());
911 }
912
913 @Override
914 public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
915 Object... bsmArgs) {
916 buf.setLength(0);
917 buf.append(tab2).append("INVOKEDYNAMIC").append(' ');
918 buf.append(name);
919 appendDescriptor(METHOD_DESCRIPTOR, desc);
920 buf.append(" [");
921 buf.append('\n');
922 buf.append(tab3);
923 appendHandle(bsm);
924 buf.append('\n');
925 buf.append(tab3).append("// arguments:");
926 if (bsmArgs.length == 0) {
927 buf.append(" none");
928 } else {
929 buf.append('\n');
930 for (int i = 0; i < bsmArgs.length; i++) {
931 buf.append(tab3);
932 Object cst = bsmArgs[i];
933 if (cst instanceof String) {
934 Printer.appendString(buf, (String) cst);
935 } else if (cst instanceof Type) {
936 Type type = (Type) cst;
937 if(type.getSort() == Type.METHOD){
938 appendDescriptor(METHOD_DESCRIPTOR, type.getDescriptor());
939 } else {
940 buf.append(type.getDescriptor()).append(".class");
941 }
942 } else if (cst instanceof Handle) {
943 appendHandle((Handle) cst);
944 } else {
945 buf.append(cst);
946 }
947 buf.append(", \n");
948 }
949 buf.setLength(buf.length() - 3);
950 }
951 buf.append('\n');
952 buf.append(tab2).append("]\n");
953 text.add(buf.toString());
954 }
955
956 @Override
957 public void visitJumpInsn(final int opcode, final Label label) {
958 buf.setLength(0);
959 buf.append(tab2).append(OPCODES[opcode]).append(' ');
960 appendLabel(label);
961 buf.append('\n');
962 text.add(buf.toString());
963 }
964
965 @Override
966 public void visitLabel(final Label label) {
967 buf.setLength(0);
968 buf.append(ltab);
969 appendLabel(label);
970 buf.append('\n');
971 text.add(buf.toString());
972 }
973
974 @Override
975 public void visitLdcInsn(final Object cst) {
976 buf.setLength(0);
977 buf.append(tab2).append("LDC ");
978 if (cst instanceof String) {
979 Printer.appendString(buf, (String) cst);
980 } else if (cst instanceof Type) {
981 buf.append(((Type) cst).getDescriptor()).append(".class");
982 } else {
983 buf.append(cst);
984 }
985 buf.append('\n');
986 text.add(buf.toString());
987 }
988
989 @Override
990 public void visitIincInsn(final int var, final int increment) {
991 buf.setLength(0);
992 buf.append(tab2).append("IINC ").append(var).append(' ')
993 .append(increment).append('\n');
994 text.add(buf.toString());
995 }
996
997 @Override
998 public void visitTableSwitchInsn(final int min, final int max,
999 final Label dflt, final Label... labels) {
1000 buf.setLength(0);
1001 buf.append(tab2).append("TABLESWITCH\n");
1002 for (int i = 0; i < labels.length; ++i) {
1003 buf.append(tab3).append(min + i).append(": ");
1004 appendLabel(labels[i]);
1005 buf.append('\n');
1006 }
1007 buf.append(tab3).append("default: ");
1008 appendLabel(dflt);
1009 buf.append('\n');
1010 text.add(buf.toString());
1011 }
1012
1013 @Override
1014 public void visitLookupSwitchInsn(final Label dflt, final int[] keys,
1015 final Label[] labels) {
1016 buf.setLength(0);
1017 buf.append(tab2).append("LOOKUPSWITCH\n");
1018 for (int i = 0; i < labels.length; ++i) {
1019 buf.append(tab3).append(keys[i]).append(": ");
1020 appendLabel(labels[i]);
1021 buf.append('\n');
1022 }
1023 buf.append(tab3).append("default: ");
1024 appendLabel(dflt);
1025 buf.append('\n');
1026 text.add(buf.toString());
1027 }
1028
1029 @Override
1030 public void visitMultiANewArrayInsn(final String desc, final int dims) {
1031 buf.setLength(0);
1032 buf.append(tab2).append("MULTIANEWARRAY ");
1033 appendDescriptor(FIELD_DESCRIPTOR, desc);
1034 buf.append(' ').append(dims).append('\n');
1035 text.add(buf.toString());
1036 }
1037
1038 @Override
1039 public Textifier visitInsnAnnotation(int typeRef, TypePath typePath,
1040 String desc, boolean visible) {
1041 return visitTypeAnnotation(typeRef, typePath, desc, visible);
1042 }
1043
1044 @Override
1045 public void visitTryCatchBlock(final Label start, final Label end,
1046 final Label handler, final String type) {
1047 buf.setLength(0);
1048 buf.append(tab2).append("TRYCATCHBLOCK ");
1049 appendLabel(start);
1050 buf.append(' ');
1051 appendLabel(end);
1052 buf.append(' ');
1053 appendLabel(handler);
1054 buf.append(' ');
1055 appendDescriptor(INTERNAL_NAME, type);
1056 buf.append('\n');
1057 text.add(buf.toString());
1058 }
1059
1060 @Override
1061 public Textifier visitTryCatchAnnotation(int typeRef, TypePath typePath,
1062 String desc, boolean visible) {
1063 buf.setLength(0);
1064 buf.append(tab2).append("TRYCATCHBLOCK @");
1065 appendDescriptor(FIELD_DESCRIPTOR, desc);
1066 buf.append('(');
1067 text.add(buf.toString());
1068 Textifier t = createTextifier();
1069 text.add(t.getText());
1070 buf.setLength(0);
1071 buf.append(") : ");
1072 appendTypeReference(typeRef);
1073 buf.append(", ").append(typePath);
1074 buf.append(visible ? "\n" : " // invisible\n");
1075 text.add(buf.toString());
1076 return t;
1077 }
1078
1079 @Override
1080 public void visitLocalVariable(final String name, final String desc,
1081 final String signature, final Label start, final Label end,
1082 final int index) {
1083 buf.setLength(0);
1084 buf.append(tab2).append("LOCALVARIABLE ").append(name).append(' ');
1085 appendDescriptor(FIELD_DESCRIPTOR, desc);
1086 buf.append(' ');
1087 appendLabel(start);
1088 buf.append(' ');
1089 appendLabel(end);
1090 buf.append(' ').append(index).append('\n');
1091
1092 if (signature != null) {
1093 buf.append(tab2);
1094 appendDescriptor(FIELD_SIGNATURE, signature);
1095
1096 TraceSignatureVisitor sv = new TraceSignatureVisitor(0);
1097 SignatureReader r = new SignatureReader(signature);
1098 r.acceptType(sv);
1099 buf.append(tab2).append("// declaration: ")
1100 .append(sv.getDeclaration()).append('\n');
1101 }
1102 text.add(buf.toString());
1103 }
1104
1105 @Override
1106 public Textifier visitLocalVariableAnnotation(int typeRef, TypePath typePath,
1107 Label[] start, Label[] end, int[] index, String desc,
1108 boolean visible) {
1109 buf.setLength(0);
1110 buf.append(tab2).append("LOCALVARIABLE @");
1111 appendDescriptor(FIELD_DESCRIPTOR, desc);
1112 buf.append('(');
1113 text.add(buf.toString());
1114 Textifier t = createTextifier();
1115 text.add(t.getText());
1116 buf.setLength(0);
1117 buf.append(") : ");
1118 appendTypeReference(typeRef);
1119 buf.append(", ").append(typePath);
1120 for (int i = 0; i < start.length; ++i) {
1121 buf.append(" [ ");
1122 appendLabel(start[i]);
1123 buf.append(" - ");
1124 appendLabel(end[i]);
1125 buf.append(" - ").append(index[i]).append(" ]");
1126 }
1127 buf.append(visible ? "\n" : " // invisible\n");
1128 text.add(buf.toString());
1129 return t;
1130 }
1131
1132 @Override
1133 public void visitLineNumber(final int line, final Label start) {
1134 buf.setLength(0);
1135 buf.append(tab2).append("LINENUMBER ").append(line).append(' ');
1136 appendLabel(start);
1137 buf.append('\n');
1138 text.add(buf.toString());
1139 }
1140
1141 @Override
1142 public void visitMaxs(final int maxStack, final int maxLocals) {
1143 buf.setLength(0);
1144 buf.append(tab2).append("MAXSTACK = ").append(maxStack).append('\n');
1145 text.add(buf.toString());
1146
1147 buf.setLength(0);
1148 buf.append(tab2).append("MAXLOCALS = ").append(maxLocals).append('\n');
1149 text.add(buf.toString());
1150 }
1151
1152 @Override
1153 public void visitMethodEnd() {
1154 }
1155
1156 // ------------------------------------------------------------------------
1157 // Common methods
1158 // ------------------------------------------------------------------------
1159
1160 /**
1161 * Prints a disassembled view of the given annotation.
1162 *
1163 * @param desc
1164 * the class descriptor of the annotation class.
1165 * @param visible
1166 * <tt>true</tt> if the annotation is visible at runtime.
1167 * @return a visitor to visit the annotation values.
1168 */
1169 public Textifier visitAnnotation(final String desc, final boolean visible) {
1170 buf.setLength(0);
1171 buf.append(tab).append('@');
1172 appendDescriptor(FIELD_DESCRIPTOR, desc);
1173 buf.append('(');
1174 text.add(buf.toString());
1175 Textifier t = createTextifier();
1176 text.add(t.getText());
1177 text.add(visible ? ")\n" : ") // invisible\n");
1178 return t;
1179 }
1180
1181 /**
1182 * Prints a disassembled view of the given type annotation.
1183 *
1184 * @param typeRef
1185 * a reference to the annotated type. See {@link TypeReference}.
1186 * @param typePath
1187 * the path to the annotated type argument, wildcard bound, array
1188 * element type, or static inner type within 'typeRef'. May be
1189 * <tt>null</tt> if the annotation targets 'typeRef' as a whole.
1190 * @param desc
1191 * the class descriptor of the annotation class.
1192 * @param visible
1193 * <tt>true</tt> if the annotation is visible at runtime.
1194 * @return a visitor to visit the annotation values.
1195 */
1196 public Textifier visitTypeAnnotation(final int typeRef,
1197 final TypePath typePath, final String desc, final boolean visible) {
1198 buf.setLength(0);
1199 buf.append(tab).append('@');
1200 appendDescriptor(FIELD_DESCRIPTOR, desc);
1201 buf.append('(');
1202 text.add(buf.toString());
1203 Textifier t = createTextifier();
1204 text.add(t.getText());
1205 buf.setLength(0);
1206 buf.append(") : ");
1207 appendTypeReference(typeRef);
1208 buf.append(", ").append(typePath);
1209 buf.append(visible ? "\n" : " // invisible\n");
1210 text.add(buf.toString());
1211 return t;
1212 }
1213
1214 /**
1215 * Prints a disassembled view of the given attribute.
1216 *
1217 * @param attr
1218 * an attribute.
1219 */
1220 public void visitAttribute(final Attribute attr) {
1221 buf.setLength(0);
1222 buf.append(tab).append("ATTRIBUTE ");
1223 appendDescriptor(-1, attr.type);
1224
1225 if (attr instanceof Textifiable) {
1226 ((Textifiable) attr).textify(buf, null);
1227 } else {
1228 buf.append(" : unknown\n");
1229 }
1230
1231 text.add(buf.toString());
1232 }
1233
1234 // ------------------------------------------------------------------------
1235 // Utility methods
1236 // ------------------------------------------------------------------------
1237
1238 /**
1239 * Creates a new TraceVisitor instance.
1240 *
1241 * @return a new TraceVisitor.
1242 */
1243 protected Textifier createTextifier() {
1244 return new Textifier();
1245 }
1246
1247 /**
1248 * Appends an internal name, a type descriptor or a type signature to
1249 * {@link #buf buf}.
1250 *
1251 * @param type
1252 * indicates if desc is an internal name, a field descriptor, a
1253 * method descriptor, a class signature, ...
1254 * @param desc
1255 * an internal name, type descriptor, or type signature. May be
1256 * <tt>null</tt>.
1257 */
1258 protected void appendDescriptor(final int type, final String desc) {
1259 if (type == CLASS_SIGNATURE || type == FIELD_SIGNATURE
1260 || type == METHOD_SIGNATURE) {
1261 if (desc != null) {
1262 buf.append("// signature ").append(desc).append('\n');
1263 }
1264 } else {
1265 buf.append(desc);
1266 }
1267 }
1268
1269 /**
1270 * Appends the name of the given label to {@link #buf buf}. Creates a new
1271 * label name if the given label does not yet have one.
1272 *
1273 * @param l
1274 * a label.
1275 */
1276 protected void appendLabel(final Label l) {
1277 if (labelNames == null) {
1278 labelNames = new HashMap<Label, String>();
1279 }
1280 String name = labelNames.get(l);
1281 if (name == null) {
1282 name = "L" + labelNames.size();
1283 labelNames.put(l, name);
1284 }
1285 buf.append(name);
1286 }
1287
1288 /**
1289 * Appends the information about the given handle to {@link #buf buf}.
1290 *
1291 * @param h
1292 * a handle, non null.
1293 */
1294 protected void appendHandle(final Handle h) {
1295 int tag = h.getTag();
1296 buf.append("// handle kind 0x").append(Integer.toHexString(tag))
1297 .append(" : ");
1298 boolean isMethodHandle = false;
1299 switch (tag) {
1300 case Opcodes.H_GETFIELD:
1301 buf.append("GETFIELD");
1302 break;
1303 case Opcodes.H_GETSTATIC:
1304 buf.append("GETSTATIC");
1305 break;
1306 case Opcodes.H_PUTFIELD:
1307 buf.append("PUTFIELD");
1308 break;
1309 case Opcodes.H_PUTSTATIC:
1310 buf.append("PUTSTATIC");
1311 break;
1312 case Opcodes.H_INVOKEINTERFACE:
1313 buf.append("INVOKEINTERFACE");
1314 isMethodHandle = true;
1315 break;
1316 case Opcodes.H_INVOKESPECIAL:
1317 buf.append("INVOKESPECIAL");
1318 isMethodHandle = true;
1319 break;
1320 case Opcodes.H_INVOKESTATIC:
1321 buf.append("INVOKESTATIC");
1322 isMethodHandle = true;
1323 break;
1324 case Opcodes.H_INVOKEVIRTUAL:
1325 buf.append("INVOKEVIRTUAL");
1326 isMethodHandle = true;
1327 break;
1328 case Opcodes.H_NEWINVOKESPECIAL:
1329 buf.append("NEWINVOKESPECIAL");
1330 isMethodHandle = true;
1331 break;
1332 }
1333 buf.append('\n');
1334 buf.append(tab3);
1335 appendDescriptor(INTERNAL_NAME, h.getOwner());
1336 buf.append('.');
1337 buf.append(h.getName());
1338 if(!isMethodHandle){
1339 buf.append('(');
1340 }
1341 appendDescriptor(HANDLE_DESCRIPTOR, h.getDesc());
1342 if(!isMethodHandle){
1343 buf.append(')');
1344 }
1345 }
1346
1347 /**
1348 * Appends a string representation of the given access modifiers to
1349 * {@link #buf buf}.
1350 *
1351 * @param access
1352 * some access modifiers.
1353 */
1354 private void appendAccess(final int access) {
1355 if ((access & Opcodes.ACC_PUBLIC) != 0) {
1356 buf.append("public ");
1357 }
1358 if ((access & Opcodes.ACC_PRIVATE) != 0) {
1359 buf.append("private ");
1360 }
1361 if ((access & Opcodes.ACC_PROTECTED) != 0) {
1362 buf.append("protected ");
1363 }
1364 if ((access & Opcodes.ACC_FINAL) != 0) {
1365 buf.append("final ");
1366 }
1367 if ((access & Opcodes.ACC_STATIC) != 0) {
1368 buf.append("static ");
1369 }
1370 if ((access & Opcodes.ACC_SYNCHRONIZED) != 0) {
1371 buf.append("synchronized ");
1372 }
1373 if ((access & Opcodes.ACC_VOLATILE) != 0) {
1374 buf.append("volatile ");
1375 }
1376 if ((access & Opcodes.ACC_TRANSIENT) != 0) {
1377 buf.append("transient ");
1378 }
1379 if ((access & Opcodes.ACC_ABSTRACT) != 0) {
1380 buf.append("abstract ");
1381 }
1382 if ((access & Opcodes.ACC_STRICT) != 0) {
1383 buf.append("strictfp ");
1384 }
1385 if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
1386 buf.append("synthetic ");
1387 }
1388 if ((access & Opcodes.ACC_MANDATED) != 0) {
1389 buf.append("mandated ");
1390 }
1391 if ((access & Opcodes.ACC_ENUM) != 0) {
1392 buf.append("enum ");
1393 }
1394 }
1395
1396 private void appendComa(final int i) {
1397 if (i != 0) {
1398 buf.append(", ");
1399 }
1400 }
1401
1402 private void appendTypeReference(final int typeRef) {
1403 TypeReference ref = new TypeReference(typeRef);
1404 switch (ref.getSort()) {
1405 case TypeReference.CLASS_TYPE_PARAMETER:
1406 buf.append("CLASS_TYPE_PARAMETER ").append(
1407 ref.getTypeParameterIndex());
1408 break;
1409 case TypeReference.METHOD_TYPE_PARAMETER:
1410 buf.append("METHOD_TYPE_PARAMETER ").append(
1411 ref.getTypeParameterIndex());
1412 break;
1413 case TypeReference.CLASS_EXTENDS:
1414 buf.append("CLASS_EXTENDS ").append(ref.getSuperTypeIndex());
1415 break;
1416 case TypeReference.CLASS_TYPE_PARAMETER_BOUND:
1417 buf.append("CLASS_TYPE_PARAMETER_BOUND ")
1418 .append(ref.getTypeParameterIndex()).append(", ")
1419 .append(ref.getTypeParameterBoundIndex());
1420 break;
1421 case TypeReference.METHOD_TYPE_PARAMETER_BOUND:
1422 buf.append("METHOD_TYPE_PARAMETER_BOUND ")
1423 .append(ref.getTypeParameterIndex()).append(", ")
1424 .append(ref.getTypeParameterBoundIndex());
1425 break;
1426 case TypeReference.FIELD:
1427 buf.append("FIELD");
1428 break;
1429 case TypeReference.METHOD_RETURN:
1430 buf.append("METHOD_RETURN");
1431 break;
1432 case TypeReference.METHOD_RECEIVER:
1433 buf.append("METHOD_RECEIVER");
1434 break;
1435 case TypeReference.METHOD_FORMAL_PARAMETER:
1436 buf.append("METHOD_FORMAL_PARAMETER ").append(
1437 ref.getFormalParameterIndex());
1438 break;
1439 case TypeReference.THROWS:
1440 buf.append("THROWS ").append(ref.getExceptionIndex());
1441 break;
1442 case TypeReference.LOCAL_VARIABLE:
1443 buf.append("LOCAL_VARIABLE");
1444 break;
1445 case TypeReference.RESOURCE_VARIABLE:
1446 buf.append("RESOURCE_VARIABLE");
1447 break;
1448 case TypeReference.EXCEPTION_PARAMETER:
1449 buf.append("EXCEPTION_PARAMETER ").append(
1450 ref.getTryCatchBlockIndex());
1451 break;
1452 case TypeReference.INSTANCEOF:
1453 buf.append("INSTANCEOF");
1454 break;
1455 case TypeReference.NEW:
1456 buf.append("NEW");
1457 break;
1458 case TypeReference.CONSTRUCTOR_REFERENCE:
1459 buf.append("CONSTRUCTOR_REFERENCE");
1460 break;
1461 case TypeReference.METHOD_REFERENCE:
1462 buf.append("METHOD_REFERENCE");
1463 break;
1464 case TypeReference.CAST:
1465 buf.append("CAST ").append(ref.getTypeArgumentIndex());
1466 break;
1467 case TypeReference.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
1468 buf.append("CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT ").append(
1469 ref.getTypeArgumentIndex());
1470 break;
1471 case TypeReference.METHOD_INVOCATION_TYPE_ARGUMENT:
1472 buf.append("METHOD_INVOCATION_TYPE_ARGUMENT ").append(
1473 ref.getTypeArgumentIndex());
1474 break;
1475 case TypeReference.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT:
1476 buf.append("CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT ").append(
1477 ref.getTypeArgumentIndex());
1478 break;
1479 case TypeReference.METHOD_REFERENCE_TYPE_ARGUMENT:
1480 buf.append("METHOD_REFERENCE_TYPE_ARGUMENT ").append(
1481 ref.getTypeArgumentIndex());
1482 break;
1483 }
1484 }
1485
1486 private void appendFrameTypes(final int n, final Object[] o) {
1487 for (int i = 0; i < n; ++i) {
1488 if (i > 0) {
1489 buf.append(' ');
1490 }
1491 if (o[i] instanceof String) {
1492 String desc = (String) o[i];
1493 if (desc.startsWith("[")) {
1494 appendDescriptor(FIELD_DESCRIPTOR, desc);
1495 } else {
1496 appendDescriptor(INTERNAL_NAME, desc);
1497 }
1498 } else if (o[i] instanceof Integer) {
1499 switch (((Integer) o[i]).intValue()) {
1500 case 0:
1501 appendDescriptor(FIELD_DESCRIPTOR, "T");
1502 break;
1503 case 1:
1504 appendDescriptor(FIELD_DESCRIPTOR, "I");
1505 break;
1506 case 2:
1507 appendDescriptor(FIELD_DESCRIPTOR, "F");
1508 break;
1509 case 3:
1510 appendDescriptor(FIELD_DESCRIPTOR, "D");
1511 break;
1512 case 4:
1513 appendDescriptor(FIELD_DESCRIPTOR, "J");
1514 break;
1515 case 5:
1516 appendDescriptor(FIELD_DESCRIPTOR, "N");
1517 break;
1518 case 6:
1519 appendDescriptor(FIELD_DESCRIPTOR, "U");
1520 break;
1521 }
1522 } else {
1523 appendLabel((Label) o[i]);
1524 }
1525 }
1526 }
1546 } else {
1547 appendLabel((Label) frameTypes[i]);
1548 }
1549 }
1550 }
1551
1552 /**
1553 * Creates and adds to {@link #text} a new {@link Textifier}, followed by the given string.
1554 *
1555 * @param endText the text to add to {@link #text} after the textifier. May be <tt>null</tt>.
1556 * @return the newly created {@link Textifier}.
1557 */
1558 private Textifier addNewTextifier(final String endText) {
1559 Textifier textifier = createTextifier();
1560 text.add(textifier.getText());
1561 if (endText != null) {
1562 text.add(endText);
1563 }
1564 return textifier;
1565 }
1566
1567 /**
1568 * Creates a new {@link Textifier}.
1569 *
1570 * @return a new {@link Textifier}.
1571 */
1572 protected Textifier createTextifier() {
1573 return new Textifier();
1574 }
15271575 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.util;
3028
3129 import org.eclipse.persistence.internal.libraries.asm.AnnotationVisitor;
3230 import org.eclipse.persistence.internal.libraries.asm.Opcodes;
3331
3432 /**
35 * An {@link AnnotationVisitor} that prints the annotations it visits with a
36 * {@link Printer}.
37 *
33 * An {@link AnnotationVisitor} that prints the annotations it visits with a {@link Printer}.
34 *
3835 * @author Eric Bruneton
3936 */
4037 public final class TraceAnnotationVisitor extends AnnotationVisitor {
4138
42 private final Printer p;
39 /** The printer to convert the visited annotation into text. */
40 private final Printer printer;
4341
44 public TraceAnnotationVisitor(final Printer p) {
45 this(null, p);
46 }
42 /**
43 * Constructs a new {@link TraceAnnotationVisitor}.
44 *
45 * @param printer the printer to convert the visited annotation into text.
46 */
47 public TraceAnnotationVisitor(final Printer printer) {
48 this(null, printer);
49 }
4750
48 public TraceAnnotationVisitor(final AnnotationVisitor av, final Printer p) {
49 super(Opcodes.ASM6, av);
50 this.p = p;
51 }
51 /**
52 * Constructs a new {@link TraceAnnotationVisitor}.
53 *
54 * @param annotationVisitor the annotation visitor to which to delegate calls. May be <tt>null</tt>.
55 * @param printer the printer to convert the visited annotation into text.
56 */
57 public TraceAnnotationVisitor(final AnnotationVisitor annotationVisitor, final Printer printer) {
58 super(Opcodes.ASM6, annotationVisitor);
59 this.printer = printer;
60 }
5261
53 @Override
54 public void visit(final String name, final Object value) {
55 p.visit(name, value);
56 super.visit(name, value);
57 }
62 @Override
63 public void visit(final String name, final Object value) {
64 printer.visit(name, value);
65 super.visit(name, value);
66 }
5867
59 @Override
60 public void visitEnum(final String name, final String desc,
61 final String value) {
62 p.visitEnum(name, desc, value);
63 super.visitEnum(name, desc, value);
64 }
68 @Override
69 public void visitEnum(final String name, final String descriptor, final String value) {
70 printer.visitEnum(name, descriptor, value);
71 super.visitEnum(name, descriptor, value);
72 }
6573
66 @Override
67 public AnnotationVisitor visitAnnotation(final String name,
68 final String desc) {
69 Printer p = this.p.visitAnnotation(name, desc);
70 AnnotationVisitor av = this.av == null ? null : this.av
71 .visitAnnotation(name, desc);
72 return new TraceAnnotationVisitor(av, p);
73 }
74 @Override
75 public AnnotationVisitor visitAnnotation(final String name, final String descriptor) {
76 Printer annotationPrinter = printer.visitAnnotation(name, descriptor);
77 return new TraceAnnotationVisitor(super.visitAnnotation(name, descriptor), annotationPrinter);
78 }
7479
75 @Override
76 public AnnotationVisitor visitArray(final String name) {
77 Printer p = this.p.visitArray(name);
78 AnnotationVisitor av = this.av == null ? null : this.av
79 .visitArray(name);
80 return new TraceAnnotationVisitor(av, p);
81 }
80 @Override
81 public AnnotationVisitor visitArray(final String name) {
82 Printer arrayPrinter = printer.visitArray(name);
83 return new TraceAnnotationVisitor(super.visitArray(name), arrayPrinter);
84 }
8285
83 @Override
84 public void visitEnd() {
85 p.visitAnnotationEnd();
86 super.visitEnd();
87 }
86 @Override
87 public void visitEnd() {
88 printer.visitAnnotationEnd();
89 super.visitEnd();
90 }
8891 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.util;
3028
3129 import java.io.PrintWriter;
4038 import org.eclipse.persistence.internal.libraries.asm.TypePath;
4139
4240 /**
43 * A {@link ClassVisitor} that prints the classes it visits with a
44 * {@link Printer}. This class visitor can be used in the middle of a class
45 * visitor chain to trace the class that is visited at a given point in this
46 * chain. This may be useful for debugging purposes.
47 * <p>
48 * The trace printed when visiting the <tt>Hello</tt> class is the following:
49 * <p>
50 * <blockquote>
51 *
41 * A {@link ClassVisitor} that prints the classes it visits with a {@link Printer}. This class
42 * visitor can be used in the middle of a class visitor chain to trace the class that is visited at
43 * a given point in this chain. This may be useful for debugging purposes.
44 *
45 * <p>When used with a {@link Textifier}, the trace printed when visiting the <tt>Hello</tt> class
46 * is the following:
47 *
5248 * <pre>
5349 * // class version 49.0 (49) // access flags 0x21 public class Hello {
54 *
50 *
5551 * // compiled from: Hello.java
56 *
57 * // access flags 0x1 public &lt;init&gt; ()V ALOAD 0 INVOKESPECIAL
58 * java/lang/Object &lt;init&gt; ()V RETURN MAXSTACK = 1 MAXLOCALS = 1
59 *
60 * // access flags 0x9 public static main ([Ljava/lang/String;)V GETSTATIC
61 * java/lang/System out Ljava/io/PrintStream; LDC &quot;hello&quot;
62 * INVOKEVIRTUAL java/io/PrintStream println (Ljava/lang/String;)V RETURN
63 * MAXSTACK = 2 MAXLOCALS = 1 }
52 *
53 * // access flags 0x1
54 * public &lt;init&gt; ()V
55 * ALOAD 0
56 * INVOKESPECIAL java/lang/Object &lt;init&gt; ()V
57 * RETURN
58 * MAXSTACK = 1 MAXLOCALS = 1
59 *
60 * // access flags 0x9
61 * public static main ([Ljava/lang/String;)V
62 * GETSTATIC java/lang/System out Ljava/io/PrintStream;
63 * LDC &quot;hello&quot;
64 * INVOKEVIRTUAL java/io/PrintStream println (Ljava/lang/String;)V
65 * RETURN
66 * MAXSTACK = 2 MAXLOCALS = 1
67 * }
6468 * </pre>
65 *
66 * </blockquote> where <tt>Hello</tt> is defined by:
67 * <p>
68 * <blockquote>
69 *
69 *
70 * where <tt>Hello</tt> is defined by:
71 *
7072 * <pre>
7173 * public class Hello {
72 *
73 * public static void main(String[] args) {
74 * System.out.println(&quot;hello&quot;);
75 * }
74 *
75 * public static void main(String[] args) {
76 * System.out.println(&quot;hello&quot;);
77 * }
7678 * }
7779 * </pre>
78 *
79 * </blockquote>
80 *
80 *
8181 * @author Eric Bruneton
8282 * @author Eugene Kuleshov
8383 */
8484 public final class TraceClassVisitor extends ClassVisitor {
8585
86 /**
87 * The print writer to be used to print the class. May be null.
88 */
89 private final PrintWriter pw;
90
91 /**
92 * The object that actually converts visit events into text.
93 */
94 public final Printer p;
95
96 /**
97 * Constructs a new {@link TraceClassVisitor}.
98 *
99 * @param pw
100 * the print writer to be used to print the class.
101 */
102 public TraceClassVisitor(final PrintWriter pw) {
103 this(null, pw);
86 /** The print writer to be used to print the class. May be <tt>null</tt>. */
87 private final PrintWriter printWriter;
88
89 /** The printer to convert the visited class into text. */
90 public final Printer p;
91
92 /**
93 * Constructs a new {@link TraceClassVisitor}.
94 *
95 * @param printWriter the print writer to be used to print the class. May be <tt>null</tt>.
96 */
97 public TraceClassVisitor(final PrintWriter printWriter) {
98 this(null, printWriter);
99 }
100
101 /**
102 * Constructs a new {@link TraceClassVisitor}.
103 *
104 * @param classVisitor the class visitor to which to delegate calls. May be <tt>null</tt>.
105 * @param printWriter the print writer to be used to print the class. May be <tt>null</tt>.
106 */
107 public TraceClassVisitor(final ClassVisitor classVisitor, final PrintWriter printWriter) {
108 this(classVisitor, new Textifier(), printWriter);
109 }
110
111 /**
112 * Constructs a new {@link TraceClassVisitor}.
113 *
114 * @param classVisitor the class visitor to which to delegate calls. May be <tt>null</tt>.
115 * @param printer the printer to convert the visited class into text.
116 * @param printWriter the print writer to be used to print the class. May be <tt>null</tt>.
117 */
118 public TraceClassVisitor(
119 final ClassVisitor classVisitor, final Printer printer, final PrintWriter printWriter) {
120 super(Opcodes.ASM6, classVisitor);
121 this.printWriter = printWriter;
122 this.p = printer;
123 }
124
125 @Override
126 public void visit(
127 final int version,
128 final int access,
129 final String name,
130 final String signature,
131 final String superName,
132 final String[] interfaces) {
133 p.visit(version, access, name, signature, superName, interfaces);
134 super.visit(version, access, name, signature, superName, interfaces);
135 }
136
137 @Override
138 public void visitSource(final String file, final String debug) {
139 p.visitSource(file, debug);
140 super.visitSource(file, debug);
141 }
142
143 @Override
144 public ModuleVisitor visitModule(final String name, final int flags, final String version) {
145 Printer modulePrinter = p.visitModule(name, flags, version);
146 return new TraceModuleVisitor(super.visitModule(name, flags, version), modulePrinter);
147 }
148
149 @Override
150 public void visitOuterClass(final String owner, final String name, final String descriptor) {
151 p.visitOuterClass(owner, name, descriptor);
152 super.visitOuterClass(owner, name, descriptor);
153 }
154
155 @Override
156 public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
157 Printer annotationPrinter = p.visitClassAnnotation(descriptor, visible);
158 return new TraceAnnotationVisitor(
159 super.visitAnnotation(descriptor, visible), annotationPrinter);
160 }
161
162 @Override
163 public AnnotationVisitor visitTypeAnnotation(
164 final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
165 Printer annotationPrinter = p.visitClassTypeAnnotation(typeRef, typePath, descriptor, visible);
166 return new TraceAnnotationVisitor(
167 super.visitTypeAnnotation(typeRef, typePath, descriptor, visible), annotationPrinter);
168 }
169
170 @Override
171 public void visitAttribute(final Attribute attribute) {
172 p.visitClassAttribute(attribute);
173 super.visitAttribute(attribute);
174 }
175
176 @Override
177 public void visitInnerClass(
178 final String name, final String outerName, final String innerName, final int access) {
179 p.visitInnerClass(name, outerName, innerName, access);
180 super.visitInnerClass(name, outerName, innerName, access);
181 }
182
183 @Override
184 public FieldVisitor visitField(
185 final int access,
186 final String name,
187 final String descriptor,
188 final String signature,
189 final Object value) {
190 Printer fieldPrinter = p.visitField(access, name, descriptor, signature, value);
191 return new TraceFieldVisitor(
192 super.visitField(access, name, descriptor, signature, value), fieldPrinter);
193 }
194
195 @Override
196 public MethodVisitor visitMethod(
197 final int access,
198 final String name,
199 final String descriptor,
200 final String signature,
201 final String[] exceptions) {
202 Printer methodPrinter = p.visitMethod(access, name, descriptor, signature, exceptions);
203 return new TraceMethodVisitor(
204 super.visitMethod(access, name, descriptor, signature, exceptions), methodPrinter);
205 }
206
207 @Override
208 public void visitEnd() {
209 p.visitClassEnd();
210 if (printWriter != null) {
211 p.print(printWriter);
212 printWriter.flush();
104213 }
105
106 /**
107 * Constructs a new {@link TraceClassVisitor}.
108 *
109 * @param cv
110 * the {@link ClassVisitor} to which this visitor delegates
111 * calls. May be <tt>null</tt>.
112 * @param pw
113 * the print writer to be used to print the class.
114 */
115 public TraceClassVisitor(final ClassVisitor cv, final PrintWriter pw) {
116 this(cv, new Textifier(), pw);
117 }
118
119 /**
120 * Constructs a new {@link TraceClassVisitor}.
121 *
122 * @param cv
123 * the {@link ClassVisitor} to which this visitor delegates
124 * calls. May be <tt>null</tt>.
125 * @param p
126 * the object that actually converts visit events into text.
127 * @param pw
128 * the print writer to be used to print the class. May be null if
129 * you simply want to use the result via
130 * {@link Printer#getText()}, instead of printing it.
131 */
132 public TraceClassVisitor(final ClassVisitor cv, final Printer p,
133 final PrintWriter pw) {
134 super(Opcodes.ASM6, cv);
135 this.pw = pw;
136 this.p = p;
137 }
138
139 @Override
140 public void visit(final int version, final int access, final String name,
141 final String signature, final String superName,
142 final String[] interfaces) {
143 p.visit(version, access, name, signature, superName, interfaces);
144 super.visit(version, access, name, signature, superName, interfaces);
145 }
146
147 @Override
148 public void visitSource(final String file, final String debug) {
149 p.visitSource(file, debug);
150 super.visitSource(file, debug);
151 }
152
153 @Override
154 public ModuleVisitor visitModule() {
155 Printer p = this.p.visitModule();
156 ModuleVisitor mv = super.visitModule();
157 return new TraceModuleVisitor(mv, p);
158 }
159
160 @Override
161 public void visitOuterClass(final String owner, final String name,
162 final String desc) {
163 p.visitOuterClass(owner, name, desc);
164 super.visitOuterClass(owner, name, desc);
165 }
166
167 @Override
168 public AnnotationVisitor visitAnnotation(final String desc,
169 final boolean visible) {
170 Printer p = this.p.visitClassAnnotation(desc, visible);
171 AnnotationVisitor av = cv == null ? null : cv.visitAnnotation(desc,
172 visible);
173 return new TraceAnnotationVisitor(av, p);
174 }
175
176 @Override
177 public AnnotationVisitor visitTypeAnnotation(int typeRef,
178 TypePath typePath, String desc, boolean visible) {
179 Printer p = this.p.visitClassTypeAnnotation(typeRef, typePath, desc,
180 visible);
181 AnnotationVisitor av = cv == null ? null : cv.visitTypeAnnotation(
182 typeRef, typePath, desc, visible);
183 return new TraceAnnotationVisitor(av, p);
184 }
185
186 @Override
187 public void visitAttribute(final Attribute attr) {
188 p.visitClassAttribute(attr);
189 super.visitAttribute(attr);
190 }
191
192 @Override
193 public void visitInnerClass(final String name, final String outerName,
194 final String innerName, final int access) {
195 p.visitInnerClass(name, outerName, innerName, access);
196 super.visitInnerClass(name, outerName, innerName, access);
197 }
198
199 @Override
200 public FieldVisitor visitField(final int access, final String name,
201 final String desc, final String signature, final Object value) {
202 Printer p = this.p.visitField(access, name, desc, signature, value);
203 FieldVisitor fv = cv == null ? null : cv.visitField(access, name, desc,
204 signature, value);
205 return new TraceFieldVisitor(fv, p);
206 }
207
208 @Override
209 public MethodVisitor visitMethod(final int access, final String name,
210 final String desc, final String signature, final String[] exceptions) {
211 Printer p = this.p.visitMethod(access, name, desc, signature,
212 exceptions);
213 MethodVisitor mv = cv == null ? null : cv.visitMethod(access, name,
214 desc, signature, exceptions);
215 return new TraceMethodVisitor(mv, p);
216 }
217
218 @Override
219 public void visitEnd() {
220 p.visitClassEnd();
221 if (pw != null) {
222 p.print(pw);
223 pw.flush();
224 }
225 super.visitEnd();
226 }
214 super.visitEnd();
215 }
227216 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.util;
3028
3129 import org.eclipse.persistence.internal.libraries.asm.AnnotationVisitor;
3533 import org.eclipse.persistence.internal.libraries.asm.TypePath;
3634
3735 /**
38 * A {@link FieldVisitor} that prints the fields it visits with a
39 * {@link Printer}.
40 *
36 * A {@link FieldVisitor} that prints the fields it visits with a {@link Printer}.
37 *
4138 * @author Eric Bruneton
4239 */
4340 public final class TraceFieldVisitor extends FieldVisitor {
4441
45 public final Printer p;
42 /** The printer to convert the visited field into text. */
43 public final Printer p;
4644
47 public TraceFieldVisitor(final Printer p) {
48 this(null, p);
49 }
45 /**
46 * Constructs a new {@link TraceFieldVisitor}.
47 *
48 * @param printer the printer to convert the visited field into text.
49 */
50 public TraceFieldVisitor(final Printer printer) {
51 this(null, printer);
52 }
5053
51 public TraceFieldVisitor(final FieldVisitor fv, final Printer p) {
52 super(Opcodes.ASM6, fv);
53 this.p = p;
54 }
54 /**
55 * Constructs a new {@link TraceFieldVisitor}.
56 *
57 * @param fieldVisitor the field visitor to which to delegate calls. May be <tt>null</tt>.
58 * @param printer the printer to convert the visited field into text.
59 */
60 public TraceFieldVisitor(final FieldVisitor fieldVisitor, final Printer printer) {
61 super(Opcodes.ASM6, fieldVisitor);
62 this.p = printer;
63 }
5564
56 @Override
57 public AnnotationVisitor visitAnnotation(final String desc,
58 final boolean visible) {
59 Printer p = this.p.visitFieldAnnotation(desc, visible);
60 AnnotationVisitor av = fv == null ? null : fv.visitAnnotation(desc,
61 visible);
62 return new TraceAnnotationVisitor(av, p);
63 }
65 @Override
66 public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
67 Printer annotationPrinter = p.visitFieldAnnotation(descriptor, visible);
68 return new TraceAnnotationVisitor(
69 super.visitAnnotation(descriptor, visible), annotationPrinter);
70 }
6471
65 @Override
66 public AnnotationVisitor visitTypeAnnotation(int typeRef,
67 TypePath typePath, String desc, boolean visible) {
68 Printer p = this.p.visitFieldTypeAnnotation(typeRef, typePath, desc,
69 visible);
70 AnnotationVisitor av = fv == null ? null : fv.visitTypeAnnotation(
71 typeRef, typePath, desc, visible);
72 return new TraceAnnotationVisitor(av, p);
73 }
72 @Override
73 public AnnotationVisitor visitTypeAnnotation(
74 final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
75 Printer annotationPrinter = p.visitFieldTypeAnnotation(typeRef, typePath, descriptor, visible);
76 return new TraceAnnotationVisitor(
77 super.visitTypeAnnotation(typeRef, typePath, descriptor, visible), annotationPrinter);
78 }
7479
75 @Override
76 public void visitAttribute(final Attribute attr) {
77 p.visitFieldAttribute(attr);
78 super.visitAttribute(attr);
79 }
80 @Override
81 public void visitAttribute(final Attribute attribute) {
82 p.visitFieldAttribute(attribute);
83 super.visitAttribute(attribute);
84 }
8085
81 @Override
82 public void visitEnd() {
83 p.visitFieldEnd();
84 super.visitEnd();
85 }
86 @Override
87 public void visitEnd() {
88 p.visitFieldEnd();
89 super.visitEnd();
90 }
8691 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.util;
3028
3129 import org.eclipse.persistence.internal.libraries.asm.AnnotationVisitor;
3735 import org.eclipse.persistence.internal.libraries.asm.TypePath;
3836
3937 /**
40 * A {@link MethodVisitor} that prints the methods it visits with a
41 * {@link Printer}.
42 *
38 * A {@link MethodVisitor} that prints the methods it visits with a {@link Printer}.
39 *
4340 * @author Eric Bruneton
4441 */
4542 public final class TraceMethodVisitor extends MethodVisitor {
4643
47 public final Printer p;
48
49 public TraceMethodVisitor(final Printer p) {
50 this(null, p);
44 /** The printer to convert the visited method into text. */
45 public final Printer p;
46
47 /**
48 * Constructs a new {@link TraceMethodVisitor}.
49 *
50 * @param printer the printer to convert the visited method into text.
51 */
52 public TraceMethodVisitor(final Printer printer) {
53 this(null, printer);
54 }
55
56 /**
57 * Constructs a new {@link TraceMethodVisitor}.
58 *
59 * @param methodVisitor the method visitor to which to delegate calls. May be <tt>null</tt>.
60 * @param printer the printer to convert the visited method into text.
61 */
62 public TraceMethodVisitor(final MethodVisitor methodVisitor, final Printer printer) {
63 super(Opcodes.ASM6, methodVisitor);
64 this.p = printer;
65 }
66
67 @Override
68 public void visitParameter(final String name, final int access) {
69 p.visitParameter(name, access);
70 super.visitParameter(name, access);
71 }
72
73 @Override
74 public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
75 Printer annotationPrinter = p.visitMethodAnnotation(descriptor, visible);
76 return new TraceAnnotationVisitor(
77 super.visitAnnotation(descriptor, visible), annotationPrinter);
78 }
79
80 @Override
81 public AnnotationVisitor visitTypeAnnotation(
82 final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
83 Printer annotationPrinter = p.visitMethodTypeAnnotation(typeRef, typePath, descriptor, visible);
84 return new TraceAnnotationVisitor(
85 super.visitTypeAnnotation(typeRef, typePath, descriptor, visible), annotationPrinter);
86 }
87
88 @Override
89 public void visitAttribute(final Attribute attribute) {
90 p.visitMethodAttribute(attribute);
91 super.visitAttribute(attribute);
92 }
93
94 @Override
95 public AnnotationVisitor visitAnnotationDefault() {
96 Printer annotationPrinter = p.visitAnnotationDefault();
97 return new TraceAnnotationVisitor(super.visitAnnotationDefault(), annotationPrinter);
98 }
99
100 @Override
101 public void visitAnnotableParameterCount(final int parameterCount, final boolean visible) {
102 p.visitAnnotableParameterCount(parameterCount, visible);
103 super.visitAnnotableParameterCount(parameterCount, visible);
104 }
105
106 @Override
107 public AnnotationVisitor visitParameterAnnotation(
108 final int parameter, final String descriptor, final boolean visible) {
109 Printer annotationPrinter = p.visitParameterAnnotation(parameter, descriptor, visible);
110 return new TraceAnnotationVisitor(
111 super.visitParameterAnnotation(parameter, descriptor, visible), annotationPrinter);
112 }
113
114 @Override
115 public void visitCode() {
116 p.visitCode();
117 super.visitCode();
118 }
119
120 @Override
121 public void visitFrame(
122 final int type,
123 final int nLocal,
124 final Object[] local,
125 final int nStack,
126 final Object[] stack) {
127 p.visitFrame(type, nLocal, local, nStack, stack);
128 super.visitFrame(type, nLocal, local, nStack, stack);
129 }
130
131 @Override
132 public void visitInsn(final int opcode) {
133 p.visitInsn(opcode);
134 super.visitInsn(opcode);
135 }
136
137 @Override
138 public void visitIntInsn(final int opcode, final int operand) {
139 p.visitIntInsn(opcode, operand);
140 super.visitIntInsn(opcode, operand);
141 }
142
143 @Override
144 public void visitVarInsn(final int opcode, final int var) {
145 p.visitVarInsn(opcode, var);
146 super.visitVarInsn(opcode, var);
147 }
148
149 @Override
150 public void visitTypeInsn(final int opcode, final String type) {
151 p.visitTypeInsn(opcode, type);
152 super.visitTypeInsn(opcode, type);
153 }
154
155 @Override
156 public void visitFieldInsn(
157 final int opcode, final String owner, final String name, final String descriptor) {
158 p.visitFieldInsn(opcode, owner, name, descriptor);
159 super.visitFieldInsn(opcode, owner, name, descriptor);
160 }
161
162 /** @deprecated*/
163 @Deprecated
164 @Override
165 public void visitMethodInsn(
166 final int opcode, final String owner, final String name, final String descriptor) {
167 if (api >= Opcodes.ASM5) {
168 super.visitMethodInsn(opcode, owner, name, descriptor);
169 return;
51170 }
52
53 public TraceMethodVisitor(final MethodVisitor mv, final Printer p) {
54 super(Opcodes.ASM6, mv);
55 this.p = p;
171 p.visitMethodInsn(opcode, owner, name, descriptor);
172 if (mv != null) {
173 mv.visitMethodInsn(opcode, owner, name, descriptor);
56174 }
57
58 @Override
59 public void visitParameter(String name, int access) {
60 p.visitParameter(name, access);
61 super.visitParameter(name, access);
175 }
176
177 @Override
178 public void visitMethodInsn(
179 final int opcode,
180 final String owner,
181 final String name,
182 final String descriptor,
183 final boolean isInterface) {
184 if (api < Opcodes.ASM5) {
185 super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
186 return;
62187 }
63
64 @Override
65 public AnnotationVisitor visitAnnotation(final String desc,
66 final boolean visible) {
67 Printer p = this.p.visitMethodAnnotation(desc, visible);
68 AnnotationVisitor av = mv == null ? null : mv.visitAnnotation(desc,
69 visible);
70 return new TraceAnnotationVisitor(av, p);
188 p.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
189 if (mv != null) {
190 mv.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
71191 }
72
73 @Override
74 public AnnotationVisitor visitTypeAnnotation(int typeRef,
75 TypePath typePath, String desc, boolean visible) {
76 Printer p = this.p.visitMethodTypeAnnotation(typeRef, typePath, desc,
77 visible);
78 AnnotationVisitor av = mv == null ? null : mv.visitTypeAnnotation(
79 typeRef, typePath, desc, visible);
80 return new TraceAnnotationVisitor(av, p);
81 }
82
83 @Override
84 public void visitAttribute(final Attribute attr) {
85 p.visitMethodAttribute(attr);
86 super.visitAttribute(attr);
87 }
88
89 @Override
90 public AnnotationVisitor visitAnnotationDefault() {
91 Printer p = this.p.visitAnnotationDefault();
92 AnnotationVisitor av = mv == null ? null : mv.visitAnnotationDefault();
93 return new TraceAnnotationVisitor(av, p);
94 }
95
96 @Override
97 public AnnotationVisitor visitParameterAnnotation(final int parameter,
98 final String desc, final boolean visible) {
99 Printer p = this.p.visitParameterAnnotation(parameter, desc, visible);
100 AnnotationVisitor av = mv == null ? null : mv.visitParameterAnnotation(
101 parameter, desc, visible);
102 return new TraceAnnotationVisitor(av, p);
103 }
104
105 @Override
106 public void visitCode() {
107 p.visitCode();
108 super.visitCode();
109 }
110
111 @Override
112 public void visitFrame(final int type, final int nLocal,
113 final Object[] local, final int nStack, final Object[] stack) {
114 p.visitFrame(type, nLocal, local, nStack, stack);
115 super.visitFrame(type, nLocal, local, nStack, stack);
116 }
117
118 @Override
119 public void visitInsn(final int opcode) {
120 p.visitInsn(opcode);
121 super.visitInsn(opcode);
122 }
123
124 @Override
125 public void visitIntInsn(final int opcode, final int operand) {
126 p.visitIntInsn(opcode, operand);
127 super.visitIntInsn(opcode, operand);
128 }
129
130 @Override
131 public void visitVarInsn(final int opcode, final int var) {
132 p.visitVarInsn(opcode, var);
133 super.visitVarInsn(opcode, var);
134 }
135
136 @Override
137 public void visitTypeInsn(final int opcode, final String type) {
138 p.visitTypeInsn(opcode, type);
139 super.visitTypeInsn(opcode, type);
140 }
141
142 @Override
143 public void visitFieldInsn(final int opcode, final String owner,
144 final String name, final String desc) {
145 p.visitFieldInsn(opcode, owner, name, desc);
146 super.visitFieldInsn(opcode, owner, name, desc);
147 }
148
149 @Deprecated
150 @Override
151 public void visitMethodInsn(int opcode, String owner, String name,
152 String desc) {
153 if (api >= Opcodes.ASM5) {
154 super.visitMethodInsn(opcode, owner, name, desc);
155 return;
156 }
157 p.visitMethodInsn(opcode, owner, name, desc);
158 if (mv != null) {
159 mv.visitMethodInsn(opcode, owner, name, desc);
160 }
161 }
162
163 @Override
164 public void visitMethodInsn(int opcode, String owner, String name,
165 String desc, boolean itf) {
166 if (api < Opcodes.ASM5) {
167 super.visitMethodInsn(opcode, owner, name, desc, itf);
168 return;
169 }
170 p.visitMethodInsn(opcode, owner, name, desc, itf);
171 if (mv != null) {
172 mv.visitMethodInsn(opcode, owner, name, desc, itf);
173 }
174 }
175
176 @Override
177 public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
178 Object... bsmArgs) {
179 p.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
180 super.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
181 }
182
183 @Override
184 public void visitJumpInsn(final int opcode, final Label label) {
185 p.visitJumpInsn(opcode, label);
186 super.visitJumpInsn(opcode, label);
187 }
188
189 @Override
190 public void visitLabel(final Label label) {
191 p.visitLabel(label);
192 super.visitLabel(label);
193 }
194
195 @Override
196 public void visitLdcInsn(final Object cst) {
197 p.visitLdcInsn(cst);
198 super.visitLdcInsn(cst);
199 }
200
201 @Override
202 public void visitIincInsn(final int var, final int increment) {
203 p.visitIincInsn(var, increment);
204 super.visitIincInsn(var, increment);
205 }
206
207 @Override
208 public void visitTableSwitchInsn(final int min, final int max,
209 final Label dflt, final Label... labels) {
210 p.visitTableSwitchInsn(min, max, dflt, labels);
211 super.visitTableSwitchInsn(min, max, dflt, labels);
212 }
213
214 @Override
215 public void visitLookupSwitchInsn(final Label dflt, final int[] keys,
216 final Label[] labels) {
217 p.visitLookupSwitchInsn(dflt, keys, labels);
218 super.visitLookupSwitchInsn(dflt, keys, labels);
219 }
220
221 @Override
222 public void visitMultiANewArrayInsn(final String desc, final int dims) {
223 p.visitMultiANewArrayInsn(desc, dims);
224 super.visitMultiANewArrayInsn(desc, dims);
225 }
226
227 @Override
228 public AnnotationVisitor visitInsnAnnotation(int typeRef,
229 TypePath typePath, String desc, boolean visible) {
230 Printer p = this.p
231 .visitInsnAnnotation(typeRef, typePath, desc, visible);
232 AnnotationVisitor av = mv == null ? null : mv.visitInsnAnnotation(
233 typeRef, typePath, desc, visible);
234 return new TraceAnnotationVisitor(av, p);
235 }
236
237 @Override
238 public void visitTryCatchBlock(final Label start, final Label end,
239 final Label handler, final String type) {
240 p.visitTryCatchBlock(start, end, handler, type);
241 super.visitTryCatchBlock(start, end, handler, type);
242 }
243
244 @Override
245 public AnnotationVisitor visitTryCatchAnnotation(int typeRef,
246 TypePath typePath, String desc, boolean visible) {
247 Printer p = this.p.visitTryCatchAnnotation(typeRef, typePath, desc,
248 visible);
249 AnnotationVisitor av = mv == null ? null : mv.visitTryCatchAnnotation(
250 typeRef, typePath, desc, visible);
251 return new TraceAnnotationVisitor(av, p);
252 }
253
254 @Override
255 public void visitLocalVariable(final String name, final String desc,
256 final String signature, final Label start, final Label end,
257 final int index) {
258 p.visitLocalVariable(name, desc, signature, start, end, index);
259 super.visitLocalVariable(name, desc, signature, start, end, index);
260 }
261
262 @Override
263 public AnnotationVisitor visitLocalVariableAnnotation(int typeRef,
264 TypePath typePath, Label[] start, Label[] end, int[] index,
265 String desc, boolean visible) {
266 Printer p = this.p.visitLocalVariableAnnotation(typeRef, typePath,
267 start, end, index, desc, visible);
268 AnnotationVisitor av = mv == null ? null : mv
269 .visitLocalVariableAnnotation(typeRef, typePath, start, end,
270 index, desc, visible);
271 return new TraceAnnotationVisitor(av, p);
272 }
273
274 @Override
275 public void visitLineNumber(final int line, final Label start) {
276 p.visitLineNumber(line, start);
277 super.visitLineNumber(line, start);
278 }
279
280 @Override
281 public void visitMaxs(final int maxStack, final int maxLocals) {
282 p.visitMaxs(maxStack, maxLocals);
283 super.visitMaxs(maxStack, maxLocals);
284 }
285
286 @Override
287 public void visitEnd() {
288 p.visitMethodEnd();
289 super.visitEnd();
290 }
192 }
193
194 @Override
195 public void visitInvokeDynamicInsn(
196 final String name,
197 final String descriptor,
198 final Handle bootstrapMethodHandle,
199 final Object... bootstrapMethodArguments) {
200 p.visitInvokeDynamicInsn(name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments);
201 super.visitInvokeDynamicInsn(name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments);
202 }
203
204 @Override
205 public void visitJumpInsn(final int opcode, final Label label) {
206 p.visitJumpInsn(opcode, label);
207 super.visitJumpInsn(opcode, label);
208 }
209
210 @Override
211 public void visitLabel(final Label label) {
212 p.visitLabel(label);
213 super.visitLabel(label);
214 }
215
216 @Override
217 public void visitLdcInsn(final Object value) {
218 p.visitLdcInsn(value);
219 super.visitLdcInsn(value);
220 }
221
222 @Override
223 public void visitIincInsn(final int var, final int increment) {
224 p.visitIincInsn(var, increment);
225 super.visitIincInsn(var, increment);
226 }
227
228 @Override
229 public void visitTableSwitchInsn(
230 final int min, final int max, final Label dflt, final Label... labels) {
231 p.visitTableSwitchInsn(min, max, dflt, labels);
232 super.visitTableSwitchInsn(min, max, dflt, labels);
233 }
234
235 @Override
236 public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) {
237 p.visitLookupSwitchInsn(dflt, keys, labels);
238 super.visitLookupSwitchInsn(dflt, keys, labels);
239 }
240
241 @Override
242 public void visitMultiANewArrayInsn(final String descriptor, final int numDimensions) {
243 p.visitMultiANewArrayInsn(descriptor, numDimensions);
244 super.visitMultiANewArrayInsn(descriptor, numDimensions);
245 }
246
247 @Override
248 public AnnotationVisitor visitInsnAnnotation(
249 final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
250 Printer annotationPrinter = p.visitInsnAnnotation(typeRef, typePath, descriptor, visible);
251 return new TraceAnnotationVisitor(
252 super.visitInsnAnnotation(typeRef, typePath, descriptor, visible), annotationPrinter);
253 }
254
255 @Override
256 public void visitTryCatchBlock(
257 final Label start, final Label end, final Label handler, final String type) {
258 p.visitTryCatchBlock(start, end, handler, type);
259 super.visitTryCatchBlock(start, end, handler, type);
260 }
261
262 @Override
263 public AnnotationVisitor visitTryCatchAnnotation(
264 final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
265 Printer annotationPrinter = p.visitTryCatchAnnotation(typeRef, typePath, descriptor, visible);
266 return new TraceAnnotationVisitor(
267 super.visitTryCatchAnnotation(typeRef, typePath, descriptor, visible), annotationPrinter);
268 }
269
270 @Override
271 public void visitLocalVariable(
272 final String name,
273 final String descriptor,
274 final String signature,
275 final Label start,
276 final Label end,
277 final int index) {
278 p.visitLocalVariable(name, descriptor, signature, start, end, index);
279 super.visitLocalVariable(name, descriptor, signature, start, end, index);
280 }
281
282 @Override
283 public AnnotationVisitor visitLocalVariableAnnotation(
284 final int typeRef,
285 final TypePath typePath,
286 final Label[] start,
287 final Label[] end,
288 final int[] index,
289 final String descriptor,
290 final boolean visible) {
291 Printer annotationPrinter =
292 p.visitLocalVariableAnnotation(typeRef, typePath, start, end, index, descriptor, visible);
293 return new TraceAnnotationVisitor(
294 super.visitLocalVariableAnnotation(
295 typeRef, typePath, start, end, index, descriptor, visible),
296 annotationPrinter);
297 }
298
299 @Override
300 public void visitLineNumber(final int line, final Label start) {
301 p.visitLineNumber(line, start);
302 super.visitLineNumber(line, start);
303 }
304
305 @Override
306 public void visitMaxs(final int maxStack, final int maxLocals) {
307 p.visitMaxs(maxStack, maxLocals);
308 super.visitMaxs(maxStack, maxLocals);
309 }
310
311 @Override
312 public void visitEnd() {
313 p.visitMethodEnd();
314 super.visitEnd();
315 }
291316 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.util;
3028
3129 import org.eclipse.persistence.internal.libraries.asm.ModuleVisitor;
3230 import org.eclipse.persistence.internal.libraries.asm.Opcodes;
3331
3432 /**
35 * A {@link ModuleVisitor} that prints the fields it visits with a
36 * {@link Printer}.
37 *
33 * A {@link ModuleVisitor} that prints the fields it visits with a {@link Printer}.
34 *
3835 * @author Remi Forax
3936 */
4037 public final class TraceModuleVisitor extends ModuleVisitor {
41
42 public final Printer p;
4338
44 public TraceModuleVisitor(final Printer p) {
45 this(null, p);
46 }
39 /** The printer to convert the visited module into text. */
40 public final Printer p;
4741
48 public TraceModuleVisitor(final ModuleVisitor mv, final Printer p) {
49 super(Opcodes.ASM6, mv);
50 this.p = p;
51 }
42 /**
43 * Constructs a new {@link TraceModuleVisitor}.
44 *
45 * @param printer the printer to convert the visited module into text.
46 */
47 public TraceModuleVisitor(final Printer printer) {
48 this(null, printer);
49 }
5250
53 @Override
54 public void visitRequire(String module, int access) {
55 p.visitRequire(module, access);
56 super.visitRequire(module, access);
57 }
58
59 @Override
60 public void visitExport(String packaze, String... modules) {
61 p.visitExport(packaze, modules);
62 super.visitExport(packaze, modules);
63 }
64
65 @Override
66 public void visitUse(String use) {
67 p.visitUse(use);
68 super.visitUse(use);
69 }
70
71 @Override
72 public void visitProvide(String service, String impl) {
73 p.visitProvide(service, impl);
74 super.visitProvide(service, impl);
75 }
51 /**
52 * Constructs a new {@link TraceModuleVisitor}.
53 *
54 * @param moduleVisitor the module visitor to which to delegate calls. May be <tt>null</tt>.
55 * @param printer the printer to convert the visited module into text.
56 */
57 public TraceModuleVisitor(final ModuleVisitor moduleVisitor, final Printer printer) {
58 super(Opcodes.ASM6, moduleVisitor);
59 this.p = printer;
60 }
7661
77 @Override
78 public void visitEnd() {
79 p.visitModuleEnd();
80 super.visitEnd();
81 }
62 @Override
63 public void visitMainClass(final String mainClass) {
64 p.visitMainClass(mainClass);
65 super.visitMainClass(mainClass);
66 }
67
68 @Override
69 public void visitPackage(final String packaze) {
70 p.visitPackage(packaze);
71 super.visitPackage(packaze);
72 }
73
74 @Override
75 public void visitRequire(final String module, final int access, final String version) {
76 p.visitRequire(module, access, version);
77 super.visitRequire(module, access, version);
78 }
79
80 @Override
81 public void visitExport(final String packaze, final int access, final String... modules) {
82 p.visitExport(packaze, access, modules);
83 super.visitExport(packaze, access, modules);
84 }
85
86 @Override
87 public void visitOpen(final String packaze, final int access, final String... modules) {
88 p.visitOpen(packaze, access, modules);
89 super.visitOpen(packaze, access, modules);
90 }
91
92 @Override
93 public void visitUse(final String use) {
94 p.visitUse(use);
95 super.visitUse(use);
96 }
97
98 @Override
99 public void visitProvide(final String service, final String... providers) {
100 p.visitProvide(service, providers);
101 super.visitProvide(service, providers);
102 }
103
104 @Override
105 public void visitEnd() {
106 p.visitModuleEnd();
107 super.visitEnd();
108 }
82109 }
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.util;
3028
3129 import org.eclipse.persistence.internal.libraries.asm.Opcodes;
3230 import org.eclipse.persistence.internal.libraries.asm.signature.SignatureVisitor;
3331
3432 /**
35 * A {@link SignatureVisitor} that prints a disassembled view of the signature
36 * it visits.
37 *
33 * A {@link SignatureVisitor} that builds the Java generic type declaration corresponding to the
34 * signature it visits.
35 *
3836 * @author Eugene Kuleshov
3937 * @author Eric Bruneton
4038 */
4139 public final class TraceSignatureVisitor extends SignatureVisitor {
4240
43 private final StringBuilder declaration;
44
45 private boolean isInterface;
46
47 private boolean seenFormalParameter;
48
49 private boolean seenInterfaceBound;
50
51 private boolean seenParameter;
52
53 private boolean seenInterface;
54
55 private StringBuilder returnType;
56
57 private StringBuilder exceptions;
58
59 /**
60 * Stack used to keep track of class types that have arguments. Each element
61 * of this stack is a boolean encoded in one bit. The top of the stack is
62 * the lowest order bit. Pushing false = *2, pushing true = *2+1, popping =
63 * /2.
64 */
65 private int argumentStack;
66
67 /**
68 * Stack used to keep track of array class types. Each element of this stack
69 * is a boolean encoded in one bit. The top of the stack is the lowest order
70 * bit. Pushing false = *2, pushing true = *2+1, popping = /2.
71 */
72 private int arrayStack;
73
74 private String separator = "";
75
76 public TraceSignatureVisitor(final int access) {
77 super(Opcodes.ASM6);
78 isInterface = (access & Opcodes.ACC_INTERFACE) != 0;
79 this.declaration = new StringBuilder();
80 }
81
82 private TraceSignatureVisitor(final StringBuilder buf) {
83 super(Opcodes.ASM6);
84 this.declaration = buf;
85 }
86
87 @Override
88 public void visitFormalTypeParameter(final String name) {
89 declaration.append(seenFormalParameter ? ", " : "<").append(name);
90 seenFormalParameter = true;
91 seenInterfaceBound = false;
92 }
93
94 @Override
95 public SignatureVisitor visitClassBound() {
96 separator = " extends ";
97 startType();
98 return this;
99 }
100
101 @Override
102 public SignatureVisitor visitInterfaceBound() {
103 separator = seenInterfaceBound ? ", " : " extends ";
104 seenInterfaceBound = true;
105 startType();
106 return this;
107 }
108
109 @Override
110 public SignatureVisitor visitSuperclass() {
111 endFormals();
112 separator = " extends ";
113 startType();
114 return this;
115 }
116
117 @Override
118 public SignatureVisitor visitInterface() {
119 separator = seenInterface ? ", " : isInterface ? " extends "
120 : " implements ";
121 seenInterface = true;
122 startType();
123 return this;
124 }
125
126 @Override
127 public SignatureVisitor visitParameterType() {
128 endFormals();
129 if (seenParameter) {
130 declaration.append(", ");
131 } else {
132 seenParameter = true;
133 declaration.append('(');
134 }
135 startType();
136 return this;
137 }
138
139 @Override
140 public SignatureVisitor visitReturnType() {
141 endFormals();
142 if (seenParameter) {
143 seenParameter = false;
144 } else {
145 declaration.append('(');
146 }
147 declaration.append(')');
148 returnType = new StringBuilder();
149 return new TraceSignatureVisitor(returnType);
150 }
151
152 @Override
153 public SignatureVisitor visitExceptionType() {
154 if (exceptions == null) {
155 exceptions = new StringBuilder();
156 } else {
157 exceptions.append(", ");
158 }
159 // startType();
160 return new TraceSignatureVisitor(exceptions);
161 }
162
163 @Override
164 public void visitBaseType(final char descriptor) {
165 switch (descriptor) {
166 case 'V':
167 declaration.append("void");
168 break;
169 case 'B':
170 declaration.append("byte");
171 break;
172 case 'J':
173 declaration.append("long");
174 break;
175 case 'Z':
176 declaration.append("boolean");
177 break;
178 case 'I':
179 declaration.append("int");
180 break;
181 case 'S':
182 declaration.append("short");
183 break;
184 case 'C':
185 declaration.append("char");
186 break;
187 case 'F':
188 declaration.append("float");
189 break;
190 // case 'D':
191 default:
192 declaration.append("double");
193 break;
194 }
195 endType();
196 }
197
198 @Override
199 public void visitTypeVariable(final String name) {
200 declaration.append(name);
201 endType();
202 }
203
204 @Override
205 public SignatureVisitor visitArrayType() {
206 startType();
207 arrayStack |= 1;
208 return this;
209 }
210
211 @Override
212 public void visitClassType(final String name) {
213 if ("java/lang/Object".equals(name)) {
214 // Map<java.lang.Object,java.util.List>
215 // or
216 // abstract public V get(Object key); (seen in Dictionary.class)
217 // should have Object
218 // but java.lang.String extends java.lang.Object is unnecessary
219 boolean needObjectClass = argumentStack % 2 != 0 || seenParameter;
220 if (needObjectClass) {
221 declaration.append(separator).append(name.replace('/', '.'));
222 }
223 } else {
224 declaration.append(separator).append(name.replace('/', '.'));
225 }
226 separator = "";
227 argumentStack *= 2;
228 }
229
230 @Override
231 public void visitInnerClassType(final String name) {
232 if (argumentStack % 2 != 0) {
233 declaration.append('>');
234 }
235 argumentStack /= 2;
236 declaration.append('.');
41 private static final String COMMA_SEPARATOR = ", ";
42 private static final String EXTENDS_SEPARATOR = " extends ";
43 private static final String IMPLEMENTS_SEPARATOR = " implements ";
44
45 /** Whether the visited signature is a class signature of a Java interface. */
46 private final boolean isInterface;
47
48 /** The Java generic type declaration corresponding to the visited signature. */
49 private final StringBuilder declaration;
50
51 /** The Java generic method return type declaration corresponding to the visited signature. */
52 private StringBuilder returnType;
53
54 /** The Java generic exception types declaration corresponding to the visited signature. */
55 private StringBuilder exceptions;
56
57 /** Whether {@link #visitFormalTypeParameter} has been called. */
58 private boolean formalTypeParameterVisited;
59
60 /** Whether {@link #visitInterfaceBound} has been called. */
61 private boolean interfaceBoundVisited;
62
63 /** Whether {@link #visitParameterType} has been called. */
64 private boolean parameterTypeVisited;
65
66 /** Whether {@link #visitInterface} has been called. */
67 private boolean interfaceVisited;
68
69 /**
70 * The stack used to keep track of class types that have arguments. Each element of this stack is
71 * a boolean encoded in one bit. The top of the stack is the least significant bit. Pushing false
72 * = *2, pushing true = *2+1, popping = /2.
73 */
74 private int argumentStack;
75
76 /**
77 * The stack used to keep track of array class types. Each element of this stack is a boolean
78 * encoded in one bit. The top of the stack is the lowest order bit. Pushing false = *2, pushing
79 * true = *2+1, popping = /2.
80 */
81 private int arrayStack;
82
83 /** The separator to append before the next visited class or inner class type. */
84 private String separator = "";
85
86 /**
87 * Constructs a new {@link TraceSignatureVisitor}.
88 *
89 * @param accessFlags for class type signatures, the access flags of the class.
90 */
91 public TraceSignatureVisitor(final int accessFlags) {
92 super(Opcodes.ASM6);
93 this.isInterface = (accessFlags & Opcodes.ACC_INTERFACE) != 0;
94 this.declaration = new StringBuilder();
95 }
96
97 private TraceSignatureVisitor(final StringBuilder stringBuilder) {
98 super(Opcodes.ASM6);
99 this.isInterface = false;
100 this.declaration = stringBuilder;
101 }
102
103 @Override
104 public void visitFormalTypeParameter(final String name) {
105 declaration.append(formalTypeParameterVisited ? COMMA_SEPARATOR : "<").append(name);
106 formalTypeParameterVisited = true;
107 interfaceBoundVisited = false;
108 }
109
110 @Override
111 public SignatureVisitor visitClassBound() {
112 separator = EXTENDS_SEPARATOR;
113 startType();
114 return this;
115 }
116
117 @Override
118 public SignatureVisitor visitInterfaceBound() {
119 separator = interfaceBoundVisited ? COMMA_SEPARATOR : EXTENDS_SEPARATOR;
120 interfaceBoundVisited = true;
121 startType();
122 return this;
123 }
124
125 @Override
126 public SignatureVisitor visitSuperclass() {
127 endFormals();
128 separator = EXTENDS_SEPARATOR;
129 startType();
130 return this;
131 }
132
133 @Override
134 public SignatureVisitor visitInterface() {
135 if (interfaceVisited) {
136 separator = COMMA_SEPARATOR;
137 } else {
138 separator = isInterface ? EXTENDS_SEPARATOR : IMPLEMENTS_SEPARATOR;
139 interfaceVisited = true;
140 }
141 startType();
142 return this;
143 }
144
145 @Override
146 public SignatureVisitor visitParameterType() {
147 endFormals();
148 if (parameterTypeVisited) {
149 declaration.append(COMMA_SEPARATOR);
150 } else {
151 declaration.append('(');
152 parameterTypeVisited = true;
153 }
154 startType();
155 return this;
156 }
157
158 @Override
159 public SignatureVisitor visitReturnType() {
160 endFormals();
161 if (parameterTypeVisited) {
162 parameterTypeVisited = false;
163 } else {
164 declaration.append('(');
165 }
166 declaration.append(')');
167 returnType = new StringBuilder();
168 return new TraceSignatureVisitor(returnType);
169 }
170
171 @Override
172 public SignatureVisitor visitExceptionType() {
173 if (exceptions == null) {
174 exceptions = new StringBuilder();
175 } else {
176 exceptions.append(COMMA_SEPARATOR);
177 }
178 return new TraceSignatureVisitor(exceptions);
179 }
180
181 @Override
182 public void visitBaseType(final char descriptor) {
183 switch (descriptor) {
184 case 'V':
185 declaration.append("void");
186 break;
187 case 'B':
188 declaration.append("byte");
189 break;
190 case 'J':
191 declaration.append("long");
192 break;
193 case 'Z':
194 declaration.append("boolean");
195 break;
196 case 'I':
197 declaration.append("int");
198 break;
199 case 'S':
200 declaration.append("short");
201 break;
202 case 'C':
203 declaration.append("char");
204 break;
205 case 'F':
206 declaration.append("float");
207 break;
208 case 'D':
209 declaration.append("double");
210 break;
211 default:
212 throw new IllegalArgumentException();
213 }
214 endType();
215 }
216
217 @Override
218 public void visitTypeVariable(final String name) {
219 declaration.append(separator).append(name);
220 separator = "";
221 endType();
222 }
223
224 @Override
225 public SignatureVisitor visitArrayType() {
226 startType();
227 arrayStack |= 1;
228 return this;
229 }
230
231 @Override
232 public void visitClassType(final String name) {
233 if ("java/lang/Object".equals(name)) {
234 // 'Map<java.lang.Object,java.util.List>' or 'abstract public V get(Object key);' should have
235 // Object 'but java.lang.String extends java.lang.Object' is unnecessary.
236 boolean needObjectClass = argumentStack % 2 != 0 || parameterTypeVisited;
237 if (needObjectClass) {
237238 declaration.append(separator).append(name.replace('/', '.'));
238 separator = "";
239 argumentStack *= 2;
240 }
241
242 @Override
243 public void visitTypeArgument() {
244 if (argumentStack % 2 == 0) {
245 ++argumentStack;
246 declaration.append('<');
247 } else {
248 declaration.append(", ");
249 }
250 declaration.append('?');
251 }
252
253 @Override
254 public SignatureVisitor visitTypeArgument(final char tag) {
255 if (argumentStack % 2 == 0) {
256 ++argumentStack;
257 declaration.append('<');
258 } else {
259 declaration.append(", ");
260 }
261
262 if (tag == EXTENDS) {
263 declaration.append("? extends ");
264 } else if (tag == SUPER) {
265 declaration.append("? super ");
266 }
267
268 startType();
269 return this;
270 }
271
272 @Override
273 public void visitEnd() {
274 if (argumentStack % 2 != 0) {
275 declaration.append('>');
276 }
277 argumentStack /= 2;
278 endType();
279 }
280
281 public String getDeclaration() {
282 return declaration.toString();
283 }
284
285 public String getReturnType() {
286 return returnType == null ? null : returnType.toString();
287 }
288
289 public String getExceptions() {
290 return exceptions == null ? null : exceptions.toString();
291 }
292
293 // -----------------------------------------------
294
295 private void endFormals() {
296 if (seenFormalParameter) {
297 declaration.append('>');
298 seenFormalParameter = false;
299 }
300 }
301
302 private void startType() {
303 arrayStack *= 2;
304 }
305
306 private void endType() {
307 if (arrayStack % 2 == 0) {
308 arrayStack /= 2;
309 } else {
310 while (arrayStack % 2 != 0) {
311 arrayStack /= 2;
312 declaration.append("[]");
313 }
314 }
315 }
239 }
240 } else {
241 declaration.append(separator).append(name.replace('/', '.'));
242 }
243 separator = "";
244 argumentStack *= 2;
245 }
246
247 @Override
248 public void visitInnerClassType(final String name) {
249 if (argumentStack % 2 != 0) {
250 declaration.append('>');
251 }
252 argumentStack /= 2;
253 declaration.append('.');
254 declaration.append(separator).append(name.replace('/', '.'));
255 separator = "";
256 argumentStack *= 2;
257 }
258
259 @Override
260 public void visitTypeArgument() {
261 if (argumentStack % 2 == 0) {
262 ++argumentStack;
263 declaration.append('<');
264 } else {
265 declaration.append(COMMA_SEPARATOR);
266 }
267 declaration.append('?');
268 }
269
270 @Override
271 public SignatureVisitor visitTypeArgument(final char tag) {
272 if (argumentStack % 2 == 0) {
273 ++argumentStack;
274 declaration.append('<');
275 } else {
276 declaration.append(COMMA_SEPARATOR);
277 }
278
279 if (tag == EXTENDS) {
280 declaration.append("? extends ");
281 } else if (tag == SUPER) {
282 declaration.append("? super ");
283 }
284
285 startType();
286 return this;
287 }
288
289 @Override
290 public void visitEnd() {
291 if (argumentStack % 2 != 0) {
292 declaration.append('>');
293 }
294 argumentStack /= 2;
295 endType();
296 }
297
298 // -----------------------------------------------------------------------------------------------
299
300 /** @return the Java generic type declaration corresponding to the visited signature. */
301 public String getDeclaration() {
302 return declaration.toString();
303 }
304
305 /**
306 * @return the Java generic method return type declaration corresponding to the visited signature.
307 */
308 public String getReturnType() {
309 return returnType == null ? null : returnType.toString();
310 }
311
312 /**
313 * @return the Java generic exception types declaration corresponding to the visited signature.
314 */
315 public String getExceptions() {
316 return exceptions == null ? null : exceptions.toString();
317 }
318
319 // -----------------------------------------------------------------------------------------------
320
321 private void endFormals() {
322 if (formalTypeParameterVisited) {
323 declaration.append('>');
324 formalTypeParameterVisited = false;
325 }
326 }
327
328 private void startType() {
329 arrayStack *= 2;
330 }
331
332 private void endType() {
333 if (arrayStack % 2 == 0) {
334 arrayStack /= 2;
335 } else {
336 while (arrayStack % 2 != 0) {
337 arrayStack /= 2;
338 declaration.append("[]");
339 }
340 }
341 }
316342 }
+0
-40
org/eclipse/persistence/internal/libraries/asm/util/package.html less more
0 <html>
1 <!--
2 * ASM: a very small and fast Java bytecode manipulation framework
3 * Copyright (c) 2000-2011 INRIA, France Telecom
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the copyright holders nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
28 * THE POSSIBILITY OF SUCH DAMAGE.
29 -->
30 <body>
31 Provides ASM visitors that can be useful for programming and
32 debugging purposes. These class visitors are normally not used by applications
33 at runtime. This is why they are bundled in an optional <tt>asm-util.jar</tt>
34 library that is separated from (but requires) the <tt>asm.jar</tt> library,
35 which contains the core ASM framework.
36
37 @since ASM 1.3.2
38 </body>
39 </html>
0 /***
1 * ASM XML Adapter
2 * Copyright (c) 2004-2011, Eugene Kuleshov
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.xml;
3028
3129 import java.util.ArrayList;
4846 import org.xml.sax.helpers.DefaultHandler;
4947
5048 /**
51 * A {@link org.xml.sax.ContentHandler ContentHandler} that transforms XML
52 * document into Java class file. This class can be feeded by any kind of SAX
53 * 2.0 event producers, e.g. XML parser, XSLT or XPath engines, or custom code.
54 *
49 * A {@link org.xml.sax.ContentHandler ContentHandler} that transforms XML document into Java class
50 * file. This class can be feeded by any kind of SAX 2.0 event producers, e.g. XML parser, XSLT or
51 * XPath engines, or custom code.
52 *
53 * @deprecated This class is no longer maintained, will not support new Java features, and will
54 * eventually be deleted. Use the asm or asm.tree API instead.
5555 * @see org.eclipse.persistence.internal.libraries.asm.xml.SAXClassAdapter
5656 * @see org.eclipse.persistence.internal.libraries.asm.xml.Processor
57 *
5857 * @author Eugene Kuleshov
5958 */
59 @Deprecated
6060 public class ASMContentHandler extends DefaultHandler implements Opcodes {
6161
62 /**
63 * Stack of the intermediate processing contexts.
64 */
65 private final ArrayList<Object> stack = new ArrayList<Object>();
66
67 /**
68 * Complete name of the current element.
69 */
70 String match = "";
71
72 /**
73 * Current instance of the {@link ClassVisitor ClassVisitor} used to visit
74 * classfile bytecode.
75 */
76 protected ClassVisitor cv;
77
78 /**
79 * Map of the active {@link Label Label} instances for current method.
80 */
81 protected Map<Object, Label> labels;
82
83 private static final String BASE = "class";
84
85 private final RuleSet RULES = new RuleSet();
86 {
87 RULES.add(BASE, new ClassRule());
88 RULES.add(BASE + "/interfaces/interface", new InterfaceRule());
89 RULES.add(BASE + "/interfaces", new InterfacesRule());
90 RULES.add(BASE + "/outerclass", new OuterClassRule());
91 RULES.add(BASE + "/innerclass", new InnerClassRule());
92 RULES.add(BASE + "/source", new SourceRule());
93
94 ModuleRule moduleRule = new ModuleRule();
95 RULES.add(BASE + "/module", moduleRule);
96 RULES.add(BASE + "/module/requires", moduleRule);
97 RULES.add(BASE + "/module/exports", moduleRule);
98 RULES.add(BASE + "/module/exports/to", moduleRule);
99 RULES.add(BASE + "/module/uses", moduleRule);
100 RULES.add(BASE + "/module/provides", moduleRule);
101
102 RULES.add(BASE + "/field", new FieldRule());
103
104 RULES.add(BASE + "/method", new MethodRule());
105 RULES.add(BASE + "/method/exceptions/exception", new ExceptionRule());
106 RULES.add(BASE + "/method/exceptions", new ExceptionsRule());
107
108 RULES.add(BASE + "/method/parameter", new MethodParameterRule());
109 RULES.add(BASE + "/method/annotationDefault",
110 new AnnotationDefaultRule());
111
112 RULES.add(BASE + "/method/code/*", new OpcodesRule()); // opcodes
113
114 RULES.add(BASE + "/method/code/frame", new FrameRule());
115 RULES.add(BASE + "/method/code/frame/local", new FrameTypeRule());
116 RULES.add(BASE + "/method/code/frame/stack", new FrameTypeRule());
117
118 RULES.add(BASE + "/method/code/TABLESWITCH", new TableSwitchRule());
119 RULES.add(BASE + "/method/code/TABLESWITCH/label",
120 new TableSwitchLabelRule());
121 RULES.add(BASE + "/method/code/LOOKUPSWITCH", new LookupSwitchRule());
122 RULES.add(BASE + "/method/code/LOOKUPSWITCH/label",
123 new LookupSwitchLabelRule());
124
125 RULES.add(BASE + "/method/code/INVOKEDYNAMIC", new InvokeDynamicRule());
126 RULES.add(BASE + "/method/code/INVOKEDYNAMIC/bsmArg",
127 new InvokeDynamicBsmArgumentsRule());
128
129 RULES.add(BASE + "/method/code/Label", new LabelRule());
130 RULES.add(BASE + "/method/code/TryCatch", new TryCatchRule());
131 RULES.add(BASE + "/method/code/LineNumber", new LineNumberRule());
132 RULES.add(BASE + "/method/code/LocalVar", new LocalVarRule());
133 RULES.add(BASE + "/method/code/Max", new MaxRule());
134
135 RULES.add("*/annotation", new AnnotationRule());
136 RULES.add("*/typeAnnotation", new TypeAnnotationRule());
137 RULES.add("*/parameterAnnotation", new AnnotationParameterRule());
138 RULES.add("*/insnAnnotation", new InsnAnnotationRule());
139 RULES.add("*/tryCatchAnnotation", new TryCatchAnnotationRule());
140 RULES.add("*/localVariableAnnotation",
141 new LocalVariableAnnotationRule());
142 RULES.add("*/annotationValue", new AnnotationValueRule());
143 RULES.add("*/annotationValueAnnotation",
144 new AnnotationValueAnnotationRule());
145 RULES.add("*/annotationValueEnum", new AnnotationValueEnumRule());
146 RULES.add("*/annotationValueArray", new AnnotationValueArrayRule());
147 }
148
149 private static interface OpcodeGroup {
150 public static final int INSN = 0;
151 public static final int INSN_INT = 1;
152 public static final int INSN_VAR = 2;
153 public static final int INSN_TYPE = 3;
154 public static final int INSN_FIELD = 4;
155 public static final int INSN_METHOD = 5;
156 public static final int INSN_JUMP = 6;
157 public static final int INSN_LDC = 7;
158 public static final int INSN_IINC = 8;
159 public static final int INSN_MULTIANEWARRAY = 9;
160 }
161
162 /**
163 * Map of the opcode names to opcode and opcode group
164 */
165 static final HashMap<String, Opcode> OPCODES = new HashMap<String, Opcode>();
166 static {
167 addOpcode("NOP", NOP, OpcodeGroup.INSN);
168 addOpcode("ACONST_NULL", ACONST_NULL, OpcodeGroup.INSN);
169 addOpcode("ICONST_M1", ICONST_M1, OpcodeGroup.INSN);
170 addOpcode("ICONST_0", ICONST_0, OpcodeGroup.INSN);
171 addOpcode("ICONST_1", ICONST_1, OpcodeGroup.INSN);
172 addOpcode("ICONST_2", ICONST_2, OpcodeGroup.INSN);
173 addOpcode("ICONST_3", ICONST_3, OpcodeGroup.INSN);
174 addOpcode("ICONST_4", ICONST_4, OpcodeGroup.INSN);
175 addOpcode("ICONST_5", ICONST_5, OpcodeGroup.INSN);
176 addOpcode("LCONST_0", LCONST_0, OpcodeGroup.INSN);
177 addOpcode("LCONST_1", LCONST_1, OpcodeGroup.INSN);
178 addOpcode("FCONST_0", FCONST_0, OpcodeGroup.INSN);
179 addOpcode("FCONST_1", FCONST_1, OpcodeGroup.INSN);
180 addOpcode("FCONST_2", FCONST_2, OpcodeGroup.INSN);
181 addOpcode("DCONST_0", DCONST_0, OpcodeGroup.INSN);
182 addOpcode("DCONST_1", DCONST_1, OpcodeGroup.INSN);
183 addOpcode("BIPUSH", BIPUSH, OpcodeGroup.INSN_INT);
184 addOpcode("SIPUSH", SIPUSH, OpcodeGroup.INSN_INT);
185 addOpcode("LDC", LDC, OpcodeGroup.INSN_LDC);
186 addOpcode("ILOAD", ILOAD, OpcodeGroup.INSN_VAR);
187 addOpcode("LLOAD", LLOAD, OpcodeGroup.INSN_VAR);
188 addOpcode("FLOAD", FLOAD, OpcodeGroup.INSN_VAR);
189 addOpcode("DLOAD", DLOAD, OpcodeGroup.INSN_VAR);
190 addOpcode("ALOAD", ALOAD, OpcodeGroup.INSN_VAR);
191 addOpcode("IALOAD", IALOAD, OpcodeGroup.INSN);
192 addOpcode("LALOAD", LALOAD, OpcodeGroup.INSN);
193 addOpcode("FALOAD", FALOAD, OpcodeGroup.INSN);
194 addOpcode("DALOAD", DALOAD, OpcodeGroup.INSN);
195 addOpcode("AALOAD", AALOAD, OpcodeGroup.INSN);
196 addOpcode("BALOAD", BALOAD, OpcodeGroup.INSN);
197 addOpcode("CALOAD", CALOAD, OpcodeGroup.INSN);
198 addOpcode("SALOAD", SALOAD, OpcodeGroup.INSN);
199 addOpcode("ISTORE", ISTORE, OpcodeGroup.INSN_VAR);
200 addOpcode("LSTORE", LSTORE, OpcodeGroup.INSN_VAR);
201 addOpcode("FSTORE", FSTORE, OpcodeGroup.INSN_VAR);
202 addOpcode("DSTORE", DSTORE, OpcodeGroup.INSN_VAR);
203 addOpcode("ASTORE", ASTORE, OpcodeGroup.INSN_VAR);
204 addOpcode("IASTORE", IASTORE, OpcodeGroup.INSN);
205 addOpcode("LASTORE", LASTORE, OpcodeGroup.INSN);
206 addOpcode("FASTORE", FASTORE, OpcodeGroup.INSN);
207 addOpcode("DASTORE", DASTORE, OpcodeGroup.INSN);
208 addOpcode("AASTORE", AASTORE, OpcodeGroup.INSN);
209 addOpcode("BASTORE", BASTORE, OpcodeGroup.INSN);
210 addOpcode("CASTORE", CASTORE, OpcodeGroup.INSN);
211 addOpcode("SASTORE", SASTORE, OpcodeGroup.INSN);
212 addOpcode("POP", POP, OpcodeGroup.INSN);
213 addOpcode("POP2", POP2, OpcodeGroup.INSN);
214 addOpcode("DUP", DUP, OpcodeGroup.INSN);
215 addOpcode("DUP_X1", DUP_X1, OpcodeGroup.INSN);
216 addOpcode("DUP_X2", DUP_X2, OpcodeGroup.INSN);
217 addOpcode("DUP2", DUP2, OpcodeGroup.INSN);
218 addOpcode("DUP2_X1", DUP2_X1, OpcodeGroup.INSN);
219 addOpcode("DUP2_X2", DUP2_X2, OpcodeGroup.INSN);
220 addOpcode("SWAP", SWAP, OpcodeGroup.INSN);
221 addOpcode("IADD", IADD, OpcodeGroup.INSN);
222 addOpcode("LADD", LADD, OpcodeGroup.INSN);
223 addOpcode("FADD", FADD, OpcodeGroup.INSN);
224 addOpcode("DADD", DADD, OpcodeGroup.INSN);
225 addOpcode("ISUB", ISUB, OpcodeGroup.INSN);
226 addOpcode("LSUB", LSUB, OpcodeGroup.INSN);
227 addOpcode("FSUB", FSUB, OpcodeGroup.INSN);
228 addOpcode("DSUB", DSUB, OpcodeGroup.INSN);
229 addOpcode("IMUL", IMUL, OpcodeGroup.INSN);
230 addOpcode("LMUL", LMUL, OpcodeGroup.INSN);
231 addOpcode("FMUL", FMUL, OpcodeGroup.INSN);
232 addOpcode("DMUL", DMUL, OpcodeGroup.INSN);
233 addOpcode("IDIV", IDIV, OpcodeGroup.INSN);
234 addOpcode("LDIV", LDIV, OpcodeGroup.INSN);
235 addOpcode("FDIV", FDIV, OpcodeGroup.INSN);
236 addOpcode("DDIV", DDIV, OpcodeGroup.INSN);
237 addOpcode("IREM", IREM, OpcodeGroup.INSN);
238 addOpcode("LREM", LREM, OpcodeGroup.INSN);
239 addOpcode("FREM", FREM, OpcodeGroup.INSN);
240 addOpcode("DREM", DREM, OpcodeGroup.INSN);
241 addOpcode("INEG", INEG, OpcodeGroup.INSN);
242 addOpcode("LNEG", LNEG, OpcodeGroup.INSN);
243 addOpcode("FNEG", FNEG, OpcodeGroup.INSN);
244 addOpcode("DNEG", DNEG, OpcodeGroup.INSN);
245 addOpcode("ISHL", ISHL, OpcodeGroup.INSN);
246 addOpcode("LSHL", LSHL, OpcodeGroup.INSN);
247 addOpcode("ISHR", ISHR, OpcodeGroup.INSN);
248 addOpcode("LSHR", LSHR, OpcodeGroup.INSN);
249 addOpcode("IUSHR", IUSHR, OpcodeGroup.INSN);
250 addOpcode("LUSHR", LUSHR, OpcodeGroup.INSN);
251 addOpcode("IAND", IAND, OpcodeGroup.INSN);
252 addOpcode("LAND", LAND, OpcodeGroup.INSN);
253 addOpcode("IOR", IOR, OpcodeGroup.INSN);
254 addOpcode("LOR", LOR, OpcodeGroup.INSN);
255 addOpcode("IXOR", IXOR, OpcodeGroup.INSN);
256 addOpcode("LXOR", LXOR, OpcodeGroup.INSN);
257 addOpcode("IINC", IINC, OpcodeGroup.INSN_IINC);
258 addOpcode("I2L", I2L, OpcodeGroup.INSN);
259 addOpcode("I2F", I2F, OpcodeGroup.INSN);
260 addOpcode("I2D", I2D, OpcodeGroup.INSN);
261 addOpcode("L2I", L2I, OpcodeGroup.INSN);
262 addOpcode("L2F", L2F, OpcodeGroup.INSN);
263 addOpcode("L2D", L2D, OpcodeGroup.INSN);
264 addOpcode("F2I", F2I, OpcodeGroup.INSN);
265 addOpcode("F2L", F2L, OpcodeGroup.INSN);
266 addOpcode("F2D", F2D, OpcodeGroup.INSN);
267 addOpcode("D2I", D2I, OpcodeGroup.INSN);
268 addOpcode("D2L", D2L, OpcodeGroup.INSN);
269 addOpcode("D2F", D2F, OpcodeGroup.INSN);
270 addOpcode("I2B", I2B, OpcodeGroup.INSN);
271 addOpcode("I2C", I2C, OpcodeGroup.INSN);
272 addOpcode("I2S", I2S, OpcodeGroup.INSN);
273 addOpcode("LCMP", LCMP, OpcodeGroup.INSN);
274 addOpcode("FCMPL", FCMPL, OpcodeGroup.INSN);
275 addOpcode("FCMPG", FCMPG, OpcodeGroup.INSN);
276 addOpcode("DCMPL", DCMPL, OpcodeGroup.INSN);
277 addOpcode("DCMPG", DCMPG, OpcodeGroup.INSN);
278 addOpcode("IFEQ", IFEQ, OpcodeGroup.INSN_JUMP);
279 addOpcode("IFNE", IFNE, OpcodeGroup.INSN_JUMP);
280 addOpcode("IFLT", IFLT, OpcodeGroup.INSN_JUMP);
281 addOpcode("IFGE", IFGE, OpcodeGroup.INSN_JUMP);
282 addOpcode("IFGT", IFGT, OpcodeGroup.INSN_JUMP);
283 addOpcode("IFLE", IFLE, OpcodeGroup.INSN_JUMP);
284 addOpcode("IF_ICMPEQ", IF_ICMPEQ, OpcodeGroup.INSN_JUMP);
285 addOpcode("IF_ICMPNE", IF_ICMPNE, OpcodeGroup.INSN_JUMP);
286 addOpcode("IF_ICMPLT", IF_ICMPLT, OpcodeGroup.INSN_JUMP);
287 addOpcode("IF_ICMPGE", IF_ICMPGE, OpcodeGroup.INSN_JUMP);
288 addOpcode("IF_ICMPGT", IF_ICMPGT, OpcodeGroup.INSN_JUMP);
289 addOpcode("IF_ICMPLE", IF_ICMPLE, OpcodeGroup.INSN_JUMP);
290 addOpcode("IF_ACMPEQ", IF_ACMPEQ, OpcodeGroup.INSN_JUMP);
291 addOpcode("IF_ACMPNE", IF_ACMPNE, OpcodeGroup.INSN_JUMP);
292 addOpcode("GOTO", GOTO, OpcodeGroup.INSN_JUMP);
293 addOpcode("JSR", JSR, OpcodeGroup.INSN_JUMP);
294 addOpcode("RET", RET, OpcodeGroup.INSN_VAR);
295 addOpcode("IRETURN", IRETURN, OpcodeGroup.INSN);
296 addOpcode("LRETURN", LRETURN, OpcodeGroup.INSN);
297 addOpcode("FRETURN", FRETURN, OpcodeGroup.INSN);
298 addOpcode("DRETURN", DRETURN, OpcodeGroup.INSN);
299 addOpcode("ARETURN", ARETURN, OpcodeGroup.INSN);
300 addOpcode("RETURN", RETURN, OpcodeGroup.INSN);
301 addOpcode("GETSTATIC", GETSTATIC, OpcodeGroup.INSN_FIELD);
302 addOpcode("PUTSTATIC", PUTSTATIC, OpcodeGroup.INSN_FIELD);
303 addOpcode("GETFIELD", GETFIELD, OpcodeGroup.INSN_FIELD);
304 addOpcode("PUTFIELD", PUTFIELD, OpcodeGroup.INSN_FIELD);
305 addOpcode("INVOKEVIRTUAL", INVOKEVIRTUAL, OpcodeGroup.INSN_METHOD);
306 addOpcode("INVOKESPECIAL", INVOKESPECIAL, OpcodeGroup.INSN_METHOD);
307 addOpcode("INVOKESTATIC", INVOKESTATIC, OpcodeGroup.INSN_METHOD);
308 addOpcode("INVOKEINTERFACE", INVOKEINTERFACE, OpcodeGroup.INSN_METHOD);
309 addOpcode("NEW", NEW, OpcodeGroup.INSN_TYPE);
310 addOpcode("NEWARRAY", NEWARRAY, OpcodeGroup.INSN_INT);
311 addOpcode("ANEWARRAY", ANEWARRAY, OpcodeGroup.INSN_TYPE);
312 addOpcode("ARRAYLENGTH", ARRAYLENGTH, OpcodeGroup.INSN);
313 addOpcode("ATHROW", ATHROW, OpcodeGroup.INSN);
314 addOpcode("CHECKCAST", CHECKCAST, OpcodeGroup.INSN_TYPE);
315 addOpcode("INSTANCEOF", INSTANCEOF, OpcodeGroup.INSN_TYPE);
316 addOpcode("MONITORENTER", MONITORENTER, OpcodeGroup.INSN);
317 addOpcode("MONITOREXIT", MONITOREXIT, OpcodeGroup.INSN);
318 addOpcode("MULTIANEWARRAY", MULTIANEWARRAY,
319 OpcodeGroup.INSN_MULTIANEWARRAY);
320 addOpcode("IFNULL", IFNULL, OpcodeGroup.INSN_JUMP);
321 addOpcode("IFNONNULL", IFNONNULL, OpcodeGroup.INSN_JUMP);
322 }
323
324 private static void addOpcode(String operStr, int oper, int group) {
325 OPCODES.put(operStr, new Opcode(oper, group));
326 }
327
328 static final HashMap<String, Integer> TYPES = new HashMap<String, Integer>();
329 static {
330 String[] types = SAXCodeAdapter.TYPES;
331 for (int i = 0; i < types.length; i++) {
332 TYPES.put(types[i], i);
62 /** Stack of the intermediate processing contexts. */
63 private final ArrayList<Object> stack = new ArrayList<Object>();
64
65 /** Complete name of the current element. */
66 String match = "";
67
68 /** Current instance of the {@link ClassVisitor ClassVisitor} used to visit classfile bytecode. */
69 protected ClassVisitor cv;
70
71 /** Map of the active {@link Label Label} instances for current method. */
72 protected Map<Object, Label> labels;
73
74 private static final String BASE = "class";
75
76 private final RuleSet RULES = new RuleSet();
77
78 {
79 RULES.add(BASE, new ClassRule());
80 RULES.add(BASE + "/interfaces/interface", new InterfaceRule());
81 RULES.add(BASE + "/interfaces", new InterfacesRule());
82 RULES.add(BASE + "/outerclass", new OuterClassRule());
83 RULES.add(BASE + "/innerclass", new InnerClassRule());
84 RULES.add(BASE + "/source", new SourceRule());
85
86 ModuleRule moduleRule = new ModuleRule();
87 RULES.add(BASE + "/module", moduleRule);
88 RULES.add(BASE + "/module/main-class", moduleRule);
89 RULES.add(BASE + "/module/packages", moduleRule);
90 RULES.add(BASE + "/module/requires", moduleRule);
91 RULES.add(BASE + "/module/exports", moduleRule);
92 RULES.add(BASE + "/module/exports/to", moduleRule);
93 RULES.add(BASE + "/module/opens", moduleRule);
94 RULES.add(BASE + "/module/opens/to", moduleRule);
95 RULES.add(BASE + "/module/uses", moduleRule);
96 RULES.add(BASE + "/module/provides", moduleRule);
97 RULES.add(BASE + "/module/provides/with", moduleRule);
98
99 RULES.add(BASE + "/field", new FieldRule());
100
101 RULES.add(BASE + "/method", new MethodRule());
102 RULES.add(BASE + "/method/exceptions/exception", new ExceptionRule());
103 RULES.add(BASE + "/method/exceptions", new ExceptionsRule());
104
105 RULES.add(BASE + "/method/parameter", new MethodParameterRule());
106 RULES.add(BASE + "/method/annotationDefault", new AnnotationDefaultRule());
107
108 RULES.add(BASE + "/method/code/*", new OpcodesRule()); // opcodes
109
110 RULES.add(BASE + "/method/code/frame", new FrameRule());
111 RULES.add(BASE + "/method/code/frame/local", new FrameTypeRule());
112 RULES.add(BASE + "/method/code/frame/stack", new FrameTypeRule());
113
114 RULES.add(BASE + "/method/code/TABLESWITCH", new TableSwitchRule());
115 RULES.add(BASE + "/method/code/TABLESWITCH/label", new TableSwitchLabelRule());
116 RULES.add(BASE + "/method/code/LOOKUPSWITCH", new LookupSwitchRule());
117 RULES.add(BASE + "/method/code/LOOKUPSWITCH/label", new LookupSwitchLabelRule());
118
119 RULES.add(BASE + "/method/code/INVOKEDYNAMIC", new InvokeDynamicRule());
120 RULES.add(BASE + "/method/code/INVOKEDYNAMIC/bsmArg", new InvokeDynamicBsmArgumentsRule());
121
122 RULES.add(BASE + "/method/code/Label", new LabelRule());
123 RULES.add(BASE + "/method/code/TryCatch", new TryCatchRule());
124 RULES.add(BASE + "/method/code/LineNumber", new LineNumberRule());
125 RULES.add(BASE + "/method/code/LocalVar", new LocalVarRule());
126 RULES.add(BASE + "/method/code/Max", new MaxRule());
127
128 RULES.add("*/annotation", new AnnotationRule());
129 RULES.add("*/typeAnnotation", new TypeAnnotationRule());
130 RULES.add("*/annotableParameterCount", new AnnotableParameterCountRule());
131 RULES.add("*/parameterAnnotation", new AnnotationParameterRule());
132 RULES.add("*/insnAnnotation", new InsnAnnotationRule());
133 RULES.add("*/tryCatchAnnotation", new TryCatchAnnotationRule());
134 RULES.add("*/localVariableAnnotation", new LocalVariableAnnotationRule());
135 RULES.add("*/annotationValue", new AnnotationValueRule());
136 RULES.add("*/annotationValueAnnotation", new AnnotationValueAnnotationRule());
137 RULES.add("*/annotationValueEnum", new AnnotationValueEnumRule());
138 RULES.add("*/annotationValueArray", new AnnotationValueArrayRule());
139 }
140
141 private static interface OpcodeGroup {
142 public static final int INSN = 0;
143 public static final int INSN_INT = 1;
144 public static final int INSN_VAR = 2;
145 public static final int INSN_TYPE = 3;
146 public static final int INSN_FIELD = 4;
147 public static final int INSN_METHOD = 5;
148 public static final int INSN_JUMP = 6;
149 public static final int INSN_LDC = 7;
150 public static final int INSN_IINC = 8;
151 public static final int INSN_MULTIANEWARRAY = 9;
152 }
153
154 /** Map of the opcode names to opcode and opcode group */
155 static final HashMap<String, Opcode> OPCODES = new HashMap<String, Opcode>();
156
157 static {
158 addOpcode("NOP", NOP, OpcodeGroup.INSN);
159 addOpcode("ACONST_NULL", ACONST_NULL, OpcodeGroup.INSN);
160 addOpcode("ICONST_M1", ICONST_M1, OpcodeGroup.INSN);
161 addOpcode("ICONST_0", ICONST_0, OpcodeGroup.INSN);
162 addOpcode("ICONST_1", ICONST_1, OpcodeGroup.INSN);
163 addOpcode("ICONST_2", ICONST_2, OpcodeGroup.INSN);
164 addOpcode("ICONST_3", ICONST_3, OpcodeGroup.INSN);
165 addOpcode("ICONST_4", ICONST_4, OpcodeGroup.INSN);
166 addOpcode("ICONST_5", ICONST_5, OpcodeGroup.INSN);
167 addOpcode("LCONST_0", LCONST_0, OpcodeGroup.INSN);
168 addOpcode("LCONST_1", LCONST_1, OpcodeGroup.INSN);
169 addOpcode("FCONST_0", FCONST_0, OpcodeGroup.INSN);
170 addOpcode("FCONST_1", FCONST_1, OpcodeGroup.INSN);
171 addOpcode("FCONST_2", FCONST_2, OpcodeGroup.INSN);
172 addOpcode("DCONST_0", DCONST_0, OpcodeGroup.INSN);
173 addOpcode("DCONST_1", DCONST_1, OpcodeGroup.INSN);
174 addOpcode("BIPUSH", BIPUSH, OpcodeGroup.INSN_INT);
175 addOpcode("SIPUSH", SIPUSH, OpcodeGroup.INSN_INT);
176 addOpcode("LDC", LDC, OpcodeGroup.INSN_LDC);
177 addOpcode("ILOAD", ILOAD, OpcodeGroup.INSN_VAR);
178 addOpcode("LLOAD", LLOAD, OpcodeGroup.INSN_VAR);
179 addOpcode("FLOAD", FLOAD, OpcodeGroup.INSN_VAR);
180 addOpcode("DLOAD", DLOAD, OpcodeGroup.INSN_VAR);
181 addOpcode("ALOAD", ALOAD, OpcodeGroup.INSN_VAR);
182 addOpcode("IALOAD", IALOAD, OpcodeGroup.INSN);
183 addOpcode("LALOAD", LALOAD, OpcodeGroup.INSN);
184 addOpcode("FALOAD", FALOAD, OpcodeGroup.INSN);
185 addOpcode("DALOAD", DALOAD, OpcodeGroup.INSN);
186 addOpcode("AALOAD", AALOAD, OpcodeGroup.INSN);
187 addOpcode("BALOAD", BALOAD, OpcodeGroup.INSN);
188 addOpcode("CALOAD", CALOAD, OpcodeGroup.INSN);
189 addOpcode("SALOAD", SALOAD, OpcodeGroup.INSN);
190 addOpcode("ISTORE", ISTORE, OpcodeGroup.INSN_VAR);
191 addOpcode("LSTORE", LSTORE, OpcodeGroup.INSN_VAR);
192 addOpcode("FSTORE", FSTORE, OpcodeGroup.INSN_VAR);
193 addOpcode("DSTORE", DSTORE, OpcodeGroup.INSN_VAR);
194 addOpcode("ASTORE", ASTORE, OpcodeGroup.INSN_VAR);
195 addOpcode("IASTORE", IASTORE, OpcodeGroup.INSN);
196 addOpcode("LASTORE", LASTORE, OpcodeGroup.INSN);
197 addOpcode("FASTORE", FASTORE, OpcodeGroup.INSN);
198 addOpcode("DASTORE", DASTORE, OpcodeGroup.INSN);
199 addOpcode("AASTORE", AASTORE, OpcodeGroup.INSN);
200 addOpcode("BASTORE", BASTORE, OpcodeGroup.INSN);
201 addOpcode("CASTORE", CASTORE, OpcodeGroup.INSN);
202 addOpcode("SASTORE", SASTORE, OpcodeGroup.INSN);
203 addOpcode("POP", POP, OpcodeGroup.INSN);
204 addOpcode("POP2", POP2, OpcodeGroup.INSN);
205 addOpcode("DUP", DUP, OpcodeGroup.INSN);
206 addOpcode("DUP_X1", DUP_X1, OpcodeGroup.INSN);
207 addOpcode("DUP_X2", DUP_X2, OpcodeGroup.INSN);
208 addOpcode("DUP2", DUP2, OpcodeGroup.INSN);
209 addOpcode("DUP2_X1", DUP2_X1, OpcodeGroup.INSN);
210 addOpcode("DUP2_X2", DUP2_X2, OpcodeGroup.INSN);
211 addOpcode("SWAP", SWAP, OpcodeGroup.INSN);
212 addOpcode("IADD", IADD, OpcodeGroup.INSN);
213 addOpcode("LADD", LADD, OpcodeGroup.INSN);
214 addOpcode("FADD", FADD, OpcodeGroup.INSN);
215 addOpcode("DADD", DADD, OpcodeGroup.INSN);
216 addOpcode("ISUB", ISUB, OpcodeGroup.INSN);
217 addOpcode("LSUB", LSUB, OpcodeGroup.INSN);
218 addOpcode("FSUB", FSUB, OpcodeGroup.INSN);
219 addOpcode("DSUB", DSUB, OpcodeGroup.INSN);
220 addOpcode("IMUL", IMUL, OpcodeGroup.INSN);
221 addOpcode("LMUL", LMUL, OpcodeGroup.INSN);
222 addOpcode("FMUL", FMUL, OpcodeGroup.INSN);
223 addOpcode("DMUL", DMUL, OpcodeGroup.INSN);
224 addOpcode("IDIV", IDIV, OpcodeGroup.INSN);
225 addOpcode("LDIV", LDIV, OpcodeGroup.INSN);
226 addOpcode("FDIV", FDIV, OpcodeGroup.INSN);
227 addOpcode("DDIV", DDIV, OpcodeGroup.INSN);
228 addOpcode("IREM", IREM, OpcodeGroup.INSN);
229 addOpcode("LREM", LREM, OpcodeGroup.INSN);
230 addOpcode("FREM", FREM, OpcodeGroup.INSN);
231 addOpcode("DREM", DREM, OpcodeGroup.INSN);
232 addOpcode("INEG", INEG, OpcodeGroup.INSN);
233 addOpcode("LNEG", LNEG, OpcodeGroup.INSN);
234 addOpcode("FNEG", FNEG, OpcodeGroup.INSN);
235 addOpcode("DNEG", DNEG, OpcodeGroup.INSN);
236 addOpcode("ISHL", ISHL, OpcodeGroup.INSN);
237 addOpcode("LSHL", LSHL, OpcodeGroup.INSN);
238 addOpcode("ISHR", ISHR, OpcodeGroup.INSN);
239 addOpcode("LSHR", LSHR, OpcodeGroup.INSN);
240 addOpcode("IUSHR", IUSHR, OpcodeGroup.INSN);
241 addOpcode("LUSHR", LUSHR, OpcodeGroup.INSN);
242 addOpcode("IAND", IAND, OpcodeGroup.INSN);
243 addOpcode("LAND", LAND, OpcodeGroup.INSN);
244 addOpcode("IOR", IOR, OpcodeGroup.INSN);
245 addOpcode("LOR", LOR, OpcodeGroup.INSN);
246 addOpcode("IXOR", IXOR, OpcodeGroup.INSN);
247 addOpcode("LXOR", LXOR, OpcodeGroup.INSN);
248 addOpcode("IINC", IINC, OpcodeGroup.INSN_IINC);
249 addOpcode("I2L", I2L, OpcodeGroup.INSN);
250 addOpcode("I2F", I2F, OpcodeGroup.INSN);
251 addOpcode("I2D", I2D, OpcodeGroup.INSN);
252 addOpcode("L2I", L2I, OpcodeGroup.INSN);
253 addOpcode("L2F", L2F, OpcodeGroup.INSN);
254 addOpcode("L2D", L2D, OpcodeGroup.INSN);
255 addOpcode("F2I", F2I, OpcodeGroup.INSN);
256 addOpcode("F2L", F2L, OpcodeGroup.INSN);
257 addOpcode("F2D", F2D, OpcodeGroup.INSN);
258 addOpcode("D2I", D2I, OpcodeGroup.INSN);
259 addOpcode("D2L", D2L, OpcodeGroup.INSN);
260 addOpcode("D2F", D2F, OpcodeGroup.INSN);
261 addOpcode("I2B", I2B, OpcodeGroup.INSN);
262 addOpcode("I2C", I2C, OpcodeGroup.INSN);
263 addOpcode("I2S", I2S, OpcodeGroup.INSN);
264 addOpcode("LCMP", LCMP, OpcodeGroup.INSN);
265 addOpcode("FCMPL", FCMPL, OpcodeGroup.INSN);
266 addOpcode("FCMPG", FCMPG, OpcodeGroup.INSN);
267 addOpcode("DCMPL", DCMPL, OpcodeGroup.INSN);
268 addOpcode("DCMPG", DCMPG, OpcodeGroup.INSN);
269 addOpcode("IFEQ", IFEQ, OpcodeGroup.INSN_JUMP);
270 addOpcode("IFNE", IFNE, OpcodeGroup.INSN_JUMP);
271 addOpcode("IFLT", IFLT, OpcodeGroup.INSN_JUMP);
272 addOpcode("IFGE", IFGE, OpcodeGroup.INSN_JUMP);
273 addOpcode("IFGT", IFGT, OpcodeGroup.INSN_JUMP);
274 addOpcode("IFLE", IFLE, OpcodeGroup.INSN_JUMP);
275 addOpcode("IF_ICMPEQ", IF_ICMPEQ, OpcodeGroup.INSN_JUMP);
276 addOpcode("IF_ICMPNE", IF_ICMPNE, OpcodeGroup.INSN_JUMP);
277 addOpcode("IF_ICMPLT", IF_ICMPLT, OpcodeGroup.INSN_JUMP);
278 addOpcode("IF_ICMPGE", IF_ICMPGE, OpcodeGroup.INSN_JUMP);
279 addOpcode("IF_ICMPGT", IF_ICMPGT, OpcodeGroup.INSN_JUMP);
280 addOpcode("IF_ICMPLE", IF_ICMPLE, OpcodeGroup.INSN_JUMP);
281 addOpcode("IF_ACMPEQ", IF_ACMPEQ, OpcodeGroup.INSN_JUMP);
282 addOpcode("IF_ACMPNE", IF_ACMPNE, OpcodeGroup.INSN_JUMP);
283 addOpcode("GOTO", GOTO, OpcodeGroup.INSN_JUMP);
284 addOpcode("JSR", JSR, OpcodeGroup.INSN_JUMP);
285 addOpcode("RET", RET, OpcodeGroup.INSN_VAR);
286 addOpcode("IRETURN", IRETURN, OpcodeGroup.INSN);
287 addOpcode("LRETURN", LRETURN, OpcodeGroup.INSN);
288 addOpcode("FRETURN", FRETURN, OpcodeGroup.INSN);
289 addOpcode("DRETURN", DRETURN, OpcodeGroup.INSN);
290 addOpcode("ARETURN", ARETURN, OpcodeGroup.INSN);
291 addOpcode("RETURN", RETURN, OpcodeGroup.INSN);
292 addOpcode("GETSTATIC", GETSTATIC, OpcodeGroup.INSN_FIELD);
293 addOpcode("PUTSTATIC", PUTSTATIC, OpcodeGroup.INSN_FIELD);
294 addOpcode("GETFIELD", GETFIELD, OpcodeGroup.INSN_FIELD);
295 addOpcode("PUTFIELD", PUTFIELD, OpcodeGroup.INSN_FIELD);
296 addOpcode("INVOKEVIRTUAL", INVOKEVIRTUAL, OpcodeGroup.INSN_METHOD);
297 addOpcode("INVOKESPECIAL", INVOKESPECIAL, OpcodeGroup.INSN_METHOD);
298 addOpcode("INVOKESTATIC", INVOKESTATIC, OpcodeGroup.INSN_METHOD);
299 addOpcode("INVOKEINTERFACE", INVOKEINTERFACE, OpcodeGroup.INSN_METHOD);
300 addOpcode("NEW", NEW, OpcodeGroup.INSN_TYPE);
301 addOpcode("NEWARRAY", NEWARRAY, OpcodeGroup.INSN_INT);
302 addOpcode("ANEWARRAY", ANEWARRAY, OpcodeGroup.INSN_TYPE);
303 addOpcode("ARRAYLENGTH", ARRAYLENGTH, OpcodeGroup.INSN);
304 addOpcode("ATHROW", ATHROW, OpcodeGroup.INSN);
305 addOpcode("CHECKCAST", CHECKCAST, OpcodeGroup.INSN_TYPE);
306 addOpcode("INSTANCEOF", INSTANCEOF, OpcodeGroup.INSN_TYPE);
307 addOpcode("MONITORENTER", MONITORENTER, OpcodeGroup.INSN);
308 addOpcode("MONITOREXIT", MONITOREXIT, OpcodeGroup.INSN);
309 addOpcode("MULTIANEWARRAY", MULTIANEWARRAY, OpcodeGroup.INSN_MULTIANEWARRAY);
310 addOpcode("IFNULL", IFNULL, OpcodeGroup.INSN_JUMP);
311 addOpcode("IFNONNULL", IFNONNULL, OpcodeGroup.INSN_JUMP);
312 }
313
314 private static void addOpcode(String operStr, int oper, int group) {
315 OPCODES.put(operStr, new Opcode(oper, group));
316 }
317
318 static final HashMap<String, Integer> TYPES = new HashMap<String, Integer>();
319
320 static {
321 String[] types = SAXCodeAdapter.TYPES;
322 for (int i = 0; i < types.length; i++) {
323 TYPES.put(types[i], i);
324 }
325 }
326
327 /**
328 * Constructs a new {@link ASMContentHandler ASMContentHandler} object.
329 *
330 * @param cv class visitor that will be called to reconstruct the classfile using the XML stream.
331 */
332 public ASMContentHandler(final ClassVisitor cv) {
333 this.cv = cv;
334 }
335
336 /**
337 * Process notification of the start of an XML element being reached.
338 *
339 * @param ns - The Namespace URI, or the empty string if the element has no Namespace URI or if
340 * Namespace processing is not being performed.
341 * @param lName - The local name (without prefix), or the empty string if Namespace processing is
342 * not being performed.
343 * @param qName - The qualified name (with prefix), or the empty string if qualified names are not
344 * available.
345 * @param list - The attributes attached to the element. If there are no attributes, it shall be
346 * an empty Attributes object.
347 * @exception SAXException if a parsing error is to be reported
348 */
349 @Override
350 public final void startElement(
351 final String ns, final String lName, final String qName, final Attributes list)
352 throws SAXException {
353 // the actual element name is either in lName or qName, depending
354 // on whether the parser is namespace aware
355 String name = lName == null || lName.length() == 0 ? qName : lName;
356
357 // Compute the current matching rule
358 StringBuilder sb = new StringBuilder(match);
359 if (match.length() > 0) {
360 sb.append('/');
361 }
362 sb.append(name);
363 match = sb.toString();
364
365 // Fire "begin" events for all relevant rules
366 Rule r = (Rule) RULES.match(match);
367 if (r != null) {
368 r.begin(name, list);
369 }
370 }
371
372 /**
373 * Process notification of the end of an XML element being reached.
374 *
375 * @param ns - The Namespace URI, or the empty string if the element has no Namespace URI or if
376 * Namespace processing is not being performed.
377 * @param lName - The local name (without prefix), or the empty string if Namespace processing is
378 * not being performed.
379 * @param qName - The qualified XML 1.0 name (with prefix), or the empty string if qualified names
380 * are not available.
381 * @exception SAXException if a parsing error is to be reported
382 */
383 @Override
384 public final void endElement(final String ns, final String lName, final String qName)
385 throws SAXException {
386 // the actual element name is either in lName or qName, depending
387 // on whether the parser is namespace aware
388 String name = lName == null || lName.length() == 0 ? qName : lName;
389
390 // Fire "end" events for all relevant rules in reverse order
391 Rule r = (Rule) RULES.match(match);
392 if (r != null) {
393 r.end(name);
394 }
395
396 // Recover the previous match expression
397 int slash = match.lastIndexOf('/');
398 if (slash >= 0) {
399 match = match.substring(0, slash);
400 } else {
401 match = "";
402 }
403 }
404
405 /**
406 * Return the top object on the stack without removing it. If there are no objects on the stack,
407 * return <code>null</code>.
408 *
409 * @return the top object on the stack without removing it.
410 */
411 final Object peek() {
412 int size = stack.size();
413 return size == 0 ? null : stack.get(size - 1);
414 }
415
416 /**
417 * Pop the top object off of the stack, and return it. If there are no objects on the stack,
418 * return <code>null</code>.
419 *
420 * @return the top object off of the stack.
421 */
422 final Object pop() {
423 int size = stack.size();
424 return size == 0 ? null : stack.remove(size - 1);
425 }
426
427 /**
428 * Push a new object onto the top of the object stack.
429 *
430 * @param object The new object
431 */
432 final void push(final Object object) {
433 stack.add(object);
434 }
435
436 static final class RuleSet {
437
438 private final HashMap<String, Object> rules = new HashMap<String, Object>();
439
440 private final ArrayList<String> lpatterns = new ArrayList<String>();
441
442 private final ArrayList<String> rpatterns = new ArrayList<String>();
443
444 public void add(final String path, final Object rule) {
445 String pattern = path;
446 if (path.startsWith("*/")) {
447 pattern = path.substring(1);
448 lpatterns.add(pattern);
449 } else if (path.endsWith("/*")) {
450 pattern = path.substring(0, path.length() - 1);
451 rpatterns.add(pattern);
452 }
453 rules.put(pattern, rule);
454 }
455
456 public Object match(final String path) {
457 if (rules.containsKey(path)) {
458 return rules.get(path);
459 }
460
461 int n = path.lastIndexOf('/');
462 for (Iterator<String> it = lpatterns.iterator(); it.hasNext(); ) {
463 String pattern = it.next();
464 if (path.substring(n).endsWith(pattern)) {
465 return rules.get(pattern);
333466 }
334 }
335
336 /**
337 * Constructs a new {@link ASMContentHandler ASMContentHandler} object.
338 *
339 * @param cv
340 * class visitor that will be called to reconstruct the classfile
341 * using the XML stream.
342 */
343 public ASMContentHandler(final ClassVisitor cv) {
344 this.cv = cv;
345 }
346
347 /**
348 * Process notification of the start of an XML element being reached.
349 *
350 * @param ns
351 * - The Namespace URI, or the empty string if the element has no
352 * Namespace URI or if Namespace processing is not being
353 * performed.
354 * @param lName
355 * - The local name (without prefix), or the empty string if
356 * Namespace processing is not being performed.
357 * @param qName
358 * - The qualified name (with prefix), or the empty string if
359 * qualified names are not available.
360 * @param list
361 * - The attributes attached to the element. If there are no
362 * attributes, it shall be an empty Attributes object.
363 * @exception SAXException
364 * if a parsing error is to be reported
365 */
366 @Override
367 public final void startElement(final String ns, final String lName,
368 final String qName, final Attributes list) throws SAXException {
369 // the actual element name is either in lName or qName, depending
370 // on whether the parser is namespace aware
371 String name = lName == null || lName.length() == 0 ? qName : lName;
372
373 // Compute the current matching rule
374 StringBuilder sb = new StringBuilder(match);
375 if (match.length() > 0) {
376 sb.append('/');
467 }
468
469 for (Iterator<String> it = rpatterns.iterator(); it.hasNext(); ) {
470 String pattern = it.next();
471 if (path.startsWith(pattern)) {
472 return rules.get(pattern);
377473 }
378 sb.append(name);
379 match = sb.toString();
380
381 // Fire "begin" events for all relevant rules
382 Rule r = (Rule) RULES.match(match);
383 if (r != null) {
384 r.begin(name, list);
474 }
475
476 return null;
477 }
478 }
479
480 /** Rule */
481 protected abstract class Rule {
482
483 public void begin(final String name, final Attributes attrs) throws SAXException {}
484
485 public void end(final String name) {}
486
487 protected final Object getValue(final String desc, final String val) throws SAXException {
488 Object value = null;
489 if (val != null) {
490 if ("Ljava/lang/String;".equals(desc)) {
491 value = decode(val);
492 } else if ("Ljava/lang/Integer;".equals(desc)
493 || "I".equals(desc)
494 || "S".equals(desc)
495 || "B".equals(desc)
496 || "C".equals(desc)
497 || "Z".equals(desc)) {
498 value = new Integer(val);
499
500 } else if ("Ljava/lang/Short;".equals(desc)) {
501 value = new Short(val);
502
503 } else if ("Ljava/lang/Byte;".equals(desc)) {
504 value = new Byte(val);
505
506 } else if ("Ljava/lang/Character;".equals(desc)) {
507 value = new Character(decode(val).charAt(0));
508
509 } else if ("Ljava/lang/Boolean;".equals(desc)) {
510 value = Boolean.valueOf(val);
511
512 } else if ("Ljava/lang/Long;".equals(desc) || "J".equals(desc)) {
513 value = new Long(val);
514 } else if ("Ljava/lang/Float;".equals(desc) || "F".equals(desc)) {
515 value = new Float(val);
516 } else if ("Ljava/lang/Double;".equals(desc) || "D".equals(desc)) {
517 value = new Double(val);
518 } else if (Type.getDescriptor(Type.class).equals(desc)) {
519 value = Type.getType(val);
520
521 } else if (Type.getDescriptor(Handle.class).equals(desc)) {
522 value = decodeHandle(val);
523
524 } else {
525 // TODO use of default toString().
526 throw new SAXException("Invalid value:" + val + " desc:" + desc + " ctx:" + this);
385527 }
386 }
387
388 /**
389 * Process notification of the end of an XML element being reached.
390 *
391 * @param ns
392 * - The Namespace URI, or the empty string if the element has no
393 * Namespace URI or if Namespace processing is not being
394 * performed.
395 * @param lName
396 * - The local name (without prefix), or the empty string if
397 * Namespace processing is not being performed.
398 * @param qName
399 * - The qualified XML 1.0 name (with prefix), or the empty
400 * string if qualified names are not available.
401 *
402 * @exception SAXException
403 * if a parsing error is to be reported
404 */
405 @Override
406 public final void endElement(final String ns, final String lName,
407 final String qName) throws SAXException {
408 // the actual element name is either in lName or qName, depending
409 // on whether the parser is namespace aware
410 String name = lName == null || lName.length() == 0 ? qName : lName;
411
412 // Fire "end" events for all relevant rules in reverse order
413 Rule r = (Rule) RULES.match(match);
414 if (r != null) {
415 r.end(name);
528 }
529 return value;
530 }
531
532 Handle decodeHandle(final String val) throws SAXException {
533 try {
534 int dotIndex = val.indexOf('.');
535 int descIndex = val.indexOf('(', dotIndex + 1);
536 int tagIndex = val.lastIndexOf('(');
537 int itfIndex = val.indexOf(' ', tagIndex + 1);
538
539 boolean itf = itfIndex != -1;
540 int tag = Integer.parseInt(val.substring(tagIndex + 1, itf ? itfIndex : val.length() - 1));
541 String owner = val.substring(0, dotIndex);
542 String name = val.substring(dotIndex + 1, descIndex);
543 String desc = val.substring(descIndex, tagIndex - 1);
544 return new Handle(tag, owner, name, desc, itf);
545
546 } catch (RuntimeException e) {
547 throw new SAXException("Malformed handle " + val, e);
548 }
549 }
550
551 private final String decode(final String val) throws SAXException {
552 StringBuilder sb = new StringBuilder(val.length());
553 try {
554 int n = 0;
555 while (n < val.length()) {
556 char c = val.charAt(n);
557 if (c == '\\') {
558 n++;
559 c = val.charAt(n);
560 if (c == '\\') {
561 sb.append('\\');
562 } else {
563 n++; // skip 'u'
564 sb.append((char) Integer.parseInt(val.substring(n, n + 4), 16));
565 n += 3;
566 }
567 } else {
568 sb.append(c);
569 }
570 n++;
416571 }
417572
418 // Recover the previous match expression
419 int slash = match.lastIndexOf('/');
420 if (slash >= 0) {
421 match = match.substring(0, slash);
573 } catch (RuntimeException ex) {
574 throw new SAXException(ex);
575 }
576 return sb.toString();
577 }
578
579 protected final Label getLabel(final Object label) {
580 Label lbl = labels.get(label);
581 if (lbl == null) {
582 lbl = new Label();
583 labels.put(label, lbl);
584 }
585 return lbl;
586 }
587
588 // TODO verify move to stack
589 protected final MethodVisitor getCodeVisitor() {
590 return (MethodVisitor) peek();
591 }
592
593 protected final int getAccess(final String s) {
594 int access = 0;
595 if (s.indexOf("public") != -1) {
596 access |= ACC_PUBLIC;
597 }
598 if (s.indexOf("private") != -1) {
599 access |= ACC_PRIVATE;
600 }
601 if (s.indexOf("protected") != -1) {
602 access |= ACC_PROTECTED;
603 }
604 if (s.indexOf("static") != -1) {
605 access |= ACC_STATIC;
606 }
607 if (s.indexOf("final") != -1) {
608 access |= ACC_FINAL;
609 }
610 if (s.indexOf("super") != -1) {
611 access |= ACC_SUPER;
612 }
613 if (s.indexOf("synchronized") != -1) {
614 access |= ACC_SYNCHRONIZED;
615 }
616 if (s.indexOf("volatile") != -1) {
617 access |= ACC_VOLATILE;
618 }
619 if (s.indexOf("bridge") != -1) {
620 access |= ACC_BRIDGE;
621 }
622 if (s.indexOf("varargs") != -1) {
623 access |= ACC_VARARGS;
624 }
625 if (s.indexOf("transient") != -1) {
626 access |= ACC_TRANSIENT;
627 }
628 if (s.indexOf("native") != -1) {
629 access |= ACC_NATIVE;
630 }
631 if (s.indexOf("interface") != -1) {
632 access |= ACC_INTERFACE;
633 }
634 if (s.indexOf("abstract") != -1) {
635 access |= ACC_ABSTRACT;
636 }
637 if (s.indexOf("strict") != -1) {
638 access |= ACC_STRICT;
639 }
640 if (s.indexOf("synthetic") != -1) {
641 access |= ACC_SYNTHETIC;
642 }
643 if (s.indexOf("annotation") != -1) {
644 access |= ACC_ANNOTATION;
645 }
646 if (s.indexOf("enum") != -1) {
647 access |= ACC_ENUM;
648 }
649 if (s.indexOf("deprecated") != -1) {
650 access |= ACC_DEPRECATED;
651 }
652 if (s.indexOf("mandated") != -1) {
653 access |= ACC_MANDATED;
654 }
655 if (s.indexOf("module") != -1) {
656 access |= ACC_MODULE;
657 }
658 if (s.indexOf("open") != -1) {
659 access |= ACC_OPEN;
660 }
661 if (s.indexOf("transitive") != -1) {
662 access |= ACC_TRANSITIVE;
663 }
664 return access;
665 }
666 }
667
668 /** ClassRule */
669 final class ClassRule extends Rule {
670
671 @Override
672 public final void begin(final String name, final Attributes attrs) {
673 int major = Integer.parseInt(attrs.getValue("major"));
674 int minor = Integer.parseInt(attrs.getValue("minor"));
675 HashMap<String, Object> vals = new HashMap<String, Object>();
676 vals.put("version", minor << 16 | major);
677 vals.put("access", attrs.getValue("access"));
678 vals.put("name", attrs.getValue("name"));
679 vals.put("parent", attrs.getValue("parent"));
680 vals.put("source", attrs.getValue("source"));
681 vals.put("signature", attrs.getValue("signature"));
682 vals.put("interfaces", new ArrayList<String>());
683 push(vals);
684 // values will be extracted in InterfacesRule.end();
685 }
686 }
687
688 final class SourceRule extends Rule {
689
690 @Override
691 public void begin(final String name, final Attributes attrs) {
692 String file = attrs.getValue("file");
693 String debug = attrs.getValue("debug");
694 cv.visitSource(file, debug);
695 }
696 }
697
698 /** InterfaceRule */
699 final class InterfaceRule extends Rule {
700
701 @Override
702 @SuppressWarnings("unchecked")
703 public final void begin(final String name, final Attributes attrs) {
704 ((ArrayList<String>) ((HashMap<?, ?>) peek()).get("interfaces")).add(attrs.getValue("name"));
705 }
706 }
707
708 /** InterfacesRule */
709 final class InterfacesRule extends Rule {
710
711 @Override
712 public final void end(final String element) {
713 HashMap<?, ?> vals = (HashMap<?, ?>) pop();
714 int version = ((Integer) vals.get("version")).intValue();
715 int access = getAccess((String) vals.get("access"));
716 String name = (String) vals.get("name");
717 String signature = (String) vals.get("signature");
718 String parent = (String) vals.get("parent");
719 ArrayList<?> infs = (ArrayList<?>) vals.get("interfaces");
720 String[] interfaces = infs.toArray(new String[infs.size()]);
721 cv.visit(version, access, name, signature, parent, interfaces);
722 push(cv);
723 }
724 }
725
726 /** ModuleRule: module, requires, exports, opens, uses and provides */
727 final class ModuleRule extends Rule {
728 @Override
729 public final void begin(final String element, final Attributes attrs) throws SAXException {
730 if ("module".equals(element)) {
731 push(
732 cv.visitModule(
733 attrs.getValue("name"),
734 getAccess(attrs.getValue("access")),
735 attrs.getValue("version")));
736 } else if ("main-class".equals(element)) {
737 ModuleVisitor mv = (ModuleVisitor) peek();
738 mv.visitMainClass(attrs.getValue("name"));
739 } else if ("packages".equals(element)) {
740 ModuleVisitor mv = (ModuleVisitor) peek();
741 mv.visitPackage(attrs.getValue("name"));
742 } else if ("requires".equals(element)) {
743 ModuleVisitor mv = (ModuleVisitor) peek();
744 int access = getAccess(attrs.getValue("access"));
745 if ((access & Opcodes.ACC_STATIC) != 0) {
746 access = access & ~Opcodes.ACC_STATIC | Opcodes.ACC_STATIC_PHASE;
747 }
748 mv.visitRequire(attrs.getValue("module"), access, attrs.getValue("version"));
749 } else if ("exports".equals(element)) {
750 push(attrs.getValue("name"));
751 push(getAccess(attrs.getValue("access")));
752 ArrayList<String> list = new ArrayList<String>();
753 push(list);
754 } else if ("opens".equals(element)) {
755 push(attrs.getValue("name"));
756 push(getAccess(attrs.getValue("access")));
757 ArrayList<String> list = new ArrayList<String>();
758 push(list);
759 } else if ("to".equals(element)) {
760 @SuppressWarnings("unchecked")
761 ArrayList<String> list = (ArrayList<String>) peek();
762 list.add(attrs.getValue("module"));
763 } else if ("uses".equals(element)) {
764 ModuleVisitor mv = (ModuleVisitor) peek();
765 mv.visitUse(attrs.getValue("service"));
766 } else if ("provides".equals(element)) {
767 push(attrs.getValue("service"));
768 push(0); // see end() below
769 ArrayList<String> list = new ArrayList<String>();
770 push(list);
771 } else if ("with".equals(element)) {
772 @SuppressWarnings("unchecked")
773 ArrayList<String> list = (ArrayList<String>) peek();
774 list.add(attrs.getValue("provider"));
775 }
776 }
777
778 @Override
779 public void end(final String element) {
780 boolean exports = "exports".equals(element);
781 boolean opens = "opens".equals(element);
782 boolean provides = "provides".equals(element);
783 if (exports || opens || provides) {
784 @SuppressWarnings("unchecked")
785 ArrayList<String> list = (ArrayList<String>) pop();
786 int access = (Integer) pop();
787 String name = (String) pop();
788 String[] tos = null;
789 if (!list.isEmpty()) {
790 tos = list.toArray(new String[list.size()]);
791 }
792 ModuleVisitor mv = (ModuleVisitor) peek();
793 if (exports) {
794 mv.visitExport(name, access, tos);
422795 } else {
423 match = "";
796 if (opens) {
797 mv.visitOpen(name, access, tos);
798 } else {
799 mv.visitProvide(name, tos);
800 }
424801 }
425 }
426
427 /**
428 * Return the top object on the stack without removing it. If there are no
429 * objects on the stack, return <code>null</code>.
430 *
431 * @return the top object on the stack without removing it.
432 */
433 final Object peek() {
434 int size = stack.size();
435 return size == 0 ? null : stack.get(size - 1);
436 }
437
438 /**
439 * Pop the top object off of the stack, and return it. If there are no
440 * objects on the stack, return <code>null</code>.
441 *
442 * @return the top object off of the stack.
443 */
444 final Object pop() {
445 int size = stack.size();
446 return size == 0 ? null : stack.remove(size - 1);
447 }
448
449 /**
450 * Push a new object onto the top of the object stack.
451 *
452 * @param object
453 * The new object
454 */
455 final void push(final Object object) {
456 stack.add(object);
457 }
458
459 static final class RuleSet {
460
461 private final HashMap<String, Object> rules = new HashMap<String, Object>();
462
463 private final ArrayList<String> lpatterns = new ArrayList<String>();
464
465 private final ArrayList<String> rpatterns = new ArrayList<String>();
466
467 public void add(final String path, final Object rule) {
468 String pattern = path;
469 if (path.startsWith("*/")) {
470 pattern = path.substring(1);
471 lpatterns.add(pattern);
472 } else if (path.endsWith("/*")) {
473 pattern = path.substring(0, path.length() - 1);
474 rpatterns.add(pattern);
475 }
476 rules.put(pattern, rule);
802 } else if ("module".equals(element)) {
803 ((ModuleVisitor) pop()).visitEnd();
804 }
805 }
806 }
807
808 /** OuterClassRule */
809 final class OuterClassRule extends Rule {
810
811 @Override
812 public final void begin(final String element, final Attributes attrs) {
813 String owner = attrs.getValue("owner");
814 String name = attrs.getValue("name");
815 String desc = attrs.getValue("desc");
816 cv.visitOuterClass(owner, name, desc);
817 }
818 }
819
820 /** InnerClassRule */
821 final class InnerClassRule extends Rule {
822
823 @Override
824 public final void begin(final String element, final Attributes attrs) {
825 int access = getAccess(attrs.getValue("access"));
826 String name = attrs.getValue("name");
827 String outerName = attrs.getValue("outerName");
828 String innerName = attrs.getValue("innerName");
829 cv.visitInnerClass(name, outerName, innerName, access);
830 }
831 }
832
833 /** FieldRule */
834 final class FieldRule extends Rule {
835
836 @Override
837 public final void begin(final String element, final Attributes attrs) throws SAXException {
838 int access = getAccess(attrs.getValue("access"));
839 String name = attrs.getValue("name");
840 String signature = attrs.getValue("signature");
841 String desc = attrs.getValue("desc");
842 Object value = getValue(desc, attrs.getValue("value"));
843 push(cv.visitField(access, name, desc, signature, value));
844 }
845
846 @Override
847 public void end(final String name) {
848 ((FieldVisitor) pop()).visitEnd();
849 }
850 }
851
852 /** MethodRule */
853 final class MethodRule extends Rule {
854
855 @Override
856 public final void begin(final String name, final Attributes attrs) {
857 labels = new HashMap<Object, Label>();
858 HashMap<String, Object> vals = new HashMap<String, Object>();
859 vals.put("access", attrs.getValue("access"));
860 vals.put("name", attrs.getValue("name"));
861 vals.put("desc", attrs.getValue("desc"));
862 vals.put("signature", attrs.getValue("signature"));
863 vals.put("exceptions", new ArrayList<String>());
864 push(vals);
865 // values will be extracted in ExceptionsRule.end();
866 }
867
868 @Override
869 public final void end(final String name) {
870 ((MethodVisitor) pop()).visitEnd();
871 labels = null;
872 }
873 }
874
875 /** ExceptionRule */
876 final class ExceptionRule extends Rule {
877
878 @Override
879 @SuppressWarnings("unchecked")
880 public final void begin(final String name, final Attributes attrs) {
881 ((ArrayList<String>) ((HashMap<?, ?>) peek()).get("exceptions")).add(attrs.getValue("name"));
882 }
883 }
884
885 /** ExceptionsRule */
886 final class ExceptionsRule extends Rule {
887
888 @Override
889 public final void end(final String element) {
890 HashMap<?, ?> vals = (HashMap<?, ?>) pop();
891 int access = getAccess((String) vals.get("access"));
892 String name = (String) vals.get("name");
893 String desc = (String) vals.get("desc");
894 String signature = (String) vals.get("signature");
895 ArrayList<?> excs = (ArrayList<?>) vals.get("exceptions");
896 String[] exceptions = excs.toArray(new String[excs.size()]);
897
898 push(cv.visitMethod(access, name, desc, signature, exceptions));
899 }
900 }
901
902 /** MethodParameterRule */
903 final class MethodParameterRule extends Rule {
904 @Override
905 public void begin(final String nm, final Attributes attrs) {
906 String name = attrs.getValue("name");
907 int access = getAccess(attrs.getValue("access"));
908 getCodeVisitor().visitParameter(name, access);
909 }
910 }
911
912 /** TableSwitchRule */
913 final class TableSwitchRule extends Rule {
914
915 @Override
916 public final void begin(final String name, final Attributes attrs) {
917 HashMap<String, Object> vals = new HashMap<String, Object>();
918 vals.put("min", attrs.getValue("min"));
919 vals.put("max", attrs.getValue("max"));
920 vals.put("dflt", attrs.getValue("dflt"));
921 vals.put("labels", new ArrayList<String>());
922 push(vals);
923 }
924
925 @Override
926 public final void end(final String name) {
927 HashMap<?, ?> vals = (HashMap<?, ?>) pop();
928 int min = Integer.parseInt((String) vals.get("min"));
929 int max = Integer.parseInt((String) vals.get("max"));
930 Label dflt = getLabel(vals.get("dflt"));
931 ArrayList<?> lbls = (ArrayList<?>) vals.get("labels");
932 Label[] labels = lbls.toArray(new Label[lbls.size()]);
933 getCodeVisitor().visitTableSwitchInsn(min, max, dflt, labels);
934 }
935 }
936
937 /** TableSwitchLabelRule */
938 final class TableSwitchLabelRule extends Rule {
939
940 @Override
941 @SuppressWarnings("unchecked")
942 public final void begin(final String name, final Attributes attrs) {
943 ((ArrayList<Label>) ((HashMap<?, ?>) peek()).get("labels"))
944 .add(getLabel(attrs.getValue("name")));
945 }
946 }
947
948 /** LookupSwitchRule */
949 final class LookupSwitchRule extends Rule {
950
951 @Override
952 public final void begin(final String name, final Attributes attrs) {
953 HashMap<String, Object> vals = new HashMap<String, Object>();
954 vals.put("dflt", attrs.getValue("dflt"));
955 vals.put("labels", new ArrayList<Label>());
956 vals.put("keys", new ArrayList<String>());
957 push(vals);
958 }
959
960 @Override
961 public final void end(final String name) {
962 HashMap<?, ?> vals = (HashMap<?, ?>) pop();
963 Label dflt = getLabel(vals.get("dflt"));
964 @SuppressWarnings("unchecked")
965 ArrayList<String> keyList = (ArrayList<String>) vals.get("keys");
966 ArrayList<?> lbls = (ArrayList<?>) vals.get("labels");
967 Label[] labels = lbls.toArray(new Label[lbls.size()]);
968 int[] keys = new int[keyList.size()];
969 for (int i = 0; i < keys.length; i++) {
970 keys[i] = Integer.parseInt(keyList.get(i));
971 }
972 getCodeVisitor().visitLookupSwitchInsn(dflt, keys, labels);
973 }
974 }
975
976 /** LookupSwitchLabelRule */
977 final class LookupSwitchLabelRule extends Rule {
978
979 @Override
980 @SuppressWarnings("unchecked")
981 public final void begin(final String name, final Attributes attrs) {
982 HashMap<?, ?> vals = (HashMap<?, ?>) peek();
983 ((ArrayList<Label>) vals.get("labels")).add(getLabel(attrs.getValue("name")));
984 ((ArrayList<String>) vals.get("keys")).add(attrs.getValue("key"));
985 }
986 }
987
988 /** FrameRule */
989 final class FrameRule extends Rule {
990
991 @Override
992 public void begin(final String name, final Attributes attrs) {
993 HashMap<String, Object> typeLists = new HashMap<String, Object>();
994 typeLists.put("local", new ArrayList<Object>());
995 typeLists.put("stack", new ArrayList<Object>());
996 push(attrs.getValue("type"));
997 push(attrs.getValue("count") == null ? "0" : attrs.getValue("count"));
998 push(typeLists);
999 }
1000
1001 @Override
1002 public void end(final String name) {
1003 HashMap<?, ?> typeLists = (HashMap<?, ?>) pop();
1004 ArrayList<?> locals = (ArrayList<?>) typeLists.get("local");
1005 int nLocal = locals.size();
1006 Object[] local = locals.toArray();
1007 ArrayList<?> stacks = (ArrayList<?>) typeLists.get("stack");
1008 int nStack = stacks.size();
1009 Object[] stack = stacks.toArray();
1010 String count = (String) pop();
1011 String type = (String) pop();
1012 if ("NEW".equals(type)) {
1013 getCodeVisitor().visitFrame(F_NEW, nLocal, local, nStack, stack);
1014 } else if ("FULL".equals(type)) {
1015 getCodeVisitor().visitFrame(F_FULL, nLocal, local, nStack, stack);
1016 } else if ("APPEND".equals(type)) {
1017 getCodeVisitor().visitFrame(F_APPEND, nLocal, local, 0, null);
1018 } else if ("CHOP".equals(type)) {
1019 getCodeVisitor().visitFrame(F_CHOP, Integer.parseInt(count), null, 0, null);
1020 } else if ("SAME".equals(type)) {
1021 getCodeVisitor().visitFrame(F_SAME, 0, null, 0, null);
1022 } else if ("SAME1".equals(type)) {
1023 getCodeVisitor().visitFrame(F_SAME1, 0, null, nStack, stack);
1024 }
1025 }
1026 }
1027
1028 final class FrameTypeRule extends Rule {
1029
1030 @Override
1031 public void begin(final String name, final Attributes attrs) {
1032 @SuppressWarnings("unchecked")
1033 ArrayList<Object> types = (ArrayList<Object>) ((HashMap<?, ?>) peek()).get(name);
1034 String type = attrs.getValue("type");
1035 if ("uninitialized".equals(type)) {
1036 types.add(getLabel(attrs.getValue("label")));
1037 } else {
1038 Integer t = TYPES.get(type);
1039 if (t == null) {
1040 types.add(type);
1041 } else {
1042 types.add(t);
4771043 }
478
479 public Object match(final String path) {
480 if (rules.containsKey(path)) {
481 return rules.get(path);
482 }
483
484 int n = path.lastIndexOf('/');
485 for (Iterator<String> it = lpatterns.iterator(); it.hasNext();) {
486 String pattern = it.next();
487 if (path.substring(n).endsWith(pattern)) {
488 return rules.get(pattern);
489 }
490 }
491
492 for (Iterator<String> it = rpatterns.iterator(); it.hasNext();) {
493 String pattern = it.next();
494 if (path.startsWith(pattern)) {
495 return rules.get(pattern);
496 }
497 }
498
499 return null;
500 }
501 }
502
503 /**
504 * Rule
505 */
506 protected abstract class Rule {
507
508 public void begin(final String name, final Attributes attrs)
509 throws SAXException {
510 }
511
512 public void end(final String name) {
513 }
514
515 protected final Object getValue(final String desc, final String val)
516 throws SAXException {
517 Object value = null;
518 if (val != null) {
519 if ("Ljava/lang/String;".equals(desc)) {
520 value = decode(val);
521 } else if ("Ljava/lang/Integer;".equals(desc)
522 || "I".equals(desc) || "S".equals(desc)
523 || "B".equals(desc) || "C".equals(desc)
524 || "Z".equals(desc)) {
525 value = new Integer(val);
526
527 } else if ("Ljava/lang/Short;".equals(desc)) {
528 value = new Short(val);
529
530 } else if ("Ljava/lang/Byte;".equals(desc)) {
531 value = new Byte(val);
532
533 } else if ("Ljava/lang/Character;".equals(desc)) {
534 value = new Character(decode(val).charAt(0));
535
536 } else if ("Ljava/lang/Boolean;".equals(desc)) {
537 value = Boolean.valueOf(val);
538
539 } else if ("Ljava/lang/Long;".equals(desc) || "J".equals(desc)) {
540 value = new Long(val);
541 } else if ("Ljava/lang/Float;".equals(desc) || "F".equals(desc)) {
542 value = new Float(val);
543 } else if ("Ljava/lang/Double;".equals(desc)
544 || "D".equals(desc)) {
545 value = new Double(val);
546 } else if (Type.getDescriptor(Type.class).equals(desc)) {
547 value = Type.getType(val);
548
549 } else if (Type.getDescriptor(Handle.class).equals(desc)) {
550 value = decodeHandle(val);
551
552 } else {
553 // TODO use of default toString().
554 throw new SAXException("Invalid value:" + val + " desc:"
555 + desc + " ctx:" + this);
556 }
557 }
558 return value;
559 }
560
561 Handle decodeHandle(final String val) throws SAXException {
562 try {
563 int dotIndex = val.indexOf('.');
564 int descIndex = val.indexOf('(', dotIndex + 1);
565 int tagIndex = val.lastIndexOf('(');
566 int itfIndex = val.indexOf(' ', tagIndex + 1);
567
568 boolean itf = itfIndex != -1;
569 int tag = Integer.parseInt(
570 val.substring(tagIndex + 1,
571 itf? val.length() - 1: itfIndex));
572 String owner = val.substring(0, dotIndex);
573 String name = val.substring(dotIndex + 1, descIndex);
574 String desc = val.substring(descIndex, tagIndex - 1);
575 return new Handle(tag, owner, name, desc, itf);
576
577 } catch (RuntimeException e) {
578 throw new SAXException("Malformed handle " + val, e);
579 }
580 }
581
582 private final String decode(final String val) throws SAXException {
583 StringBuilder sb = new StringBuilder(val.length());
584 try {
585 int n = 0;
586 while (n < val.length()) {
587 char c = val.charAt(n);
588 if (c == '\\') {
589 n++;
590 c = val.charAt(n);
591 if (c == '\\') {
592 sb.append('\\');
593 } else {
594 n++; // skip 'u'
595 sb.append((char) Integer.parseInt(
596 val.substring(n, n + 4), 16));
597 n += 3;
598 }
599 } else {
600 sb.append(c);
601 }
602 n++;
603 }
604
605 } catch (RuntimeException ex) {
606 throw new SAXException(ex);
607 }
608 return sb.toString();
609 }
610
611 protected final Label getLabel(final Object label) {
612 Label lbl = labels.get(label);
613 if (lbl == null) {
614 lbl = new Label();
615 labels.put(label, lbl);
616 }
617 return lbl;
618 }
619
620 // TODO verify move to stack
621 protected final MethodVisitor getCodeVisitor() {
622 return (MethodVisitor) peek();
623 }
624
625 protected final int getAccess(final String s) {
626 int access = 0;
627 if (s.indexOf("public") != -1) {
628 access |= ACC_PUBLIC;
629 }
630 if (s.indexOf("private") != -1) {
631 access |= ACC_PRIVATE;
632 }
633 if (s.indexOf("protected") != -1) {
634 access |= ACC_PROTECTED;
635 }
636 if (s.indexOf("static") != -1) {
637 access |= ACC_STATIC;
638 }
639 if (s.indexOf("final") != -1) {
640 access |= ACC_FINAL;
641 }
642 if (s.indexOf("super") != -1) {
643 access |= ACC_SUPER;
644 }
645 if (s.indexOf("synchronized") != -1) {
646 access |= ACC_SYNCHRONIZED;
647 }
648 if (s.indexOf("volatile") != -1) {
649 access |= ACC_VOLATILE;
650 }
651 if (s.indexOf("bridge") != -1) {
652 access |= ACC_BRIDGE;
653 }
654 if (s.indexOf("varargs") != -1) {
655 access |= ACC_VARARGS;
656 }
657 if (s.indexOf("transient") != -1) {
658 access |= ACC_TRANSIENT;
659 }
660 if (s.indexOf("native") != -1) {
661 access |= ACC_NATIVE;
662 }
663 if (s.indexOf("interface") != -1) {
664 access |= ACC_INTERFACE;
665 }
666 if (s.indexOf("abstract") != -1) {
667 access |= ACC_ABSTRACT;
668 }
669 if (s.indexOf("strict") != -1) {
670 access |= ACC_STRICT;
671 }
672 if (s.indexOf("synthetic") != -1) {
673 access |= ACC_SYNTHETIC;
674 }
675 if (s.indexOf("annotation") != -1) {
676 access |= ACC_ANNOTATION;
677 }
678 if (s.indexOf("enum") != -1) {
679 access |= ACC_ENUM;
680 }
681 if (s.indexOf("deprecated") != -1) {
682 access |= ACC_DEPRECATED;
683 }
684 if (s.indexOf("mandated") != -1) {
685 access |= ACC_MANDATED;
686 }
687 if (s.indexOf("module") != -1) {
688 access |= ACC_MODULE;
689 }
690 return access;
691 }
692 }
693
694 /**
695 * ClassRule
696 */
697 final class ClassRule extends Rule {
698
699 @Override
700 public final void begin(final String name, final Attributes attrs) {
701 int major = Integer.parseInt(attrs.getValue("major"));
702 int minor = Integer.parseInt(attrs.getValue("minor"));
703 HashMap<String, Object> vals = new HashMap<String, Object>();
704 vals.put("version", minor << 16 | major);
705 vals.put("access", attrs.getValue("access"));
706 vals.put("name", attrs.getValue("name"));
707 vals.put("parent", attrs.getValue("parent"));
708 vals.put("source", attrs.getValue("source"));
709 vals.put("signature", attrs.getValue("signature"));
710 vals.put("interfaces", new ArrayList<String>());
711 push(vals);
712 // values will be extracted in InterfacesRule.end();
713 }
714 }
715
716 final class SourceRule extends Rule {
717
718 @Override
719 public void begin(final String name, final Attributes attrs) {
720 String file = attrs.getValue("file");
721 String debug = attrs.getValue("debug");
722 cv.visitSource(file, debug);
723 }
724 }
725
726 /**
727 * InterfaceRule
728 */
729 final class InterfaceRule extends Rule {
730
731 @Override
732 @SuppressWarnings("unchecked")
733 public final void begin(final String name, final Attributes attrs) {
734 ((ArrayList<String>) ((HashMap<?, ?>) peek()).get("interfaces"))
735 .add(attrs.getValue("name"));
736 }
737 }
738
739 /**
740 * InterfacesRule
741 */
742 final class InterfacesRule extends Rule {
743
744 @Override
745 public final void end(final String element) {
746 HashMap<?, ?> vals = (HashMap<?, ?>) pop();
747 int version = ((Integer) vals.get("version")).intValue();
748 int access = getAccess((String) vals.get("access"));
749 String name = (String) vals.get("name");
750 String signature = (String) vals.get("signature");
751 String parent = (String) vals.get("parent");
752 ArrayList<?> infs = (ArrayList<?>) vals.get("interfaces");
753 String[] interfaces = infs.toArray(new String[infs.size()]);
754 cv.visit(version, access, name, signature, parent, interfaces);
755 push(cv);
756 }
757 }
758
759 /**
760 * ModuleRule: module, requires, exports, restricted-to, uses and provides
761 */
762 final class ModuleRule extends Rule {
763 @Override
764 public final void begin(final String element, final Attributes attrs)
765 throws SAXException {
766 if ("module".equals(element)) {
767 push(cv.visitModule());
768 } else if ("requires".equals(element)) {
769 ModuleVisitor mv = (ModuleVisitor) peek();
770 mv.visitRequire(attrs.getValue("module"),
771 getAccess(attrs.getValue("access")));
772 } else if ("exports".equals(element)) {
773 // encode the name of the exported package as the first item
774 ArrayList<String> list = new ArrayList<String>();
775 list.add(attrs.getValue("name"));
776 push(list);
777 } else if ("to".equals(element)) {
778 @SuppressWarnings("unchecked")
779 ArrayList<String> list = (ArrayList<String>) peek();
780 list.add(attrs.getValue("module"));
781 } else if ("uses".equals(element)) {
782 ModuleVisitor mv = (ModuleVisitor) peek();
783 mv.visitUse(attrs.getValue("service"));
784 } else if ("provides".equals(element)) {
785 ModuleVisitor mv = (ModuleVisitor) peek();
786 mv.visitProvide(attrs.getValue("service"), attrs.getValue("impl"));
787 }
788 }
789
790 @Override
791 public void end(final String element) {
792 if ("exports".equals(element)) {
793 @SuppressWarnings("unchecked")
794 ArrayList<String> list = (ArrayList<String>) pop();
795 String export = list.remove(0); // name of the exported package
796 String[] tos = null;
797 if (!list.isEmpty()) {
798 tos = list.toArray(new String[list.size()]);
799 }
800 ModuleVisitor mv = (ModuleVisitor) peek();
801 mv.visitExport(export, tos);
802 } else if ("module".equals(element)) {
803 ((ModuleVisitor) pop()).visitEnd();
804 }
805 }
806 }
807
808 /**
809 * OuterClassRule
810 */
811 final class OuterClassRule extends Rule {
812
813 @Override
814 public final void begin(final String element, final Attributes attrs) {
815 String owner = attrs.getValue("owner");
816 String name = attrs.getValue("name");
817 String desc = attrs.getValue("desc");
818 cv.visitOuterClass(owner, name, desc);
819 }
820 }
821
822 /**
823 * InnerClassRule
824 */
825 final class InnerClassRule extends Rule {
826
827 @Override
828 public final void begin(final String element, final Attributes attrs) {
829 int access = getAccess(attrs.getValue("access"));
830 String name = attrs.getValue("name");
831 String outerName = attrs.getValue("outerName");
832 String innerName = attrs.getValue("innerName");
833 cv.visitInnerClass(name, outerName, innerName, access);
834 }
835 }
836
837 /**
838 * FieldRule
839 */
840 final class FieldRule extends Rule {
841
842 @Override
843 public final void begin(final String element, final Attributes attrs)
844 throws SAXException {
845 int access = getAccess(attrs.getValue("access"));
846 String name = attrs.getValue("name");
847 String signature = attrs.getValue("signature");
848 String desc = attrs.getValue("desc");
849 Object value = getValue(desc, attrs.getValue("value"));
850 push(cv.visitField(access, name, desc, signature, value));
851 }
852
853 @Override
854 public void end(final String name) {
855 ((FieldVisitor) pop()).visitEnd();
856 }
857 }
858
859 /**
860 * MethodRule
861 */
862 final class MethodRule extends Rule {
863
864 @Override
865 public final void begin(final String name, final Attributes attrs) {
866 labels = new HashMap<Object, Label>();
867 HashMap<String, Object> vals = new HashMap<String, Object>();
868 vals.put("access", attrs.getValue("access"));
869 vals.put("name", attrs.getValue("name"));
870 vals.put("desc", attrs.getValue("desc"));
871 vals.put("signature", attrs.getValue("signature"));
872 vals.put("exceptions", new ArrayList<String>());
873 push(vals);
874 // values will be extracted in ExceptionsRule.end();
875 }
876
877 @Override
878 public final void end(final String name) {
879 ((MethodVisitor) pop()).visitEnd();
880 labels = null;
881 }
882 }
883
884 /**
885 * ExceptionRule
886 */
887 final class ExceptionRule extends Rule {
888
889 @Override
890 @SuppressWarnings("unchecked")
891 public final void begin(final String name, final Attributes attrs) {
892 ((ArrayList<String>) ((HashMap<?, ?>) peek()).get("exceptions"))
893 .add(attrs.getValue("name"));
894 }
895 }
896
897 /**
898 * ExceptionsRule
899 */
900 final class ExceptionsRule extends Rule {
901
902 @Override
903 public final void end(final String element) {
904 HashMap<?, ?> vals = (HashMap<?, ?>) pop();
905 int access = getAccess((String) vals.get("access"));
906 String name = (String) vals.get("name");
907 String desc = (String) vals.get("desc");
908 String signature = (String) vals.get("signature");
909 ArrayList<?> excs = (ArrayList<?>) vals.get("exceptions");
910 String[] exceptions = excs.toArray(new String[excs.size()]);
911
912 push(cv.visitMethod(access, name, desc, signature, exceptions));
913 }
914 }
915
916 /**
917 * MethodParameterRule
918 */
919 final class MethodParameterRule extends Rule {
920 @Override
921 public void begin(final String nm, final Attributes attrs) {
922 String name = attrs.getValue("name");
923 int access = getAccess(attrs.getValue("access"));
924 getCodeVisitor().visitParameter(name, access);
925 }
926 }
927
928 /**
929 * TableSwitchRule
930 */
931 final class TableSwitchRule extends Rule {
932
933 @Override
934 public final void begin(final String name, final Attributes attrs) {
935 HashMap<String, Object> vals = new HashMap<String, Object>();
936 vals.put("min", attrs.getValue("min"));
937 vals.put("max", attrs.getValue("max"));
938 vals.put("dflt", attrs.getValue("dflt"));
939 vals.put("labels", new ArrayList<String>());
940 push(vals);
941 }
942
943 @Override
944 public final void end(final String name) {
945 HashMap<?, ?> vals = (HashMap<?, ?>) pop();
946 int min = Integer.parseInt((String) vals.get("min"));
947 int max = Integer.parseInt((String) vals.get("max"));
948 Label dflt = getLabel(vals.get("dflt"));
949 ArrayList<?> lbls = (ArrayList<?>) vals.get("labels");
950 Label[] labels = lbls.toArray(new Label[lbls.size()]);
951 getCodeVisitor().visitTableSwitchInsn(min, max, dflt, labels);
952 }
953 }
954
955 /**
956 * TableSwitchLabelRule
957 */
958 final class TableSwitchLabelRule extends Rule {
959
960 @Override
961 @SuppressWarnings("unchecked")
962 public final void begin(final String name, final Attributes attrs) {
963 ((ArrayList<Label>) ((HashMap<?, ?>) peek()).get("labels"))
964 .add(getLabel(attrs.getValue("name")));
965 }
966 }
967
968 /**
969 * LookupSwitchRule
970 */
971 final class LookupSwitchRule extends Rule {
972
973 @Override
974 public final void begin(final String name, final Attributes attrs) {
975 HashMap<String, Object> vals = new HashMap<String, Object>();
976 vals.put("dflt", attrs.getValue("dflt"));
977 vals.put("labels", new ArrayList<Label>());
978 vals.put("keys", new ArrayList<String>());
979 push(vals);
980 }
981
982 @Override
983 public final void end(final String name) {
984 HashMap<?, ?> vals = (HashMap<?, ?>) pop();
985 Label dflt = getLabel(vals.get("dflt"));
986 @SuppressWarnings("unchecked")
987 ArrayList<String> keyList = (ArrayList<String>) vals.get("keys");
988 ArrayList<?> lbls = (ArrayList<?>) vals.get("labels");
989 Label[] labels = lbls.toArray(new Label[lbls.size()]);
990 int[] keys = new int[keyList.size()];
991 for (int i = 0; i < keys.length; i++) {
992 keys[i] = Integer.parseInt(keyList.get(i));
993 }
994 getCodeVisitor().visitLookupSwitchInsn(dflt, keys, labels);
995 }
996 }
997
998 /**
999 * LookupSwitchLabelRule
1000 */
1001 final class LookupSwitchLabelRule extends Rule {
1002
1003 @Override
1004 @SuppressWarnings("unchecked")
1005 public final void begin(final String name, final Attributes attrs) {
1006 HashMap<?, ?> vals = (HashMap<?, ?>) peek();
1007 ((ArrayList<Label>) vals.get("labels")).add(getLabel(attrs
1008 .getValue("name")));
1009 ((ArrayList<String>) vals.get("keys")).add(attrs.getValue("key"));
1010 }
1011 }
1012
1013 /**
1014 * FrameRule
1015 */
1016 final class FrameRule extends Rule {
1017
1018 @Override
1019 public void begin(final String name, final Attributes attrs) {
1020 HashMap<String, Object> typeLists = new HashMap<String, Object>();
1021 typeLists.put("local", new ArrayList<Object>());
1022 typeLists.put("stack", new ArrayList<Object>());
1023 push(attrs.getValue("type"));
1024 push(attrs.getValue("count") == null ? "0" : attrs
1025 .getValue("count"));
1026 push(typeLists);
1027 }
1028
1029 @Override
1030 public void end(final String name) {
1031 HashMap<?, ?> typeLists = (HashMap<?, ?>) pop();
1032 ArrayList<?> locals = (ArrayList<?>) typeLists.get("local");
1033 int nLocal = locals.size();
1034 Object[] local = locals.toArray();
1035 ArrayList<?> stacks = (ArrayList<?>) typeLists.get("stack");
1036 int nStack = stacks.size();
1037 Object[] stack = stacks.toArray();
1038 String count = (String) pop();
1039 String type = (String) pop();
1040 if ("NEW".equals(type)) {
1041 getCodeVisitor()
1042 .visitFrame(F_NEW, nLocal, local, nStack, stack);
1043 } else if ("FULL".equals(type)) {
1044 getCodeVisitor().visitFrame(F_FULL, nLocal, local, nStack,
1045 stack);
1046 } else if ("APPEND".equals(type)) {
1047 getCodeVisitor().visitFrame(F_APPEND, nLocal, local, 0, null);
1048 } else if ("CHOP".equals(type)) {
1049 getCodeVisitor().visitFrame(F_CHOP, Integer.parseInt(count),
1050 null, 0, null);
1051 } else if ("SAME".equals(type)) {
1052 getCodeVisitor().visitFrame(F_SAME, 0, null, 0, null);
1053 } else if ("SAME1".equals(type)) {
1054 getCodeVisitor().visitFrame(F_SAME1, 0, null, nStack, stack);
1055 }
1056 }
1057 }
1058
1059 final class FrameTypeRule extends Rule {
1060
1061 @Override
1062 public void begin(final String name, final Attributes attrs) {
1063 @SuppressWarnings("unchecked")
1064 ArrayList<Object> types = (ArrayList<Object>) ((HashMap<?, ?>) peek())
1065 .get(name);
1066 String type = attrs.getValue("type");
1067 if ("uninitialized".equals(type)) {
1068 types.add(getLabel(attrs.getValue("label")));
1069 } else {
1070 Integer t = TYPES.get(type);
1071 if (t == null) {
1072 types.add(type);
1073 } else {
1074 types.add(t);
1075 }
1076 }
1077 }
1078 }
1079
1080 /**
1081 * LabelRule
1082 */
1083 final class LabelRule extends Rule {
1084
1085 @Override
1086 public final void begin(final String name, final Attributes attrs) {
1087 getCodeVisitor().visitLabel(getLabel(attrs.getValue("name")));
1088 }
1089 }
1090
1091 /**
1092 * TryCatchRule
1093 */
1094 final class TryCatchRule extends Rule {
1095
1096 @Override
1097 public final void begin(final String name, final Attributes attrs) {
1098 Label start = getLabel(attrs.getValue("start"));
1099 Label end = getLabel(attrs.getValue("end"));
1100 Label handler = getLabel(attrs.getValue("handler"));
1101 String type = attrs.getValue("type");
1102 getCodeVisitor().visitTryCatchBlock(start, end, handler, type);
1103 }
1104 }
1105
1106 /**
1107 * LineNumberRule
1108 */
1109 final class LineNumberRule extends Rule {
1110
1111 @Override
1112 public final void begin(final String name, final Attributes attrs) {
1113 int line = Integer.parseInt(attrs.getValue("line"));
1114 Label start = getLabel(attrs.getValue("start"));
1115 getCodeVisitor().visitLineNumber(line, start);
1116 }
1117 }
1118
1119 /**
1120 * LocalVarRule
1121 */
1122 final class LocalVarRule extends Rule {
1123
1124 @Override
1125 public final void begin(final String element, final Attributes attrs) {
1126 String name = attrs.getValue("name");
1127 String desc = attrs.getValue("desc");
1128 String signature = attrs.getValue("signature");
1129 Label start = getLabel(attrs.getValue("start"));
1130 Label end = getLabel(attrs.getValue("end"));
1131 int var = Integer.parseInt(attrs.getValue("var"));
1132 getCodeVisitor().visitLocalVariable(name, desc, signature, start,
1133 end, var);
1134 }
1135 }
1136
1137 /**
1138 * InvokeDynamicRule
1139 */
1140 final class InvokeDynamicRule extends Rule {
1141 @Override
1142 public final void begin(final String element, final Attributes attrs)
1143 throws SAXException {
1144 push(attrs.getValue("name"));
1145 push(attrs.getValue("desc"));
1146 push(decodeHandle(attrs.getValue("bsm")));
1147 push(new ArrayList<Object>());
1148 }
1149
1150 @Override
1151 public final void end(final String element) {
1152 ArrayList<?> bsmArgs = (ArrayList<?>) pop();
1153 Handle bsm = (Handle) pop();
1154 String desc = (String) pop();
1155 String name = (String) pop();
1156 getCodeVisitor().visitInvokeDynamicInsn(name, desc, bsm,
1157 bsmArgs.toArray());
1158 }
1159 }
1160
1161 /**
1162 * InvokeDynamicBsmArgumentsRule
1163 */
1164 final class InvokeDynamicBsmArgumentsRule extends Rule {
1165 @Override
1166 public final void begin(final String element, final Attributes attrs)
1167 throws SAXException {
1168 @SuppressWarnings("unchecked")
1169 ArrayList<Object> bsmArgs = (ArrayList<Object>) peek();
1170 bsmArgs.add(getValue(attrs.getValue("desc"), attrs.getValue("cst")));
1171 }
1172 }
1173
1174 /**
1175 * OpcodesRule
1176 */
1177 final class OpcodesRule extends Rule {
1178
1179 // public boolean match( String match, String element) {
1180 // return match.startsWith( path) && OPCODES.containsKey( element);
1181 // }
1182
1183 @Override
1184 public final void begin(final String element, final Attributes attrs)
1185 throws SAXException {
1186 Opcode o = OPCODES.get(element);
1187 if (o == null) {
1188 throw new SAXException("Invalid element: " + element + " at "
1189 + match);
1190 }
1191
1192 switch (o.type) {
1193 case OpcodeGroup.INSN:
1194 getCodeVisitor().visitInsn(o.opcode);
1195 break;
1196
1197 case OpcodeGroup.INSN_FIELD:
1198 getCodeVisitor().visitFieldInsn(o.opcode,
1199 attrs.getValue("owner"), attrs.getValue("name"),
1200 attrs.getValue("desc"));
1201 break;
1202
1203 case OpcodeGroup.INSN_INT:
1204 getCodeVisitor().visitIntInsn(o.opcode,
1205 Integer.parseInt(attrs.getValue("value")));
1206 break;
1207
1208 case OpcodeGroup.INSN_JUMP:
1209 getCodeVisitor().visitJumpInsn(o.opcode,
1210 getLabel(attrs.getValue("label")));
1211 break;
1212
1213 case OpcodeGroup.INSN_METHOD:
1214 getCodeVisitor().visitMethodInsn(o.opcode,
1215 attrs.getValue("owner"), attrs.getValue("name"),
1216 attrs.getValue("desc"),
1217 attrs.getValue("itf").equals("true"));
1218 break;
1219
1220 case OpcodeGroup.INSN_TYPE:
1221 getCodeVisitor()
1222 .visitTypeInsn(o.opcode, attrs.getValue("desc"));
1223 break;
1224
1225 case OpcodeGroup.INSN_VAR:
1226 getCodeVisitor().visitVarInsn(o.opcode,
1227 Integer.parseInt(attrs.getValue("var")));
1228 break;
1229
1230 case OpcodeGroup.INSN_IINC:
1231 getCodeVisitor().visitIincInsn(
1232 Integer.parseInt(attrs.getValue("var")),
1233 Integer.parseInt(attrs.getValue("inc")));
1234 break;
1235
1236 case OpcodeGroup.INSN_LDC:
1237 getCodeVisitor()
1238 .visitLdcInsn(
1239 getValue(attrs.getValue("desc"),
1240 attrs.getValue("cst")));
1241 break;
1242
1243 case OpcodeGroup.INSN_MULTIANEWARRAY:
1244 getCodeVisitor().visitMultiANewArrayInsn(
1245 attrs.getValue("desc"),
1246 Integer.parseInt(attrs.getValue("dims")));
1247 break;
1248
1249 default:
1250 throw new Error("Internal error");
1251
1252 }
1253 }
1254 }
1255
1256 /**
1257 * MaxRule
1258 */
1259 final class MaxRule extends Rule {
1260
1261 @Override
1262 public final void begin(final String element, final Attributes attrs) {
1263 int maxStack = Integer.parseInt(attrs.getValue("maxStack"));
1264 int maxLocals = Integer.parseInt(attrs.getValue("maxLocals"));
1265 getCodeVisitor().visitMaxs(maxStack, maxLocals);
1266 }
1267 }
1268
1269 final class AnnotationRule extends Rule {
1270
1271 @Override
1272 public void begin(final String name, final Attributes attrs) {
1273 String desc = attrs.getValue("desc");
1274 boolean visible = Boolean.valueOf(attrs.getValue("visible"))
1275 .booleanValue();
1276
1277 Object v = peek();
1278 if (v instanceof ClassVisitor) {
1279 push(((ClassVisitor) v).visitAnnotation(desc, visible));
1280 } else if (v instanceof FieldVisitor) {
1281 push(((FieldVisitor) v).visitAnnotation(desc, visible));
1282 } else if (v instanceof MethodVisitor) {
1283 push(((MethodVisitor) v).visitAnnotation(desc, visible));
1284 }
1285 }
1286
1287 @Override
1288 public void end(final String name) {
1289 AnnotationVisitor av = (AnnotationVisitor) pop();
1290 if (av != null) {
1291 av.visitEnd();
1292 }
1293 }
1294 }
1295
1296 final class TypeAnnotationRule extends Rule {
1297
1298 @Override
1299 public void begin(final String name, final Attributes attrs) {
1300 String desc = attrs.getValue("desc");
1301 boolean visible = Boolean.valueOf(attrs.getValue("visible"))
1302 .booleanValue();
1303 int typeRef = Integer.parseInt(attrs.getValue("typeRef"));
1304 TypePath typePath = TypePath.fromString(attrs.getValue("typePath"));
1305
1306 Object v = peek();
1307 if (v instanceof ClassVisitor) {
1308 push(((ClassVisitor) v).visitTypeAnnotation(typeRef, typePath,
1309 desc, visible));
1310 } else if (v instanceof FieldVisitor) {
1311 push(((FieldVisitor) v).visitTypeAnnotation(typeRef, typePath,
1312 desc, visible));
1313 } else if (v instanceof MethodVisitor) {
1314 push(((MethodVisitor) v).visitTypeAnnotation(typeRef, typePath,
1315 desc, visible));
1316 }
1317 }
1318
1319 @Override
1320 public void end(final String name) {
1321 AnnotationVisitor av = (AnnotationVisitor) pop();
1322 if (av != null) {
1323 av.visitEnd();
1324 }
1325 }
1326 }
1327
1328 final class AnnotationParameterRule extends Rule {
1329
1330 @Override
1331 public void begin(final String name, final Attributes attrs) {
1332 int parameter = Integer.parseInt(attrs.getValue("parameter"));
1333 String desc = attrs.getValue("desc");
1334 boolean visible = Boolean.valueOf(attrs.getValue("visible"))
1335 .booleanValue();
1336
1337 push(((MethodVisitor) peek()).visitParameterAnnotation(parameter,
1338 desc, visible));
1339 }
1340
1341 @Override
1342 public void end(final String name) {
1343 AnnotationVisitor av = (AnnotationVisitor) pop();
1344 if (av != null) {
1345 av.visitEnd();
1346 }
1347 }
1348 }
1349
1350 final class InsnAnnotationRule extends Rule {
1351
1352 @Override
1353 public void begin(final String name, final Attributes attrs) {
1354 String desc = attrs.getValue("desc");
1355 boolean visible = Boolean.valueOf(attrs.getValue("visible"))
1356 .booleanValue();
1357 int typeRef = Integer.parseInt(attrs.getValue("typeRef"));
1358 TypePath typePath = TypePath.fromString(attrs.getValue("typePath"));
1359 push(((MethodVisitor) peek()).visitInsnAnnotation(typeRef,
1360 typePath, desc, visible));
1361 }
1362
1363 @Override
1364 public void end(final String name) {
1365 AnnotationVisitor av = (AnnotationVisitor) pop();
1366 if (av != null) {
1367 av.visitEnd();
1368 }
1369 }
1370 }
1371
1372 final class TryCatchAnnotationRule extends Rule {
1373
1374 @Override
1375 public void begin(final String name, final Attributes attrs) {
1376 String desc = attrs.getValue("desc");
1377 boolean visible = Boolean.valueOf(attrs.getValue("visible"))
1378 .booleanValue();
1379 int typeRef = Integer.parseInt(attrs.getValue("typeRef"));
1380 TypePath typePath = TypePath.fromString(attrs.getValue("typePath"));
1381 push(((MethodVisitor) peek()).visitTryCatchAnnotation(typeRef,
1382 typePath, desc, visible));
1383 }
1384
1385 @Override
1386 public void end(final String name) {
1387 AnnotationVisitor av = (AnnotationVisitor) pop();
1388 if (av != null) {
1389 av.visitEnd();
1390 }
1391 }
1392 }
1393
1394 final class LocalVariableAnnotationRule extends Rule {
1395
1396 @Override
1397 public void begin(final String name, final Attributes attrs) {
1398 String desc = attrs.getValue("desc");
1399 boolean visible = Boolean.valueOf(attrs.getValue("visible"))
1400 .booleanValue();
1401 int typeRef = Integer.parseInt(attrs.getValue("typeRef"));
1402 TypePath typePath = TypePath.fromString(attrs.getValue("typePath"));
1403 String[] s = attrs.getValue("start").split(" ");
1404 Label[] start = new Label[s.length];
1405 for (int i = 0; i < start.length; ++i) {
1406 start[i] = getLabel(s[i]);
1407 }
1408 String[] e = attrs.getValue("end").split(" ");
1409 Label[] end = new Label[e.length];
1410 for (int i = 0; i < end.length; ++i) {
1411 end[i] = getLabel(e[i]);
1412 }
1413 String[] v = attrs.getValue("index").split(" ");
1414 int[] index = new int[v.length];
1415 for (int i = 0; i < index.length; ++i) {
1416 index[i] = Integer.parseInt(v[i]);
1417 }
1418 push(((MethodVisitor) peek()).visitLocalVariableAnnotation(typeRef,
1419 typePath, start, end, index, desc, visible));
1420 }
1421
1422 @Override
1423 public void end(final String name) {
1424 AnnotationVisitor av = (AnnotationVisitor) pop();
1425 if (av != null) {
1426 av.visitEnd();
1427 }
1428 }
1429 }
1430
1431 final class AnnotationValueRule extends Rule {
1432
1433 @Override
1434 public void begin(final String nm, final Attributes attrs)
1435 throws SAXException {
1436 AnnotationVisitor av = (AnnotationVisitor) peek();
1437 if (av != null) {
1438 av.visit(
1439 attrs.getValue("name"),
1440 getValue(attrs.getValue("desc"),
1441 attrs.getValue("value")));
1442 }
1443 }
1444 }
1445
1446 final class AnnotationValueEnumRule extends Rule {
1447
1448 @Override
1449 public void begin(final String nm, final Attributes attrs) {
1450 AnnotationVisitor av = (AnnotationVisitor) peek();
1451 if (av != null) {
1452 av.visitEnum(attrs.getValue("name"), attrs.getValue("desc"),
1453 attrs.getValue("value"));
1454 }
1455 }
1456 }
1457
1458 final class AnnotationValueAnnotationRule extends Rule {
1459
1460 @Override
1461 public void begin(final String nm, final Attributes attrs) {
1462 AnnotationVisitor av = (AnnotationVisitor) peek();
1463 push(av == null ? null : av.visitAnnotation(attrs.getValue("name"),
1464 attrs.getValue("desc")));
1465 }
1466
1467 @Override
1468 public void end(final String name) {
1469 AnnotationVisitor av = (AnnotationVisitor) pop();
1470 if (av != null) {
1471 av.visitEnd();
1472 }
1473 }
1474 }
1475
1476 final class AnnotationValueArrayRule extends Rule {
1477
1478 @Override
1479 public void begin(final String nm, final Attributes attrs) {
1480 AnnotationVisitor av = (AnnotationVisitor) peek();
1481 push(av == null ? null : av.visitArray(attrs.getValue("name")));
1482 }
1483
1484 @Override
1485 public void end(final String name) {
1486 AnnotationVisitor av = (AnnotationVisitor) pop();
1487 if (av != null) {
1488 av.visitEnd();
1489 }
1490 }
1491 }
1492
1493 final class AnnotationDefaultRule extends Rule {
1494
1495 @Override
1496 public void begin(final String nm, final Attributes attrs) {
1497 MethodVisitor av = (MethodVisitor) peek();
1498 push(av == null ? null : av.visitAnnotationDefault());
1499 }
1500
1501 @Override
1502 public void end(final String name) {
1503 AnnotationVisitor av = (AnnotationVisitor) pop();
1504 if (av != null) {
1505 av.visitEnd();
1506 }
1507 }
1508 }
1509
1510 /**
1511 * Opcode
1512 */
1513 static final class Opcode {
1514
1515 public final int opcode;
1516
1517 public final int type;
1518
1519 Opcode(final int opcode, final int type) {
1520 this.opcode = opcode;
1521 this.type = type;
1522 }
1523 }
1044 }
1045 }
1046 }
1047
1048 /** LabelRule */
1049 final class LabelRule extends Rule {
1050
1051 @Override
1052 public final void begin(final String name, final Attributes attrs) {
1053 getCodeVisitor().visitLabel(getLabel(attrs.getValue("name")));
1054 }
1055 }
1056
1057 /** TryCatchRule */
1058 final class TryCatchRule extends Rule {
1059
1060 @Override
1061 public final void begin(final String name, final Attributes attrs) {
1062 Label start = getLabel(attrs.getValue("start"));
1063 Label end = getLabel(attrs.getValue("end"));
1064 Label handler = getLabel(attrs.getValue("handler"));
1065 String type = attrs.getValue("type");
1066 getCodeVisitor().visitTryCatchBlock(start, end, handler, type);
1067 }
1068 }
1069
1070 /** LineNumberRule */
1071 final class LineNumberRule extends Rule {
1072
1073 @Override
1074 public final void begin(final String name, final Attributes attrs) {
1075 int line = Integer.parseInt(attrs.getValue("line"));
1076 Label start = getLabel(attrs.getValue("start"));
1077 getCodeVisitor().visitLineNumber(line, start);
1078 }
1079 }
1080
1081 /** LocalVarRule */
1082 final class LocalVarRule extends Rule {
1083
1084 @Override
1085 public final void begin(final String element, final Attributes attrs) {
1086 String name = attrs.getValue("name");
1087 String desc = attrs.getValue("desc");
1088 String signature = attrs.getValue("signature");
1089 Label start = getLabel(attrs.getValue("start"));
1090 Label end = getLabel(attrs.getValue("end"));
1091 int var = Integer.parseInt(attrs.getValue("var"));
1092 getCodeVisitor().visitLocalVariable(name, desc, signature, start, end, var);
1093 }
1094 }
1095
1096 /** InvokeDynamicRule */
1097 final class InvokeDynamicRule extends Rule {
1098 @Override
1099 public final void begin(final String element, final Attributes attrs) throws SAXException {
1100 push(attrs.getValue("name"));
1101 push(attrs.getValue("desc"));
1102 push(decodeHandle(attrs.getValue("bsm")));
1103 push(new ArrayList<Object>());
1104 }
1105
1106 @Override
1107 public final void end(final String element) {
1108 ArrayList<?> bsmArgs = (ArrayList<?>) pop();
1109 Handle bsm = (Handle) pop();
1110 String desc = (String) pop();
1111 String name = (String) pop();
1112 getCodeVisitor().visitInvokeDynamicInsn(name, desc, bsm, bsmArgs.toArray());
1113 }
1114 }
1115
1116 /** InvokeDynamicBsmArgumentsRule */
1117 final class InvokeDynamicBsmArgumentsRule extends Rule {
1118 @Override
1119 public final void begin(final String element, final Attributes attrs) throws SAXException {
1120 @SuppressWarnings("unchecked")
1121 ArrayList<Object> bsmArgs = (ArrayList<Object>) peek();
1122 bsmArgs.add(getValue(attrs.getValue("desc"), attrs.getValue("cst")));
1123 }
1124 }
1125
1126 /** OpcodesRule */
1127 final class OpcodesRule extends Rule {
1128
1129 // public boolean match( String match, String element) {
1130 // return match.startsWith( path) && OPCODES.containsKey( element);
1131 // }
1132
1133 @Override
1134 public final void begin(final String element, final Attributes attrs) throws SAXException {
1135 Opcode o = OPCODES.get(element);
1136 if (o == null) {
1137 throw new SAXException("Invalid element: " + element + " at " + match);
1138 }
1139
1140 switch (o.type) {
1141 case OpcodeGroup.INSN:
1142 getCodeVisitor().visitInsn(o.opcode);
1143 break;
1144
1145 case OpcodeGroup.INSN_FIELD:
1146 getCodeVisitor()
1147 .visitFieldInsn(
1148 o.opcode,
1149 attrs.getValue("owner"),
1150 attrs.getValue("name"),
1151 attrs.getValue("desc"));
1152 break;
1153
1154 case OpcodeGroup.INSN_INT:
1155 getCodeVisitor().visitIntInsn(o.opcode, Integer.parseInt(attrs.getValue("value")));
1156 break;
1157
1158 case OpcodeGroup.INSN_JUMP:
1159 getCodeVisitor().visitJumpInsn(o.opcode, getLabel(attrs.getValue("label")));
1160 break;
1161
1162 case OpcodeGroup.INSN_METHOD:
1163 getCodeVisitor()
1164 .visitMethodInsn(
1165 o.opcode,
1166 attrs.getValue("owner"),
1167 attrs.getValue("name"),
1168 attrs.getValue("desc"),
1169 attrs.getValue("itf").equals("true"));
1170 break;
1171
1172 case OpcodeGroup.INSN_TYPE:
1173 getCodeVisitor().visitTypeInsn(o.opcode, attrs.getValue("desc"));
1174 break;
1175
1176 case OpcodeGroup.INSN_VAR:
1177 getCodeVisitor().visitVarInsn(o.opcode, Integer.parseInt(attrs.getValue("var")));
1178 break;
1179
1180 case OpcodeGroup.INSN_IINC:
1181 getCodeVisitor()
1182 .visitIincInsn(
1183 Integer.parseInt(attrs.getValue("var")), Integer.parseInt(attrs.getValue("inc")));
1184 break;
1185
1186 case OpcodeGroup.INSN_LDC:
1187 getCodeVisitor().visitLdcInsn(getValue(attrs.getValue("desc"), attrs.getValue("cst")));
1188 break;
1189
1190 case OpcodeGroup.INSN_MULTIANEWARRAY:
1191 getCodeVisitor()
1192 .visitMultiANewArrayInsn(
1193 attrs.getValue("desc"), Integer.parseInt(attrs.getValue("dims")));
1194 break;
1195
1196 default:
1197 throw new Error("Internal error");
1198 }
1199 }
1200 }
1201
1202 /** MaxRule */
1203 final class MaxRule extends Rule {
1204
1205 @Override
1206 public final void begin(final String element, final Attributes attrs) {
1207 int maxStack = Integer.parseInt(attrs.getValue("maxStack"));
1208 int maxLocals = Integer.parseInt(attrs.getValue("maxLocals"));
1209 getCodeVisitor().visitMaxs(maxStack, maxLocals);
1210 }
1211 }
1212
1213 final class AnnotationRule extends Rule {
1214
1215 @Override
1216 public void begin(final String name, final Attributes attrs) {
1217 String desc = attrs.getValue("desc");
1218 boolean visible = Boolean.valueOf(attrs.getValue("visible")).booleanValue();
1219
1220 Object v = peek();
1221 if (v instanceof ClassVisitor) {
1222 push(((ClassVisitor) v).visitAnnotation(desc, visible));
1223 } else if (v instanceof FieldVisitor) {
1224 push(((FieldVisitor) v).visitAnnotation(desc, visible));
1225 } else if (v instanceof MethodVisitor) {
1226 push(((MethodVisitor) v).visitAnnotation(desc, visible));
1227 }
1228 }
1229
1230 @Override
1231 public void end(final String name) {
1232 AnnotationVisitor av = (AnnotationVisitor) pop();
1233 if (av != null) {
1234 av.visitEnd();
1235 }
1236 }
1237 }
1238
1239 final class TypeAnnotationRule extends Rule {
1240
1241 @Override
1242 public void begin(final String name, final Attributes attrs) {
1243 String desc = attrs.getValue("desc");
1244 boolean visible = Boolean.valueOf(attrs.getValue("visible")).booleanValue();
1245 int typeRef = Integer.parseInt(attrs.getValue("typeRef"));
1246 TypePath typePath = TypePath.fromString(attrs.getValue("typePath"));
1247
1248 Object v = peek();
1249 if (v instanceof ClassVisitor) {
1250 push(((ClassVisitor) v).visitTypeAnnotation(typeRef, typePath, desc, visible));
1251 } else if (v instanceof FieldVisitor) {
1252 push(((FieldVisitor) v).visitTypeAnnotation(typeRef, typePath, desc, visible));
1253 } else if (v instanceof MethodVisitor) {
1254 push(((MethodVisitor) v).visitTypeAnnotation(typeRef, typePath, desc, visible));
1255 }
1256 }
1257
1258 @Override
1259 public void end(final String name) {
1260 AnnotationVisitor av = (AnnotationVisitor) pop();
1261 if (av != null) {
1262 av.visitEnd();
1263 }
1264 }
1265 }
1266
1267 final class AnnotableParameterCountRule extends Rule {
1268
1269 @Override
1270 public void begin(final String name, final Attributes attrs) {
1271 int parameterCount = Integer.parseInt(attrs.getValue("count"));
1272 boolean visible = Boolean.valueOf(attrs.getValue("visible")).booleanValue();
1273 ((MethodVisitor) peek()).visitAnnotableParameterCount(parameterCount, visible);
1274 }
1275 }
1276
1277 final class AnnotationParameterRule extends Rule {
1278
1279 @Override
1280 public void begin(final String name, final Attributes attrs) {
1281 int parameter = Integer.parseInt(attrs.getValue("parameter"));
1282 String desc = attrs.getValue("desc");
1283 boolean visible = Boolean.valueOf(attrs.getValue("visible")).booleanValue();
1284
1285 push(((MethodVisitor) peek()).visitParameterAnnotation(parameter, desc, visible));
1286 }
1287
1288 @Override
1289 public void end(final String name) {
1290 AnnotationVisitor av = (AnnotationVisitor) pop();
1291 if (av != null) {
1292 av.visitEnd();
1293 }
1294 }
1295 }
1296
1297 final class InsnAnnotationRule extends Rule {
1298
1299 @Override
1300 public void begin(final String name, final Attributes attrs) {
1301 String desc = attrs.getValue("desc");
1302 boolean visible = Boolean.valueOf(attrs.getValue("visible")).booleanValue();
1303 int typeRef = Integer.parseInt(attrs.getValue("typeRef"));
1304 TypePath typePath = TypePath.fromString(attrs.getValue("typePath"));
1305 push(((MethodVisitor) peek()).visitInsnAnnotation(typeRef, typePath, desc, visible));
1306 }
1307
1308 @Override
1309 public void end(final String name) {
1310 AnnotationVisitor av = (AnnotationVisitor) pop();
1311 if (av != null) {
1312 av.visitEnd();
1313 }
1314 }
1315 }
1316
1317 final class TryCatchAnnotationRule extends Rule {
1318
1319 @Override
1320 public void begin(final String name, final Attributes attrs) {
1321 String desc = attrs.getValue("desc");
1322 boolean visible = Boolean.valueOf(attrs.getValue("visible")).booleanValue();
1323 int typeRef = Integer.parseInt(attrs.getValue("typeRef"));
1324 TypePath typePath = TypePath.fromString(attrs.getValue("typePath"));
1325 push(((MethodVisitor) peek()).visitTryCatchAnnotation(typeRef, typePath, desc, visible));
1326 }
1327
1328 @Override
1329 public void end(final String name) {
1330 AnnotationVisitor av = (AnnotationVisitor) pop();
1331 if (av != null) {
1332 av.visitEnd();
1333 }
1334 }
1335 }
1336
1337 final class LocalVariableAnnotationRule extends Rule {
1338
1339 @Override
1340 public void begin(final String name, final Attributes attrs) {
1341 String desc = attrs.getValue("desc");
1342 boolean visible = Boolean.valueOf(attrs.getValue("visible")).booleanValue();
1343 int typeRef = Integer.parseInt(attrs.getValue("typeRef"));
1344 TypePath typePath = TypePath.fromString(attrs.getValue("typePath"));
1345 String[] s = attrs.getValue("start").split(" ");
1346 Label[] start = new Label[s.length];
1347 for (int i = 0; i < start.length; ++i) {
1348 start[i] = getLabel(s[i]);
1349 }
1350 String[] e = attrs.getValue("end").split(" ");
1351 Label[] end = new Label[e.length];
1352 for (int i = 0; i < end.length; ++i) {
1353 end[i] = getLabel(e[i]);
1354 }
1355 String[] v = attrs.getValue("index").split(" ");
1356 int[] index = new int[v.length];
1357 for (int i = 0; i < index.length; ++i) {
1358 index[i] = Integer.parseInt(v[i]);
1359 }
1360 push(
1361 ((MethodVisitor) peek())
1362 .visitLocalVariableAnnotation(typeRef, typePath, start, end, index, desc, visible));
1363 }
1364
1365 @Override
1366 public void end(final String name) {
1367 AnnotationVisitor av = (AnnotationVisitor) pop();
1368 if (av != null) {
1369 av.visitEnd();
1370 }
1371 }
1372 }
1373
1374 final class AnnotationValueRule extends Rule {
1375
1376 @Override
1377 public void begin(final String nm, final Attributes attrs) throws SAXException {
1378 AnnotationVisitor av = (AnnotationVisitor) peek();
1379 if (av != null) {
1380 av.visit(attrs.getValue("name"), getValue(attrs.getValue("desc"), attrs.getValue("value")));
1381 }
1382 }
1383 }
1384
1385 final class AnnotationValueEnumRule extends Rule {
1386
1387 @Override
1388 public void begin(final String nm, final Attributes attrs) {
1389 AnnotationVisitor av = (AnnotationVisitor) peek();
1390 if (av != null) {
1391 av.visitEnum(attrs.getValue("name"), attrs.getValue("desc"), attrs.getValue("value"));
1392 }
1393 }
1394 }
1395
1396 final class AnnotationValueAnnotationRule extends Rule {
1397
1398 @Override
1399 public void begin(final String nm, final Attributes attrs) {
1400 AnnotationVisitor av = (AnnotationVisitor) peek();
1401 push(av == null ? null : av.visitAnnotation(attrs.getValue("name"), attrs.getValue("desc")));
1402 }
1403
1404 @Override
1405 public void end(final String name) {
1406 AnnotationVisitor av = (AnnotationVisitor) pop();
1407 if (av != null) {
1408 av.visitEnd();
1409 }
1410 }
1411 }
1412
1413 final class AnnotationValueArrayRule extends Rule {
1414
1415 @Override
1416 public void begin(final String nm, final Attributes attrs) {
1417 AnnotationVisitor av = (AnnotationVisitor) peek();
1418 push(av == null ? null : av.visitArray(attrs.getValue("name")));
1419 }
1420
1421 @Override
1422 public void end(final String name) {
1423 AnnotationVisitor av = (AnnotationVisitor) pop();
1424 if (av != null) {
1425 av.visitEnd();
1426 }
1427 }
1428 }
1429
1430 final class AnnotationDefaultRule extends Rule {
1431
1432 @Override
1433 public void begin(final String nm, final Attributes attrs) {
1434 MethodVisitor av = (MethodVisitor) peek();
1435 push(av == null ? null : av.visitAnnotationDefault());
1436 }
1437
1438 @Override
1439 public void end(final String name) {
1440 AnnotationVisitor av = (AnnotationVisitor) pop();
1441 if (av != null) {
1442 av.visitEnd();
1443 }
1444 }
1445 }
1446
1447 /** Opcode */
1448 static final class Opcode {
1449
1450 public final int opcode;
1451
1452 public final int type;
1453
1454 Opcode(final int opcode, final int type) {
1455 this.opcode = opcode;
1456 this.type = type;
1457 }
1458 }
15241459 }
0 /***
1 * ASM XML Adapter
2 * Copyright (c) 2004-2011, Eugene Kuleshov
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.xml;
3028
3129 import java.io.BufferedOutputStream;
6664 import org.xml.sax.helpers.XMLReaderFactory;
6765
6866 /**
69 * Processor is a command line tool that can be used for bytecode waving
70 * directed by XSL transformation.
71 * <p>
72 * In order to use a concrete XSLT engine, system property
73 * <tt>javax.xml.transform.TransformerFactory</tt> must be set to one of the
74 * following values.
75 *
67 * Processor is a command line tool that can be used for bytecode waving directed by XSL
68 * transformation.
69 *
70 * <p>In order to use a concrete XSLT engine, system property
71 * <tt>javax.xml.transform.TransformerFactory</tt> must be set to one of the following values.
72 *
7673 * <blockquote>
74 *
7775 * <table border="1" cellspacing="0" cellpadding="3">
76 * <caption>Possible TransformerFactory values</caption>
7877 * <tr>
7978 * <td>jd.xslt</td>
8079 * <td>jd.xml.xslt.trax.TransformerFactoryImpl</td>
8180 * </tr>
82 *
81 *
8382 * <tr>
8483 * <td>Saxon</td>
8584 * <td>net.sf.saxon.TransformerFactoryImpl</td>
8685 * </tr>
87 *
86 *
8887 * <tr>
8988 * <td>Caucho</td>
9089 * <td>com.caucho.xsl.Xsl</td>
9190 * </tr>
92 *
91 *
9392 * <tr>
9493 * <td>Xalan interpeter</td>
9594 * <td>org.apache.xalan.processor.TransformerFactory</td>
9695 * </tr>
97 *
96 *
9897 * <tr>
9998 * <td>Xalan xsltc</td>
10099 * <td>org.apache.xalan.xsltc.trax.TransformerFactoryImpl</td>
101100 * </tr>
102101 * </table>
102 *
103103 * </blockquote>
104 *
104 *
105 * @deprecated This class is no longer maintained, will not support new Java features, and will
106 * eventually be deleted. Use the asm or asm.tree API instead.
105107 * @author Eugene Kuleshov
106108 */
109 @Deprecated
107110 public class Processor {
108111
109 public static final int BYTECODE = 1;
110
111 public static final int MULTI_XML = 2;
112
113 public static final int SINGLE_XML = 3;
114
115 private static final String SINGLE_XML_NAME = "classes.xml";
116
117 private final int inRepresentation;
118
119 private final int outRepresentation;
120
121 private final InputStream input;
122
123 private final OutputStream output;
124
125 private final Source xslt;
126
127 private int n = 0;
128
129 public Processor(final int inRepresenation, final int outRepresentation,
130 final InputStream input, final OutputStream output,
131 final Source xslt) {
132 this.inRepresentation = inRepresenation;
133 this.outRepresentation = outRepresentation;
134 this.input = input;
135 this.output = output;
136 this.xslt = xslt;
137 }
138
139 public int process() throws TransformerException, IOException, SAXException {
140 ZipInputStream zis = new ZipInputStream(input);
141 final ZipOutputStream zos = new ZipOutputStream(output);
142 final OutputStreamWriter osw = new OutputStreamWriter(zos);
143
144 Thread.currentThread().setContextClassLoader(
145 getClass().getClassLoader());
146
147 TransformerFactory tf = TransformerFactory.newInstance();
148 if (!tf.getFeature(SAXSource.FEATURE)
149 || !tf.getFeature(SAXResult.FEATURE)) {
150 return 0;
112 public static final int BYTECODE = 1;
113
114 public static final int MULTI_XML = 2;
115
116 public static final int SINGLE_XML = 3;
117
118 private static final String SINGLE_XML_NAME = "classes.xml";
119
120 private final int inRepresentation;
121
122 private final int outRepresentation;
123
124 private final InputStream input;
125
126 private final OutputStream output;
127
128 private final Source xslt;
129
130 private int n = 0;
131
132 public Processor(
133 final int inRepresenation,
134 final int outRepresentation,
135 final InputStream input,
136 final OutputStream output,
137 final Source xslt) {
138 this.inRepresentation = inRepresenation;
139 this.outRepresentation = outRepresentation;
140 this.input = input;
141 this.output = output;
142 this.xslt = xslt;
143 }
144
145 public int process() throws TransformerException, IOException, SAXException {
146 ZipInputStream zis = new ZipInputStream(input);
147 final ZipOutputStream zos = new ZipOutputStream(output);
148 final OutputStreamWriter osw = new OutputStreamWriter(zos);
149
150 Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
151
152 TransformerFactory tf = TransformerFactory.newInstance();
153 if (!tf.getFeature(SAXSource.FEATURE) || !tf.getFeature(SAXResult.FEATURE)) {
154 return 0;
155 }
156
157 SAXTransformerFactory saxtf = (SAXTransformerFactory) tf;
158 Templates templates = null;
159 if (xslt != null) {
160 templates = saxtf.newTemplates(xslt);
161 }
162
163 // configuring outHandlerFactory
164 // ///////////////////////////////////////////////////////
165
166 EntryElement entryElement = getEntryElement(zos);
167
168 ContentHandler outDocHandler = null;
169 switch (outRepresentation) {
170 case BYTECODE:
171 outDocHandler =
172 new OutputSlicingHandler(new ASMContentHandlerFactory(zos), entryElement, false);
173 break;
174
175 case MULTI_XML:
176 outDocHandler =
177 new OutputSlicingHandler(new SAXWriterFactory(osw, true), entryElement, true);
178 break;
179
180 case SINGLE_XML:
181 ZipEntry outputEntry = new ZipEntry(SINGLE_XML_NAME);
182 zos.putNextEntry(outputEntry);
183 outDocHandler = new SAXWriter(osw, false);
184 break;
185 }
186
187 // configuring inputDocHandlerFactory
188 // /////////////////////////////////////////////////
189 ContentHandler inDocHandler;
190 if (templates == null) {
191 inDocHandler = outDocHandler;
192 } else {
193 inDocHandler =
194 new InputSlicingHandler(
195 "class",
196 outDocHandler,
197 new TransformerHandlerFactory(saxtf, templates, outDocHandler));
198 }
199 ContentHandlerFactory inDocHandlerFactory = new SubdocumentHandlerFactory(inDocHandler);
200
201 if (inDocHandler != null && inRepresentation != SINGLE_XML) {
202 inDocHandler.startDocument();
203 inDocHandler.startElement("", "classes", "classes", new AttributesImpl());
204 }
205
206 int i = 0;
207 ZipEntry ze;
208 while ((ze = zis.getNextEntry()) != null) {
209 update(ze.getName(), n++);
210 if (isClassEntry(ze)) {
211 processEntry(zis, ze, inDocHandlerFactory);
212 } else {
213 OutputStream os = entryElement.openEntry(getName(ze));
214 copyEntry(zis, os);
215 entryElement.closeEntry();
216 }
217
218 i++;
219 }
220
221 if (inDocHandler != null && inRepresentation != SINGLE_XML) {
222 inDocHandler.endElement("", "classes", "classes");
223 inDocHandler.endDocument();
224 }
225
226 if (outRepresentation == SINGLE_XML) {
227 zos.closeEntry();
228 }
229 zos.flush();
230 zos.close();
231
232 return i;
233 }
234
235 private void copyEntry(final InputStream is, final OutputStream os) throws IOException {
236 if (outRepresentation == SINGLE_XML) {
237 return;
238 }
239
240 byte[] buff = new byte[2048];
241 int i;
242 while ((i = is.read(buff)) != -1) {
243 os.write(buff, 0, i);
244 }
245 }
246
247 private boolean isClassEntry(final ZipEntry ze) {
248 String name = ze.getName();
249 return inRepresentation == SINGLE_XML && name.equals(SINGLE_XML_NAME)
250 || name.endsWith(".class")
251 || name.endsWith(".class.xml");
252 }
253
254 private void processEntry(
255 final ZipInputStream zis, final ZipEntry ze, final ContentHandlerFactory handlerFactory) {
256 ContentHandler handler = handlerFactory.createContentHandler();
257 try {
258
259 // if (CODE2ASM.equals(command)) { // read bytecode and process it
260 // // with TraceClassVisitor
261 // ClassReader cr = new ClassReader(readEntry(zis, ze));
262 // cr.accept(new TraceClassVisitor(null, new PrintWriter(os)),
263 // false);
264 // }
265
266 boolean singleInputDocument = inRepresentation == SINGLE_XML;
267 if (inRepresentation == BYTECODE) { // read bytecode and process it
268 // with handler
269 ClassReader cr = new ClassReader(readEntry(zis, ze));
270 cr.accept(new SAXClassAdapter(handler, singleInputDocument), 0);
271
272 } else { // read XML and process it with handler
273 XMLReader reader = XMLReaderFactory.createXMLReader();
274 reader.setContentHandler(handler);
275 reader.parse(
276 new InputSource(
277 singleInputDocument
278 ? (InputStream) new ProtectedInputStream(zis)
279 : new ByteArrayInputStream(readEntry(zis, ze))));
280 }
281 } catch (Exception ex) {
282 update(ze.getName(), 0);
283 update(ex, 0);
284 }
285 }
286
287 private EntryElement getEntryElement(final ZipOutputStream zos) {
288 if (outRepresentation == SINGLE_XML) {
289 return new SingleDocElement(zos);
290 }
291 return new ZipEntryElement(zos);
292 }
293
294 // private ContentHandlerFactory getHandlerFactory(
295 // OutputStream os,
296 // SAXTransformerFactory saxtf,
297 // Templates templates)
298 // {
299 // ContentHandlerFactory factory = null;
300 // if (templates == null) {
301 // if (outputRepresentation == BYTECODE) { // factory used to write
302 // // bytecode
303 // factory = new ASMContentHandlerFactory(os, computeMax);
304 // } else { // factory used to write XML
305 // factory = new SAXWriterFactory(os, true);
306 // }
307 // } else {
308 // if (outputRepresentation == BYTECODE) { // factory used to transform
309 // // and then write bytecode
310 // factory = new ASMTransformerHandlerFactory(saxtf,
311 // templates,
312 // os,
313 // computeMax);
314 // } else { // factory used to transformand then write XML
315 // factory = new TransformerHandlerFactory(saxtf,
316 // templates,
317 // os,
318 // outputRepresentation == SINGLE_XML);
319 // }
320 // }
321 // return factory;
322 // }
323
324 private String getName(final ZipEntry ze) {
325 String name = ze.getName();
326 if (isClassEntry(ze)) {
327 if (inRepresentation != BYTECODE && outRepresentation == BYTECODE) {
328 name = name.substring(0, name.length() - 4); // .class.xml to
329 // .class
330 } else if (inRepresentation == BYTECODE && outRepresentation != BYTECODE) {
331 name += ".xml"; // .class to .class.xml
332 }
333 // } else if( CODE2ASM.equals( command)) {
334 // name = name.substring( 0, name.length()-6).concat( ".asm");
335 }
336 return name;
337 }
338
339 private static byte[] readEntry(final InputStream zis, final ZipEntry ze) throws IOException {
340 long size = ze.getSize();
341 if (size > -1) {
342 byte[] buff = new byte[(int) size];
343 int k = 0;
344 int n;
345 while ((n = zis.read(buff, k, buff.length - k)) > 0) {
346 k += n;
347 }
348 return buff;
349 }
350
351 ByteArrayOutputStream bos = new ByteArrayOutputStream();
352 byte[] buff = new byte[4096];
353 int i;
354 while ((i = zis.read(buff)) != -1) {
355 bos.write(buff, 0, i);
356 }
357 return bos.toByteArray();
358 }
359
360 /*
361 * (non-Javadoc)
362 *
363 * @see java.util.Observer#update(java.util.Observable, java.lang.Object)
364 */
365 protected void update(final Object arg, final int n) {
366 if (arg instanceof Throwable) {
367 ((Throwable) arg).printStackTrace();
368 } else {
369 if (n % 100 == 0) {
370 System.err.println(n + " " + arg);
371 }
372 }
373 }
374
375 public static void main(final String[] args) throws Exception {
376 if (args.length < 2) {
377 showUsage();
378 return;
379 }
380
381 int inRepresentation = getRepresentation(args[0]);
382 int outRepresentation = getRepresentation(args[1]);
383
384 InputStream is = System.in;
385 OutputStream os = new BufferedOutputStream(System.out);
386
387 Source xslt = null;
388 // boolean computeMax = true;
389
390 for (int i = 2; i < args.length; i++) {
391 if ("-in".equals(args[i])) {
392 is = new FileInputStream(args[++i]);
393
394 } else if ("-out".equals(args[i])) {
395 os = new BufferedOutputStream(new FileOutputStream(args[++i]));
396
397 } else if ("-xslt".equals(args[i])) {
398 xslt = new StreamSource(new FileInputStream(args[++i]));
399
400 // } else if( "-computemax".equals( args[ i].toLowerCase())) {
401 // computeMax = true;
402
403 } else {
404 showUsage();
405 return;
406 }
407 }
408
409 if (inRepresentation == 0 || outRepresentation == 0) {
410 showUsage();
411 return;
412 }
413
414 Processor m = new Processor(inRepresentation, outRepresentation, is, os, xslt);
415
416 long l1 = System.currentTimeMillis();
417 int n = m.process();
418 long l2 = System.currentTimeMillis();
419 System.err.println(n);
420 System.err.println((l2 - l1) + "ms " + 1000f * n / (l2 - l1) + " resources/sec");
421 }
422
423 private static int getRepresentation(final String s) {
424 if ("code".equals(s)) {
425 return BYTECODE;
426 } else if ("xml".equals(s)) {
427 return MULTI_XML;
428 } else if ("singlexml".equals(s)) {
429 return SINGLE_XML;
430 }
431 return 0;
432 }
433
434 private static void showUsage() {
435 System.err.println(
436 "Usage: Main <in format> <out format> [-in <input jar>] [-out <output jar>] [-xslt <xslt fiel>]");
437 System.err.println(" when -in or -out is omitted sysin and sysout would be used");
438 System.err.println(" <in format> and <out format> - code | xml | singlexml");
439 }
440
441 /**
442 * IputStream wrapper class used to protect input streams from being closed by some stupid XML
443 * parsers.
444 */
445 private static final class ProtectedInputStream extends InputStream {
446 private final InputStream is;
447
448 ProtectedInputStream(final InputStream is) {
449 this.is = is;
450 }
451
452 @Override
453 public final void close() throws IOException {}
454
455 @Override
456 public final int read() throws IOException {
457 return is.read();
458 }
459
460 @Override
461 public final int read(final byte[] b, final int off, final int len) throws IOException {
462 return is.read(b, off, len);
463 }
464
465 @Override
466 public final int available() throws IOException {
467 return is.available();
468 }
469 }
470
471 /**
472 * A {@link ContentHandlerFactory} is used to create {@link ContentHandler} instances for concrete
473 * context.
474 */
475 private static interface ContentHandlerFactory {
476
477 /**
478 * Creates an instance of the content handler.
479 *
480 * @return content handler
481 */
482 ContentHandler createContentHandler();
483 }
484
485 /** SAXWriterFactory */
486 private static final class SAXWriterFactory implements ContentHandlerFactory {
487 private final Writer w;
488
489 private final boolean optimizeEmptyElements;
490
491 SAXWriterFactory(final Writer w, final boolean optimizeEmptyElements) {
492 this.w = w;
493 this.optimizeEmptyElements = optimizeEmptyElements;
494 }
495
496 public final ContentHandler createContentHandler() {
497 return new SAXWriter(w, optimizeEmptyElements);
498 }
499 }
500
501 /** ASMContentHandlerFactory */
502 private static final class ASMContentHandlerFactory implements ContentHandlerFactory {
503 final OutputStream os;
504
505 ASMContentHandlerFactory(final OutputStream os) {
506 this.os = os;
507 }
508
509 public final ContentHandler createContentHandler() {
510 final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
511 return new ASMContentHandler(cw) {
512 @Override
513 public void endDocument() throws SAXException {
514 try {
515 os.write(cw.toByteArray());
516 } catch (IOException e) {
517 throw new SAXException(e);
518 }
151519 }
152
153 SAXTransformerFactory saxtf = (SAXTransformerFactory) tf;
154 Templates templates = null;
155 if (xslt != null) {
156 templates = saxtf.newTemplates(xslt);
520 };
521 }
522 }
523
524 /** TransformerHandlerFactory */
525 private static final class TransformerHandlerFactory implements ContentHandlerFactory {
526 private SAXTransformerFactory saxtf;
527
528 private final Templates templates;
529
530 private ContentHandler outputHandler;
531
532 TransformerHandlerFactory(
533 final SAXTransformerFactory saxtf,
534 final Templates templates,
535 final ContentHandler outputHandler) {
536 this.saxtf = saxtf;
537 this.templates = templates;
538 this.outputHandler = outputHandler;
539 }
540
541 public final ContentHandler createContentHandler() {
542 try {
543 TransformerHandler handler = saxtf.newTransformerHandler(templates);
544 handler.setResult(new SAXResult(outputHandler));
545 return handler;
546 } catch (TransformerConfigurationException ex) {
547 throw new RuntimeException(ex.toString());
548 }
549 }
550 }
551
552 /** SubdocumentHandlerFactory */
553 private static final class SubdocumentHandlerFactory implements ContentHandlerFactory {
554 private final ContentHandler subdocumentHandler;
555
556 SubdocumentHandlerFactory(final ContentHandler subdocumentHandler) {
557 this.subdocumentHandler = subdocumentHandler;
558 }
559
560 public final ContentHandler createContentHandler() {
561 return subdocumentHandler;
562 }
563 }
564
565 /**
566 * A {@link ContentHandler} and {@link LexicalHandler } that serializes XML from SAX 2.0 events
567 * into {@link Writer}.
568 *
569 * <p><i>This implementation does not support namespaces, entity definitions (uncluding DTD),
570 * CDATA and </i>
571 */
572 private static final class SAXWriter extends DefaultHandler implements LexicalHandler {
573 private static final char[] OFF =
574 " "
575 .toCharArray();
576
577 private Writer w;
578
579 private final boolean optimizeEmptyElements;
580
581 private boolean openElement = false;
582
583 private int ident = 0;
584
585 /**
586 * Constructs <code>SAXWriter</code>.
587 *
588 * @param w writer
589 * @param optimizeEmptyElements if set to <code>true</code>, short XML syntax will be used for
590 * empty elements
591 */
592 SAXWriter(final Writer w, final boolean optimizeEmptyElements) {
593 this.w = w;
594 this.optimizeEmptyElements = optimizeEmptyElements;
595 }
596
597 @Override
598 public final void startElement(
599 final String ns, final String localName, final String qName, final Attributes atts)
600 throws SAXException {
601 try {
602 closeElement();
603
604 writeIdent();
605 w.write('<' + qName);
606 if (atts != null && atts.getLength() > 0) {
607 writeAttributes(atts);
157608 }
158609
159 // configuring outHandlerFactory
160 // ///////////////////////////////////////////////////////
161
162 EntryElement entryElement = getEntryElement(zos);
163
164 ContentHandler outDocHandler = null;
165 switch (outRepresentation) {
166 case BYTECODE:
167 outDocHandler = new OutputSlicingHandler(
168 new ASMContentHandlerFactory(zos), entryElement, false);
610 if (optimizeEmptyElements) {
611 openElement = true;
612 } else {
613 w.write(">\n");
614 }
615 ident += 2;
616
617 } catch (IOException ex) {
618 throw new SAXException(ex);
619 }
620 }
621
622 @Override
623 public final void endElement(final String ns, final String localName, final String qName)
624 throws SAXException {
625 ident -= 2;
626 try {
627 if (openElement) {
628 w.write("/>\n");
629 openElement = false;
630 } else {
631 writeIdent();
632 w.write("</" + qName + ">\n");
633 }
634
635 } catch (IOException ex) {
636 throw new SAXException(ex);
637 }
638 }
639
640 @Override
641 public final void endDocument() throws SAXException {
642 try {
643 w.flush();
644
645 } catch (IOException ex) {
646 throw new SAXException(ex);
647 }
648 }
649
650 public final void comment(final char[] ch, final int off, final int len) throws SAXException {
651 try {
652 closeElement();
653
654 writeIdent();
655 w.write("<!-- ");
656 w.write(ch, off, len);
657 w.write(" -->\n");
658
659 } catch (IOException ex) {
660 throw new SAXException(ex);
661 }
662 }
663
664 public final void startDTD(final String arg0, final String arg1, final String arg2)
665 throws SAXException {}
666
667 public final void endDTD() throws SAXException {}
668
669 public final void startEntity(final String arg0) throws SAXException {}
670
671 public final void endEntity(final String arg0) throws SAXException {}
672
673 public final void startCDATA() throws SAXException {}
674
675 public final void endCDATA() throws SAXException {}
676
677 private final void writeAttributes(final Attributes atts) throws IOException {
678 StringBuilder sb = new StringBuilder();
679 int len = atts.getLength();
680 for (int i = 0; i < len; i++) {
681 sb.append(' ')
682 .append(atts.getLocalName(i))
683 .append("=\"")
684 .append(esc(atts.getValue(i)))
685 .append('\"');
686 }
687 w.write(sb.toString());
688 }
689
690 /**
691 * Encode string with escaping.
692 *
693 * @param str string to encode.
694 * @return encoded string
695 */
696 private static final String esc(final String str) {
697 StringBuilder sb = new StringBuilder(str.length());
698 for (int i = 0; i < str.length(); i++) {
699 char ch = str.charAt(i);
700 switch (ch) {
701 case '&':
702 sb.append("&amp;");
169703 break;
170704
171 case MULTI_XML:
172 outDocHandler = new OutputSlicingHandler(new SAXWriterFactory(osw,
173 true), entryElement, true);
705 case '<':
706 sb.append("&lt;");
174707 break;
175708
176 case SINGLE_XML:
177 ZipEntry outputEntry = new ZipEntry(SINGLE_XML_NAME);
178 zos.putNextEntry(outputEntry);
179 outDocHandler = new SAXWriter(osw, false);
709 case '>':
710 sb.append("&gt;");
180711 break;
181712
182 }
183
184 // configuring inputDocHandlerFactory
185 // /////////////////////////////////////////////////
186 ContentHandler inDocHandler;
187 if (templates == null) {
188 inDocHandler = outDocHandler;
189 } else {
190 inDocHandler = new InputSlicingHandler("class", outDocHandler,
191 new TransformerHandlerFactory(saxtf, templates,
192 outDocHandler));
193 }
194 ContentHandlerFactory inDocHandlerFactory = new SubdocumentHandlerFactory(
195 inDocHandler);
196
197 if (inDocHandler != null && inRepresentation != SINGLE_XML) {
198 inDocHandler.startDocument();
199 inDocHandler.startElement("", "classes", "classes",
200 new AttributesImpl());
201 }
202
203 int i = 0;
204 ZipEntry ze;
205 while ((ze = zis.getNextEntry()) != null) {
206 update(ze.getName(), n++);
207 if (isClassEntry(ze)) {
208 processEntry(zis, ze, inDocHandlerFactory);
713 case '\"':
714 sb.append("&quot;");
715 break;
716
717 default:
718 if (ch > 0x7f) {
719 sb.append("&#").append(Integer.toString(ch)).append(';');
209720 } else {
210 OutputStream os = entryElement.openEntry(getName(ze));
211 copyEntry(zis, os);
212 entryElement.closeEntry();
213 }
214
215 i++;
216 }
217
218 if (inDocHandler != null && inRepresentation != SINGLE_XML) {
219 inDocHandler.endElement("", "classes", "classes");
220 inDocHandler.endDocument();
221 }
222
223 if (outRepresentation == SINGLE_XML) {
224 zos.closeEntry();
225 }
226 zos.flush();
227 zos.close();
228
229 return i;
230 }
231
232 private void copyEntry(final InputStream is, final OutputStream os)
233 throws IOException {
234 if (outRepresentation == SINGLE_XML) {
235 return;
236 }
237
238 byte[] buff = new byte[2048];
239 int i;
240 while ((i = is.read(buff)) != -1) {
241 os.write(buff, 0, i);
242 }
243 }
244
245 private boolean isClassEntry(final ZipEntry ze) {
246 String name = ze.getName();
247 return inRepresentation == SINGLE_XML && name.equals(SINGLE_XML_NAME)
248 || name.endsWith(".class") || name.endsWith(".class.xml");
249 }
250
251 private void processEntry(final ZipInputStream zis, final ZipEntry ze,
252 final ContentHandlerFactory handlerFactory) {
253 ContentHandler handler = handlerFactory.createContentHandler();
254 try {
255
256 // if (CODE2ASM.equals(command)) { // read bytecode and process it
257 // // with TraceClassVisitor
258 // ClassReader cr = new ClassReader(readEntry(zis, ze));
259 // cr.accept(new TraceClassVisitor(null, new PrintWriter(os)),
260 // false);
261 // }
262
263 boolean singleInputDocument = inRepresentation == SINGLE_XML;
264 if (inRepresentation == BYTECODE) { // read bytecode and process it
265 // with handler
266 ClassReader cr = new ClassReader(readEntry(zis, ze));
267 cr.accept(new SAXClassAdapter(handler, singleInputDocument), 0);
268
269 } else { // read XML and process it with handler
270 XMLReader reader = XMLReaderFactory.createXMLReader();
271 reader.setContentHandler(handler);
272 reader.parse(new InputSource(
273 singleInputDocument ? (InputStream) new ProtectedInputStream(
274 zis) : new ByteArrayInputStream(readEntry(zis,
275 ze))));
276
277 }
278 } catch (Exception ex) {
279 update(ze.getName(), 0);
280 update(ex, 0);
281 }
282 }
283
284 private EntryElement getEntryElement(final ZipOutputStream zos) {
285 if (outRepresentation == SINGLE_XML) {
286 return new SingleDocElement(zos);
287 }
288 return new ZipEntryElement(zos);
289 }
290
291 // private ContentHandlerFactory getHandlerFactory(
292 // OutputStream os,
293 // SAXTransformerFactory saxtf,
294 // Templates templates)
295 // {
296 // ContentHandlerFactory factory = null;
297 // if (templates == null) {
298 // if (outputRepresentation == BYTECODE) { // factory used to write
299 // // bytecode
300 // factory = new ASMContentHandlerFactory(os, computeMax);
301 // } else { // factory used to write XML
302 // factory = new SAXWriterFactory(os, true);
303 // }
304 // } else {
305 // if (outputRepresentation == BYTECODE) { // factory used to transform
306 // // and then write bytecode
307 // factory = new ASMTransformerHandlerFactory(saxtf,
308 // templates,
309 // os,
310 // computeMax);
311 // } else { // factory used to transformand then write XML
312 // factory = new TransformerHandlerFactory(saxtf,
313 // templates,
314 // os,
315 // outputRepresentation == SINGLE_XML);
316 // }
317 // }
318 // return factory;
319 // }
320
321 private String getName(final ZipEntry ze) {
322 String name = ze.getName();
323 if (isClassEntry(ze)) {
324 if (inRepresentation != BYTECODE && outRepresentation == BYTECODE) {
325 name = name.substring(0, name.length() - 4); // .class.xml to
326 // .class
327 } else if (inRepresentation == BYTECODE
328 && outRepresentation != BYTECODE) {
329 name += ".xml"; // .class to .class.xml
330 }
331 // } else if( CODE2ASM.equals( command)) {
332 // name = name.substring( 0, name.length()-6).concat( ".asm");
333 }
334 return name;
335 }
336
337 private static byte[] readEntry(final InputStream zis, final ZipEntry ze)
338 throws IOException {
339 long size = ze.getSize();
340 if (size > -1) {
341 byte[] buff = new byte[(int) size];
342 int k = 0;
343 int n;
344 while ((n = zis.read(buff, k, buff.length - k)) > 0) {
345 k += n;
346 }
347 return buff;
348 }
349
350 ByteArrayOutputStream bos = new ByteArrayOutputStream();
351 byte[] buff = new byte[4096];
352 int i;
353 while ((i = zis.read(buff)) != -1) {
354 bos.write(buff, 0, i);
355 }
356 return bos.toByteArray();
357 }
358
359 /*
360 * (non-Javadoc)
361 *
362 * @see java.util.Observer#update(java.util.Observable, java.lang.Object)
363 */
364 protected void update(final Object arg, final int n) {
365 if (arg instanceof Throwable) {
366 ((Throwable) arg).printStackTrace();
367 } else {
368 if (n % 100 == 0) {
369 System.err.println(n + " " + arg);
721 sb.append(ch);
370722 }
371723 }
372 }
373
374 public static void main(final String[] args) throws Exception {
375 if (args.length < 2) {
376 showUsage();
377 return;
724 }
725 return sb.toString();
726 }
727
728 private final void writeIdent() throws IOException {
729 int n = ident;
730 while (n > 0) {
731 if (n > OFF.length) {
732 w.write(OFF);
733 n -= OFF.length;
734 } else {
735 w.write(OFF, 0, n);
736 n = 0;
378737 }
379
380 int inRepresentation = getRepresentation(args[0]);
381 int outRepresentation = getRepresentation(args[1]);
382
383 InputStream is = System.in;
384 OutputStream os = new BufferedOutputStream(System.out);
385
386 Source xslt = null;
387 // boolean computeMax = true;
388
389 for (int i = 2; i < args.length; i++) {
390 if ("-in".equals(args[i])) {
391 is = new FileInputStream(args[++i]);
392
393 } else if ("-out".equals(args[i])) {
394 os = new BufferedOutputStream(new FileOutputStream(args[++i]));
395
396 } else if ("-xslt".equals(args[i])) {
397 xslt = new StreamSource(new FileInputStream(args[++i]));
398
399 // } else if( "-computemax".equals( args[ i].toLowerCase())) {
400 // computeMax = true;
401
402 } else {
403 showUsage();
404 return;
405
406 }
738 }
739 }
740
741 private final void closeElement() throws IOException {
742 if (openElement) {
743 w.write(">\n");
744 }
745 openElement = false;
746 }
747 }
748
749 /**
750 * A {@link ContentHandler} that splits XML documents into smaller chunks. Each chunk is processed
751 * by the nested {@link ContentHandler}. This is useful for running XSLT engine against large XML
752 * document that will hardly fit into the memory all together.
753 *
754 * <p>TODO use complete path for subdocumentRoot
755 */
756 private static final class InputSlicingHandler extends DefaultHandler {
757 private String subdocumentRoot;
758
759 private final ContentHandler rootHandler;
760
761 private ContentHandlerFactory subdocumentHandlerFactory;
762
763 private boolean subdocument = false;
764
765 private ContentHandler subdocumentHandler;
766
767 /**
768 * Constructs a new {@link InputSlicingHandler} object.
769 *
770 * @param subdocumentRoot name/path to the root element of the subdocument
771 * @param rootHandler content handler for the entire document (subdocument envelope).
772 * @param subdocumentHandlerFactory a {@link ContentHandlerFactory} used to create {@link
773 * ContentHandler} instances for subdocuments.
774 */
775 InputSlicingHandler(
776 final String subdocumentRoot,
777 final ContentHandler rootHandler,
778 final ContentHandlerFactory subdocumentHandlerFactory) {
779 this.subdocumentRoot = subdocumentRoot;
780 this.rootHandler = rootHandler;
781 this.subdocumentHandlerFactory = subdocumentHandlerFactory;
782 }
783
784 @Override
785 public final void startElement(
786 final String namespaceURI,
787 final String localName,
788 final String qName,
789 final Attributes list)
790 throws SAXException {
791 if (subdocument) {
792 subdocumentHandler.startElement(namespaceURI, localName, qName, list);
793 } else if (localName.equals(subdocumentRoot)) {
794 subdocumentHandler = subdocumentHandlerFactory.createContentHandler();
795 subdocumentHandler.startDocument();
796 subdocumentHandler.startElement(namespaceURI, localName, qName, list);
797 subdocument = true;
798 } else if (rootHandler != null) {
799 rootHandler.startElement(namespaceURI, localName, qName, list);
800 }
801 }
802
803 @Override
804 public final void endElement(
805 final String namespaceURI, final String localName, final String qName) throws SAXException {
806 if (subdocument) {
807 subdocumentHandler.endElement(namespaceURI, localName, qName);
808 if (localName.equals(subdocumentRoot)) {
809 subdocumentHandler.endDocument();
810 subdocument = false;
407811 }
408
409 if (inRepresentation == 0 || outRepresentation == 0) {
410 showUsage();
411 return;
812 } else if (rootHandler != null) {
813 rootHandler.endElement(namespaceURI, localName, qName);
814 }
815 }
816
817 @Override
818 public final void startDocument() throws SAXException {
819 if (rootHandler != null) {
820 rootHandler.startDocument();
821 }
822 }
823
824 @Override
825 public final void endDocument() throws SAXException {
826 if (rootHandler != null) {
827 rootHandler.endDocument();
828 }
829 }
830
831 @Override
832 public final void characters(final char[] buff, final int offset, final int size)
833 throws SAXException {
834 if (subdocument) {
835 subdocumentHandler.characters(buff, offset, size);
836 } else if (rootHandler != null) {
837 rootHandler.characters(buff, offset, size);
838 }
839 }
840 }
841
842 /**
843 * A {@link ContentHandler} that splits XML documents into smaller chunks. Each chunk is processed
844 * by the nested {@link ContentHandler} obtained from {@link ContentHandlerFactory}. This is
845 * useful for running XSLT engine against large XML document that will hardly fit into the memory
846 * all together.
847 *
848 * <p>TODO use complete path for subdocumentRoot
849 */
850 private static final class OutputSlicingHandler extends DefaultHandler {
851 private final String subdocumentRoot;
852
853 private ContentHandlerFactory subdocumentHandlerFactory;
854
855 private final EntryElement entryElement;
856
857 private boolean isXml;
858
859 private boolean subdocument = false;
860
861 private ContentHandler subdocumentHandler;
862
863 /**
864 * Constructs a new {@link OutputSlicingHandler} object.
865 *
866 * @param subdocumentHandlerFactory a {@link ContentHandlerFactory} used to create {@link
867 * ContentHandler} instances for subdocuments.
868 * @param entryElement TODO.
869 * @param isXml TODO.
870 */
871 OutputSlicingHandler(
872 final ContentHandlerFactory subdocumentHandlerFactory,
873 final EntryElement entryElement,
874 final boolean isXml) {
875 this.subdocumentRoot = "class";
876 this.subdocumentHandlerFactory = subdocumentHandlerFactory;
877 this.entryElement = entryElement;
878 this.isXml = isXml;
879 }
880
881 @Override
882 public final void startElement(
883 final String namespaceURI,
884 final String localName,
885 final String qName,
886 final Attributes list)
887 throws SAXException {
888 if (subdocument) {
889 subdocumentHandler.startElement(namespaceURI, localName, qName, list);
890 } else if (localName.equals(subdocumentRoot)) {
891 String name = list.getValue("name");
892 if (name == null || name.length() == 0) {
893 throw new SAXException("Class element without name attribute.");
412894 }
413
414 Processor m = new Processor(inRepresentation, outRepresentation, is,
415 os, xslt);
416
417 long l1 = System.currentTimeMillis();
418 int n = m.process();
419 long l2 = System.currentTimeMillis();
420 System.err.println(n);
421 System.err.println((l2 - l1) + "ms " + 1000f * n / (l2 - l1)
422 + " resources/sec");
423 }
424
425 private static int getRepresentation(final String s) {
426 if ("code".equals(s)) {
427 return BYTECODE;
428 } else if ("xml".equals(s)) {
429 return MULTI_XML;
430 } else if ("singlexml".equals(s)) {
431 return SINGLE_XML;
895 try {
896 entryElement.openEntry(isXml ? name + ".class.xml" : name + ".class");
897 } catch (IOException ex) {
898 throw new SAXException(ex.toString(), ex);
432899 }
433 return 0;
434 }
435
436 private static void showUsage() {
437 System.err
438 .println("Usage: Main <in format> <out format> [-in <input jar>] [-out <output jar>] [-xslt <xslt fiel>]");
439 System.err
440 .println(" when -in or -out is omitted sysin and sysout would be used");
441 System.err
442 .println(" <in format> and <out format> - code | xml | singlexml");
443 }
444
445 /**
446 * IputStream wrapper class used to protect input streams from being closed
447 * by some stupid XML parsers.
448 */
449 private static final class ProtectedInputStream extends InputStream {
450 private final InputStream is;
451
452 ProtectedInputStream(final InputStream is) {
453 this.is = is;
900 subdocumentHandler = subdocumentHandlerFactory.createContentHandler();
901 subdocumentHandler.startDocument();
902 subdocumentHandler.startElement(namespaceURI, localName, qName, list);
903 subdocument = true;
904 }
905 }
906
907 @Override
908 public final void endElement(
909 final String namespaceURI, final String localName, final String qName) throws SAXException {
910 if (subdocument) {
911 subdocumentHandler.endElement(namespaceURI, localName, qName);
912 if (localName.equals(subdocumentRoot)) {
913 subdocumentHandler.endDocument();
914 subdocument = false;
915 try {
916 entryElement.closeEntry();
917 } catch (IOException ex) {
918 throw new SAXException(ex.toString(), ex);
919 }
454920 }
455
456 @Override
457 public final void close() throws IOException {
458 }
459
460 @Override
461 public final int read() throws IOException {
462 return is.read();
463 }
464
465 @Override
466 public final int read(final byte[] b, final int off, final int len)
467 throws IOException {
468 return is.read(b, off, len);
469 }
470
471 @Override
472 public final int available() throws IOException {
473 return is.available();
474 }
475 }
476
477 /**
478 * A {@link ContentHandlerFactory ContentHandlerFactory} is used to create
479 * {@link org.xml.sax.ContentHandler ContentHandler} instances for concrete
480 * context.
481 */
482 private static interface ContentHandlerFactory {
483
484 /**
485 * Creates an instance of the content handler.
486 *
487 * @return content handler
488 */
489 ContentHandler createContentHandler();
490
491 }
492
493 /**
494 * SAXWriterFactory
495 */
496 private static final class SAXWriterFactory implements
497 ContentHandlerFactory {
498 private final Writer w;
499
500 private final boolean optimizeEmptyElements;
501
502 SAXWriterFactory(final Writer w, final boolean optimizeEmptyElements) {
503 this.w = w;
504 this.optimizeEmptyElements = optimizeEmptyElements;
505 }
506
507 public final ContentHandler createContentHandler() {
508 return new SAXWriter(w, optimizeEmptyElements);
509 }
510
511 }
512
513 /**
514 * ASMContentHandlerFactory
515 */
516 private static final class ASMContentHandlerFactory implements
517 ContentHandlerFactory {
518 final OutputStream os;
519
520 ASMContentHandlerFactory(final OutputStream os) {
521 this.os = os;
522 }
523
524 public final ContentHandler createContentHandler() {
525 final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
526 return new ASMContentHandler(cw) {
527 @Override
528 public void endDocument() throws SAXException {
529 try {
530 os.write(cw.toByteArray());
531 } catch (IOException e) {
532 throw new SAXException(e);
533 }
534 }
535 };
536 }
537
538 }
539
540 /**
541 * TransformerHandlerFactory
542 */
543 private static final class TransformerHandlerFactory implements
544 ContentHandlerFactory {
545 private SAXTransformerFactory saxtf;
546
547 private final Templates templates;
548
549 private ContentHandler outputHandler;
550
551 TransformerHandlerFactory(final SAXTransformerFactory saxtf,
552 final Templates templates, final ContentHandler outputHandler) {
553 this.saxtf = saxtf;
554 this.templates = templates;
555 this.outputHandler = outputHandler;
556 }
557
558 public final ContentHandler createContentHandler() {
559 try {
560 TransformerHandler handler = saxtf
561 .newTransformerHandler(templates);
562 handler.setResult(new SAXResult(outputHandler));
563 return handler;
564 } catch (TransformerConfigurationException ex) {
565 throw new RuntimeException(ex.toString());
566 }
567 }
568 }
569
570 /**
571 * SubdocumentHandlerFactory
572 */
573 private static final class SubdocumentHandlerFactory implements
574 ContentHandlerFactory {
575 private final ContentHandler subdocumentHandler;
576
577 SubdocumentHandlerFactory(final ContentHandler subdocumentHandler) {
578 this.subdocumentHandler = subdocumentHandler;
579 }
580
581 public final ContentHandler createContentHandler() {
582 return subdocumentHandler;
583 }
584
585 }
586
587 /**
588 * A {@link org.xml.sax.ContentHandler ContentHandler} and
589 * {@link org.xml.sax.ext.LexicalHandler LexicalHandler} that serializes XML
590 * from SAX 2.0 events into {@link java.io.Writer Writer}.
591 *
592 * <i><blockquote> This implementation does not support namespaces, entity
593 * definitions (uncluding DTD), CDATA and text elements. </blockquote></i>
594 */
595 private static final class SAXWriter extends DefaultHandler implements
596 LexicalHandler {
597 private static final char[] OFF = " "
598 .toCharArray();
599
600 private Writer w;
601
602 private final boolean optimizeEmptyElements;
603
604 private boolean openElement = false;
605
606 private int ident = 0;
607
608 /**
609 * Creates <code>SAXWriter</code>.
610 *
611 * @param w
612 * writer
613 * @param optimizeEmptyElements
614 * if set to <code>true</code>, short XML syntax will be used
615 * for empty elements
616 */
617 SAXWriter(final Writer w, final boolean optimizeEmptyElements) {
618 this.w = w;
619 this.optimizeEmptyElements = optimizeEmptyElements;
620 }
621
622 @Override
623 public final void startElement(final String ns, final String localName,
624 final String qName, final Attributes atts) throws SAXException {
625 try {
626 closeElement();
627
628 writeIdent();
629 w.write('<' + qName);
630 if (atts != null && atts.getLength() > 0) {
631 writeAttributes(atts);
632 }
633
634 if (optimizeEmptyElements) {
635 openElement = true;
636 } else {
637 w.write(">\n");
638 }
639 ident += 2;
640
641 } catch (IOException ex) {
642 throw new SAXException(ex);
643
644 }
645 }
646
647 @Override
648 public final void endElement(final String ns, final String localName,
649 final String qName) throws SAXException {
650 ident -= 2;
651 try {
652 if (openElement) {
653 w.write("/>\n");
654 openElement = false;
655 } else {
656 writeIdent();
657 w.write("</" + qName + ">\n");
658 }
659
660 } catch (IOException ex) {
661 throw new SAXException(ex);
662
663 }
664 }
665
666 @Override
667 public final void endDocument() throws SAXException {
668 try {
669 w.flush();
670
671 } catch (IOException ex) {
672 throw new SAXException(ex);
673
674 }
675 }
676
677 public final void comment(final char[] ch, final int off, final int len)
678 throws SAXException {
679 try {
680 closeElement();
681
682 writeIdent();
683 w.write("<!-- ");
684 w.write(ch, off, len);
685 w.write(" -->\n");
686
687 } catch (IOException ex) {
688 throw new SAXException(ex);
689
690 }
691 }
692
693 public final void startDTD(final String arg0, final String arg1,
694 final String arg2) throws SAXException {
695 }
696
697 public final void endDTD() throws SAXException {
698 }
699
700 public final void startEntity(final String arg0) throws SAXException {
701 }
702
703 public final void endEntity(final String arg0) throws SAXException {
704 }
705
706 public final void startCDATA() throws SAXException {
707 }
708
709 public final void endCDATA() throws SAXException {
710 }
711
712 private final void writeAttributes(final Attributes atts)
713 throws IOException {
714 StringBuilder sb = new StringBuilder();
715 int len = atts.getLength();
716 for (int i = 0; i < len; i++) {
717 sb.append(' ').append(atts.getLocalName(i)).append("=\"")
718 .append(esc(atts.getValue(i))).append('\"');
719 }
720 w.write(sb.toString());
721 }
722
723 /**
724 * Encode string with escaping.
725 *
726 * @param str
727 * string to encode.
728 * @return encoded string
729 */
730 private static final String esc(final String str) {
731 StringBuilder sb = new StringBuilder(str.length());
732 for (int i = 0; i < str.length(); i++) {
733 char ch = str.charAt(i);
734 switch (ch) {
735 case '&':
736 sb.append("&amp;");
737 break;
738
739 case '<':
740 sb.append("&lt;");
741 break;
742
743 case '>':
744 sb.append("&gt;");
745 break;
746
747 case '\"':
748 sb.append("&quot;");
749 break;
750
751 default:
752 if (ch > 0x7f) {
753 sb.append("&#").append(Integer.toString(ch))
754 .append(';');
755 } else {
756 sb.append(ch);
757 }
758
759 }
760 }
761 return sb.toString();
762 }
763
764 private final void writeIdent() throws IOException {
765 int n = ident;
766 while (n > 0) {
767 if (n > OFF.length) {
768 w.write(OFF);
769 n -= OFF.length;
770 } else {
771 w.write(OFF, 0, n);
772 n = 0;
773 }
774 }
775 }
776
777 private final void closeElement() throws IOException {
778 if (openElement) {
779 w.write(">\n");
780 }
781 openElement = false;
782 }
783
784 }
785
786 /**
787 * A {@link org.xml.sax.ContentHandler ContentHandler} that splits XML
788 * documents into smaller chunks. Each chunk is processed by the nested
789 * {@link org.xml.sax.ContentHandler ContentHandler} obtained from
790 * {@link java.net.ContentHandlerFactory ContentHandlerFactory}. This is
791 * useful for running XSLT engine against large XML document that will
792 * hardly fit into the memory all together.
793 * <p>
794 * TODO use complete path for subdocumentRoot
795 */
796 private static final class InputSlicingHandler extends DefaultHandler {
797 private String subdocumentRoot;
798
799 private final ContentHandler rootHandler;
800
801 private ContentHandlerFactory subdocumentHandlerFactory;
802
803 private boolean subdocument = false;
804
805 private ContentHandler subdocumentHandler;
806
807 /**
808 * Constructs a new {@link InputSlicingHandler SubdocumentHandler}
809 * object.
810 *
811 * @param subdocumentRoot
812 * name/path to the root element of the subdocument
813 * @param rootHandler
814 * content handler for the entire document (subdocument
815 * envelope).
816 * @param subdocumentHandlerFactory
817 * a {@link ContentHandlerFactory ContentHandlerFactory} used
818 * to create {@link ContentHandler ContentHandler} instances
819 * for subdocuments.
820 */
821 InputSlicingHandler(final String subdocumentRoot,
822 final ContentHandler rootHandler,
823 final ContentHandlerFactory subdocumentHandlerFactory) {
824 this.subdocumentRoot = subdocumentRoot;
825 this.rootHandler = rootHandler;
826 this.subdocumentHandlerFactory = subdocumentHandlerFactory;
827 }
828
829 @Override
830 public final void startElement(final String namespaceURI,
831 final String localName, final String qName,
832 final Attributes list) throws SAXException {
833 if (subdocument) {
834 subdocumentHandler.startElement(namespaceURI, localName, qName,
835 list);
836 } else if (localName.equals(subdocumentRoot)) {
837 subdocumentHandler = subdocumentHandlerFactory
838 .createContentHandler();
839 subdocumentHandler.startDocument();
840 subdocumentHandler.startElement(namespaceURI, localName, qName,
841 list);
842 subdocument = true;
843 } else if (rootHandler != null) {
844 rootHandler.startElement(namespaceURI, localName, qName, list);
845 }
846 }
847
848 @Override
849 public final void endElement(final String namespaceURI,
850 final String localName, final String qName) throws SAXException {
851 if (subdocument) {
852 subdocumentHandler.endElement(namespaceURI, localName, qName);
853 if (localName.equals(subdocumentRoot)) {
854 subdocumentHandler.endDocument();
855 subdocument = false;
856 }
857 } else if (rootHandler != null) {
858 rootHandler.endElement(namespaceURI, localName, qName);
859 }
860 }
861
862 @Override
863 public final void startDocument() throws SAXException {
864 if (rootHandler != null) {
865 rootHandler.startDocument();
866 }
867 }
868
869 @Override
870 public final void endDocument() throws SAXException {
871 if (rootHandler != null) {
872 rootHandler.endDocument();
873
874 }
875 }
876
877 @Override
878 public final void characters(final char[] buff, final int offset,
879 final int size) throws SAXException {
880 if (subdocument) {
881 subdocumentHandler.characters(buff, offset, size);
882 } else if (rootHandler != null) {
883 rootHandler.characters(buff, offset, size);
884 }
885 }
886
887 }
888
889 /**
890 * A {@link org.xml.sax.ContentHandler ContentHandler} that splits XML
891 * documents into smaller chunks. Each chunk is processed by the nested
892 * {@link org.xml.sax.ContentHandler ContentHandler} obtained from
893 * {@link java.net.ContentHandlerFactory ContentHandlerFactory}. This is
894 * useful for running XSLT engine against large XML document that will
895 * hardly fit into the memory all together.
896 *
897 * <p>
898 * TODO use complete path for subdocumentRoot
899 */
900 private static final class OutputSlicingHandler extends DefaultHandler {
901 private final String subdocumentRoot;
902
903 private ContentHandlerFactory subdocumentHandlerFactory;
904
905 private final EntryElement entryElement;
906
907 private boolean isXml;
908
909 private boolean subdocument = false;
910
911 private ContentHandler subdocumentHandler;
912
913 /**
914 * Constructs a new {@link OutputSlicingHandler SubdocumentHandler}
915 * object.
916 *
917 * @param subdocumentHandlerFactory
918 * a {@link ContentHandlerFactory ContentHandlerFactory} used
919 * to create {@link ContentHandler ContentHandler} instances
920 * for subdocuments.
921 * @param entryElement
922 * TODO.
923 * @param isXml
924 * TODO.
925 */
926 OutputSlicingHandler(
927 final ContentHandlerFactory subdocumentHandlerFactory,
928 final EntryElement entryElement, final boolean isXml) {
929 this.subdocumentRoot = "class";
930 this.subdocumentHandlerFactory = subdocumentHandlerFactory;
931 this.entryElement = entryElement;
932 this.isXml = isXml;
933 }
934
935 @Override
936 public final void startElement(final String namespaceURI,
937 final String localName, final String qName,
938 final Attributes list) throws SAXException {
939 if (subdocument) {
940 subdocumentHandler.startElement(namespaceURI, localName, qName,
941 list);
942 } else if (localName.equals(subdocumentRoot)) {
943 String name = list.getValue("name");
944 if (name == null || name.length() == 0) {
945 throw new SAXException(
946 "Class element without name attribute.");
947 }
948 try {
949 entryElement.openEntry(isXml ? name + ".class.xml" : name
950 + ".class");
951 } catch (IOException ex) {
952 throw new SAXException(ex.toString(), ex);
953 }
954 subdocumentHandler = subdocumentHandlerFactory
955 .createContentHandler();
956 subdocumentHandler.startDocument();
957 subdocumentHandler.startElement(namespaceURI, localName, qName,
958 list);
959 subdocument = true;
960 }
961 }
962
963 @Override
964 public final void endElement(final String namespaceURI,
965 final String localName, final String qName) throws SAXException {
966 if (subdocument) {
967 subdocumentHandler.endElement(namespaceURI, localName, qName);
968 if (localName.equals(subdocumentRoot)) {
969 subdocumentHandler.endDocument();
970 subdocument = false;
971 try {
972 entryElement.closeEntry();
973 } catch (IOException ex) {
974 throw new SAXException(ex.toString(), ex);
975 }
976 }
977 }
978 }
979
980 @Override
981 public final void startDocument() throws SAXException {
982 }
983
984 @Override
985 public final void endDocument() throws SAXException {
986 }
987
988 @Override
989 public final void characters(final char[] buff, final int offset,
990 final int size) throws SAXException {
991 if (subdocument) {
992 subdocumentHandler.characters(buff, offset, size);
993 }
994 }
995
996 }
997
998 private static interface EntryElement {
999
1000 OutputStream openEntry(String name) throws IOException;
1001
1002 void closeEntry() throws IOException;
1003
1004 }
1005
1006 private static final class SingleDocElement implements EntryElement {
1007 private final OutputStream os;
1008
1009 SingleDocElement(final OutputStream os) {
1010 this.os = os;
1011 }
1012
1013 public OutputStream openEntry(final String name) throws IOException {
1014 return os;
1015 }
1016
1017 public void closeEntry() throws IOException {
1018 os.flush();
1019 }
1020
1021 }
1022
1023 private static final class ZipEntryElement implements EntryElement {
1024 private ZipOutputStream zos;
1025
1026 ZipEntryElement(final ZipOutputStream zos) {
1027 this.zos = zos;
1028 }
1029
1030 public OutputStream openEntry(final String name) throws IOException {
1031 ZipEntry entry = new ZipEntry(name);
1032 zos.putNextEntry(entry);
1033 return zos;
1034 }
1035
1036 public void closeEntry() throws IOException {
1037 zos.flush();
1038 zos.closeEntry();
1039 }
1040
1041 }
1042
921 }
922 }
923
924 @Override
925 public final void startDocument() throws SAXException {}
926
927 @Override
928 public final void endDocument() throws SAXException {}
929
930 @Override
931 public final void characters(final char[] buff, final int offset, final int size)
932 throws SAXException {
933 if (subdocument) {
934 subdocumentHandler.characters(buff, offset, size);
935 }
936 }
937 }
938
939 private static interface EntryElement {
940
941 OutputStream openEntry(String name) throws IOException;
942
943 void closeEntry() throws IOException;
944 }
945
946 private static final class SingleDocElement implements EntryElement {
947 private final OutputStream os;
948
949 SingleDocElement(final OutputStream os) {
950 this.os = os;
951 }
952
953 public OutputStream openEntry(final String name) throws IOException {
954 return os;
955 }
956
957 public void closeEntry() throws IOException {
958 os.flush();
959 }
960 }
961
962 private static final class ZipEntryElement implements EntryElement {
963 private ZipOutputStream zos;
964
965 ZipEntryElement(final ZipOutputStream zos) {
966 this.zos = zos;
967 }
968
969 public OutputStream openEntry(final String name) throws IOException {
970 ZipEntry entry = new ZipEntry(name);
971 zos.putNextEntry(entry);
972 return zos;
973 }
974
975 public void closeEntry() throws IOException {
976 zos.flush();
977 zos.closeEntry();
978 }
979 }
1043980 }
0 /***
1 * ASM XML Adapter
2 * Copyright (c) 2004-2011, Eugene Kuleshov
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.xml;
3028
3129 import org.xml.sax.Attributes;
3432
3533 /**
3634 * SAXAdapter
37 *
35 *
36 * @deprecated This class is no longer maintained, will not support new Java features, and will
37 * eventually be deleted. Use the asm or asm.tree API instead.
3838 * @author Eugene Kuleshov
3939 */
40 @Deprecated
4041 public class SAXAdapter {
4142
42 private final ContentHandler h;
43 private final ContentHandler h;
4344
44 protected SAXAdapter(final ContentHandler h) {
45 this.h = h;
45 protected SAXAdapter(final ContentHandler h) {
46 this.h = h;
47 }
48
49 protected ContentHandler getContentHandler() {
50 return h;
51 }
52
53 protected void addDocumentStart() {
54 try {
55 h.startDocument();
56 } catch (SAXException ex) {
57 throw new RuntimeException(ex.getMessage(), ex.getException());
4658 }
59 }
4760
48 protected ContentHandler getContentHandler() {
49 return h;
61 protected void addDocumentEnd() {
62 try {
63 h.endDocument();
64 } catch (SAXException ex) {
65 throw new RuntimeException(ex.getMessage(), ex.getException());
5066 }
67 }
5168
52 protected void addDocumentStart() {
53 try {
54 h.startDocument();
55 } catch (SAXException ex) {
56 throw new RuntimeException(ex.getMessage(), ex.getException());
57 }
69 protected final void addStart(final String name, final Attributes attrs) {
70 try {
71 h.startElement("", name, name, attrs);
72 } catch (SAXException ex) {
73 throw new RuntimeException(ex.getMessage(), ex.getException());
5874 }
75 }
5976
60 protected void addDocumentEnd() {
61 try {
62 h.endDocument();
63 } catch (SAXException ex) {
64 throw new RuntimeException(ex.getMessage(), ex.getException());
65 }
77 protected final void addEnd(final String name) {
78 try {
79 h.endElement("", name, name);
80 } catch (SAXException ex) {
81 throw new RuntimeException(ex.getMessage(), ex.getException());
6682 }
83 }
6784
68 protected final void addStart(final String name, final Attributes attrs) {
69 try {
70 h.startElement("", name, name, attrs);
71 } catch (SAXException ex) {
72 throw new RuntimeException(ex.getMessage(), ex.getException());
73 }
74 }
75
76 protected final void addEnd(final String name) {
77 try {
78 h.endElement("", name, name);
79 } catch (SAXException ex) {
80 throw new RuntimeException(ex.getMessage(), ex.getException());
81 }
82 }
83
84 protected final void addElement(final String name, final Attributes attrs) {
85 addStart(name, attrs);
86 addEnd(name);
87 }
85 protected final void addElement(final String name, final Attributes attrs) {
86 addStart(name, attrs);
87 addEnd(name);
88 }
8889 }
0 /***
1 * ASM XML Adapter
2 * Copyright (c) 2004-2011, Eugene Kuleshov
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.xml;
3028
3129 import org.eclipse.persistence.internal.libraries.asm.AnnotationVisitor;
3634
3735 /**
3836 * SAXAnnotationAdapter
39 *
37 *
38 * @deprecated This class is no longer maintained, will not support new Java features, and will
39 * eventually be deleted. Use the asm or asm.tree API instead.
4040 * @author Eugene Kuleshov
4141 */
42 @Deprecated
4243 public final class SAXAnnotationAdapter extends AnnotationVisitor {
4344
44 SAXAdapter sa;
45
46 private final String elementName;
47
48 public SAXAnnotationAdapter(final SAXAdapter sa, final String elementName,
49 final int visible, final String name, final String desc) {
50 this(Opcodes.ASM6, sa, elementName, visible, desc, name, -1, -1, null,
51 null, null, null);
52 }
53
54 public SAXAnnotationAdapter(final SAXAdapter sa, final String elementName,
55 final int visible, final int parameter, final String desc) {
56 this(Opcodes.ASM6, sa, elementName, visible, desc, null, parameter, -1,
57 null, null, null, null);
58 }
59
60 public SAXAnnotationAdapter(final SAXAdapter sa, final String elementName,
61 final int visible, final String name, final String desc,
62 final int typeRef, final TypePath typePath) {
63 this(Opcodes.ASM6, sa, elementName, visible, desc, name, -1, typeRef,
64 typePath, null, null, null);
65 }
66
67 public SAXAnnotationAdapter(final SAXAdapter sa, final String elementName,
68 final int visible, final String name, final String desc,
69 int typeRef, TypePath typePath, final String[] start,
70 final String[] end, final int[] index) {
71 this(Opcodes.ASM6, sa, elementName, visible, desc, name, -1, typeRef,
72 typePath, start, end, index);
73 }
74
75 protected SAXAnnotationAdapter(final int api, final SAXAdapter sa,
76 final String elementName, final int visible, final String desc,
77 final String name, final int parameter) {
78 this(api, sa, elementName, visible, desc, name, parameter, -1, null,
79 null, null, null);
80 }
81
82 protected SAXAnnotationAdapter(final int api, final SAXAdapter sa,
83 final String elementName, final int visible, final String desc,
84 final String name, final int parameter, final int typeRef,
85 final TypePath typePath, final String[] start, final String[] end,
86 final int[] index) {
87 super(api);
88 this.sa = sa;
89 this.elementName = elementName;
90
91 AttributesImpl att = new AttributesImpl();
92 if (name != null) {
93 att.addAttribute("", "name", "name", "", name);
94 }
95 if (visible != 0) {
96 att.addAttribute("", "visible", "visible", "", visible > 0 ? "true"
97 : "false");
98 }
99 if (parameter != -1) {
100 att.addAttribute("", "parameter", "parameter", "",
101 Integer.toString(parameter));
102 }
103 if (desc != null) {
104 att.addAttribute("", "desc", "desc", "", desc);
105 }
106 if (typeRef != -1) {
107 att.addAttribute("", "typeRef", "typeRef", "",
108 Integer.toString(typeRef));
109 }
110 if (typePath != null) {
111 att.addAttribute("", "typePath", "typePath", "",
112 typePath.toString());
113 }
114 if (start != null) {
115 StringBuilder value = new StringBuilder(start[0]);
116 for (int i = 1; i < start.length; ++i) {
117 value.append(" ").append(start[i]);
118 }
119 att.addAttribute("", "start", "start", "", value.toString());
120 }
121 if (end != null) {
122 StringBuilder value = new StringBuilder(end[0]);
123 for (int i = 1; i < end.length; ++i) {
124 value.append(" ").append(end[i]);
125 }
126 att.addAttribute("", "end", "end", "", value.toString());
127 }
128 if (index != null) {
129 StringBuilder value = new StringBuilder();
130 value.append(index[0]);
131 for (int i = 1; i < index.length; ++i) {
132 value.append(" ").append(index[i]);
133 }
134 att.addAttribute("", "index", "index", "", value.toString());
135 }
136
137 sa.addStart(elementName, att);
138 }
139
140 @Override
141 public void visit(final String name, final Object value) {
142 Class<?> c = value.getClass();
143 if (c.isArray()) {
144 AnnotationVisitor av = visitArray(name);
145 if (value instanceof byte[]) {
146 byte[] b = (byte[]) value;
147 for (int i = 0; i < b.length; i++) {
148 av.visit(null, b[i]);
149 }
150
151 } else if (value instanceof char[]) {
152 char[] b = (char[]) value;
153 for (int i = 0; i < b.length; i++) {
154 av.visit(null, b[i]);
155 }
156
157 } else if (value instanceof short[]) {
158 short[] b = (short[]) value;
159 for (int i = 0; i < b.length; i++) {
160 av.visit(null, b[i]);
161 }
162
163 } else if (value instanceof boolean[]) {
164 boolean[] b = (boolean[]) value;
165 for (int i = 0; i < b.length; i++) {
166 av.visit(null, Boolean.valueOf(b[i]));
167 }
168
169 } else if (value instanceof int[]) {
170 int[] b = (int[]) value;
171 for (int i = 0; i < b.length; i++) {
172 av.visit(null, b[i]);
173 }
174
175 } else if (value instanceof long[]) {
176 long[] b = (long[]) value;
177 for (int i = 0; i < b.length; i++) {
178 av.visit(null, b[i]);
179 }
180
181 } else if (value instanceof float[]) {
182 float[] b = (float[]) value;
183 for (int i = 0; i < b.length; i++) {
184 av.visit(null, b[i]);
185 }
186
187 } else if (value instanceof double[]) {
188 double[] b = (double[]) value;
189 for (int i = 0; i < b.length; i++) {
190 av.visit(null, b[i]);
191 }
192
193 }
194 av.visitEnd();
195 } else {
196 addValueElement("annotationValue", name, Type.getDescriptor(c),
197 value.toString());
198 }
199 }
200
201 @Override
202 public void visitEnum(final String name, final String desc,
203 final String value) {
204 addValueElement("annotationValueEnum", name, desc, value);
205 }
206
207 @Override
208 public AnnotationVisitor visitAnnotation(final String name,
209 final String desc) {
210 return new SAXAnnotationAdapter(sa, "annotationValueAnnotation", 0,
211 name, desc);
212 }
213
214 @Override
215 public AnnotationVisitor visitArray(final String name) {
216 return new SAXAnnotationAdapter(sa, "annotationValueArray", 0, name,
217 null);
218 }
219
220 @Override
221 public void visitEnd() {
222 sa.addEnd(elementName);
223 }
224
225 private void addValueElement(final String element, final String name,
226 final String desc, final String value) {
227 AttributesImpl att = new AttributesImpl();
228 if (name != null) {
229 att.addAttribute("", "name", "name", "", name);
230 }
231 if (desc != null) {
232 att.addAttribute("", "desc", "desc", "", desc);
233 }
234 if (value != null) {
235 att.addAttribute("", "value", "value", "",
236 SAXClassAdapter.encode(value));
237 }
238
239 sa.addElement(element, att);
240 }
45 SAXAdapter sa;
46
47 private final String elementName;
48
49 public SAXAnnotationAdapter(
50 final SAXAdapter sa,
51 final String elementName,
52 final int visible,
53 final String name,
54 final String desc) {
55 this(Opcodes.ASM6, sa, elementName, visible, desc, name, -1, -1, null, null, null, null);
56 }
57
58 public SAXAnnotationAdapter(
59 final SAXAdapter sa,
60 final String elementName,
61 final int visible,
62 final int parameter,
63 final String desc) {
64 this(Opcodes.ASM6, sa, elementName, visible, desc, null, parameter, -1, null, null, null, null);
65 }
66
67 public SAXAnnotationAdapter(
68 final SAXAdapter sa,
69 final String elementName,
70 final int visible,
71 final String name,
72 final String desc,
73 final int typeRef,
74 final TypePath typePath) {
75 this(
76 Opcodes.ASM6,
77 sa,
78 elementName,
79 visible,
80 desc,
81 name,
82 -1,
83 typeRef,
84 typePath,
85 null,
86 null,
87 null);
88 }
89
90 public SAXAnnotationAdapter(
91 final SAXAdapter sa,
92 final String elementName,
93 final int visible,
94 final String name,
95 final String desc,
96 int typeRef,
97 TypePath typePath,
98 final String[] start,
99 final String[] end,
100 final int[] index) {
101 this(
102 Opcodes.ASM6,
103 sa,
104 elementName,
105 visible,
106 desc,
107 name,
108 -1,
109 typeRef,
110 typePath,
111 start,
112 end,
113 index);
114 }
115
116 protected SAXAnnotationAdapter(
117 final int api,
118 final SAXAdapter sa,
119 final String elementName,
120 final int visible,
121 final String desc,
122 final String name,
123 final int parameter) {
124 this(api, sa, elementName, visible, desc, name, parameter, -1, null, null, null, null);
125 }
126
127 protected SAXAnnotationAdapter(
128 final int api,
129 final SAXAdapter sa,
130 final String elementName,
131 final int visible,
132 final String desc,
133 final String name,
134 final int parameter,
135 final int typeRef,
136 final TypePath typePath,
137 final String[] start,
138 final String[] end,
139 final int[] index) {
140 super(api);
141 this.sa = sa;
142 this.elementName = elementName;
143
144 AttributesImpl att = new AttributesImpl();
145 if (name != null) {
146 att.addAttribute("", "name", "name", "", name);
147 }
148 if (visible != 0) {
149 att.addAttribute("", "visible", "visible", "", visible > 0 ? "true" : "false");
150 }
151 if (parameter != -1) {
152 att.addAttribute("", "parameter", "parameter", "", Integer.toString(parameter));
153 }
154 if (desc != null) {
155 att.addAttribute("", "desc", "desc", "", desc);
156 }
157 if (typeRef != -1) {
158 att.addAttribute("", "typeRef", "typeRef", "", Integer.toString(typeRef));
159 }
160 if (typePath != null) {
161 att.addAttribute("", "typePath", "typePath", "", typePath.toString());
162 }
163 if (start != null) {
164 StringBuilder value = new StringBuilder(start[0]);
165 for (int i = 1; i < start.length; ++i) {
166 value.append(" ").append(start[i]);
167 }
168 att.addAttribute("", "start", "start", "", value.toString());
169 }
170 if (end != null) {
171 StringBuilder value = new StringBuilder(end[0]);
172 for (int i = 1; i < end.length; ++i) {
173 value.append(" ").append(end[i]);
174 }
175 att.addAttribute("", "end", "end", "", value.toString());
176 }
177 if (index != null) {
178 StringBuilder value = new StringBuilder();
179 value.append(index[0]);
180 for (int i = 1; i < index.length; ++i) {
181 value.append(" ").append(index[i]);
182 }
183 att.addAttribute("", "index", "index", "", value.toString());
184 }
185
186 sa.addStart(elementName, att);
187 }
188
189 @Override
190 public void visit(final String name, final Object value) {
191 Class<?> c = value.getClass();
192 if (c.isArray()) {
193 AnnotationVisitor av = visitArray(name);
194 if (value instanceof byte[]) {
195 byte[] b = (byte[]) value;
196 for (int i = 0; i < b.length; i++) {
197 av.visit(null, b[i]);
198 }
199
200 } else if (value instanceof char[]) {
201 char[] b = (char[]) value;
202 for (int i = 0; i < b.length; i++) {
203 av.visit(null, b[i]);
204 }
205
206 } else if (value instanceof short[]) {
207 short[] b = (short[]) value;
208 for (int i = 0; i < b.length; i++) {
209 av.visit(null, b[i]);
210 }
211
212 } else if (value instanceof boolean[]) {
213 boolean[] b = (boolean[]) value;
214 for (int i = 0; i < b.length; i++) {
215 av.visit(null, Boolean.valueOf(b[i]));
216 }
217
218 } else if (value instanceof int[]) {
219 int[] b = (int[]) value;
220 for (int i = 0; i < b.length; i++) {
221 av.visit(null, b[i]);
222 }
223
224 } else if (value instanceof long[]) {
225 long[] b = (long[]) value;
226 for (int i = 0; i < b.length; i++) {
227 av.visit(null, b[i]);
228 }
229
230 } else if (value instanceof float[]) {
231 float[] b = (float[]) value;
232 for (int i = 0; i < b.length; i++) {
233 av.visit(null, b[i]);
234 }
235
236 } else if (value instanceof double[]) {
237 double[] b = (double[]) value;
238 for (int i = 0; i < b.length; i++) {
239 av.visit(null, b[i]);
240 }
241 }
242 av.visitEnd();
243 } else {
244 addValueElement("annotationValue", name, Type.getDescriptor(c), value.toString());
245 }
246 }
247
248 @Override
249 public void visitEnum(final String name, final String desc, final String value) {
250 addValueElement("annotationValueEnum", name, desc, value);
251 }
252
253 @Override
254 public AnnotationVisitor visitAnnotation(final String name, final String desc) {
255 return new SAXAnnotationAdapter(sa, "annotationValueAnnotation", 0, name, desc);
256 }
257
258 @Override
259 public AnnotationVisitor visitArray(final String name) {
260 return new SAXAnnotationAdapter(sa, "annotationValueArray", 0, name, null);
261 }
262
263 @Override
264 public void visitEnd() {
265 sa.addEnd(elementName);
266 }
267
268 private void addValueElement(
269 final String element, final String name, final String desc, final String value) {
270 AttributesImpl att = new AttributesImpl();
271 if (name != null) {
272 att.addAttribute("", "name", "name", "", name);
273 }
274 if (desc != null) {
275 att.addAttribute("", "desc", "desc", "", desc);
276 }
277 if (value != null) {
278 att.addAttribute("", "value", "value", "", SAXClassAdapter.encode(value));
279 }
280
281 sa.addElement(element, att);
282 }
241283 }
0 /***
1 * ASM XML Adapter
2 * Copyright (c) 2004-2011, Eugene Kuleshov
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.xml;
3028
3129 import org.eclipse.persistence.internal.libraries.asm.AnnotationVisitor;
3937 import org.xml.sax.helpers.AttributesImpl;
4038
4139 /**
42 * A {@link org.eclipse.persistence.internal.libraries.asm.ClassVisitor ClassVisitor} that generates SAX 2.0
43 * events from the visited class. It can feed any kind of
44 * {@link org.xml.sax.ContentHandler ContentHandler}, e.g. XML serializer, XSLT
45 * or XQuery engines.
46 *
40 * A {@link org.eclipse.persistence.internal.libraries.asm.ClassVisitor ClassVisitor} that generates SAX 2.0 events from the
41 * visited class. It can feed any kind of {@link org.xml.sax.ContentHandler ContentHandler}, e.g.
42 * XML serializer, XSLT or XQuery engines.
43 *
44 * @deprecated This class is no longer maintained, will not support new Java features, and will
45 * eventually be deleted. Use the asm or asm.tree API instead.
4746 * @see org.eclipse.persistence.internal.libraries.asm.xml.Processor
4847 * @see org.eclipse.persistence.internal.libraries.asm.xml.ASMContentHandler
49 *
5048 * @author Eugene Kuleshov
5149 */
50 @Deprecated
5251 public final class SAXClassAdapter extends ClassVisitor {
5352
54 SAXAdapter sa;
55
56 private final boolean singleDocument;
57
58 /**
59 * Pseudo access flag used to distinguish class access flags.
60 */
61 private static final int ACCESS_CLASS = 262144;
62
63 /**
64 * Pseudo access flag used to distinguish field access flags.
65 */
66 private static final int ACCESS_FIELD = 524288;
67
68 /**
69 * Pseudo access flag used to distinguish inner class flags.
70 */
71 private static final int ACCESS_INNER = 1048576;
72
73 /**
74 * Constructs a new {@link SAXClassAdapter SAXClassAdapter} object.
75 *
76 * @param h
77 * content handler that will be used to send SAX 2.0 events.
78 * @param singleDocument
79 * if <tt>true</tt> adapter will not produce
80 * {@link ContentHandler#startDocument() startDocument()} and
81 * {@link ContentHandler#endDocument() endDocument()} events.
82 */
83 public SAXClassAdapter(final ContentHandler h, boolean singleDocument) {
84 super(Opcodes.ASM6);
85 this.sa = new SAXAdapter(h);
86 this.singleDocument = singleDocument;
87 if (!singleDocument) {
88 sa.addDocumentStart();
53 SAXAdapter sa;
54
55 private final boolean singleDocument;
56
57 /** Pseudo access flag used to distinguish class access flags. */
58 private static final int ACCESS_CLASS = 262144;
59
60 /** Pseudo access flag used to distinguish field access flags. */
61 private static final int ACCESS_FIELD = 524288;
62
63 /** Pseudo access flag used to distinguish inner class flags. */
64 private static final int ACCESS_INNER = 1048576;
65
66 /** Pseudo access flag used to distinguish module flags. */
67 static final int ACCESS_MODULE = 2097152;
68
69 /** Pseudo access flag used to distinguish module requires flags. */
70 static final int ACCESS_MODULE_REQUIRES = 4194304;
71
72 /**
73 * Constructs a new {@link SAXClassAdapter SAXClassAdapter} object.
74 *
75 * @param h content handler that will be used to send SAX 2.0 events.
76 * @param singleDocument if <tt>true</tt> adapter will not produce {@link
77 * ContentHandler#startDocument() startDocument()} and {@link ContentHandler#endDocument()
78 * endDocument()} events.
79 */
80 public SAXClassAdapter(final ContentHandler h, boolean singleDocument) {
81 super(Opcodes.ASM6);
82 this.sa = new SAXAdapter(h);
83 this.singleDocument = singleDocument;
84 if (!singleDocument) {
85 sa.addDocumentStart();
86 }
87 }
88
89 @Override
90 public void visitSource(final String source, final String debug) {
91 AttributesImpl att = new AttributesImpl();
92 if (source != null) {
93 att.addAttribute("", "file", "file", "", encode(source));
94 }
95 if (debug != null) {
96 att.addAttribute("", "debug", "debug", "", encode(debug));
97 }
98
99 sa.addElement("source", att);
100 }
101
102 @Override
103 public ModuleVisitor visitModule(final String name, final int access, final String version) {
104 AttributesImpl att = new AttributesImpl();
105 att.addAttribute("", "name", "name", "", name);
106 StringBuilder sb = new StringBuilder();
107 appendAccess(access | ACCESS_MODULE, sb);
108 att.addAttribute("", "access", "access", "", sb.toString());
109 if (version != null) {
110 att.addAttribute("", "version", "version", "", encode(version));
111 }
112 sa.addStart("module", att);
113 return new SAXModuleAdapter(sa);
114 }
115
116 @Override
117 public void visitOuterClass(final String owner, final String name, final String desc) {
118 AttributesImpl att = new AttributesImpl();
119 att.addAttribute("", "owner", "owner", "", owner);
120 if (name != null) {
121 att.addAttribute("", "name", "name", "", name);
122 }
123 if (desc != null) {
124 att.addAttribute("", "desc", "desc", "", desc);
125 }
126
127 sa.addElement("outerclass", att);
128 }
129
130 @Override
131 public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) {
132 return new SAXAnnotationAdapter(sa, "annotation", visible ? 1 : -1, null, desc);
133 }
134
135 @Override
136 public AnnotationVisitor visitTypeAnnotation(
137 int typeRef, TypePath typePath, String desc, boolean visible) {
138 return new SAXAnnotationAdapter(
139 sa, "typeAnnotation", visible ? 1 : -1, null, desc, typeRef, typePath);
140 }
141
142 @Override
143 public void visit(
144 final int version,
145 final int access,
146 final String name,
147 final String signature,
148 final String superName,
149 final String[] interfaces) {
150 StringBuilder sb = new StringBuilder();
151 appendAccess(access | ACCESS_CLASS, sb);
152
153 AttributesImpl att = new AttributesImpl();
154 att.addAttribute("", "access", "access", "", sb.toString());
155 if (name != null) {
156 att.addAttribute("", "name", "name", "", name);
157 }
158 if (signature != null) {
159 att.addAttribute("", "signature", "signature", "", encode(signature));
160 }
161 if (superName != null) {
162 att.addAttribute("", "parent", "parent", "", superName);
163 }
164 att.addAttribute("", "major", "major", "", Integer.toString(version & 0xFFFF));
165 att.addAttribute("", "minor", "minor", "", Integer.toString(version >>> 16));
166 sa.addStart("class", att);
167
168 sa.addStart("interfaces", new AttributesImpl());
169 if (interfaces != null && interfaces.length > 0) {
170 for (int i = 0; i < interfaces.length; i++) {
171 AttributesImpl att2 = new AttributesImpl();
172 att2.addAttribute("", "name", "name", "", interfaces[i]);
173 sa.addElement("interface", att2);
174 }
175 }
176 sa.addEnd("interfaces");
177 }
178
179 @Override
180 public FieldVisitor visitField(
181 final int access,
182 final String name,
183 final String desc,
184 final String signature,
185 final Object value) {
186 StringBuilder sb = new StringBuilder();
187 appendAccess(access | ACCESS_FIELD, sb);
188
189 AttributesImpl att = new AttributesImpl();
190 att.addAttribute("", "access", "access", "", sb.toString());
191 att.addAttribute("", "name", "name", "", name);
192 att.addAttribute("", "desc", "desc", "", desc);
193 if (signature != null) {
194 att.addAttribute("", "signature", "signature", "", encode(signature));
195 }
196 if (value != null) {
197 att.addAttribute("", "value", "value", "", encode(value.toString()));
198 }
199
200 return new SAXFieldAdapter(sa, att);
201 }
202
203 @Override
204 public MethodVisitor visitMethod(
205 final int access,
206 final String name,
207 final String desc,
208 final String signature,
209 final String[] exceptions) {
210 StringBuilder sb = new StringBuilder();
211 appendAccess(access, sb);
212
213 AttributesImpl att = new AttributesImpl();
214 att.addAttribute("", "access", "access", "", sb.toString());
215 att.addAttribute("", "name", "name", "", name);
216 att.addAttribute("", "desc", "desc", "", desc);
217 if (signature != null) {
218 att.addAttribute("", "signature", "signature", "", signature);
219 }
220 sa.addStart("method", att);
221
222 sa.addStart("exceptions", new AttributesImpl());
223 if (exceptions != null && exceptions.length > 0) {
224 for (int i = 0; i < exceptions.length; i++) {
225 AttributesImpl att2 = new AttributesImpl();
226 att2.addAttribute("", "name", "name", "", exceptions[i]);
227 sa.addElement("exception", att2);
228 }
229 }
230 sa.addEnd("exceptions");
231
232 return new SAXCodeAdapter(sa, access);
233 }
234
235 @Override
236 public final void visitInnerClass(
237 final String name, final String outerName, final String innerName, final int access) {
238 StringBuilder sb = new StringBuilder();
239 appendAccess(access | ACCESS_INNER, sb);
240
241 AttributesImpl att = new AttributesImpl();
242 att.addAttribute("", "access", "access", "", sb.toString());
243 if (name != null) {
244 att.addAttribute("", "name", "name", "", name);
245 }
246 if (outerName != null) {
247 att.addAttribute("", "outerName", "outerName", "", outerName);
248 }
249 if (innerName != null) {
250 att.addAttribute("", "innerName", "innerName", "", innerName);
251 }
252 sa.addElement("innerclass", att);
253 }
254
255 @Override
256 public final void visitEnd() {
257 sa.addEnd("class");
258 if (!singleDocument) {
259 sa.addDocumentEnd();
260 }
261 }
262
263 static final String encode(final String s) {
264 StringBuilder sb = new StringBuilder();
265 for (int i = 0; i < s.length(); i++) {
266 char c = s.charAt(i);
267 if (c == '\\') {
268 sb.append("\\\\");
269 } else if (c < 0x20 || c > 0x7f) {
270 sb.append("\\u");
271 if (c < 0x10) {
272 sb.append("000");
273 } else if (c < 0x100) {
274 sb.append("00");
275 } else if (c < 0x1000) {
276 sb.append('0');
89277 }
90 }
91
92 @Override
93 public void visitSource(final String source, final String debug) {
94 AttributesImpl att = new AttributesImpl();
95 if (source != null) {
96 att.addAttribute("", "file", "file", "", encode(source));
278 sb.append(Integer.toString(c, 16));
279 } else {
280 sb.append(c);
281 }
282 }
283 return sb.toString();
284 }
285
286 static void appendAccess(final int access, final StringBuilder sb) {
287 if ((access & Opcodes.ACC_PUBLIC) != 0) {
288 sb.append("public ");
289 }
290 if ((access & Opcodes.ACC_PRIVATE) != 0) {
291 sb.append("private ");
292 }
293 if ((access & Opcodes.ACC_PROTECTED) != 0) {
294 sb.append("protected ");
295 }
296 if ((access & Opcodes.ACC_FINAL) != 0) {
297 if ((access & ACCESS_MODULE) == 0) {
298 sb.append("final ");
299 } else {
300 sb.append("transitive ");
301 }
302 }
303 if ((access & Opcodes.ACC_STATIC) != 0) {
304 sb.append("static ");
305 }
306 if ((access & Opcodes.ACC_SUPER) != 0) {
307 if ((access & ACCESS_CLASS) == 0) {
308 if ((access & ACCESS_MODULE_REQUIRES) != 0) {
309 sb.append("transitive ");
310 } else {
311 if ((access & ACCESS_MODULE) == 0) {
312 sb.append("synchronized ");
313 } else {
314 sb.append("open ");
315 }
97316 }
98 if (debug != null) {
99 att.addAttribute("", "debug", "debug", "", encode(debug));
317 } else {
318 sb.append("super ");
319 }
320 }
321 if ((access & Opcodes.ACC_VOLATILE) != 0) {
322 if ((access & ACCESS_FIELD) == 0) {
323 sb.append("bridge ");
324 } else {
325 if ((access & ACCESS_MODULE_REQUIRES) == 0) {
326 sb.append("volatile ");
327 } else {
328 sb.append("static ");
100329 }
101
102 sa.addElement("source", att);
103 }
104
105 @Override
106 public ModuleVisitor visitModule() {
107 AttributesImpl att = new AttributesImpl();
108 sa.addStart("module", att);
109 return new SAXModuleAdapter(sa);
110 }
111
112 @Override
113 public void visitOuterClass(final String owner, final String name,
114 final String desc) {
115 AttributesImpl att = new AttributesImpl();
116 att.addAttribute("", "owner", "owner", "", owner);
117 if (name != null) {
118 att.addAttribute("", "name", "name", "", name);
119 }
120 if (desc != null) {
121 att.addAttribute("", "desc", "desc", "", desc);
122 }
123
124 sa.addElement("outerclass", att);
125 }
126
127 @Override
128 public AnnotationVisitor visitAnnotation(final String desc,
129 final boolean visible) {
130 return new SAXAnnotationAdapter(sa, "annotation", visible ? 1 : -1,
131 null, desc);
132 }
133
134 @Override
135 public AnnotationVisitor visitTypeAnnotation(int typeRef,
136 TypePath typePath, String desc, boolean visible) {
137 return new SAXAnnotationAdapter(sa, "typeAnnotation", visible ? 1 : -1,
138 null, desc, typeRef, typePath);
139 }
140
141 @Override
142 public void visit(final int version, final int access, final String name,
143 final String signature, final String superName,
144 final String[] interfaces) {
145 StringBuilder sb = new StringBuilder();
146 appendAccess(access | ACCESS_CLASS, sb);
147
148 AttributesImpl att = new AttributesImpl();
149 att.addAttribute("", "access", "access", "", sb.toString());
150 if (name != null) {
151 att.addAttribute("", "name", "name", "", name);
152 }
153 if (signature != null) {
154 att.addAttribute("", "signature", "signature", "",
155 encode(signature));
156 }
157 if (superName != null) {
158 att.addAttribute("", "parent", "parent", "", superName);
159 }
160 att.addAttribute("", "major", "major", "",
161 Integer.toString(version & 0xFFFF));
162 att.addAttribute("", "minor", "minor", "",
163 Integer.toString(version >>> 16));
164 sa.addStart("class", att);
165
166 sa.addStart("interfaces", new AttributesImpl());
167 if (interfaces != null && interfaces.length > 0) {
168 for (int i = 0; i < interfaces.length; i++) {
169 AttributesImpl att2 = new AttributesImpl();
170 att2.addAttribute("", "name", "name", "", interfaces[i]);
171 sa.addElement("interface", att2);
172 }
173 }
174 sa.addEnd("interfaces");
175 }
176
177 @Override
178 public FieldVisitor visitField(final int access, final String name,
179 final String desc, final String signature, final Object value) {
180 StringBuilder sb = new StringBuilder();
181 appendAccess(access | ACCESS_FIELD, sb);
182
183 AttributesImpl att = new AttributesImpl();
184 att.addAttribute("", "access", "access", "", sb.toString());
185 att.addAttribute("", "name", "name", "", name);
186 att.addAttribute("", "desc", "desc", "", desc);
187 if (signature != null) {
188 att.addAttribute("", "signature", "signature", "",
189 encode(signature));
190 }
191 if (value != null) {
192 att.addAttribute("", "value", "value", "", encode(value.toString()));
193 }
194
195 return new SAXFieldAdapter(sa, att);
196 }
197
198 @Override
199 public MethodVisitor visitMethod(final int access, final String name,
200 final String desc, final String signature, final String[] exceptions) {
201 StringBuilder sb = new StringBuilder();
202 appendAccess(access, sb);
203
204 AttributesImpl att = new AttributesImpl();
205 att.addAttribute("", "access", "access", "", sb.toString());
206 att.addAttribute("", "name", "name", "", name);
207 att.addAttribute("", "desc", "desc", "", desc);
208 if (signature != null) {
209 att.addAttribute("", "signature", "signature", "", signature);
210 }
211 sa.addStart("method", att);
212
213 sa.addStart("exceptions", new AttributesImpl());
214 if (exceptions != null && exceptions.length > 0) {
215 for (int i = 0; i < exceptions.length; i++) {
216 AttributesImpl att2 = new AttributesImpl();
217 att2.addAttribute("", "name", "name", "", exceptions[i]);
218 sa.addElement("exception", att2);
219 }
220 }
221 sa.addEnd("exceptions");
222
223 return new SAXCodeAdapter(sa, access);
224 }
225
226 @Override
227 public final void visitInnerClass(final String name,
228 final String outerName, final String innerName, final int access) {
229 StringBuilder sb = new StringBuilder();
230 appendAccess(access | ACCESS_INNER, sb);
231
232 AttributesImpl att = new AttributesImpl();
233 att.addAttribute("", "access", "access", "", sb.toString());
234 if (name != null) {
235 att.addAttribute("", "name", "name", "", name);
236 }
237 if (outerName != null) {
238 att.addAttribute("", "outerName", "outerName", "", outerName);
239 }
240 if (innerName != null) {
241 att.addAttribute("", "innerName", "innerName", "", innerName);
242 }
243 sa.addElement("innerclass", att);
244 }
245
246 @Override
247 public final void visitEnd() {
248 sa.addEnd("class");
249 if (!singleDocument) {
250 sa.addDocumentEnd();
251 }
252 }
253
254 static final String encode(final String s) {
255 StringBuilder sb = new StringBuilder();
256 for (int i = 0; i < s.length(); i++) {
257 char c = s.charAt(i);
258 if (c == '\\') {
259 sb.append("\\\\");
260 } else if (c < 0x20 || c > 0x7f) {
261 sb.append("\\u");
262 if (c < 0x10) {
263 sb.append("000");
264 } else if (c < 0x100) {
265 sb.append("00");
266 } else if (c < 0x1000) {
267 sb.append('0');
268 }
269 sb.append(Integer.toString(c, 16));
270 } else {
271 sb.append(c);
272 }
273 }
274 return sb.toString();
275 }
276
277 static void appendAccess(final int access, final StringBuilder sb) {
278 if ((access & Opcodes.ACC_PUBLIC) != 0) {
279 sb.append("public ");
280 }
281 if ((access & Opcodes.ACC_PRIVATE) != 0) {
282 sb.append("private ");
283 }
284 if ((access & Opcodes.ACC_PROTECTED) != 0) {
285 sb.append("protected ");
286 }
287 if ((access & Opcodes.ACC_FINAL) != 0) {
288 sb.append("final ");
289 }
290 if ((access & Opcodes.ACC_STATIC) != 0) {
291 sb.append("static ");
292 }
293 if ((access & Opcodes.ACC_SUPER) != 0) {
294 if ((access & ACCESS_CLASS) == 0) {
295 sb.append("synchronized ");
296 } else {
297 sb.append("super ");
298 }
299 }
300 if ((access & Opcodes.ACC_VOLATILE) != 0) {
301 if ((access & ACCESS_FIELD) == 0) {
302 sb.append("bridge ");
303 } else {
304 sb.append("volatile ");
305 }
306 }
307 if ((access & Opcodes.ACC_TRANSIENT) != 0) {
308 if ((access & ACCESS_FIELD) == 0) {
309 sb.append("varargs ");
310 } else {
311 sb.append("transient ");
312 }
313 }
314 if ((access & Opcodes.ACC_NATIVE) != 0) {
315 sb.append("native ");
316 }
317 if ((access & Opcodes.ACC_STRICT) != 0) {
318 sb.append("strict ");
319 }
320 if ((access & Opcodes.ACC_INTERFACE) != 0) {
321 sb.append("interface ");
322 }
323 if ((access & Opcodes.ACC_ABSTRACT) != 0) {
324 sb.append("abstract ");
325 }
326 if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
327 sb.append("synthetic ");
328 }
329 if ((access & Opcodes.ACC_ANNOTATION) != 0) {
330 sb.append("annotation ");
331 }
332 if ((access & Opcodes.ACC_ENUM) != 0) {
333 sb.append("enum ");
334 }
335 if ((access & Opcodes.ACC_DEPRECATED) != 0) {
336 sb.append("deprecated ");
337 }
338 if ((access & (Opcodes.ACC_MANDATED|Opcodes.ACC_MODULE)) != 0) {
339 if ((access & ACCESS_CLASS) == 0) {
340 sb.append("module ");
341 } else {
342 sb.append("mandated ");
343 }
344 }
345 }
330 }
331 }
332 if ((access & Opcodes.ACC_TRANSIENT) != 0) {
333 if ((access & ACCESS_FIELD) == 0) {
334 sb.append("varargs ");
335 } else {
336 sb.append("transient ");
337 }
338 }
339 if ((access & Opcodes.ACC_NATIVE) != 0) {
340 sb.append("native ");
341 }
342 if ((access & Opcodes.ACC_STRICT) != 0) {
343 sb.append("strict ");
344 }
345 if ((access & Opcodes.ACC_INTERFACE) != 0) {
346 sb.append("interface ");
347 }
348 if ((access & Opcodes.ACC_ABSTRACT) != 0) {
349 sb.append("abstract ");
350 }
351 if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
352 sb.append("synthetic ");
353 }
354 if ((access & Opcodes.ACC_ANNOTATION) != 0) {
355 sb.append("annotation ");
356 }
357 if ((access & Opcodes.ACC_ENUM) != 0) {
358 sb.append("enum ");
359 }
360 if ((access & Opcodes.ACC_DEPRECATED) != 0) {
361 sb.append("deprecated ");
362 }
363 if ((access & Opcodes.ACC_MANDATED) != 0) {
364 if ((access & ACCESS_CLASS) == 0) {
365 sb.append("module ");
366 } else {
367 sb.append("mandated ");
368 }
369 }
370 }
346371 }
0 /***
1 * ASM XML Adapter
2 * Copyright (c) 2004-2011, Eugene Kuleshov
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.xml;
3028
3129 import java.util.HashMap;
4240 import org.xml.sax.helpers.AttributesImpl;
4341
4442 /**
45 * A {@link MethodVisitor} that generates SAX 2.0 events from the visited
46 * method.
47 *
43 * A {@link MethodVisitor} that generates SAX 2.0 events from the visited method.
44 *
45 * @deprecated This class is no longer maintained, will not support new Java features, and will
46 * eventually be deleted. Use the asm or asm.tree API instead.
4847 * @see org.eclipse.persistence.internal.libraries.asm.xml.SAXClassAdapter
4948 * @see org.eclipse.persistence.internal.libraries.asm.xml.Processor
50 *
5149 * @author Eugene Kuleshov
5250 */
51 @Deprecated
5352 public final class SAXCodeAdapter extends MethodVisitor {
5453
55 static final String[] TYPES = { "top", "int", "float", "double", "long",
56 "null", "uninitializedThis" };
57
58 SAXAdapter sa;
59
60 int access;
61
62 private final Map<Label, String> labelNames;
63
64 /**
65 * Constructs a new {@link SAXCodeAdapter SAXCodeAdapter} object.
66 *
67 * @param sa
68 * content handler that will be used to send SAX 2.0 events.
69 */
70 public SAXCodeAdapter(final SAXAdapter sa, final int access) {
71 super(Opcodes.ASM6);
72 this.sa = sa;
73 this.access = access;
74 this.labelNames = new HashMap<Label, String>();
75 }
76
77 @Override
78 public void visitParameter(String name, int access) {
79 AttributesImpl attrs = new AttributesImpl();
80 if (name != null) {
81 attrs.addAttribute("", "name", "name", "", name);
54 static final String[] TYPES = {
55 "top", "int", "float", "double", "long", "null", "uninitializedThis"
56 };
57
58 SAXAdapter sa;
59
60 int access;
61
62 private final Map<Label, String> labelNames;
63
64 /**
65 * Constructs a new {@link SAXCodeAdapter SAXCodeAdapter} object.
66 *
67 * @param sa content handler that will be used to send SAX 2.0 events.
68 * @param access the method access flags.
69 */
70 public SAXCodeAdapter(final SAXAdapter sa, final int access) {
71 super(Opcodes.ASM6);
72 this.sa = sa;
73 this.access = access;
74 this.labelNames = new HashMap<Label, String>();
75 }
76
77 @Override
78 public void visitParameter(String name, int access) {
79 AttributesImpl attrs = new AttributesImpl();
80 if (name != null) {
81 attrs.addAttribute("", "name", "name", "", name);
82 }
83 StringBuilder sb = new StringBuilder();
84 SAXClassAdapter.appendAccess(access, sb);
85 attrs.addAttribute("", "access", "access", "", sb.toString());
86 sa.addElement("parameter", attrs);
87 }
88
89 @Override
90 public final void visitCode() {
91 if ((access & (Opcodes.ACC_ABSTRACT | Opcodes.ACC_INTERFACE | Opcodes.ACC_NATIVE)) == 0) {
92 sa.addStart("code", new AttributesImpl());
93 }
94 }
95
96 @Override
97 public void visitFrame(
98 final int type,
99 final int nLocal,
100 final Object[] local,
101 final int nStack,
102 final Object[] stack) {
103 AttributesImpl attrs = new AttributesImpl();
104 switch (type) {
105 case Opcodes.F_NEW:
106 case Opcodes.F_FULL:
107 if (type == Opcodes.F_NEW) {
108 attrs.addAttribute("", "type", "type", "", "NEW");
109 } else {
110 attrs.addAttribute("", "type", "type", "", "FULL");
82111 }
83 StringBuilder sb = new StringBuilder();
84 SAXClassAdapter.appendAccess(access, sb);
85 attrs.addAttribute("", "access", "access", "", sb.toString());
86 sa.addElement("parameter", attrs);
87 }
88
89 @Override
90 public final void visitCode() {
91 if ((access & (Opcodes.ACC_ABSTRACT | Opcodes.ACC_INTERFACE | Opcodes.ACC_NATIVE)) == 0) {
92 sa.addStart("code", new AttributesImpl());
93 }
94 }
95
96 @Override
97 public void visitFrame(final int type, final int nLocal,
98 final Object[] local, final int nStack, final Object[] stack) {
99 AttributesImpl attrs = new AttributesImpl();
100 switch (type) {
101 case Opcodes.F_NEW:
102 case Opcodes.F_FULL:
103 if (type == Opcodes.F_NEW) {
104 attrs.addAttribute("", "type", "type", "", "NEW");
105 } else {
106 attrs.addAttribute("", "type", "type", "", "FULL");
107 }
108 sa.addStart("frame", attrs);
109 appendFrameTypes(true, nLocal, local);
110 appendFrameTypes(false, nStack, stack);
111 break;
112 case Opcodes.F_APPEND:
113 attrs.addAttribute("", "type", "type", "", "APPEND");
114 sa.addStart("frame", attrs);
115 appendFrameTypes(true, nLocal, local);
116 break;
117 case Opcodes.F_CHOP:
118 attrs.addAttribute("", "type", "type", "", "CHOP");
119 attrs.addAttribute("", "count", "count", "",
120 Integer.toString(nLocal));
121 sa.addStart("frame", attrs);
122 break;
123 case Opcodes.F_SAME:
124 attrs.addAttribute("", "type", "type", "", "SAME");
125 sa.addStart("frame", attrs);
126 break;
127 case Opcodes.F_SAME1:
128 attrs.addAttribute("", "type", "type", "", "SAME1");
129 sa.addStart("frame", attrs);
130 appendFrameTypes(false, 1, stack);
131 break;
132 }
133 sa.addEnd("frame");
134 }
135
136 private void appendFrameTypes(final boolean local, final int n,
137 final Object[] types) {
138 for (int i = 0; i < n; ++i) {
139 Object type = types[i];
140 AttributesImpl attrs = new AttributesImpl();
141 if (type instanceof String) {
142 attrs.addAttribute("", "type", "type", "", (String) type);
143 } else if (type instanceof Integer) {
144 attrs.addAttribute("", "type", "type", "",
145 TYPES[((Integer) type).intValue()]);
146 } else {
147 attrs.addAttribute("", "type", "type", "", "uninitialized");
148 attrs.addAttribute("", "label", "label", "",
149 getLabel((Label) type));
150 }
151 sa.addElement(local ? "local" : "stack", attrs);
152 }
153 }
154
155 @Override
156 public final void visitInsn(final int opcode) {
157 sa.addElement(Printer.OPCODES[opcode], new AttributesImpl());
158 }
159
160 @Override
161 public final void visitIntInsn(final int opcode, final int operand) {
162 AttributesImpl attrs = new AttributesImpl();
163 attrs.addAttribute("", "value", "value", "", Integer.toString(operand));
164 sa.addElement(Printer.OPCODES[opcode], attrs);
165 }
166
167 @Override
168 public final void visitVarInsn(final int opcode, final int var) {
169 AttributesImpl attrs = new AttributesImpl();
170 attrs.addAttribute("", "var", "var", "", Integer.toString(var));
171 sa.addElement(Printer.OPCODES[opcode], attrs);
172 }
173
174 @Override
175 public final void visitTypeInsn(final int opcode, final String type) {
176 AttributesImpl attrs = new AttributesImpl();
177 attrs.addAttribute("", "desc", "desc", "", type);
178 sa.addElement(Printer.OPCODES[opcode], attrs);
179 }
180
181 @Override
182 public final void visitFieldInsn(final int opcode, final String owner,
183 final String name, final String desc) {
184 AttributesImpl attrs = new AttributesImpl();
185 attrs.addAttribute("", "owner", "owner", "", owner);
186 attrs.addAttribute("", "name", "name", "", name);
187 attrs.addAttribute("", "desc", "desc", "", desc);
188 sa.addElement(Printer.OPCODES[opcode], attrs);
189 }
190
191 @Override
192 public final void visitMethodInsn(final int opcode, final String owner,
193 final String name, final String desc, final boolean itf) {
194 AttributesImpl attrs = new AttributesImpl();
195 attrs.addAttribute("", "owner", "owner", "", owner);
196 attrs.addAttribute("", "name", "name", "", name);
197 attrs.addAttribute("", "desc", "desc", "", desc);
198 attrs.addAttribute("", "itf", "itf", "", itf ? "true" : "false");
199 sa.addElement(Printer.OPCODES[opcode], attrs);
200 }
201
202 @Override
203 public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
204 Object... bsmArgs) {
205 AttributesImpl attrs = new AttributesImpl();
206 attrs.addAttribute("", "name", "name", "", name);
207 attrs.addAttribute("", "desc", "desc", "", desc);
208 attrs.addAttribute("", "bsm", "bsm", "",
209 SAXClassAdapter.encode(bsm.toString()));
210 sa.addStart("INVOKEDYNAMIC", attrs);
211 for (int i = 0; i < bsmArgs.length; i++) {
212 sa.addElement("bsmArg", getConstantAttribute(bsmArgs[i]));
213 }
214 sa.addEnd("INVOKEDYNAMIC");
215 }
216
217 @Override
218 public final void visitJumpInsn(final int opcode, final Label label) {
219 AttributesImpl attrs = new AttributesImpl();
220 attrs.addAttribute("", "label", "label", "", getLabel(label));
221 sa.addElement(Printer.OPCODES[opcode], attrs);
222 }
223
224 @Override
225 public final void visitLabel(final Label label) {
226 AttributesImpl attrs = new AttributesImpl();
227 attrs.addAttribute("", "name", "name", "", getLabel(label));
228 sa.addElement("Label", attrs);
229 }
230
231 @Override
232 public final void visitLdcInsn(final Object cst) {
233 sa.addElement(Printer.OPCODES[Opcodes.LDC], getConstantAttribute(cst));
234 }
235
236 private static AttributesImpl getConstantAttribute(final Object cst) {
237 AttributesImpl attrs = new AttributesImpl();
238 attrs.addAttribute("", "cst", "cst", "",
239 SAXClassAdapter.encode(cst.toString()));
240 attrs.addAttribute("", "desc", "desc", "",
241 Type.getDescriptor(cst.getClass()));
242 return attrs;
243 }
244
245 @Override
246 public final void visitIincInsn(final int var, final int increment) {
247 AttributesImpl attrs = new AttributesImpl();
248 attrs.addAttribute("", "var", "var", "", Integer.toString(var));
249 attrs.addAttribute("", "inc", "inc", "", Integer.toString(increment));
250 sa.addElement(Printer.OPCODES[Opcodes.IINC], attrs);
251 }
252
253 @Override
254 public final void visitTableSwitchInsn(final int min, final int max,
255 final Label dflt, final Label... labels) {
256 AttributesImpl attrs = new AttributesImpl();
257 attrs.addAttribute("", "min", "min", "", Integer.toString(min));
258 attrs.addAttribute("", "max", "max", "", Integer.toString(max));
259 attrs.addAttribute("", "dflt", "dflt", "", getLabel(dflt));
260 String o = Printer.OPCODES[Opcodes.TABLESWITCH];
261 sa.addStart(o, attrs);
262 for (int i = 0; i < labels.length; i++) {
263 AttributesImpl att2 = new AttributesImpl();
264 att2.addAttribute("", "name", "name", "", getLabel(labels[i]));
265 sa.addElement("label", att2);
266 }
267 sa.addEnd(o);
268 }
269
270 @Override
271 public final void visitLookupSwitchInsn(final Label dflt, final int[] keys,
272 final Label[] labels) {
273 AttributesImpl att = new AttributesImpl();
274 att.addAttribute("", "dflt", "dflt", "", getLabel(dflt));
275 String o = Printer.OPCODES[Opcodes.LOOKUPSWITCH];
276 sa.addStart(o, att);
277 for (int i = 0; i < labels.length; i++) {
278 AttributesImpl att2 = new AttributesImpl();
279 att2.addAttribute("", "name", "name", "", getLabel(labels[i]));
280 att2.addAttribute("", "key", "key", "", Integer.toString(keys[i]));
281 sa.addElement("label", att2);
282 }
283 sa.addEnd(o);
284 }
285
286 @Override
287 public final void visitMultiANewArrayInsn(final String desc, final int dims) {
288 AttributesImpl attrs = new AttributesImpl();
289 attrs.addAttribute("", "desc", "desc", "", desc);
290 attrs.addAttribute("", "dims", "dims", "", Integer.toString(dims));
291 sa.addElement(Printer.OPCODES[Opcodes.MULTIANEWARRAY], attrs);
292 }
293
294 @Override
295 public final void visitTryCatchBlock(final Label start, final Label end,
296 final Label handler, final String type) {
297 AttributesImpl attrs = new AttributesImpl();
298 attrs.addAttribute("", "start", "start", "", getLabel(start));
299 attrs.addAttribute("", "end", "end", "", getLabel(end));
300 attrs.addAttribute("", "handler", "handler", "", getLabel(handler));
301 if (type != null) {
302 attrs.addAttribute("", "type", "type", "", type);
303 }
304 sa.addElement("TryCatch", attrs);
305 }
306
307 @Override
308 public final void visitMaxs(final int maxStack, final int maxLocals) {
309 AttributesImpl attrs = new AttributesImpl();
310 attrs.addAttribute("", "maxStack", "maxStack", "",
311 Integer.toString(maxStack));
312 attrs.addAttribute("", "maxLocals", "maxLocals", "",
313 Integer.toString(maxLocals));
314 sa.addElement("Max", attrs);
315
316 sa.addEnd("code");
317 }
318
319 @Override
320 public void visitLocalVariable(final String name, final String desc,
321 final String signature, final Label start, final Label end,
322 final int index) {
323 AttributesImpl attrs = new AttributesImpl();
324 attrs.addAttribute("", "name", "name", "", name);
325 attrs.addAttribute("", "desc", "desc", "", desc);
326 if (signature != null) {
327 attrs.addAttribute("", "signature", "signature", "",
328 SAXClassAdapter.encode(signature));
329 }
330 attrs.addAttribute("", "start", "start", "", getLabel(start));
331 attrs.addAttribute("", "end", "end", "", getLabel(end));
332 attrs.addAttribute("", "var", "var", "", Integer.toString(index));
333 sa.addElement("LocalVar", attrs);
334 }
335
336 @Override
337 public final void visitLineNumber(final int line, final Label start) {
338 AttributesImpl attrs = new AttributesImpl();
339 attrs.addAttribute("", "line", "line", "", Integer.toString(line));
340 attrs.addAttribute("", "start", "start", "", getLabel(start));
341 sa.addElement("LineNumber", attrs);
342 }
343
344 @Override
345 public AnnotationVisitor visitAnnotationDefault() {
346 return new SAXAnnotationAdapter(sa, "annotationDefault", 0, null, null);
347 }
348
349 @Override
350 public AnnotationVisitor visitAnnotation(final String desc,
351 final boolean visible) {
352 return new SAXAnnotationAdapter(sa, "annotation", visible ? 1 : -1,
353 null, desc);
354 }
355
356 @Override
357 public AnnotationVisitor visitTypeAnnotation(int typeRef,
358 TypePath typePath, String desc, boolean visible) {
359 return new SAXAnnotationAdapter(sa, "typeAnnotation", visible ? 1 : -1,
360 null, desc, typeRef, typePath);
361 }
362
363 @Override
364 public AnnotationVisitor visitParameterAnnotation(final int parameter,
365 final String desc, final boolean visible) {
366 return new SAXAnnotationAdapter(sa, "parameterAnnotation", visible ? 1
367 : -1, parameter, desc);
368 }
369
370 @Override
371 public AnnotationVisitor visitInsnAnnotation(int typeRef,
372 TypePath typePath, String desc, boolean visible) {
373 return new SAXAnnotationAdapter(sa, "insnAnnotation", visible ? 1 : -1,
374 null, desc, typeRef, typePath);
375 }
376
377 @Override
378 public AnnotationVisitor visitTryCatchAnnotation(int typeRef,
379 TypePath typePath, String desc, boolean visible) {
380 return new SAXAnnotationAdapter(sa, "tryCatchAnnotation", visible ? 1
381 : -1, null, desc, typeRef, typePath);
382 }
383
384 @Override
385 public AnnotationVisitor visitLocalVariableAnnotation(int typeRef,
386 TypePath typePath, Label[] start, Label[] end, int[] index,
387 String desc, boolean visible) {
388 String[] s = new String[start.length];
389 String[] e = new String[end.length];
390 for (int i = 0; i < s.length; ++i) {
391 s[i] = getLabel(start[i]);
392 }
393 for (int i = 0; i < e.length; ++i) {
394 e[i] = getLabel(end[i]);
395 }
396 return new SAXAnnotationAdapter(sa, "localVariableAnnotation",
397 visible ? 1 : -1, null, desc, typeRef, typePath, s, e, index);
398 }
399
400 @Override
401 public void visitEnd() {
402 sa.addEnd("method");
403 }
404
405 private final String getLabel(final Label label) {
406 String name = labelNames.get(label);
407 if (name == null) {
408 name = Integer.toString(labelNames.size());
409 labelNames.put(label, name);
410 }
411 return name;
412 }
413
112 sa.addStart("frame", attrs);
113 appendFrameTypes(true, nLocal, local);
114 appendFrameTypes(false, nStack, stack);
115 break;
116 case Opcodes.F_APPEND:
117 attrs.addAttribute("", "type", "type", "", "APPEND");
118 sa.addStart("frame", attrs);
119 appendFrameTypes(true, nLocal, local);
120 break;
121 case Opcodes.F_CHOP:
122 attrs.addAttribute("", "type", "type", "", "CHOP");
123 attrs.addAttribute("", "count", "count", "", Integer.toString(nLocal));
124 sa.addStart("frame", attrs);
125 break;
126 case Opcodes.F_SAME:
127 attrs.addAttribute("", "type", "type", "", "SAME");
128 sa.addStart("frame", attrs);
129 break;
130 case Opcodes.F_SAME1:
131 attrs.addAttribute("", "type", "type", "", "SAME1");
132 sa.addStart("frame", attrs);
133 appendFrameTypes(false, 1, stack);
134 break;
135 }
136 sa.addEnd("frame");
137 }
138
139 private void appendFrameTypes(final boolean local, final int n, final Object[] types) {
140 for (int i = 0; i < n; ++i) {
141 Object type = types[i];
142 AttributesImpl attrs = new AttributesImpl();
143 if (type instanceof String) {
144 attrs.addAttribute("", "type", "type", "", (String) type);
145 } else if (type instanceof Integer) {
146 attrs.addAttribute("", "type", "type", "", TYPES[((Integer) type).intValue()]);
147 } else {
148 attrs.addAttribute("", "type", "type", "", "uninitialized");
149 attrs.addAttribute("", "label", "label", "", getLabel((Label) type));
150 }
151 sa.addElement(local ? "local" : "stack", attrs);
152 }
153 }
154
155 @Override
156 public final void visitInsn(final int opcode) {
157 sa.addElement(Printer.OPCODES[opcode], new AttributesImpl());
158 }
159
160 @Override
161 public final void visitIntInsn(final int opcode, final int operand) {
162 AttributesImpl attrs = new AttributesImpl();
163 attrs.addAttribute("", "value", "value", "", Integer.toString(operand));
164 sa.addElement(Printer.OPCODES[opcode], attrs);
165 }
166
167 @Override
168 public final void visitVarInsn(final int opcode, final int var) {
169 AttributesImpl attrs = new AttributesImpl();
170 attrs.addAttribute("", "var", "var", "", Integer.toString(var));
171 sa.addElement(Printer.OPCODES[opcode], attrs);
172 }
173
174 @Override
175 public final void visitTypeInsn(final int opcode, final String type) {
176 AttributesImpl attrs = new AttributesImpl();
177 attrs.addAttribute("", "desc", "desc", "", type);
178 sa.addElement(Printer.OPCODES[opcode], attrs);
179 }
180
181 @Override
182 public final void visitFieldInsn(
183 final int opcode, final String owner, final String name, final String desc) {
184 AttributesImpl attrs = new AttributesImpl();
185 attrs.addAttribute("", "owner", "owner", "", owner);
186 attrs.addAttribute("", "name", "name", "", name);
187 attrs.addAttribute("", "desc", "desc", "", desc);
188 sa.addElement(Printer.OPCODES[opcode], attrs);
189 }
190
191 @Override
192 public final void visitMethodInsn(
193 final int opcode,
194 final String owner,
195 final String name,
196 final String desc,
197 final boolean itf) {
198 AttributesImpl attrs = new AttributesImpl();
199 attrs.addAttribute("", "owner", "owner", "", owner);
200 attrs.addAttribute("", "name", "name", "", name);
201 attrs.addAttribute("", "desc", "desc", "", desc);
202 attrs.addAttribute("", "itf", "itf", "", itf ? "true" : "false");
203 sa.addElement(Printer.OPCODES[opcode], attrs);
204 }
205
206 @Override
207 public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) {
208 AttributesImpl attrs = new AttributesImpl();
209 attrs.addAttribute("", "name", "name", "", name);
210 attrs.addAttribute("", "desc", "desc", "", desc);
211 attrs.addAttribute("", "bsm", "bsm", "", SAXClassAdapter.encode(bsm.toString()));
212 sa.addStart("INVOKEDYNAMIC", attrs);
213 for (int i = 0; i < bsmArgs.length; i++) {
214 sa.addElement("bsmArg", getConstantAttribute(bsmArgs[i]));
215 }
216 sa.addEnd("INVOKEDYNAMIC");
217 }
218
219 @Override
220 public final void visitJumpInsn(final int opcode, final Label label) {
221 AttributesImpl attrs = new AttributesImpl();
222 attrs.addAttribute("", "label", "label", "", getLabel(label));
223 sa.addElement(Printer.OPCODES[opcode], attrs);
224 }
225
226 @Override
227 public final void visitLabel(final Label label) {
228 AttributesImpl attrs = new AttributesImpl();
229 attrs.addAttribute("", "name", "name", "", getLabel(label));
230 sa.addElement("Label", attrs);
231 }
232
233 @Override
234 public final void visitLdcInsn(final Object cst) {
235 sa.addElement(Printer.OPCODES[Opcodes.LDC], getConstantAttribute(cst));
236 }
237
238 private static AttributesImpl getConstantAttribute(final Object cst) {
239 AttributesImpl attrs = new AttributesImpl();
240 attrs.addAttribute("", "cst", "cst", "", SAXClassAdapter.encode(cst.toString()));
241 attrs.addAttribute("", "desc", "desc", "", Type.getDescriptor(cst.getClass()));
242 return attrs;
243 }
244
245 @Override
246 public final void visitIincInsn(final int var, final int increment) {
247 AttributesImpl attrs = new AttributesImpl();
248 attrs.addAttribute("", "var", "var", "", Integer.toString(var));
249 attrs.addAttribute("", "inc", "inc", "", Integer.toString(increment));
250 sa.addElement(Printer.OPCODES[Opcodes.IINC], attrs);
251 }
252
253 @Override
254 public final void visitTableSwitchInsn(
255 final int min, final int max, final Label dflt, final Label... labels) {
256 AttributesImpl attrs = new AttributesImpl();
257 attrs.addAttribute("", "min", "min", "", Integer.toString(min));
258 attrs.addAttribute("", "max", "max", "", Integer.toString(max));
259 attrs.addAttribute("", "dflt", "dflt", "", getLabel(dflt));
260 String o = Printer.OPCODES[Opcodes.TABLESWITCH];
261 sa.addStart(o, attrs);
262 for (int i = 0; i < labels.length; i++) {
263 AttributesImpl att2 = new AttributesImpl();
264 att2.addAttribute("", "name", "name", "", getLabel(labels[i]));
265 sa.addElement("label", att2);
266 }
267 sa.addEnd(o);
268 }
269
270 @Override
271 public final void visitLookupSwitchInsn(
272 final Label dflt, final int[] keys, final Label[] labels) {
273 AttributesImpl att = new AttributesImpl();
274 att.addAttribute("", "dflt", "dflt", "", getLabel(dflt));
275 String o = Printer.OPCODES[Opcodes.LOOKUPSWITCH];
276 sa.addStart(o, att);
277 for (int i = 0; i < labels.length; i++) {
278 AttributesImpl att2 = new AttributesImpl();
279 att2.addAttribute("", "name", "name", "", getLabel(labels[i]));
280 att2.addAttribute("", "key", "key", "", Integer.toString(keys[i]));
281 sa.addElement("label", att2);
282 }
283 sa.addEnd(o);
284 }
285
286 @Override
287 public final void visitMultiANewArrayInsn(final String desc, final int dims) {
288 AttributesImpl attrs = new AttributesImpl();
289 attrs.addAttribute("", "desc", "desc", "", desc);
290 attrs.addAttribute("", "dims", "dims", "", Integer.toString(dims));
291 sa.addElement(Printer.OPCODES[Opcodes.MULTIANEWARRAY], attrs);
292 }
293
294 @Override
295 public final void visitTryCatchBlock(
296 final Label start, final Label end, final Label handler, final String type) {
297 AttributesImpl attrs = new AttributesImpl();
298 attrs.addAttribute("", "start", "start", "", getLabel(start));
299 attrs.addAttribute("", "end", "end", "", getLabel(end));
300 attrs.addAttribute("", "handler", "handler", "", getLabel(handler));
301 if (type != null) {
302 attrs.addAttribute("", "type", "type", "", type);
303 }
304 sa.addElement("TryCatch", attrs);
305 }
306
307 @Override
308 public final void visitMaxs(final int maxStack, final int maxLocals) {
309 AttributesImpl attrs = new AttributesImpl();
310 attrs.addAttribute("", "maxStack", "maxStack", "", Integer.toString(maxStack));
311 attrs.addAttribute("", "maxLocals", "maxLocals", "", Integer.toString(maxLocals));
312 sa.addElement("Max", attrs);
313
314 sa.addEnd("code");
315 }
316
317 @Override
318 public void visitLocalVariable(
319 final String name,
320 final String desc,
321 final String signature,
322 final Label start,
323 final Label end,
324 final int index) {
325 AttributesImpl attrs = new AttributesImpl();
326 attrs.addAttribute("", "name", "name", "", name);
327 attrs.addAttribute("", "desc", "desc", "", desc);
328 if (signature != null) {
329 attrs.addAttribute("", "signature", "signature", "", SAXClassAdapter.encode(signature));
330 }
331 attrs.addAttribute("", "start", "start", "", getLabel(start));
332 attrs.addAttribute("", "end", "end", "", getLabel(end));
333 attrs.addAttribute("", "var", "var", "", Integer.toString(index));
334 sa.addElement("LocalVar", attrs);
335 }
336
337 @Override
338 public final void visitLineNumber(final int line, final Label start) {
339 AttributesImpl attrs = new AttributesImpl();
340 attrs.addAttribute("", "line", "line", "", Integer.toString(line));
341 attrs.addAttribute("", "start", "start", "", getLabel(start));
342 sa.addElement("LineNumber", attrs);
343 }
344
345 @Override
346 public AnnotationVisitor visitAnnotationDefault() {
347 return new SAXAnnotationAdapter(sa, "annotationDefault", 0, null, null);
348 }
349
350 @Override
351 public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) {
352 return new SAXAnnotationAdapter(sa, "annotation", visible ? 1 : -1, null, desc);
353 }
354
355 @Override
356 public AnnotationVisitor visitTypeAnnotation(
357 int typeRef, TypePath typePath, String desc, boolean visible) {
358 return new SAXAnnotationAdapter(
359 sa, "typeAnnotation", visible ? 1 : -1, null, desc, typeRef, typePath);
360 }
361
362 @Override
363 public void visitAnnotableParameterCount(
364 final int parameterCount, final boolean visible) {
365 AttributesImpl attrs = new AttributesImpl();
366 attrs.addAttribute("", "count", "count", "", Integer.toString(parameterCount));
367 attrs.addAttribute("", "visible", "visible", "", visible ? "true" : "false");
368 sa.addElement("annotableParameterCount", attrs);
369 }
370
371 @Override
372 public AnnotationVisitor visitParameterAnnotation(
373 final int parameter, final String desc, final boolean visible) {
374 return new SAXAnnotationAdapter(sa, "parameterAnnotation", visible ? 1 : -1, parameter, desc);
375 }
376
377 @Override
378 public AnnotationVisitor visitInsnAnnotation(
379 int typeRef, TypePath typePath, String desc, boolean visible) {
380 return new SAXAnnotationAdapter(
381 sa, "insnAnnotation", visible ? 1 : -1, null, desc, typeRef, typePath);
382 }
383
384 @Override
385 public AnnotationVisitor visitTryCatchAnnotation(
386 int typeRef, TypePath typePath, String desc, boolean visible) {
387 return new SAXAnnotationAdapter(
388 sa, "tryCatchAnnotation", visible ? 1 : -1, null, desc, typeRef, typePath);
389 }
390
391 @Override
392 public AnnotationVisitor visitLocalVariableAnnotation(
393 int typeRef,
394 TypePath typePath,
395 Label[] start,
396 Label[] end,
397 int[] index,
398 String desc,
399 boolean visible) {
400 String[] s = new String[start.length];
401 String[] e = new String[end.length];
402 for (int i = 0; i < s.length; ++i) {
403 s[i] = getLabel(start[i]);
404 }
405 for (int i = 0; i < e.length; ++i) {
406 e[i] = getLabel(end[i]);
407 }
408 return new SAXAnnotationAdapter(
409 sa,
410 "localVariableAnnotation",
411 visible ? 1 : -1,
412 null,
413 desc,
414 typeRef,
415 typePath,
416 s,
417 e,
418 index);
419 }
420
421 @Override
422 public void visitEnd() {
423 sa.addEnd("method");
424 }
425
426 private final String getLabel(final Label label) {
427 String name = labelNames.get(label);
428 if (name == null) {
429 name = Integer.toString(labelNames.size());
430 labelNames.put(label, name);
431 }
432 return name;
433 }
414434 }
0 /***
1 * ASM XML Adapter
2 * Copyright (c) 2004-2011, Eugene Kuleshov
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.xml;
3028
3129 import org.eclipse.persistence.internal.libraries.asm.AnnotationVisitor;
3634
3735 /**
3836 * SAXFieldAdapter
39 *
37 *
38 * @deprecated This class is no longer maintained, will not support new Java features, and will
39 * eventually be deleted. Use the asm or asm.tree API instead.
4040 * @author Eugene Kuleshov
4141 */
42 @Deprecated
4243 public final class SAXFieldAdapter extends FieldVisitor {
4344
44 SAXAdapter sa;
45 SAXAdapter sa;
4546
46 public SAXFieldAdapter(final SAXAdapter sa, final Attributes att) {
47 super(Opcodes.ASM6);
48 this.sa = sa;
49 sa.addStart("field", att);
50 }
47 public SAXFieldAdapter(final SAXAdapter sa, final Attributes att) {
48 super(Opcodes.ASM6);
49 this.sa = sa;
50 sa.addStart("field", att);
51 }
5152
52 @Override
53 public AnnotationVisitor visitAnnotation(final String desc,
54 final boolean visible) {
55 return new SAXAnnotationAdapter(sa, "annotation", visible ? 1 : -1,
56 null, desc);
57 }
53 @Override
54 public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) {
55 return new SAXAnnotationAdapter(sa, "annotation", visible ? 1 : -1, null, desc);
56 }
5857
59 @Override
60 public AnnotationVisitor visitTypeAnnotation(int typeRef,
61 TypePath typePath, String desc, boolean visible) {
62 return new SAXAnnotationAdapter(sa, "typeAnnotation", visible ? 1 : -1,
63 null, desc, typeRef, typePath);
64 }
58 @Override
59 public AnnotationVisitor visitTypeAnnotation(
60 int typeRef, TypePath typePath, String desc, boolean visible) {
61 return new SAXAnnotationAdapter(
62 sa, "typeAnnotation", visible ? 1 : -1, null, desc, typeRef, typePath);
63 }
6564
66 @Override
67 public void visitEnd() {
68 sa.addEnd("field");
69 }
65 @Override
66 public void visitEnd() {
67 sa.addEnd("field");
68 }
7069 }
0 /***
1 * ASM XML Adapter
2 * Copyright (c) 2004-2011, Eugene Kuleshov
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
0 // ASM: a very small and fast Java bytecode manipulation framework
1 // Copyright (c) 2000-2011 INRIA, France Telecom
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the copyright holders nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 // THE POSSIBILITY OF SUCH DAMAGE.
2927 package org.eclipse.persistence.internal.libraries.asm.xml;
3028
3129 import org.eclipse.persistence.internal.libraries.asm.ModuleVisitor;
3432
3533 /**
3634 * Generate SAX event for a module description.
37 *
35 *
36 * @deprecated This class is no longer maintained, will not support new Java features, and will
37 * eventually be deleted. Use the asm or asm.tree API instead.
3838 * @author Remi Forax
3939 */
40 @Deprecated
4041 public final class SAXModuleAdapter extends ModuleVisitor {
4142
42 private final SAXAdapter sa;
43 private final SAXAdapter sa;
4344
44 public SAXModuleAdapter(final SAXAdapter sa) {
45 super(Opcodes.ASM6);
46 this.sa = sa;
45 public SAXModuleAdapter(final SAXAdapter sa) {
46 super(Opcodes.ASM6);
47 this.sa = sa;
48 }
49
50 @Override
51 public void visitMainClass(String mainClass) {
52 AttributesImpl att = new AttributesImpl();
53 att.addAttribute("", "name", "name", "", mainClass);
54 sa.addElement("main-class", att);
55 }
56
57 @Override
58 public void visitPackage(String packaze) {
59 AttributesImpl att = new AttributesImpl();
60 att.addAttribute("", "name", "name", "", packaze);
61 sa.addElement("packages", att);
62 }
63
64 @Override
65 public void visitRequire(String module, int access, String version) {
66 AttributesImpl att = new AttributesImpl();
67 StringBuilder sb = new StringBuilder();
68 SAXClassAdapter.appendAccess(access | SAXClassAdapter.ACCESS_MODULE, sb);
69 att.addAttribute("", "module", "module", "", module);
70 att.addAttribute("", "access", "access", "", sb.toString());
71 if (version != null) {
72 att.addAttribute("", "version", "version", "", version);
4773 }
74 sa.addElement("requires", att);
75 }
4876
49 @Override
50 public void visitRequire(String module, int access) {
51 AttributesImpl att = new AttributesImpl();
52 StringBuilder sb = new StringBuilder();
53 SAXClassAdapter.appendAccess(access, sb);
54 att.addAttribute("", "module", "module", "", module);
55 att.addAttribute("", "access", "access", "", sb.toString());
56 sa.addElement("requires", att);
77 @Override
78 public void visitExport(String packaze, int access, String... modules) {
79 AttributesImpl att = new AttributesImpl();
80 StringBuilder sb = new StringBuilder();
81 SAXClassAdapter.appendAccess(access | SAXClassAdapter.ACCESS_MODULE, sb);
82 att.addAttribute("", "name", "name", "", packaze);
83 att.addAttribute("", "access", "access", "", sb.toString());
84 sa.addStart("exports", att);
85 if (modules != null && modules.length > 0) {
86 for (String to : modules) {
87 AttributesImpl atts = new AttributesImpl();
88 atts.addAttribute("", "module", "module", "", to);
89 sa.addElement("to", atts);
90 }
5791 }
58
59 @Override
60 public void visitExport(String packaze, String... modules) {
61 AttributesImpl att = new AttributesImpl();
62 att.addAttribute("", "name", "name", "", packaze);
63 sa.addStart("exports", att);
64 if (modules != null && modules.length > 0) {
65 for(String to: modules) {
66 AttributesImpl atts = new AttributesImpl();
67 atts.addAttribute("", "module", "module", "", to);
68 sa.addElement("to", atts);
69 }
70 }
71 sa.addEnd("exports");
92 sa.addEnd("exports");
93 }
94
95 @Override
96 public void visitOpen(String packaze, int access, String... modules) {
97 AttributesImpl att = new AttributesImpl();
98 StringBuilder sb = new StringBuilder();
99 SAXClassAdapter.appendAccess(access | SAXClassAdapter.ACCESS_MODULE, sb);
100 att.addAttribute("", "name", "name", "", packaze);
101 att.addAttribute("", "access", "access", "", sb.toString());
102 sa.addStart("opens", att);
103 if (modules != null && modules.length > 0) {
104 for (String to : modules) {
105 AttributesImpl atts = new AttributesImpl();
106 atts.addAttribute("", "module", "module", "", to);
107 sa.addElement("to", atts);
108 }
72109 }
110 sa.addEnd("opens");
111 }
73112
74 @Override
75 public void visitUse(String service) {
76 AttributesImpl att = new AttributesImpl();
77 att.addAttribute("", "service", "service", "", service);
78 sa.addElement("uses", att);
113 @Override
114 public void visitUse(String service) {
115 AttributesImpl att = new AttributesImpl();
116 att.addAttribute("", "service", "service", "", service);
117 sa.addElement("uses", att);
118 }
119
120 @Override
121 public void visitProvide(String service, String... providers) {
122 AttributesImpl att = new AttributesImpl();
123 att.addAttribute("", "service", "service", "", service);
124 sa.addStart("provides", att);
125 for (String provider : providers) {
126 AttributesImpl atts = new AttributesImpl();
127 atts.addAttribute("", "provider", "provider", "", provider);
128 sa.addElement("with", atts);
79129 }
80
81 @Override
82 public void visitProvide(String service, String impl) {
83 AttributesImpl att = new AttributesImpl();
84 att.addAttribute("", "service", "service", "", service);
85 att.addAttribute("", "impl", "impl", "", impl);
86 sa.addElement("provides", att);
87 }
88
89 @Override
90 public void visitEnd() {
91 sa.addEnd("module");
92 }
130 sa.addEnd("provides");
131 }
132
133 @Override
134 public void visitEnd() {
135 sa.addEnd("module");
136 }
93137 }
+0
-363
org/eclipse/persistence/internal/libraries/asm/xml/asm-xml.dtd less more
0 <!--
1 ASM XML Adapter
2 Copyright (c) 2004-2011, Eugene Kuleshov
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8 1. Redistributions of source code must retain the above copyright
9 notice, this list of conditions and the following disclaimer.
10 2. Redistributions in binary form must reproduce the above copyright
11 notice, this list of conditions and the following disclaimer in the
12 documentation and/or other materials provided with the distribution.
13 3. Neither the name of the copyright holders nor the names of its
14 contributors may be used to endorse or promote products derived from
15 this software without specific prior written permission.
16
17 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 THE POSSIBILITY OF SUCH DAMAGE.
28 -->
29
30 <!--
31 This DTD must be used to create XML documents to be processed by
32 org.objectweb.asm.xml.ASMContentHandler
33 -->
34
35 <!--
36 Root element used to aggregate multiple classes into single document.
37 -->
38 <!ELEMENT classes ( class+ )>
39
40 <!--
41 Root element for a single class.
42 -->
43 <!ELEMENT class ( interfaces, module?, ( field | innerclass | method )*)>
44 <!ATTLIST class access CDATA #REQUIRED>
45 <!ATTLIST class name CDATA #REQUIRED>
46 <!ATTLIST class parent CDATA #REQUIRED>
47 <!ATTLIST class major CDATA #REQUIRED>
48 <!ATTLIST class minor CDATA #REQUIRED>
49 <!ATTLIST class source CDATA #IMPLIED>
50
51 <!ELEMENT interfaces ( interface* )>
52 <!ELEMENT interface EMPTY>
53 <!ATTLIST interface name CDATA #REQUIRED>
54
55 <!ELEMENT module ( requires*, exports*, uses*, provides* )>
56 <!ELEMENT requires EMPTY>
57 <!ATTLIST requires module CDATA #REQUIRED>
58 <!ATTLIST requires access CDATA #REQUIRED>
59 <!ELEMENT exports ( to* )>
60 <!ATTLIST exports name CDATA #REQUIRED>
61 <!ELEMENT to EMPTY>
62 <!ATTLIST to module CDATA #REQUIRED>
63 <!ELEMENT uses EMPTY>
64 <!ATTLIST uses service CDATA #REQUIRED>
65 <!ELEMENT provides EMPTY>
66 <!ATTLIST provides service CDATA #REQUIRED>
67 <!ATTLIST provides impl CDATA #REQUIRED>
68
69 <!ELEMENT field EMPTY>
70 <!ATTLIST field access CDATA #REQUIRED>
71 <!ATTLIST field desc CDATA #REQUIRED>
72 <!ATTLIST field name CDATA #REQUIRED>
73 <!--
74 All characters out of interval 0x20 to 0x7f (inclusive) must
75 be encoded (\uXXXX) and character '\' must be replaced by "\\"
76 -->
77 <!ATTLIST field value CDATA #IMPLIED>
78
79 <!ELEMENT innerclass EMPTY>
80 <!ATTLIST innerclass access CDATA #REQUIRED>
81 <!ATTLIST innerclass innerName CDATA #IMPLIED>
82 <!ATTLIST innerclass name CDATA #REQUIRED>
83 <!ATTLIST innerclass outerName CDATA #IMPLIED>
84
85 <!--
86 Root element for method definition.
87 -->
88 <!ELEMENT method ( exceptions, code? )>
89 <!ATTLIST method access CDATA #REQUIRED>
90 <!ATTLIST method desc CDATA #REQUIRED>
91 <!ATTLIST method name CDATA #REQUIRED>
92
93 <!ELEMENT exceptions ( exception* )>
94 <!ELEMENT exception EMPTY>
95 <!ATTLIST exception name CDATA #REQUIRED>
96
97 <!--
98 code element contains bytecode instructions and definitions for labels, line numbers, try/catch and max
99 -->
100 <!ELEMENT code (( AALOAD | AASTORE | ACONST_NULL | ALOAD | ANEWARRAY | ARETURN | ARRAYLENGTH | ASTORE | ATHROW | BALOAD | BASTORE | BIPUSH | CALOAD | CASTORE | CHECKCAST | D2F | D2I | D2L | DADD | DALOAD | DASTORE | DCMPG | DCMPL | DCONST_0 | DCONST_1 | DDIV | DLOAD | DMUL | DNEG | DREM | DRETURN | DSTORE | DSUB | DUP | DUP2 | DUP2_X1 | DUP2_X2 | DUP_X1 | DUP_X2 | SWAP | F2D | F2I | F2L | FADD | FALOAD | FASTORE | FCMPG | FCMPL | FCONST_0 | FCONST_1 | FCONST_2 | FDIV | FLOAD | FMUL | FNEG | FREM | FRETURN | FSTORE | FSUB | GETFIELD | GETSTATIC | GOTO | I2B | I2C | I2D | I2F | I2L | I2S | IADD | IALOAD | IAND | IASTORE | ICONST_0 | ICONST_1 | ICONST_2 | ICONST_3 | ICONST_4 | ICONST_5 | ICONST_M1 | IDIV | IFEQ | IFGE | IFGT | IFLE | IFLT | IFNE | IFNONNULL | IFNULL | IF_ACMPEQ | IF_ACMPNE | IF_ICMPEQ | IF_ICMPGE | IF_ICMPGT | IF_ICMPLE | IF_ICMPLT | IF_ICMPNE | IINC | ILOAD | IMUL | INEG | INSTANCEOF | INVOKEINTERFACE | INVOKESPECIAL | INVOKESTATIC | INVOKEVIRTUAL | IOR | IREM | IRETURN | ISHL | ISHR | ISTORE | ISUB | IUSHR | IXOR | JSR | L2D | L2F | L2I | LADD | LALOAD | LAND | LASTORE | LCMP | LCONST_0 | LCONST_1 | LDC | LDIV | LLOAD | LMUL | LNEG | LOOKUPSWITCH | LOR | LREM | LRETURN | LSHL | LSHR | LSTORE | LSUB | LUSHR | LXOR | MONITORENTER | MONITOREXIT | MULTIANEWARRAY | NEW | NEWARRAY | NOP | POP | POP2 | PUTFIELD | PUTSTATIC | RET | RETURN | SALOAD | SASTORE | SIPUSH | TABLESWITCH | Label | LineNumber | TryCatch )*, Max)>
101
102 <!ELEMENT Label EMPTY>
103 <!ATTLIST Label name CDATA #REQUIRED>
104
105 <!ELEMENT TryCatch EMPTY>
106 <!ATTLIST TryCatch end CDATA #REQUIRED>
107 <!ATTLIST TryCatch handler CDATA #REQUIRED>
108 <!ATTLIST TryCatch start CDATA #REQUIRED>
109 <!ATTLIST TryCatch type CDATA #IMPLIED>
110
111 <!ELEMENT LineNumber EMPTY>
112 <!ATTLIST LineNumber line CDATA #REQUIRED>
113 <!ATTLIST LineNumber start CDATA #REQUIRED>
114
115 <!ELEMENT Max EMPTY>
116 <!ATTLIST Max maxLocals CDATA #REQUIRED>
117 <!ATTLIST Max maxStack CDATA #REQUIRED>
118
119 <!ELEMENT AALOAD EMPTY>
120 <!ELEMENT AASTORE EMPTY>
121 <!ELEMENT ACONST_NULL EMPTY>
122 <!ELEMENT ALOAD EMPTY>
123 <!ATTLIST ALOAD var CDATA #REQUIRED>
124 <!ELEMENT ANEWARRAY EMPTY>
125 <!ATTLIST ANEWARRAY desc CDATA #REQUIRED>
126 <!ELEMENT ARETURN EMPTY>
127 <!ELEMENT ARRAYLENGTH EMPTY>
128 <!ELEMENT ASTORE EMPTY>
129 <!ATTLIST ASTORE var CDATA #REQUIRED>
130 <!ELEMENT ATHROW EMPTY>
131 <!ELEMENT BALOAD EMPTY>
132 <!ELEMENT BASTORE EMPTY>
133 <!ELEMENT BIPUSH EMPTY>
134 <!ATTLIST BIPUSH value CDATA #REQUIRED>
135 <!ELEMENT CALOAD EMPTY>
136 <!ELEMENT CASTORE EMPTY>
137 <!ELEMENT CHECKCAST EMPTY>
138 <!ATTLIST CHECKCAST desc CDATA #REQUIRED>
139 <!ELEMENT D2F EMPTY>
140 <!ELEMENT D2I EMPTY>
141 <!ELEMENT D2L EMPTY>
142 <!ELEMENT DADD EMPTY>
143 <!ELEMENT DALOAD EMPTY>
144 <!ELEMENT DASTORE EMPTY>
145 <!ELEMENT DCMPG EMPTY>
146 <!ELEMENT DCMPL EMPTY>
147 <!ELEMENT DCONST_0 EMPTY>
148 <!ELEMENT DCONST_1 EMPTY>
149 <!ELEMENT DDIV EMPTY>
150 <!ELEMENT DLOAD EMPTY>
151 <!ATTLIST DLOAD var CDATA #REQUIRED>
152 <!ELEMENT DMUL EMPTY>
153 <!ELEMENT DNEG EMPTY>
154 <!ELEMENT DREM EMPTY>
155 <!ELEMENT DRETURN EMPTY>
156 <!ELEMENT DSTORE EMPTY>
157 <!ATTLIST DSTORE var CDATA #REQUIRED>
158 <!ELEMENT DSUB EMPTY>
159 <!ELEMENT DUP EMPTY>
160 <!ELEMENT DUP2 EMPTY>
161 <!ELEMENT DUP2_X1 EMPTY>
162 <!ELEMENT DUP2_X2 EMPTY>
163 <!ELEMENT DUP_X1 EMPTY>
164 <!ELEMENT DUP_X2 EMPTY>
165 <!ELEMENT SWAP EMPTY>
166 <!ELEMENT F2D EMPTY>
167 <!ELEMENT F2I EMPTY>
168 <!ELEMENT F2L EMPTY>
169 <!ELEMENT FADD EMPTY>
170 <!ELEMENT FALOAD EMPTY>
171 <!ELEMENT FASTORE EMPTY>
172 <!ELEMENT FCMPG EMPTY>
173 <!ELEMENT FCMPL EMPTY>
174 <!ELEMENT FCONST_0 EMPTY>
175 <!ELEMENT FCONST_1 EMPTY>
176 <!ELEMENT FCONST_2 EMPTY>
177 <!ELEMENT FDIV EMPTY>
178 <!ELEMENT FLOAD EMPTY>
179 <!ATTLIST FLOAD var CDATA #REQUIRED>
180 <!ELEMENT FMUL EMPTY>
181 <!ELEMENT FNEG EMPTY>
182 <!ELEMENT FREM EMPTY>
183 <!ELEMENT FRETURN EMPTY>
184 <!ELEMENT FSTORE EMPTY>
185 <!ATTLIST FSTORE var CDATA #REQUIRED>
186 <!ELEMENT FSUB EMPTY>
187 <!ELEMENT GETFIELD EMPTY>
188 <!ATTLIST GETFIELD desc CDATA #REQUIRED>
189 <!ATTLIST GETFIELD name CDATA #REQUIRED>
190 <!ATTLIST GETFIELD owner CDATA #REQUIRED>
191 <!ELEMENT GETSTATIC EMPTY>
192 <!ATTLIST GETSTATIC desc CDATA #REQUIRED>
193 <!ATTLIST GETSTATIC name CDATA #REQUIRED>
194 <!ATTLIST GETSTATIC owner CDATA #REQUIRED>
195 <!ELEMENT GOTO EMPTY>
196 <!ATTLIST GOTO label CDATA #REQUIRED>
197 <!ELEMENT I2B EMPTY>
198 <!ELEMENT I2C EMPTY>
199 <!ELEMENT I2D EMPTY>
200 <!ELEMENT I2F EMPTY>
201 <!ELEMENT I2L EMPTY>
202 <!ELEMENT I2S EMPTY>
203 <!ELEMENT IADD EMPTY>
204 <!ELEMENT IALOAD EMPTY>
205 <!ELEMENT IAND EMPTY>
206 <!ELEMENT IASTORE EMPTY>
207 <!ELEMENT ICONST_0 EMPTY>
208 <!ELEMENT ICONST_1 EMPTY>
209 <!ELEMENT ICONST_2 EMPTY>
210 <!ELEMENT ICONST_3 EMPTY>
211 <!ELEMENT ICONST_4 EMPTY>
212 <!ELEMENT ICONST_5 EMPTY>
213 <!ELEMENT ICONST_M1 EMPTY>
214 <!ELEMENT IDIV EMPTY>
215 <!ELEMENT IFEQ EMPTY>
216 <!ATTLIST IFEQ label CDATA #REQUIRED>
217 <!ELEMENT IFGE EMPTY>
218 <!ATTLIST IFGE label CDATA #REQUIRED>
219 <!ELEMENT IFGT EMPTY>
220 <!ATTLIST IFGT label CDATA #REQUIRED>
221 <!ELEMENT IFLE EMPTY>
222 <!ATTLIST IFLE label CDATA #REQUIRED>
223 <!ELEMENT IFLT EMPTY>
224 <!ATTLIST IFLT label CDATA #REQUIRED>
225 <!ELEMENT IFNE EMPTY>
226 <!ATTLIST IFNE label CDATA #REQUIRED>
227 <!ELEMENT IFNONNULL EMPTY>
228 <!ATTLIST IFNONNULL label CDATA #REQUIRED>
229 <!ELEMENT IFNULL EMPTY>
230 <!ATTLIST IFNULL label CDATA #REQUIRED>
231 <!ELEMENT IF_ACMPEQ EMPTY>
232 <!ATTLIST IF_ACMPEQ label CDATA #REQUIRED>
233 <!ELEMENT IF_ACMPNE EMPTY>
234 <!ATTLIST IF_ACMPNE label CDATA #REQUIRED>
235 <!ELEMENT IF_ICMPEQ EMPTY>
236 <!ATTLIST IF_ICMPEQ label CDATA #REQUIRED>
237 <!ELEMENT IF_ICMPGE EMPTY>
238 <!ATTLIST IF_ICMPGE label CDATA #REQUIRED>
239 <!ELEMENT IF_ICMPGT EMPTY>
240 <!ATTLIST IF_ICMPGT label CDATA #REQUIRED>
241 <!ELEMENT IF_ICMPLE EMPTY>
242 <!ATTLIST IF_ICMPLE label CDATA #REQUIRED>
243 <!ELEMENT IF_ICMPLT EMPTY>
244 <!ATTLIST IF_ICMPLT label CDATA #REQUIRED>
245 <!ELEMENT IF_ICMPNE EMPTY>
246 <!ATTLIST IF_ICMPNE label CDATA #REQUIRED>
247 <!ELEMENT IINC EMPTY>
248 <!ATTLIST IINC inc CDATA #REQUIRED>
249 <!ATTLIST IINC var CDATA #REQUIRED>
250 <!ELEMENT ILOAD EMPTY>
251 <!ATTLIST ILOAD var CDATA #REQUIRED>
252 <!ELEMENT IMUL EMPTY>
253 <!ELEMENT INEG EMPTY>
254 <!ELEMENT INSTANCEOF EMPTY>
255 <!ATTLIST INSTANCEOF desc CDATA #REQUIRED>
256 <!ELEMENT INVOKEINTERFACE EMPTY>
257 <!ATTLIST INVOKEINTERFACE desc CDATA #REQUIRED>
258 <!ATTLIST INVOKEINTERFACE name CDATA #REQUIRED>
259 <!ATTLIST INVOKEINTERFACE owner CDATA #REQUIRED>
260 <!ELEMENT INVOKESPECIAL EMPTY>
261 <!ATTLIST INVOKESPECIAL desc CDATA #REQUIRED>
262 <!ATTLIST INVOKESPECIAL name CDATA #REQUIRED>
263 <!ATTLIST INVOKESPECIAL owner CDATA #REQUIRED>
264 <!ELEMENT INVOKESTATIC EMPTY>
265 <!ATTLIST INVOKESTATIC desc CDATA #REQUIRED>
266 <!ATTLIST INVOKESTATIC name CDATA #REQUIRED>
267 <!ATTLIST INVOKESTATIC owner CDATA #REQUIRED>
268 <!ELEMENT INVOKEVIRTUAL EMPTY>
269 <!ATTLIST INVOKEVIRTUAL desc CDATA #REQUIRED>
270 <!ATTLIST INVOKEVIRTUAL name CDATA #REQUIRED>
271 <!ATTLIST INVOKEVIRTUAL owner CDATA #REQUIRED>
272 <!ELEMENT INVOKEDYNAMIC ( bsmArgs+ )>
273 <!ATTLIST INVOKEDYNAMIC desc CDATA #REQUIRED>
274 <!ATTLIST INVOKEDYNAMIC name CDATA #REQUIRED>
275 <!ATTLIST INVOKEDYNAMIC bsm CDATA #REQUIRED>
276 <!ELEMENT bsmArgs EMPTY>
277 <!ATTLIST bsmArgs cst CDATA #REQUIRED>
278 <!ATTLIST bsmArgs desc CDATA #REQUIRED>
279 <!ELEMENT IOR EMPTY>
280 <!ELEMENT IREM EMPTY>
281 <!ELEMENT IRETURN EMPTY>
282 <!ELEMENT ISHL EMPTY>
283 <!ELEMENT ISHR EMPTY>
284 <!ELEMENT ISTORE EMPTY>
285 <!ATTLIST ISTORE var CDATA #REQUIRED>
286 <!ELEMENT ISUB EMPTY>
287 <!ELEMENT IUSHR EMPTY>
288 <!ELEMENT IXOR EMPTY>
289 <!ELEMENT JSR EMPTY>
290 <!ATTLIST JSR label CDATA #REQUIRED>
291 <!ELEMENT L2D EMPTY>
292 <!ELEMENT L2F EMPTY>
293 <!ELEMENT L2I EMPTY>
294 <!ELEMENT LADD EMPTY>
295 <!ELEMENT LALOAD EMPTY>
296 <!ELEMENT LAND EMPTY>
297 <!ELEMENT LASTORE EMPTY>
298 <!ELEMENT LCMP EMPTY>
299 <!ELEMENT LCONST_0 EMPTY>
300 <!ELEMENT LCONST_1 EMPTY>
301 <!ELEMENT LDC EMPTY>
302 <!--
303 All characters out of interval 0x20 to 0x7f (inclusive) must
304 be encoded (\uXXXX) and character '\' must be replaced by "\\"
305 -->
306 <!ATTLIST LDC cst CDATA #REQUIRED>
307 <!ATTLIST LDC desc CDATA #REQUIRED>
308 <!ELEMENT LDIV EMPTY>
309 <!ELEMENT LLOAD EMPTY>
310 <!ATTLIST LLOAD var CDATA #REQUIRED>
311 <!ELEMENT LMUL EMPTY>
312 <!ELEMENT LNEG EMPTY>
313 <!ELEMENT LOR EMPTY>
314 <!ELEMENT LREM EMPTY>
315 <!ELEMENT LRETURN EMPTY>
316 <!ELEMENT LSHL EMPTY>
317 <!ELEMENT LSHR EMPTY>
318 <!ELEMENT LSTORE EMPTY>
319 <!ATTLIST LSTORE var CDATA #REQUIRED>
320 <!ELEMENT LSUB EMPTY>
321 <!ELEMENT LUSHR EMPTY>
322 <!ELEMENT LXOR EMPTY>
323 <!ELEMENT MONITORENTER EMPTY>
324 <!ELEMENT MONITOREXIT EMPTY>
325 <!ELEMENT MULTIANEWARRAY EMPTY>
326 <!ATTLIST MULTIANEWARRAY desc CDATA #REQUIRED>
327 <!ATTLIST MULTIANEWARRAY dims CDATA #REQUIRED>
328 <!ELEMENT NEW EMPTY>
329 <!ATTLIST NEW desc CDATA #REQUIRED>
330 <!ELEMENT NEWARRAY EMPTY>
331 <!ATTLIST NEWARRAY value CDATA #REQUIRED>
332 <!ELEMENT NOP EMPTY>
333 <!ELEMENT POP EMPTY>
334 <!ELEMENT POP2 EMPTY>
335 <!ELEMENT PUTFIELD EMPTY>
336 <!ATTLIST PUTFIELD desc CDATA #REQUIRED>
337 <!ATTLIST PUTFIELD name CDATA #REQUIRED>
338 <!ATTLIST PUTFIELD owner CDATA #REQUIRED>
339 <!ELEMENT PUTSTATIC EMPTY>
340 <!ATTLIST PUTSTATIC desc CDATA #REQUIRED>
341 <!ATTLIST PUTSTATIC name CDATA #REQUIRED>
342 <!ATTLIST PUTSTATIC owner CDATA #REQUIRED>
343 <!ELEMENT RET EMPTY>
344 <!ATTLIST RET var CDATA #REQUIRED>
345 <!ELEMENT RETURN EMPTY>
346 <!ELEMENT SALOAD EMPTY>
347 <!ELEMENT SASTORE EMPTY>
348 <!ELEMENT SIPUSH EMPTY>
349 <!ATTLIST SIPUSH value CDATA #REQUIRED>
350
351 <!ELEMENT LOOKUPSWITCH ( label+ )>
352 <!ATTLIST LOOKUPSWITCH dflt CDATA #REQUIRED>
353
354 <!ELEMENT TABLESWITCH ( label+ )>
355 <!ATTLIST TABLESWITCH dflt CDATA #REQUIRED>
356 <!ATTLIST TABLESWITCH max CDATA #REQUIRED>
357 <!ATTLIST TABLESWITCH min CDATA #REQUIRED>
358
359 <!ELEMENT label EMPTY>
360 <!ATTLIST label key CDATA #IMPLIED>
361 <!ATTLIST label name CDATA #REQUIRED>
362
+0
-96
org/eclipse/persistence/internal/libraries/asm/xml/package.html less more
0 <html>
1 <!--
2 * ASM XML Adapter
3 * Copyright (c) 2004-2011, Eugene Kuleshov
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the copyright holders nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
28 * THE POSSIBILITY OF SUCH DAMAGE.
29 -->
30 <body>
31 Provides <a href="http://sax.sourceforge.net/">SAX 2.0</a> adapters for ASM
32 visitors to convert classes to and from XML.
33 These adapters can be chained with other SAX compliant content handlers and
34 filters, eg. XSLT or XQuery engines. This package is bundled as
35 a separate <tt>asm-xml.jar</tt> library and requires <tt>asm.jar</tt>.
36 <p>
37 <tt>ASMContentHandler</tt> and <tt>SAXClassAdapter/SAXCodeAdapter</tt>
38 are using <a href="asm-xml.dtd">asm-xml.dtd</a>.
39 Here is the example of bytecode to bytecode XSLT transformation.
40
41 <pre>
42 SAXTransformerFactory saxtf = ( SAXTransformerFactory) TransformerFactory.newInstance();
43 Templates templates = saxtf.newTemplates( xsltSource);
44
45 TransformerHandler handler = saxtf.newTransformerHandler( templates);
46 handler.setResult( new SAXResult( new ASMContentHandler( outputStream, computeMax)));
47
48 ClassReader cr = new ClassReader( bytecode);
49 cr.accept( new SAXClassAdapter( handler, cr.getVersion(), false), false);
50 </pre>
51
52 See JAXP and SAX documentation for more detils.
53
54 <p>
55 There are few illustrations of the bytecode transformation with XSLT in
56 examples directory. The following XSLT procesors has been tested.
57
58 <blockquote>
59 <table border="1" cellspacing="0" cellpadding="3">
60 <tr>
61 <th>Engine</td>
62 <th>javax.xml.transform.TransformerFactory property</td>
63 </tr>
64
65 <tr>
66 <td>jd.xslt</td>
67 <td>jd.xml.xslt.trax.TransformerFactoryImpl</td>
68 </tr>
69
70 <tr>
71 <td>Saxon</td>
72 <td>net.sf.saxon.TransformerFactoryImpl</td>
73 </tr>
74
75 <tr>
76 <td>Caucho</td>
77 <td>com.caucho.xsl.Xsl</td>
78 </tr>
79
80 <tr>
81 <td>Xalan interpeter</td>
82 <td>org.apache.xalan.processor.TransformerFactory</td>
83 </tr>
84
85 <tr>
86 <td>Xalan xsltc</td>
87 <td>org.apache.xalan.xsltc.trax.TransformerFactoryImpl</td>
88 </tr>
89 </table>
90 </blockquote>
91
92 @since ASM 1.4.3
93
94 </body>
95 </html>
00 /*******************************************************************************
1 * Copyright (c) 1998, 2016 Oracle, IBM Corporation and/or its affiliates. All rights reserved.
1 * Copyright (c) 1998, 2020 Oracle, IBM Corporation and/or its affiliates. All rights reserved.
22 * This program and the accompanying materials are made available under the
33 * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
44 * which accompanies this distribution.
403403 { "sdo_missing_schemaLocation", "Referenced schema with uri {0} could not be processed because no schemaLocation attribute was specified."},
404404 { "sdo_invalid_schemaLocation", "Could not create schemaLocation [{0}] for import with uri [{1}]."},
405405 { "sdo_error_processing_referenced_schema", "An {0} occurred processing referenced schema with uri {1} with schemaLocation {2}."},
406 { "sdo_error_deserialization", "Unauthorized deserialization attempt with class {0}."},
406407 { "ox_turn_global_logging_off", " {0} Turning global session logging off."},
407408 { "ox_lowering_global_logging_from_default_info_to_warning", " {0} Lowering global logging from default INFO to WARNING level."},
408409 { "ox_turn_session_logging_off", " {0} Turning session logging off."},
0 /*******************************************************************************
1 * Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved.
2 * This program and the accompanying materials are made available under the
3 * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
4 * which accompanies this distribution.
5 * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
6 * and the Eclipse Distribution License is available at
7 * http://www.eclipse.org/org/documents/edl-v10.php.
8 *
9 * Contributors:
10 * 06/08/2015-2.6 Tomas Kraus
11 * - initial API and implementation.
12 ******************************************************************************/
13 package org.eclipse.persistence.internal.logging;
14
15 import java.security.AccessController;
16 import java.util.HashMap;
17 import java.util.Map;
18
19 import org.eclipse.persistence.internal.localization.LoggingLocalization;
20 import org.eclipse.persistence.internal.localization.i18n.LoggingLocalizationResource;
21 import org.eclipse.persistence.internal.security.PrivilegedAccessHelper;
22 import org.eclipse.persistence.internal.security.PrivilegedGetSystemProperty;
23 import org.eclipse.persistence.logging.AbstractSessionLog;
24 import org.eclipse.persistence.logging.SessionLog;
25
26 /**
27 * INTERNAL:
28 * Log to EclipseLink logger and optionally to standard error output.
29 * Standard error output logging is enabled by:
30 * <ul><li>{@code org.eclipse.persistence.jpa.log.stderr} for all logger categories</li>
31 * <li>{@code org.eclipse.persistence.jpa.<category>.log.stderr} for individual logger category</li></ul>
32 * Logger API is based on {@link SessionLog}.
33 * @since 2.7
34 */
35 public class StdErrLogger {
36
37 /** Logger. */
38 private static final SessionLog LOGGER = AbstractSessionLog.getLog();
39
40 /** Standard error output logger property name prefix. */
41 private static final String PROPERTY_NAME_PREFIX = "eclipselink.log";
42
43 /** Standard error output logger property name suffix. */
44 private static final String PROPERTY_NAME_SUFFIX = "stderr";
45
46 /** Standard error output logger property name components separator. */
47 private static final char PROPERTY_NAME_SEPARATOR = '.';
48
49 /** {@link String} to separate logging category from message text in standard error output. */
50 private static final String CATEGORY_SEPARATOR = ": ";
51
52 /** {@link String} to prefix stack trace message in standard error output. */
53 private static final String STACK_TRACE_PREFIX = " - ";
54
55 /** Standard error output triggers for specific EclipseLink logging categories. */
56 private static final Map<String, Boolean> logEnabledCategory = initLogEnabledCategory();
57
58 // PERF: Global standard error output trigger to check before getting from Map.
59 /** Global standard error output trigger. EclipseLink logging categories are allowed to be sent to standard error
60 * output when value is set to {@code true}. No standard error output will be done when value is set
61 * to {@code false}. */
62 private static final boolean logEnabled = logEnabledCategory != null;
63
64 /**
65 * INTERNAL:
66 * Initialize {@logEnabledCategory} standard error output triggers for specific EclipseLink logging categories.
67 * @return Standard error output triggers {@link Map} for specific EclipseLink logging categories or {@code null}
68 * if no standard error output was enabled.
69 */
70 private static Map<String, Boolean> initLogEnabledCategory() {
71 final int PropertyExtensionsLength = PROPERTY_NAME_PREFIX.length() + PROPERTY_NAME_SUFFIX.length() + 2;
72 final Map<String, Boolean> logEnabledMap = new HashMap<>(SessionLog.loggerCatagories.length);
73 boolean globalTrigger;
74 if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()) {
75 globalTrigger = Boolean.valueOf(AccessController.doPrivileged(new PrivilegedGetSystemProperty(
76 PROPERTY_NAME_PREFIX + PROPERTY_NAME_SEPARATOR + PROPERTY_NAME_SUFFIX)));
77 } else {
78 globalTrigger = Boolean.valueOf(System.getProperty(
79 PROPERTY_NAME_PREFIX + PROPERTY_NAME_SEPARATOR + PROPERTY_NAME_SUFFIX));
80 }
81 boolean enable = globalTrigger;
82 for (final String category : SessionLog.loggerCatagories) {
83 if (globalTrigger) {
84 logEnabledMap.put(category, Boolean.TRUE);
85 } else {
86 StringBuilder propertyKey = new StringBuilder(PropertyExtensionsLength + category.length());
87 propertyKey.append(PROPERTY_NAME_PREFIX);
88 propertyKey.append(PROPERTY_NAME_SEPARATOR);
89 propertyKey.append(category);
90 propertyKey.append(PROPERTY_NAME_SEPARATOR);
91 propertyKey.append(PROPERTY_NAME_SUFFIX);
92 boolean trigger;
93 if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()) {
94 trigger = Boolean.valueOf(AccessController.doPrivileged(
95 new PrivilegedGetSystemProperty(propertyKey.toString())));
96 } else {
97 trigger = Boolean.valueOf(System.getProperty(propertyKey.toString()));
98 }
99 logEnabledMap.put(category, Boolean.valueOf(trigger));
100 enable = enable || trigger;
101 }
102 }
103 if (!enable) {
104 logEnabledMap.clear();
105 }
106 return enable ? logEnabledMap : null;
107 }
108
109 /**
110 * INTERNAL:
111 * Check if a message of the given category would actually be logged to standard error output.
112 * @return Value of {@code true} when a message of the given {@code category} would actually be logged to standard
113 * error output or {@code false} otherwise.
114 */
115 private static final boolean shouldLogToStdErr(final String category) {
116 final Boolean enabled = logEnabledCategory.get(category);
117 return enabled != null ? enabled.booleanValue() : false;
118 }
119
120 /**
121 * INTERNAL:
122 * Log message to standard error output.
123 * @param category The EclipseLink logging category.
124 * @param messageKey The {@link TraceLocalizationResource} log message key.
125 * @param arguments Arguments of the log message.
126 */
127 private static void logStdErr(
128 final String category, final String messageKey, final Object... arguments) {
129 final String message = arguments == null || arguments.length == 0 ?
130 LoggingLocalization.buildMessage(messageKey) : LoggingLocalization.buildMessage(messageKey, arguments);
131 final int messageLength = message != null ? message.length() : 0;
132 final int categoryLength = category != null ? category.length() + CATEGORY_SEPARATOR.length() : 0;
133 if (categoryLength > 0 || messageLength > 0) {
134 final StringBuilder sb = new StringBuilder(categoryLength + messageLength);
135 if (categoryLength > 0) {
136 sb.append(category);
137 sb.append(CATEGORY_SEPARATOR);
138 }
139 if (messageLength > 0) {
140 sb.append(message);
141 }
142 System.err.println(sb.toString());
143 }
144 }
145
146 /**
147 * INTERNAL:
148 * Log message to standard error output.
149 * @param category The EclipseLink logging category.
150 * @param throwable {@link Throwable} to be logged.
151 */
152 private static void logThrowableStdErr(final String category, final Throwable throwable) {
153 final int categoryLength = category != null ? category.length() + CATEGORY_SEPARATOR.length() : 0;
154 for (StackTraceElement ste : throwable.getStackTrace()) {
155 final String message = ste.toString();
156 StringBuilder sb = new StringBuilder(categoryLength + STACK_TRACE_PREFIX.length() + message.length());
157 if (categoryLength > 0) {
158 sb.append(category);
159 sb.append(CATEGORY_SEPARATOR);
160 }
161 sb.append(STACK_TRACE_PREFIX);
162 sb.append(message);
163 System.err.println(sb.toString());
164 }
165 }
166
167 /**
168 * INTERNAL:
169 * Check if a message of the given {@code category} and {@code level} would actually be logged by EclipseLink logger
170 * or to standard error output.
171 * @param level The log request level value.
172 * @param category The EclipseLink logging category.
173 * @return Value of {@code true} if message will be logged or {@code false} otherwise.
174 */
175 public static final boolean shouldLog(final int level, final String category) {
176 return (logEnabled && shouldLogToStdErr(category)) || LOGGER.shouldLog(level, category);
177 }
178
179 /**
180 * INTERNAL:
181 * Log message with no arguments to EclipseLink logger and standard error output.
182 * @param level The log request level value.
183 * @param category The EclipseLink logging category.
184 * @param messageKey The {@link TraceLocalizationResource} log message key.
185 */
186 public static final void log(final int level, final String category, final String messageKey) {
187 LOGGER.log(level, category, messageKey, null);
188 if (logEnabled && shouldLogToStdErr(category)) {
189 logStdErr(category, messageKey);
190 }
191 }
192
193 /**
194 * INTERNAL:
195 * Log message with arguments array to EclipseLink logger and standard error output.
196 * @param level The log request level value.
197 * @param category The EclipseLink logging category.
198 * @param messageKey {@link TraceLocalizationResource} message key.
199 * @param arguments Arguments of the log message.
200 */
201 public static final void log(
202 final int level, final String category, final String messageKey, final Object... arguments) {
203 LOGGER.log(level, category, messageKey, arguments);
204 if (logEnabled && shouldLogToStdErr(category)) {
205 logStdErr(category, messageKey, arguments);
206 }
207 }
208
209 /**
210 * INTERNAL:
211 * Log {@link Throwable} to EclipseLink logger and standard error output.
212 * @param level The log request level value.
213 * @param category The EclipseLink logging category.
214 * @param throwable {@link Throwable} to be logged.
215 */
216 public static final void logThrowable(final int level, final String category, final Throwable throwable) {
217 LOGGER.logThrowable(level, category, throwable);
218 if (logEnabled && shouldLogToStdErr(category)) {
219 logThrowableStdErr(category, throwable);
220 }
221 }
222
223 }
0 /*******************************************************************************
1 * Copyright (c) 1998, 2013 Oracle and/or its affiliates. All rights reserved.
2 * This program and the accompanying materials are made available under the
3 * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
4 * which accompanies this distribution.
5 * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
6 * and the Eclipse Distribution License is available at
7 * http://www.eclipse.org/org/documents/edl-v10.php.
8 *
9 * Contributors:
10 * 10/28/2008-1.1 James Sutherland - initial implementation
11 ******************************************************************************/
12 package org.eclipse.persistence.internal.queries;
13
14 import java.util.ArrayList;
15 import java.util.Collection;
16 import java.util.Vector;
17
18 import org.eclipse.persistence.internal.sessions.AbstractSession;
19
20 /**
21 * PERF: Avoids reflection usage for ArrayList.
22 */
23 public class ArrayListContainerPolicy extends ListContainerPolicy {
24 /**
25 * INTERNAL:
26 * Construct a new policy.
27 */
28 public ArrayListContainerPolicy() {
29 super();
30 }
31
32 /**
33 * INTERNAL:
34 * Construct a new policy for the specified class.
35 */
36 public ArrayListContainerPolicy(Class containerClass) {
37 super(containerClass);
38 }
39
40 /**
41 * INTERNAL:
42 * Construct a new policy for the specified class name.
43 */
44 public ArrayListContainerPolicy(String containerClassName) {
45 super(containerClassName);
46 }
47
48 /**
49 * INTERNAL:
50 * Return a clone of the specified container.
51 */
52 public Object cloneFor(Object container) {
53 if (container == null) {
54 return null;
55 }
56 try {
57 return ((ArrayList)container).clone();
58 } catch (Exception notArrayList) {
59 // Could potentially be another Collection type as well.
60 return new ArrayList((Collection)container);
61 }
62 }
63
64 /**
65 * INTERNAL:
66 * Return an ArrayList from the Vector.
67 */
68 public Object buildContainerFromVector(Vector vector, AbstractSession session) {
69 return new ArrayList(vector);
70 }
71
72 /**
73 * INTERNAL:
74 * Return a new ArrayList.
75 */
76 public Object containerInstance() {
77 return new ArrayList();
78 }
79
80 /**
81 * INTERNAL:
82 * Return a new ArrayList.
83 */
84 public Object containerInstance(int initialCapacity) {
85 return new ArrayList(initialCapacity);
86 }
87 }
0 /*******************************************************************************
1 * Copyright (c) 1998, 2018 Oracle and/or its affiliates. All rights reserved.
2 * This program and the accompanying materials are made available under the
3 * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
4 * which accompanies this distribution.
5 * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
6 * and the Eclipse Distribution License is available at
7 * http://www.eclipse.org/org/documents/edl-v10.php.
8 *
9 * Contributors:
10 * 10/28/2008-1.1 James Sutherland - initial implementation
11 ******************************************************************************/
12 package org.eclipse.persistence.internal.queries;
13
14 import java.util.ArrayList;
15 import java.util.Collection;
16 import java.util.Vector;
17
18 import org.eclipse.persistence.internal.sessions.AbstractSession;
19
20 /**
21 * PERF: Avoids reflection usage for ArrayList.
22 */
23 public class ArrayListContainerPolicy extends ListContainerPolicy {
24 /**
25 * INTERNAL:
26 * Construct a new policy.
27 */
28 public ArrayListContainerPolicy() {
29 super();
30 }
31
32 /**
33 * INTERNAL:
34 * Construct a new policy for the specified class.
35 */
36 public ArrayListContainerPolicy(Class containerClass) {
37 super(containerClass);
38 }
39
40 /**
41 * INTERNAL:
42 * Construct a new policy for the specified class name.
43 */
44 public ArrayListContainerPolicy(String containerClassName) {
45 super(containerClassName);
46 }
47
48 /**
49 * INTERNAL:
50 * Return a clone of the specified container.
51 */
52 public Object cloneFor(Object container) {
53 if (container == null) {
54 return null;
55 }
56 if (container.getClass() == ArrayList.class) {
57 return ((ArrayList)container).clone();
58 }
59
60 // Could potentially be another Collection type as well.
61 return new ArrayList((Collection) container);
62 }
63
64 /**
65 * INTERNAL:
66 * Return an ArrayList from the Vector.
67 */
68 public Object buildContainerFromVector(Vector vector, AbstractSession session) {
69 return new ArrayList(vector);
70 }
71
72 /**
73 * INTERNAL:
74 * Return a new ArrayList.
75 */
76 public Object containerInstance() {
77 return new ArrayList();
78 }
79
80 /**
81 * INTERNAL:
82 * Return a new ArrayList.
83 */
84 public Object containerInstance(int initialCapacity) {
85 return new ArrayList(initialCapacity);
86 }
87 }
0 /*******************************************************************************
1 * Copyright (c) 1998, 2015 Oracle and/or its affiliates. All rights reserved.
2 * This program and the accompanying materials are made available under the
3 * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
4 * which accompanies this distribution.
5 * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
6 * and the Eclipse Distribution License is available at
7 * http://www.eclipse.org/org/documents/edl-v10.php.
8 *
9 * Contributors:
10 * Oracle - initial API and implementation from Oracle TopLink
11 ******************************************************************************/
12 package org.eclipse.persistence.internal.queries;
13
14 import java.util.*;
15
0 /*******************************************************************************
1 * Copyright (c) 1998, 2018 Oracle and/or its affiliates. All rights reserved.
2 * This program and the accompanying materials are made available under the
3 * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
4 * which accompanies this distribution.
5 * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
6 * and the Eclipse Distribution License is available at
7 * http://www.eclipse.org/org/documents/edl-v10.php.
8 *
9 * Contributors:
10 * Oracle - initial API and implementation from Oracle TopLink
11 ******************************************************************************/
12 package org.eclipse.persistence.internal.queries;
13
14 import java.util.*;
15
1616 import org.eclipse.persistence.indirection.IndirectCollectionsFactory;
17 import org.eclipse.persistence.internal.sessions.AbstractSession;
18
19 /**
20 * PERF: Avoids reflection usage for IndirectList.
21 *
22 * @see ContainerPolicy
23 * @author Big Country
24 * @since TOPLink/Java 2.5
25 */
26 public class IndirectListContainerPolicy extends ListContainerPolicy {
27
28 /**
29 * INTERNAL:
30 * Construct a new policy.
31 */
32 public IndirectListContainerPolicy() {
33 super();
34 }
35
36 /**
37 * INTERNAL:
38 * Construct a new policy for the specified class.
39 */
40 public IndirectListContainerPolicy(Class containerClass) {
41 super(containerClass);
42 }
43
44
45 /**
46 * INTERNAL:
47 * Return a clone of the specified container.
48 */
49 public Object cloneFor(Object container) {
50 if (container == null) {
51 return null;
52 }
53 // Use Vector as new objects can have a Vector.
54 try {
55 return ((Vector)container).clone();
56 } catch (Exception notVector) {
57 // Could potentially be another Collection type as well.
58 return IndirectCollectionsFactory.createIndirectList((Collection)container);
59 }
60 }
61
62 /**
63 * INTERNAL:
64 * Just return the Vector.
65 */
66 public Object buildContainerFromVector(Vector vector, AbstractSession session) {
17 import org.eclipse.persistence.internal.sessions.AbstractSession;
18
19 /**
20 * PERF: Avoids reflection usage for IndirectList.
21 *
22 * @see ContainerPolicy
23 * @author Big Country
24 * @since TOPLink/Java 2.5
25 */
26 public class IndirectListContainerPolicy extends ListContainerPolicy {
27
28 /**
29 * INTERNAL:
30 * Construct a new policy.
31 */
32 public IndirectListContainerPolicy() {
33 super();
34 }
35
36 /**
37 * INTERNAL:
38 * Construct a new policy for the specified class.
39 */
40 public IndirectListContainerPolicy(Class containerClass) {
41 super(containerClass);
42 }
43
44
45 /**
46 * INTERNAL:
47 * Return a clone of the specified container.
48 */
49 public Object cloneFor(Object container) {
50 if (container == null) {
51 return null;
52 }
53 // Use Vector as new objects can have a Vector.
54 if (container.getClass() == Vector.class) {
55 return ((Vector)container).clone();
56 }
57
58 // Could potentially be another Collection type as well.
59 return IndirectCollectionsFactory.createIndirectList((Collection)container);
60 }
61
62 /**
63 * INTERNAL:
64 * Just return the Vector.
65 */
66 public Object buildContainerFromVector(Vector vector, AbstractSession session) {
6767 return IndirectCollectionsFactory.createIndirectList(vector);
68 }
69
70 /**
71 * INTERNAL:
72 * Return a new Vector.
73 */
74 public Object containerInstance() {
68 }
69
70 /**
71 * INTERNAL:
72 * Return a new Vector.
73 */
74 public Object containerInstance() {
7575 return IndirectCollectionsFactory.createIndirectList();
76 }
77
78 /**
79 * INTERNAL:
80 * Return a new Vector.
81 */
82 public Object containerInstance(int initialCapacity) {
76 }
77
78 /**
79 * INTERNAL:
80 * Return a new Vector.
81 */
82 public Object containerInstance(int initialCapacity) {
8383 return IndirectCollectionsFactory.createIndirectList(initialCapacity);
84 }
85 }
84 }
85 }
0 /*******************************************************************************
1 * Copyright (c) 1998, 2015 Oracle and/or its affiliates. All rights reserved.
2 * This program and the accompanying materials are made available under the
3 * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
4 * which accompanies this distribution.
5 * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
6 * and the Eclipse Distribution License is available at
7 * http://www.eclipse.org/org/documents/edl-v10.php.
8 *
9 * Contributors:
10 * Oracle - initial API and implementation from Oracle TopLink
11 ******************************************************************************/
12 package org.eclipse.persistence.internal.queries;
13
14 import java.security.AccessController;
15 import java.security.PrivilegedActionException;
16 import java.util.*;
17 import java.lang.reflect.*;
18 import org.eclipse.persistence.descriptors.changetracking.CollectionChangeEvent;
19 import org.eclipse.persistence.exceptions.*;
20 import org.eclipse.persistence.internal.helper.ClassConstants;
21 import org.eclipse.persistence.internal.helper.DatabaseField;
22 import org.eclipse.persistence.internal.helper.Helper;
23 import org.eclipse.persistence.internal.security.PrivilegedAccessHelper;
24 import org.eclipse.persistence.internal.security.PrivilegedMethodInvoker;
25 import org.eclipse.persistence.internal.security.PrivilegedClassForName;
26 import org.eclipse.persistence.internal.security.PrivilegedGetMethod;
27 import org.eclipse.persistence.internal.sessions.AbstractSession;
28 import org.eclipse.persistence.mappings.CollectionMapping;
29 import org.eclipse.persistence.mappings.querykeys.QueryKey;
30
31 /**
32 * <p><b>Purpose</b>: The abstract class for ContainerPolicy's whose container class implements
33 * a container interface.
34 * <p>
35 *
36 * @see CollectionContainerPolicy
37 * @see MapContainerPolicy
38 */
39 public abstract class InterfaceContainerPolicy extends ContainerPolicy {
40
41 /** The concrete container class. */
42 protected Class containerClass;
43 protected String containerClassName;
44
45 /** The method which will return a clone of an instance of the containerClass. */
46 protected transient Method cloneMethod;
47
48 /**
49 * INTERNAL:
50 * Construct a new policy.
51 */
52 public InterfaceContainerPolicy() {
53 super();
54 }
55
56 /**
57 * INTERNAL:
58 * Construct a new policy for the specified class.
59 */
60 public InterfaceContainerPolicy(Class containerClass) {
61 setContainerClass(containerClass);
62 }
63
64 /**
65 * INTERNAL:
66 * Construct a new policy for the specified class name.
67 */
68 public InterfaceContainerPolicy(String containerClassName) {
69 setContainerClassName(containerClassName);
70 }
71
72 /**
73 * INTERNAL:
74 * Return if the policy is equal to the other.
75 * By default if they are the same class, they are considered equal.
76 * This is used for query parse caching.
77 */
78 public boolean equals(Object object) {
79 return super.equals(object) && getContainerClass().equals(((InterfaceContainerPolicy)object).getContainerClass());
80 }
81
82 /**
83 * INTERNAL:
84 * Return a clone of the specified container.
85 */
86 @Override
87 public Object cloneFor(Object container) {
88 if (container == null) {
89 return null;
90 }
91
92 try {
93 return invokeCloneMethodOn(getCloneMethod(), container);
94 } catch (IllegalArgumentException ex) {
95 // container may be a superclass of the concrete container class
96 // so we have to use the right clone method...
97 return invokeCloneMethodOn(getCloneMethod(container.getClass()), container);
98 }
99 }
100
101 /**
102 * INTERNAL:
103 * Convert all the class-name-based settings in this ContainerPolicy to actual class-based
104 * settings. This method is used when converting a project that has been built
105 * with class names to a project with classes.
106 * @param classLoader
107 */
108 @Override
109 public void convertClassNamesToClasses(ClassLoader classLoader){
110 super.convertClassNamesToClasses(classLoader);
111 if (getContainerClassName() == null){
112 return;
113 }
114 Class containerClass = null;
115 try{
116 if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()) {
117 try {
0 /*******************************************************************************
1 * Copyright (c) 1998, 2018 Oracle and/or its affiliates. All rights reserved.
2 * This program and the accompanying materials are made available under the
3 * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
4 * which accompanies this distribution.
5 * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
6 * and the Eclipse Distribution License is available at
7 * http://www.eclipse.org/org/documents/edl-v10.php.
8 *
9 * Contributors:
10 * Oracle - initial API and implementation from Oracle TopLink
11 ******************************************************************************/
12 package org.eclipse.persistence.internal.queries;
13
14 import java.security.AccessController;
15 import java.security.PrivilegedActionException;
16 import java.util.*;
17 import java.util.concurrent.ConcurrentHashMap;
18 import java.lang.ref.ReferenceQueue;
19 import java.lang.ref.WeakReference;
20 import java.lang.reflect.*;
21 import org.eclipse.persistence.descriptors.changetracking.CollectionChangeEvent;
22 import org.eclipse.persistence.exceptions.*;
23 import org.eclipse.persistence.internal.helper.ClassConstants;
24 import org.eclipse.persistence.internal.helper.DatabaseField;
25 import org.eclipse.persistence.internal.helper.Helper;
26 import org.eclipse.persistence.internal.security.PrivilegedAccessHelper;
27 import org.eclipse.persistence.internal.security.PrivilegedMethodInvoker;
28 import org.eclipse.persistence.internal.security.PrivilegedClassForName;
29 import org.eclipse.persistence.internal.security.PrivilegedGetMethod;
30 import org.eclipse.persistence.internal.sessions.AbstractSession;
31 import org.eclipse.persistence.mappings.CollectionMapping;
32 import org.eclipse.persistence.mappings.querykeys.QueryKey;
33
34 /**
35 * <p><b>Purpose</b>: The abstract class for ContainerPolicy's whose container class implements
36 * a container interface.
37 * <p>
38 *
39 * @see CollectionContainerPolicy
40 * @see MapContainerPolicy
41 */
42 public abstract class InterfaceContainerPolicy extends ContainerPolicy {
43
44 private static final ReferenceQueue<Class> refQueue = new ReferenceQueue<>();
45 private static final ConcurrentHashMap<ClassWeakReference, Method> cloneMethodCache = new ConcurrentHashMap<>();
46
47 /** The concrete container class. */
48 protected Class containerClass;
49 protected String containerClassName;
50
51 /** The method which will return a clone of an instance of the containerClass. */
52 protected transient Method cloneMethod;
53
54 /**
55 * INTERNAL:
56 * Construct a new policy.
57 */
58 public InterfaceContainerPolicy() {
59 super();
60 }
61
62 /**
63 * INTERNAL:
64 * Construct a new policy for the specified class.
65 */
66 public InterfaceContainerPolicy(Class containerClass) {
67 setContainerClass(containerClass);
68 }
69
70 /**
71 * INTERNAL:
72 * Construct a new policy for the specified class name.
73 */
74 public InterfaceContainerPolicy(String containerClassName) {
75 setContainerClassName(containerClassName);
76 }
77
78 /**
79 * INTERNAL:
80 * Return if the policy is equal to the other.
81 * By default if they are the same class, they are considered equal.
82 * This is used for query parse caching.
83 */
84 public boolean equals(Object object) {
85 return super.equals(object) && getContainerClass().equals(((InterfaceContainerPolicy)object).getContainerClass());
86 }
87
88 @Override
89 public int hashCode() {
90 int result = super.hashCode();
91 Class containerClass = getContainerClass();
92 result = 31 * result + (containerClass != null ? containerClass.hashCode() : 0);
93 return result;
94 }
95
96 /**
97 * INTERNAL:
98 * Return a clone of the specified container.
99 */
100 @Override
101 public Object cloneFor(Object container) {
102 if (container == null) {
103 return null;
104 }
105
106 Method cloneMethod;
107 Class javaClass = container.getClass();
108 if (javaClass == getContainerClass()) {
109 cloneMethod = getCloneMethod();
110 } else {
111 // container may be a superclass of the concrete container class
112 // so we have to use the right clone method...
113 cloneMethod = getCloneMethod(javaClass);
114 }
115 return invokeCloneMethodOn(cloneMethod, container);
116 }
117
118 /**
119 * INTERNAL:
120 * Convert all the class-name-based settings in this ContainerPolicy to actual class-based
121 * settings. This method is used when converting a project that has been built
122 * with class names to a project with classes.
123 * @param classLoader
124 */
125 @Override
126 public void convertClassNamesToClasses(ClassLoader classLoader){
127 super.convertClassNamesToClasses(classLoader);
128 if (getContainerClassName() == null){
129 return;
130 }
131 Class containerClass = null;
132 try{
133 if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()) {
134 try {
118135 containerClass = AccessController.doPrivileged(new PrivilegedClassForName(getContainerClassName(), true, classLoader));
119 } catch (PrivilegedActionException exception) {
120 throw ValidationException.classNotFoundWhileConvertingClassNames(getContainerClassName(), exception.getException());
121 }
122 } else {
136 } catch (PrivilegedActionException exception) {
137 throw ValidationException.classNotFoundWhileConvertingClassNames(getContainerClassName(), exception.getException());
138 }
139 } else {
123140 containerClass = PrivilegedAccessHelper.getClassForName(getContainerClassName(), true, classLoader);
124 }
125 } catch (ClassNotFoundException exception) {
126 throw ValidationException.classNotFoundWhileConvertingClassNames(getContainerClassName(), exception);
127 }
128 setContainerClass(containerClass);
129 }
130
131 /**
132 * INTERNAL:
133 * Creates a CollectionChangeEvent for the container
134 */
135 @Override
136 public CollectionChangeEvent createChangeEvent(Object collectionOwner, String propertyName, Object collectionChanged, Object elementChanged, int changeType, Integer index, boolean isChangeApplied) {
137 return new CollectionChangeEvent(collectionOwner, propertyName, collectionChanged, elementChanged, changeType, index, false, isChangeApplied);// make the remove change event fire.
138 }
139
140 /**
141 * INTERNAL:
142 * Create a query key that links to the map key
143 * InterfaceContainerPolicy does not support maps, so this method will return null
144 * subclasses will extend this method.
145 */
146 public QueryKey createQueryKeyForMapKey() {
147 return null;
148 }
149
150 /**
151 * INTERNAL:
152 * Return the 'clone()' Method for the container class.
153 * Lazy initialization is used, so we can serialize these things.
154 */
155 public Method getCloneMethod() {
156 if (cloneMethod == null) {
157 setCloneMethod(getCloneMethod(getContainerClass()));
158 }
159 return cloneMethod;
160 }
161
162 /**
163 * INTERNAL:
164 * Return the 'clone()' Method for the specified class.
165 * Return null if the method does not exist anywhere in the hierarchy
166 */
167 protected Method getCloneMethod(Class javaClass) {
168 try {
169 // This must not be set "accessible" - clone() must be public, and some JVM's do not allow access to JDK classes.
170 if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){
171 try {
172 return AccessController.doPrivileged(new PrivilegedGetMethod(javaClass, "clone", (Class[])null, false));
173 } catch (PrivilegedActionException exception) {
174 throw QueryException.methodDoesNotExistInContainerClass("clone", javaClass);
175 }
176 } else {
177 return PrivilegedAccessHelper.getMethod(javaClass, "clone", (Class[])null, false);
178 }
179 } catch (NoSuchMethodException ex) {
180 throw QueryException.methodDoesNotExistInContainerClass("clone", javaClass);
181 }
182 }
183
184 /**
185 * INTERNAL:
186 * Returns the container class to be used with this policy.
187 */
188 @Override
189 public Class getContainerClass() {
190 return containerClass;
191 }
192
193 public String getContainerClassName() {
194 if ((containerClassName == null) && (containerClass != null)) {
195 containerClassName = containerClass.getName();
196 }
197 return containerClassName;
198 }
199
200 /**
201 * INTERNAL:
202 * Return the DatabaseField that represents the key in a DirectMapMapping. If the
203 * keyMapping is not a DirectMapping, this will return null.
204 */
205 public DatabaseField getDirectKeyField(CollectionMapping mapping) {
206 return null;
207 }
208
209 public abstract Class getInterfaceType();
210
211 /**
212 * INTERNAL:
213 * Return whether the iterator has more objects,
214 */
215 @Override
216 public boolean hasNext(Object iterator) {
217 return ((Iterator)iterator).hasNext();
218 }
219
220 /**
221 * INTERNAL:
222 * Invoke the specified clone method on the container,
223 * handling the necessary exceptions.
224 */
225 protected Object invokeCloneMethodOn(Method method, Object container) {
226 try {
227 if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){
228 try {
229 return AccessController.doPrivileged(new PrivilegedMethodInvoker(method, container, (Object[])null));
230 } catch (PrivilegedActionException exception) {
231 Exception throwableException = exception.getException();
232 if (throwableException instanceof IllegalAccessException) {
233 throw QueryException.cannotAccessMethodOnObject(method, container);
234 } else {
235 throw QueryException.methodInvocationFailed(method, container, throwableException);
236 }
237 }
238 } else {
239 return PrivilegedAccessHelper.invokeMethod(method, container, (Object[])null);
240 }
241 } catch (IllegalAccessException ex1) {
242 throw QueryException.cannotAccessMethodOnObject(method, container);
243 } catch (InvocationTargetException ex2) {
244 throw QueryException.methodInvocationFailed(method, container, ex2);
245 }
246 }
247
248 /**
249 * INTERNAL:
250 * Return whether a map key this container policy represents is an attribute
251 * By default this method will return false since only subclasses actually represent maps.
252 */
253 public boolean isMapKeyAttribute(){
254 return false;
255 }
256
257 /**
258 * INTERNAL:
259 * Validate the container type.
260 */
261 @Override
262 public boolean isValidContainerType(Class containerType) {
263 return Helper.classImplementsInterface(containerType, getInterfaceType());
264 }
265
266 /**
267 * INTERNAL:
268 * Return the next object on the queue.
269 * Valid for some subclasses only.
270 */
271 @Override
272 protected Object next(Object iterator) {
273 return ((Iterator)iterator).next();
274 }
275
276 /**
277 * INTERNAL:
278 * Set the Method that will return a clone of an instance of the containerClass.
279 */
280 public void setCloneMethod(Method cloneMethod) {
281 this.cloneMethod = cloneMethod;
282 }
283
284 /**
285 * INTERNAL:
286 * Set the class to use as the container.
287 */
288 @Override
289 public void setContainerClass(Class containerClass) {
290 this.containerClass = containerClass;
291 initializeConstructor();
292 }
293
294 public void setContainerClassName(String containerClassName) {
295 this.containerClassName = containerClassName;
296 }
297
298 /**
299 * INTERNAL:
300 * Return a container populated with the contents of the specified Vector.
301 */
302 @Override
303 public Object buildContainerFromVector(Vector vector, AbstractSession session) {
304 // PERF: If a Vector policy just return the original.
305 if (this.containerClass == ClassConstants.Vector_class) {
306 return vector;
307 }
308 return super.buildContainerFromVector(vector, session);
309 }
310
311 @Override
312 protected Object toStringInfo() {
313 return getContainerClass();
314 }
315 }
141 }
142 } catch (ClassNotFoundException exception) {
143 throw ValidationException.classNotFoundWhileConvertingClassNames(getContainerClassName(), exception);
144 }
145 setContainerClass(containerClass);
146 }
147
148 /**
149 * INTERNAL:
150 * Creates a CollectionChangeEvent for the container
151 */
152 @Override
153 public CollectionChangeEvent createChangeEvent(Object collectionOwner, String propertyName, Object collectionChanged, Object elementChanged, int changeType, Integer index, boolean isChangeApplied) {
154 return new CollectionChangeEvent(collectionOwner, propertyName, collectionChanged, elementChanged, changeType, index, false, isChangeApplied);// make the remove change event fire.
155 }
156
157 /**
158 * INTERNAL:
159 * Create a query key that links to the map key
160 * InterfaceContainerPolicy does not support maps, so this method will return null
161 * subclasses will extend this method.
162 */
163 public QueryKey createQueryKeyForMapKey() {
164 return null;
165 }
166
167 /**
168 * INTERNAL:
169 * Return the 'clone()' Method for the container class.
170 * Lazy initialization is used, so we can serialize these things.
171 */
172 public Method getCloneMethod() {
173 if (cloneMethod == null) {
174 setCloneMethod(getCloneMethod(getContainerClass()));
175 }
176 return cloneMethod;
177 }
178
179 /**
180 * INTERNAL:
181 * Return the 'clone()' Method for the specified class.
182 * Return null if the method does not exist anywhere in the hierarchy
183 */
184 protected Method getCloneMethod(Class javaClass) {
185 for (Object key; (key = refQueue.poll()) != null;) {
186 cloneMethodCache.remove(key);
187 }
188 Method cloneMethod = cloneMethodCache.get(new ClassWeakReference(javaClass));
189 if (cloneMethod != null) {
190 return cloneMethod;
191 }
192 try {
193 // This must not be set "accessible" - clone() must be public, and some JVM's do not allow access to JDK classes.
194 if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){
195 try {
196 cloneMethod = AccessController.doPrivileged(new PrivilegedGetMethod(javaClass, "clone", (Class[])null, false));
197 } catch (PrivilegedActionException exception) {
198 throw QueryException.methodDoesNotExistInContainerClass("clone", javaClass);
199 }
200 } else {
201 cloneMethod = PrivilegedAccessHelper.getMethod(javaClass, "clone", (Class[])null, false);
202 }
203 } catch (NoSuchMethodException ex) {
204 throw QueryException.methodDoesNotExistInContainerClass("clone", javaClass);
205 }
206
207 cloneMethodCache.put(new ClassWeakReference(javaClass, refQueue), cloneMethod);
208 return cloneMethod;
209 }
210
211 /**
212 * INTERNAL:
213 * Returns the container class to be used with this policy.
214 */
215 @Override
216 public Class getContainerClass() {
217 return containerClass;
218 }
219
220 public String getContainerClassName() {
221 if ((containerClassName == null) && (containerClass != null)) {
222 containerClassName = containerClass.getName();
223 }
224 return containerClassName;
225 }
226
227 /**
228 * INTERNAL:
229 * Return the DatabaseField that represents the key in a DirectMapMapping. If the
230 * keyMapping is not a DirectMapping, this will return null.
231 */
232 public DatabaseField getDirectKeyField(CollectionMapping mapping) {
233 return null;
234 }
235
236 public abstract Class getInterfaceType();
237
238 /**
239 * INTERNAL:
240 * Return whether the iterator has more objects,
241 */
242 @Override
243 public boolean hasNext(Object iterator) {
244 return ((Iterator)iterator).hasNext();
245 }
246
247 /**
248 * INTERNAL:
249 * Invoke the specified clone method on the container,
250 * handling the necessary exceptions.
251 */
252 protected Object invokeCloneMethodOn(Method method, Object container) {
253 try {
254 if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){
255 try {
256 return AccessController.doPrivileged(new PrivilegedMethodInvoker(method, container, (Object[])null));
257 } catch (PrivilegedActionException exception) {
258 Exception throwableException = exception.getException();
259 if (throwableException instanceof IllegalAccessException) {
260 throw QueryException.cannotAccessMethodOnObject(method, container);
261 } else {
262 throw QueryException.methodInvocationFailed(method, container, throwableException);
263 }
264 }
265 } else {
266 return PrivilegedAccessHelper.invokeMethod(method, container, (Object[])null);
267 }
268 } catch (IllegalAccessException ex1) {
269 throw QueryException.cannotAccessMethodOnObject(method, container);
270 } catch (InvocationTargetException ex2) {
271 throw QueryException.methodInvocationFailed(method, container, ex2);
272 }
273 }
274
275 /**
276 * INTERNAL:
277 * Return whether a map key this container policy represents is an attribute
278 * By default this method will return false since only subclasses actually represent maps.
279 */
280 public boolean isMapKeyAttribute(){
281 return false;
282 }
283
284 /**
285 * INTERNAL:
286 * Validate the container type.
287 */
288 @Override
289 public boolean isValidContainerType(Class containerType) {
290 return Helper.classImplementsInterface(containerType, getInterfaceType());
291 }
292
293 /**
294 * INTERNAL:
295 * Return the next object on the queue.
296 * Valid for some subclasses only.
297 */
298 @Override
299 protected Object next(Object iterator) {
300 return ((Iterator)iterator).next();
301 }
302
303 /**
304 * INTERNAL:
305 * Set the Method that will return a clone of an instance of the containerClass.
306 */
307 public void setCloneMethod(Method cloneMethod) {
308 this.cloneMethod = cloneMethod;
309 }
310
311 /**
312 * INTERNAL:
313 * Set the class to use as the container.
314 */
315 @Override
316 public void setContainerClass(Class containerClass) {
317 this.containerClass = containerClass;
318 initializeConstructor();
319 }
320
321 public void setContainerClassName(String containerClassName) {
322 this.containerClassName = containerClassName;
323 }
324
325 /**
326 * INTERNAL:
327 * Return a container populated with the contents of the specified Vector.
328 */
329 @Override
330 public Object buildContainerFromVector(Vector vector, AbstractSession session) {
331 // PERF: If a Vector policy just return the original.
332 if (this.containerClass == ClassConstants.Vector_class) {
333 return vector;
334 }
335 return super.buildContainerFromVector(vector, session);
336 }
337
338 @Override
339 protected Object toStringInfo() {
340 return getContainerClass();
341 }
342
343 private static final class ClassWeakReference extends WeakReference<Class> {
344 private final int hash;
345
346 ClassWeakReference(Class referent) {
347 super(referent);
348 hash = referent.hashCode();
349 }
350
351 ClassWeakReference(Class referent, ReferenceQueue<Class> referenceQueue) {
352 super(referent, referenceQueue);
353 hash = referent.hashCode();
354 }
355
356 @Override
357 public int hashCode() {
358 return hash;
359 }
360
361 @Override
362 public boolean equals(Object obj) {
363 if (obj == this) {
364 return true;
365 }
366 if (obj instanceof ClassWeakReference) {
367 return get() == ((ClassWeakReference) obj).get();
368 }
369 return false;
370 }
371
372 @Override
373 public String toString() {
374 Class referent = get();
375 return new StringBuilder("ClassWeakReference: ").append(referent == null ? null : referent).toString();
376 }
377 }
378 }
0 /*******************************************************************************
1 * Copyright (c) 1998, 2013 Oracle and/or its affiliates. All rights reserved.
2 * This program and the accompanying materials are made available under the
3 * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
4 * which accompanies this distribution.
5 * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
6 * and the Eclipse Distribution License is available at
7 * http://www.eclipse.org/org/documents/edl-v10.php.
8 *
9 * Contributors:
10 * 10/28/2008-1.1 James Sutherland - initial implementation
11 ******************************************************************************/
12 package org.eclipse.persistence.internal.queries;
13
14 import java.util.Collection;
15 import java.util.Vector;
16
17 import org.eclipse.persistence.internal.sessions.AbstractSession;
18
19 /**
20 * PERF: Avoids reflection usage for Vectors.
21 */
22 public class VectorContainerPolicy extends ListContainerPolicy {
23 /**
24 * INTERNAL:
25 * Construct a new policy.
26 */
27 public VectorContainerPolicy() {
28 super();
29 }
30
31 /**
32 * INTERNAL:
33 * Construct a new policy for the specified class.
34 */
35 public VectorContainerPolicy(Class containerClass) {
36 super(containerClass);
37 }
38
39 /**
40 * INTERNAL:
41 * Construct a new policy for the specified class name.
42 */
43 public VectorContainerPolicy(String containerClassName) {
44 super(containerClassName);
45 }
46
47 /**
48 * INTERNAL:
49 * Return a clone of the specified container.
50 */
51 public Object cloneFor(Object container) {
52 if (container == null) {
53 return null;
54 }
55 try {
56 return ((Vector)container).clone();
57 } catch (Exception notVector) {
58 // Could potentially be another Collection type as well.
59 return new Vector((Collection)container);
60 }
61 }
62
63 /**
64 * INTERNAL:
65 * Just return the Vector.
66 */
67 public Object buildContainerFromVector(Vector vector, AbstractSession session) {
68 return vector;
69 }
70
71 /**
72 * INTERNAL:
73 * Return a new Vector.
74 */
75 public Object containerInstance() {
76 return new Vector();
77 }
78
79 /**
80 * INTERNAL:
81 * Return a new Vector.
82 */
83 public Object containerInstance(int initialCapacity) {
84 return new Vector(initialCapacity);
85 }
86 }
0 /*******************************************************************************
1 * Copyright (c) 1998, 2018 Oracle and/or its affiliates. All rights reserved.
2 * This program and the accompanying materials are made available under the
3 * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
4 * which accompanies this distribution.
5 * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
6 * and the Eclipse Distribution License is available at
7 * http://www.eclipse.org/org/documents/edl-v10.php.
8 *
9 * Contributors:
10 * 10/28/2008-1.1 James Sutherland - initial implementation
11 ******************************************************************************/
12 package org.eclipse.persistence.internal.queries;
13
14 import java.util.Collection;
15 import java.util.Vector;
16
17 import org.eclipse.persistence.internal.sessions.AbstractSession;
18
19 /**
20 * PERF: Avoids reflection usage for Vectors.
21 */
22 public class VectorContainerPolicy extends ListContainerPolicy {
23 /**
24 * INTERNAL:
25 * Construct a new policy.
26 */
27 public VectorContainerPolicy() {
28 super();
29 }
30
31 /**
32 * INTERNAL:
33 * Construct a new policy for the specified class.
34 */
35 public VectorContainerPolicy(Class containerClass) {
36 super(containerClass);
37 }
38
39 /**
40 * INTERNAL:
41 * Construct a new policy for the specified class name.
42 */
43 public VectorContainerPolicy(String containerClassName) {
44 super(containerClassName);
45 }
46
47 /**
48 * INTERNAL:
49 * Return a clone of the specified container.
50 */
51 public Object cloneFor(Object container) {
52 if (container == null) {
53 return null;
54 }
55 if (container.getClass() == Vector.class) {
56 return ((Vector) container).clone();
57 }
58
59 // Could potentially be another Collection type as well.
60 return new Vector((Collection) container);
61 }
62
63 /**
64 * INTERNAL:
65 * Just return the Vector.
66 */
67 public Object buildContainerFromVector(Vector vector, AbstractSession session) {
68 return vector;
69 }
70
71 /**
72 * INTERNAL:
73 * Return a new Vector.
74 */
75 public Object containerInstance() {
76 return new Vector();
77 }
78
79 /**
80 * INTERNAL:
81 * Return a new Vector.
82 */
83 public Object containerInstance(int initialCapacity) {
84 return new Vector(initialCapacity);
85 }
86 }
1414 * instead of throwing NPE during deploy validation.
1515 * 30/05/2012-2.4 Guy Pelletier
1616 * - 354678: Temp classloader is still being used during metadata processing
17 *
17 * 06/16/2015-2.7 Tomas Kraus
18 * - 254437: Added getSystemProperty methods and fixed line separator property.
1819 ******************************************************************************/
1920 package org.eclipse.persistence.internal.security;
2021
6162 "org.eclipse.persistence.fetchgroupmonitor", "org.eclipse.persistence.querymonitor", "SAP_J2EE_Engine_Version",
6263 PersistenceUnitProperties.ECLIPSELINK_PERSISTENCE_XML, PersistenceUnitProperties.JAVASE_DB_INTERACTION,
6364 PersistenceUnitProperties.LOGGING_FILE, PersistenceUnitProperties.LOGGING_LEVEL,
64 SystemProperties.ARCHIVE_FACTORY, SystemProperties.DO_NOT_PROCESS_XTOMANY_FOR_QBE, SystemProperties.RECORD_STACK_ON_LOCK,
65 SystemProperties.ARCHIVE_FACTORY, SystemProperties.ENFORCE_TARGET_SERVER, SystemProperties.RECORD_STACK_ON_LOCK,
6566 SystemProperties.WEAVING_OUTPUT_PATH, SystemProperties.WEAVING_SHOULD_OVERWRITE, SystemProperties.WEAVING_REFLECTIVE_INTROSPECTION,
66 SystemProperties.DO_NOT_PROCESS_XTOMANY_FOR_QBE,
67 SystemProperties.DO_NOT_PROCESS_XTOMANY_FOR_QBE, SystemProperties.ONETOMANY_DEFER_INSERTS,
6768 ServerPlatformBase.JMX_REGISTER_RUN_MBEAN_PROPERTY, ServerPlatformBase.JMX_REGISTER_DEV_MBEAN_PROPERTY,
6869 XMLPlatformFactory.XML_PLATFORM_PROPERTY};
6970 private final static Set<String> legalPropertiesSet = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(legalProperties)));
169170
170171 /**
171172 * Gets the class loader for a given class. Wraps the call in a privileged block if necessary
173 * @deprecated Will be removed in next version.
172174 */
173175 public static ClassLoader privilegedGetClassLoaderForClass(final Class clazz) {
174176 try{
436438 }
437439
438440 /**
441 * INTERNAL:
439442 * Get the line separator character.
440 * Previous versions of TopLink always did this in a privileged block so we will continue to do so.
441 */
442 public static String getLineSeparator() {
443 if (shouldUsePrivilegedAccess()) {
444 return AccessController.doPrivileged(new PrivilegedGetSystemProperty("file.separator"));
445 } else {
446 return org.eclipse.persistence.internal.helper.Helper.cr();
447 }
443 * @return The {@link String} containing the platform-appropriate characters for line separator.
444 */
445 public static final String getLineSeparator() {
446 return getSystemProperty("line.separator");
448447 }
449448
450449 /**
1515 * - 440594: Tolerate invalid NamedQuery at EntityManager creation.
1616 * 09/03/2015 - Will Dazey
1717 * - 456067 : Added support for defining query timeout units
18 * 09/28/2015 - Will Dazey
19 * - 478331 : Added support for defining local or server as the default locale for obtaining timestamps
1820 ******************************************************************************/
1921 package org.eclipse.persistence.internal.sessions;
2022
219221 addProp(new BooleanProp(PersistenceUnitProperties.MULTITENANT_SHARED_EMF, "true"));
220222 //Enhancement
221223 addProp(new QueryTimeoutUnitProp());
224 addProp(new BooleanProp(PersistenceUnitProperties.USE_LOCAL_TIMESTAMP, "false"));
222225 }
223226
224227 Prop(String name) {
00 /*******************************************************************************
1 * Copyright (c) 2015, 2016 Oracle and/or its affiliates. All rights reserved.
1 * Copyright (c) 2015, 2020 Oracle and/or its affiliates. All rights reserved.
22 * This program and the accompanying materials are made available under the
33 * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
44 * which accompanies this distribution.
3333 }
3434
3535 /**
36 * {@see ConstraintViolation#getMessage}
36 * @see ConstraintViolation#getMessage
3737 */
3838 public String getMessage() {
3939 return constraintViolation.getMessage();
4040 }
4141
4242 /**
43 * {@see ConstraintViolation#getMessageTemplate}
43 * @see ConstraintViolation#getMessageTemplate
4444 */
4545 public String getMessageTemplate() {
4646 return constraintViolation.getMessageTemplate();
4747 }
4848
4949 /**
50 * {@see ConstraintViolation#getRootBean}
50 * @see ConstraintViolation#getRootBean
5151 */
5252 public T getRootBean() {
5353 return constraintViolation.getRootBean();
5454 }
5555
5656 /**
57 * {@see ConstraintViolation#getRootBeanClass}
57 * @see ConstraintViolation#getRootBeanClass
5858 */
5959 public Class<T> getRootBeanClass() {
6060 return constraintViolation.getRootBeanClass();
6161 }
6262
6363 /**
64 * {@see ConstraintViolation#getLeafBean}
64 * @see ConstraintViolation#getLeafBean
6565 */
6666 public Object getLeafBean() {
6767 return constraintViolation.getLeafBean();
6868 }
6969
7070 /**
71 * {@see ConstraintViolation#getExecutableParameters}
71 * @see ConstraintViolation#getExecutableParameters
7272 */
7373 public Object[] getExecutableParameters() {
7474 return constraintViolation.getExecutableParameters();
7575 }
7676
7777 /**
78 * {@see ConstraintViolation#getExecutableReturnValue}
78 * @see ConstraintViolation#getExecutableReturnValue
7979 */
8080 public Object getExecutableReturnValue() {
8181 return constraintViolation.getExecutableReturnValue();
8282 }
8383
8484 /**
85 * {@see ConstraintViolation#getPropertyPath}
85 * @see ConstraintViolation#getPropertyPath
8686 */
8787 public Path getPropertyPath() {
8888 return constraintViolation.getPropertyPath();
8989 }
9090
9191 /**
92 * {@see ConstraintViolation#getInvalidValue}
92 * @see ConstraintViolation#getInvalidValue
9393 */
9494 public Object getInvalidValue() {
9595 return constraintViolation.getInvalidValue();
9696 }
9797
9898 /**
99 * {@see ConstraintViolation#getConstraintDescriptor}
99 * @see ConstraintViolation#getConstraintDescriptor
100100 */
101101 public ConstraintDescriptor<?> getConstraintDescriptor() {
102102 return constraintViolation.getConstraintDescriptor();
1818 import java.text.*;
1919 import java.util.Date;
2020 import org.eclipse.persistence.internal.security.*;
21 import org.eclipse.persistence.internal.helper.Helper;
2122
2223 /**
2324 * <p>
3334
3435 // Line separator string. This is the value of the line.separator
3536 // property at the moment that the SimpleFormatter was created.
36 private String lineSeparator = PrivilegedAccessHelper.getLineSeparator();
37 private final String lineSeparator = Helper.cr();
3738
3839 /**
3940 * Format the given LogRecord.
00 /*******************************************************************************
1 * Copyright (c) 1998, 2014 Oracle and/or its affiliates. All rights reserved.
1 * Copyright (c) 1998, 2018 Oracle and/or its affiliates. All rights reserved.
22 * This program and the accompanying materials are made available under the
33 * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
44 * which accompanies this distribution.
1515 * 10/25/2012-2.5 Guy Pelletier
1616 * - 374688: JPA 2.1 Converter support
1717 * 02/11/2013-2.5 Guy Pelletier
18 * - 365931: @JoinColumn(name="FK_DEPT",insertable = false, updatable = true) causes INSERT statement to include this data value that it is associated with
18 * - 365931: @JoinColumn(name="FK_DEPT",insertable = false, updatable = true) causes INSERT statement to include this data value that it is associated with
19 * 03/14/2018-2.7 Will Dazey
20 * - 500753: Synchronize initialization of InsertQuery
1921 ******************************************************************************/
2022 package org.eclipse.persistence.mappings;
2123
3133
3234 import org.eclipse.persistence.descriptors.ClassDescriptor;
3335 import org.eclipse.persistence.descriptors.DescriptorEvent;
34 import org.eclipse.persistence.descriptors.DescriptorEventManager;
36 import org.eclipse.persistence.descriptors.DescriptorEventManager;
3537 import org.eclipse.persistence.descriptors.changetracking.AttributeChangeTrackingPolicy;
3638 import org.eclipse.persistence.descriptors.changetracking.DeferredChangeDetectionPolicy;
3739 import org.eclipse.persistence.descriptors.changetracking.ObjectChangeTrackingPolicy;
25242526
25252527 /**
25262528 * INTERNAL:
2527 * Returns clone of InsertObjectQuery from the reference descriptor, if it is not set - create it.
2529 * Returns a clone of InsertObjectQuery from the ClassDescriptor's DescriptorQueryManager or a new one
25282530 */
25292531 protected InsertObjectQuery getInsertObjectQuery(AbstractSession session, ClassDescriptor desc) {
2530 InsertObjectQuery insertQuery = desc.getQueryManager().getInsertQuery();
2531 if (insertQuery == null) {
2532 insertQuery = new InsertObjectQuery();
2533 desc.getQueryManager().setInsertQuery(insertQuery);
2534 }
2535 if (insertQuery.getModifyRow() == null) {
2536 AbstractRecord modifyRow = new DatabaseRecord();
2537 for (int i = 0; i < getTargetForeignKeyFields().size(); i++) {
2538 DatabaseField field = getTargetForeignKeyFields().elementAt(i);
2539 modifyRow.put(field, null);
2540 }
2541 desc.getObjectBuilder().buildTemplateInsertRow(session, modifyRow);
2542 getContainerPolicy().addFieldsForMapKey(modifyRow);
2543 if(this.listOrderField != null) {
2544 modifyRow.put(this.listOrderField, null);
2545 }
2546 insertQuery.setModifyRow(modifyRow);
2547 }
2532 InsertObjectQuery insertQuery = desc.getQueryManager().getInsertQuery();
2533 if (insertQuery == null) {
2534 insertQuery = new InsertObjectQuery();
2535 insertQuery.setDescriptor(desc);
2536 insertQuery.checkPrepare(session, insertQuery.getTranslationRow());
2537 } else {
2538 // Ensure the query has been prepared.
2539 insertQuery.checkPrepare(session, insertQuery.getTranslationRow());
2540 insertQuery = (InsertObjectQuery)insertQuery.clone();
2541 }
2542 insertQuery.setIsExecutionClone(true);
25482543 return insertQuery;
25492544 }
25502545
25552550 public InsertObjectQuery getAndPrepareModifyQueryForInsert(ObjectLevelModifyQuery originalQuery, Object object) {
25562551 AbstractSession session = originalQuery.getSession();
25572552 ClassDescriptor objReferenceDescriptor = getReferenceDescriptor(object.getClass(), session);
2558 InsertObjectQuery insertQueryFromDescriptor = getInsertObjectQuery(session, objReferenceDescriptor);
2559 insertQueryFromDescriptor.checkPrepare(session, insertQueryFromDescriptor.getModifyRow());
2560
2561 InsertObjectQuery insertQuery = (InsertObjectQuery)insertQueryFromDescriptor.clone();
2553 InsertObjectQuery insertQuery = getInsertObjectQuery(session, objReferenceDescriptor);
2554
25622555 insertQuery.setObject(object);
25632556 insertQuery.setDescriptor(objReferenceDescriptor);
25642557
0 /*******************************************************************************
1 * Copyright (c) 1998, 2014 Oracle and/or its affiliates. All rights reserved.
2 * This program and the accompanying materials are made available under the
3 * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
4 * which accompanies this distribution.
5 * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
6 * and the Eclipse Distribution License is available at
7 * http://www.eclipse.org/org/documents/edl-v10.php.
8 *
9 * Contributors:
10 * Oracle - initial API and implementation from Oracle TopLink
11 * 07/19/2011-2.2.1 Guy Pelletier
12 * - 338812: ManyToMany mapping in aggregate object violate integrity constraint on deletion
13 ******************************************************************************/
14 package org.eclipse.persistence.mappings;
15
16 import java.util.*;
17
18 import org.eclipse.persistence.exceptions.*;
19 import org.eclipse.persistence.expressions.*;
20 import org.eclipse.persistence.internal.helper.*;
21 import org.eclipse.persistence.internal.identitymaps.*;
22 import org.eclipse.persistence.internal.queries.*;
23 import org.eclipse.persistence.internal.sessions.*;
24 import org.eclipse.persistence.queries.*;
25 import org.eclipse.persistence.sessions.DatabaseRecord;
26 import org.eclipse.persistence.internal.descriptors.CascadeLockingPolicy;
27 import org.eclipse.persistence.descriptors.ClassDescriptor;
28 import org.eclipse.persistence.internal.descriptors.ObjectBuilder;
29 import org.eclipse.persistence.internal.expressions.FieldExpression;
30 import org.eclipse.persistence.internal.expressions.ParameterExpression;
31 import org.eclipse.persistence.internal.expressions.SQLUpdateStatement;
32 import org.eclipse.persistence.mappings.foundation.MapComponentMapping;
33
34 /**
35 * <p><b>Purpose</b>: This mapping is used to represent the
36 * typical RDBMS relationship between a single
37 * source object and collection of target objects; where,
38 * on the database, the target objects have references
39 * (foreign keys) to the source object.
40 *
41 * @author Sati
42 * @since TOPLink/Java 1.0
43 */
44 public class OneToManyMapping extends CollectionMapping implements RelationalMapping, MapComponentMapping {
45
46 /** Used for data modification events. */
47 protected static final String PostInsert = "postInsert";
48 protected static final String ObjectRemoved = "objectRemoved";
49 protected static final String ObjectAdded = "objectAdded";
50
51 /** The target foreign key fields that reference the sourceKeyFields. */
52 protected Vector<DatabaseField> targetForeignKeyFields;
53
54 /** The (typically primary) source key fields that are referenced by the targetForeignKeyFields. */
55 protected Vector<DatabaseField> sourceKeyFields;
56
57 /** This maps the target foreign key fields to the corresponding (primary) source key fields. */
58 protected transient Map<DatabaseField, DatabaseField> targetForeignKeysToSourceKeys;
59
60 /** This maps the (primary) source key fields to the corresponding target foreign key fields. */
61 protected transient Map<DatabaseField, DatabaseField> sourceKeysToTargetForeignKeys;
62
63 /** All targetForeignKeyFields should have the same table.
64 * Used only in case data modification events required.
65 **/
66 protected transient DatabaseTable targetForeignKeyTable;
67
68 /** Primary keys of targetForeignKeyTable:
69 * the same as referenceDescriptor().getPrimaryKeyFields() in case the table is default table of reference descriptor;
70 * otherwise contains secondary table's primary key fields in the same order as default table primary keys mapped to them.
71 * Used only in case data modification events required.
72 **/
73 protected transient List<DatabaseField> targetPrimaryKeyFields;
74
75 /**
76 * Keep a reference to the source and target expressions to post initialize
77 * when building a selection criteria early.
78 */
79 protected transient List<Expression> sourceExpressionsToPostInitialize;
80 protected transient List<Expression> targetExpressionsToPostInitialize;
81
82 /**
83 * Query used to update a single target row setting its foreign key to point to the source.
84 * Run once for each target added to the source.
85 * Example:
86 * for Employee with managedEmployees attribute mapped with UnidirectionalOneToMany
87 * the query looks like:
88 * UPDATE EMPLOYEE SET MANAGER_ID = 1 WHERE (EMP_ID = 2)
89 * where 1 is id of the source, and 2 is the id of the target to be added.
90 * Used only in case data modification events required.
91 **/
92 protected DataModifyQuery addTargetQuery;
93 protected boolean hasCustomAddTargetQuery;
94
95 /**
96 * Query used to update a single target row changing its foreign key value from the one pointing to the source to null.
97 * Run once for each target removed from the source.
98 * Example:
99 * for Employee with managedEmployees attribute mapped with UnidirectionalOneToMany
100 * the query looks like:
101 * UPDATE EMPLOYEE SET MANAGER_ID = null WHERE ((MANAGER_ID = 1) AND (EMP_ID = 2))
102 * where 1 is id of the source, and 2 is the id of the target to be removed.
103 * Used only in case data modification events required.
104 **/
105 protected DataModifyQuery removeTargetQuery;
106 protected boolean hasCustomRemoveTargetQuery;
107
108 /**
109 * Query used to update all target rows changing target foreign key value from the one pointing to the source to null.
110 * Run before the source object is deleted.
111 * Example:
112 * for Employee with managedEmployees attribute mapped with UnidirectionalOneToMany
113 * the query looks like:
114 * UPDATE EMPLOYEE SET MANAGER_ID = null WHERE (MANAGER_ID = 1)
115 * where 1 is id of the source to be deleted.
116 * Used only in case data modification events required.
117 **/
118 protected DataModifyQuery removeAllTargetsQuery;
119 protected boolean hasCustomRemoveAllTargetsQuery;
120
121 /**
122 * PUBLIC:
123 * Default constructor.
124 */
125 public OneToManyMapping() {
126 super();
127
128 this.targetForeignKeysToSourceKeys = new HashMap(2);
129 this.sourceKeysToTargetForeignKeys = new HashMap(2);
130
131 this.sourceKeyFields = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(1);
132 this.targetForeignKeyFields = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(1);
133 this.sourceExpressionsToPostInitialize = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(1);
134 this.targetExpressionsToPostInitialize = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(1);
135
136 this.deleteAllQuery = new DeleteAllQuery();
137 this.removeTargetQuery = new DataModifyQuery();
138 this.removeAllTargetsQuery = new DataModifyQuery();
139
140 this.isListOrderFieldSupported = true;
141 }
142
143 /**
144 * INTERNAL:
145 */
146 @Override
147 public boolean isRelationalMapping() {
148 return true;
149 }
150
151 /**
152 * INTERNAL:
153 * Add the associated fields to the appropriate collections.
154 */
155 @Override
156 public void addTargetForeignKeyField(DatabaseField targetForeignKeyField, DatabaseField sourceKeyField) {
157 getTargetForeignKeyFields().addElement(targetForeignKeyField);
158 getSourceKeyFields().addElement(sourceKeyField);
159 }
160
161 /**
162 * PUBLIC:
163 * Define the target foreign key relationship in the one-to-many mapping.
164 * This method is used for composite target foreign key relationships.
165 * That is, the target object's table has multiple foreign key fields
166 * that are references to
167 * the source object's (typically primary) key fields.
168 * Both the target foreign key field name and the corresponding
169 * source primary key field name must be specified.
170 * Because the target object's table must store a foreign key to the source table,
171 * the target object must map that foreign key, this is normally done through a
172 * one-to-one mapping back-reference. Other options include:
173 * <ul>
174 * <li> use a DirectToFieldMapping and maintain the
175 * foreign key fields directly in the target
176 * <li> use a ManyToManyMapping
177 * <li> use an AggregateCollectionMapping
178 * </ul>
179 * @see DirectToFieldMapping
180 * @see ManyToManyMapping
181 * @see AggregateCollectionMapping
182 */
183 public void addTargetForeignKeyFieldName(String targetForeignKeyFieldName, String sourceKeyFieldName) {
184 addTargetForeignKeyField(new DatabaseField(targetForeignKeyFieldName), new DatabaseField(sourceKeyFieldName));
185 }
186
187 /**
188 * INTERNAL:
189 * Verifies listOrderField's table: it must be the same table that contains all target foreign keys.
190 * Precondition: listOrderField != null.
191 */
192 protected void buildListOrderField() {
193 if(this.listOrderField.hasTableName()) {
194 if(!this.targetForeignKeyTable.equals(this.listOrderField.getTable())) {
195 throw DescriptorException.listOrderFieldTableIsWrong(this.getDescriptor(), this, this.listOrderField.getTable(), this.targetForeignKeyTable);
196 }
197 } else {
198 listOrderField.setTable(this.targetForeignKeyTable);
199 }
200 this.listOrderField = this.getReferenceDescriptor().buildField(this.listOrderField, this.targetForeignKeyTable);
201 }
202
203 /**
204 * The selection criteria are created with target foreign keys and source "primary" keys.
205 * These criteria are then used to read the target records from the table.
206 * These criteria are also used as the default "delete all" criteria.
207 *
208 * CR#3922 - This method is almost the same as buildSelectionCriteria() the difference
209 * is that TargetForeignKeysToSourceKeys contains more information after login then SourceKeyFields
210 * contains before login.
211 */
212 protected Expression buildDefaultSelectionCriteriaAndAddFieldsToQuery() {
213 Expression selectionCriteria = null;
214 Expression builder = new ExpressionBuilder();
215
216 for (Iterator keys = getTargetForeignKeysToSourceKeys().keySet().iterator();
217 keys.hasNext();) {
218 DatabaseField targetForeignKey = (DatabaseField)keys.next();
219 DatabaseField sourceKey = getTargetForeignKeysToSourceKeys().get(targetForeignKey);
220
221 Expression partialSelectionCriteria = builder.getField(targetForeignKey).equal(builder.getParameter(sourceKey));
222 selectionCriteria = partialSelectionCriteria.and(selectionCriteria);
223 }
224 getContainerPolicy().addAdditionalFieldsToQuery(getSelectionQuery(), builder);
225
226 return selectionCriteria;
227 }
228
229 /**
230 * This method would allow customers to get the potential selection criteria for a mapping
231 * prior to initialization. This would allow them to more easily create an amendment method
232 * that would amend the SQL for the join.
233 *
234 * CR#3922 - This method is almost the same as buildDefaultSelectionCriteria() the difference
235 * is that TargetForeignKeysToSourceKeys contains more information after login then SourceKeyFields
236 * contains before login.
237 */
238 public Expression buildSelectionCriteria() {
239 //CR3922
240 Expression selectionCriteria = null;
241 Expression builder = new ExpressionBuilder();
242
243 Enumeration sourceKeys = getSourceKeyFields().elements();
244 for (Enumeration targetForeignKeys = getTargetForeignKeyFields().elements();
245 targetForeignKeys.hasMoreElements();) {
246 DatabaseField targetForeignKey = (DatabaseField)targetForeignKeys.nextElement();
247 DatabaseField sourceKey = (DatabaseField)sourceKeys.nextElement();
248 Expression targetExpression = builder.getField(targetForeignKey);
249 Expression sourceExpression = builder.getParameter(sourceKey);
250 // store the expressions in order to initialize their fields later
251 this.targetExpressionsToPostInitialize.add(targetExpression);
252 this.sourceExpressionsToPostInitialize.add(sourceExpression);
253
254 Expression partialSelectionCriteria = targetExpression.equal(sourceExpression);
255 selectionCriteria = partialSelectionCriteria.and(selectionCriteria);
256 }
257 return selectionCriteria;
258 }
259
260 /**
261 * INTERNAL:
262 * This method is used to store the FK fields that can be cached that correspond to noncacheable mappings
263 * the FK field values will be used to re-issue the query when cloning the shared cache entity
264 */
265 @Override
266 public void collectQueryParameters(Set<DatabaseField> cacheFields){
267 for (DatabaseField field : getSourceKeyFields()) {
268 cacheFields.add(field);
269 }
270 }
271
272 /**
273 * INTERNAL:
274 * Clone the appropriate attributes.
275 */
276 @Override
277 public Object clone() {
278 OneToManyMapping clone = (OneToManyMapping)super.clone();
279 clone.setTargetForeignKeysToSourceKeys(new HashMap(getTargetForeignKeysToSourceKeys()));
280
281 if (addTargetQuery != null){
282 clone.addTargetQuery = (DataModifyQuery) this.addTargetQuery.clone();
283 }
284 clone.removeTargetQuery = (DataModifyQuery) this.removeTargetQuery.clone();
285 clone.removeAllTargetsQuery = (DataModifyQuery) this.removeAllTargetsQuery.clone();
286
287 return clone;
288 }
289
290 /**
291 * INTERNAL
292 * Called when a DatabaseMapping is used to map the key in a collection. Returns the key.
293 */
294 public Object createMapComponentFromRow(AbstractRecord dbRow, ObjectBuildingQuery query, CacheKey parentCacheKey, AbstractSession session, boolean isTargetProtected){
295 return session.executeQuery(getSelectionQuery(), dbRow);
296 }
297
298 /**
299 * Delete all the reference objects with a single query.
300 */
301 protected void deleteAll(DeleteObjectQuery query, AbstractSession session) throws DatabaseException {
302 Object attribute = getAttributeValueFromObject(query.getObject());
303 if (usesIndirection()) {
304 if (!this.indirectionPolicy.objectIsInstantiated(attribute)) {
305 // An empty Vector indicates to DeleteAllQuery that no objects should be removed from cache
306 ((DeleteAllQuery)this.deleteAllQuery).executeDeleteAll(session.getSessionForClass(this.referenceClass), query.getTranslationRow(), new Vector(0));
307 return;
308 }
309 }
310 Object referenceObjects = getRealCollectionAttributeValueFromObject(query.getObject(), session);
311 // PERF: Avoid delete if empty.
312 if (session.isUnitOfWork() && this.containerPolicy.isEmpty(referenceObjects)) {
313 return;
314 }
315 ((DeleteAllQuery)this.deleteAllQuery).executeDeleteAll(session.getSessionForClass(getReferenceClass()), query.getTranslationRow(), this.containerPolicy.vectorFor(referenceObjects, session));
316 }
317
318 /**
319 * This method will make sure that all the records privately owned by this mapping are
320 * actually removed. If such records are found then those are all read and removed one
321 * by one along with their privately owned parts.
322 */
323 protected void deleteReferenceObjectsLeftOnDatabase(DeleteObjectQuery query) throws DatabaseException, OptimisticLockException {
324 Object objects = readPrivateOwnedForObject(query);
325
326 // Delete all these object one by one.
327 ContainerPolicy cp = getContainerPolicy();
328 for (Object iter = cp.iteratorFor(objects); cp.hasNext(iter);) {
329 query.getSession().deleteObject(cp.next(iter, query.getSession()));
330 }
331 }
332
333 /**
334 * INTERNAL:
335 * Extract the source primary key value from the target row.
336 * Used for batch reading, most following same order and fields as in the mapping.
337 */
338 @Override
339 protected Object extractKeyFromTargetRow(AbstractRecord row, AbstractSession session) {
340 int size = this.sourceKeyFields.size();
341 Object[] key = new Object[size];
342 ConversionManager conversionManager = session.getDatasourcePlatform().getConversionManager();
343 for (int index = 0; index < size; index++) {
344 DatabaseField targetField = this.targetForeignKeyFields.get(index);
345 DatabaseField sourceField = this.sourceKeyFields.get(index);
346 Object value = row.get(targetField);
347 // Must ensure the classification gets a cache hit.
348 try {
349 value = conversionManager.convertObject(value, sourceField.getType());
350 } catch (ConversionException e) {
351 throw ConversionException.couldNotBeConverted(this, getDescriptor(), e);
352 }
353 key[index] = value;
354 }
355 return new CacheId(key);
356 }
357
358 /**
359 * Extract the key field values from the specified row.
360 * Used for batch reading. Keep the fields in the same order
361 * as in the targetForeignKeysToSourceKeys map.
362 */
363 @Override
364 protected Object extractBatchKeyFromRow(AbstractRecord row, AbstractSession session) {
365 int size = this.sourceKeyFields.size();
366 Object[] key = new Object[size];
367 ConversionManager conversionManager = session.getDatasourcePlatform().getConversionManager();
368 for (int index = 0; index < size; index++) {
369 DatabaseField sourceField = this.sourceKeyFields.get(index);
370 Object value = row.get(sourceField);
371 // Must ensure the classification to get a cache hit.
372 try {
373 value = conversionManager.convertObject(value, sourceField.getType());
374 } catch (ConversionException exception) {
375 throw ConversionException.couldNotBeConverted(this, this.descriptor, exception);
376 }
377 key[index] = value;
378 }
379 return new CacheId(key);
380 }
381
382 /**
383 * Overrides CollectionMappig because this mapping requires a DeleteAllQuery instead of a ModifyQuery.
384 */
385 protected ModifyQuery getDeleteAllQuery() {
386 if (deleteAllQuery == null) {
387 deleteAllQuery = new DeleteAllQuery();//this is casted to a DeleteAllQuery
388 }
389 return deleteAllQuery;
390 }
391
392 /**
393 * INTERNAL:
394 * Return source key fields for translation by an AggregateObjectMapping
395 */
396 @Override
397 public Collection getFieldsForTranslationInAggregate() {
398 return getSourceKeyFields();
399 }
400
401 /**
402 * PUBLIC:
403 * Return the source key field names associated with the mapping.
404 * These are in-order with the targetForeignKeyFieldNames.
405 */
406 public Vector getSourceKeyFieldNames() {
407 Vector fieldNames = new Vector(getSourceKeyFields().size());
408 for (Enumeration fieldsEnum = getSourceKeyFields().elements();
409 fieldsEnum.hasMoreElements();) {
410 fieldNames.addElement(((DatabaseField)fieldsEnum.nextElement()).getQualifiedName());
411 }
412
413 return fieldNames;
414 }
415
416 /**
417 * INTERNAL:
418 * Return the source key fields.
419 */
420 public Vector<DatabaseField> getSourceKeyFields() {
421 return sourceKeyFields;
422 }
423
424 /**
425 * INTERNAL:
426 * Return the source/target key fields.
427 */
428 public Map<DatabaseField, DatabaseField> getSourceKeysToTargetForeignKeys() {
429 if (sourceKeysToTargetForeignKeys == null) {
430 sourceKeysToTargetForeignKeys = new HashMap(2);
431 }
432 return sourceKeysToTargetForeignKeys;
433 }
434
435 /**
436 * INTERNAL:
437 * Primary keys of targetForeignKeyTable.
438 */
439 public List<DatabaseField> getTargetPrimaryKeyFields() {
440 return this.targetPrimaryKeyFields;
441 }
442
443 /**
444 * INTERNAL:
445 * Return the target foreign key field names associated with the mapping.
446 * These are in-order with the targetForeignKeyFieldNames.
447 */
448 public Vector getTargetForeignKeyFieldNames() {
449 Vector fieldNames = new Vector(getTargetForeignKeyFields().size());
450 for (Enumeration fieldsEnum = getTargetForeignKeyFields().elements();
451 fieldsEnum.hasMoreElements();) {
452 fieldNames.addElement(((DatabaseField)fieldsEnum.nextElement()).getQualifiedName());
453 }
454
455 return fieldNames;
456 }
457
458 /**
459 * INTERNAL:
460 * Return the target foreign key fields.
461 */
462 public Vector<DatabaseField> getTargetForeignKeyFields() {
463 return targetForeignKeyFields;
464 }
465
466 /**
467 * INTERNAL:
468 * Return the target/source key fields.
469 */
470 public Map<DatabaseField, DatabaseField> getTargetForeignKeysToSourceKeys() {
471 if (targetForeignKeysToSourceKeys == null) {
472 targetForeignKeysToSourceKeys = new HashMap(2);
473 }
474 return targetForeignKeysToSourceKeys;
475 }
476
477 /**
478 * INTERNAL:
479 * Maintain for backward compatibility.
480 * This is 'public' so StoredProcedureGenerator
481 * does not have to use the custom query expressions.
482 */
483 public Map getTargetForeignKeyToSourceKeys() {
484 return getTargetForeignKeysToSourceKeys();
485 }
486
487 /**
488 * INTERNAL:
489 * Return whether the mapping has any inverse constraint dependencies,
490 * such as foreign keys and join tables.
491 */
492 @Override
493 public boolean hasInverseConstraintDependency() {
494 return true;
495 }
496
497 /**
498 * INTERNAL:
499 * Initialize the mapping.
500 */
501 @Override
502 public void initialize(AbstractSession session) throws DescriptorException {
503 if (session.hasBroker()) {
504 if (getReferenceClass() == null) {
505 throw DescriptorException.referenceClassNotSpecified(this);
506 }
507 // substitute session that owns the mapping for the session that owns reference descriptor.
508 session = session.getBroker().getSessionForClass(getReferenceClass());
509 }
510
511 super.initialize(session);
512
513 getContainerPolicy().initialize(session, getReferenceDescriptor().getDefaultTable());
514 if (shouldInitializeSelectionCriteria()) {
515 setSelectionCriteria(buildDefaultSelectionCriteriaAndAddFieldsToQuery());
516 }
517
518 initializeDeleteAllQuery(session);
519
520 if (requiresDataModificationEvents() || getContainerPolicy().requiresDataModificationEvents()) {
521 initializeAddTargetQuery(session);
522 initializeRemoveTargetQuery(session);
523 initializeRemoveAllTargetsQuery(session);
524 }
525
526 // Check if any foreign keys reference a secondary table.
527 if (getDescriptor().getTables().size() > 1) {
528 DatabaseTable firstTable = getDescriptor().getTables().get(0);
529 for (DatabaseField field : getSourceKeyFields()) {
530 if (!field.getTable().equals(firstTable)) {
531 getDescriptor().setHasMultipleTableConstraintDependecy(true);
532 }
533 }
534 }
535 }
536
537 /**
538 * INTERNAL:
539 * Initialize addTargetQuery.
540 */
541 protected void initializeAddTargetQuery(AbstractSession session) {
542 AbstractRecord modifyRow = createModifyRowForAddTargetQuery();
543 if(modifyRow.isEmpty()) {
544 return;
545 }
546
547 if (!hasCustomAddTargetQuery){
548 addTargetQuery = new DataModifyQuery();
549 }
550
551 if (!addTargetQuery.hasSessionName()) {
552 addTargetQuery.setSessionName(session.getName());
553 }
554 if (hasCustomAddTargetQuery) {
555 return;
556 }
557
558 // all fields in modifyRow must have the same table
559 DatabaseTable table = (modifyRow.getFields().get(0)).getTable();
560
561 // Build where clause expression.
562 Expression whereClause = null;
563 Expression builder = new ExpressionBuilder();
564
565 int size = targetPrimaryKeyFields.size();
566 for (int index = 0; index < size; index++) {
567 DatabaseField targetPrimaryKey = targetPrimaryKeyFields.get(index);
568 Expression expression = builder.getField(targetPrimaryKey).equal(builder.getParameter(targetPrimaryKey));
569 whereClause = expression.and(whereClause);
570 }
571
572 SQLUpdateStatement statement = new SQLUpdateStatement();
573 statement.setTable(table);
574 statement.setWhereClause(whereClause);
575 statement.setModifyRow(modifyRow);
576 addTargetQuery.setSQLStatement(statement);
577 }
578
579 /**
580 * INTERNAL:
581 */
582 protected AbstractRecord createModifyRowForAddTargetQuery() {
583 AbstractRecord modifyRow = new DatabaseRecord();
584 containerPolicy.addFieldsForMapKey(modifyRow);
585 if(listOrderField != null) {
586 modifyRow.add(listOrderField, null);
587 }
588 return modifyRow;
589 }
590
591 /**
592 * INTERNAL:
593 * Initialize changeOrderTargetQuery.
594 */
595 protected void initializeChangeOrderTargetQuery(AbstractSession session) {
596 boolean hasChangeOrderTargetQuery = changeOrderTargetQuery != null;
597 if(!hasChangeOrderTargetQuery) {
598 changeOrderTargetQuery = new DataModifyQuery();
599 }
600
601 changeOrderTargetQuery = new DataModifyQuery();
602 if (!changeOrderTargetQuery.hasSessionName()) {
603 changeOrderTargetQuery.setSessionName(session.getName());
604 }
605 if (hasChangeOrderTargetQuery) {
606 return;
607 }
608
609 DatabaseTable table = this.listOrderField.getTable();
610
611 // Build where clause expression.
612 Expression whereClause = null;
613 Expression builder = new ExpressionBuilder();
614
615 int size = targetPrimaryKeyFields.size();
616 for (int index = 0; index < size; index++) {
617 DatabaseField targetPrimaryKey = targetPrimaryKeyFields.get(index);
618 Expression expression = builder.getField(targetPrimaryKey).equal(builder.getParameter(targetPrimaryKey));
619 whereClause = expression.and(whereClause);
620 }
621
622 AbstractRecord modifyRow = new DatabaseRecord();
623 modifyRow.add(this.listOrderField, null);
624
625 SQLUpdateStatement statement = new SQLUpdateStatement();
626 statement.setTable(table);
627 statement.setWhereClause(whereClause);
628 statement.setModifyRow(modifyRow);
629 changeOrderTargetQuery.setSQLStatement(statement);
630 }
631
632 /**
633 * Initialize the delete all query.
634 * This query is used to delete the collection of objects from the
635 * database.
636 */
637 protected void initializeDeleteAllQuery(AbstractSession session) {
638 ((DeleteAllQuery)getDeleteAllQuery()).setReferenceClass(getReferenceClass());
639 getDeleteAllQuery().setName(getAttributeName());
640 ((DeleteAllQuery)getDeleteAllQuery()).setIsInMemoryOnly(isCascadeOnDeleteSetOnDatabase());
641 if (!hasCustomDeleteAllQuery()) {
642 // the selection criteria are re-used by the delete all query
643 if (getSelectionCriteria() == null) {
644 getDeleteAllQuery().setSelectionCriteria(buildDefaultSelectionCriteriaAndAddFieldsToQuery());
645 } else {
646 getDeleteAllQuery().setSelectionCriteria(getSelectionCriteria());
647 }
648 }
649 if (!getDeleteAllQuery().hasSessionName()) {
650 getDeleteAllQuery().setSessionName(session.getName());
651 }
652 if (getDeleteAllQuery().getPartitioningPolicy() == null) {
653 getDeleteAllQuery().setPartitioningPolicy(getPartitioningPolicy());
654 }
655 }
656
657 /**
658 * INTERNAL:
659 * Initialize targetForeignKeyTable and initializeTargetPrimaryKeyFields.
660 * This method should be called after initializeTargetForeignKeysToSourceKeys method,
661 * which creates targetForeignKeyFields (guaranteed to be not empty in case
662 * requiresDataModificationEvents method returns true - the only case for the method to be called).
663 */
664 protected void initializeTargetPrimaryKeyFields() {
665 // all target foreign key fields must have the same table.
666 int size = getTargetForeignKeyFields().size();
667 HashSet<DatabaseTable> tables = new HashSet();
668 for(int i=0; i < size; i++) {
669 tables.add(getTargetForeignKeyFields().get(i).getTable());
670 }
671 if(tables.size() == 1) {
672 this.targetForeignKeyTable = getTargetForeignKeyFields().get(0).getTable();
673 } else {
674 // multiple foreign key tables - throw exception.
675 throw DescriptorException.multipleTargetForeignKeyTables(this.getDescriptor(), this, tables);
676 }
677
678 List defaultTablePrimaryKeyFields = getReferenceDescriptor().getPrimaryKeyFields();
679 if(this.targetForeignKeyTable.equals(getReferenceDescriptor().getDefaultTable())) {
680 this.targetPrimaryKeyFields = defaultTablePrimaryKeyFields;
681 } else {
682 int sizePk = defaultTablePrimaryKeyFields.size();
683 this.targetPrimaryKeyFields = new ArrayList();
684 for(int i=0; i < sizePk; i++) {
685 this.targetPrimaryKeyFields.add(null);
686 }
687 Map<DatabaseField, DatabaseField> map = getReferenceDescriptor().getAdditionalTablePrimaryKeyFields().get(this.targetForeignKeyTable);
688 Iterator<Map.Entry<DatabaseField, DatabaseField>> it = map.entrySet().iterator();
689 while(it.hasNext()) {
690 Map.Entry<DatabaseField, DatabaseField> entry = it.next();
691 DatabaseField sourceField = entry.getKey();
692 DatabaseField targetField = entry.getValue();
693 DatabaseField additionalTableField;
694 DatabaseField defaultTableField;
695 if(sourceField.getTable().equals(this.targetForeignKeyTable)) {
696 additionalTableField = sourceField;
697 defaultTableField = targetField;
698 } else {
699 defaultTableField = sourceField;
700 additionalTableField = targetField;
701 }
702 int index = defaultTablePrimaryKeyFields.indexOf(defaultTableField);
703 getReferenceDescriptor().buildField(additionalTableField, this.targetForeignKeyTable);
704 this.targetPrimaryKeyFields.set(index, additionalTableField);
705 }
706 }
707 }
708
709 /**
710 * INTERNAL:
711 * Initialize removeTargetQuery.
712 */
713 protected void initializeRemoveTargetQuery(AbstractSession session) {
714 if (!removeTargetQuery.hasSessionName()) {
715 removeTargetQuery.setSessionName(session.getName());
716 }
717 if (hasCustomRemoveTargetQuery) {
718 return;
719 }
720
721 // All targetForeignKeys should have the same table
722 DatabaseTable table = targetForeignKeyFields.get(0).getTable();
723
724 // Build where clause expression.
725 Expression whereClause = null;
726 Expression builder = new ExpressionBuilder();
727
728 int size = targetPrimaryKeyFields.size();
729 for (int index = 0; index < size; index++) {
730 DatabaseField targetPrimaryKey = targetPrimaryKeyFields.get(index);
731 Expression expression = builder.getField(targetPrimaryKey).equal(builder.getParameter(targetPrimaryKey));
732 whereClause = expression.and(whereClause);
733 }
734
735 AbstractRecord modifyRow = new DatabaseRecord();
736 if(shouldRemoveTargetQueryModifyTargetForeignKey()) {
737 size = targetForeignKeyFields.size();
738 for (int index = 0; index < size; index++) {
739 DatabaseField targetForeignKey = targetForeignKeyFields.get(index);
740 modifyRow.put(targetForeignKey, null);
741 Expression expression = builder.getField(targetForeignKey).equal(builder.getParameter(targetForeignKey));
742 whereClause = expression.and(whereClause);
743 }
744 }
745 if(listOrderField != null) {
746 modifyRow.add(listOrderField, null);
747 }
748
749 SQLUpdateStatement statement = new SQLUpdateStatement();
750 statement.setTable(table);
751 statement.setWhereClause(whereClause);
752 statement.setModifyRow(modifyRow);
753 removeTargetQuery.setSQLStatement(statement);
754 }
755
756 /**
757 * Initialize and set the descriptor for the referenced class in this mapping.
758 * Added here initialization of target foreign keys and target primary keys so that they are ready when
759 * CollectionMapping.initialize initializes listOrderField.
760 */
761 protected void initializeReferenceDescriptor(AbstractSession session) throws DescriptorException {
762 super.initializeReferenceDescriptor(session);
763 if (!isSourceKeySpecified()) {
764 // sourceKeyFields will be empty when #setTargetForeignKeyFieldName() is used
765 setSourceKeyFields(org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(getDescriptor().getPrimaryKeyFields()));
766 }
767 initializeTargetForeignKeysToSourceKeys();
768 if (usesIndirection()) {
769 for (DatabaseField field : getSourceKeyFields()) {
770 field.setKeepInRow(true);
771 }
772 }
773 if(requiresDataModificationEvents() || getContainerPolicy().requiresDataModificationEvents()) {
774 initializeTargetPrimaryKeyFields();
775 }
776 }
777
778 /**
779 * INTERNAL:
780 * Initialize removeAllTargetsQuery.
781 */
782 protected void initializeRemoveAllTargetsQuery(AbstractSession session) {
783 if (!removeAllTargetsQuery.hasSessionName()) {
784 removeAllTargetsQuery.setSessionName(session.getName());
785 }
786 if (hasCustomRemoveAllTargetsQuery) {
787 return;
788 }
789
790 // All targetForeignKeys should have the same table
791 DatabaseTable table = targetForeignKeyFields.get(0).getTable();
792
793 // Build where clause expression.
794 Expression whereClause = null;
795 Expression builder = new ExpressionBuilder();
796
797 AbstractRecord modifyRow = new DatabaseRecord();
798 int size = targetForeignKeyFields.size();
799 for (int index = 0; index < size; index++) {
800 DatabaseField targetForeignKey = targetForeignKeyFields.get(index);
801 if(shouldRemoveTargetQueryModifyTargetForeignKey()) {
802 modifyRow.put(targetForeignKey, null);
803 }
804 Expression expression = builder.getField(targetForeignKey).equal(builder.getParameter(targetForeignKey));
805 whereClause = expression.and(whereClause);
806 }
807 if(this.listOrderField != null) {
808 // targetForeignKeys and listOrderField should have the same table
809 modifyRow.add(this.listOrderField, null);
810 }
811
812 SQLUpdateStatement statement = new SQLUpdateStatement();
813 statement.setTable(table);
814 statement.setWhereClause(whereClause);
815 statement.setModifyRow(modifyRow);
816 removeAllTargetsQuery.setSQLStatement(statement);
817 }
818
819 /**
820 * Verify, munge, and hash the target foreign keys and source keys.
821 */
822 protected void initializeTargetForeignKeysToSourceKeys() throws DescriptorException {
823 if (getTargetForeignKeyFields().isEmpty()) {
824 if (shouldInitializeSelectionCriteria() || requiresDataModificationEvents() || getContainerPolicy().requiresDataModificationEvents()) {
825 throw DescriptorException.noTargetForeignKeysSpecified(this);
826 } else {
827 // if they have specified selection criteria, the keys do not need to be specified
828 return;
829 }
830 }
831
832 if (getTargetForeignKeyFields().size() != getSourceKeyFields().size()) {
833 throw DescriptorException.targetForeignKeysSizeMismatch(this);
834 }
835
836 for (int index = 0; index < getTargetForeignKeyFields().size(); index++) {
837 DatabaseField field = getReferenceDescriptor().buildField(getTargetForeignKeyFields().get(index));
838 getTargetForeignKeyFields().set(index, field);
839 }
840
841 for (int index = 0; index < getSourceKeyFields().size(); index++) {
842 DatabaseField field = getDescriptor().buildField(getSourceKeyFields().get(index));
843 getSourceKeyFields().set(index, field);
844 }
845
846 Iterator<DatabaseField> targetForeignKeys = getTargetForeignKeyFields().iterator();
847 Iterator<DatabaseField> sourceKeys = getSourceKeyFields().iterator();
848 while (targetForeignKeys.hasNext()) {
849 DatabaseField targetForeignKey = targetForeignKeys.next();
850 DatabaseField sourcePrimaryKey = sourceKeys.next();
851 getTargetForeignKeysToSourceKeys().put(targetForeignKey, sourcePrimaryKey);
852 getSourceKeysToTargetForeignKeys().put(sourcePrimaryKey, targetForeignKey);
853 }
854 }
855
856 /**
857 * INTERNAL:
858 */
859 @Override
860 public boolean isOneToManyMapping() {
861 return true;
862 }
863
864 /**
865 * Return whether the source key is specified.
866 * It will be empty when #setTargetForeignKeyFieldName(String) is used.
867 */
868 protected boolean isSourceKeySpecified() {
869 return !getSourceKeyFields().isEmpty();
870 }
871
872 /**
873 * INTERNAL:
874 * An object was added to the collection during an update, insert it if private.
875 */
876 @Override
877 protected void objectAddedDuringUpdate(ObjectLevelModifyQuery query, Object objectAdded, ObjectChangeSet changeSet, Map extraData) throws DatabaseException, OptimisticLockException {
878 // First insert/update object.
879 super.objectAddedDuringUpdate(query, objectAdded, changeSet, extraData);
880
881 if (requiresDataModificationEvents() || containerPolicy.requiresDataModificationEvents()){
882 // In the uow data queries are cached until the end of the commit.
883 if (query.shouldCascadeOnlyDependentParts()) {
884 // Hey I might actually want to use an inner class here... ok array for now.
885 Object[] event = new Object[4];
886 event[0] = ObjectAdded;
887 event[1] = query;
888 event[2] = objectAdded;
889 event[3] = extraData;
890 query.getSession().getCommitManager().addDataModificationEvent(this, event);
891 } else {
892 updateTargetForeignKeyPostUpdateSource_ObjectAdded(query, objectAdded, extraData);
893 }
894 }
895 }
896
897 /**
898 * INTERNAL:
899 * An object was removed to the collection during an update, delete it if private.
900 */
901 @Override
902 protected void objectRemovedDuringUpdate(ObjectLevelModifyQuery query, Object objectDeleted, Map extraData) throws DatabaseException, OptimisticLockException {
903 if(!isPrivateOwned()) {
904 if (requiresDataModificationEvents() || containerPolicy.requiresDataModificationEvents()){
905 // In the uow data queries are cached until the end of the commit.
906 if (query.shouldCascadeOnlyDependentParts()) {
907 // Hey I might actually want to use an inner class here... ok array for now.
908 Object[] event = new Object[3];
909 event[0] = ObjectRemoved;
910 event[1] = query;
911 event[2] = objectDeleted;
912 query.getSession().getCommitManager().addDataModificationEvent(this, event);
913 } else {
914 updateTargetForeignKeyPostUpdateSource_ObjectRemoved(query, objectDeleted);
915 }
916 }
917 }
918
919 // Delete object after join entry is delete if private.
920 super.objectRemovedDuringUpdate(query, objectDeleted, extraData);
921 }
922
923
924 /**
925 * INTERNAL:
926 * Perform the commit event.
927 * This is used in the uow to delay data modifications.
928 */
929 @Override
930 public void performDataModificationEvent(Object[] event, AbstractSession session) throws DatabaseException, DescriptorException {
931 // Hey I might actually want to use an inner class here... ok array for now.
932 if (event[0] == PostInsert) {
933 updateTargetRowPostInsertSource((WriteObjectQuery)event[1]);
934 } else if (event[0] == ObjectRemoved) {
935 updateTargetForeignKeyPostUpdateSource_ObjectRemoved((WriteObjectQuery)event[1], event[2]);
936 } else if (event[0] == ObjectAdded) {
937 updateTargetForeignKeyPostUpdateSource_ObjectAdded((WriteObjectQuery)event[1], event[2], (Map)event[3]);
938 } else {
939 throw DescriptorException.invalidDataModificationEventCode(event[0], this);
940 }
941 }
942
943 /**
944 * INTERNAL:
945 * Insert the reference objects.
946 */
947 @Override
948 public void postInsert(WriteObjectQuery query) throws DatabaseException, OptimisticLockException {
949 if (isReadOnly()) {
950 return;
951 }
952
953 if (shouldObjectModifyCascadeToParts(query) && !query.shouldCascadeOnlyDependentParts()) {
954 Object objects = getRealCollectionAttributeValueFromObject(query.getObject(), query.getSession());
955 // insert each object one by one
956 ContainerPolicy cp = getContainerPolicy();
957 for (Object iter = cp.iteratorFor(objects); cp.hasNext(iter);) {
958 Object wrappedObject = cp.nextEntry(iter, query.getSession());
959 Object object = cp.unwrapIteratorResult(wrappedObject);
960 if (isPrivateOwned()) {
961 // no need to set changeSet as insert is a straight copy
962 InsertObjectQuery insertQuery = new InsertObjectQuery();
963 insertQuery.setIsExecutionClone(true);
964 insertQuery.setObject(object);
965 insertQuery.setCascadePolicy(query.getCascadePolicy());
966 query.getSession().executeQuery(insertQuery);
967 } else {
968 // This will happen in a cascaded query.
969 // This is done only for persistence by reachability and is not required if the targets are in the queue anyway
970 // Avoid cycles by checking commit manager, this is allowed because there is no dependency.
971 if (!query.getSession().getCommitManager().isCommitInPreModify(object)) {
972 WriteObjectQuery writeQuery = new WriteObjectQuery();
973 writeQuery.setIsExecutionClone(true);
974 writeQuery.setObject(object);
975 writeQuery.setCascadePolicy(query.getCascadePolicy());
976 query.getSession().executeQuery(writeQuery);
977 }
978 }
979 cp.propogatePostInsert(query, wrappedObject);
980 }
981 }
982 if (requiresDataModificationEvents() || getContainerPolicy().requiresDataModificationEvents()){
983 // only cascade dependents in UOW
984 if (query.shouldCascadeOnlyDependentParts()) {
985 if (!isReadOnly() && (requiresDataModificationEvents() || containerPolicy.shouldUpdateForeignKeysPostInsert())) {
986 // Hey I might actually want to use an inner class here... ok array for now.
987 Object[] event = new Object[2];
988 event[0] = PostInsert;
989 event[1] = query;
990 query.getSession().getCommitManager().addDataModificationEvent(this, event);
991 }
992 } else {
993 if (!isReadOnly() && (requiresDataModificationEvents() || containerPolicy.shouldUpdateForeignKeysPostInsert())){
994 updateTargetRowPostInsertSource(query);
995 }
996 }
997 }
998 }
999
1000 /**
1001 * INTERNAL:
1002 * Post-initialize source and target expression fields created when a mapping's selectionCriteria
1003 * is created early with only partly initialized fields.
1004 */
1005 @Override
1006 public void postInitializeSourceAndTargetExpressions() {
1007 // EL Bug 426500
1008 // postInitialize and set source expression fields using my descriptor
1009 if (this.sourceExpressionsToPostInitialize != null && this.sourceExpressionsToPostInitialize.size() > 0) {
1010 ClassDescriptor descriptor = getDescriptor();
1011 ObjectBuilder objectBuilder = descriptor.getObjectBuilder();
1012 for (Iterator<Expression> expressions = this.sourceExpressionsToPostInitialize.iterator(); expressions.hasNext();) {
1013 Expression expression = expressions.next();
1014 DatabaseField field = null;
1015 if (expression.isParameterExpression()) {
1016 field = ((ParameterExpression)expression).getField();
1017 } else if (expression.isFieldExpression()) {
1018 field = ((FieldExpression)expression).getField();
1019 }
1020 if (field != null && (field.getType() == null || field.getTypeName() == null)) {
1021 field.setType(objectBuilder.getFieldClassification(field));
1022 }
1023 }
1024 }
1025
1026 // postInitialize and set target expression fields using my reference descriptor
1027 if (this.targetExpressionsToPostInitialize != null && this.targetExpressionsToPostInitialize.size() > 0) {
1028 ClassDescriptor descriptor = getReferenceDescriptor();
1029 ObjectBuilder objectBuilder = descriptor.getObjectBuilder();
1030 for (Iterator<Expression> expressions = this.targetExpressionsToPostInitialize.iterator(); expressions.hasNext();) {
1031 Expression expression = expressions.next();
1032 DatabaseField field = null;
1033 if (expression.isParameterExpression()) {
1034 field = ((ParameterExpression)expression).getField();
1035 } else if (expression.isFieldExpression()) {
1036 field = ((FieldExpression)expression).getField();
1037 }
1038 if (field != null && (field.getType() == null || field.getTypeName() == null)) {
1039 field.setType(objectBuilder.getFieldClassification(field));
1040 }
1041 }
1042 }
1043 }
1044
1045 /**
1046 * INTERNAL:
1047 * Update the reference objects.
1048 */
1049 @Override
1050 public void postUpdate(WriteObjectQuery query) throws DatabaseException, OptimisticLockException {
1051 if (this.isReadOnly) {
1052 return;
1053 }
1054
1055 if (!requiresDataModificationEvents() && !shouldObjectModifyCascadeToParts(query)){
1056 return;
1057 }
1058
1059 // if the target objects are not instantiated, they could not have been changed....
1060 if (!isAttributeValueInstantiatedOrChanged(query.getObject())) {
1061 return;
1062 }
1063
1064 if (query.getObjectChangeSet() != null) {
1065 // UnitOfWork
1066 writeChanges(query.getObjectChangeSet(), query);
1067 } else {
1068 // OLD COMMIT
1069 compareObjectsAndWrite(query);
1070 }
1071 }
1072
1073 /**
1074 * INTERNAL:
1075 * Return the selection criteria used to IN batch fetching.
1076 */
1077 @Override
1078 protected Expression buildBatchCriteria(ExpressionBuilder builder, ObjectLevelReadQuery query) {
1079 int size = this.targetForeignKeyFields.size();
1080 if (size > 1) {
1081 // Support composite keys using nested IN.
1082 List<Expression> fields = new ArrayList<Expression>(size);
1083 for (DatabaseField targetForeignKeyField : this.targetForeignKeyFields) {
1084 fields.add(builder.getField(targetForeignKeyField));
1085 }
1086 return query.getSession().getPlatform().buildBatchCriteriaForComplexId(builder, fields);
1087 } else {
1088 return query.getSession().getPlatform().buildBatchCriteria(builder, builder.getField(this.targetForeignKeyFields.get(0)));
1089 }
1090 }
1091
1092 /**
1093 * INTERNAL:
1094 * Delete the reference objects.
1095 */
1096 @Override
1097 public void preDelete(DeleteObjectQuery query) throws DatabaseException, OptimisticLockException {
1098 if (!shouldObjectModifyCascadeToParts(query)) {
1099 if (this.listOrderField != null) {
1100 updateTargetRowPreDeleteSource(query);
1101 }
1102 return;
1103 }
1104 AbstractSession session = query.getSession();
1105
1106 // If privately-owned parts have their privately-owned sub-parts, delete them one by one;
1107 // else delete everything in one shot.
1108 if (mustDeleteReferenceObjectsOneByOne()) {
1109 Object objects = getRealCollectionAttributeValueFromObject(query.getObject(), session);
1110 ContainerPolicy cp = getContainerPolicy();
1111 if (this.isCascadeOnDeleteSetOnDatabase && session.isUnitOfWork()) {
1112 for (Object iterator = cp.iteratorFor(objects); cp.hasNext(iterator);) {
1113 Object wrappedObject = cp.nextEntry(iterator, session);
1114 Object object = cp.unwrapIteratorResult(wrappedObject);
1115 ((UnitOfWorkImpl)session).getCascadeDeleteObjects().add(object);
1116 }
1117 }
1118 int cascade = query.getCascadePolicy();
1119 for (Object iterator = cp.iteratorFor(objects); cp.hasNext(iterator);) {
1120 Object wrappedObject = cp.nextEntry(iterator, session);
1121 Object object = cp.unwrapIteratorResult(wrappedObject);
1122 // PERF: Avoid query execution if already deleted.
1123 if (!session.getCommitManager().isCommitCompletedInPostOrIgnore(object) || this.containerPolicy.propagatesEventsToCollection()) {
1124 if (session.isUnitOfWork() && ((UnitOfWorkImpl)session).isObjectNew(object) ){
1125 session.getCommitManager().markIgnoreCommit(object);
1126 } else {
1127 DeleteObjectQuery deleteQuery = new DeleteObjectQuery();
1128 deleteQuery.setIsExecutionClone(true);
1129 deleteQuery.setObject(object);
1130 deleteQuery.setCascadePolicy(cascade);
1131 session.executeQuery(deleteQuery);
1132 this.containerPolicy.propogatePreDelete(deleteQuery, wrappedObject);
1133 }
1134 }
1135 }
1136 if (!session.isUnitOfWork()) {
1137 // This deletes any objects on the database, as the collection in memory may have been changed.
1138 // This is not required for unit of work, as the update would have already deleted these objects,
1139 // and the backup copy will include the same objects causing double deletes.
1140 deleteReferenceObjectsLeftOnDatabase(query);
1141 }
1142 } else {
1143 deleteAll(query, session);
1144 }
1145 }
1146
1147 /**
1148 * Prepare a cascade locking policy.
1149 */
1150 @Override
1151 public void prepareCascadeLockingPolicy() {
1152 CascadeLockingPolicy policy = new CascadeLockingPolicy(getDescriptor(), getReferenceDescriptor());
1153 policy.setQueryKeyFields(getSourceKeysToTargetForeignKeys());
1154 getReferenceDescriptor().addCascadeLockingPolicy(policy);
1155 }
1156
1157 /**
1158 * INTERNAL:
1159 * Returns whether this mapping uses data modification events to complete its writes
1160 * @see UnidirectionalOneToManyMapping
1161 */
1162 public boolean requiresDataModificationEvents(){
1163 return this.listOrderField != null;
1164 }
1165
1166 /**
1167 * PUBLIC:
1168 * The default add target query for mapping can be overridden by specifying the new query.
1169 * This query must set new value to target foreign key.
1170 */
1171 public void setCustomAddTargetQuery(DataModifyQuery query) {
1172 addTargetQuery = query;
1173 hasCustomAddTargetQuery = true;
1174 }
1175
1176
1177 /**
1178 * PUBLIC:
1179 */
1180 public void setAddTargetSQLString(String sqlString) {
1181 DataModifyQuery query = new DataModifyQuery();
1182 query.setSQLString(sqlString);
1183 setCustomAddTargetQuery(query);
1184 }
1185
1186 /**
1187 * PUBLIC:
1188 * The default remove target query for mapping can be overridden by specifying the new query.
1189 * In case target foreign key references the source, this query must set target foreign key to null.
1190 */
1191 public void setCustomRemoveTargetQuery(DataModifyQuery query) {
1192 removeTargetQuery = query;
1193 hasCustomRemoveTargetQuery = true;
1194 }
1195
1196 /**
1197 * PUBLIC:
1198 * The default remove all targets query for mapping can be overridden by specifying the new query.
1199 * This query must set all target foreign keys that reference the source to null.
1200 */
1201 public void setCustomRemoveAllTargetsQuery(DataModifyQuery query) {
1202 removeAllTargetsQuery = query;
1203 hasCustomRemoveAllTargetsQuery = true;
1204 }
1205
1206 /**
1207 * PUBLIC:
1208 * Set the SQL string used by the mapping to delete the target objects.
1209 * This allows the developer to override the SQL
1210 * generated by TopLink with a custom SQL statement or procedure call.
1211 * The arguments are
1212 * translated from the fields of the source row, by replacing the field names
1213 * marked by '#' with the values for those fields at execution time.
1214 * A one-to-many mapping will only use this delete all optimization if the target objects
1215 * can be deleted in a single SQL call. This is possible when the target objects
1216 * are in a single table, do not using locking, do not contain other privately-owned
1217 * parts, do not read subclasses, etc.
1218 * <p>
1219 * Example: "delete from PHONE where OWNER_ID = #EMPLOYEE_ID"
1220 */
1221 @Override
1222 public void setDeleteAllSQLString(String sqlString) {
1223 DeleteAllQuery query = new DeleteAllQuery();
1224 query.setSQLString(sqlString);
1225 setCustomDeleteAllQuery(query);
1226 }
1227
1228
1229 /**
1230 * PUBLIC:
1231 * Set the name of the session to execute the mapping's queries under.
1232 * This can be used by the session broker to override the default session
1233 * to be used for the target class.
1234 */
1235 @Override
1236 public void setSessionName(String name) {
1237 super.setSessionName(name);
1238 if (addTargetQuery != null){
1239 addTargetQuery.setSessionName(name);
1240 }
1241 removeTargetQuery.setSessionName(name);
1242 removeAllTargetsQuery.setSessionName(name);
1243 }
1244
1245 /**
1246 * INTERNAL:
1247 * Set the source key field names associated with the mapping.
1248 * These must be in-order with the targetForeignKeyFieldNames.
1249 */
1250 public void setSourceKeyFieldNames(Vector fieldNames) {
1251 Vector fields = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(fieldNames.size());
1252 for (Enumeration fieldNamesEnum = fieldNames.elements(); fieldNamesEnum.hasMoreElements();) {
1253 fields.addElement(new DatabaseField((String)fieldNamesEnum.nextElement()));
1254 }
1255
1256 setSourceKeyFields(fields);
1257 }
1258
1259 /**
1260 * INTERNAL:
1261 * Set the source key fields.
1262 */
1263 public void setSourceKeyFields(Vector<DatabaseField> sourceKeyFields) {
1264 this.sourceKeyFields = sourceKeyFields;
1265 }
1266
1267 /**
1268 * PUBLIC:
1269 * Define the target foreign key relationship in the one-to-many mapping.
1270 * This method can be used when the foreign and primary keys
1271 * have only a single field each.
1272 * (Use #addTargetForeignKeyFieldName(String, String)
1273 * for "composite" keys.)
1274 * Only the target foreign key field name is specified and the source
1275 * (primary) key field is
1276 * assumed to be the primary key of the source object.
1277 * Because the target object's table must store a foreign key to the source table,
1278 * the target object must map that foreign key, this is normally done through a
1279 * one-to-one mapping back-reference. Other options include:
1280 * <ul>
1281 * <li> use a DirectToFieldMapping and maintain the
1282 * foreign key fields directly in the target
1283 * <li> use a ManyToManyMapping
1284 * <li> use an AggregateCollectionMapping
1285 * </ul>
1286 * @see DirectToFieldMapping
1287 * @see ManyToManyMapping
1288 * @see AggregateCollectionMapping
1289 */
1290 public void setTargetForeignKeyFieldName(String targetForeignKeyFieldName) {
1291 getTargetForeignKeyFields().addElement(new DatabaseField(targetForeignKeyFieldName));
1292 }
1293
1294 /**
1295 * PUBLIC:
1296 * Define the target foreign key relationship in the one-to-many mapping.
1297 * This method is used for composite target foreign key relationships.
1298 * That is, the target object's table has multiple foreign key fields to
1299 * the source object's (typically primary) key fields.
1300 * Both the target foreign key field names and the corresponding source primary
1301 * key field names must be specified.
1302 */
1303 public void setTargetForeignKeyFieldNames(String[] targetForeignKeyFieldNames, String[] sourceKeyFieldNames) {
1304 if (targetForeignKeyFieldNames.length != sourceKeyFieldNames.length) {
1305 throw DescriptorException.targetForeignKeysSizeMismatch(this);
1306 }
1307 for (int i = 0; i < targetForeignKeyFieldNames.length; i++) {
1308 addTargetForeignKeyFieldName(targetForeignKeyFieldNames[i], sourceKeyFieldNames[i]);
1309 }
1310 }
1311
1312 /**
1313 * INTERNAL:
1314 * Set the target key field names associated with the mapping.
1315 * These must be in-order with the sourceKeyFieldNames.
1316 */
1317 public void setTargetForeignKeyFieldNames(Vector fieldNames) {
1318 Vector fields = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(fieldNames.size());
1319 for (Enumeration fieldNamesEnum = fieldNames.elements(); fieldNamesEnum.hasMoreElements();) {
1320 fields.addElement(new DatabaseField((String)fieldNamesEnum.nextElement()));
1321 }
1322
1323 setTargetForeignKeyFields(fields);
1324 }
1325
1326 /**
1327 * INTERNAL:
1328 * Set the target fields.
1329 */
1330 public void setTargetForeignKeyFields(Vector<DatabaseField> targetForeignKeyFields) {
1331 this.targetForeignKeyFields = targetForeignKeyFields;
1332 }
1333
1334 /**
1335 * INTERNAL:
1336 * Set the target fields.
1337 */
1338 protected void setTargetForeignKeysToSourceKeys(Map<DatabaseField, DatabaseField> targetForeignKeysToSourceKeys) {
1339 this.targetForeignKeysToSourceKeys = targetForeignKeysToSourceKeys;
1340 }
1341
1342 /**
1343 * Return whether any process leading to object modification
1344 * should also affect its parts.
1345 * Used by write, insert, update, and delete.
1346 */
1347 @Override
1348 protected boolean shouldObjectModifyCascadeToParts(ObjectLevelModifyQuery query) {
1349 if (isReadOnly()) {
1350 return false;
1351 }
1352
1353 if (isPrivateOwned()) {
1354 return true;
1355 }
1356
1357 if (containerPolicy.isMappedKeyMapPolicy() && containerPolicy.requiresDataModificationEvents()){
1358 return true;
1359 }
1360
1361 return query.shouldCascadeAllParts();
1362 }
1363
1364 /**
1365 * INTERNAL
1366 * If it's not a map then target foreign key has been already modified (set to null).
1367 */
1368 protected boolean shouldRemoveTargetQueryModifyTargetForeignKey() {
1369 return containerPolicy.isMapPolicy();
1370 }
1371
1372 /**
1373 * INTERNAL
1374 * Return true if this mapping supports cascaded version optimistic locking.
1375 */
1376 @Override
1377 public boolean isCascadedLockingSupported() {
1378 return true;
1379 }
1380
1381 /**
1382 * INTERNAL:
1383 * Return if this mapping support joining.
1384 */
1385 @Override
1386 public boolean isJoiningSupported() {
1387 return true;
1388 }
1389
1390 /**
1391 * INTERNAL:
1392 * Update target foreign keys after a new source was inserted. This follows following steps.
1393 */
1394 public void updateTargetRowPostInsertSource(WriteObjectQuery query) throws DatabaseException {
1395 if (isReadOnly() || addTargetQuery == null) {
1396 return;
1397 }
1398
1399 ContainerPolicy cp = getContainerPolicy();
1400 Object objects = getRealCollectionAttributeValueFromObject(query.getObject(), query.getSession());
1401 if (cp.isEmpty(objects)) {
1402 return;
1403 }
1404
1405 prepareTranslationRow(query.getTranslationRow(), query.getObject(), query.getDescriptor(), query.getSession());
1406
1407 AbstractRecord keyRow = buildKeyRowForTargetUpdate(query);
1408
1409 // Extract target field and its value. Construct insert statement and execute it
1410 int size = targetPrimaryKeyFields.size();
1411 int objectIndex = 0;
1412 for (Object iter = cp.iteratorFor(objects); cp.hasNext(iter);) {
1413 AbstractRecord databaseRow = new DatabaseRecord();
1414 databaseRow.mergeFrom(keyRow);
1415 Object wrappedObject = cp.nextEntry(iter, query.getSession());
1416 Object object = cp.unwrapIteratorResult(wrappedObject);
1417 for(int index = 0; index < size; index++) {
1418 DatabaseField targetPrimaryKey = targetPrimaryKeyFields.get(index);
1419 Object targetKeyValue = getReferenceDescriptor().getObjectBuilder().extractValueFromObjectForField(object, targetPrimaryKey, query.getSession());
1420 databaseRow.put(targetPrimaryKey, targetKeyValue);
1421 }
1422 ContainerPolicy.copyMapDataToRow(cp.getKeyMappingDataForWriteQuery(wrappedObject, query.getSession()), databaseRow);
1423 if(listOrderField != null) {
1424 databaseRow.put(listOrderField, objectIndex++);
1425 }
1426 query.getSession().executeQuery(addTargetQuery, databaseRow);
1427 }
1428 }
1429
1430 protected AbstractRecord buildKeyRowForTargetUpdate(ObjectLevelModifyQuery query){
1431 return new DatabaseRecord();
1432 }
1433
1434 /**
1435 * INTERNAL:
1436 * Update target foreign key after a target object was added to the source. This follows following steps.
1437 * <p>- Extract primary key and its value from the source object.
1438 * <p>- Extract target key and its value from the target object.
1439 * <p>- Construct an update statement with above fields and values for target table.
1440 * <p>- execute the statement.
1441 */
1442 public void updateTargetForeignKeyPostUpdateSource_ObjectAdded(ObjectLevelModifyQuery query, Object objectAdded, Map extraData) throws DatabaseException {
1443 if (isReadOnly() || addTargetQuery == null) {
1444 return;
1445 }
1446
1447 ContainerPolicy cp = getContainerPolicy();
1448 prepareTranslationRow(query.getTranslationRow(), query.getObject(), query.getDescriptor(), query.getSession());
1449 AbstractRecord databaseRow = buildKeyRowForTargetUpdate(query);
1450
1451 // Extract target field and its value. Construct insert statement and execute it
1452 int size = targetPrimaryKeyFields.size();
1453 for (int index = 0; index < size; index++) {
1454 DatabaseField targetPrimaryKey = targetPrimaryKeyFields.get(index);
1455 Object targetKeyValue = getReferenceDescriptor().getObjectBuilder().extractValueFromObjectForField(cp.unwrapIteratorResult(objectAdded), targetPrimaryKey, query.getSession());
1456 databaseRow.put(targetPrimaryKey, targetKeyValue);
1457 }
1458
1459 ContainerPolicy.copyMapDataToRow(cp.getKeyMappingDataForWriteQuery(objectAdded, query.getSession()), databaseRow);
1460 if(listOrderField != null && extraData != null) {
1461 databaseRow.put(listOrderField, extraData.get(listOrderField));
1462 }
1463
1464 query.getSession().executeQuery(addTargetQuery, databaseRow);
1465 }
1466
1467 /**
1468 * INTERNAL:
1469 * Update target foreign key after a target object was removed from the source. This follows following steps.
1470 * <p>- Extract primary key and its value from the source object.
1471 * <p>- Extract target key and its value from the target object.
1472 * <p>- Construct an update statement with above fields and values for target table.
1473 * <p>- execute the statement.
1474 */
1475 public void updateTargetForeignKeyPostUpdateSource_ObjectRemoved(ObjectLevelModifyQuery query, Object objectRemoved) throws DatabaseException {
1476 if (this.isReadOnly) {
1477 return;
1478 }
1479 AbstractSession session = query.getSession();
1480 prepareTranslationRow(query.getTranslationRow(), query.getObject(), query.getDescriptor(), session);
1481 AbstractRecord translationRow = new DatabaseRecord();
1482
1483 // Extract primary key and value from the source (use translation row).
1484 int size = this.sourceKeyFields.size();
1485 AbstractRecord modifyRow = new DatabaseRecord(size);
1486 for (int index = 0; index < size; index++) {
1487 DatabaseField sourceKey = this.sourceKeyFields.get(index);
1488 DatabaseField targetForeignKey = this.targetForeignKeyFields.get(index);
1489 Object sourceKeyValue = query.getTranslationRow().get(sourceKey);
1490 translationRow.add(targetForeignKey, sourceKeyValue);
1491 // Need to set this value to null in the modify row.
1492 modifyRow.add(targetForeignKey, null);
1493 }
1494 if(listOrderField != null) {
1495 modifyRow.add(listOrderField, null);
1496 }
1497
1498 ContainerPolicy cp = getContainerPolicy();
1499 // Extract target field and its value from the object.
1500 size = targetPrimaryKeyFields.size();
1501 for (int index = 0; index < size; index++) {
1502 DatabaseField targetPrimaryKey = targetPrimaryKeyFields.get(index);
1503 Object targetKeyValue = getReferenceDescriptor().getObjectBuilder().extractValueFromObjectForField(cp.unwrapIteratorResult(objectRemoved), targetPrimaryKey, session);
1504 translationRow.add(targetPrimaryKey, targetKeyValue);
1505 }
1506 // Need a different modify row than translation row, as the same field has different values in each.
1507 DataModifyQuery removeQuery = (DataModifyQuery)this.removeTargetQuery.clone();
1508 removeQuery.setModifyRow(modifyRow);
1509 removeQuery.setHasModifyRow(true);
1510 removeQuery.setIsExecutionClone(true);
1511 session.executeQuery(removeQuery, translationRow);
1512 }
1513
1514 /**
1515 * INTERNAL:
1516 * Update target foreign key after a target object was removed from the source. This follows following steps.
1517 * <p>- Extract primary key and its value from the source object.
1518 * <p>- Extract target key and its value from the target object.
1519 * <p>- Construct an update statement with above fields and values for target table.
1520 * <p>- execute the statement.
1521 */
1522 public void updateTargetRowPreDeleteSource(ObjectLevelModifyQuery query) throws DatabaseException {
1523 if (this.isReadOnly) {
1524 return;
1525 }
1526
1527 // Extract primary key and value from the source.
1528 int size = this.sourceKeyFields.size();
1529 AbstractRecord translationRow = new DatabaseRecord(size);
1530 AbstractRecord modifyRow = new DatabaseRecord(size);
1531 for (int index = 0; index < size; index++) {
1532 DatabaseField sourceKey = this.sourceKeyFields.get(index);
1533 DatabaseField targetForeignKey = this.targetForeignKeyFields.get(index);
1534 Object sourceKeyValue = query.getTranslationRow().get(sourceKey);
1535 translationRow.add(targetForeignKey, sourceKeyValue);
1536 // Need to set this value to null in the modify row.
1537 modifyRow.add(targetForeignKey, null);
1538 }
1539 if(listOrderField != null) {
1540 modifyRow.add(listOrderField, null);
1541 }
1542
1543 // Need a different modify row than translation row, as the same field has different values in each.
1544 DataModifyQuery removeQuery = (DataModifyQuery)this.removeAllTargetsQuery.clone();
1545 removeQuery.setModifyRow(modifyRow);
1546 removeQuery.setHasModifyRow(true);
1547 removeQuery.setIsExecutionClone(true);
1548 query.getSession().executeQuery(removeQuery, translationRow);
1549 }
1550
1551 /**
1552 * INTERNAL:
1553 * Used to verify whether the specified object is deleted or not.
1554 */
1555 @Override
1556 public boolean verifyDelete(Object object, AbstractSession session) throws DatabaseException {
1557 if (this.isPrivateOwned() || isCascadeRemove()) {
1558 Object objects = getRealCollectionAttributeValueFromObject(object, session);
1559
1560 ContainerPolicy containerPolicy = getContainerPolicy();
1561 for (Object iter = containerPolicy.iteratorFor(objects); containerPolicy.hasNext(iter);) {
1562 if (!session.verifyDelete(containerPolicy.next(iter, session))) {
1563 return false;
1564 }
1565 }
1566 }
1567 return true;
1568 }
1569 }
0 /*******************************************************************************
1 * Copyright (c) 1998, 2018 Oracle and/or its affiliates. All rights reserved.
2 * This program and the accompanying materials are made available under the
3 * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
4 * which accompanies this distribution.
5 * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
6 * and the Eclipse Distribution License is available at
7 * http://www.eclipse.org/org/documents/edl-v10.php.
8 *
9 * Contributors:
10 * Oracle - initial API and implementation from Oracle TopLink
11 * 07/19/2011-2.2.1 Guy Pelletier
12 * - 338812: ManyToMany mapping in aggregate object violate integrity constraint on deletion
13 ******************************************************************************/
14 package org.eclipse.persistence.mappings;
15
16 import java.util.ArrayList;
17 import java.util.Collection;
18 import java.util.Enumeration;
19 import java.util.HashMap;
20 import java.util.HashSet;
21 import java.util.Iterator;
22 import java.util.List;
23 import java.util.Map;
24 import java.util.Set;
25 import java.util.Vector;
26
27 import org.eclipse.persistence.descriptors.ClassDescriptor;
28 import org.eclipse.persistence.exceptions.ConversionException;
29 import org.eclipse.persistence.exceptions.DatabaseException;
30 import org.eclipse.persistence.exceptions.DescriptorException;
31 import org.eclipse.persistence.exceptions.OptimisticLockException;
32 import org.eclipse.persistence.expressions.Expression;
33 import org.eclipse.persistence.expressions.ExpressionBuilder;
34 import org.eclipse.persistence.internal.descriptors.CascadeLockingPolicy;
35 import org.eclipse.persistence.internal.descriptors.ObjectBuilder;
36 import org.eclipse.persistence.internal.expressions.FieldExpression;
37 import org.eclipse.persistence.internal.expressions.ParameterExpression;
38 import org.eclipse.persistence.internal.expressions.SQLUpdateStatement;
39 import org.eclipse.persistence.internal.helper.ConversionManager;
40 import org.eclipse.persistence.internal.helper.DatabaseField;
41 import org.eclipse.persistence.internal.helper.DatabaseTable;
42 import org.eclipse.persistence.internal.identitymaps.CacheId;
43 import org.eclipse.persistence.internal.identitymaps.CacheKey;
44 import org.eclipse.persistence.internal.queries.ContainerPolicy;
45 import org.eclipse.persistence.internal.sessions.AbstractRecord;
46 import org.eclipse.persistence.internal.sessions.AbstractSession;
47 import org.eclipse.persistence.internal.sessions.ObjectChangeSet;
48 import org.eclipse.persistence.internal.sessions.UnitOfWorkImpl;
49 import org.eclipse.persistence.mappings.foundation.MapComponentMapping;
50 import org.eclipse.persistence.queries.DataModifyQuery;
51 import org.eclipse.persistence.queries.DeleteAllQuery;
52 import org.eclipse.persistence.queries.DeleteObjectQuery;
53 import org.eclipse.persistence.queries.InsertObjectQuery;
54 import org.eclipse.persistence.queries.ModifyQuery;
55 import org.eclipse.persistence.queries.ObjectBuildingQuery;
56 import org.eclipse.persistence.queries.ObjectLevelModifyQuery;
57 import org.eclipse.persistence.queries.ObjectLevelReadQuery;
58 import org.eclipse.persistence.queries.WriteObjectQuery;
59 import org.eclipse.persistence.sessions.DatabaseRecord;
60
61 /**
62 * <p><b>Purpose</b>: This mapping is used to represent the
63 * typical RDBMS relationship between a single
64 * source object and collection of target objects; where,
65 * on the database, the target objects have references
66 * (foreign keys) to the source object.
67 *
68 * @author Sati
69 * @since TOPLink/Java 1.0
70 */
71 public class OneToManyMapping extends CollectionMapping implements RelationalMapping, MapComponentMapping {
72
73 /** Used for data modification events. */
74 protected static final String PostInsert = "postInsert";
75 protected static final String ObjectRemoved = "objectRemoved";
76 protected static final String ObjectAdded = "objectAdded";
77
78 /** The target foreign key fields that reference the sourceKeyFields. */
79 protected Vector<DatabaseField> targetForeignKeyFields;
80
81 /** The (typically primary) source key fields that are referenced by the targetForeignKeyFields. */
82 protected Vector<DatabaseField> sourceKeyFields;
83
84 /** This maps the target foreign key fields to the corresponding (primary) source key fields. */
85 protected transient Map<DatabaseField, DatabaseField> targetForeignKeysToSourceKeys;
86
87 /** This maps the (primary) source key fields to the corresponding target foreign key fields. */
88 protected transient Map<DatabaseField, DatabaseField> sourceKeysToTargetForeignKeys;
89
90 /** All targetForeignKeyFields should have the same table.
91 * Used only in case data modification events required.
92 **/
93 protected transient DatabaseTable targetForeignKeyTable;
94
95 /** Primary keys of targetForeignKeyTable:
96 * the same as referenceDescriptor().getPrimaryKeyFields() in case the table is default table of reference descriptor;
97 * otherwise contains secondary table's primary key fields in the same order as default table primary keys mapped to them.
98 * Used only in case data modification events required.
99 **/
100 protected transient List<DatabaseField> targetPrimaryKeyFields;
101
102 /**
103 * Keep a reference to the source and target expressions to post initialize
104 * when building a selection criteria early.
105 */
106 protected transient List<Expression> sourceExpressionsToPostInitialize;
107 protected transient List<Expression> targetExpressionsToPostInitialize;
108
109 /**
110 * Query used to update a single target row setting its foreign key to point to the source.
111 * Run once for each target added to the source.
112 * Example:
113 * for Employee with managedEmployees attribute mapped with UnidirectionalOneToMany
114 * the query looks like:
115 * UPDATE EMPLOYEE SET MANAGER_ID = 1 WHERE (EMP_ID = 2)
116 * where 1 is id of the source, and 2 is the id of the target to be added.
117 * Used only in case data modification events required.
118 **/
119 protected DataModifyQuery addTargetQuery;
120 protected boolean hasCustomAddTargetQuery;
121
122 /**
123 * Query used to update a single target row changing its foreign key value from the one pointing to the source to null.
124 * Run once for each target removed from the source.
125 * Example:
126 * for Employee with managedEmployees attribute mapped with UnidirectionalOneToMany
127 * the query looks like:
128 * UPDATE EMPLOYEE SET MANAGER_ID = null WHERE ((MANAGER_ID = 1) AND (EMP_ID = 2))
129 * where 1 is id of the source, and 2 is the id of the target to be removed.
130 * Used only in case data modification events required.
131 **/
132 protected DataModifyQuery removeTargetQuery;
133 protected boolean hasCustomRemoveTargetQuery;
134
135 /**
136 * Query used to update all target rows changing target foreign key value from the one pointing to the source to null.
137 * Run before the source object is deleted.
138 * Example:
139 * for Employee with managedEmployees attribute mapped with UnidirectionalOneToMany
140 * the query looks like:
141 * UPDATE EMPLOYEE SET MANAGER_ID = null WHERE (MANAGER_ID = 1)
142 * where 1 is id of the source to be deleted.
143 * Used only in case data modification events required.
144 **/
145 protected DataModifyQuery removeAllTargetsQuery;
146 protected boolean hasCustomRemoveAllTargetsQuery;
147 protected Boolean shouldDeferInserts = null;
148
149 /**
150 * PUBLIC:
151 * Default constructor.
152 */
153 public OneToManyMapping() {
154 super();
155
156 this.targetForeignKeysToSourceKeys = new HashMap(2);
157 this.sourceKeysToTargetForeignKeys = new HashMap(2);
158
159 this.sourceKeyFields = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(1);
160 this.targetForeignKeyFields = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(1);
161 this.sourceExpressionsToPostInitialize = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(1);
162 this.targetExpressionsToPostInitialize = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(1);
163
164 this.deleteAllQuery = new DeleteAllQuery();
165 this.removeTargetQuery = new DataModifyQuery();
166 this.removeAllTargetsQuery = new DataModifyQuery();
167
168 this.isListOrderFieldSupported = true;
169 }
170
171 /**
172 * INTERNAL:
173 */
174 @Override
175 public boolean isRelationalMapping() {
176 return true;
177 }
178
179 /**
180 * INTERNAL:
181 * Add the associated fields to the appropriate collections.
182 */
183 @Override
184 public void addTargetForeignKeyField(DatabaseField targetForeignKeyField, DatabaseField sourceKeyField) {
185 getTargetForeignKeyFields().addElement(targetForeignKeyField);
186 getSourceKeyFields().addElement(sourceKeyField);
187 }
188
189 /**
190 * PUBLIC:
191 * Define the target foreign key relationship in the one-to-many mapping.
192 * This method is used for composite target foreign key relationships.
193 * That is, the target object's table has multiple foreign key fields
194 * that are references to
195 * the source object's (typically primary) key fields.
196 * Both the target foreign key field name and the corresponding
197 * source primary key field name must be specified.
198 * Because the target object's table must store a foreign key to the source table,
199 * the target object must map that foreign key, this is normally done through a
200 * one-to-one mapping back-reference. Other options include:
201 * <ul>
202 * <li> use a DirectToFieldMapping and maintain the
203 * foreign key fields directly in the target
204 * <li> use a ManyToManyMapping
205 * <li> use an AggregateCollectionMapping
206 * </ul>
207 * @see DirectToFieldMapping
208 * @see ManyToManyMapping
209 * @see AggregateCollectionMapping
210 */
211 public void addTargetForeignKeyFieldName(String targetForeignKeyFieldName, String sourceKeyFieldName) {
212 addTargetForeignKeyField(new DatabaseField(targetForeignKeyFieldName), new DatabaseField(sourceKeyFieldName));
213 }
214
215 /**
216 * INTERNAL:
217 * Verifies listOrderField's table: it must be the same table that contains all target foreign keys.
218 * Precondition: listOrderField != null.
219 */
220 @Override
221 protected void buildListOrderField() {
222 if(this.listOrderField.hasTableName()) {
223 if(!this.targetForeignKeyTable.equals(this.listOrderField.getTable())) {
224 throw DescriptorException.listOrderFieldTableIsWrong(this.getDescriptor(), this, this.listOrderField.getTable(), this.targetForeignKeyTable);
225 }
226 } else {
227 listOrderField.setTable(this.targetForeignKeyTable);
228 }
229 this.listOrderField = this.getReferenceDescriptor().buildField(this.listOrderField, this.targetForeignKeyTable);
230 }
231
232 /**
233 * The selection criteria are created with target foreign keys and source "primary" keys.
234 * These criteria are then used to read the target records from the table.
235 * These criteria are also used as the default "delete all" criteria.
236 *
237 * CR#3922 - This method is almost the same as buildSelectionCriteria() the difference
238 * is that TargetForeignKeysToSourceKeys contains more information after login then SourceKeyFields
239 * contains before login.
240 */
241 protected Expression buildDefaultSelectionCriteriaAndAddFieldsToQuery() {
242 Expression selectionCriteria = null;
243 Expression builder = new ExpressionBuilder();
244
245 for (Iterator keys = getTargetForeignKeysToSourceKeys().keySet().iterator();
246 keys.hasNext();) {
247 DatabaseField targetForeignKey = (DatabaseField)keys.next();
248 DatabaseField sourceKey = getTargetForeignKeysToSourceKeys().get(targetForeignKey);
249
250 Expression partialSelectionCriteria = builder.getField(targetForeignKey).equal(builder.getParameter(sourceKey));
251 selectionCriteria = partialSelectionCriteria.and(selectionCriteria);
252 }
253 getContainerPolicy().addAdditionalFieldsToQuery(getSelectionQuery(), builder);
254
255 return selectionCriteria;
256 }
257
258 /**
259 * This method would allow customers to get the potential selection criteria for a mapping
260 * prior to initialization. This would allow them to more easily create an amendment method
261 * that would amend the SQL for the join.
262 *
263 * CR#3922 - This method is almost the same as buildDefaultSelectionCriteria() the difference
264 * is that TargetForeignKeysToSourceKeys contains more information after login then SourceKeyFields
265 * contains before login.
266 */
267 public Expression buildSelectionCriteria() {
268 //CR3922
269 Expression selectionCriteria = null;
270 Expression builder = new ExpressionBuilder();
271
272 Enumeration sourceKeys = getSourceKeyFields().elements();
273 for (Enumeration targetForeignKeys = getTargetForeignKeyFields().elements();
274 targetForeignKeys.hasMoreElements();) {
275 DatabaseField targetForeignKey = (DatabaseField)targetForeignKeys.nextElement();
276 DatabaseField sourceKey = (DatabaseField)sourceKeys.nextElement();
277 Expression targetExpression = builder.getField(targetForeignKey);
278 Expression sourceExpression = builder.getParameter(sourceKey);
279 // store the expressions in order to initialize their fields later
280 this.targetExpressionsToPostInitialize.add(targetExpression);
281 this.sourceExpressionsToPostInitialize.add(sourceExpression);
282
283 Expression partialSelectionCriteria = targetExpression.equal(sourceExpression);
284 selectionCriteria = partialSelectionCriteria.and(selectionCriteria);
285 }
286 return selectionCriteria;
287 }
288
289 /**
290 * INTERNAL:
291 * This method is used to store the FK fields that can be cached that correspond to noncacheable mappings
292 * the FK field values will be used to re-issue the query when cloning the shared cache entity
293 */
294 @Override
295 public void collectQueryParameters(Set<DatabaseField> cacheFields){
296 for (DatabaseField field : getSourceKeyFields()) {
297 cacheFields.add(field);
298 }
299 }
300
301 /**
302 * INTERNAL:
303 * Clone the appropriate attributes.
304 */
305 @Override
306 public Object clone() {
307 OneToManyMapping clone = (OneToManyMapping)super.clone();
308 clone.setTargetForeignKeysToSourceKeys(new HashMap(getTargetForeignKeysToSourceKeys()));
309
310 if (addTargetQuery != null){
311 clone.addTargetQuery = (DataModifyQuery) this.addTargetQuery.clone();
312 }
313 clone.removeTargetQuery = (DataModifyQuery) this.removeTargetQuery.clone();
314 clone.removeAllTargetsQuery = (DataModifyQuery) this.removeAllTargetsQuery.clone();
315
316 return clone;
317 }
318
319 /**
320 * INTERNAL
321 * Called when a DatabaseMapping is used to map the key in a collection. Returns the key.
322 */
323 @Override
324 public Object createMapComponentFromRow(AbstractRecord dbRow, ObjectBuildingQuery query, CacheKey parentCacheKey, AbstractSession session, boolean isTargetProtected){
325 return session.executeQuery(getSelectionQuery(), dbRow);
326 }
327
328 /**
329 * Delete all the reference objects with a single query.
330 */
331 protected void deleteAll(DeleteObjectQuery query, AbstractSession session) throws DatabaseException {
332 Object attribute = getAttributeValueFromObject(query.getObject());
333 if (usesIndirection()) {
334 if (!this.indirectionPolicy.objectIsInstantiated(attribute)) {
335 // An empty Vector indicates to DeleteAllQuery that no objects should be removed from cache
336 ((DeleteAllQuery)this.deleteAllQuery).executeDeleteAll(session.getSessionForClass(this.referenceClass), query.getTranslationRow(), new Vector(0));
337 return;
338 }
339 }
340 Object referenceObjects = getRealCollectionAttributeValueFromObject(query.getObject(), session);
341 // PERF: Avoid delete if empty.
342 if (session.isUnitOfWork() && this.containerPolicy.isEmpty(referenceObjects)) {
343 return;
344 }
345 ((DeleteAllQuery)this.deleteAllQuery).executeDeleteAll(session.getSessionForClass(getReferenceClass()), query.getTranslationRow(), this.containerPolicy.vectorFor(referenceObjects, session));
346 }
347
348 /**
349 * This method will make sure that all the records privately owned by this mapping are
350 * actually removed. If such records are found then those are all read and removed one
351 * by one along with their privately owned parts.
352 */
353 protected void deleteReferenceObjectsLeftOnDatabase(DeleteObjectQuery query) throws DatabaseException, OptimisticLockException {
354 Object objects = readPrivateOwnedForObject(query);
355
356 // Delete all these object one by one.
357 ContainerPolicy cp = getContainerPolicy();
358 for (Object iter = cp.iteratorFor(objects); cp.hasNext(iter);) {
359 query.getSession().deleteObject(cp.next(iter, query.getSession()));
360 }
361 }
362
363 /**
364 * INTERNAL:
365 * Extract the source primary key value from the target row.
366 * Used for batch reading, most following same order and fields as in the mapping.
367 */
368 @Override
369 protected Object extractKeyFromTargetRow(AbstractRecord row, AbstractSession session) {
370 int size = this.sourceKeyFields.size();
371 Object[] key = new Object[size];
372 ConversionManager conversionManager = session.getDatasourcePlatform().getConversionManager();
373 for (int index = 0; index < size; index++) {
374 DatabaseField targetField = this.targetForeignKeyFields.get(index);
375 DatabaseField sourceField = this.sourceKeyFields.get(index);
376 Object value = row.get(targetField);
377 // Must ensure the classification gets a cache hit.
378 try {
379 value = conversionManager.convertObject(value, sourceField.getType());
380 } catch (ConversionException e) {
381 throw ConversionException.couldNotBeConverted(this, getDescriptor(), e);
382 }
383 key[index] = value;
384 }
385 return new CacheId(key);
386 }
387
388 /**
389 * Extract the key field values from the specified row.
390 * Used for batch reading. Keep the fields in the same order
391 * as in the targetForeignKeysToSourceKeys map.
392 */
393 @Override
394 protected Object extractBatchKeyFromRow(AbstractRecord row, AbstractSession session) {
395 int size = this.sourceKeyFields.size();
396 Object[] key = new Object[size];
397 ConversionManager conversionManager = session.getDatasourcePlatform().getConversionManager();
398 for (int index = 0; index < size; index++) {
399 DatabaseField sourceField = this.sourceKeyFields.get(index);
400 Object value = row.get(sourceField);
401 // Must ensure the classification to get a cache hit.
402 try {
403 value = conversionManager.convertObject(value, sourceField.getType());
404 } catch (ConversionException exception) {
405 throw ConversionException.couldNotBeConverted(this, this.descriptor, exception);
406 }
407 key[index] = value;
408 }
409 return new CacheId(key);
410 }
411
412 /**
413 * Overrides CollectionMappig because this mapping requires a DeleteAllQuery instead of a ModifyQuery.
414 */
415 @Override
416 protected ModifyQuery getDeleteAllQuery() {
417 if (deleteAllQuery == null) {
418 deleteAllQuery = new DeleteAllQuery();//this is casted to a DeleteAllQuery
419 }
420 return deleteAllQuery;
421 }
422
423 /**
424 * INTERNAL:
425 * Return source key fields for translation by an AggregateObjectMapping
426 */
427 @Override
428 public Collection getFieldsForTranslationInAggregate() {
429 return getSourceKeyFields();
430 }
431
432 /**
433 * PUBLIC:
434 * Return the source key field names associated with the mapping.
435 * These are in-order with the targetForeignKeyFieldNames.
436 */
437 public Vector getSourceKeyFieldNames() {
438 Vector fieldNames = new Vector(getSourceKeyFields().size());
439 for (Enumeration fieldsEnum = getSourceKeyFields().elements();
440 fieldsEnum.hasMoreElements();) {
441 fieldNames.addElement(((DatabaseField)fieldsEnum.nextElement()).getQualifiedName());
442 }
443
444 return fieldNames;
445 }
446
447 /**
448 * INTERNAL:
449 * Return the source key fields.
450 */
451 public Vector<DatabaseField> getSourceKeyFields() {
452 return sourceKeyFields;
453 }
454
455 /**
456 * INTERNAL:
457 * Return the source/target key fields.
458 */
459 public Map<DatabaseField, DatabaseField> getSourceKeysToTargetForeignKeys() {
460 if (sourceKeysToTargetForeignKeys == null) {
461 sourceKeysToTargetForeignKeys = new HashMap(2);
462 }
463 return sourceKeysToTargetForeignKeys;
464 }
465
466 /**
467 * INTERNAL:
468 * Primary keys of targetForeignKeyTable.
469 */
470 @Override
471 public List<DatabaseField> getTargetPrimaryKeyFields() {
472 return this.targetPrimaryKeyFields;
473 }
474
475 /**
476 * INTERNAL:
477 * Return the target foreign key field names associated with the mapping.
478 * These are in-order with the targetForeignKeyFieldNames.
479 */
480 public Vector getTargetForeignKeyFieldNames() {
481 Vector fieldNames = new Vector(getTargetForeignKeyFields().size());
482 for (Enumeration fieldsEnum = getTargetForeignKeyFields().elements();
483 fieldsEnum.hasMoreElements();) {
484 fieldNames.addElement(((DatabaseField)fieldsEnum.nextElement()).getQualifiedName());
485 }
486
487 return fieldNames;
488 }
489
490 /**
491 * INTERNAL:
492 * Return the target foreign key fields.
493 */
494 public Vector<DatabaseField> getTargetForeignKeyFields() {
495 return targetForeignKeyFields;
496 }
497
498 /**
499 * INTERNAL:
500 * Return the target/source key fields.
501 */
502 public Map<DatabaseField, DatabaseField> getTargetForeignKeysToSourceKeys() {
503 if (targetForeignKeysToSourceKeys == null) {
504 targetForeignKeysToSourceKeys = new HashMap(2);
505 }
506 return targetForeignKeysToSourceKeys;
507 }
508
509 /**
510 * INTERNAL:
511 * Maintain for backward compatibility.
512 * This is 'public' so StoredProcedureGenerator
513 * does not have to use the custom query expressions.
514 */
515 public Map getTargetForeignKeyToSourceKeys() {
516 return getTargetForeignKeysToSourceKeys();
517 }
518
519 /**
520 * INTERNAL:
521 * Return whether the mapping has any inverse constraint dependencies,
522 * such as foreign keys and join tables.
523 */
524 @Override
525 public boolean hasInverseConstraintDependency() {
526 return true;
527 }
528
529 /**
530 * INTERNAL:
531 * Initialize the mapping.
532 */
533 @Override
534 public void initialize(AbstractSession session) throws DescriptorException {
535 if (session.hasBroker()) {
536 if (getReferenceClass() == null) {
537 throw DescriptorException.referenceClassNotSpecified(this);
538 }
539 // substitute session that owns the mapping for the session that owns reference descriptor.
540 session = session.getBroker().getSessionForClass(getReferenceClass());
541 }
542
543 super.initialize(session);
544
545 getContainerPolicy().initialize(session, getReferenceDescriptor().getDefaultTable());
546 if (shouldInitializeSelectionCriteria()) {
547 setSelectionCriteria(buildDefaultSelectionCriteriaAndAddFieldsToQuery());
548 }
549
550 initializeDeleteAllQuery(session);
551
552 if (requiresDataModificationEvents() || getContainerPolicy().requiresDataModificationEvents()) {
553 initializeAddTargetQuery(session);
554 initializeRemoveTargetQuery(session);
555 initializeRemoveAllTargetsQuery(session);
556 }
557
558 // Check if any foreign keys reference a secondary table.
559 if (getDescriptor().getTables().size() > 1) {
560 DatabaseTable firstTable = getDescriptor().getTables().get(0);
561 for (DatabaseField field : getSourceKeyFields()) {
562 if (!field.getTable().equals(firstTable)) {
563 getDescriptor().setHasMultipleTableConstraintDependecy(true);
564 }
565 }
566 }
567 }
568
569 /**
570 * INTERNAL:
571 * Initialize addTargetQuery.
572 */
573 protected void initializeAddTargetQuery(AbstractSession session) {
574 AbstractRecord modifyRow = createModifyRowForAddTargetQuery();
575 if(modifyRow.isEmpty()) {
576 return;
577 }
578
579 if (!hasCustomAddTargetQuery){
580 addTargetQuery = new DataModifyQuery();
581 }
582
583 if (!addTargetQuery.hasSessionName()) {
584 addTargetQuery.setSessionName(session.getName());
585 }
586 if (hasCustomAddTargetQuery) {
587 return;
588 }
589
590 // all fields in modifyRow must have the same table
591 DatabaseTable table = (modifyRow.getFields().get(0)).getTable();
592
593 // Build where clause expression.
594 Expression whereClause = null;
595 Expression builder = new ExpressionBuilder();
596
597 int size = targetPrimaryKeyFields.size();
598 for (int index = 0; index < size; index++) {
599 DatabaseField targetPrimaryKey = targetPrimaryKeyFields.get(index);
600 Expression expression = builder.getField(targetPrimaryKey).equal(builder.getParameter(targetPrimaryKey));
601 whereClause = expression.and(whereClause);
602 }
603
604 SQLUpdateStatement statement = new SQLUpdateStatement();
605 statement.setTable(table);
606 statement.setWhereClause(whereClause);
607 statement.setModifyRow(modifyRow);
608 addTargetQuery.setSQLStatement(statement);
609 }
610
611 /**
612 * INTERNAL:
613 */
614 protected AbstractRecord createModifyRowForAddTargetQuery() {
615 AbstractRecord modifyRow = new DatabaseRecord();
616 containerPolicy.addFieldsForMapKey(modifyRow);
617 if(listOrderField != null) {
618 modifyRow.add(listOrderField, null);
619 }
620 return modifyRow;
621 }
622
623 /**
624 * INTERNAL:
625 * Initialize changeOrderTargetQuery.
626 */
627 @Override
628 protected void initializeChangeOrderTargetQuery(AbstractSession session) {
629 boolean hasChangeOrderTargetQuery = changeOrderTargetQuery != null;
630 if(!hasChangeOrderTargetQuery) {
631 changeOrderTargetQuery = new DataModifyQuery();
632 }
633
634 changeOrderTargetQuery = new DataModifyQuery();
635 if (!changeOrderTargetQuery.hasSessionName()) {
636 changeOrderTargetQuery.setSessionName(session.getName());
637 }
638 if (hasChangeOrderTargetQuery) {
639 return;
640 }
641
642 DatabaseTable table = this.listOrderField.getTable();
643
644 // Build where clause expression.
645 Expression whereClause = null;
646 Expression builder = new ExpressionBuilder();
647
648 int size = targetPrimaryKeyFields.size();
649 for (int index = 0; index < size; index++) {
650 DatabaseField targetPrimaryKey = targetPrimaryKeyFields.get(index);
651 Expression expression = builder.getField(targetPrimaryKey).equal(builder.getParameter(targetPrimaryKey));
652 whereClause = expression.and(whereClause);
653 }
654
655 AbstractRecord modifyRow = new DatabaseRecord();
656 modifyRow.add(this.listOrderField, null);
657
658 SQLUpdateStatement statement = new SQLUpdateStatement();
659 statement.setTable(table);
660 statement.setWhereClause(whereClause);
661 statement.setModifyRow(modifyRow);
662 changeOrderTargetQuery.setSQLStatement(statement);
663 }
664
665 /**
666 * Initialize the delete all query.
667 * This query is used to delete the collection of objects from the
668 * database.
669 */
670 protected void initializeDeleteAllQuery(AbstractSession session) {
671 ((DeleteAllQuery)getDeleteAllQuery()).setReferenceClass(getReferenceClass());
672 getDeleteAllQuery().setName(getAttributeName());
673 ((DeleteAllQuery)getDeleteAllQuery()).setIsInMemoryOnly(isCascadeOnDeleteSetOnDatabase());
674 if (!hasCustomDeleteAllQuery()) {
675 // the selection criteria are re-used by the delete all query
676 if (getSelectionCriteria() == null) {
677 getDeleteAllQuery().setSelectionCriteria(buildDefaultSelectionCriteriaAndAddFieldsToQuery());
678 } else {
679 getDeleteAllQuery().setSelectionCriteria(getSelectionCriteria());
680 }
681 }
682 if (!getDeleteAllQuery().hasSessionName()) {
683 getDeleteAllQuery().setSessionName(session.getName());
684 }
685 if (getDeleteAllQuery().getPartitioningPolicy() == null) {
686 getDeleteAllQuery().setPartitioningPolicy(getPartitioningPolicy());
687 }
688 }
689
690 /**
691 * INTERNAL:
692 * Initialize targetForeignKeyTable and initializeTargetPrimaryKeyFields.
693 * This method should be called after initializeTargetForeignKeysToSourceKeys method,
694 * which creates targetForeignKeyFields (guaranteed to be not empty in case
695 * requiresDataModificationEvents method returns true - the only case for the method to be called).
696 */
697 protected void initializeTargetPrimaryKeyFields() {
698 // all target foreign key fields must have the same table.
699 int size = getTargetForeignKeyFields().size();
700 HashSet<DatabaseTable> tables = new HashSet();
701 for(int i=0; i < size; i++) {
702 tables.add(getTargetForeignKeyFields().get(i).getTable());
703 }
704 if(tables.size() == 1) {
705 this.targetForeignKeyTable = getTargetForeignKeyFields().get(0).getTable();
706 } else {
707 // multiple foreign key tables - throw exception.
708 throw DescriptorException.multipleTargetForeignKeyTables(this.getDescriptor(), this, tables);
709 }
710
711 List defaultTablePrimaryKeyFields = getReferenceDescriptor().getPrimaryKeyFields();
712 if(this.targetForeignKeyTable.equals(getReferenceDescriptor().getDefaultTable())) {
713 this.targetPrimaryKeyFields = defaultTablePrimaryKeyFields;
714 } else {
715 int sizePk = defaultTablePrimaryKeyFields.size();
716 this.targetPrimaryKeyFields = new ArrayList();
717 for(int i=0; i < sizePk; i++) {
718 this.targetPrimaryKeyFields.add(null);
719 }
720 Map<DatabaseField, DatabaseField> map = getReferenceDescriptor().getAdditionalTablePrimaryKeyFields().get(this.targetForeignKeyTable);
721 Iterator<Map.Entry<DatabaseField, DatabaseField>> it = map.entrySet().iterator();
722 while(it.hasNext()) {
723 Map.Entry<DatabaseField, DatabaseField> entry = it.next();
724 DatabaseField sourceField = entry.getKey();
725 DatabaseField targetField = entry.getValue();
726 DatabaseField additionalTableField;
727 DatabaseField defaultTableField;
728 if(sourceField.getTable().equals(this.targetForeignKeyTable)) {
729 additionalTableField = sourceField;
730 defaultTableField = targetField;
731 } else {
732 defaultTableField = sourceField;
733 additionalTableField = targetField;
734 }
735 int index = defaultTablePrimaryKeyFields.indexOf(defaultTableField);
736 getReferenceDescriptor().buildField(additionalTableField, this.targetForeignKeyTable);
737 this.targetPrimaryKeyFields.set(index, additionalTableField);
738 }
739 }
740 }
741
742 /**
743 * INTERNAL:
744 * Initialize removeTargetQuery.
745 */
746 protected void initializeRemoveTargetQuery(AbstractSession session) {
747 if (!removeTargetQuery.hasSessionName()) {
748 removeTargetQuery.setSessionName(session.getName());
749 }
750 if (hasCustomRemoveTargetQuery) {
751 return;
752 }
753
754 // All targetForeignKeys should have the same table
755 DatabaseTable table = targetForeignKeyFields.get(0).getTable();
756
757 // Build where clause expression.
758 Expression whereClause = null;
759 Expression builder = new ExpressionBuilder();
760
761 int size = targetPrimaryKeyFields.size();
762 for (int index = 0; index < size; index++) {
763 DatabaseField targetPrimaryKey = targetPrimaryKeyFields.get(index);
764 Expression expression = builder.getField(targetPrimaryKey).equal(builder.getParameter(targetPrimaryKey));
765 whereClause = expression.and(whereClause);
766 }
767
768 AbstractRecord modifyRow = new DatabaseRecord();
769 if(shouldRemoveTargetQueryModifyTargetForeignKey()) {
770 size = targetForeignKeyFields.size();
771 for (int index = 0; index < size; index++) {
772 DatabaseField targetForeignKey = targetForeignKeyFields.get(index);
773 modifyRow.put(targetForeignKey, null);
774 Expression expression = builder.getField(targetForeignKey).equal(builder.getParameter(targetForeignKey));
775 whereClause = expression.and(whereClause);
776 }
777 }
778 if(listOrderField != null) {
779 modifyRow.add(listOrderField, null);
780 }
781
782 SQLUpdateStatement statement = new SQLUpdateStatement();
783 statement.setTable(table);
784 statement.setWhereClause(whereClause);
785 statement.setModifyRow(modifyRow);
786 removeTargetQuery.setSQLStatement(statement);
787 }
788
789 /**
790 * Initialize and set the descriptor for the referenced class in this mapping.
791 * Added here initialization of target foreign keys and target primary keys so that they are ready when
792 * CollectionMapping.initialize initializes listOrderField.
793 */
794 @Override
795 protected void initializeReferenceDescriptor(AbstractSession session) throws DescriptorException {
796 super.initializeReferenceDescriptor(session);
797 if (!isSourceKeySpecified()) {
798 // sourceKeyFields will be empty when #setTargetForeignKeyFieldName() is used
799 setSourceKeyFields(org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(getDescriptor().getPrimaryKeyFields()));
800 }
801 initializeTargetForeignKeysToSourceKeys();
802 if (usesIndirection()) {
803 for (DatabaseField field : getSourceKeyFields()) {
804 field.setKeepInRow(true);
805 }
806 }
807 if(requiresDataModificationEvents() || getContainerPolicy().requiresDataModificationEvents()) {
808 initializeTargetPrimaryKeyFields();
809 }
810 }
811
812 /**
813 * INTERNAL:
814 * Initialize removeAllTargetsQuery.
815 */
816 protected void initializeRemoveAllTargetsQuery(AbstractSession session) {
817 if (!removeAllTargetsQuery.hasSessionName()) {
818 removeAllTargetsQuery.setSessionName(session.getName());
819 }
820 if (hasCustomRemoveAllTargetsQuery) {
821 return;
822 }
823
824 // All targetForeignKeys should have the same table
825 DatabaseTable table = targetForeignKeyFields.get(0).getTable();
826
827 // Build where clause expression.
828 Expression whereClause = null;
829 Expression builder = new ExpressionBuilder();
830
831 AbstractRecord modifyRow = new DatabaseRecord();
832 int size = targetForeignKeyFields.size();
833 for (int index = 0; index < size; index++) {
834 DatabaseField targetForeignKey = targetForeignKeyFields.get(index);
835 if(shouldRemoveTargetQueryModifyTargetForeignKey()) {
836 modifyRow.put(targetForeignKey, null);
837 }
838 Expression expression = builder.getField(targetForeignKey).equal(builder.getParameter(targetForeignKey));
839 whereClause = expression.and(whereClause);
840 }
841 if(this.listOrderField != null) {
842 // targetForeignKeys and listOrderField should have the same table
843 modifyRow.add(this.listOrderField, null);
844 }
845
846 SQLUpdateStatement statement = new SQLUpdateStatement();
847 statement.setTable(table);
848 statement.setWhereClause(whereClause);
849 statement.setModifyRow(modifyRow);
850 removeAllTargetsQuery.setSQLStatement(statement);
851 }
852
853 /**
854 * Verify, munge, and hash the target foreign keys and source keys.
855 */
856 protected void initializeTargetForeignKeysToSourceKeys() throws DescriptorException {
857 if (getTargetForeignKeyFields().isEmpty()) {
858 if (shouldInitializeSelectionCriteria() || requiresDataModificationEvents() || getContainerPolicy().requiresDataModificationEvents()) {
859 throw DescriptorException.noTargetForeignKeysSpecified(this);
860 } else {
861 // if they have specified selection criteria, the keys do not need to be specified
862 return;
863 }
864 }
865
866 if (getTargetForeignKeyFields().size() != getSourceKeyFields().size()) {
867 throw DescriptorException.targetForeignKeysSizeMismatch(this);
868 }
869
870 for (int index = 0; index < getTargetForeignKeyFields().size(); index++) {
871 DatabaseField field = getReferenceDescriptor().buildField(getTargetForeignKeyFields().get(index));
872 getTargetForeignKeyFields().set(index, field);
873 }
874
875 for (int index = 0; index < getSourceKeyFields().size(); index++) {
876 DatabaseField field = getDescriptor().buildField(getSourceKeyFields().get(index));
877 getSourceKeyFields().set(index, field);
878 }
879
880 Iterator<DatabaseField> targetForeignKeys = getTargetForeignKeyFields().iterator();
881 Iterator<DatabaseField> sourceKeys = getSourceKeyFields().iterator();
882 while (targetForeignKeys.hasNext()) {
883 DatabaseField targetForeignKey = targetForeignKeys.next();
884 DatabaseField sourcePrimaryKey = sourceKeys.next();
885 getTargetForeignKeysToSourceKeys().put(targetForeignKey, sourcePrimaryKey);
886 getSourceKeysToTargetForeignKeys().put(sourcePrimaryKey, targetForeignKey);
887 }
888 }
889
890 /**
891 * INTERNAL:
892 */
893 @Override
894 public boolean isOneToManyMapping() {
895 return true;
896 }
897
898 /**
899 * Return whether the source key is specified.
900 * It will be empty when #setTargetForeignKeyFieldName(String) is used.
901 */
902 protected boolean isSourceKeySpecified() {
903 return !getSourceKeyFields().isEmpty();
904 }
905
906 /**
907 * INTERNAL:
908 * An object was added to the collection during an update, insert it if private.
909 */
910 @Override
911 protected void objectAddedDuringUpdate(ObjectLevelModifyQuery query, Object objectAdded, ObjectChangeSet changeSet, Map extraData) throws DatabaseException, OptimisticLockException {
912 // First insert/update object.
913 super.objectAddedDuringUpdate(query, objectAdded, changeSet, extraData);
914
915 if (requiresDataModificationEvents() || containerPolicy.requiresDataModificationEvents()){
916 // In the uow data queries are cached until the end of the commit.
917 if (query.shouldCascadeOnlyDependentParts()) {
918 if (shouldDeferInsert()) {
919 // Hey I might actually want to use an inner class here... ok array for now.
920 Object[] event = new Object[4];
921 event[0] = ObjectAdded;
922 event[1] = query;
923 event[2] = objectAdded;
924 event[3] = extraData;
925 query.getSession().getCommitManager().addDataModificationEvent(this, event);
926 } else {
927 ContainerPolicy cp = getContainerPolicy();
928 prepareTranslationRow(query.getTranslationRow(), query.getObject(), query.getDescriptor(), query.getSession());
929 AbstractRecord keyRow = buildKeyRowForTargetUpdate(query);
930
931 // Extract target field and its value. Construct insert statement and execute it
932 ClassDescriptor referenceDesc = getReferenceDescriptor();
933 AbstractSession session = query.getSession();
934
935 AbstractRecord databaseRow = referenceDesc.getObjectBuilder().buildRow(keyRow, objectAdded, session, WriteType.INSERT);
936 ContainerPolicy.copyMapDataToRow(cp.getKeyMappingDataForWriteQuery(objectAdded, query.getSession()), databaseRow);
937 if(listOrderField != null && extraData != null) {
938 databaseRow.put(listOrderField, extraData.get(listOrderField));
939 }
940
941 InsertObjectQuery insertQuery = getInsertObjectQuery(session, referenceDesc);
942 insertQuery.setObject(objectAdded);
943 insertQuery.setCascadePolicy(query.getCascadePolicy());
944 insertQuery.setTranslationRow(databaseRow);
945 insertQuery.setModifyRow(databaseRow);
946 insertQuery.setIsPrepared(false);
947 query.getSession().executeQuery(insertQuery);
948 }
949 } else {
950 updateTargetForeignKeyPostUpdateSource_ObjectAdded(query, objectAdded, extraData);
951 }
952 }
953 }
954
955 /**
956 * INTERNAL:
957 * An object was removed to the collection during an update, delete it if private.
958 */
959 @Override
960 protected void objectRemovedDuringUpdate(ObjectLevelModifyQuery query, Object objectDeleted, Map extraData) throws DatabaseException, OptimisticLockException {
961 if(!isPrivateOwned()) {
962 if (requiresDataModificationEvents() || containerPolicy.requiresDataModificationEvents()){
963 // In the uow data queries are cached until the end of the commit.
964 if (query.shouldCascadeOnlyDependentParts()) {
965 // Hey I might actually want to use an inner class here... ok array for now.
966 Object[] event = new Object[3];
967 event[0] = ObjectRemoved;
968 event[1] = query;
969 event[2] = objectDeleted;
970 query.getSession().getCommitManager().addDataModificationEvent(this, event);
971 } else {
972 updateTargetForeignKeyPostUpdateSource_ObjectRemoved(query, objectDeleted);
973 }
974 }
975 }
976
977 // Delete object after join entry is delete if private.
978 super.objectRemovedDuringUpdate(query, objectDeleted, extraData);
979 }
980
981
982 /**
983 * INTERNAL:
984 * Perform the commit event.
985 * This is used in the uow to delay data modifications.
986 */
987 @Override
988 public void performDataModificationEvent(Object[] event, AbstractSession session) throws DatabaseException, DescriptorException {
989 // Hey I might actually want to use an inner class here... ok array for now.
990 if (event[0] == PostInsert) {
991 updateTargetRowPostInsertSource((WriteObjectQuery)event[1]);
992 } else if (event[0] == ObjectRemoved) {
993 updateTargetForeignKeyPostUpdateSource_ObjectRemoved((WriteObjectQuery)event[1], event[2]);
994 } else if (event[0] == ObjectAdded) {
995 updateTargetForeignKeyPostUpdateSource_ObjectAdded((WriteObjectQuery)event[1], event[2], (Map)event[3]);
996 } else {
997 throw DescriptorException.invalidDataModificationEventCode(event[0], this);
998 }
999 }
1000
1001 /**
1002 * INTERNAL:
1003 * Insert the reference objects.
1004 */
1005 @Override
1006 public void postInsert(WriteObjectQuery query) throws DatabaseException, OptimisticLockException {
1007 if (isReadOnly()) {
1008 return;
1009 }
1010
1011 if (shouldObjectModifyCascadeToParts(query) && !query.shouldCascadeOnlyDependentParts()) {
1012 Object objects = getRealCollectionAttributeValueFromObject(query.getObject(), query.getSession());
1013 // insert each object one by one
1014 ContainerPolicy cp = getContainerPolicy();
1015 for (Object iter = cp.iteratorFor(objects); cp.hasNext(iter);) {
1016 Object wrappedObject = cp.nextEntry(iter, query.getSession());
1017 Object object = cp.unwrapIteratorResult(wrappedObject);
1018 if (isPrivateOwned()) {
1019 // no need to set changeSet as insert is a straight copy
1020 InsertObjectQuery insertQuery = new InsertObjectQuery();
1021 insertQuery.setIsExecutionClone(true);
1022 insertQuery.setObject(object);
1023 insertQuery.setCascadePolicy(query.getCascadePolicy());
1024 query.getSession().executeQuery(insertQuery);
1025 } else {
1026 // This will happen in a cascaded query.
1027 // This is done only for persistence by reachability and is not required if the targets are in the queue anyway
1028 // Avoid cycles by checking commit manager, this is allowed because there is no dependency.
1029 if (!query.getSession().getCommitManager().isCommitInPreModify(object)) {
1030 WriteObjectQuery writeQuery = new WriteObjectQuery();
1031 writeQuery.setIsExecutionClone(true);
1032 writeQuery.setObject(object);
1033 writeQuery.setCascadePolicy(query.getCascadePolicy());
1034 query.getSession().executeQuery(writeQuery);
1035 }
1036 }
1037 cp.propogatePostInsert(query, wrappedObject);
1038 }
1039 }
1040 if (requiresDataModificationEvents() || getContainerPolicy().requiresDataModificationEvents()) {
1041 // only cascade dependents in UOW
1042 if (query.shouldCascadeOnlyDependentParts()) {
1043 if ((requiresDataModificationEvents() || containerPolicy.shouldUpdateForeignKeysPostInsert())) {
1044 if (shouldDeferInsert()) {
1045 // Hey I might actually want to use an inner class here... ok array for now.
1046 Object[] event = new Object[2];
1047 event[0] = PostInsert;
1048 event[1] = query;
1049 query.getSession().getCommitManager().addDataModificationEvent(this, event);
1050 } else {
1051 ContainerPolicy cp = getContainerPolicy();
1052 Object objects = getRealCollectionAttributeValueFromObject(query.getObject(), query.getSession());
1053 if (cp.isEmpty(objects)) {
1054 return;
1055 }
1056
1057 prepareTranslationRow(query.getTranslationRow(), query.getObject(), query.getDescriptor(), query.getSession());
1058
1059 AbstractRecord keyRow = buildKeyRowForTargetUpdate(query);
1060
1061 // Extract target field and its value. Construct insert
1062 // statement and execute it
1063 ClassDescriptor referenceDesc = getReferenceDescriptor();
1064 AbstractSession session = query.getSession();
1065 int objectIndex = 0;
1066 for (Object iter = cp.iteratorFor(objects); cp.hasNext(iter);) {
1067 AbstractRecord row = new DatabaseRecord();
1068 row.mergeFrom(keyRow);
1069 Object wrappedObject = cp.nextEntry(iter, query.getSession());
1070 Object object = cp.unwrapIteratorResult(wrappedObject);
1071 AbstractRecord databaseRow = referenceDesc.getObjectBuilder().buildRow(row, object, session, WriteType.INSERT);
1072 ContainerPolicy.copyMapDataToRow(cp.getKeyMappingDataForWriteQuery(wrappedObject, session), databaseRow);
1073 if (listOrderField != null) {
1074 databaseRow.put(listOrderField, objectIndex++);
1075 }
1076 InsertObjectQuery insertQuery = getInsertObjectQuery(session, referenceDesc);
1077 insertQuery.setObject(object);
1078 insertQuery.setCascadePolicy(query.getCascadePolicy());
1079 insertQuery.setTranslationRow(databaseRow);
1080 insertQuery.setModifyRow(databaseRow);
1081 insertQuery.setIsPrepared(false);
1082 query.getSession().executeQuery(insertQuery);
1083 }
1084 }
1085 }
1086 } else {
1087 if ((requiresDataModificationEvents() || containerPolicy.shouldUpdateForeignKeysPostInsert())) {
1088 updateTargetRowPostInsertSource(query);
1089 }
1090 }
1091 }
1092 }
1093
1094 /**
1095 * INTERNAL:
1096 * Post-initialize source and target expression fields created when a mapping's selectionCriteria
1097 * is created early with only partly initialized fields.
1098 */
1099 @Override
1100 public void postInitializeSourceAndTargetExpressions() {
1101 // EL Bug 426500
1102 // postInitialize and set source expression fields using my descriptor
1103 if (this.sourceExpressionsToPostInitialize != null && this.sourceExpressionsToPostInitialize.size() > 0) {
1104 ClassDescriptor descriptor = getDescriptor();
1105 ObjectBuilder objectBuilder = descriptor.getObjectBuilder();
1106 for (Iterator<Expression> expressions = this.sourceExpressionsToPostInitialize.iterator(); expressions.hasNext();) {
1107 Expression expression = expressions.next();
1108 DatabaseField field = null;
1109 if (expression.isParameterExpression()) {
1110 field = ((ParameterExpression)expression).getField();
1111 } else if (expression.isFieldExpression()) {
1112 field = ((FieldExpression)expression).getField();
1113 }
1114 if (field != null && (field.getType() == null || field.getTypeName() == null)) {
1115 field.setType(objectBuilder.getFieldClassification(field));
1116 }
1117 }
1118 }
1119
1120 // postInitialize and set target expression fields using my reference descriptor
1121 if (this.targetExpressionsToPostInitialize != null && this.targetExpressionsToPostInitialize.size() > 0) {
1122 ClassDescriptor descriptor = getReferenceDescriptor();
1123 ObjectBuilder objectBuilder = descriptor.getObjectBuilder();
1124 for (Iterator<Expression> expressions = this.targetExpressionsToPostInitialize.iterator(); expressions.hasNext();) {
1125 Expression expression = expressions.next();
1126 DatabaseField field = null;
1127 if (expression.isParameterExpression()) {
1128 field = ((ParameterExpression)expression).getField();
1129 } else if (expression.isFieldExpression()) {
1130 field = ((FieldExpression)expression).getField();
1131 }
1132 if (field != null && (field.getType() == null || field.getTypeName() == null)) {
1133 field.setType(objectBuilder.getFieldClassification(field));
1134 }
1135 }
1136 }
1137 }
1138
1139 /**
1140 * INTERNAL:
1141 * Update the reference objects.
1142 */
1143 @Override
1144 public void postUpdate(WriteObjectQuery query) throws DatabaseException, OptimisticLockException {
1145 if (this.isReadOnly) {
1146 return;
1147 }
1148
1149 if (!requiresDataModificationEvents() && !shouldObjectModifyCascadeToParts(query)){
1150 return;
1151 }
1152
1153 // if the target objects are not instantiated, they could not have been changed....
1154 if (!isAttributeValueInstantiatedOrChanged(query.getObject())) {
1155 return;
1156 }
1157
1158 if (query.getObjectChangeSet() != null) {
1159 // UnitOfWork
1160 writeChanges(query.getObjectChangeSet(), query);
1161 } else {
1162 // OLD COMMIT
1163 compareObjectsAndWrite(query);
1164 }
1165 }
1166
1167 /**
1168 * INTERNAL:
1169 * Return the selection criteria used to IN batch fetching.
1170 */
1171 @Override
1172 protected Expression buildBatchCriteria(ExpressionBuilder builder, ObjectLevelReadQuery query) {
1173 int size = this.targetForeignKeyFields.size();
1174 if (size > 1) {
1175 // Support composite keys using nested IN.
1176 List<Expression> fields = new ArrayList<Expression>(size);
1177 for (DatabaseField targetForeignKeyField : this.targetForeignKeyFields) {
1178 fields.add(builder.getField(targetForeignKeyField));
1179 }
1180 return query.getSession().getPlatform().buildBatchCriteriaForComplexId(builder, fields);
1181 } else {
1182 return query.getSession().getPlatform().buildBatchCriteria(builder, builder.getField(this.targetForeignKeyFields.get(0)));
1183 }
1184 }
1185
1186 /**
1187 * INTERNAL:
1188 * Delete the reference objects.
1189 */
1190 @Override
1191 public void preDelete(DeleteObjectQuery query) throws DatabaseException, OptimisticLockException {
1192 if (!shouldObjectModifyCascadeToParts(query)) {
1193 if (this.listOrderField != null) {
1194 updateTargetRowPreDeleteSource(query);
1195 }
1196 return;
1197 }
1198 AbstractSession session = query.getSession();
1199
1200 // If privately-owned parts have their privately-owned sub-parts, delete them one by one;
1201 // else delete everything in one shot.
1202 if (mustDeleteReferenceObjectsOneByOne()) {
1203 Object objects = getRealCollectionAttributeValueFromObject(query.getObject(), session);
1204 ContainerPolicy cp = getContainerPolicy();
1205 if (this.isCascadeOnDeleteSetOnDatabase && session.isUnitOfWork()) {
1206 for (Object iterator = cp.iteratorFor(objects); cp.hasNext(iterator);) {
1207 Object wrappedObject = cp.nextEntry(iterator, session);
1208 Object object = cp.unwrapIteratorResult(wrappedObject);
1209 ((UnitOfWorkImpl)session).getCascadeDeleteObjects().add(object);
1210 }
1211 }
1212 int cascade = query.getCascadePolicy();
1213 for (Object iterator = cp.iteratorFor(objects); cp.hasNext(iterator);) {
1214 Object wrappedObject = cp.nextEntry(iterator, session);
1215 Object object = cp.unwrapIteratorResult(wrappedObject);
1216 // PERF: Avoid query execution if already deleted.
1217 if (!session.getCommitManager().isCommitCompletedInPostOrIgnore(object) || this.containerPolicy.propagatesEventsToCollection()) {
1218 if (session.isUnitOfWork() && ((UnitOfWorkImpl)session).isObjectNew(object) ){
1219 session.getCommitManager().markIgnoreCommit(object);
1220 } else {
1221 DeleteObjectQuery deleteQuery = new DeleteObjectQuery();
1222 deleteQuery.setIsExecutionClone(true);
1223 deleteQuery.setObject(object);
1224 deleteQuery.setCascadePolicy(cascade);
1225 session.executeQuery(deleteQuery);
1226 this.containerPolicy.propogatePreDelete(deleteQuery, wrappedObject);
1227 }
1228 }
1229 }
1230 if (!session.isUnitOfWork()) {
1231 // This deletes any objects on the database, as the collection in memory may have been changed.
1232 // This is not required for unit of work, as the update would have already deleted these objects,
1233 // and the backup copy will include the same objects causing double deletes.
1234 deleteReferenceObjectsLeftOnDatabase(query);
1235 }
1236 } else {
1237 deleteAll(query, session);
1238 }
1239 }
1240
1241 /**
1242 * Prepare a cascade locking policy.
1243 */
1244 @Override
1245 public void prepareCascadeLockingPolicy() {
1246 CascadeLockingPolicy policy = new CascadeLockingPolicy(getDescriptor(), getReferenceDescriptor());
1247 policy.setQueryKeyFields(getSourceKeysToTargetForeignKeys());
1248 getReferenceDescriptor().addCascadeLockingPolicy(policy);
1249 }
1250
1251 /**
1252 * INTERNAL:
1253 * Returns whether this mapping uses data modification events to complete its writes
1254 * @see UnidirectionalOneToManyMapping
1255 */
1256 public boolean requiresDataModificationEvents(){
1257 return this.listOrderField != null;
1258 }
1259
1260 /**
1261 * PUBLIC:
1262 * The default add target query for mapping can be overridden by specifying the new query.
1263 * This query must set new value to target foreign key.
1264 */
1265 public void setCustomAddTargetQuery(DataModifyQuery query) {
1266 addTargetQuery = query;
1267 hasCustomAddTargetQuery = true;
1268 }
1269
1270
1271 /**
1272 * PUBLIC:
1273 */
1274 public void setAddTargetSQLString(String sqlString) {
1275 DataModifyQuery query = new DataModifyQuery();
1276 query.setSQLString(sqlString);
1277 setCustomAddTargetQuery(query);
1278 }
1279
1280 /**
1281 * PUBLIC:
1282 * The default remove target query for mapping can be overridden by specifying the new query.
1283 * In case target foreign key references the source, this query must set target foreign key to null.
1284 */
1285 public void setCustomRemoveTargetQuery(DataModifyQuery query) {
1286 removeTargetQuery = query;
1287 hasCustomRemoveTargetQuery = true;
1288 }
1289
1290 /**
1291 * PUBLIC:
1292 * The default remove all targets query for mapping can be overridden by specifying the new query.
1293 * This query must set all target foreign keys that reference the source to null.
1294 */
1295 public void setCustomRemoveAllTargetsQuery(DataModifyQuery query) {
1296 removeAllTargetsQuery = query;
1297 hasCustomRemoveAllTargetsQuery = true;
1298 }
1299
1300 /**
1301 * PUBLIC:
1302 * Set the SQL string used by the mapping to delete the target objects.
1303 * This allows the developer to override the SQL
1304 * generated by TopLink with a custom SQL statement or procedure call.
1305 * The arguments are
1306 * translated from the fields of the source row, by replacing the field names
1307 * marked by '#' with the values for those fields at execution time.
1308 * A one-to-many mapping will only use this delete all optimization if the target objects
1309 * can be deleted in a single SQL call. This is possible when the target objects
1310 * are in a single table, do not using locking, do not contain other privately-owned
1311 * parts, do not read subclasses, etc.
1312 * <p>
1313 * Example: "delete from PHONE where OWNER_ID = #EMPLOYEE_ID"
1314 */
1315 @Override
1316 public void setDeleteAllSQLString(String sqlString) {
1317 DeleteAllQuery query = new DeleteAllQuery();
1318 query.setSQLString(sqlString);
1319 setCustomDeleteAllQuery(query);
1320 }
1321
1322
1323 /**
1324 * PUBLIC:
1325 * Set the name of the session to execute the mapping's queries under.
1326 * This can be used by the session broker to override the default session
1327 * to be used for the target class.
1328 */
1329 @Override
1330 public void setSessionName(String name) {
1331 super.setSessionName(name);
1332 if (addTargetQuery != null){
1333 addTargetQuery.setSessionName(name);
1334 }
1335 removeTargetQuery.setSessionName(name);
1336 removeAllTargetsQuery.setSessionName(name);
1337 }
1338
1339 /**
1340 * INTERNAL:
1341 * Set the source key field names associated with the mapping.
1342 * These must be in-order with the targetForeignKeyFieldNames.
1343 */
1344 public void setSourceKeyFieldNames(Vector fieldNames) {
1345 Vector fields = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(fieldNames.size());
1346 for (Enumeration fieldNamesEnum = fieldNames.elements(); fieldNamesEnum.hasMoreElements();) {
1347 fields.addElement(new DatabaseField((String)fieldNamesEnum.nextElement()));
1348 }
1349
1350 setSourceKeyFields(fields);
1351 }
1352
1353 /**
1354 * INTERNAL:
1355 * Set the source key fields.
1356 */
1357 public void setSourceKeyFields(Vector<DatabaseField> sourceKeyFields) {
1358 this.sourceKeyFields = sourceKeyFields;
1359 }
1360
1361 /**
1362 * PUBLIC:
1363 * Define the target foreign key relationship in the one-to-many mapping.
1364 * This method can be used when the foreign and primary keys
1365 * have only a single field each.
1366 * (Use #addTargetForeignKeyFieldName(String, String)
1367 * for "composite" keys.)
1368 * Only the target foreign key field name is specified and the source
1369 * (primary) key field is
1370 * assumed to be the primary key of the source object.
1371 * Because the target object's table must store a foreign key to the source table,
1372 * the target object must map that foreign key, this is normally done through a
1373 * one-to-one mapping back-reference. Other options include:
1374 * <ul>
1375 * <li> use a DirectToFieldMapping and maintain the
1376 * foreign key fields directly in the target
1377 * <li> use a ManyToManyMapping
1378 * <li> use an AggregateCollectionMapping
1379 * </ul>
1380 * @see DirectToFieldMapping
1381 * @see ManyToManyMapping
1382 * @see AggregateCollectionMapping
1383 */
1384 public void setTargetForeignKeyFieldName(String targetForeignKeyFieldName) {
1385 getTargetForeignKeyFields().addElement(new DatabaseField(targetForeignKeyFieldName));
1386 }
1387
1388 /**
1389 * PUBLIC:
1390 * Define the target foreign key relationship in the one-to-many mapping.
1391 * This method is used for composite target foreign key relationships.
1392 * That is, the target object's table has multiple foreign key fields to
1393 * the source object's (typically primary) key fields.
1394 * Both the target foreign key field names and the corresponding source primary
1395 * key field names must be specified.
1396 */
1397 public void setTargetForeignKeyFieldNames(String[] targetForeignKeyFieldNames, String[] sourceKeyFieldNames) {
1398 if (targetForeignKeyFieldNames.length != sourceKeyFieldNames.length) {
1399 throw DescriptorException.targetForeignKeysSizeMismatch(this);
1400 }
1401 for (int i = 0; i < targetForeignKeyFieldNames.length; i++) {
1402 addTargetForeignKeyFieldName(targetForeignKeyFieldNames[i], sourceKeyFieldNames[i]);
1403 }
1404 }
1405
1406 /**
1407 * INTERNAL:
1408 * Set the target key field names associated with the mapping.
1409 * These must be in-order with the sourceKeyFieldNames.
1410 */
1411 public void setTargetForeignKeyFieldNames(Vector fieldNames) {
1412 Vector fields = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(fieldNames.size());
1413 for (Enumeration fieldNamesEnum = fieldNames.elements(); fieldNamesEnum.hasMoreElements();) {
1414 fields.addElement(new DatabaseField((String)fieldNamesEnum.nextElement()));
1415 }
1416
1417 setTargetForeignKeyFields(fields);
1418 }
1419
1420 /**
1421 * INTERNAL:
1422 * Set the target fields.
1423 */
1424 public void setTargetForeignKeyFields(Vector<DatabaseField> targetForeignKeyFields) {
1425 this.targetForeignKeyFields = targetForeignKeyFields;
1426 }
1427
1428 /**
1429 * INTERNAL:
1430 * Set the target fields.
1431 */
1432 protected void setTargetForeignKeysToSourceKeys(Map<DatabaseField, DatabaseField> targetForeignKeysToSourceKeys) {
1433 this.targetForeignKeysToSourceKeys = targetForeignKeysToSourceKeys;
1434 }
1435
1436 /**
1437 * Return whether any process leading to object modification
1438 * should also affect its parts.
1439 * Used by write, insert, update, and delete.
1440 */
1441 @Override
1442 protected boolean shouldObjectModifyCascadeToParts(ObjectLevelModifyQuery query) {
1443 if (isReadOnly()) {
1444 return false;
1445 }
1446
1447 if (isPrivateOwned()) {
1448 return true;
1449 }
1450
1451 if (containerPolicy.isMappedKeyMapPolicy() && containerPolicy.requiresDataModificationEvents()){
1452 return true;
1453 }
1454
1455 return query.shouldCascadeAllParts();
1456 }
1457
1458 /**
1459 * INTERNAL
1460 * If it's not a map then target foreign key has been already modified (set to null).
1461 */
1462 protected boolean shouldRemoveTargetQueryModifyTargetForeignKey() {
1463 return containerPolicy.isMapPolicy();
1464 }
1465
1466 /**
1467 * INTERNAL
1468 * Return true if this mapping supports cascaded version optimistic locking.
1469 */
1470 @Override
1471 public boolean isCascadedLockingSupported() {
1472 return true;
1473 }
1474
1475 /**
1476 * INTERNAL:
1477 * Return if this mapping support joining.
1478 */
1479 @Override
1480 public boolean isJoiningSupported() {
1481 return true;
1482 }
1483
1484 /**
1485 * INTERNAL:
1486 * Update target foreign keys after a new source was inserted. This follows following steps.
1487 */
1488 public void updateTargetRowPostInsertSource(WriteObjectQuery query) throws DatabaseException {
1489 if (isReadOnly() || addTargetQuery == null) {
1490 return;
1491 }
1492
1493 ContainerPolicy cp = getContainerPolicy();
1494 Object objects = getRealCollectionAttributeValueFromObject(query.getObject(), query.getSession());
1495 if (cp.isEmpty(objects)) {
1496 return;
1497 }
1498
1499 prepareTranslationRow(query.getTranslationRow(), query.getObject(), query.getDescriptor(), query.getSession());
1500
1501 AbstractRecord keyRow = buildKeyRowForTargetUpdate(query);
1502
1503 // Extract target field and its value. Construct insert statement and execute it
1504 int size = targetPrimaryKeyFields.size();
1505 int objectIndex = 0;
1506 for (Object iter = cp.iteratorFor(objects); cp.hasNext(iter);) {
1507 AbstractRecord databaseRow = new DatabaseRecord();
1508 databaseRow.mergeFrom(keyRow);
1509 Object wrappedObject = cp.nextEntry(iter, query.getSession());
1510 Object object = cp.unwrapIteratorResult(wrappedObject);
1511 for(int index = 0; index < size; index++) {
1512 DatabaseField targetPrimaryKey = targetPrimaryKeyFields.get(index);
1513 Object targetKeyValue = getReferenceDescriptor().getObjectBuilder().extractValueFromObjectForField(object, targetPrimaryKey, query.getSession());
1514 databaseRow.put(targetPrimaryKey, targetKeyValue);
1515 }
1516 ContainerPolicy.copyMapDataToRow(cp.getKeyMappingDataForWriteQuery(wrappedObject, query.getSession()), databaseRow);
1517 if(listOrderField != null) {
1518 databaseRow.put(listOrderField, objectIndex++);
1519 }
1520 query.getSession().executeQuery(addTargetQuery, databaseRow);
1521 }
1522 }
1523
1524 protected AbstractRecord buildKeyRowForTargetUpdate(ObjectLevelModifyQuery query){
1525 return new DatabaseRecord();
1526 }
1527
1528 /**
1529 * INTERNAL:
1530 * Update target foreign key after a target object was added to the source. This follows following steps.
1531 * <p>- Extract primary key and its value from the source object.
1532 * <p>- Extract target key and its value from the target object.
1533 * <p>- Construct an update statement with above fields and values for target table.
1534 * <p>- execute the statement.
1535 */
1536 public void updateTargetForeignKeyPostUpdateSource_ObjectAdded(ObjectLevelModifyQuery query, Object objectAdded, Map extraData) throws DatabaseException {
1537 if (isReadOnly() || addTargetQuery == null) {
1538 return;
1539 }
1540
1541 ContainerPolicy cp = getContainerPolicy();
1542 prepareTranslationRow(query.getTranslationRow(), query.getObject(), query.getDescriptor(), query.getSession());
1543 AbstractRecord databaseRow = buildKeyRowForTargetUpdate(query);
1544
1545 // Extract target field and its value. Construct insert statement and execute it
1546 int size = targetPrimaryKeyFields.size();
1547 for (int index = 0; index < size; index++) {
1548 DatabaseField targetPrimaryKey = targetPrimaryKeyFields.get(index);
1549 Object targetKeyValue = getReferenceDescriptor().getObjectBuilder().extractValueFromObjectForField(cp.unwrapIteratorResult(objectAdded), targetPrimaryKey, query.getSession());
1550 databaseRow.put(targetPrimaryKey, targetKeyValue);
1551 }
1552
1553 ContainerPolicy.copyMapDataToRow(cp.getKeyMappingDataForWriteQuery(objectAdded, query.getSession()), databaseRow);
1554 if(listOrderField != null && extraData != null) {
1555 databaseRow.put(listOrderField, extraData.get(listOrderField));
1556 }
1557
1558 query.getSession().executeQuery(addTargetQuery, databaseRow);
1559 }
1560
1561 /**
1562 * INTERNAL:
1563 * Update target foreign key after a target object was removed from the source. This follows following steps.
1564 * <p>- Extract primary key and its value from the source object.
1565 * <p>- Extract target key and its value from the target object.
1566 * <p>- Construct an update statement with above fields and values for target table.
1567 * <p>- execute the statement.
1568 */
1569 public void updateTargetForeignKeyPostUpdateSource_ObjectRemoved(ObjectLevelModifyQuery query, Object objectRemoved) throws DatabaseException {
1570 if (this.isReadOnly) {
1571 return;
1572 }
1573 AbstractSession session = query.getSession();
1574 prepareTranslationRow(query.getTranslationRow(), query.getObject(), query.getDescriptor(), session);
1575 AbstractRecord translationRow = new DatabaseRecord();
1576
1577 // Extract primary key and value from the source (use translation row).
1578 int size = this.sourceKeyFields.size();
1579 AbstractRecord modifyRow = new DatabaseRecord(size);
1580 for (int index = 0; index < size; index++) {
1581 DatabaseField sourceKey = this.sourceKeyFields.get(index);
1582 DatabaseField targetForeignKey = this.targetForeignKeyFields.get(index);
1583 Object sourceKeyValue = query.getTranslationRow().get(sourceKey);
1584 translationRow.add(targetForeignKey, sourceKeyValue);
1585 // Need to set this value to null in the modify row.
1586 modifyRow.add(targetForeignKey, null);
1587 }
1588 if(listOrderField != null) {
1589 modifyRow.add(listOrderField, null);
1590 }
1591
1592 ContainerPolicy cp = getContainerPolicy();
1593 // Extract target field and its value from the object.
1594 size = targetPrimaryKeyFields.size();
1595 for (int index = 0; index < size; index++) {
1596 DatabaseField targetPrimaryKey = targetPrimaryKeyFields.get(index);
1597 Object targetKeyValue = getReferenceDescriptor().getObjectBuilder().extractValueFromObjectForField(cp.unwrapIteratorResult(objectRemoved), targetPrimaryKey, session);
1598 translationRow.add(targetPrimaryKey, targetKeyValue);
1599 }
1600 // Need a different modify row than translation row, as the same field has different values in each.
1601 DataModifyQuery removeQuery = (DataModifyQuery)this.removeTargetQuery.clone();
1602 removeQuery.setModifyRow(modifyRow);
1603 removeQuery.setHasModifyRow(true);
1604 removeQuery.setIsExecutionClone(true);
1605 session.executeQuery(removeQuery, translationRow);
1606 }
1607
1608 /**
1609 * INTERNAL:
1610 * Update target foreign key after a target object was removed from the source. This follows following steps.
1611 * <p>- Extract primary key and its value from the source object.
1612 * <p>- Extract target key and its value from the target object.
1613 * <p>- Construct an update statement with above fields and values for target table.
1614 * <p>- execute the statement.
1615 */
1616 public void updateTargetRowPreDeleteSource(ObjectLevelModifyQuery query) throws DatabaseException {
1617 if (this.isReadOnly) {
1618 return;
1619 }
1620
1621 // Extract primary key and value from the source.
1622 int size = this.sourceKeyFields.size();
1623 AbstractRecord translationRow = new DatabaseRecord(size);
1624 AbstractRecord modifyRow = new DatabaseRecord(size);
1625 for (int index = 0; index < size; index++) {
1626 DatabaseField sourceKey = this.sourceKeyFields.get(index);
1627 DatabaseField targetForeignKey = this.targetForeignKeyFields.get(index);
1628 Object sourceKeyValue = query.getTranslationRow().get(sourceKey);
1629 translationRow.add(targetForeignKey, sourceKeyValue);
1630 // Need to set this value to null in the modify row.
1631 modifyRow.add(targetForeignKey, null);
1632 }
1633 if(listOrderField != null) {
1634 modifyRow.add(listOrderField, null);
1635 }
1636
1637 // Need a different modify row than translation row, as the same field has different values in each.
1638 DataModifyQuery removeQuery = (DataModifyQuery)this.removeAllTargetsQuery.clone();
1639 removeQuery.setModifyRow(modifyRow);
1640 removeQuery.setHasModifyRow(true);
1641 removeQuery.setIsExecutionClone(true);
1642 query.getSession().executeQuery(removeQuery, translationRow);
1643 }
1644
1645 /**
1646 * INTERNAL:
1647 * Used to verify whether the specified object is deleted or not.
1648 */
1649 @Override
1650 public boolean verifyDelete(Object object, AbstractSession session) throws DatabaseException {
1651 if (this.isPrivateOwned() || isCascadeRemove()) {
1652 Object objects = getRealCollectionAttributeValueFromObject(object, session);
1653
1654 ContainerPolicy containerPolicy = getContainerPolicy();
1655 for (Object iter = containerPolicy.iteratorFor(objects); containerPolicy.hasNext(iter);) {
1656 if (!session.verifyDelete(containerPolicy.next(iter, session))) {
1657 return false;
1658 }
1659 }
1660 }
1661 return true;
1662 }
1663
1664 public boolean shouldDeferInsert() {
1665 if (shouldDeferInserts == null) {
1666 shouldDeferInserts = true;
1667 }
1668 return shouldDeferInserts;
1669 }
1670
1671 public void setShouldDeferInsert(boolean defer) {
1672 shouldDeferInserts = defer;
1673 }
1674
1675 /**
1676 * INTERNAL:
1677 * Returns a clone of InsertObjectQuery from the ClassDescriptor's DescriptorQueryManager or a new one
1678 */
1679 private InsertObjectQuery getInsertObjectQuery(AbstractSession session, ClassDescriptor desc) {
1680 InsertObjectQuery insertQuery = desc.getQueryManager().getInsertQuery();
1681 if (insertQuery == null) {
1682 insertQuery = new InsertObjectQuery();
1683 insertQuery.setDescriptor(desc);
1684 insertQuery.checkPrepare(session, insertQuery.getTranslationRow());
1685 } else {
1686 // Ensure the query has been prepared.
1687 insertQuery.checkPrepare(session, insertQuery.getTranslationRow());
1688 insertQuery = (InsertObjectQuery)insertQuery.clone();
1689 }
1690 insertQuery.setIsExecutionClone(true);
1691 return insertQuery;
1692 }
1693 }
00 /*******************************************************************************
1 * Copyright (c) 1998, 2013 Oracle and/or its affiliates. All rights reserved.
1 * Copyright (c) 1998, 2018 Oracle and/or its affiliates. All rights reserved.
22 * This program and the accompanying materials are made available under the
33 * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
44 * which accompanies this distribution.
1616 import java.util.Iterator;
1717 import java.util.Vector;
1818
19 import org.eclipse.persistence.config.SystemProperties;
1920 import org.eclipse.persistence.descriptors.ClassDescriptor;
2021 import org.eclipse.persistence.exceptions.ConversionException;
2122 import org.eclipse.persistence.exceptions.DatabaseException;
2425 import org.eclipse.persistence.internal.descriptors.CascadeLockingPolicy;
2526 import org.eclipse.persistence.internal.helper.ConversionManager;
2627 import org.eclipse.persistence.internal.helper.DatabaseField;
28 import org.eclipse.persistence.internal.security.PrivilegedAccessHelper;
2729 import org.eclipse.persistence.internal.sessions.AbstractRecord;
2830 import org.eclipse.persistence.internal.sessions.AbstractSession;
2931 import org.eclipse.persistence.internal.sessions.ChangeRecord;
7577 * Build a row containing the keys for use in the query that updates the row for the
7678 * target object during an insert or update
7779 */
80 @Override
7881 protected AbstractRecord buildKeyRowForTargetUpdate(ObjectLevelModifyQuery query){
7982 AbstractRecord keyRow = new DatabaseRecord();
8083 // Extract primary key and value from the source.
133136 /**
134137 * INTERNAL:
135138 */
139 @Override
136140 public boolean isOwned(){
137141 return true;
138142 }
140144 /**
141145 * INTERNAL:
142146 */
147 @Override
143148 public boolean isUnidirectionalOneToManyMapping() {
144149 return true;
145150 }
148153 * INTERNAL:
149154 * Initialize the mapping.
150155 */
156 @Override
151157 public void initialize(AbstractSession session) throws DescriptorException {
152158 super.initialize(session);
153159 if (getReferenceDescriptor().getOptimisticLockingPolicy() != null) {
163169 /**
164170 * Initialize the type of the target foreign key, as it will be null as it is not mapped in the target.
165171 */
172 @Override
166173 public void postInitialize(AbstractSession session) {
167174 super.postInitialize(session);
168175 Iterator<DatabaseField> targetForeignKeys = getTargetForeignKeyFields().iterator();
188195 /**
189196 * INTERNAL:
190197 */
198 @Override
191199 protected AbstractRecord createModifyRowForAddTargetQuery() {
192200 AbstractRecord modifyRow = super.createModifyRowForAddTargetQuery();
193201 int size = targetForeignKeyFields.size();
202210 * INTERNAL:
203211 * Delete the reference objects.
204212 */
213 @Override
205214 public void preDelete(DeleteObjectQuery query) throws DatabaseException, OptimisticLockException {
206215 if (shouldObjectModifyCascadeToParts(query)) {
207216 super.preDelete(query);
214223 /**
215224 * Prepare a cascade locking policy.
216225 */
226 @Override
217227 public void prepareCascadeLockingPolicy() {
218228 CascadeLockingPolicy policy = new CascadeLockingPolicy(getDescriptor(), getReferenceDescriptor());
219229 policy.setQueryKeyFields(getSourceKeysToTargetForeignKeys());
375385 * INTERNAL
376386 * Target foreign key of the removed object should be modified (set to null).
377387 */
388 @Override
378389 protected boolean shouldRemoveTargetQueryModifyTargetForeignKey() {
379390 return true;
380 }
391 }
392
393 @Override
394 public boolean shouldDeferInsert() {
395 if (shouldDeferInserts == null) {
396 String property = PrivilegedAccessHelper.getSystemProperty(SystemProperties.ONETOMANY_DEFER_INSERTS);
397 shouldDeferInserts = true;
398 if (property != null) {
399 shouldDeferInserts = "true".equalsIgnoreCase(property);
400 } else {
401 for (DatabaseField f : targetForeignKeyFields) {
402 if (!f.isNullable()) {
403 shouldDeferInserts = false;
404 break;
405 }
406 }
407 }
408 }
409 return shouldDeferInserts;
410 }
381411 }
0 /*******************************************************************************
1 * Copyright (c) 1998, 2015 Oracle and/or its affiliates, IBM Corporation. All rights reserved.
2 * This program and the accompanying materials are made available under the
3 * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
4 * which accompanies this distribution.
5 * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
6 * and the Eclipse Distribution License is available at
7 * http://www.eclipse.org/org/documents/edl-v10.php.
8 *
9 * Contributors:
10 * Oracle - initial API and implementation from Oracle TopLink
11 * 09/14/2011-2.3.1 Guy Pelletier
12 * - 357533: Allow DDL queries to execute even when Multitenant entities are part of the PU
13 * 02/19/2015 - Rick Curtis
14 * - 458877 : Add national character support
15 * 02/24/2016-2.6.0 Rick Curtis
16 * - 460740: Fix pessimistic locking with setFirst/Max results on DB2
17 *****************************************************************************/
18 package org.eclipse.persistence.platform.database;
19
20 import java.io.*;
21 import java.sql.*;
22 import java.util.*;
23
24 import org.eclipse.persistence.exceptions.ValidationException;
25 import org.eclipse.persistence.expressions.*;
26 import org.eclipse.persistence.internal.helper.*;
27 import org.eclipse.persistence.internal.sessions.AbstractRecord;
28 import org.eclipse.persistence.internal.sessions.AbstractSession;
29 import org.eclipse.persistence.internal.databaseaccess.DatabaseCall;
30 import org.eclipse.persistence.internal.databaseaccess.FieldTypeDefinition;
31 import org.eclipse.persistence.internal.expressions.ExpressionSQLPrinter;
32 import org.eclipse.persistence.internal.expressions.ParameterExpression;
33 import org.eclipse.persistence.internal.expressions.SQLSelectStatement;
34 import org.eclipse.persistence.queries.*;
35 import org.eclipse.persistence.tools.schemaframework.FieldDefinition;
36
37 /**
38 * <p>
39 * <b>Purpose</b>: Provides DB2 specific behavior.
40 * <p>
41 * <b>Responsibilities</b>:
42 * <ul>
43 * <li>Support for schema creation.
44 * <li>Native SQL for byte[], Date, Time, {@literal &} Timestamp.
45 * <li>Support for table qualified names.
46 * <li>Support for stored procedures.
47 * <li>Support for temp tables.
48 * <li>Support for casting.
49 * <li>Support for database functions.
50 * <li>Support for identity sequencing.
51 * <li>Support for SEQUENCE sequencing.
52 * </ul>
53 *
54 * @since TOPLink/Java 1.0
55 */
56 public class DB2Platform extends org.eclipse.persistence.platform.database.DatabasePlatform {
57
58 public DB2Platform() {
59 super();
60 this.pingSQL = "VALUES(1)";
61 }
62
63 @Override
64 public void initializeConnectionData(Connection connection) throws SQLException {
65 // DB2 database doesn't support NVARCHAR column types and as such doesn't support calling
66 // get/setNString() on the driver.
67 this.driverSupportsNationalCharacterVarying = false;
68 }
69
70 /**
71 * INTERNAL:
72 * Append a byte[] in native DB@ format BLOB(hexString) if usesNativeSQL(),
73 * otherwise use ODBC format from DatabasePLatform.
74 */
75 @Override
76 protected void appendByteArray(byte[] bytes, Writer writer) throws IOException {
77 if (usesNativeSQL()) {
78 writer.write("BLOB(x'");
79 Helper.writeHexString(bytes, writer);
80 writer.write("')");
81 } else {
82 super.appendByteArray(bytes, writer);
83 }
84 }
85
86 /**
87 * INTERNAL:
88 * Appends the Date in native format if usesNativeSQL() otherwise use ODBC
89 * format from DatabasePlatform. Native format: 'mm/dd/yyyy'
90 */
91 @Override
92 protected void appendDate(java.sql.Date date, Writer writer) throws IOException {
93 if (usesNativeSQL()) {
94 appendDB2Date(date, writer);
95 } else {
96 super.appendDate(date, writer);
97 }
98 }
99
100 /**
101 * INTERNAL:
102 * Write a timestamp in DB2 specific format (mm/dd/yyyy).
103 */
104 protected void appendDB2Date(java.sql.Date date, Writer writer) throws IOException {
105 writer.write("'");
106 // PERF: Avoid deprecated get methods, that are now very inefficient and
107 // used from toString.
108 Calendar calendar = Helper.allocateCalendar();
109 calendar.setTime(date);
110
111 if ((calendar.get(Calendar.MONTH) + 1) < 10) {
112 writer.write('0');
113 }
114 writer.write(Integer.toString(calendar.get(Calendar.MONTH) + 1));
115 writer.write('/');
116 if (calendar.get(Calendar.DATE) < 10) {
117 writer.write('0');
118 }
119 writer.write(Integer.toString(calendar.get(Calendar.DATE)));
120 writer.write('/');
121 writer.write(Integer.toString(calendar.get(Calendar.YEAR)));
122 writer.write("'");
123
124 Helper.releaseCalendar(calendar);
125 }
126
127 /**
128 * INTERNAL:
129 * Write a timestamp in DB2 specific format (yyyy-mm-dd-hh.mm.ss.ffffff).
130 */
131 protected void appendDB2Timestamp(java.sql.Timestamp timestamp, Writer writer) throws IOException {
132 // PERF: Avoid deprecated get methods, that are now very inefficient and
133 // used from toString.
134 Calendar calendar = Helper.allocateCalendar();
135 calendar.setTime(timestamp);
136
137 writer.write(Helper.printDate(calendar));
138 writer.write('-');
139 if (calendar.get(Calendar.HOUR_OF_DAY) < 10) {
140 writer.write('0');
141 }
142 writer.write(Integer.toString(calendar.get(Calendar.HOUR_OF_DAY)));
143 writer.write('.');
144 if (calendar.get(Calendar.MINUTE) < 10) {
145 writer.write('0');
146 }
147 writer.write(Integer.toString(calendar.get(Calendar.MINUTE)));
148 writer.write('.');
149 if (calendar.get(Calendar.SECOND) < 10) {
150 writer.write('0');
151 }
152 writer.write(Integer.toString(calendar.get(Calendar.SECOND)));
153 writer.write('.');
154
155 Helper.releaseCalendar(calendar);
156
157 // Must truncate the nanos to six decimal places,
158 // it is actually a complex algorithm...
159 String nanoString = Integer.toString(timestamp.getNanos());
160 int numberOfZeros = 0;
161 for (int num = Math.min(9 - nanoString.length(), 6); num > 0; num--) {
162 writer.write('0');
163 numberOfZeros++;
164 }
165 if ((nanoString.length() + numberOfZeros) > 6) {
166 nanoString = nanoString.substring(0, (6 - numberOfZeros));
167 }
168 writer.write(nanoString);
169 }
170
171 /**
172 * Write a timestamp in DB2 specific format (yyyy-mm-dd-hh.mm.ss.ffffff).
173 */
174 protected void appendDB2Calendar(Calendar calendar, Writer writer) throws IOException {
175 int hour;
176 int minute;
177 int second;
178 if (!Helper.getDefaultTimeZone().equals(calendar.getTimeZone())) {
179 // Must convert the calendar to the local timezone if different, as
180 // dates have no timezone (always local).
181 Calendar localCalendar = Helper.allocateCalendar();
182 localCalendar.setTimeInMillis(calendar.getTimeInMillis());
183 hour = calendar.get(Calendar.HOUR_OF_DAY);
184 minute = calendar.get(Calendar.MINUTE);
185 second = calendar.get(Calendar.SECOND);
186 Helper.releaseCalendar(localCalendar);
187 } else {
188 hour = calendar.get(Calendar.HOUR_OF_DAY);
189 minute = calendar.get(Calendar.MINUTE);
190 second = calendar.get(Calendar.SECOND);
191 }
192 writer.write(Helper.printDate(calendar));
193 writer.write('-');
194 if (hour < 10) {
195 writer.write('0');
196 }
197 writer.write(Integer.toString(hour));
198 writer.write('.');
199 if (minute < 10) {
200 writer.write('0');
201 }
202 writer.write(Integer.toString(minute));
203 writer.write('.');
204 if (second < 10) {
205 writer.write('0');
206 }
207 writer.write(Integer.toString(second));
208 writer.write('.');
209
210 // Must truncate the nanos to six decimal places,
211 // it is actually a complex algorithm...
212 String millisString = Integer.toString(calendar.get(Calendar.MILLISECOND));
213 int numberOfZeros = 0;
214 for (int num = Math.min(3 - millisString.length(), 3); num > 0; num--) {
215 writer.write('0');
216 numberOfZeros++;
217 }
218 if ((millisString.length() + numberOfZeros) > 3) {
219 millisString = millisString.substring(0, (3 - numberOfZeros));
220 }
221 writer.write(millisString);
222 }
223
224 /**
225 * INTERNAL:
226 * Append the Time in Native format if usesNativeSQL() otherwise use ODBC
227 * format from DAtabasePlatform. Native Format: 'hh:mm:ss'
228 */
229 @Override
230 protected void appendTime(java.sql.Time time, Writer writer) throws IOException {
231 if (usesNativeSQL()) {
232 writer.write("'");
233 writer.write(Helper.printTime(time));
234 writer.write("'");
235 } else {
236 super.appendTime(time, writer);
237 }
238 }
239
240 /**
241 * INTERNAL:
242 * Append the Timestamp in native format if usesNativeSQL() is true
243 * otherwise use ODBC format from DatabasePlatform. Native format:
244 * 'YYYY-MM-DD-hh.mm.ss.SSSSSS'
245 */
246 @Override
247 protected void appendTimestamp(java.sql.Timestamp timestamp, Writer writer) throws IOException {
248 if (usesNativeSQL()) {
249 writer.write("'");
250 appendDB2Timestamp(timestamp, writer);
251 writer.write("'");
252 } else {
253 super.appendTimestamp(timestamp, writer);
254 }
255 }
256
257 /**
258 * INTERNAL:
259 * Append the Timestamp in native format if usesNativeSQL() is true
260 * otherwise use ODBC format from DatabasePlatform. Native format:
261 * 'YYYY-MM-DD-hh.mm.ss.SSSSSS'
262 */
263 @Override
264 protected void appendCalendar(Calendar calendar, Writer writer) throws IOException {
265 if (usesNativeSQL()) {
266 writer.write("'");
267 appendDB2Calendar(calendar, writer);
268 writer.write("'");
269 } else {
270 super.appendCalendar(calendar, writer);
271 }
272 }
273
274 @Override
275 protected Hashtable buildFieldTypes() {
276 Hashtable fieldTypeMapping = new Hashtable();
277
278 fieldTypeMapping.put(Boolean.class, new FieldTypeDefinition("SMALLINT DEFAULT 0", false));
279
280 fieldTypeMapping.put(Integer.class, new FieldTypeDefinition("INTEGER", false));
281 fieldTypeMapping.put(Long.class, new FieldTypeDefinition("BIGINT", false));
282 fieldTypeMapping.put(Float.class, new FieldTypeDefinition("FLOAT", false));
283 fieldTypeMapping.put(Double.class, new FieldTypeDefinition("FLOAT", false));
284 fieldTypeMapping.put(Short.class, new FieldTypeDefinition("SMALLINT", false));
285 fieldTypeMapping.put(Byte.class, new FieldTypeDefinition("SMALLINT", false));
286 fieldTypeMapping.put(java.math.BigInteger.class, new FieldTypeDefinition("BIGINT", false));
287 fieldTypeMapping.put(java.math.BigDecimal.class, new FieldTypeDefinition("DECIMAL", 15));
288 fieldTypeMapping.put(Number.class, new FieldTypeDefinition("DECIMAL", 15));
289 if(getUseNationalCharacterVaryingTypeForString()){
290 fieldTypeMapping.put(String.class, new FieldTypeDefinition("VARCHAR", DEFAULT_VARCHAR_SIZE, "FOR MIXED DATA"));
291 }else {
292 fieldTypeMapping.put(String.class, new FieldTypeDefinition("VARCHAR", DEFAULT_VARCHAR_SIZE));
293 }
294 fieldTypeMapping.put(Character.class, new FieldTypeDefinition("CHAR", 1));
295 fieldTypeMapping.put(Byte[].class, new FieldTypeDefinition("BLOB", 64000));
296 fieldTypeMapping.put(Character[].class, new FieldTypeDefinition("CLOB", 64000));
297 fieldTypeMapping.put(byte[].class, new FieldTypeDefinition("BLOB", 64000));
298 fieldTypeMapping.put(char[].class, new FieldTypeDefinition("CLOB", 64000));
299 fieldTypeMapping.put(java.sql.Blob.class, new FieldTypeDefinition("BLOB", 64000));
300 fieldTypeMapping.put(java.sql.Clob.class, new FieldTypeDefinition("CLOB", 64000));
301
302 fieldTypeMapping.put(java.sql.Date.class, new FieldTypeDefinition("DATE", false));
303 fieldTypeMapping.put(java.sql.Time.class, new FieldTypeDefinition("TIME", false));
304 fieldTypeMapping.put(java.sql.Timestamp.class, new FieldTypeDefinition("TIMESTAMP", false));
305
306 return fieldTypeMapping;
307 }
308
309 /**
310 * INTERNAL: returns the maximum number of characters that can be used in a
311 * field name on this platform.
312 */
313 @Override
314 public int getMaxFieldNameSize() {
315 return 128;
316 }
317
318 /**
319 * INTERNAL: returns the maximum number of characters that can be used in a
320 * foreign key name on this platform.
321 */
322 @Override
323 public int getMaxForeignKeyNameSize() {
324 return 18;
325 }
326
327 /**
328 * INTERNAL:
329 * returns the maximum number of characters that can be used in a unique key
330 * name on this platform.
331 */
332 @Override
333 public int getMaxUniqueKeyNameSize() {
334 return 18;
335 }
336
337 /**
338 * INTERNAL:
339 * Return the catalog information through using the native SQL catalog
340 * selects. This is required because many JDBC driver do not support
341 * meta-data. Wildcards can be passed as arguments.
342 * This is currently not used.
343 */
344 public Vector getNativeTableInfo(String table, String creator, AbstractSession session) {
345 String query = "SELECT * FROM SYSIBM.SYSTABLES WHERE TBCREATOR NOT IN ('SYS', 'SYSTEM')";
346 if (table != null) {
347 if (table.indexOf('%') != -1) {
348 query = query + " AND TBNAME LIKE " + table;
349 } else {
350 query = query + " AND TBNAME = " + table;
351 }
352 }
353 if (creator != null) {
354 if (creator.indexOf('%') != -1) {
355 query = query + " AND TBCREATOR LIKE " + creator;
356 } else {
357 query = query + " AND TBCREATOR = " + creator;
358 }
359 }
360 return session.executeSelectingCall(new org.eclipse.persistence.queries.SQLCall(query));
361 }
362
363 /**
364 * INTERNAL:
365 * Used for sp calls.
366 */
367 @Override
368 public String getProcedureCallHeader() {
369 return "CALL ";
370 }
371
372 /**
373 * INTERNAL:
374 * Used for pessimistic locking in DB2.
375 * Without the "WITH RS" the lock is not held.
376 */
377 // public String getSelectForUpdateString() { return " FOR UPDATE"; }
378 @Override
379 public String getSelectForUpdateString() {
380 return " FOR READ ONLY WITH RS USE AND KEEP UPDATE LOCKS";
381 //return " FOR READ ONLY WITH RR";
382 //return " FOR READ ONLY WITH RS";
383 //return " FOR UPDATE WITH RS";
384 }
385
386 /**
387 * INTERNAL:
388 * Used for stored procedure defs.
389 */
390 @Override
391 public String getProcedureEndString() {
392 return "END";
393 }
394
395 /**
396 * Used for stored procedure defs.
397 */
398 @Override
399 public String getProcedureBeginString() {
400 return "BEGIN";
401 }
402
403 /**
404 * INTERNAL:
405 * Used for stored procedure defs.
406 */
407 @Override
408 public String getProcedureAsString() {
409 return "";
410 }
411
412 /**
413 * INTERNAL:
414 * This is required in the construction of the stored procedures with output
415 * parameters.
416 */
417 @Override
418 public boolean shouldPrintOutputTokenAtStart() {
419 return true;
420 }
421
422 /**
423 * INTERNAL:
424 * This method returns the query to select the timestamp from the server for
425 * DB2.
426 */
427 @Override
428 public ValueReadQuery getTimestampQuery() {
429 if (timestampQuery == null) {
430 timestampQuery = new ValueReadQuery();
431 timestampQuery.setSQLString("SELECT DISTINCT CURRENT TIMESTAMP FROM SYSIBM.SYSTABLES");
432 timestampQuery.setAllowNativeSQLQuery(true);
433 }
434 return timestampQuery;
435 }
436
437 /**
438 * INTERNAL:
439 * Initialize any platform-specific operators
440 */
441 @Override
442 protected void initializePlatformOperators() {
443 super.initializePlatformOperators();
444
445 addOperator(ExpressionOperator.simpleFunction(ExpressionOperator.ToUpperCase, "UCASE"));
446 addOperator(ExpressionOperator.simpleFunction(ExpressionOperator.ToLowerCase, "LCASE"));
447 addOperator(concatOperator());
448 addOperator(ExpressionOperator.simpleTwoArgumentFunction(ExpressionOperator.Instring, "Locate"));
449 // CR#2811076 some missing DB2 functions added.
450 addOperator(ExpressionOperator.simpleFunction(ExpressionOperator.ToNumber, "DECIMAL"));
451 addOperator(ExpressionOperator.simpleFunction(ExpressionOperator.ToChar, "CHAR"));
452 addOperator(ExpressionOperator.simpleFunction(ExpressionOperator.DateToString, "CHAR"));
453 addOperator(ExpressionOperator.simpleFunction(ExpressionOperator.ToDate, "DATE"));
454 addOperator(ltrim2Operator());
455 addOperator(rtrim2Operator());
456 }
457
458 @Override
459 public boolean isDB2() {
460 return true;
461 }
462
463 /**
464 * INTERNAL:
465 * Builds a table of maximum numeric values keyed on java class. This is
466 * used for type testing but might also be useful to end users attempting to
467 * sanitize values.
468 * <p>
469 * <b>NOTE</b>: BigInteger {@literal &} BigDecimal maximums are dependent upon their
470 * precision {@literal &} Scale
471 */
472 @Override
473 public Hashtable maximumNumericValues() {
474 Hashtable values = new Hashtable();
475
476 values.put(Integer.class, Integer.valueOf(Integer.MAX_VALUE));
477 values.put(Long.class, Long.valueOf(Integer.MAX_VALUE));
478 values.put(Float.class, Float.valueOf(123456789));
479 values.put(Double.class, Double.valueOf(Float.MAX_VALUE));
480 values.put(Short.class, Short.valueOf(Short.MAX_VALUE));
481 values.put(Byte.class, Byte.valueOf(Byte.MAX_VALUE));
482 values.put(java.math.BigInteger.class, new java.math.BigInteger("999999999999999"));
483 values.put(java.math.BigDecimal.class, new java.math.BigDecimal("0.999999999999999"));
484 return values;
485 }
486
487 /**
488 * INTERNAL:
489 * Builds a table of minimum numeric values keyed on java class. This is
490 * used for type testing but might also be useful to end users attempting to
491 * sanitize values.
492 * <p>
493 * <b>NOTE</b>: BigInteger {@literal &} BigDecimal minimums are dependent upon their
494 * precision {@literal &} Scale
495 */
496 @Override
497 public Hashtable minimumNumericValues() {
498 Hashtable values = new Hashtable();
499
500 values.put(Integer.class, Integer.valueOf(Integer.MIN_VALUE));
501 values.put(Long.class, Long.valueOf(Integer.MIN_VALUE));
502 values.put(Float.class, Float.valueOf(-123456789));
503 values.put(Double.class, Double.valueOf(Float.MIN_VALUE));
504 values.put(Short.class, Short.valueOf(Short.MIN_VALUE));
505 values.put(Byte.class, Byte.valueOf(Byte.MIN_VALUE));
506 values.put(java.math.BigInteger.class, new java.math.BigInteger("-999999999999999"));
507 values.put(java.math.BigDecimal.class, new java.math.BigDecimal("-0.999999999999999"));
508 return values;
509 }
510
511 /**
512 * INTERNAL:
513 * Allow for the platform to ignore exceptions. This is required for DB2
514 * which throws no-data modified as an exception.
515 */
516 @Override
517 public boolean shouldIgnoreException(SQLException exception) {
518 if (exception.getMessage().equals("No data found") || exception.getMessage().equals("No row was found for FETCH, UPDATE or DELETE; or the result of a query is an empty table")
519 || (exception.getErrorCode() == 100)) {
520 return true;
521 }
522 return super.shouldIgnoreException(exception);
523 }
524
525 /**
526 * INTERNAL:
527 * JDBC defines and outer join syntax, many drivers do not support this. So
528 * we normally avoid it.
529 */
530 @Override
531 public boolean shouldUseJDBCOuterJoinSyntax() {
532 return false;
533 }
534
535 /**
536 * INTERNAL:
537 * The Concat operator is of the form .... VARCHAR ( <operand1> ||
538 * <operand2> )
539 */
540 private ExpressionOperator concatOperator() {
541 ExpressionOperator exOperator = new ExpressionOperator();
542 exOperator.setType(ExpressionOperator.FunctionOperator);
543 exOperator.setSelector(ExpressionOperator.Concat);
544 Vector v = new Vector(5);
545 v.add("VARCHAR(");
546 v.add(" || ");
547 v.add(")");
548 exOperator.printsAs(v);
549 exOperator.bePrefix();
550 exOperator.setNodeClass(ClassConstants.FunctionExpression_Class);
551 return exOperator;
552 }
553
554 /**
555 * INTERNAL:
556 * The 2 arg LTRIM operator is of the form .... TRIM (LEADING, <operand2> FROM <operand1> )
557 */
558 private ExpressionOperator ltrim2Operator() {
559 ExpressionOperator operator = new ExpressionOperator();
560 operator.setType(ExpressionOperator.FunctionOperator);
561 operator.setSelector(ExpressionOperator.LeftTrim2);
562 Vector v = new Vector(5);
563 v.add("TRIM(LEADING ");
564 v.add(" FROM ");
565 v.add(")");
566 operator.printsAs(v);
567 operator.bePrefix();
568 int[] argumentIndices = new int[2];
569 argumentIndices[0] = 1;
570 argumentIndices[1] = 0;
571 operator.setArgumentIndices(argumentIndices);
572 operator.setNodeClass(ClassConstants.FunctionExpression_Class);
573 operator.setIsBindingSupported(false);
574 return operator;
575 }
576
577 /**
578 * INTERNAL:
579 * The 2 arg RTRIM operator is of the form .... TRIM (TRAILING, <operand2> FROM <operand1> )
580 */
581 private ExpressionOperator rtrim2Operator() {
582 ExpressionOperator operator = new ExpressionOperator();
583 operator.setType(ExpressionOperator.FunctionOperator);
584 operator.setSelector(ExpressionOperator.RightTrim2);
585 Vector v = new Vector(5);
586 v.add("TRIM(TRAILING ");
587 v.add(" FROM ");
588 v.add(")");
589 operator.printsAs(v);
590 operator.bePrefix();
591 int[] argumentIndices = new int[2];
592 argumentIndices[0] = 1;
593 argumentIndices[1] = 0;
594 operator.setArgumentIndices(argumentIndices);
595 operator.setNodeClass(ClassConstants.FunctionExpression_Class);
596 operator.setIsBindingSupported(false);
597 return operator;
598 }
599
600 /**
601 * INTERNAL: Build the identity query for native sequencing.
602 */
603 @Override
604 public ValueReadQuery buildSelectQueryForIdentity() {
605 ValueReadQuery selectQuery = new ValueReadQuery();
606 StringWriter writer = new StringWriter();
607 writer.write("SELECT IDENTITY_VAL_LOCAL() FROM SYSIBM.SYSDUMMY1");
608
609 selectQuery.setSQLString(writer.toString());
610 return selectQuery;
611 }
612
613 /**
614 * INTERNAL: Append the receiver's field 'identity' constraint clause to a
615 * writer.
616 * Used by table creation with sequencing.
617 */
618 @Override
619 public void printFieldIdentityClause(Writer writer) throws ValidationException {
620 try {
621 writer.write(" GENERATED ALWAYS AS IDENTITY");
622 } catch (IOException ioException) {
623 throw ValidationException.fileError(ioException);
624 }
625 }
626
627 @Override
628 protected void printFieldTypeSize(Writer writer, FieldDefinition field, FieldTypeDefinition ftd) throws IOException {
629 super.printFieldTypeSize(writer, field, ftd);
630 String suffix = ftd.getTypesuffix();
631 if (suffix != null) {
632 writer.append(" " + suffix);
633 }
634 }
635
636 /**
637 * INTERNAL: Indicates whether the platform supports identity. DB2 does
638 * through AS IDENTITY field types.
639 * This is used by sequencing.
640 */
641 @Override
642 public boolean supportsIdentity() {
643 return true;
644 }
645
646 /**
647 * INTERNAL: DB2 supports temp tables.
648 * This is used by UpdateAllQuerys.
649 */
650 @Override
651 public boolean supportsGlobalTempTables() {
652 return true;
653 }
654
655 /**
656 * INTERNAL: DB2 temp table syntax.
657 * This is used by UpdateAllQuerys.
658 */
659 @Override
660 protected String getCreateTempTableSqlPrefix() {
661 return "DECLARE GLOBAL TEMPORARY TABLE ";
662 }
663
664 /**
665 * INTERNAL: DB2 temp table syntax.
666 * This is used by UpdateAllQuerys.
667 */
668 @Override
669 public DatabaseTable getTempTableForTable(DatabaseTable table) {
670 DatabaseTable tempTable = super.getTempTableForTable(table);
671 tempTable.setTableQualifier("session");
672 return tempTable;
673 }
674
675 /**
676 * INTERNAL: DB2 temp table syntax.
677 * This is used by UpdateAllQuerys.
678 */
679 @Override
680 protected String getCreateTempTableSqlSuffix() {
681 return " ON COMMIT DELETE ROWS NOT LOGGED";
682 }
683
684 /**
685 * INTERNAL: DB2 allows LIKE to be used to create temp tables, which avoids having to know the types.
686 * This is used by UpdateAllQuerys.
687 */
688 @Override
689 protected String getCreateTempTableSqlBodyForTable(DatabaseTable table) {
690 return " LIKE " + table.getQualifiedNameDelimited(this);
691 }
692
693 /**
694 * INTERNAL: DB2 has issues with binding with temp table queries.
695 * This is used by UpdateAllQuerys.
696 */
697 @Override
698 public boolean dontBindUpdateAllQueryUsingTempTables() {
699 return true;
700 }
701
702 /**
703 * INTERNAL: DB2 does not allow NULL in select clause.
704 * This is used by UpdateAllQuerys.
705 */
706 @Override
707 public boolean isNullAllowedInSelectClause() {
708 return false;
709 }
710
711 /**
712 * INTERNAL
713 * DB2 has some issues with using parameters on certain functions and relations.
714 * This allows statements to disable binding only in these cases.
715 * If users set casting on, then casting is used instead of dynamic SQL.
716 */
717 @Override
718 public boolean isDynamicSQLRequiredForFunctions() {
719 return !isCastRequired();
720 }
721
722 /**
723 * INTERNAL:
724 * DB2 requires casting on certain operations, such as the CONCAT function,
725 * and parameterized queries of the form, ":param = :param". This method
726 * will write CAST operation to parameters if the type is known.
727 * This is not used by default, only if isCastRequired is set to true,
728 * by default dynamic SQL is used to avoid the issue in only the required cases.
729 */
730 @Override
731 public void writeParameterMarker(Writer writer, ParameterExpression parameter, AbstractRecord record, DatabaseCall call) throws IOException {
732 String paramaterMarker = "?";
733 Object type = parameter.getType();
734 // Update-all query requires casting of null parameter values in select into.
735 if ((type != null) && (this.isCastRequired || ((call.getQuery() != null) && call.getQuery().isUpdateAllQuery()))) {
736 BasicTypeHelperImpl typeHelper = BasicTypeHelperImpl.getInstance();
737 String castType = null;
738 if (typeHelper.isBooleanType(type) || typeHelper.isByteType(type) || typeHelper.isShortType(type)) {
739 castType = "SMALLINT";
740 } else if (typeHelper.isIntType(type)) {
741 castType = "INTEGER";
742 } else if (typeHelper.isLongType(type)) {
743 castType = "BIGINT";
744 } else if (typeHelper.isFloatType(type)) {
745 castType = "REAL";
746 } else if (typeHelper.isDoubleType(type)) {
747 castType = "DOUBLE";
748 } else if (typeHelper.isStringType(type)) {
749 castType = "VARCHAR(" + getCastSizeForVarcharParameter() + ")";
750 }
751
752 if (castType != null) {
753 paramaterMarker = "CAST (? AS " + castType + " )";
754 }
755 }
756 writer.write(paramaterMarker);
757 }
758
759 /**
760 * INTERNAL:
761 * DB2 does not seem to allow FOR UPDATE on queries with multiple tables.
762 * This is only used by testing to exclude these tests.
763 */
764 @Override
765 public boolean supportsLockingQueriesWithMultipleTables() {
766 return false;
767 }
768
769 /**
770 * INTERNAL: DB2 added SEQUENCE support as of (I believe) v8.
771 */
772 @Override
773 public ValueReadQuery buildSelectQueryForSequenceObject(String seqName, Integer size) {
774 return new ValueReadQuery("VALUES(NEXT VALUE FOR " + getQualifiedName(seqName) + ")");
775 }
776
777 /**
778 * INTERNAL: DB2 added SEQUENCE support as of (I believe) v8.
779 */
780 @Override
781 public boolean supportsSequenceObjects() {
782 return true;
783 }
784
785 /**
786 * INTERNAL: DB2 added SEQUENCE support as of (I believe) v8.
787 */
788 @Override
789 public boolean isAlterSequenceObjectSupported() {
790 return true;
791 }
792
793 @Override
794 public boolean shouldPrintForUpdateClause() {
795 return false;
796 }
797 /**
798 * INTERNAL:
799 * Print the SQL representation of the statement on a stream, storing the fields
800 * in the DatabaseCall. This implementation works MaxRows and FirstResult into the SQL using
801 * DB2's ROWNUMBER() OVER() to filter values if shouldUseRownumFiltering is true.
802 */
803 @Override
804 public void printSQLSelectStatement(DatabaseCall call, ExpressionSQLPrinter printer, SQLSelectStatement statement){
805 int max = 0;
806 int firstRow = 0;
807
808 if (statement.getQuery()!=null){
809 max = statement.getQuery().getMaxRows();
810 firstRow = statement.getQuery().getFirstResult();
811 }
812
813 if ( !(this.shouldUseRownumFiltering()) || ( !(max>0) && !(firstRow>0) ) ){
814 super.printSQLSelectStatement(call, printer, statement);
815 statement.appendForUpdateClause(printer);
816 return;
817 } else if ( max > 0 ){
818 statement.setUseUniqueFieldAliases(true);
819 printer.printString("SELECT * FROM (SELECT * FROM (SELECT ");
820 printer.printString("EL_TEMP.*, ROWNUMBER() OVER() AS EL_ROWNM FROM (");
821 call.setFields(statement.printSQL(printer));
822 printer.printString(") AS EL_TEMP) AS EL_TEMP2 WHERE EL_ROWNM <= ");
823 printer.printParameter(DatabaseCall.MAXROW_FIELD);
824 printer.printString(") AS EL_TEMP3 WHERE EL_ROWNM > ");
825 printer.printParameter(DatabaseCall.FIRSTRESULT_FIELD);
826 // If we have a ForUpdate clause, it must be on the outermost query
827 statement.appendForUpdateClause(printer);
828 } else {// firstRow>0
829 statement.setUseUniqueFieldAliases(true);
830 printer.printString("SELECT * FROM (SELECT EL_TEMP.*, ROWNUMBER() OVER() AS EL_ROWNM FROM (");
831 call.setFields(statement.printSQL(printer));
832 printer.printString(") AS EL_TEMP) AS EL_TEMP2 WHERE EL_ROWNM > ");
833 printer.printParameter(DatabaseCall.FIRSTRESULT_FIELD);
834 statement.appendForUpdateClause(printer);
835 }
836 call.setIgnoreFirstRowSetting(true);
837 call.setIgnoreMaxResultsSetting(true);
838 }
839
840 }
0 /*******************************************************************************
1 * Copyright (c) 1998, 201* Oracle and/or its affiliates, IBM Corporation. All rights reserved.
2 * This program and the accompanying materials are made available under the
3 * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
4 * which accompanies this distribution.
5 * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
6 * and the Eclipse Distribution License is available at
7 * http://www.eclipse.org/org/documents/edl-v10.php.
8 *
9 * Contributors:
10 * Oracle - initial API and implementation from Oracle TopLink
11 * 09/14/2011-2.3.1 Guy Pelletier
12 * - 357533: Allow DDL queries to execute even when Multitenant entities are part of the PU
13 * 02/19/2015 - Rick Curtis
14 * - 458877 : Add national character support
15 * 02/24/2016-2.6.0 Rick Curtis
16 * - 460740: Fix pessimistic locking with setFirst/Max results on DB2
17 * 12/06/2018 - Will Dazey
18 * - 542491: Add new 'eclipselink.jdbc.force-bind-parameters' property to force enable binding
19 *****************************************************************************/
20 package org.eclipse.persistence.platform.database;
21
22 import java.io.*;
23 import java.sql.*;
24 import java.util.*;
25
26 import org.eclipse.persistence.exceptions.ValidationException;
27 import org.eclipse.persistence.expressions.*;
28 import org.eclipse.persistence.internal.helper.*;
29 import org.eclipse.persistence.internal.sessions.AbstractRecord;
30 import org.eclipse.persistence.internal.sessions.AbstractSession;
31 import org.eclipse.persistence.internal.databaseaccess.DatabaseCall;
32 import org.eclipse.persistence.internal.databaseaccess.FieldTypeDefinition;
33 import org.eclipse.persistence.internal.expressions.ExpressionSQLPrinter;
34 import org.eclipse.persistence.internal.expressions.ParameterExpression;
35 import org.eclipse.persistence.internal.expressions.SQLSelectStatement;
36 import org.eclipse.persistence.queries.*;
37 import org.eclipse.persistence.tools.schemaframework.FieldDefinition;
38
39 /**
40 * <p>
41 * <b>Purpose</b>: Provides DB2 specific behavior.
42 * <p>
43 * <b>Responsibilities</b>:
44 * <ul>
45 * <li>Support for schema creation.
46 * <li>Native SQL for byte[], Date, Time, {@literal &} Timestamp.
47 * <li>Support for table qualified names.
48 * <li>Support for stored procedures.
49 * <li>Support for temp tables.
50 * <li>Support for casting.
51 * <li>Support for database functions.
52 * <li>Support for identity sequencing.
53 * <li>Support for SEQUENCE sequencing.
54 * </ul>
55 *
56 * @since TOPLink/Java 1.0
57 */
58 public class DB2Platform extends org.eclipse.persistence.platform.database.DatabasePlatform {
59
60 public DB2Platform() {
61 super();
62 this.pingSQL = "VALUES(1)";
63 }
64
65 @Override
66 public void initializeConnectionData(Connection connection) throws SQLException {
67 // DB2 database doesn't support NVARCHAR column types and as such doesn't support calling
68 // get/setNString() on the driver.
69 this.driverSupportsNationalCharacterVarying = false;
70 }
71
72 /**
73 * INTERNAL:
74 * Append a byte[] in native DB@ format BLOB(hexString) if usesNativeSQL(),
75 * otherwise use ODBC format from DatabasePLatform.
76 */
77 @Override
78 protected void appendByteArray(byte[] bytes, Writer writer) throws IOException {
79 if (usesNativeSQL()) {
80 writer.write("BLOB(x'");
81 Helper.writeHexString(bytes, writer);
82 writer.write("')");
83 } else {
84 super.appendByteArray(bytes, writer);
85 }
86 }
87
88 /**
89 * INTERNAL:
90 * Appends the Date in native format if usesNativeSQL() otherwise use ODBC
91 * format from DatabasePlatform. Native format: 'mm/dd/yyyy'
92 */
93 @Override
94 protected void appendDate(java.sql.Date date, Writer writer) throws IOException {
95 if (usesNativeSQL()) {
96 appendDB2Date(date, writer);
97 } else {
98 super.appendDate(date, writer);
99 }
100 }
101
102 /**
103 * INTERNAL:
104 * Write a timestamp in DB2 specific format (mm/dd/yyyy).
105 */
106 protected void appendDB2Date(java.sql.Date date, Writer writer) throws IOException {
107 writer.write("'");
108 // PERF: Avoid deprecated get methods, that are now very inefficient and
109 // used from toString.
110 Calendar calendar = Helper.allocateCalendar();
111 calendar.setTime(date);
112
113 if ((calendar.get(Calendar.MONTH) + 1) < 10) {
114 writer.write('0');
115 }
116 writer.write(Integer.toString(calendar.get(Calendar.MONTH) + 1));
117 writer.write('/');
118 if (calendar.get(Calendar.DATE) < 10) {
119 writer.write('0');
120 }
121 writer.write(Integer.toString(calendar.get(Calendar.DATE)));
122 writer.write('/');
123 writer.write(Integer.toString(calendar.get(Calendar.YEAR)));
124 writer.write("'");
125
126 Helper.releaseCalendar(calendar);
127 }
128
129 /**
130 * INTERNAL:
131 * Write a timestamp in DB2 specific format (yyyy-mm-dd-hh.mm.ss.ffffff).
132 */
133 protected void appendDB2Timestamp(java.sql.Timestamp timestamp, Writer writer) throws IOException {
134 // PERF: Avoid deprecated get methods, that are now very inefficient and
135 // used from toString.
136 Calendar calendar = Helper.allocateCalendar();
137 calendar.setTime(timestamp);
138
139 writer.write(Helper.printDate(calendar));
140 writer.write('-');
141 if (calendar.get(Calendar.HOUR_OF_DAY) < 10) {
142 writer.write('0');
143 }
144 writer.write(Integer.toString(calendar.get(Calendar.HOUR_OF_DAY)));
145 writer.write('.');
146 if (calendar.get(Calendar.MINUTE) < 10) {
147 writer.write('0');
148 }
149 writer.write(Integer.toString(calendar.get(Calendar.MINUTE)));
150 writer.write('.');
151 if (calendar.get(Calendar.SECOND) < 10) {
152 writer.write('0');
153 }
154 writer.write(Integer.toString(calendar.get(Calendar.SECOND)));
155 writer.write('.');
156
157 Helper.releaseCalendar(calendar);
158
159 // Must truncate the nanos to six decimal places,
160 // it is actually a complex algorithm...
161 String nanoString = Integer.toString(timestamp.getNanos());
162 int numberOfZeros = 0;
163 for (int num = Math.min(9 - nanoString.length(), 6); num > 0; num--) {
164 writer.write('0');
165 numberOfZeros++;
166 }
167 if ((nanoString.length() + numberOfZeros) > 6) {
168 nanoString = nanoString.substring(0, (6 - numberOfZeros));
169 }
170 writer.write(nanoString);
171 }
172
173 /**
174 * Write a timestamp in DB2 specific format (yyyy-mm-dd-hh.mm.ss.ffffff).
175 */
176 protected void appendDB2Calendar(Calendar calendar, Writer writer) throws IOException {
177 int hour;
178 int minute;
179 int second;
180 if (!Helper.getDefaultTimeZone().equals(calendar.getTimeZone())) {
181 // Must convert the calendar to the local timezone if different, as
182 // dates have no timezone (always local).
183 Calendar localCalendar = Helper.allocateCalendar();
184 localCalendar.setTimeInMillis(calendar.getTimeInMillis());
185 hour = calendar.get(Calendar.HOUR_OF_DAY);
186 minute = calendar.get(Calendar.MINUTE);
187 second = calendar.get(Calendar.SECOND);
188 Helper.releaseCalendar(localCalendar);
189 } else {
190 hour = calendar.get(Calendar.HOUR_OF_DAY);
191 minute = calendar.get(Calendar.MINUTE);
192 second = calendar.get(Calendar.SECOND);
193 }
194 writer.write(Helper.printDate(calendar));
195 writer.write('-');
196 if (hour < 10) {
197 writer.write('0');
198 }
199 writer.write(Integer.toString(hour));
200 writer.write('.');
201 if (minute < 10) {
202 writer.write('0');
203 }
204 writer.write(Integer.toString(minute));
205 writer.write('.');
206 if (second < 10) {
207 writer.write('0');
208 }
209 writer.write(Integer.toString(second));
210 writer.write('.');
211
212 // Must truncate the nanos to six decimal places,
213 // it is actually a complex algorithm...
214 String millisString = Integer.toString(calendar.get(Calendar.MILLISECOND));
215 int numberOfZeros = 0;
216 for (int num = Math.min(3 - millisString.length(), 3); num > 0; num--) {
217 writer.write('0');
218 numberOfZeros++;
219 }
220 if ((millisString.length() + numberOfZeros) > 3) {
221 millisString = millisString.substring(0, (3 - numberOfZeros));
222 }
223 writer.write(millisString);
224 }
225
226 /**
227 * INTERNAL:
228 * Append the Time in Native format if usesNativeSQL() otherwise use ODBC
229 * format from DAtabasePlatform. Native Format: 'hh:mm:ss'
230 */
231 @Override
232 protected void appendTime(java.sql.Time time, Writer writer) throws IOException {
233 if (usesNativeSQL()) {
234 writer.write("'");
235 writer.write(Helper.printTime(time));
236 writer.write("'");
237 } else {
238 super.appendTime(time, writer);
239 }
240 }
241
242 /**
243 * INTERNAL:
244 * Append the Timestamp in native format if usesNativeSQL() is true
245 * otherwise use ODBC format from DatabasePlatform. Native format:
246 * 'YYYY-MM-DD-hh.mm.ss.SSSSSS'
247 */
248 @Override
249 protected void appendTimestamp(java.sql.Timestamp timestamp, Writer writer) throws IOException {
250 if (usesNativeSQL()) {
251 writer.write("'");
252 appendDB2Timestamp(timestamp, writer);
253 writer.write("'");
254 } else {
255 super.appendTimestamp(timestamp, writer);
256 }
257 }
258
259 /**
260 * INTERNAL:
261 * Append the Timestamp in native format if usesNativeSQL() is true
262 * otherwise use ODBC format from DatabasePlatform. Native format:
263 * 'YYYY-MM-DD-hh.mm.ss.SSSSSS'
264 */
265 @Override
266 protected void appendCalendar(Calendar calendar, Writer writer) throws IOException {
267 if (usesNativeSQL()) {
268 writer.write("'");
269 appendDB2Calendar(calendar, writer);
270 writer.write("'");
271 } else {
272 super.appendCalendar(calendar, writer);
273 }
274 }
275
276 @Override
277 protected Hashtable buildFieldTypes() {
278 Hashtable fieldTypeMapping = new Hashtable();
279
280 fieldTypeMapping.put(Boolean.class, new FieldTypeDefinition("SMALLINT DEFAULT 0", false));
281
282 fieldTypeMapping.put(Integer.class, new FieldTypeDefinition("INTEGER", false));
283 fieldTypeMapping.put(Long.class, new FieldTypeDefinition("BIGINT", false));
284 fieldTypeMapping.put(Float.class, new FieldTypeDefinition("FLOAT", false));
285 fieldTypeMapping.put(Double.class, new FieldTypeDefinition("FLOAT", false));
286 fieldTypeMapping.put(Short.class, new FieldTypeDefinition("SMALLINT", false));
287 fieldTypeMapping.put(Byte.class, new FieldTypeDefinition("SMALLINT", false));
288 fieldTypeMapping.put(java.math.BigInteger.class, new FieldTypeDefinition("BIGINT", false));
289 fieldTypeMapping.put(java.math.BigDecimal.class, new FieldTypeDefinition("DECIMAL", 15));
290 fieldTypeMapping.put(Number.class, new FieldTypeDefinition("DECIMAL", 15));
291 if(getUseNationalCharacterVaryingTypeForString()){
292 fieldTypeMapping.put(String.class, new FieldTypeDefinition("VARCHAR", DEFAULT_VARCHAR_SIZE, "FOR MIXED DATA"));
293 }else {
294 fieldTypeMapping.put(String.class, new FieldTypeDefinition("VARCHAR", DEFAULT_VARCHAR_SIZE));
295 }
296 fieldTypeMapping.put(Character.class, new FieldTypeDefinition("CHAR", 1));
297 fieldTypeMapping.put(Byte[].class, new FieldTypeDefinition("BLOB", 64000));
298 fieldTypeMapping.put(Character[].class, new FieldTypeDefinition("CLOB", 64000));
299 fieldTypeMapping.put(byte[].class, new FieldTypeDefinition("BLOB", 64000));
300 fieldTypeMapping.put(char[].class, new FieldTypeDefinition("CLOB", 64000));
301 fieldTypeMapping.put(java.sql.Blob.class, new FieldTypeDefinition("BLOB", 64000));
302 fieldTypeMapping.put(java.sql.Clob.class, new FieldTypeDefinition("CLOB", 64000));
303
304 fieldTypeMapping.put(java.sql.Date.class, new FieldTypeDefinition("DATE", false));
305 fieldTypeMapping.put(java.sql.Time.class, new FieldTypeDefinition("TIME", false));
306 fieldTypeMapping.put(java.sql.Timestamp.class, new FieldTypeDefinition("TIMESTAMP", false));
307
308 return fieldTypeMapping;
309 }
310
311 /**
312 * INTERNAL: returns the maximum number of characters that can be used in a
313 * field name on this platform.
314 */
315 @Override
316 public int getMaxFieldNameSize() {
317 return 128;
318 }
319
320 /**
321 * INTERNAL: returns the maximum number of characters that can be used in a
322 * foreign key name on this platform.
323 */
324 @Override
325 public int getMaxForeignKeyNameSize() {
326 return 18;
327 }
328
329 /**
330 * INTERNAL:
331 * returns the maximum number of characters that can be used in a unique key
332 * name on this platform.
333 */
334 @Override
335 public int getMaxUniqueKeyNameSize() {
336 return 18;
337 }
338
339 /**
340 * INTERNAL:
341 * Return the catalog information through using the native SQL catalog
342 * selects. This is required because many JDBC driver do not support
343 * meta-data. Wildcards can be passed as arguments.
344 * This is currently not used.
345 */
346 public Vector getNativeTableInfo(String table, String creator, AbstractSession session) {
347 String query = "SELECT * FROM SYSIBM.SYSTABLES WHERE TBCREATOR NOT IN ('SYS', 'SYSTEM')";
348 if (table != null) {
349 if (table.indexOf('%') != -1) {
350 query = query + " AND TBNAME LIKE " + table;
351 } else {
352 query = query + " AND TBNAME = " + table;
353 }
354 }
355 if (creator != null) {
356 if (creator.indexOf('%') != -1) {
357 query = query + " AND TBCREATOR LIKE " + creator;
358 } else {
359 query = query + " AND TBCREATOR = " + creator;
360 }
361 }
362 return session.executeSelectingCall(new org.eclipse.persistence.queries.SQLCall(query));
363 }
364
365 /**
366 * INTERNAL:
367 * Used for sp calls.
368 */
369 @Override
370 public String getProcedureCallHeader() {
371 return "CALL ";
372 }
373
374 /**
375 * INTERNAL:
376 * Used for pessimistic locking in DB2.
377 * Without the "WITH RS" the lock is not held.
378 */
379 // public String getSelectForUpdateString() { return " FOR UPDATE"; }
380 @Override
381 public String getSelectForUpdateString() {
382 return " FOR READ ONLY WITH RS USE AND KEEP UPDATE LOCKS";
383 //return " FOR READ ONLY WITH RR";
384 //return " FOR READ ONLY WITH RS";
385 //return " FOR UPDATE WITH RS";
386 }
387
388 /**
389 * INTERNAL:
390 * Used for stored procedure defs.
391 */
392 @Override
393 public String getProcedureEndString() {
394 return "END";
395 }
396
397 /**
398 * Used for stored procedure defs.
399 */
400 @Override
401 public String getProcedureBeginString() {
402 return "BEGIN";
403 }
404
405 /**
406 * INTERNAL:
407 * Used for stored procedure defs.
408 */
409 @Override
410 public String getProcedureAsString() {
411 return "";
412 }
413
414 /**
415 * INTERNAL:
416 * This is required in the construction of the stored procedures with output
417 * parameters.
418 */
419 @Override
420 public boolean shouldPrintOutputTokenAtStart() {
421 return true;
422 }
423
424 /**
425 * INTERNAL:
426 * This method returns the query to select the timestamp from the server for
427 * DB2.
428 */
429 @Override
430 public ValueReadQuery getTimestampQuery() {
431 if (timestampQuery == null) {
432 timestampQuery = new ValueReadQuery();
433 timestampQuery.setSQLString("SELECT DISTINCT CURRENT TIMESTAMP FROM SYSIBM.SYSTABLES");
434 timestampQuery.setAllowNativeSQLQuery(true);
435 }
436 return timestampQuery;
437 }
438
439 /**
440 * INTERNAL:
441 * Initialize any platform-specific operators
442 */
443 @Override
444 protected void initializePlatformOperators() {
445 super.initializePlatformOperators();
446
447 addOperator(ExpressionOperator.simpleFunction(ExpressionOperator.ToUpperCase, "UCASE"));
448 addOperator(ExpressionOperator.simpleFunction(ExpressionOperator.ToLowerCase, "LCASE"));
449 addOperator(concatOperator());
450 addOperator(ExpressionOperator.simpleTwoArgumentFunction(ExpressionOperator.Instring, "Locate"));
451 // CR#2811076 some missing DB2 functions added.
452 addOperator(ExpressionOperator.simpleFunction(ExpressionOperator.ToNumber, "DECIMAL"));
453 addOperator(ExpressionOperator.simpleFunction(ExpressionOperator.ToChar, "CHAR"));
454 addOperator(ExpressionOperator.simpleFunction(ExpressionOperator.DateToString, "CHAR"));
455 addOperator(ExpressionOperator.simpleFunction(ExpressionOperator.ToDate, "DATE"));
456 addOperator(ltrim2Operator());
457 addOperator(rtrim2Operator());
458 }
459
460 @Override
461 public boolean isDB2() {
462 return true;
463 }
464
465 /**
466 * INTERNAL:
467 * Builds a table of maximum numeric values keyed on java class. This is
468 * used for type testing but might also be useful to end users attempting to
469 * sanitize values.
470 * <p>
471 * <b>NOTE</b>: BigInteger {@literal &} BigDecimal maximums are dependent upon their
472 * precision {@literal &} Scale
473 */
474 @Override
475 public Hashtable maximumNumericValues() {
476 Hashtable values = new Hashtable();
477
478 values.put(Integer.class, Integer.valueOf(Integer.MAX_VALUE));
479 values.put(Long.class, Long.valueOf(Integer.MAX_VALUE));
480 values.put(Float.class, Float.valueOf(123456789));
481 values.put(Double.class, Double.valueOf(Float.MAX_VALUE));
482 values.put(Short.class, Short.valueOf(Short.MAX_VALUE));
483 values.put(Byte.class, Byte.valueOf(Byte.MAX_VALUE));
484 values.put(java.math.BigInteger.class, new java.math.BigInteger("999999999999999"));
485 values.put(java.math.BigDecimal.class, new java.math.BigDecimal("0.999999999999999"));
486 return values;
487 }
488
489 /**
490 * INTERNAL:
491 * Builds a table of minimum numeric values keyed on java class. This is
492 * used for type testing but might also be useful to end users attempting to
493 * sanitize values.
494 * <p>
495 * <b>NOTE</b>: BigInteger {@literal &} BigDecimal minimums are dependent upon their
496 * precision {@literal &} Scale
497 */
498 @Override
499 public Hashtable minimumNumericValues() {
500 Hashtable values = new Hashtable();
501
502 values.put(Integer.class, Integer.valueOf(Integer.MIN_VALUE));
503 values.put(Long.class, Long.valueOf(Integer.MIN_VALUE));
504 values.put(Float.class, Float.valueOf(-123456789));
505 values.put(Double.class, Double.valueOf(Float.MIN_VALUE));
506 values.put(Short.class, Short.valueOf(Short.MIN_VALUE));
507 values.put(Byte.class, Byte.valueOf(Byte.MIN_VALUE));
508 values.put(java.math.BigInteger.class, new java.math.BigInteger("-999999999999999"));
509 values.put(java.math.BigDecimal.class, new java.math.BigDecimal("-0.999999999999999"));
510 return values;
511 }
512
513 /**
514 * INTERNAL:
515 * Allow for the platform to ignore exceptions. This is required for DB2
516 * which throws no-data modified as an exception.
517 */
518 @Override
519 public boolean shouldIgnoreException(SQLException exception) {
520 if (exception.getMessage().equals("No data found") || exception.getMessage().equals("No row was found for FETCH, UPDATE or DELETE; or the result of a query is an empty table")
521 || (exception.getErrorCode() == 100)) {
522 return true;
523 }
524 return super.shouldIgnoreException(exception);
525 }
526
527 /**
528 * INTERNAL:
529 * JDBC defines and outer join syntax, many drivers do not support this. So
530 * we normally avoid it.
531 */
532 @Override
533 public boolean shouldUseJDBCOuterJoinSyntax() {
534 return false;
535 }
536
537 /**
538 * INTERNAL:
539 * The Concat operator is of the form .... VARCHAR ( <operand1> ||
540 * <operand2> )
541 */
542 private ExpressionOperator concatOperator() {
543 ExpressionOperator exOperator = new ExpressionOperator();
544 exOperator.setType(ExpressionOperator.FunctionOperator);
545 exOperator.setSelector(ExpressionOperator.Concat);
546 Vector v = new Vector(5);
547 v.add("VARCHAR(");
548 v.add(" || ");
549 v.add(")");
550 exOperator.printsAs(v);
551 exOperator.bePrefix();
552 exOperator.setNodeClass(ClassConstants.FunctionExpression_Class);
553 return exOperator;
554 }
555
556 /**
557 * INTERNAL:
558 * The 2 arg LTRIM operator is of the form .... TRIM (LEADING, <operand2> FROM <operand1> )
559 */
560 private ExpressionOperator ltrim2Operator() {
561 ExpressionOperator operator = new ExpressionOperator();
562 operator.setType(ExpressionOperator.FunctionOperator);
563 operator.setSelector(ExpressionOperator.LeftTrim2);
564 Vector v = new Vector(5);
565 v.add("TRIM(LEADING ");
566 v.add(" FROM ");
567 v.add(")");
568 operator.printsAs(v);
569 operator.bePrefix();
570 int[] argumentIndices = new int[2];
571 argumentIndices[0] = 1;
572 argumentIndices[1] = 0;
573 operator.setArgumentIndices(argumentIndices);
574 operator.setNodeClass(ClassConstants.FunctionExpression_Class);
575 operator.setIsBindingSupported(false);
576 return operator;
577 }
578
579 /**
580 * INTERNAL:
581 * The 2 arg RTRIM operator is of the form .... TRIM (TRAILING, <operand2> FROM <operand1> )
582 */
583 private ExpressionOperator rtrim2Operator() {
584 ExpressionOperator operator = new ExpressionOperator();
585 operator.setType(ExpressionOperator.FunctionOperator);
586 operator.setSelector(ExpressionOperator.RightTrim2);
587 Vector v = new Vector(5);
588 v.add("TRIM(TRAILING ");
589 v.add(" FROM ");
590 v.add(")");
591 operator.printsAs(v);
592 operator.bePrefix();
593 int[] argumentIndices = new int[2];
594 argumentIndices[0] = 1;
595 argumentIndices[1] = 0;
596 operator.setArgumentIndices(argumentIndices);
597 operator.setNodeClass(ClassConstants.FunctionExpression_Class);
598 operator.setIsBindingSupported(false);
599 return operator;
600 }
601
602 /**
603 * INTERNAL: Build the identity query for native sequencing.
604 */
605 @Override
606 public ValueReadQuery buildSelectQueryForIdentity() {
607 ValueReadQuery selectQuery = new ValueReadQuery();
608 StringWriter writer = new StringWriter();
609 writer.write("SELECT IDENTITY_VAL_LOCAL() FROM SYSIBM.SYSDUMMY1");
610
611 selectQuery.setSQLString(writer.toString());
612 return selectQuery;
613 }
614
615 /**
616 * INTERNAL: Append the receiver's field 'identity' constraint clause to a
617 * writer.
618 * Used by table creation with sequencing.
619 */
620 @Override
621 public void printFieldIdentityClause(Writer writer) throws ValidationException {
622 try {
623 writer.write(" GENERATED ALWAYS AS IDENTITY");
624 } catch (IOException ioException) {
625 throw ValidationException.fileError(ioException);
626 }
627 }
628
629 @Override
630 protected void printFieldTypeSize(Writer writer, FieldDefinition field, FieldTypeDefinition ftd) throws IOException {
631 super.printFieldTypeSize(writer, field, ftd);
632 String suffix = ftd.getTypesuffix();
633 if (suffix != null) {
634 writer.append(" " + suffix);
635 }
636 }
637
638 /**
639 * INTERNAL: Indicates whether the platform supports identity. DB2 does
640 * through AS IDENTITY field types.
641 * This is used by sequencing.
642 */
643 @Override
644 public boolean supportsIdentity() {
645 return true;
646 }
647
648 /**
649 * INTERNAL: DB2 supports temp tables.
650 * This is used by UpdateAllQuerys.
651 */
652 @Override
653 public boolean supportsGlobalTempTables() {
654 return true;
655 }
656
657 /**
658 * INTERNAL: DB2 temp table syntax.
659 * This is used by UpdateAllQuerys.
660 */
661 @Override
662 protected String getCreateTempTableSqlPrefix() {
663 return "DECLARE GLOBAL TEMPORARY TABLE ";
664 }
665
666 /**
667 * INTERNAL: DB2 temp table syntax.
668 * This is used by UpdateAllQuerys.
669 */
670 @Override
671 public DatabaseTable getTempTableForTable(DatabaseTable table) {
672 DatabaseTable tempTable = super.getTempTableForTable(table);
673 tempTable.setTableQualifier("session");
674 return tempTable;
675 }
676
677 /**
678 * INTERNAL: DB2 temp table syntax.
679 * This is used by UpdateAllQuerys.
680 */
681 @Override
682 protected String getCreateTempTableSqlSuffix() {
683 return " ON COMMIT DELETE ROWS NOT LOGGED";
684 }
685
686 /**
687 * INTERNAL: DB2 allows LIKE to be used to create temp tables, which avoids having to know the types.
688 * This is used by UpdateAllQuerys.
689 */
690 @Override
691 protected String getCreateTempTableSqlBodyForTable(DatabaseTable table) {
692 return " LIKE " + table.getQualifiedNameDelimited(this);
693 }
694
695 /**
696 * INTERNAL: DB2 has issues with binding with temp table queries.
697 * This is used by UpdateAllQuerys.
698 */
699 @Override
700 public boolean dontBindUpdateAllQueryUsingTempTables() {
701 return true;
702 }
703
704 /**
705 * INTERNAL: DB2 does not allow NULL in select clause.
706 * This is used by UpdateAllQuerys.
707 */
708 @Override
709 public boolean isNullAllowedInSelectClause() {
710 return false;
711 }
712
713 /**
714 * INTERNAL
715 * DB2 has some issues with using parameters on certain functions and relations.
716 * This allows statements to disable binding only in these cases.
717 * If users set casting on, then casting is used instead of dynamic SQL.
718 */
719 @Override
720 public boolean isDynamicSQLRequiredForFunctions() {
721 if(shouldForceBindAllParameters()) {
722 return false;
723 }
724 return !isCastRequired();
725 }
726
727 /**
728 * INTERNAL:
729 * DB2 requires casting on certain operations, such as the CONCAT function,
730 * and parameterized queries of the form, ":param = :param". This method
731 * will write CAST operation to parameters if the type is known.
732 * This is not used by default, only if isCastRequired is set to true,
733 * by default dynamic SQL is used to avoid the issue in only the required cases.
734 */
735 @Override
736 public void writeParameterMarker(Writer writer, ParameterExpression parameter, AbstractRecord record, DatabaseCall call) throws IOException {
737 String paramaterMarker = "?";
738 Object type = parameter.getType();
739 // Update-all query requires casting of null parameter values in select into.
740 if ((type != null) && (this.isCastRequired || ((call.getQuery() != null) && call.getQuery().isUpdateAllQuery()))) {
741 BasicTypeHelperImpl typeHelper = BasicTypeHelperImpl.getInstance();
742 String castType = null;
743 if (typeHelper.isBooleanType(type) || typeHelper.isByteType(type) || typeHelper.isShortType(type)) {
744 castType = "SMALLINT";
745 } else if (typeHelper.isIntType(type)) {
746 castType = "INTEGER";
747 } else if (typeHelper.isLongType(type)) {
748 castType = "BIGINT";
749 } else if (typeHelper.isFloatType(type)) {
750 castType = "REAL";
751 } else if (typeHelper.isDoubleType(type)) {
752 castType = "DOUBLE";
753 } else if (typeHelper.isStringType(type)) {
754 castType = "VARCHAR(" + getCastSizeForVarcharParameter() + ")";
755 }
756
757 if (castType != null) {
758 paramaterMarker = "CAST (? AS " + castType + " )";
759 }
760 }
761 writer.write(paramaterMarker);
762 }
763
764 /**
765 * INTERNAL:
766 * DB2 does not seem to allow FOR UPDATE on queries with multiple tables.
767 * This is only used by testing to exclude these tests.
768 */
769 @Override
770 public boolean supportsLockingQueriesWithMultipleTables() {
771 return false;
772 }
773
774 /**
775 * INTERNAL: DB2 added SEQUENCE support as of (I believe) v8.
776 */
777 @Override
778 public ValueReadQuery buildSelectQueryForSequenceObject(String seqName, Integer size) {
779 return new ValueReadQuery("VALUES(NEXT VALUE FOR " + getQualifiedName(seqName) + ")");
780 }
781
782 /**
783 * INTERNAL: DB2 added SEQUENCE support as of (I believe) v8.
784 */
785 @Override
786 public boolean supportsSequenceObjects() {
787 return true;
788 }
789
790 /**
791 * INTERNAL: DB2 added SEQUENCE support as of (I believe) v8.
792 */
793 @Override
794 public boolean isAlterSequenceObjectSupported() {
795 return true;
796 }
797
798 @Override
799 public boolean shouldPrintForUpdateClause() {
800 return false;
801 }
802 /**
803 * INTERNAL:
804 * Print the SQL representation of the statement on a stream, storing the fields
805 * in the DatabaseCall. This implementation works MaxRows and FirstResult into the SQL using
806 * DB2's ROWNUMBER() OVER() to filter values if shouldUseRownumFiltering is true.
807 */
808 @Override
809 public void printSQLSelectStatement(DatabaseCall call, ExpressionSQLPrinter printer, SQLSelectStatement statement){
810 int max = 0;
811 int firstRow = 0;
812
813 if (statement.getQuery()!=null){
814 max = statement.getQuery().getMaxRows();
815 firstRow = statement.getQuery().getFirstResult();
816 }
817
818 if ( !(this.shouldUseRownumFiltering()) || ( !(max>0) && !(firstRow>0) ) ){
819 super.printSQLSelectStatement(call, printer, statement);
820 statement.appendForUpdateClause(printer);
821 return;
822 } else if ( max > 0 ){
823 statement.setUseUniqueFieldAliases(true);
824 printer.printString("SELECT * FROM (SELECT * FROM (SELECT ");
825 printer.printString("EL_TEMP.*, ROWNUMBER() OVER() AS EL_ROWNM FROM (");
826 call.setFields(statement.printSQL(printer));
827 printer.printString(") AS EL_TEMP) AS EL_TEMP2 WHERE EL_ROWNM <= ");
828 printer.printParameter(DatabaseCall.MAXROW_FIELD);
829 printer.printString(") AS EL_TEMP3 WHERE EL_ROWNM > ");
830 printer.printParameter(DatabaseCall.FIRSTRESULT_FIELD);
831 // If we have a ForUpdate clause, it must be on the outermost query
832 statement.appendForUpdateClause(printer);
833 } else {// firstRow>0
834 statement.setUseUniqueFieldAliases(true);
835 printer.printString("SELECT * FROM (SELECT EL_TEMP.*, ROWNUMBER() OVER() AS EL_ROWNM FROM (");
836 call.setFields(statement.printSQL(printer));
837 printer.printString(") AS EL_TEMP) AS EL_TEMP2 WHERE EL_ROWNM > ");
838 printer.printParameter(DatabaseCall.FIRSTRESULT_FIELD);
839 statement.appendForUpdateClause(printer);
840 }
841 call.setIgnoreFirstRowSetting(true);
842 call.setIgnoreMaxResultsSetting(true);
843 }
844
845 }
00 /*******************************************************************************
1 * Copyright (c) 1998, 2014 Oracle and/or its affiliates. All rights reserved.
1 * Copyright (c) 1998, 2015 Oracle and/or its affiliates, IBM Corporation. All rights reserved.
22 * This program and the accompanying materials are made available under the
33 * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
44 * which accompanies this distribution.
1515 * 05/10/2014 - 428675 - 2.5.2 - Rick Curtis - Add support for WebSphere logger.
1616 * 04/01/2015 Will Dazey
1717 * - 463726: Added DatabaseSession null check
18 * 11/05/2015 Dalia Abo Sheasha
19 * - 480787: Wrap several privileged method calls with a doPrivileged block
1820 ******************************************************************************/
1921 package org.eclipse.persistence.platform.server.was;
2022
5759 /** Override by subclass: Search String in application server session for war modules */
5860 APP_SERVER_CLASSLOADER_MODULE_WAR_SEARCH_STRING_PREFIX = ".war!/";
5961 APP_SERVER_CLASSLOADER_MODULE_EJB_WAR_SEARCH_STRING_POSTFIX = "]";
62
63 // Change the default value of property "eclipselink.security.usedoprivileged".
64 PrivilegedAccessHelper.setDefaultUseDoPrivilegedValue(true);
6065 }
6166
6267 /**
0 /*******************************************************************************
1 * Copyright (c) 1998, 2015 Oracle and/or its affiliates. All rights reserved.
2 * This program and the accompanying materials are made available under the
3 * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
4 * which accompanies this distribution.
5 * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
6 * and the Eclipse Distribution License is available at
7 * http://www.eclipse.org/org/documents/edl-v10.php.
8 *
9 * Contributors:
10 * Oracle - initial API and implementation from Oracle TopLink
11 * 04/01/2011-2.3 Guy Pelletier
12 * - 337323: Multi-tenant with shared schema support (part 2)
13 * 09/09/2011-2.3.1 Guy Pelletier
14 * - 356197: Add new VPD type to MultitenantType
0 /*******************************************************************************
1 * Copyright (c) 1998, 2018 Oracle and/or its affiliates. All rights reserved.
2 * This program and the accompanying materials are made available under the
3 * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
4 * which accompanies this distribution.
5 * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
6 * and the Eclipse Distribution License is available at
7 * http://www.eclipse.org/org/documents/edl-v10.php.
8 *
9 * Contributors:
10 * Oracle - initial API and implementation from Oracle TopLink
11 * 04/01/2011-2.3 Guy Pelletier
12 * - 337323: Multi-tenant with shared schema support (part 2)
13 * 09/09/2011-2.3.1 Guy Pelletier
14 * - 356197: Add new VPD type to MultitenantType
1515 ******************************************************************************/
16 package org.eclipse.persistence.queries;
17
18 import java.sql.ResultSet;
19 import java.sql.ResultSetMetaData;
20 import java.sql.SQLException;
21 import java.sql.Statement;
22 import java.util.ArrayList;
23 import java.util.Collection;
24 import java.util.IdentityHashMap;
25 import java.util.Iterator;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.Vector;
29
30 import org.eclipse.persistence.exceptions.DatabaseException;
31 import org.eclipse.persistence.exceptions.QueryException;
32 import org.eclipse.persistence.expressions.Expression;
33 import org.eclipse.persistence.expressions.ExpressionBuilder;
34 import org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor;
35 import org.eclipse.persistence.internal.databaseaccess.DatabaseCall;
36 import org.eclipse.persistence.internal.databaseaccess.DatabasePlatform;
37 import org.eclipse.persistence.internal.descriptors.ObjectBuilder;
38 import org.eclipse.persistence.internal.helper.ClassConstants;
39 import org.eclipse.persistence.internal.helper.DatabaseField;
40 import org.eclipse.persistence.internal.helper.InvalidObject;
41 import org.eclipse.persistence.internal.helper.ThreadCursoredList;
42 import org.eclipse.persistence.internal.queries.ContainerPolicy;
43 import org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism;
44 import org.eclipse.persistence.internal.sessions.AbstractRecord;
45 import org.eclipse.persistence.internal.sessions.AbstractSession;
46 import org.eclipse.persistence.internal.sessions.ResultSetRecord;
47 import org.eclipse.persistence.internal.sessions.SimpleResultSetRecord;
48 import org.eclipse.persistence.internal.sessions.UnitOfWorkImpl;
49 import org.eclipse.persistence.internal.sessions.remote.RemoteSessionController;
50 import org.eclipse.persistence.internal.sessions.remote.Transporter;
51 import org.eclipse.persistence.mappings.DatabaseMapping;
52 import org.eclipse.persistence.sessions.DatabaseRecord;
53 import org.eclipse.persistence.sessions.SessionProfiler;
54 import org.eclipse.persistence.sessions.remote.DistributedSession;
55 import org.eclipse.persistence.tools.profiler.QueryMonitor;
56
57 /**
58 * <p><b>Purpose</b>:
59 * Concrete class for all read queries involving a collection of objects.
16 package org.eclipse.persistence.queries;
17
18 import java.sql.ResultSet;
19 import java.sql.ResultSetMetaData;
20 import java.sql.SQLException;
21 import java.sql.Statement;
22 import java.util.ArrayList;
23 import java.util.Collection;
24 import java.util.IdentityHashMap;
25 import java.util.Iterator;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.Vector;
29
30 import org.eclipse.persistence.exceptions.DatabaseException;
31 import org.eclipse.persistence.exceptions.QueryException;
32 import org.eclipse.persistence.expressions.Expression;
33 import org.eclipse.persistence.expressions.ExpressionBuilder;
34 import org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor;
35 import org.eclipse.persistence.internal.databaseaccess.DatabaseCall;
36 import org.eclipse.persistence.internal.databaseaccess.DatabasePlatform;
37 import org.eclipse.persistence.internal.descriptors.ObjectBuilder;
38 import org.eclipse.persistence.internal.expressions.QueryKeyExpression;
39 import org.eclipse.persistence.internal.helper.ClassConstants;
40 import org.eclipse.persistence.internal.helper.DatabaseField;
41 import org.eclipse.persistence.internal.helper.InvalidObject;
42 import org.eclipse.persistence.internal.helper.ThreadCursoredList;
43 import org.eclipse.persistence.internal.queries.ContainerPolicy;
44 import org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism;
45 import org.eclipse.persistence.internal.sessions.AbstractRecord;
46 import org.eclipse.persistence.internal.sessions.AbstractSession;
47 import org.eclipse.persistence.internal.sessions.ResultSetRecord;
48 import org.eclipse.persistence.internal.sessions.SimpleResultSetRecord;
49 import org.eclipse.persistence.internal.sessions.UnitOfWorkImpl;
50 import org.eclipse.persistence.internal.sessions.remote.RemoteSessionController;
51 import org.eclipse.persistence.internal.sessions.remote.Transporter;
52 import org.eclipse.persistence.mappings.DatabaseMapping;
53 import org.eclipse.persistence.mappings.OneToManyMapping;
54 import org.eclipse.persistence.sessions.DatabaseRecord;
55 import org.eclipse.persistence.sessions.SessionProfiler;
56 import org.eclipse.persistence.sessions.remote.DistributedSession;
57 import org.eclipse.persistence.tools.profiler.QueryMonitor;
58
59 /**
60 * <p><b>Purpose</b>:
61 * Concrete class for all read queries involving a collection of objects.
6062 *
61 * <p><b>Responsibilities</b>:
62 * Return a container of the objects generated by the query.
63 * Implements the inheritance feature when dealing with abstract descriptors
64 *
65 * @author Yvon Lavoie
66 * @since TOPLink/Java 1.0
67 */
68 public class ReadAllQuery extends ObjectLevelReadQuery {
69 /** Used for collection and stream support. */
70 protected ContainerPolicy containerPolicy;
71
72 /** Used for Oracle HierarchicalQuery support */
73 protected Expression startWithExpression;
74 protected Expression connectByExpression;
75 protected List<Expression> orderSiblingsByExpressions;
63 * <p><b>Responsibilities</b>:
64 * Return a container of the objects generated by the query.
65 * Implements the inheritance feature when dealing with abstract descriptors
66 *
67 * @author Yvon Lavoie
68 * @since TOPLink/Java 1.0
69 */
70 public class ReadAllQuery extends ObjectLevelReadQuery {
71 /** Used for collection and stream support. */
72 protected ContainerPolicy containerPolicy;
73
74 /** Used for Oracle HierarchicalQuery support */
75 protected Expression startWithExpression;
76 protected Expression connectByExpression;
77 protected List<Expression> orderSiblingsByExpressions;
7678 protected Direction direction;
7779
7880 /**
107109 return mapping != null && mapping.isOneToOneMapping() ? CHILD_TO_PARENT : PARENT_TO_CHILD;
108110 }
109111 }
110
111 /**
112 * PUBLIC:
113 * Return a new read all query.
114 * A reference class must be specified before execution.
115 * It is better to provide the class and expression builder on construction to ensure a single expression builder is used.
116 * If no selection criteria is specified this will read all objects of the class from the database.
117 */
118 public ReadAllQuery() {
119 super();
120 setContainerPolicy(ContainerPolicy.buildDefaultPolicy());
121 }
122
123 /**
124 * PUBLIC:
125 * Return a new read all query.
126 * It is better to provide the class and expression builder on construction to ensure a single expression builder is used.
127 * If no selection criteria is specified this will read all objects of the class from the database.
128 */
129 public ReadAllQuery(Class classToRead) {
130 this();
131 this.referenceClass = classToRead;
132 }
133
134 /**
135 * PUBLIC:
136 * Return a new read all query for the class and the selection criteria.
137 */
138 public ReadAllQuery(Class classToRead, Expression selectionCriteria) {
139 this();
140 this.referenceClass = classToRead;
141 setSelectionCriteria(selectionCriteria);
142 }
143
144 /**
145 * PUBLIC:
146 * Return a new read all query for the class.
147 * The expression builder must be used for all associated expressions used with the query.
148 */
149 public ReadAllQuery(Class classToRead, ExpressionBuilder builder) {
150 this();
151 this.defaultBuilder = builder;
152 this.referenceClass = classToRead;
153 }
154
155 /**
156 * PUBLIC:
157 * Return a new read all query.
158 * The call represents a database interaction such as SQL, Stored Procedure.
159 */
160 public ReadAllQuery(Class classToRead, Call call) {
161 this();
162 this.referenceClass = classToRead;
163 setCall(call);
164 }
165
166 /**
167 * PUBLIC:
168 * Return a query by example query to find all objects matching the attributes of the example object.
169 */
170 public ReadAllQuery(Object exampleObject, QueryByExamplePolicy policy) {
171 this();
172 setExampleObject(exampleObject);
173 setQueryByExamplePolicy(policy);
174 }
175
176 /**
177 * PUBLIC:
178 * The expression builder should be provide on creation to ensure only one is used.
179 */
180 public ReadAllQuery(ExpressionBuilder builder) {
181 this();
182 this.defaultBuilder = builder;
183 }
184
185 /**
186 * PUBLIC:
187 * Create a read all query with the database call.
188 */
189 public ReadAllQuery(Call call) {
190 this();
191 setCall(call);
192 }
193
194 /**
195 * PUBLIC:
196 * Order the query results by the object's attribute or query key name.
197 */
198 public void addAscendingOrdering(String queryKeyName) {
199 addOrdering(getExpressionBuilder().get(queryKeyName).ascending());
200 }
201
202 /**
203 * INTERNAL:
204 * <P> This method is called by the object builder when building an original.
205 * It will cause the original to be cached in the query results if the query
206 * is set to do so.
207 */
208 @Override
209 public void cacheResult(Object unwrappedOriginal) {
210 Collection container = (Collection)getTemporaryCachedQueryResults();
211 if (container == null) {
212 container = (Collection)getContainerPolicy().containerInstance();
213 setTemporaryCachedQueryResults(container);
214 }
215 getContainerPolicy().addInto(unwrappedOriginal, container, getSession());
216 }
217
218 /**
219 * INTERNAL:
220 * The cache check is done before the prepare as a hit will not require the work to be done.
221 */
222 @Override
223 protected Object checkEarlyReturnLocal(AbstractSession session, AbstractRecord translationRow) {
224 // Check for in-memory only query.
225 if (shouldCheckCacheOnly()) {
226 // assert !isReportQuery();
227 if (shouldUseWrapperPolicy()) {
228 getContainerPolicy().setElementDescriptor(this.descriptor);
229 }
230
231 // PERF: Fixed to not query each unit of work cache (is not conforming),
232 // avoid hashtable and primary key indexing.
233 // At some point we may need to support some kind of in-memory with conforming option,
234 // but we do not currently allow this.
235 AbstractSession rootSession = session;
236 while (rootSession.isUnitOfWork()) {
237 rootSession = ((UnitOfWorkImpl)rootSession).getParent();
238 }
239 Vector allCachedVector = rootSession.getIdentityMapAccessor().getAllFromIdentityMap(getSelectionCriteria(), getReferenceClass(), translationRow, getInMemoryQueryIndirectionPolicyState(), false);
240
241 // Must ensure that all of the objects returned are correctly registered in the unit of work.
242 if (session.isUnitOfWork()) {
243 allCachedVector = ((UnitOfWorkImpl)session).registerAllObjects(allCachedVector);
244 }
245
246 this.isCacheCheckComplete = true;
247
248 return getContainerPolicy().buildContainerFromVector(allCachedVector, session);
249 } else {
250 return null;
251 }
252 }
253
254 /**
255 * INTERNAL:
256 * Check to see if a custom query should be used for this query.
257 * This is done before the query is copied and prepared/executed.
258 * null means there is none.
112
113 /**
114 * PUBLIC:
115 * Return a new read all query.
116 * A reference class must be specified before execution.
117 * It is better to provide the class and expression builder on construction to ensure a single expression builder is used.
118 * If no selection criteria is specified this will read all objects of the class from the database.
119 */
120 public ReadAllQuery() {
121 super();
122 setContainerPolicy(ContainerPolicy.buildDefaultPolicy());
123 }
124
125 /**
126 * PUBLIC:
127 * Return a new read all query.
128 * It is better to provide the class and expression builder on construction to ensure a single expression builder is used.
129 * If no selection criteria is specified this will read all objects of the class from the database.
130 */
131 public ReadAllQuery(Class classToRead) {
132 this();
133 this.referenceClass = classToRead;
134 }
135
136 /**
137 * PUBLIC:
138 * Return a new read all query for the class and the selection criteria.
139 */
140 public ReadAllQuery(Class classToRead, Expression selectionCriteria) {
141 this();
142 this.referenceClass = classToRead;
143 setSelectionCriteria(selectionCriteria);
144 }
145
146 /**
147 * PUBLIC:
148 * Return a new read all query for the class.
149 * The expression builder must be used for all associated expressions used with the query.
150 */
151 public ReadAllQuery(Class classToRead, ExpressionBuilder builder) {
152 this();
153 this.defaultBuilder = builder;
154 this.referenceClass = classToRead;
155 }
156
157 /**
158 * PUBLIC:
159 * Return a new read all query.
160 * The call represents a database interaction such as SQL, Stored Procedure.
161 */
162 public ReadAllQuery(Class classToRead, Call call) {
163 this();
164 this.referenceClass = classToRead;
165 setCall(call);
166 }
167
168 /**
169 * PUBLIC:
170 * Return a query by example query to find all objects matching the attributes of the example object.
171 */
172 public ReadAllQuery(Object exampleObject, QueryByExamplePolicy policy) {
173 this();
174 setExampleObject(exampleObject);
175 setQueryByExamplePolicy(policy);
176 }
177
178 /**
179 * PUBLIC:
180 * The expression builder should be provide on creation to ensure only one is used.
181 */
182 public ReadAllQuery(ExpressionBuilder builder) {
183 this();
184 this.defaultBuilder = builder;
185 }
186
187 /**
188 * PUBLIC:
189 * Create a read all query with the database call.
190 */
191 public ReadAllQuery(Call call) {
192 this();
193 setCall(call);
194 }
195
196 /**
197 * PUBLIC:
198 * Order the query results by the object's attribute or query key name.
199 */
200 public void addAscendingOrdering(String queryKeyName) {
201 addOrdering(getExpressionBuilder().get(queryKeyName).ascending());
202 }
203
204 /**
205 * INTERNAL:
206 * <P> This method is called by the object builder when building an original.
207 * It will cause the original to be cached in the query results if the query
208 * is set to do so.
209 */
210 @Override
211 public void cacheResult(Object unwrappedOriginal) {
212 Collection container = (Collection)getTemporaryCachedQueryResults();
213 if (container == null) {
214 container = (Collection)getContainerPolicy().containerInstance();
215 setTemporaryCachedQueryResults(container);
216 }
217 getContainerPolicy().addInto(unwrappedOriginal, container, getSession());
218 }
219
220 /**
221 * INTERNAL:
222 * The cache check is done before the prepare as a hit will not require the work to be done.
223 */
224 @Override
225 protected Object checkEarlyReturnLocal(AbstractSession session, AbstractRecord translationRow) {
226 // Check for in-memory only query.
227 if (shouldCheckCacheOnly()) {
228 // assert !isReportQuery();
229 if (shouldUseWrapperPolicy()) {
230 getContainerPolicy().setElementDescriptor(this.descriptor);
231 }
232
233 // PERF: Fixed to not query each unit of work cache (is not conforming),
234 // avoid hashtable and primary key indexing.
235 // At some point we may need to support some kind of in-memory with conforming option,
236 // but we do not currently allow this.
237 AbstractSession rootSession = session;
238 while (rootSession.isUnitOfWork()) {
239 rootSession = ((UnitOfWorkImpl)rootSession).getParent();
240 }
241 Vector allCachedVector = rootSession.getIdentityMapAccessor().getAllFromIdentityMap(getSelectionCriteria(), getReferenceClass(), translationRow, getInMemoryQueryIndirectionPolicyState(), false);
242
243 // Must ensure that all of the objects returned are correctly registered in the unit of work.
244 if (session.isUnitOfWork()) {
245 allCachedVector = ((UnitOfWorkImpl)session).registerAllObjects(allCachedVector);
246 }
247
248 this.isCacheCheckComplete = true;
249
250 return getContainerPolicy().buildContainerFromVector(allCachedVector, session);
251 } else {
252 return null;
253 }
254 }
255
256 /**
257 * INTERNAL:
258 * Check to see if a custom query should be used for this query.
259 * This is done before the query is copied and prepared/executed.
260 * null means there is none.
259261 */
260262 @Override
261263 protected DatabaseQuery checkForCustomQuery(AbstractSession session, AbstractRecord translationRow) {
283285 }
284286
285287 /**
286 * INTERNAL:
287 * Clone the query.
288 */
289 @Override
290 public Object clone() {
291 ReadAllQuery cloneQuery = (ReadAllQuery)super.clone();
292
293 // Don't use setters as that will trigger unprepare
294 cloneQuery.containerPolicy = this.containerPolicy.clone(cloneQuery);
295
296 return cloneQuery;
297 }
298
299 /**
300 * INTERNAL:
301 * Conform the result if specified.
302 */
303 protected Object conformResult(Object result, UnitOfWorkImpl unitOfWork, AbstractRecord arguments, boolean buildDirectlyFromRows) {
304 if (getSelectionCriteria() != null) {
305 ExpressionBuilder builder = getSelectionCriteria().getBuilder();
306 builder.setSession(unitOfWork.getRootSession(null));
307 builder.setQueryClass(getReferenceClass());
308 }
309
310 // If the query is redirected then the collection returned might no longer
311 // correspond to the original container policy. CR#2342-S.M.
312 ContainerPolicy cp;
313 if (getRedirector() != null) {
314 cp = ContainerPolicy.buildPolicyFor(result.getClass());
315 } else {
316 cp = getContainerPolicy();
317 }
318
319 // This code is now a great deal different... For one, registration is done
320 // as part of conforming. Also, this should only be called if one actually
321 // is conforming.
322 // First scan the UnitOfWork for conforming instances.
323 // This will walk through the entire cache of registered objects.
324 // Let p be objects from result not in the cache.
325 // Let c be objects from cache.
326 // Presently p intersect c = empty set, but later p subset c.
327 // By checking cache now doesConform will be called p fewer times.
328 Map<Object, Object> indexedInterimResult = unitOfWork.scanForConformingInstances(getSelectionCriteria(), getReferenceClass(), arguments, this);
329
330 Cursor cursor = null;
331 // In the case of cursors just conform/register the initially read collection.
332 if (cp.isCursorPolicy()) {
333 cursor = (Cursor)result;
334 cp = ContainerPolicy.buildPolicyFor(ClassConstants.Vector_class);
335 // In nested UnitOfWork session might have been session of the parent.
336 cursor.setSession(unitOfWork);
337 result = cursor.getObjectCollection();
338 // for later incremental conforming...
339 cursor.setInitiallyConformingIndex(indexedInterimResult);
340 cursor.setSelectionCriteriaClone(getSelectionCriteria());
341 cursor.setTranslationRow(arguments);
342 }
343
344 // Now conform the result from the database.
345 // Remove any deleted or changed objects that no longer conform.
346 // Deletes will only work for simple queries, queries with or's or anyof's may not return
288 * INTERNAL:
289 * Clone the query.
290 */
291 @Override
292 public Object clone() {
293 ReadAllQuery cloneQuery = (ReadAllQuery)super.clone();
294
295 // Don't use setters as that will trigger unprepare
296 cloneQuery.containerPolicy = this.containerPolicy.clone(cloneQuery);
297
298 return cloneQuery;
299 }
300
301 /**
302 * INTERNAL:
303 * Conform the result if specified.
304 */
305 protected Object conformResult(Object result, UnitOfWorkImpl unitOfWork, AbstractRecord arguments, boolean buildDirectlyFromRows) {
306 Expression selectionCriteria = getSelectionCriteria();
307 if (selectionCriteria != null) {
308 ExpressionBuilder builder = getSelectionCriteria().getBuilder();
309 builder.setSession(unitOfWork.getRootSession(null));
310 builder.setQueryClass(getReferenceClass());
311 if (getQueryMechanism().isExpressionQueryMechanism() && selectionCriteria.isLogicalExpression()) {
312 // bug #526546
313 if (builder.derivedExpressions != null) {
314 for (Expression e : builder.derivedExpressions) {
315 if (e.isQueryKeyExpression() && ((QueryKeyExpression) e).shouldQueryToManyRelationship()) {
316 DatabaseMapping mapping = ((QueryKeyExpression) e).getMapping();
317 if (mapping.isOneToManyMapping()) {
318 OneToManyMapping otm = (OneToManyMapping) mapping;
319 Expression join = otm.buildSelectionCriteria();
320 selectionCriteria = selectionCriteria.and(join);
321 }
322 }
323 }
324 }
325 }
326
327 }
328
329 // If the query is redirected then the collection returned might no longer
330 // correspond to the original container policy. CR#2342-S.M.
331 ContainerPolicy cp;
332 if (getRedirector() != null) {
333 cp = ContainerPolicy.buildPolicyFor(result.getClass());
334 } else {
335 cp = getContainerPolicy();
336 }
337
338 // This code is now a great deal different... For one, registration is done
339 // as part of conforming. Also, this should only be called if one actually
340 // is conforming.
341 // First scan the UnitOfWork for conforming instances.
342 // This will walk through the entire cache of registered objects.
343 // Let p be objects from result not in the cache.
344 // Let c be objects from cache.
345 // Presently p intersect c = empty set, but later p subset c.
346 // By checking cache now doesConform will be called p fewer times.
347 Map<Object, Object> indexedInterimResult = unitOfWork.scanForConformingInstances(selectionCriteria, getReferenceClass(), arguments, this);
348
349 Cursor cursor = null;
350 // In the case of cursors just conform/register the initially read collection.
351 if (cp.isCursorPolicy()) {
352 cursor = (Cursor)result;
353 cp = ContainerPolicy.buildPolicyFor(ClassConstants.Vector_class);
354 // In nested UnitOfWork session might have been session of the parent.
355 cursor.setSession(unitOfWork);
356 result = cursor.getObjectCollection();
357 // for later incremental conforming...
358 cursor.setInitiallyConformingIndex(indexedInterimResult);
359 cursor.setSelectionCriteriaClone(getSelectionCriteria());
360 cursor.setTranslationRow(arguments);
361 }
362
363 // Now conform the result from the database.
364 // Remove any deleted or changed objects that no longer conform.
365 // Deletes will only work for simple queries, queries with or's or anyof's may not return
347366 // correct results when untriggered indirection is in the model.
348 List fromDatabase = null;
349
350 // When building directly from rows, one of the performance benefits
351 // is that we no longer have to wrap and then unwrap the originals.
352 // result is just a vector, not a container of wrapped originals.
353 if (buildDirectlyFromRows) {
354 List<AbstractRecord> rows = (List<AbstractRecord>)result;
355 int size = rows.size();
356 fromDatabase = new ArrayList(size);
357 for (int index = 0; index < size; index++) {
358 AbstractRecord row = rows.get(index);
359 // null is placed in the row collection for 1-m joining to filter duplicate rows.
360 if (row != null) {
361 Object clone = conformIndividualResult(buildObject(row), unitOfWork, arguments, getSelectionCriteria(), indexedInterimResult);
362 if (clone != null) {
363 fromDatabase.add(clone);
364 }
365 }
366 }
367 } else {
368 fromDatabase = new ArrayList(cp.sizeFor(result));
369 AbstractSession sessionToUse = unitOfWork.getParent();
370 for (Object iter = cp.iteratorFor(result); cp.hasNext(iter);) {
371 Object object = cp.next(iter, sessionToUse);
372 Object clone = conformIndividualResult(registerIndividualResult(object, null, unitOfWork, null, null), unitOfWork, arguments, getSelectionCriteria(), indexedInterimResult);
373 if (clone != null) {
374 fromDatabase.add(clone);
375 }
376 }
377 }
378
367 List fromDatabase = null;
368
369 // When building directly from rows, one of the performance benefits
370 // is that we no longer have to wrap and then unwrap the originals.
371 // result is just a vector, not a container of wrapped originals.
372 if (buildDirectlyFromRows) {
373 List<AbstractRecord> rows = (List<AbstractRecord>)result;
374 int size = rows.size();
375 fromDatabase = new ArrayList(size);
376 for (int index = 0; index < size; index++) {
377 AbstractRecord row = rows.get(index);
378 // null is placed in the row collection for 1-m joining to filter duplicate rows.
379 if (row != null) {
380 Object clone = conformIndividualResult(buildObject(row), unitOfWork, arguments, getSelectionCriteria(), indexedInterimResult);
381 if (clone != null) {
382 fromDatabase.add(clone);
383 }
384 }
385 }
386 } else {
387 fromDatabase = new ArrayList(cp.sizeFor(result));
388 AbstractSession sessionToUse = unitOfWork.getParent();
389 for (Object iter = cp.iteratorFor(result); cp.hasNext(iter);) {
390 Object object = cp.next(iter, sessionToUse);
391 Object clone = conformIndividualResult(registerIndividualResult(object, null, unitOfWork, null, null), unitOfWork, arguments, getSelectionCriteria(), indexedInterimResult);
392 if (clone != null) {
393 fromDatabase.add(clone);
394 }
395 }
396 }
397
379398 // Now add the unwrapped conforming instances into an appropriate container.
380 // Wrapping is done automatically.
381 // Make sure a vector of exactly the right size is returned.
382 Object conformedResult = cp.containerInstance(indexedInterimResult.size() + fromDatabase.size());
383 for (Iterator enumtr = indexedInterimResult.values().iterator(); enumtr.hasNext();) {
384 Object eachClone = enumtr.next();
385 cp.addInto(eachClone, conformedResult, unitOfWork);
386 }
387 int size = fromDatabase.size();
388 for (int index = 0; index < size; index++) {
389 Object eachClone = fromDatabase.get(index);
390 cp.addInto(eachClone, conformedResult, unitOfWork);
391 }
392
393 if (cursor != null) {
394 cursor.setObjectCollection((List)conformedResult);
395
396 // For nested UOW must copy all in object collection to
399 // Wrapping is done automatically.
400 // Make sure a vector of exactly the right size is returned.
401 Object conformedResult = cp.containerInstance(indexedInterimResult.size() + fromDatabase.size());
402 for (Iterator enumtr = indexedInterimResult.values().iterator(); enumtr.hasNext();) {
403 Object eachClone = enumtr.next();
404 cp.addInto(eachClone, conformedResult, unitOfWork);
405 }
406 int size = fromDatabase.size();
407 for (int index = 0; index < size; index++) {
408 Object eachClone = fromDatabase.get(index);
409 cp.addInto(eachClone, conformedResult, unitOfWork);
410 }
411
412 if (cursor != null) {
413 cursor.setObjectCollection((List)conformedResult);
414
415 // For nested UOW must copy all in object collection to
397416 // initiallyConformingIndex, as some of these could have been from
398 // the parent UnitOfWork.
399 if (unitOfWork.isNestedUnitOfWork()) {
400 for (Object clone : cursor.getObjectCollection()) {
401 indexedInterimResult.put(clone, clone);
402 }
403 }
404 return cursor;
405 } else {
406 return conformedResult;
407 }
408 }
409
410 /**
411 * INTERNAL:
412 * Execute the query. If there are cached results return those.
413 * This must override the super to support result caching.
414 *
415 * @param session - the session in which the receiver will be executed.
416 * @return An object or vector, the result of executing the query.
417 * @exception DatabaseException - an error has occurred on the database
418 */
419 @Override
417 // the parent UnitOfWork.
418 if (unitOfWork.isNestedUnitOfWork()) {
419 for (Object clone : cursor.getObjectCollection()) {
420 indexedInterimResult.put(clone, clone);
421 }
422 }
423 return cursor;
424 } else {
425 return conformedResult;
426 }
427 }
428
429 /**
430 * INTERNAL:
431 * Execute the query. If there are cached results return those.
432 * This must override the super to support result caching.
433 *
434 * @param session - the session in which the receiver will be executed.
435 * @return An object or vector, the result of executing the query.
436 * @exception DatabaseException - an error has occurred on the database
437 */
438 @Override
420439 public Object execute(AbstractSession session, AbstractRecord row) throws DatabaseException {
421 if (shouldCacheQueryResults()) {
422 if (getContainerPolicy().overridesRead()) {
423 throw QueryException.cannotCacheCursorResultsOnQuery(this);
424 }
425 if (shouldConformResultsInUnitOfWork()) {
426 throw QueryException.cannotConformAndCacheQueryResults(this);
427 }
428 if (isPrepared()) {// only prepared queries can have cached results.
429 Object queryResults = getQueryResults(session, row, true);
430 if (queryResults != null) {
431 if (QueryMonitor.shouldMonitor()) {
432 QueryMonitor.incrementReadAllHits(this);
433 }
434 session.incrementProfile(SessionProfiler.CacheHits, this);
440 if (shouldCacheQueryResults()) {
441 if (getContainerPolicy().overridesRead()) {
442 throw QueryException.cannotCacheCursorResultsOnQuery(this);
443 }
444 if (shouldConformResultsInUnitOfWork()) {
445 throw QueryException.cannotConformAndCacheQueryResults(this);
446 }
447 if (isPrepared()) {// only prepared queries can have cached results.
448 Object queryResults = getQueryResults(session, row, true);
449 if (queryResults != null) {
450 if (QueryMonitor.shouldMonitor()) {
451 QueryMonitor.incrementReadAllHits(this);
452 }
453 session.incrementProfile(SessionProfiler.CacheHits, this);
435454 // bug6138532 - check for "cached no results" (InvalidObject singleton) in query
436 // results, and return an empty container instance as configured
437 if (queryResults == InvalidObject.instance) {
438 return getContainerPolicy().containerInstance(0);
439 }
440 Collection results = (Collection)queryResults;
441 if (session.isUnitOfWork()) {
442 ContainerPolicy policy = getContainerPolicy();
443 Object resultCollection = policy.containerInstance(results.size());
444 Object iterator = policy.iteratorFor(results);
445 while (policy.hasNext(iterator)) {
446 Object result = ((UnitOfWorkImpl)session).registerExistingObject(policy.next(iterator, session), this.descriptor, null, true);
447 policy.addInto(result, resultCollection, session);
448 }
449 return resultCollection;
450 }
451 return results;
452 }
453 }
454 session.incrementProfile(SessionProfiler.CacheMisses, this);
455 }
456 if (QueryMonitor.shouldMonitor()) {
457 QueryMonitor.incrementReadAllMisses(this);
458 }
459 return super.execute(session, row);
460 }
461
462 /**
463 * INTERNAL:
464 * Execute the query.
465 * Get the rows and build the object from the rows.
466 * @exception DatabaseException - an error has occurred on the database
467 * @return java.lang.Object collection of objects resulting from execution of query.
468 */
469 @Override
470 protected Object executeObjectLevelReadQuery() throws DatabaseException {
471 Object result = null;
472
473 if (this.containerPolicy.overridesRead()) {
474 this.executionTime = System.currentTimeMillis();
475 return this.containerPolicy.execute();
476 }
477
478 if (this.descriptor.isDescriptorForInterface()) {
479 Object returnValue = this.descriptor.getInterfacePolicy().selectAllObjectsUsingMultipleTableSubclassRead(this);
480 this.executionTime = System.currentTimeMillis();
481 return returnValue;
482 }
483
484 if (this.descriptor.hasTablePerClassPolicy() && this.descriptor.isAbstract()) {
485 result = this.containerPolicy.containerInstance();
486
487 if (this.shouldIncludeData) {
488 ComplexQueryResult complexResult = new ComplexQueryResult();
489 complexResult.setResult(result);
490 complexResult.setData(new ArrayList());
491 result = complexResult;
492 }
493 } else {
494 Object sopObject = getTranslationRow().getSopObject();
495 boolean useOptimization = false;
496 if (sopObject == null) {
455 // results, and return an empty container instance as configured
456 if (queryResults == InvalidObject.instance) {
457 return getContainerPolicy().containerInstance(0);
458 }
459 Collection results = (Collection)queryResults;
460 if (session.isUnitOfWork()) {
461 ContainerPolicy policy = getContainerPolicy();
462 Object resultCollection = policy.containerInstance(results.size());
463 Object iterator = policy.iteratorFor(results);
464 while (policy.hasNext(iterator)) {
465 Object result = ((UnitOfWorkImpl)session).registerExistingObject(policy.next(iterator, session), this.descriptor, null, true);
466 policy.addInto(result, resultCollection, session);
467 }
468 return resultCollection;
469 }
470 return results;
471 }
472 }
473 session.incrementProfile(SessionProfiler.CacheMisses, this);
474 }
475 if (QueryMonitor.shouldMonitor()) {
476 QueryMonitor.incrementReadAllMisses(this);
477 }
478 return super.execute(session, row);
479 }
480
481 /**
482 * INTERNAL:
483 * Execute the query.
484 * Get the rows and build the object from the rows.
485 * @exception DatabaseException - an error has occurred on the database
486 * @return java.lang.Object collection of objects resulting from execution of query.
487 */
488 @Override
489 protected Object executeObjectLevelReadQuery() throws DatabaseException {
490 Object result = null;
491
492 if (this.containerPolicy.overridesRead()) {
493 this.executionTime = System.currentTimeMillis();
494 return this.containerPolicy.execute();
495 }
496
497 if (this.descriptor.isDescriptorForInterface()) {
498 Object returnValue = this.descriptor.getInterfacePolicy().selectAllObjectsUsingMultipleTableSubclassRead(this);
499 this.executionTime = System.currentTimeMillis();
500 return returnValue;
501 }
502
503 if (this.descriptor.hasTablePerClassPolicy() && this.descriptor.isAbstract()) {
504 result = this.containerPolicy.containerInstance();
505
506 if (this.shouldIncludeData) {
507 ComplexQueryResult complexResult = new ComplexQueryResult();
508 complexResult.setResult(result);
509 complexResult.setData(new ArrayList());
510 result = complexResult;
511 }
512 } else {
513 Object sopObject = getTranslationRow().getSopObject();
514 boolean useOptimization = false;
515 if (sopObject == null) {
497516 useOptimization = usesResultSetAccessOptimization();
498517 }
499518
500 if (useOptimization) {
501 DatabaseCall call = ((DatasourceCallQueryMechanism)this.queryMechanism).selectResultSet();
502 this.executionTime = System.currentTimeMillis();
503 Statement statement = call.getStatement();
504 ResultSet resultSet = call.getResult();
505 DatabaseAccessor dbAccessor = (DatabaseAccessor)getAccessor();
506 boolean exceptionOccured = false;
507 try {
508 if (this.session.isUnitOfWork()) {
519 if (useOptimization) {
520 DatabaseCall call = ((DatasourceCallQueryMechanism)this.queryMechanism).selectResultSet();
521 this.executionTime = System.currentTimeMillis();
522 Statement statement = call.getStatement();
523 ResultSet resultSet = call.getResult();
524 DatabaseAccessor dbAccessor = (DatabaseAccessor)getAccessor();
525 boolean exceptionOccured = false;
526 try {
527 if (this.session.isUnitOfWork()) {
509528 result = registerResultSetInUnitOfWork(resultSet, call.getFields(), call.getFieldsArray(), (UnitOfWorkImpl)this.session, this.translationRow);
510 } else {
511 result = this.containerPolicy.containerInstance();
512 this.descriptor.getObjectBuilder().buildObjectsFromResultSetInto(this, resultSet, call.getFields(), call.getFieldsArray(), result);
513 }
514 } catch (SQLException exception) {
515 exceptionOccured = true;
516 DatabaseException commException = dbAccessor.processExceptionForCommError(this.session, exception, call);
517 if (commException != null) {
518 throw commException;
519 }
520 throw DatabaseException.sqlException(exception, call, dbAccessor, this.session, false);
521 } finally {
522 try {
523 if (resultSet != null) {
524 resultSet.close();
525 }
526 if (dbAccessor != null) {
527 if (statement != null) {
528 dbAccessor.releaseStatement(statement, call.getSQLString(), call, this.session);
529 }
530 }
531 if (call.hasAllocatedConnection()) {
532 getExecutionSession().releaseConnectionAfterCall(this);
533 }
534 } catch (RuntimeException cleanupException) {
535 if (!exceptionOccured) {
536 throw cleanupException;
537 }
538 } catch (SQLException cleanupSQLException) {
539 if (!exceptionOccured) {
540 throw DatabaseException.sqlException(cleanupSQLException, call, dbAccessor, this.session, false);
541 }
542 }
543 }
544 } else {
545 List<AbstractRecord> rows;
546 if (sopObject != null) {
547 Object valuesIterator = this.containerPolicy.iteratorFor(getTranslationRow().getSopObject());
548 int size = this.containerPolicy.sizeFor(sopObject);
549 rows = new ArrayList<AbstractRecord>(size);
550 while (this.containerPolicy.hasNext(valuesIterator)) {
551 Object memberSopObject = this.containerPolicy.next(valuesIterator, this.session);
552 DatabaseRecord memberRow = new DatabaseRecord(0);
553 memberRow.setSopObject(memberSopObject);
529 } else {
530 result = this.containerPolicy.containerInstance();
531 this.descriptor.getObjectBuilder().buildObjectsFromResultSetInto(this, resultSet, call.getFields(), call.getFieldsArray(), result);
532 }
533 } catch (SQLException exception) {
534 exceptionOccured = true;
535 DatabaseException commException = dbAccessor.processExceptionForCommError(this.session, exception, call);
536 if (commException != null) {
537 throw commException;
538 }
539 throw DatabaseException.sqlException(exception, call, dbAccessor, this.session, false);
540 } finally {
541 try {
542 if (resultSet != null) {
543 resultSet.close();
544 }
545 if (dbAccessor != null) {
546 if (statement != null) {
547 dbAccessor.releaseStatement(statement, call.getSQLString(), call, this.session);
548 }
549 }
550 if (call.hasAllocatedConnection()) {
551 getExecutionSession().releaseConnectionAfterCall(this);
552 }
553 } catch (RuntimeException cleanupException) {
554 if (!exceptionOccured) {
555 throw cleanupException;
556 }
557 } catch (SQLException cleanupSQLException) {
558 if (!exceptionOccured) {
559 throw DatabaseException.sqlException(cleanupSQLException, call, dbAccessor, this.session, false);
560 }
561 }
562 }
563 } else {
564 List<AbstractRecord> rows;
565 if (sopObject != null) {
566 Object valuesIterator = this.containerPolicy.iteratorFor(getTranslationRow().getSopObject());
567 int size = this.containerPolicy.sizeFor(sopObject);
568 rows = new ArrayList<AbstractRecord>(size);
569 while (this.containerPolicy.hasNext(valuesIterator)) {
570 Object memberSopObject = this.containerPolicy.next(valuesIterator, this.session);
571 DatabaseRecord memberRow = new DatabaseRecord(0);
572 memberRow.setSopObject(memberSopObject);
554573 rows.add(memberRow);
555 }
556 this.executionTime = System.currentTimeMillis();
557 } else {
558 rows = getQueryMechanism().selectAllRows();
559 this.executionTime = System.currentTimeMillis();
560
561 // If using 1-m joins, must set all rows.
562 if (hasJoining() && this.joinedAttributeManager.isToManyJoin()) {
563 this.joinedAttributeManager.setDataResults(rows, this.session);
564 }
565 // Batch fetching in IN requires access to the rows to build the id array.
566 if ((this.batchFetchPolicy != null) && this.batchFetchPolicy.isIN()) {
567 this.batchFetchPolicy.setDataResults(rows);
568 }
569 }
570
571 if (this.session.isUnitOfWork()) {
574 }
575 this.executionTime = System.currentTimeMillis();
576 } else {
577 rows = getQueryMechanism().selectAllRows();
578 this.executionTime = System.currentTimeMillis();
579
580 // If using 1-m joins, must set all rows.
581 if (hasJoining() && this.joinedAttributeManager.isToManyJoin()) {
582 this.joinedAttributeManager.setDataResults(rows, this.session);
583 }
584 // Batch fetching in IN requires access to the rows to build the id array.
585 if ((this.batchFetchPolicy != null) && this.batchFetchPolicy.isIN()) {
586 this.batchFetchPolicy.setDataResults(rows);
587 }
588 }
589
590 if (this.session.isUnitOfWork()) {
572591 result = registerResultInUnitOfWork(rows, (UnitOfWorkImpl)this.session, this.translationRow, true);//
573 } else {
574 if (rows instanceof ThreadCursoredList) {
575 result = this.containerPolicy.containerInstance();
576 } else {
577 result = this.containerPolicy.containerInstance(rows.size());
578 }
579 this.descriptor.getObjectBuilder().buildObjectsInto(this, rows, result);
580 }
581
582 if (sopObject != null) {
583 if (!this.descriptor.getObjectBuilder().isSimple()) {
584 // remove sopObject so it's not stuck in any value holder.
585 for (AbstractRecord row : rows) {
586 row.setSopObject(null);
587 }
588 }
589 } else {
590 if (this.shouldIncludeData) {
591 ComplexQueryResult complexResult = new ComplexQueryResult();
592 complexResult.setResult(result);
593 complexResult.setData(rows);
594 result = complexResult;
595 }
596 }
597 }
598 }
599
600 // Add the other (already registered) results and return them.
601 if (this.descriptor.hasTablePerClassPolicy()) {
602 result = this.containerPolicy.concatenateContainers(
603 result, this.descriptor.getTablePerClassPolicy().selectAllObjectsUsingMultipleTableSubclassRead(this), this.session);
604 }
605
606 // If the results were empty, then ensure they get cached still.
607 if (shouldCacheQueryResults() && this.containerPolicy.isEmpty(result)) {
608 this.temporaryCachedQueryResults = InvalidObject.instance();
609 }
610
611 return result;
612 }
613
614 /**
615 * INTERNAL:
616 * Execute the query building the objects directly from the database result-set.
617 * @exception DatabaseException - an error has occurred on the database
618 * @return an ArrayList of the resulting objects.
619 */
620 @Override
621 protected Object executeObjectLevelReadQueryFromResultSet() throws DatabaseException {
622 AbstractSession session = this.session;
623 DatabasePlatform platform = session.getPlatform();
624 DatabaseCall call = ((DatasourceCallQueryMechanism)this.queryMechanism).selectResultSet();
625 Statement statement = call.getStatement();
626 ResultSet resultSet = call.getResult();
627 DatabaseAccessor accessor = (DatabaseAccessor)getAccessor();
628 boolean exceptionOccured = false;
629 try {
630 ResultSetMetaData metaData = resultSet.getMetaData();
631 List results = new ArrayList();
632 ObjectBuilder builder = this.descriptor.getObjectBuilder();
633 while (resultSet.next()) {
634 results.add(builder.buildObjectFromResultSet(this, this.joinedAttributeManager, resultSet, session, accessor, metaData, platform, call.getFields(), call.getFieldsArray()));
635 }
636 return results;
637 } catch (SQLException exception) {
638 exceptionOccured = true;
639 DatabaseException commException = accessor.processExceptionForCommError(session, exception, call);
640 if (commException != null) {
641 throw commException;
642 }
643 throw DatabaseException.sqlException(exception, call, accessor, session, false);
644 } finally {
645 try {
646 if (resultSet != null) {
647 resultSet.close();
648 }
649 if (statement != null) {
650 accessor.releaseStatement(statement, call.getSQLString(), call, session);
651 }
652 if (accessor != null) {
653 session.releaseReadConnection(accessor);
654 }
655 } catch (SQLException exception) {
656 if (!exceptionOccured) {
657 //in the case of an external connection pool the connection may be null after the statement release
658 // if it is null we will be unable to check the connection for a comm error and
659 //therefore must return as if it was not a comm error.
660 DatabaseException commException = accessor.processExceptionForCommError(session, exception, call);
661 if (commException != null) {
662 throw commException;
663 }
664 throw DatabaseException.sqlException(exception, call, accessor, session, false);
665 }
666 }
667 }
668 }
669
670 /**
671 * INTERNAL:
672 * Extract the correct query result from the transporter.
673 */
674 @Override
675 public Object extractRemoteResult(Transporter transporter) {
676 return ((DistributedSession)getSession()).getObjectsCorrespondingToAll(transporter.getObject(), transporter.getObjectDescriptors(), new IdentityHashMap(), this, getContainerPolicy());
677 }
678
679 /**
680 * INTERNAL:
681 * Return the query's container policy.
682 */
683 public ContainerPolicy getContainerPolicy() {
684 return containerPolicy;
685 }
686
687 /**
688 * INTERNAL:
689 * Returns the specific default redirector for this query type. There are numerous default query redirectors.
690 * See ClassDescriptor for their types.
691 */
692 @Override
693 protected QueryRedirector getDefaultRedirector() {
694 return descriptor.getDefaultReadAllQueryRedirector();
695 }
696
697 /**
698 * PUBLIC:
699 * @return Expression - the start with expression used to generated the hierarchical query clause in
700 * Oracle
701 */
702 public Expression getStartWithExpression() {
703 return startWithExpression;
704 }
705
706 /**
707 * PUBLIC:
708 * @return Expression - the connect by expression used to generate the hierarchical query caluse in Oracle
709 */
710 public Expression getConnectByExpression() {
711 return connectByExpression;
712 }
713
714 /**
715 * PUBLIC:
592 } else {
593 if (rows instanceof ThreadCursoredList) {
594 result = this.containerPolicy.containerInstance();
595 } else {
596 result = this.containerPolicy.containerInstance(rows.size());
597 }
598 this.descriptor.getObjectBuilder().buildObjectsInto(this, rows, result);
599 }
600
601 if (sopObject != null) {
602 if (!this.descriptor.getObjectBuilder().isSimple()) {
603 // remove sopObject so it's not stuck in any value holder.
604 for (AbstractRecord row : rows) {
605 row.setSopObject(null);
606 }
607 }
608 } else {
609 if (this.shouldIncludeData) {
610 ComplexQueryResult complexResult = new ComplexQueryResult();
611 complexResult.setResult(result);
612 complexResult.setData(rows);
613 result = complexResult;
614 }
615 }
616 }
617 }
618
619 // Add the other (already registered) results and return them.
620 if (this.descriptor.hasTablePerClassPolicy()) {
621 result = this.containerPolicy.concatenateContainers(
622 result, this.descriptor.getTablePerClassPolicy().selectAllObjectsUsingMultipleTableSubclassRead(this), this.session);
623 }
624
625 // If the results were empty, then ensure they get cached still.
626 if (shouldCacheQueryResults() && this.containerPolicy.isEmpty(result)) {
627 this.temporaryCachedQueryResults = InvalidObject.instance();
628 }
629
630 return result;
631 }
632
633 /**
634 * INTERNAL:
635 * Execute the query building the objects directly from the database result-set.
636 * @exception DatabaseException - an error has occurred on the database
637 * @return an ArrayList of the resulting objects.
638 */
639 @Override
640 protected Object executeObjectLevelReadQueryFromResultSet() throws DatabaseException {
641 AbstractSession session = this.session;
642 DatabasePlatform platform = session.getPlatform();
643 DatabaseCall call = ((DatasourceCallQueryMechanism)this.queryMechanism).selectResultSet();
644 Statement statement = call.getStatement();
645 ResultSet resultSet = call.getResult();
646 DatabaseAccessor accessor = (DatabaseAccessor)getAccessor();
647 boolean exceptionOccured = false;
648 try {
649 ResultSetMetaData metaData = resultSet.getMetaData();
650 List results = new ArrayList();
651 ObjectBuilder builder = this.descriptor.getObjectBuilder();
652 while (resultSet.next()) {
653 results.add(builder.buildObjectFromResultSet(this, this.joinedAttributeManager, resultSet, session, accessor, metaData, platform, call.getFields(), call.getFieldsArray()));
654 }
655 return results;
656 } catch (SQLException exception) {
657 exceptionOccured = true;
658 DatabaseException commException = accessor.processExceptionForCommError(session, exception, call);
659 if (commException != null) {
660 throw commException;
661 }
662 throw DatabaseException.sqlException(exception, call, accessor, session, false);
663 } finally {
664 try {
665 if (resultSet != null) {
666 resultSet.close();
667 }
668 if (statement != null) {
669 accessor.releaseStatement(statement, call.getSQLString(), call, session);
670 }
671 if (accessor != null) {
672 session.releaseReadConnection(accessor);
673 }
674 } catch (SQLException exception) {
675 if (!exceptionOccured) {
676 //in the case of an external connection pool the connection may be null after the statement release
677 // if it is null we will be unable to check the connection for a comm error and
678 //therefore must return as if it was not a comm error.
679 DatabaseException commException = accessor.processExceptionForCommError(session, exception, call);
680 if (commException != null) {
681 throw commException;
682 }
683 throw DatabaseException.sqlException(exception, call, accessor, session, false);
684 }
685 }
686 }
687 }
688
689 /**
690 * INTERNAL:
691 * Extract the correct query result from the transporter.
692 */
693 @Override
694 public Object extractRemoteResult(Transporter transporter) {
695 return ((DistributedSession)getSession()).getObjectsCorrespondingToAll(transporter.getObject(), transporter.getObjectDescriptors(), new IdentityHashMap(), this, getContainerPolicy());
696 }
697
698 /**
699 * INTERNAL:
700 * Return the query's container policy.
701 */
702 public ContainerPolicy getContainerPolicy() {
703 return containerPolicy;
704 }
705
706 /**
707 * INTERNAL:
708 * Returns the specific default redirector for this query type. There are numerous default query redirectors.
709 * See ClassDescriptor for their types.
710 */
711 @Override
712 protected QueryRedirector getDefaultRedirector() {
713 return descriptor.getDefaultReadAllQueryRedirector();
714 }
715
716 /**
717 * PUBLIC:
718 * @return Expression - the start with expression used to generated the hierarchical query clause in
719 * Oracle
720 */
721 public Expression getStartWithExpression() {
722 return startWithExpression;
723 }
724
725 /**
726 * PUBLIC:
727 * @return Expression - the connect by expression used to generate the hierarchical query caluse in Oracle
728 */
729 public Expression getConnectByExpression() {
730 return connectByExpression;
731 }
732
733 /**
734 * PUBLIC:
716735 * @return {@literal List<Expression>} - the ordering expressions used to generate the hierarchical query clause in Oracle
717 */
718 public List<Expression> getOrderSiblingsByExpressions() {
719 return orderSiblingsByExpressions;
720 }
721
722 /**
736 */
737 public List<Expression> getOrderSiblingsByExpressions() {
738 return orderSiblingsByExpressions;
739 }
740
741 /**
723742 * PUBLIC:
724743 * @return Direction - the direction in which the hierarchy is traversed
725744 */
728747 }
729748
730749 /**
731 * INTERNAL:
732 * Verify that we have hierarchical query expressions
733 */
734 public boolean hasHierarchicalExpressions() {
735 return ((this.startWithExpression != null) || (this.connectByExpression != null) || (this.orderSiblingsByExpressions != null));
736 }
737
738 /**
739 * INTERNAL:
740 * Return true if the query uses default properties.
741 * This is used to determine if this query is cacheable.
742 * i.e. does not use any properties that may conflict with another query
743 * with the same JPQL or selection criteria.
744 */
745 @Override
746 public boolean isDefaultPropertiesQuery() {
747 return super.isDefaultPropertiesQuery()
748 && (!hasBatchReadAttributes())
749 && (!hasHierarchicalExpressions())
750 && (!this.containerPolicy.isCursorPolicy());
751 }
752
753 /**
754 * INTERNAL:
755 * Return if the query is equal to the other.
756 * This is used to allow dynamic expression query SQL to be cached.
757 */
758 @Override
759 public boolean equals(Object object) {
760 if (this == object) {
761 return true;
762 }
763 if (!super.equals(object)) {
764 return false;
765 }
766 ReadAllQuery query = (ReadAllQuery) object;
767 if (!this.containerPolicy.equals(query.containerPolicy)) {
768 return false;
769 }
770 return true;
771 }
772
773 /**
774 * PUBLIC:
775 * Return if this is a read all query.
776 */
777 @Override
778 public boolean isReadAllQuery() {
779 return true;
780 }
781
782 /**
783 * INTERNAL:
784 * Prepare the receiver for execution in a session.
785 */
786 @Override
787 protected void prepare() throws QueryException {
788 if ((!isReportQuery()) && prepareFromCachedQuery()) {
789 return;
790 }
791 super.prepare();
792
793 this.containerPolicy.prepare(this, getSession());
794
795 if (hasJoining() && isExpressionQuery()) {
796 // 1-m join fetching with pagination requires an order by.
797 if (this.joinedAttributeManager.isToManyJoin()
798 && ((this.maxRows > 0) || (this.firstResult > 0) || this.containerPolicy.isCursorPolicy())) {
799 if (!hasOrderByExpressions()) {
800 for (DatabaseField primaryKey : this.descriptor.getPrimaryKeyFields()) {
801 addOrdering(getExpressionBuilder().getField(primaryKey));
802 }
803 }
804 }
805 }
806
807 if (this.containerPolicy.overridesRead()) {
808 return;
809 }
810
811 if (this.descriptor.isDescriptorForInterface()) {
812 return;
813 }
814
815 prepareSelectAllRows();
816
817 if (!isReportQuery()) {
818 // should be called after prepareSelectRow so that the call knows whether it returns ResultSet
819 prepareResultSetAccessOptimization();
820 }
821 }
822
823 /**
824 * INTERNAL:
825 * Prepare the query from the prepared query.
826 * This allows a dynamic query to prepare itself directly from a prepared query instance.
827 * This is used in the JPQL parse cache to allow preparsed queries to be used to prepare
828 * dynamic queries.
829 * This only copies over properties that are configured through JPQL.
830 */
831 @Override
832 public void prepareFromQuery(DatabaseQuery query) {
833 super.prepareFromQuery(query);
834 if (query.isReadAllQuery()) {
835 ReadAllQuery readQuery = (ReadAllQuery)query;
836 this.containerPolicy = readQuery.containerPolicy;
837 if (readQuery.hasHierarchicalExpressions()) {
838 this.orderSiblingsByExpressions = readQuery.orderSiblingsByExpressions;
839 this.connectByExpression = readQuery.connectByExpression;
840 this.startWithExpression = readQuery.startWithExpression;
841 }
842 }
843 }
844
845 /**
846 * INTERNAL:
847 * Set the properties needed to be cascaded into the custom query.
848 */
849 @Override
850 protected void prepareCustomQuery(DatabaseQuery customQuery) {
851 super.prepareCustomQuery(customQuery);
852 ReadAllQuery customReadQuery = (ReadAllQuery)customQuery;
853 customReadQuery.containerPolicy = this.containerPolicy;
854 customReadQuery.cascadePolicy = this.cascadePolicy;
855 customReadQuery.shouldRefreshIdentityMapResult = this.shouldRefreshIdentityMapResult;
856 customReadQuery.shouldMaintainCache = this.shouldMaintainCache;
857 customReadQuery.shouldUseWrapperPolicy = this.shouldUseWrapperPolicy;
858 }
859
860 /**
861 * INTERNAL:
862 * Prepare the receiver for execution in a session.
863 */
864 @Override
865 public void prepareForExecution() throws QueryException {
866 super.prepareForExecution();
867
868 this.containerPolicy.prepareForExecution();
750 * INTERNAL:
751 * Verify that we have hierarchical query expressions
752 */
753 public boolean hasHierarchicalExpressions() {
754 return ((this.startWithExpression != null) || (this.connectByExpression != null) || (this.orderSiblingsByExpressions != null));
755 }
756
757 /**
758 * INTERNAL:
759 * Return true if the query uses default properties.
760 * This is used to determine if this query is cacheable.
761 * i.e. does not use any properties that may conflict with another query
762 * with the same JPQL or selection criteria.
763 */
764 @Override
765 public boolean isDefaultPropertiesQuery() {
766 return super.isDefaultPropertiesQuery()
767 && (!hasBatchReadAttributes())
768 && (!hasHierarchicalExpressions())
769 && (!this.containerPolicy.isCursorPolicy());
770 }
771
772 /**
773 * INTERNAL:
774 * Return if the query is equal to the other.
775 * This is used to allow dynamic expression query SQL to be cached.
776 */
777 @Override
778 public boolean equals(Object object) {
779 if (this == object) {
780 return true;
781 }
782 if (!super.equals(object)) {
783 return false;
784 }
785 ReadAllQuery query = (ReadAllQuery) object;
786 if (!this.containerPolicy.equals(query.containerPolicy)) {
787 return false;
788 }
789 return true;
790 }
791
792 /**
793 * PUBLIC:
794 * Return if this is a read all query.
795 */
796 @Override
797 public boolean isReadAllQuery() {
798 return true;
799 }
800
801 /**
802 * INTERNAL:
803 * Prepare the receiver for execution in a session.
804 */
805 @Override
806 protected void prepare() throws QueryException {
807 if ((!isReportQuery()) && prepareFromCachedQuery()) {
808 return;
809 }
810 super.prepare();
811
812 this.containerPolicy.prepare(this, getSession());
813
814 if (hasJoining() && isExpressionQuery()) {
815 // 1-m join fetching with pagination requires an order by.
816 if (this.joinedAttributeManager.isToManyJoin()
817 && ((this.maxRows > 0) || (this.firstResult > 0) || this.containerPolicy.isCursorPolicy())) {
818 if (!hasOrderByExpressions()) {
819 for (DatabaseField primaryKey : this.descriptor.getPrimaryKeyFields()) {
820 addOrdering(getExpressionBuilder().getField(primaryKey));
821 }
822 }
823 }
824 }
825
826 if (this.containerPolicy.overridesRead()) {
827 return;
828 }
829
830 if (this.descriptor.isDescriptorForInterface()) {
831 return;
832 }
833
834 prepareSelectAllRows();
835
836 if (!isReportQuery()) {
837 // should be called after prepareSelectRow so that the call knows whether it returns ResultSet
838 prepareResultSetAccessOptimization();
839 }
840 }
841
842 /**
843 * INTERNAL:
844 * Prepare the query from the prepared query.
845 * This allows a dynamic query to prepare itself directly from a prepared query instance.
846 * This is used in the JPQL parse cache to allow preparsed queries to be used to prepare
847 * dynamic queries.
848 * This only copies over properties that are configured through JPQL.
849 */
850 @Override
851 public void prepareFromQuery(DatabaseQuery query) {
852 super.prepareFromQuery(query);
853 if (query.isReadAllQuery()) {
854 ReadAllQuery readQuery = (ReadAllQuery)query;
855 this.containerPolicy = readQuery.containerPolicy;
856 if (readQuery.hasHierarchicalExpressions()) {
857 this.orderSiblingsByExpressions = readQuery.orderSiblingsByExpressions;
858 this.connectByExpression = readQuery.connectByExpression;
859 this.startWithExpression = readQuery.startWithExpression;
860 }
861 }
862 }
863
864 /**
865 * INTERNAL:
866 * Set the properties needed to be cascaded into the custom query.
867 */
868 @Override
869 protected void prepareCustomQuery(DatabaseQuery customQuery) {
870 super.prepareCustomQuery(customQuery);
871 ReadAllQuery customReadQuery = (ReadAllQuery)customQuery;
872 customReadQuery.containerPolicy = this.containerPolicy;
873 customReadQuery.cascadePolicy = this.cascadePolicy;
874 customReadQuery.shouldRefreshIdentityMapResult = this.shouldRefreshIdentityMapResult;
875 customReadQuery.shouldMaintainCache = this.shouldMaintainCache;
876 customReadQuery.shouldUseWrapperPolicy = this.shouldUseWrapperPolicy;
877 }
878
879 /**
880 * INTERNAL:
881 * Prepare the receiver for execution in a session.
882 */
883 @Override
884 public void prepareForExecution() throws QueryException {
885 super.prepareForExecution();
886
887 this.containerPolicy.prepareForExecution();
869888
870889 // Modifying the translation row here will modify it on the original
871 // query which is not good. So we have to clone the translation row if
872 // we are going to append tenant discriminator fields to it.
873 if (descriptor.hasMultitenantPolicy()) {
874 translationRow = translationRow.clone();
875 descriptor.getMultitenantPolicy().addFieldsToRow(translationRow, getSession());
876 }
877 }
878
879 /**
880 * INTERNAL:
881 * Prepare the mechanism.
882 */
883 protected void prepareSelectAllRows() {
884 getQueryMechanism().prepareSelectAllRows();
885 }
886
887 /**
888 * INTERNAL:
889 * All objects queried via a UnitOfWork get registered here. If the query
890 * went to the database.
891 * <p>
892 * Involves registering the query result individually and in totality, and
893 * hence refreshing / conforming is done here.
894 *
895 * @param result may be collection (read all) or an object (read one),
896 * or even a cursor. If in transaction the shared cache will
897 * be bypassed, meaning the result may not be originals from the parent
898 * but raw database rows.
899 * @param unitOfWork the unitOfWork the result is being registered in.
900 * @param arguments the original arguments/parameters passed to the query
901 * execution. Used by conforming
902 * @param buildDirectlyFromRows If in transaction must construct
903 * a registered result from raw database rows.
904 *
905 * @return the final (conformed, refreshed, wrapped) UnitOfWork query result
906 */
907 @Override
908 public Object registerResultInUnitOfWork(Object result, UnitOfWorkImpl unitOfWork, AbstractRecord arguments, boolean buildDirectlyFromRows) {
909 // For bug 2612366: Conforming results in UOW extremely slow.
890 // query which is not good. So we have to clone the translation row if
891 // we are going to append tenant discriminator fields to it.
892 if (descriptor.hasMultitenantPolicy()) {
893 translationRow = translationRow.clone();
894 descriptor.getMultitenantPolicy().addFieldsToRow(translationRow, getSession());
895 }
896 }
897
898 /**
899 * INTERNAL:
900 * Prepare the mechanism.
901 */
902 protected void prepareSelectAllRows() {
903 getQueryMechanism().prepareSelectAllRows();
904 }
905
906 /**
907 * INTERNAL:
908 * All objects queried via a UnitOfWork get registered here. If the query
909 * went to the database.
910 * <p>
911 * Involves registering the query result individually and in totality, and
912 * hence refreshing / conforming is done here.
913 *
914 * @param result may be collection (read all) or an object (read one),
915 * or even a cursor. If in transaction the shared cache will
916 * be bypassed, meaning the result may not be originals from the parent
917 * but raw database rows.
918 * @param unitOfWork the unitOfWork the result is being registered in.
919 * @param arguments the original arguments/parameters passed to the query
920 * execution. Used by conforming
921 * @param buildDirectlyFromRows If in transaction must construct
922 * a registered result from raw database rows.
923 *
924 * @return the final (conformed, refreshed, wrapped) UnitOfWork query result
925 */
926 @Override
927 public Object registerResultInUnitOfWork(Object result, UnitOfWorkImpl unitOfWork, AbstractRecord arguments, boolean buildDirectlyFromRows) {
928 // For bug 2612366: Conforming results in UOW extremely slow.
910929 // Replacing results with registered versions in the UOW is a part of
911 // conforming and is now done while conforming to maximize performance.
912 if (unitOfWork.hasCloneMapping() // PERF: Avoid conforming empty uow.
913 && (shouldConformResultsInUnitOfWork() || this.descriptor.shouldAlwaysConformResultsInUnitOfWork())) {
914 return conformResult(result, unitOfWork, arguments, buildDirectlyFromRows);
915 }
916
917 // When building directly from rows, one of the performance benefits
918 // is that we no longer have to wrap and then unwrap the originals.
919 // result is just a vector, not a collection of wrapped originals.
920 // Also for cursors the initial connection is automatically registered.
921 if (buildDirectlyFromRows) {
922 List<AbstractRecord> rows = (List<AbstractRecord>)result;
923 ContainerPolicy cp = this.containerPolicy;
924 int size = rows.size();
925 Object clones = cp.containerInstance(size);
926 if(cp.shouldAddAll()) {
927 List clonesIn = new ArrayList(size);
928 List<AbstractRecord> rowsIn = new ArrayList(size);
929 for (int index = 0; index < size; index++) {
930 AbstractRecord row = rows.get(index);
931
932 // null is placed in the row collection for 1-m joining to filter duplicate rows.
933 if (row != null) {
934 Object clone = buildObject(row);
935 clonesIn.add(clone);
936 rowsIn.add(row);
937 }
938 }
939 cp.addAll(clonesIn, clones, unitOfWork, rowsIn, this, null, true);
940 } else {
941 boolean quickAdd = (clones instanceof Collection) && !this.descriptor.getObjectBuilder().hasWrapperPolicy();
942 if (this.descriptor.getCachePolicy().shouldPrefetchCacheKeys()
930 // conforming and is now done while conforming to maximize performance.
931 if (unitOfWork.hasCloneMapping() // PERF: Avoid conforming empty uow.
932 && (shouldConformResultsInUnitOfWork() || this.descriptor.shouldAlwaysConformResultsInUnitOfWork())) {
933 return conformResult(result, unitOfWork, arguments, buildDirectlyFromRows);
934 }
935
936 // When building directly from rows, one of the performance benefits
937 // is that we no longer have to wrap and then unwrap the originals.
938 // result is just a vector, not a collection of wrapped originals.
939 // Also for cursors the initial connection is automatically registered.
940 if (buildDirectlyFromRows) {
941 List<AbstractRecord> rows = (List<AbstractRecord>)result;
942 ContainerPolicy cp = this.containerPolicy;
943 int size = rows.size();
944 Object clones = cp.containerInstance(size);
945 if(cp.shouldAddAll()) {
946 List clonesIn = new ArrayList(size);
947 List<AbstractRecord> rowsIn = new ArrayList(size);
948 for (int index = 0; index < size; index++) {
949 AbstractRecord row = rows.get(index);
950
951 // null is placed in the row collection for 1-m joining to filter duplicate rows.
952 if (row != null) {
953 Object clone = buildObject(row);
954 clonesIn.add(clone);
955 rowsIn.add(row);
956 }
957 }
958 cp.addAll(clonesIn, clones, unitOfWork, rowsIn, this, null, true);
959 } else {
960 boolean quickAdd = (clones instanceof Collection) && !this.descriptor.getObjectBuilder().hasWrapperPolicy();
961 if (this.descriptor.getCachePolicy().shouldPrefetchCacheKeys()
943962 && shouldMaintainCache()
944 && ! shouldRetrieveBypassCache()
945 && ((!(unitOfWork.hasCommitManager() && unitOfWork.getCommitManager().isActive())
946 && ! unitOfWork.wasTransactionBegunPrematurely()
947 && !this.descriptor.getCachePolicy().shouldIsolateObjectsInUnitOfWork()
948 && ! this.descriptor.getCachePolicy().shouldIsolateProtectedObjectsInUnitOfWork())
949 || (unitOfWork.isClassReadOnly(this.getReferenceClass(), this.getDescriptor())))){
950 Object[] pkList = new Object[size];
951 for (int i = 0; i< size; ++i){
952 pkList[i] = getDescriptor().getObjectBuilder().extractPrimaryKeyFromRow(rows.get(i), session);
953 }
954 setPrefetchedCacheKeys(unitOfWork.getParentIdentityMapSession(this).getIdentityMapAccessorInstance().getAllCacheKeysFromIdentityMapWithEntityPK(pkList, descriptor));
955 }
956 for (int index = 0; index < size; index++) {
957 AbstractRecord row = rows.get(index);
958
959 // null is placed in the row collection for 1-m joining to filter duplicate rows.
960 if (row != null) {
961 Object clone = buildObject(row);
962 if (quickAdd) {
963 ((Collection)clones).add(clone);
964 } else {
965 cp.addInto(clone, clones, unitOfWork, row, this, null, true);
966 }
967 }
968 }
969 }
970 return clones;
971 }
972
973 ContainerPolicy cp;
974 Cursor cursor = null;
975
976 // If the query is redirected then the collection returned might no longer
977 // correspond to the original container policy. CR#2342-S.M.
978 if (getRedirector() != null) {
979 cp = ContainerPolicy.buildPolicyFor(result.getClass());
980 } else {
981 cp = this.containerPolicy;
982 }
983
984 // In the case of cursors just register the initially read collection.
985 if (cp.isCursorPolicy()) {
986 cursor = (Cursor)result;
987 // In nested UnitOfWork session might have been session of the parent.
988 cursor.setSession(unitOfWork);
989 cp = ContainerPolicy.buildPolicyFor(ClassConstants.Vector_class);
990 result = cursor.getObjectCollection();
991 }
992
993 Object clones = cp.containerInstance(cp.sizeFor(result));
994 AbstractSession sessionToUse = unitOfWork.getParent();
995 for (Object iter = cp.iteratorFor(result); cp.hasNext(iter);) {
996 Object object = cp.next(iter, sessionToUse);
997 Object clone = registerIndividualResult(object, null, unitOfWork, this.joinedAttributeManager, null);
998 cp.addInto(clone, clones, unitOfWork);
999 }
1000 if (cursor != null) {
1001 cursor.setObjectCollection((Vector)clones);
1002 return cursor;
1003 } else {
1004 return clones;
1005 }
1006 }
1007
1008 /**
1009 * INTERNAL:
1010 * Version of the previous method for ResultSet optimization.
1011 *
1012 * @return the final (conformed, refreshed, wrapped) UnitOfWork query result
1013 */
1014 public Object registerResultSetInUnitOfWork(ResultSet resultSet, Vector fields, DatabaseField[] fieldsArray, UnitOfWorkImpl unitOfWork, AbstractRecord arguments) throws SQLException {
1015 // TODO: add support for Conforming results in UOW - currently conforming in uow is not compatible with ResultSet optimization.
1016
1017 ContainerPolicy cp = this.containerPolicy;
1018 Object clones = cp.containerInstance();
1019 ResultSetMetaData metaData = resultSet.getMetaData();
1020 boolean hasNext = resultSet.next();
1021 if (hasNext) {
963 && ! shouldRetrieveBypassCache()
964 && ((!(unitOfWork.hasCommitManager() && unitOfWork.getCommitManager().isActive())
965 && ! unitOfWork.wasTransactionBegunPrematurely()
966 && !this.descriptor.getCachePolicy().shouldIsolateObjectsInUnitOfWork()
967 && ! this.descriptor.getCachePolicy().shouldIsolateProtectedObjectsInUnitOfWork())
968 || (unitOfWork.isClassReadOnly(this.getReferenceClass(), this.getDescriptor())))){
969 Object[] pkList = new Object[size];
970 for (int i = 0; i< size; ++i){
971 pkList[i] = getDescriptor().getObjectBuilder().extractPrimaryKeyFromRow(rows.get(i), session);
972 }
973 setPrefetchedCacheKeys(unitOfWork.getParentIdentityMapSession(this).getIdentityMapAccessorInstance().getAllCacheKeysFromIdentityMapWithEntityPK(pkList, descriptor));
974 }
975 for (int index = 0; index < size; index++) {
976 AbstractRecord row = rows.get(index);
977
978 // null is placed in the row collection for 1-m joining to filter duplicate rows.
979 if (row != null) {
980 Object clone = buildObject(row);
981 if (quickAdd) {
982 ((Collection)clones).add(clone);
983 } else {
984 cp.addInto(clone, clones, unitOfWork, row, this, null, true);
985 }
986 }
987 }
988 }
989 return clones;
990 }
991
992 ContainerPolicy cp;
993 Cursor cursor = null;
994
995 // If the query is redirected then the collection returned might no longer
996 // correspond to the original container policy. CR#2342-S.M.
997 if (getRedirector() != null) {
998 cp = ContainerPolicy.buildPolicyFor(result.getClass());
999 } else {
1000 cp = this.containerPolicy;
1001 }
1002
1003 // In the case of cursors just register the initially read collection.
1004 if (cp.isCursorPolicy()) {
1005 cursor = (Cursor)result;
1006 // In nested UnitOfWork session might have been session of the parent.
1007 cursor.setSession(unitOfWork);
1008 cp = ContainerPolicy.buildPolicyFor(ClassConstants.Vector_class);
1009 result = cursor.getObjectCollection();
1010 }
1011
1012 Object clones = cp.containerInstance(cp.sizeFor(result));
1013 AbstractSession sessionToUse = unitOfWork.getParent();
1014 for (Object iter = cp.iteratorFor(result); cp.hasNext(iter);) {
1015 Object object = cp.next(iter, sessionToUse);
1016 Object clone = registerIndividualResult(object, null, unitOfWork, this.joinedAttributeManager, null);
1017 cp.addInto(clone, clones, unitOfWork);
1018 }
1019 if (cursor != null) {
1020 cursor.setObjectCollection((Vector)clones);
1021 return cursor;
1022 } else {
1023 return clones;
1024 }
1025 }
1026
1027 /**
1028 * INTERNAL:
1029 * Version of the previous method for ResultSet optimization.
1030 *
1031 * @return the final (conformed, refreshed, wrapped) UnitOfWork query result
1032 */
1033 public Object registerResultSetInUnitOfWork(ResultSet resultSet, Vector fields, DatabaseField[] fieldsArray, UnitOfWorkImpl unitOfWork, AbstractRecord arguments) throws SQLException {
1034 // TODO: add support for Conforming results in UOW - currently conforming in uow is not compatible with ResultSet optimization.
1035
1036 ContainerPolicy cp = this.containerPolicy;
1037 Object clones = cp.containerInstance();
1038 ResultSetMetaData metaData = resultSet.getMetaData();
1039 boolean hasNext = resultSet.next();
1040 if (hasNext) {
10221041 // TODO: possibly add support for SortedListContainerPolicy (cp.shouldAddAll() == true) - this policy currently is not compatible with ResultSet optimization
1023 boolean quickAdd = (clones instanceof Collection) && !this.descriptor.getObjectBuilder().hasWrapperPolicy();
1024 DatabaseAccessor dbAccessor = (DatabaseAccessor)getAccessor();
1042 boolean quickAdd = (clones instanceof Collection) && !this.descriptor.getObjectBuilder().hasWrapperPolicy();
1043 DatabaseAccessor dbAccessor = (DatabaseAccessor)getAccessor();
10251044 boolean useSimple = this.descriptor.getObjectBuilder().isSimple();
1026 AbstractSession executionSession = getExecutionSession();
1027 DatabasePlatform platform = dbAccessor.getPlatform();
1028 boolean optimizeData = platform.shouldOptimizeDataConversion();
1029 if (useSimple) {
1030 // None of the fields are relational - the row could be reused, just clear all the values.
1031 SimpleResultSetRecord row = new SimpleResultSetRecord(fields, fieldsArray, resultSet, metaData, dbAccessor, executionSession, platform, optimizeData);
1032 if (this.descriptor.isDescriptorTypeAggregate()) {
1033 // Aggregate Collection may have an unmapped primary key referencing the owner, the corresponding field will not be used when the object is populated and therefore may not be cleared.
1034 row.setShouldKeepValues(true);
1035 }
1036 while (hasNext) {
1037 Object clone = buildObject(row);
1038 if (quickAdd) {
1039 ((Collection)clones).add(clone);
1040 } else {
1041 // TODO: investigate is it possible to support MappedKeyMapPolicy - this policy currently is not compatible with ResultSet optimization
1045 AbstractSession executionSession = getExecutionSession();
1046 DatabasePlatform platform = dbAccessor.getPlatform();
1047 boolean optimizeData = platform.shouldOptimizeDataConversion();
1048 if (useSimple) {
1049 // None of the fields are relational - the row could be reused, just clear all the values.
1050 SimpleResultSetRecord row = new SimpleResultSetRecord(fields, fieldsArray, resultSet, metaData, dbAccessor, executionSession, platform, optimizeData);
1051 if (this.descriptor.isDescriptorTypeAggregate()) {
1052 // Aggregate Collection may have an unmapped primary key referencing the owner, the corresponding field will not be used when the object is populated and therefore may not be cleared.
1053 row.setShouldKeepValues(true);
1054 }
1055 while (hasNext) {
1056 Object clone = buildObject(row);
1057 if (quickAdd) {
1058 ((Collection)clones).add(clone);
1059 } else {
1060 // TODO: investigate is it possible to support MappedKeyMapPolicy - this policy currently is not compatible with ResultSet optimization
10421061 cp.addInto(clone, clones, unitOfWork);
1043 }
1062 }
10441063 row.reset();
10451064 hasNext = resultSet.next();
1046 }
1047 } else {
1048 boolean shouldKeepRow = this.descriptor.getObjectBuilder().shouldKeepRow();
1049 while (hasNext) {
1050 ResultSetRecord row = new ResultSetRecord(fields, fieldsArray, resultSet, metaData, dbAccessor, executionSession, platform, optimizeData);
1051 Object clone = buildObject(row);
1052 if (quickAdd) {
1053 ((Collection)clones).add(clone);
1054 } else {
1055 // TODO: investigate is it possible to support MappedKeyMapPolicy - this policy currently is not compatible with ResultSet optimization
1056 cp.addInto(clone, clones, unitOfWork);
1057 }
1058
1059 if (shouldKeepRow) {
1060 if (row.hasResultSet()) {
1065 }
1066 } else {
1067 boolean shouldKeepRow = this.descriptor.getObjectBuilder().shouldKeepRow();
1068 while (hasNext) {
1069 ResultSetRecord row = new ResultSetRecord(fields, fieldsArray, resultSet, metaData, dbAccessor, executionSession, platform, optimizeData);
1070 Object clone = buildObject(row);
1071 if (quickAdd) {
1072 ((Collection)clones).add(clone);
1073 } else {
1074 // TODO: investigate is it possible to support MappedKeyMapPolicy - this policy currently is not compatible with ResultSet optimization
1075 cp.addInto(clone, clones, unitOfWork);
1076 }
1077
1078 if (shouldKeepRow) {
1079 if (row.hasResultSet()) {
10611080 // ResultSet has not been fully triggered - that means the cached object was used.
1062 // Yet the row still may be cached in a value holder (see loadBatchReadAttributes and loadJoinedAttributes methods).
1063 // Remove ResultSet to avoid attempt to trigger it (already closed) when pk or fk values (already extracted) accessed when the value holder is instantiated.
1064 row.removeResultSet();
1065 } else {
1066 row.removeNonIndirectionValues();
1067 }
1068 }
1081 // Yet the row still may be cached in a value holder (see loadBatchReadAttributes and loadJoinedAttributes methods).
1082 // Remove ResultSet to avoid attempt to trigger it (already closed) when pk or fk values (already extracted) accessed when the value holder is instantiated.
1083 row.removeResultSet();
1084 } else {
1085 row.removeNonIndirectionValues();
1086 }
1087 }
10691088 hasNext = resultSet.next();
1070 }
1071 }
1072 }
1073 return clones;
1074 }
1075
1076 /**
1077 * INTERNAL:
1078 * Execute the query through remote session.
1079 */
1080 @Override
1081 public Object remoteExecute() {
1082 if (this.containerPolicy.overridesRead()) {
1083 return this.containerPolicy.remoteExecute();
1084 }
1085
1086 Object cacheHit = checkEarlyReturn(this.session, this.translationRow);
1087 if (cacheHit != null) {
1088 return cacheHit;
1089 }
1090
1091 return super.remoteExecute();
1092 }
1093
1094 /**
1095 * INTERNAL:
1096 * replace the value holders in the specified result object(s)
1097 */
1098 @Override
1099 public Map replaceValueHoldersIn(Object object, RemoteSessionController controller) {
1100 return controller.replaceValueHoldersInAll(object, getContainerPolicy());
1101 }
1102
1103 /**
1104 * PUBLIC:
1105 * Set the container policy. Used to support different containers
1106 * (e.g. Collections, Maps).
1107 */
1108 public void setContainerPolicy(ContainerPolicy containerPolicy) {
1109 // CR#... a container policy is always required, default is vector,
1110 // required for deployment XML.
1111 if (containerPolicy == null) {
1112 return;
1113 }
1114 this.containerPolicy = containerPolicy;
1115 setIsPrepared(false);
1116 }
1117
1118 /**
1119 * PUBLIC:
1120 * Set the Hierarchical Query Clause for the query
1121 * <p>Example:
1122 * <p>Expression startWith = builder.get("id").equal(new Integer(100)); //can be any expression which identifies a set of employees
1123 * <p>Expression connectBy = builder.get("managedEmployees"); //indicated the relationship that the hierarchy is based on, must be self-referential
1124 * <p>Vector orderBy = new Vector();
1125 * <p>orderBy.addElement(builder.get("startDate"));
1126 * <p>readAllQuery.setHierarchicalQueryClause(startWith, connectBy, orderBy);
1127 *
1128 * <p>This query would generate SQL like this:
1129 * <p>SELECT * FROM EMPLOYEE START WITH ID=100 CONNECT BY PRIOR ID = MANAGER_ID ORDER SIBLINGS BY START_DATE
1089 }
1090 }
1091 }
1092 return clones;
1093 }
1094
1095 /**
1096 * INTERNAL:
1097 * Execute the query through remote session.
1098 */
1099 @Override
1100 public Object remoteExecute() {
1101 if (this.containerPolicy.overridesRead()) {
1102 return this.containerPolicy.remoteExecute();
1103 }
1104
1105 Object cacheHit = checkEarlyReturn(this.session, this.translationRow);
1106 if (cacheHit != null) {
1107 return cacheHit;
1108 }
1109
1110 return super.remoteExecute();
1111 }
1112
1113 /**
1114 * INTERNAL:
1115 * replace the value holders in the specified result object(s)
1116 */
1117 @Override
1118 public Map replaceValueHoldersIn(Object object, RemoteSessionController controller) {
1119 return controller.replaceValueHoldersInAll(object, getContainerPolicy());
1120 }
1121
1122 /**
1123 * PUBLIC:
1124 * Set the container policy. Used to support different containers
1125 * (e.g. Collections, Maps).
1126 */
1127 public void setContainerPolicy(ContainerPolicy containerPolicy) {
1128 // CR#... a container policy is always required, default is vector,
1129 // required for deployment XML.
1130 if (containerPolicy == null) {
1131 return;
1132 }
1133 this.containerPolicy = containerPolicy;
1134 setIsPrepared(false);
1135 }
1136
1137 /**
1138 * PUBLIC:
1139 * Set the Hierarchical Query Clause for the query
1140 * <p>Example:
1141 * <p>Expression startWith = builder.get("id").equal(new Integer(100)); //can be any expression which identifies a set of employees
1142 * <p>Expression connectBy = builder.get("managedEmployees"); //indicated the relationship that the hierarchy is based on, must be self-referential
1143 * <p>Vector orderBy = new Vector();
1144 * <p>orderBy.addElement(builder.get("startDate"));
1145 * <p>readAllQuery.setHierarchicalQueryClause(startWith, connectBy, orderBy);
11301146 *
1131 * @param startWith Describes the START WITH clause of the query - null if not needed
1132 * @param connectBy This should be a query key expression which indicates an attribute who's mapping describes the hierarchy
1133 * @param orderSiblingsExpressions Contains expressions which indicate fields to be included in the ORDER SIBLINGS BY clause - null if not required
1134 */
1135 public void setHierarchicalQueryClause(Expression startWith, Expression connectBy, List<Expression> orderSiblingsExpressions) {
1147 * <p>This query would generate SQL like this:
1148 * <p>SELECT * FROM EMPLOYEE START WITH ID=100 CONNECT BY PRIOR ID = MANAGER_ID ORDER SIBLINGS BY START_DATE
1149 *
1150 * @param startWith Describes the START WITH clause of the query - null if not needed
1151 * @param connectBy This should be a query key expression which indicates an attribute who's mapping describes the hierarchy
1152 * @param orderSiblingsExpressions Contains expressions which indicate fields to be included in the ORDER SIBLINGS BY clause - null if not required
1153 */
1154 public void setHierarchicalQueryClause(Expression startWith, Expression connectBy, List<Expression> orderSiblingsExpressions) {
11361155 setHierarchicalQueryClause(startWith, connectBy, orderSiblingsExpressions, null);
11371156 }
11381157
11721191 * and PARENT_TO_CHILD is used for collections
11731192 */
11741193 public void setHierarchicalQueryClause(Expression startWith, Expression connectBy, List<Expression> orderSiblingsExpressions, Direction direction) {
1175 this.startWithExpression = startWith;
1176 this.connectByExpression = connectBy;
1177 this.orderSiblingsByExpressions = orderSiblingsExpressions;
1194 this.startWithExpression = startWith;
1195 this.connectByExpression = connectBy;
1196 this.orderSiblingsByExpressions = orderSiblingsExpressions;
11781197 this.direction = direction;
1179 setIsPrepared(false);
1180 }
1181
1182 /**
1183 * PUBLIC:
1184 * Configure the mapping to use an instance of the specified container class
1185 * to hold the target objects.
1186 * <p>jdk1.2.x: The container class must implement (directly or indirectly) the Collection interface.
1187 * <p>jdk1.1.x: The container class must be a subclass of Vector.
1188 */
1189 public void useCollectionClass(Class concreteClass) {
1190 // Set container policy.
1191 setContainerPolicy(ContainerPolicy.buildPolicyFor(concreteClass));
1192
1193 }
1194
1195 /**
1196 * PUBLIC:
1197 * Use a CursoredStream as the result collection.
1198 * The initial read size is 10 and page size is 5.
1199 */
1200 public void useCursoredStream() {
1201 useCursoredStream(10, 5);
1202 }
1203
1204 /**
1205 * PUBLIC:
1206 * Use a CursoredStream as the result collection.
1207 * @param initialReadSize the initial number of objects to read
1208 * @param pageSize the number of objects to read when more objects
1209 * are needed from the database
1210 */
1211 public void useCursoredStream(int initialReadSize, int pageSize) {
1212 setContainerPolicy(new CursoredStreamPolicy(this, initialReadSize, pageSize));
1213 }
1214
1215 /**
1216 * PUBLIC:
1217 * Use a CursoredStream as the result collection.
1218 * @param initialReadSize the initial number of objects to read
1219 * @param pageSize the number of objects to read when more objects
1220 * are needed from the database
1221 * @param sizeQuery a query that will return the size of the result set;
1222 * this must be set if an expression is not used (i.e. custom SQL)
1223 */
1224 public void useCursoredStream(int initialReadSize, int pageSize, ValueReadQuery sizeQuery) {
1225 setContainerPolicy(new CursoredStreamPolicy(this, initialReadSize, pageSize, sizeQuery));
1226 }
1227
1228 /**
1229 * PUBLIC:
1230 * Configure the query to use an instance of the specified container class
1231 * to hold the result objects. The key used to index the value in the Map
1232 * is the value returned by a call to the specified zero-argument method.
1233 * The method must be implemented by the class (or a superclass) of the
1234 * value to be inserted into the Map.
1235 * <p>jdk1.2.x: The container class must implement (directly or indirectly) the Map interface.
1236 * <p>jdk1.1.x: The container class must be a subclass of Hashtable.
1237 * <p>The referenceClass must set before calling this method.
1238 */
1239 public void useMapClass(Class concreteClass, String methodName) {
1240 // the reference class has to be specified before coming here
1241 if (getReferenceClass() == null) {
1242 throw QueryException.referenceClassMissing(this);
1243 }
1244 ContainerPolicy policy = ContainerPolicy.buildPolicyFor(concreteClass);
1245 policy.setKeyName(methodName, getReferenceClass().getName());
1246 setContainerPolicy(policy);
1247 }
1248
1249 /**
1250 * PUBLIC:
1251 * Use a ScrollableCursor as the result collection.
1252 */
1253 public void useScrollableCursor() {
1254 useScrollableCursor(10);
1255 }
1256
1257 /**
1258 * PUBLIC:
1259 * Use a ScrollableCursor as the result collection.
1260 * @param pageSize the number of elements to be read into a the cursor
1261 * when more elements are needed from the database.
1262 */
1263 public void useScrollableCursor(int pageSize) {
1264 setContainerPolicy(new ScrollableCursorPolicy(this, pageSize));
1265 }
1266
1267 /**
1268 * PUBLIC:
1269 * Use a ScrollableCursor as the result collection.
1270 * @param policy the scrollable cursor policy allows for additional result set options.
1271 * Example:<p>
1272 * ScrollableCursorPolicy policy = new ScrollableCursorPolicy()<p>
1273 * policy.setResultSetType(ScrollableCursorPolicy.TYPE_SCROLL_INSENSITIVE);<p>
1198 setIsPrepared(false);
1199 }
1200
1201 /**
1202 * PUBLIC:
1203 * Configure the mapping to use an instance of the specified container class
1204 * to hold the target objects.
1205 * <p>jdk1.2.x: The container class must implement (directly or indirectly) the Collection interface.
1206 * <p>jdk1.1.x: The container class must be a subclass of Vector.
1207 */
1208 public void useCollectionClass(Class concreteClass) {
1209 // Set container policy.
1210 setContainerPolicy(ContainerPolicy.buildPolicyFor(concreteClass));
1211
1212 }
1213
1214 /**
1215 * PUBLIC:
1216 * Use a CursoredStream as the result collection.
1217 * The initial read size is 10 and page size is 5.
1218 */
1219 public void useCursoredStream() {
1220 useCursoredStream(10, 5);
1221 }
1222
1223 /**
1224 * PUBLIC:
1225 * Use a CursoredStream as the result collection.
1226 * @param initialReadSize the initial number of objects to read
1227 * @param pageSize the number of objects to read when more objects
1228 * are needed from the database
1229 */
1230 public void useCursoredStream(int initialReadSize, int pageSize) {
1231 setContainerPolicy(new CursoredStreamPolicy(this, initialReadSize, pageSize));
1232 }
1233
1234 /**
1235 * PUBLIC:
1236 * Use a CursoredStream as the result collection.
1237 * @param initialReadSize the initial number of objects to read
1238 * @param pageSize the number of objects to read when more objects
1239 * are needed from the database
1240 * @param sizeQuery a query that will return the size of the result set;
1241 * this must be set if an expression is not used (i.e. custom SQL)
1242 */
1243 public void useCursoredStream(int initialReadSize, int pageSize, ValueReadQuery sizeQuery) {
1244 setContainerPolicy(new CursoredStreamPolicy(this, initialReadSize, pageSize, sizeQuery));
1245 }
1246
1247 /**
1248 * PUBLIC:
1249 * Configure the query to use an instance of the specified container class
1250 * to hold the result objects. The key used to index the value in the Map
1251 * is the value returned by a call to the specified zero-argument method.
1252 * The method must be implemented by the class (or a superclass) of the
1253 * value to be inserted into the Map.
1254 * <p>jdk1.2.x: The container class must implement (directly or indirectly) the Map interface.
1255 * <p>jdk1.1.x: The container class must be a subclass of Hashtable.
1256 * <p>The referenceClass must set before calling this method.
1257 */
1258 public void useMapClass(Class concreteClass, String methodName) {
1259 // the reference class has to be specified before coming here
1260 if (getReferenceClass() == null) {
1261 throw QueryException.referenceClassMissing(this);
1262 }
1263 ContainerPolicy policy = ContainerPolicy.buildPolicyFor(concreteClass);
1264 policy.setKeyName(methodName, getReferenceClass().getName());
1265 setContainerPolicy(policy);
1266 }
1267
1268 /**
1269 * PUBLIC:
1270 * Use a ScrollableCursor as the result collection.
1271 */
1272 public void useScrollableCursor() {
1273 useScrollableCursor(10);
1274 }
1275
1276 /**
1277 * PUBLIC:
1278 * Use a ScrollableCursor as the result collection.
1279 * @param pageSize the number of elements to be read into a the cursor
1280 * when more elements are needed from the database.
1281 */
1282 public void useScrollableCursor(int pageSize) {
1283 setContainerPolicy(new ScrollableCursorPolicy(this, pageSize));
1284 }
1285
1286 /**
1287 * PUBLIC:
1288 * Use a ScrollableCursor as the result collection.
1289 * @param policy the scrollable cursor policy allows for additional result set options.
1290 * Example:<p>
1291 * ScrollableCursorPolicy policy = new ScrollableCursorPolicy()<p>
1292 * policy.setResultSetType(ScrollableCursorPolicy.TYPE_SCROLL_INSENSITIVE);<p>
12741293 * query.useScrollableCursor(policy);
1275 */
1276 public void useScrollableCursor(ScrollableCursorPolicy policy) {
1277 policy.setQuery(this);
1278 setContainerPolicy(policy);
1279 }
1280
1281 /**
1282 * INTERNAL:
1283 * Indicates whether the query can use ResultSet optimization.
1294 */
1295 public void useScrollableCursor(ScrollableCursorPolicy policy) {
1296 policy.setQuery(this);
1297 setContainerPolicy(policy);
1298 }
1299
1300 /**
1301 * INTERNAL:
1302 * Indicates whether the query can use ResultSet optimization.
12841303 * The method is called when the query is prepared,
1285 * so it should refer only to the attributes that cannot be altered without re-preparing the query.
1286 * If the query is a clone and the original has been already prepared
1304 * so it should refer only to the attributes that cannot be altered without re-preparing the query.
1305 * If the query is a clone and the original has been already prepared
12871306 * this method will be called to set a (transient and therefore set to null) usesResultSetOptimization attribute.
1288 */
1289 @Override
1290 public boolean supportsResultSetAccessOptimizationOnPrepare() {
1291 if (!super.supportsResultSetAccessOptimizationOnPrepare()) {
1292 return false;
1293 }
1294 return !this.containerPolicy.isMappedKeyMapPolicy() && !this.containerPolicy.shouldAddAll() && // MappedKeyMapPolicy requires the whole row, OrderListContainerPolicy requires all rows.
1307 */
1308 @Override
1309 public boolean supportsResultSetAccessOptimizationOnPrepare() {
1310 if (!super.supportsResultSetAccessOptimizationOnPrepare()) {
1311 return false;
1312 }
1313 return !this.containerPolicy.isMappedKeyMapPolicy() && !this.containerPolicy.shouldAddAll() && // MappedKeyMapPolicy requires the whole row, OrderListContainerPolicy requires all rows.
12951314 !this.descriptor.shouldAlwaysConformResultsInUnitOfWork(); // will be supported when conformResult method is adapted to use ResultSet;
1296 }
1297
1298 /**
1299 * INTERNAL:
1300 * Indicates whether the query can use ResultSet optimization.
1301 * Note that the session must be already set.
1315 }
1316
1317 /**
1318 * INTERNAL:
1319 * Indicates whether the query can use ResultSet optimization.
1320 * Note that the session must be already set.
13021321 * The method is called when the query is executed,
1303 * so it should refer only to the attributes that can be altered without re-preparing the query.
1304 */
1305 public boolean supportsResultSetAccessOptimizationOnExecute() {
1306 if (!super.supportsResultSetAccessOptimizationOnExecute()) {
1307 return false;
1308 }
1309 return !shouldConformResultsInUnitOfWork(); // could be supported if conformResult method is adapted to use ResultSetAccessOptimization
1310 }
1311 }
1322 * so it should refer only to the attributes that can be altered without re-preparing the query.
1323 */
1324 public boolean supportsResultSetAccessOptimizationOnExecute() {
1325 if (!super.supportsResultSetAccessOptimizationOnExecute()) {
1326 return false;
1327 }
1328 return !shouldConformResultsInUnitOfWork(); // could be supported if conformResult method is adapted to use ResultSetAccessOptimization
1329 }
1330 }
00 /*******************************************************************************
1 * Copyright (c) 1998, 2012 Oracle and/or its affiliates. All rights reserved.
1 * Copyright (c) 1998, 2020 Oracle and/or its affiliates. All rights reserved.
22 * This program and the accompanying materials are made available under the
33 * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
44 * which accompanies this distribution.
1717 import org.eclipse.persistence.internal.helper.ClassConstants;
1818 import org.eclipse.persistence.sdo.types.*;
1919 import org.eclipse.persistence.sdo.helper.SDOTypeHelper;
20
21 import java.util.Collections;
22 import java.util.HashSet;
23 import java.util.Set;
2024
2125 /**
2226 * <p><b>Purpose</b>: Maintain constants in one class
343347 /** Search string concatenated from default package for type generation and the package separator dot */
344348 public static final String JAVA_TYPE_GENERATION_DEFAULT_PACKAGE_NAME_SEARCH = JAVA_TYPEGENERATION_DEFAULT_PACKAGE_NAME + JAVA_PACKAGE_NAME_SEPARATOR;
345349
350 /** List of the classes allowed to deserialize in SDO*/
351 public static final Set<String> ALLOWED_DESERIALIZATION_CLASS_NAMES = Collections.unmodifiableSet(
352 new HashSet() {{
353 add(org.eclipse.persistence.sdo.SDOExternalizableDelegator.class.getName());
354 add(org.eclipse.persistence.sdo.AbstractExternalizableDelegator.class.getName());
355 add(java.util.ArrayList.class.getName());
356 }});
357
346358 static {
347359 if(null != sdoTypeHelper) {
348360 sdoTypeHelper.reset();
00 /*******************************************************************************
1 * Copyright (c) 1998, 2012 Oracle and/or its affiliates. All rights reserved.
1 * Copyright (c) 1998, 2020 Oracle and/or its affiliates. All rights reserved.
22 * This program and the accompanying materials are made available under the
33 * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
44 * which accompanies this distribution.
2929 */
3030 package org.eclipse.persistence.sdo.helper;
3131
32 import java.io.IOException;
33 import java.io.InputStream;
34 import java.io.ObjectInputStream;
32 import java.io.*;
33 import java.util.Arrays;
34
3535 import commonj.sdo.helper.HelperContext;
3636 import commonj.sdo.impl.HelperProvider;
37 import org.eclipse.persistence.internal.localization.LoggingLocalization;
38 import org.eclipse.persistence.logging.AbstractSessionLog;
39 import org.eclipse.persistence.sdo.SDOConstants;
3740
3841 public class DataObjectInputStream extends ObjectInputStream {
3942 private HelperContext aHelperContext;
7881 public void setHelperContext(HelperContext helperContext) {
7982 aHelperContext = helperContext;
8083 }
84
85 @Override
86 protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
87 if (!SDOConstants.ALLOWED_DESERIALIZATION_CLASS_NAMES.contains(desc.getName())) {
88 AbstractSessionLog.getLog().log(AbstractSessionLog.SEVERE, "sdo_error_deserialization", new Object[] {desc.getName()});
89 throw new InvalidClassException(LoggingLocalization.buildMessage("sdo_error_deserialization", new Object[] {desc.getName()}));
90 }
91 return super.resolveClass(desc);
92 }
93
8194 }