1 /*
2 * Copyright (c) 1996, 2020, 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 org.openjdk.asmtools.jasm.OpcodeTables.Opcode;
26 import org.openjdk.asmtools.jasm.Tables.AttrTag;
27
28 import java.io.IOException;
29 import java.util.ArrayList;
30 import java.util.HashMap;
31
32 import static org.openjdk.asmtools.jasm.RuntimeConstants.SPLIT_VERIFIER_CFV;
33
34 class CodeAttr extends AttrData {
35
36 protected ClassData cls;
37
38 protected MethodData mtd;
39 protected Environment env;
40 protected Argument max_stack, max_locals;
41 protected Instr zeroInstr, lastInstr;
42 protected int cur_pc = 0;
43 protected DataVector<TrapData> trap_table; // TrapData
44 protected DataVectorAttr<LineNumData> lin_num_tb; // LineNumData
45 protected int lastln = 0;
46 protected DataVectorAttr<LocVarData> loc_var_tb; // LocVarData
47 protected DataVector<DataVectorAttr<? extends Data>> attrs;
48 protected ArrayList<Integer> slots;
49 protected HashMap<String, LocVarData> locvarsHash;
50 protected HashMap<String, Label> labelsHash;
51 protected HashMap<String, Trap> trapsHash;
52 protected StackMapData curMapEntry = null;
53 protected DataVectorAttr<StackMapData> stackMap;
54 // type annotations
55 protected DataVectorAttr<TypeAnnotationData> type_annotAttrVis = null;
56 protected DataVectorAttr<TypeAnnotationData> type_annotAttrInv = null;
57
58 public CodeAttr(MethodData mtd, int pos, int paramcnt, Argument max_stack, Argument max_locals) {
59 super(mtd.cls, AttrTag.ATT_Code.parsekey());
60 this.mtd = mtd;
61 this.cls = mtd.cls;
62 this.env = cls.env;
63 this.max_stack = max_stack;
64 this.max_locals = max_locals;
65 lastInstr = zeroInstr = new Instr();
66 trap_table = new DataVector<>(0); // TrapData
67 attrs = new DataVector<>();
68 if (env.debugInfoFlag) {
69 lin_num_tb = new DataVectorAttr<>(cls, AttrTag.ATT_LineNumberTable.parsekey());
70 attrs.add(lin_num_tb);
71 }
72 slots = new ArrayList<>(paramcnt);
73 for (int k = 0; k < paramcnt; k++) {
74 slots.add(k, 1);
75 }
76 }
77
78 void endCode() {
79 checkTraps();
80 checkLocVars();
81 checkLabels();
82 //
83 if (type_annotAttrVis != null) {
84 attrs.add(type_annotAttrVis);
85 }
86 if (type_annotAttrInv != null) {
87 attrs.add(type_annotAttrInv);
88 }
89 }
90
91 public void addAnnotations(ArrayList<AnnotationData> list) {
92 for (AnnotationData item : list) {
93 boolean invisible = item.invisible;
94 if (item instanceof TypeAnnotationData) {
95 // Type Annotations
96 TypeAnnotationData ta = (TypeAnnotationData) item;
97 if (invisible) {
98 if (type_annotAttrInv == null) {
99 type_annotAttrInv = new DataVectorAttr(cls,
100 AttrTag.ATT_RuntimeInvisibleTypeAnnotations.parsekey());
101 }
102 type_annotAttrInv.add(ta);
103 } else {
104 if (type_annotAttrVis == null) {
105 type_annotAttrVis = new DataVectorAttr(cls,
106 AttrTag.ATT_RuntimeVisibleTypeAnnotations.parsekey());
107 }
108 type_annotAttrVis.add(ta);
109 }
110 }
111 }
112 }
113
114 /* -------------------------------------- Traps */
115 Trap trapDecl(int pos, String name) {
116 Trap local;
117 if (trapsHash == null) {
118 trapsHash = new HashMap<>(10);
119 local = null;
120 } else {
121 local = trapsHash.get(name);
122 }
123 if (local == null) {
124 local = new Trap(pos, name);
125 trapsHash.put(name, local);
126 }
127 return local;
128 }
129
130 void beginTrap(int pos, String name) {
131 Trap trap = trapDecl(pos, name);
132 if (trap.start_pc != Argument.NotSet) {
133 env.error("trap.tryredecl", name);
134 return;
135 }
136 trap.start_pc = cur_pc;
137 }
138
139 void endTrap(int pos, String name) {
140 Trap trap = trapDecl(pos, name);
141 if (trap.end_pc != Argument.NotSet) {
142 env.error("trap.endtryredecl", name);
143 return;
144 }
145 trap.end_pc = cur_pc;
146 }
147
148 void trapHandler(int pos, String name, Argument type) {
149 Trap trap = trapDecl(pos, name);
150 trap.refd = true;
151 TrapData trapData = new TrapData(pos, trap, cur_pc, type);
152 trap_table.addElement(trapData);
153 }
154
155 void checkTraps() {
156 if (trapsHash == null) {
157 return;
158 }
159 for (Trap trap : trapsHash.values()) {
160 if (!trap.refd) {
161 env.error(trap.pos, "warn.trap.notref", trap.name);
162 }
163 }
164
165 for (TrapData trapData : trap_table) {
166 Trap trapLabel = trapData.trap;
167 if (trapLabel.start_pc == Argument.NotSet) {
168 env.error(trapData.pos, "trap.notry", trapLabel.name);
169 }
170 if (trapLabel.end_pc == Argument.NotSet) {
171 env.error(trapData.pos, "trap.noendtry", trapLabel.name);
172 }
173 }
174 }
175
176 /* -------------------------------------- Labels */
177 Label labelDecl(String name) {
178 Label local;
179 if (labelsHash == null) {
180 labelsHash = new HashMap<>(10);
181 local = null;
182 } else {
183 local = labelsHash.get(name);
184 }
185 if (local == null) {
186 local = new Label(name);
187 labelsHash.put(name, local);
188 }
189 return local;
190 }
191
192 public Label LabelDef(int pos, String name) {
193 Label label = labelDecl(name);
194 if (label.defd) {
195 env.error(pos, "label.redecl", name);
196 return null;
197 }
198 label.defd = true;
199 label.arg = cur_pc;
200 return label;
201 }
202
203 public Label LabelRef(String name) {
204 Label label = labelDecl(name);
205 label.refd = true;
206 return label;
207 }
208
209 void checkLabels() {
210 if (labelsHash == null) {
211 return;
212 }
213
214 for (Label local : labelsHash.values()) {
215 // check that every label is defined
216 if (!local.defd) {
217 env.error("label.undecl", local.name);
218 }
219 }
220 }
221
222 /* -------------------------------------- Variables */
223 LocVarData locvarDecl(String name) {
224 LocVarData local;
225 if (locvarsHash == null) {
226 locvarsHash = new HashMap<>(10);
227 local = null;
228 } else {
229 local = locvarsHash.get(name);
230 }
231 if (local == null) {
232 local = new LocVarData(name);
233 locvarsHash.put(name, local);
234 }
235 return local;
236 }
237
238 public void LocVarDataDef(int slot) {
239 slots.set(slot, 1);
240 if ((max_locals != null) && (max_locals.arg < slots.size())) {
241 env.error("warn.illslot", Integer.toString(slot));
242 }
243 }
244
245 public void LocVarDataDef(String name, ConstantPool.ConstCell type) {
246 LocVarData locvar = locvarDecl(name);
247 if (locvar.defd) {
248 env.error("locvar.redecl", name);
249 return;
250 }
251 locvar.defd = true;
252 locvar.start_pc = (short) cur_pc;
253 locvar.name_cpx = cls.pool.FindCellAsciz(name);
254 locvar.sig_cpx = type;
255 int k;
256 findSlot:
257 {
258 for (k = 0; k < slots.size(); k++) {
259 if (slots.get(k) == 0) {
260 break findSlot;
261 }
262 }
263 k = slots.size();
264 }
265 LocVarDataDef(k);
266 locvar.arg = k;
267 if (loc_var_tb == null) {
268 loc_var_tb = new DataVectorAttr<>(cls, AttrTag.ATT_LocalVariableTable.parsekey());
269 attrs.add(loc_var_tb);
270 }
271 loc_var_tb.add(locvar);
272 }
273
274 public Argument LocVarDataRef(String name) {
275 LocVarData locvar = locvarDecl(name);
276 if (!locvar.defd) {
277 env.error("locvar.undecl", name);
278 locvar.defd = true; // to avoid multiple error messages
279 }
280 locvar.refd = true;
281 return locvar;
282 }
283
284 public void LocVarDataEnd(int slot) {
285 slots.set(slot, 0);
286 }
287
288 public void LocVarDataEnd(String name) {
289 LocVarData locvar = locvarsHash.get(name);
290 if (locvar == null) {
291 env.error("locvar.undecl", name);
292 return;
293 } else if (!locvar.defd) {
294 env.error("locvar.undecl", name);
295 return;
296 }
297 locvar.length = (short) (cur_pc - locvar.start_pc);
298
299 slots.set(locvar.arg, 0);
300 locvarsHash.put(name, new LocVarData(name));
301 }
302
303 void checkLocVars() {
304 if (locvarsHash == null) {
305 return;
306 }
307 for (LocVarData locvar : locvarsHash.values()) {
308 if (!locvar.defd) {
309 continue;
310 } // this is false locvar
311 // set end of scope, if not set
312 if (slots.get(locvar.arg) == 1) {
313 locvar.length = (short) (cur_pc - locvar.start_pc);
314 slots.set(locvar.arg, 0);
315 }
316 }
317 }
318
319 /* -------------------------------------- StackMap */
320 public StackMapData getStackMap() {
321 if (curMapEntry == null) {
322 curMapEntry = new StackMapData(env);
323 if (cls.cfv.major_version() >= SPLIT_VERIFIER_CFV) {
324 curMapEntry.setIsStackMapTable(true);
325 }
326 }
327 return curMapEntry;
328 }
329
330 /*====================================================== Instr */
331 void addInstr(int mnenoc_pos, Opcode opcode, Argument arg, Object arg2) {
332 Instr newInstr = new Instr(cur_pc, cls.env.pos, opcode, arg, arg2);
333 lastInstr.next = newInstr;
334 lastInstr = newInstr;
335 int len = opcode.length();
336 switch (opcode) {
337 case opc_tableswitch:
338 len = ((SwitchTable) arg2).recalcTableSwitch(cur_pc);
339 break;
340 case opc_lookupswitch:
341 len = ((SwitchTable) arg2).calcLookupSwitch(cur_pc);
342 break;
343 case opc_ldc:
344 ((ConstantPool.ConstCell) arg).setRank(ConstantPool.ReferenceRank.LDC);
345 break;
346 default:
347 if (arg instanceof ConstantPool.ConstCell) {
348 ((ConstantPool.ConstCell) arg).setRank(ConstantPool.ReferenceRank.ANY);
349 }
350 }
351 if (env.debugInfoFlag) {
352 int ln = env.lineNumber(mnenoc_pos);
353 if (ln != lastln) { // only one entry in lin_num_tb per line
354 lin_num_tb.add(new LineNumData(cur_pc, ln));
355 lastln = ln;
356 }
357 }
358 if (curMapEntry != null) {
359 curMapEntry.pc = cur_pc;
360 StackMapData prevStackFrame = null;
361 if (stackMap == null) {
362 if (cls.cfv.major_version() >= SPLIT_VERIFIER_CFV) {
363 stackMap = new DataVectorAttr<>(cls, AttrTag.ATT_StackMapTable.parsekey());
364 } else {
365 stackMap = new DataVectorAttr<>(cls, AttrTag.ATT_StackMap.parsekey());
366 }
367 attrs.add(stackMap);
368 } else if (stackMap.size() > 0) {
369 prevStackFrame = stackMap.get(stackMap.size() - 1);
370 }
371 curMapEntry.setOffset(prevStackFrame);
372 stackMap.add(curMapEntry);
373 curMapEntry = null;
374 }
375
376 cur_pc += len;
377 }
378
379 /*====================================================== Attr interface */
380 // subclasses must redefine this
381 @Override
382 public int attrLength() {
383 return 2 + 2 + 4 // for max_stack, max_locals, and cur_pc
384 + cur_pc // + 2+trap_table.size()*8
385 + trap_table.getLength() + attrs.getLength();
386 }
387
388 @Override
389 public void write(CheckedDataOutputStream out)
390 throws IOException, Parser.CompilerError {
391 int mxstck = (max_stack != null) ? max_stack.arg : 0;
392 int mxloc = (max_locals != null) ? max_locals.arg : slots.size();
393 super.write(out); // attr name, attr len
394 out.writeShort(mxstck);
395 out.writeShort(mxloc);
396 out.writeInt(cur_pc);
397 for (Instr instr = zeroInstr.next; instr != null; instr = instr.next) {
398 instr.write(out, env);
399 }
400
401 trap_table.write(out);
402
403 attrs.write(out);
404 }
405
406 /*-------------------------------------------------------- */
407 /* CodeAttr inner classes */
408 static public class Local extends Argument {
409
410 String name;
411 boolean defd = false, refd = false;
412
413 public Local(String name) {
414 this.name = name;
415 }
416 }
417
418 /**
419 *
420 */
421 static public class Label extends Local {
422
423 public Label(String name) {
424 super(name);
425 }
426 }
427
428 /**
429 *
430 */
431 class LocVarData extends Local implements Data {
432
433 // arg means slot
434 short start_pc, length;
435 ConstantPool.ConstCell name_cpx, sig_cpx;
436
437 public LocVarData(String name) {
438 super(name);
439 }
440
441 @Override
442 public int getLength() {
443 return 10;
444 }
445
446 @Override
447 public void write(CheckedDataOutputStream out) throws IOException {
448 out.writeShort(start_pc);
449 out.writeShort(length);
450 out.writeShort(name_cpx.arg);
451 out.writeShort(sig_cpx.arg);
452 out.writeShort(arg);
453 }
454 }
455
456 /**
457 *
458 */
459 class LineNumData implements Data {
460
461 int start_pc, line_number;
462
463 public LineNumData(int start_pc, int line_number) {
464 this.start_pc = start_pc;
465 this.line_number = line_number;
466 }
467
468 @Override
469 public int getLength() {
470 return 4;
471 }
472
473 @Override
474 public void write(CheckedDataOutputStream out) throws IOException {
475 out.writeShort(start_pc);
476 out.writeShort(line_number);
477 }
478 }
479
480 /**
481 *
482 */
483 class Trap extends Local {
484
485 int start_pc = Argument.NotSet, end_pc = Argument.NotSet;
486 int pos;
487
488 Trap(int pos, String name) {
489 super(name);
490 this.pos = pos;
491 }
492 }
493
494 /**
495 *
496 */
497 class TrapData implements Data {
498
499 int pos;
500 Trap trap;
501 int handler_pc;
502 Argument catchType;
503
504 public TrapData(int pos, Trap trap, int handler_pc, Argument catchType) {
505 this.pos = pos;
506 this.trap = trap;
507 this.handler_pc = handler_pc;
508 this.catchType = catchType;
509 }
510
511 @Override
512 public int getLength() {
513 return 8; // add the length of number of elements
514 }
515
516 @Override
517 public void write(CheckedDataOutputStream out) throws IOException {
518 out.writeShort(trap.start_pc);
519 out.writeShort(trap.end_pc);
520 out.writeShort(handler_pc);
521 if (catchType.isSet()) {
522 out.writeShort(catchType.arg);
523 } else {
524 out.writeShort(0);
525 }
526 }
527 } // end TrapData
528 } // end CodeAttr
529