1 /*
2 * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23 package org.openjdk.asmtools.jasm;
24
25 import static org.openjdk.asmtools.jasm.Tables.*;
26 import java.io.IOException;
27
28 /**
29 *
30 */
31 public class StackMapData implements Data {
32
33 /**
34 *
35 */
36 static public class StackMapItem1 implements Data {
37
38 StackMapType itemType;
39
40 StackMapItem1(StackMapType itemType) {
41 this.itemType = itemType;
42 }
43
44 @Override
45 public int getLength() {
46 return 1;
47 }
48
49 @Override
50 public void write(CheckedDataOutputStream out) throws IOException {
51 out.writeByte(itemType.value());
52 }
53 }
54
55 /**
56 *
57 */
58 static public class StackMapItem2 implements Data {
59
60 StackMapType itemType;
61 Argument arg;
62
63 StackMapItem2(StackMapType itemType, Argument arg) {
64 this.itemType = itemType;
65 this.arg = arg;
66 }
67
68 @Override
69 public int getLength() {
70 return 3;
71 }
72
73 @Override
74 public void write(CheckedDataOutputStream out) throws IOException {
75 out.writeByte(itemType.value());
76 out.writeShort(arg.arg);
77 }
78 }
79
80 int pc;
81 int offset;
82 int type;
83 String stackFrameType = null;
84 boolean isStackMapTable = false;
85 DataVector localsMap, stackMap;
86 Environment env;
87
88 StackMapData(Environment env) {
89 this.env = env;
90 }
91
92 void setPC(int pc) {
93 this.pc = pc;
94 }
95
96 void setOffset(int offset) {
97 this.offset = offset;
98 }
99
100 void setOffset(StackMapData prevFrame) {
101 offset = (prevFrame == null) ? pc : (pc - prevFrame.pc - 1);
102 }
103
104 void setStackFrameType(String stackFrameType) {
105 this.stackFrameType = stackFrameType;
106
107 if (stackFrameType != null) {
108 type = stackMapFrameTypeValue(stackFrameType);
109 }
110
111 if (stackFrameType == null || type == -1) {
112 env.error(pc, "invalid.stack.frame.type", stackFrameType, "" + type);
113 }
114 }
115
116 void setIsStackMapTable(boolean isStackMapTable) {
117 this.isStackMapTable = isStackMapTable;
118 }
119
120 void setLocalsMap(DataVector localsMap) {
121 this.localsMap = localsMap;
122 }
123
124 void setStackMap(DataVector stackMap) {
125 this.stackMap = stackMap;
126 }
127
128 @Override
129 public int getLength() {
130 int res = 0;
131 StackMapFrameType frame_type = StackMapFrameType.FULL_FRAME;
132 // int frame_type = FULL_FRAME;
133
134 if (isStackMapTable) {
135 if (stackFrameType != null) {
136 frame_type = stackMapFrameType(type);
137 }
138 res += 1;
139 }
140
141 switch (frame_type) {
142 case SAME_FRAME:
143 break;
144 case SAME_LOCALS_1_STACK_ITEM_FRAME:
145 res += stackMap.getLength() - 2;
146 break;
147 case SAME_LOCALS_1_STACK_ITEM_EXTENDED_FRAME:
148 res += stackMap.getLength();
149 break;
150 case CHOP_1_FRAME:
151 case CHOP_2_FRAME:
152 case CHOP_3_FRAME:
153 res += 2;
154 break;
155 case SAME_FRAME_EX:
156 res += 2;
157 break;
158 case APPEND_FRAME:
159 res += 2 + (localsMap == null ? 0 : (localsMap.getLength() - 2));
160 break;
161 case FULL_FRAME:
162 res += 2;
163 res += (localsMap == null ? 2 : localsMap.getLength());
164 res += (stackMap == null ? 2 : stackMap.getLength());
165 break;
166 default:
167 ;
168 }
169 return res;
170 }
171
172 @Override
173 public void write(CheckedDataOutputStream out) throws IOException {
174 StackMapFrameType frame_type = StackMapFrameType.FULL_FRAME;
175
176 if (isStackMapTable) {
177 if (stackFrameType != null) {
178 frame_type = stackMapFrameType(type);
179 }
180 }
181
182 switch (frame_type) {
183 case SAME_FRAME:
184 if (offset >= 64) {
185 env.error(pc, "invalid.offset.same.frame", "" + offset);
186 }
187 out.writeByte(offset);
188 break;
189 case SAME_LOCALS_1_STACK_ITEM_FRAME:
190 if (stackMap == null) {
191 env.error(pc, "no.stack.map.same.locals");
192 break;
193 }
194
195 if (stackMap.elements.size() != 1) {
196 env.error(pc, "should.be.only.one.stack.map.element");
197 break;
198 }
199
200 if (offset >= 64) {
201 env.error(pc, "invalid.offset.same.locals", "" + offset);
202 break;
203 }
204 out.writeByte(frame_type.value() + offset);
205 stackMap.writeElements(out);
206 break;
207 case SAME_LOCALS_1_STACK_ITEM_EXTENDED_FRAME:
208 if (stackMap == null) {
209 env.error(pc, "no.stack.map.same.locals");
210 break;
211 }
212
213 if (stackMap.elements.size() != 1) {
214 env.error(pc, "should.be.only.one.stack.map.element");
215 break;
216 }
217 out.writeByte(frame_type.value());
218 out.writeShort(offset);
219 stackMap.writeElements(out);
220 break;
221 case CHOP_1_FRAME:
222 case CHOP_2_FRAME:
223 case CHOP_3_FRAME:
224 case SAME_FRAME_EX:
225 boolean error = false;
226
227 if (stackMap != null) {
228 env.error(pc, "unexpected.stack.maps");
229 error = true;
230 }
231
232 if (localsMap != null) {
233 env.error(pc, "unexpected.locals.maps");
234 error = true;
235 }
236
237 if (error) {
238 break;
239 }
240 out.writeByte(frame_type.value());
241 out.writeShort(offset);
242 break;
243 case APPEND_FRAME:
244 if (localsMap == null) {
245 env.error(pc, "no.locals.map.append");
246 break;
247 }
248
249 if (localsMap.elements.size() > 3) {
250 env.error(pc, "more.locals.map.elements");
251 break;
252 }
253 out.writeByte(frame_type.value() + localsMap.elements.size() - 1);
254 out.writeShort(offset);
255 localsMap.writeElements(out);
256 break;
257 case FULL_FRAME:
258 if (isStackMapTable) {
259 out.writeByte(frame_type.value());
260 out.writeShort(offset);
261 } else {
262 out.writeShort(pc);
263 }
264
265 if (localsMap == null) {
266 out.writeShort(0);
267 } else {
268 localsMap.write(out);
269 }
270
271 if (stackMap == null) {
272 out.writeShort(0);
273 } else {
274 stackMap.write(out);
275 }
276 break;
277 default:
278 env.error(pc, "invalid.stack.frame.type", "" + frame_type);
279 }
280 }
281 }