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