1 /*
   2  * Copyright (c) 2009, 2015, 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  */
  24 
  25 /**
  26  * A SAX based parser of LogCompilation output from HotSpot.  It takes a complete
  27  */
  28 
  29 package com.sun.hotspot.tools.compiler;
  30 
  31 import java.io.FileReader;
  32 import java.io.PrintStream;
  33 import java.io.Reader;
  34 import java.util.ArrayDeque;
  35 import java.util.ArrayList;
  36 import java.util.Collections;
  37 import java.util.Comparator;
  38 import java.util.HashMap;
  39 import java.util.LinkedHashMap;
  40 import java.util.Stack;
  41 import javax.xml.parsers.SAXParser;
  42 import javax.xml.parsers.SAXParserFactory;
  43 import org.xml.sax.Attributes;
  44 import org.xml.sax.ErrorHandler;
  45 import org.xml.sax.InputSource;
  46 import org.xml.sax.helpers.DefaultHandler;
  47 
  48 public class LogParser extends DefaultHandler implements ErrorHandler, Constants {
  49 
  50     static final HashMap<String, String> typeMap;
  51     static {
  52         typeMap = new HashMap<String, String>();
  53         typeMap.put("[I", "int[]");
  54         typeMap.put("[C", "char[]");
  55         typeMap.put("[Z", "boolean[]");
  56         typeMap.put("[L", "Object[]");
  57         typeMap.put("[B", "byte[]");
  58     }
  59 
  60     static Comparator<LogEvent> sortByStart = new Comparator<LogEvent>() {
  61 
  62         public int compare(LogEvent a, LogEvent b) {
  63             double difference = (a.getStart() - b.getStart());
  64             if (difference < 0) {
  65                 return -1;
  66             }
  67             if (difference > 0) {
  68                 return 1;
  69             }
  70             return 0;
  71         }
  72 
  73         @Override
  74         public boolean equals(Object other) {
  75             return false;
  76         }
  77 
  78         @Override
  79         public int hashCode() {
  80             return 7;
  81         }
  82     };
  83     static Comparator<LogEvent> sortByNameAndStart = new Comparator<LogEvent>() {
  84 
  85         public int compare(LogEvent a, LogEvent b) {
  86             Compilation c1 = a.getCompilation();
  87             Compilation c2 = b.getCompilation();
  88             if (c1 != null && c2 != null) {
  89                 int result = c1.getMethod().toString().compareTo(c2.getMethod().toString());
  90                 if (result != 0) {
  91                     return result;
  92                 }
  93             }
  94             double difference = (a.getStart() - b.getStart());
  95             if (difference < 0) {
  96                 return -1;
  97             }
  98             if (difference > 0) {
  99                 return 1;
 100             }
 101             return 0;
 102         }
 103 
 104         public boolean equals(Object other) {
 105             return false;
 106         }
 107 
 108         @Override
 109         public int hashCode() {
 110             return 7;
 111         }
 112     };
 113     static Comparator<LogEvent> sortByElapsed = new Comparator<LogEvent>() {
 114 
 115         public int compare(LogEvent a, LogEvent b) {
 116             double difference = (a.getElapsedTime() - b.getElapsedTime());
 117             if (difference < 0) {
 118                 return -1;
 119             }
 120             if (difference > 0) {
 121                 return 1;
 122             }
 123             return 0;
 124         }
 125 
 126         @Override
 127         public boolean equals(Object other) {
 128             return false;
 129         }
 130 
 131         @Override
 132         public int hashCode() {
 133             return 7;
 134         }
 135     };
 136 
 137     class Jvms {
 138         Jvms(Method method, int bci) {
 139             this.method = method;
 140             this.bci = bci;
 141         }
 142         final public Method method;
 143         final public int bci;
 144         final public String toString() {
 145             return "@" + bci + " " + method;
 146         }
 147     }
 148 
 149     class LockElimination extends BasicLogEvent {
 150 
 151         ArrayList<Jvms> jvms = new ArrayList<Jvms>(1);
 152         final String kind;
 153         final String classId;
 154         final String tagName;
 155         LockElimination(String tagName, double start, String id, String kind, String classId) {
 156             super(start, id);
 157             this.kind = kind;
 158             this.classId = classId;
 159             this.tagName = tagName;
 160         }
 161 
 162         @Override
 163         public void print(PrintStream stream) {
 164             stream.printf("%s %s %s %s  %.3f ", getId(), tagName, kind, classId, getStart());
 165             stream.print(jvms.toString());
 166             stream.print("\n");
 167         }
 168 
 169         void addJVMS(Method method, int bci) {
 170             jvms.add(new Jvms(method, bci));
 171         }
 172 
 173     }
 174 
 175     private ArrayList<LogEvent> events = new ArrayList<LogEvent>();
 176 
 177     private HashMap<String, String> types = new HashMap<String, String>();
 178     private HashMap<String, Method> methods = new HashMap<String, Method>();
 179     private LinkedHashMap<String, NMethod> nmethods = new LinkedHashMap<String, NMethod>();
 180     private HashMap<String, Compilation> compiles = new HashMap<String, Compilation>();
 181     private String failureReason;
 182     private int bci;
 183     private Stack<CallSite> scopes = new Stack<CallSite>();
 184     private Compilation compile;
 185     private CallSite site;
 186     private CallSite methodHandleSite;
 187     private Stack<Phase> phaseStack = new Stack<Phase>();
 188     private LockElimination currentLockElimination;
 189     private UncommonTrapEvent currentTrap;
 190     private Stack<CallSite> lateInlineScope;
 191     private boolean lateInlining;
 192 
 193 
 194     long parseLong(String l) {
 195         try {
 196             return Long.decode(l).longValue();
 197         } catch (NumberFormatException nfe) {
 198             int split = l.length() - 8;
 199             String s1 = "0x" + l.substring(split);
 200             String s2 = l.substring(0, split);
 201             long v1 = Long.decode(s1).longValue() & 0xffffffffL;
 202             long v2 = (Long.decode(s2).longValue() & 0xffffffffL) << 32;
 203             if (!l.equals("0x" + Long.toHexString(v1 + v2))) {
 204                 System.out.println(l);
 205                 System.out.println(s1);
 206                 System.out.println(s2);
 207                 System.out.println(v1);
 208                 System.out.println(v2);
 209                 System.out.println(Long.toHexString(v1 + v2));
 210                 throw new InternalError("bad conversion");
 211             }
 212             return v1 + v2;
 213         }
 214     }
 215 
 216     public static ArrayList<LogEvent> parse(String file, boolean cleanup) throws Exception {
 217         return parse(new FileReader(file), cleanup);
 218     }
 219 
 220     public static ArrayList<LogEvent> parse(Reader reader, boolean cleanup) throws Exception {
 221         // Create the XML input factory
 222         SAXParserFactory factory = SAXParserFactory.newInstance();
 223 
 224         // Create the XML LogEvent reader
 225         SAXParser p = factory.newSAXParser();
 226 
 227         if (cleanup) {
 228             // some versions of the log have slightly malformed XML, so clean it
 229             // up before passing it to SAX
 230             reader = new LogCleanupReader(reader);
 231         }
 232 
 233         LogParser log = new LogParser();
 234         try {
 235             p.parse(new InputSource(reader), log);
 236         } catch (Throwable th) {
 237             th.printStackTrace();
 238             // Carry on with what we've got...
 239         }
 240 
 241         // Associate compilations with their NMethods
 242         for (NMethod nm : log.nmethods.values()) {
 243             Compilation c = log.compiles.get(nm.getId());
 244             nm.setCompilation(c);
 245             // Native wrappers for methods don't have a compilation
 246             if (c != null) {
 247                 c.setNMethod(nm);
 248             }
 249         }
 250 
 251         // Initially we want the LogEvent log sorted by timestamp
 252         Collections.sort(log.events, sortByStart);
 253 
 254         return log.events;
 255     }
 256 
 257     String search(Attributes attr, String name) {
 258         String result = attr.getValue(name);
 259         if (result != null) {
 260             return result;
 261         } else {
 262             throw new InternalError("can't find " + name);
 263         }
 264     }
 265 
 266     String search(Attributes attr, String name, String defaultValue) {
 267         String result = attr.getValue(name);
 268         if (result != null) {
 269             return result;
 270         }
 271         return defaultValue;
 272     }
 273     int indent = 0;
 274 
 275     String type(String id) {
 276         String result = types.get(id);
 277         if (result == null) {
 278             throw new InternalError(id);
 279         }
 280         String remapped = typeMap.get(result);
 281         if (remapped != null) {
 282             return remapped;
 283         }
 284         return result;
 285     }
 286 
 287     void type(String id, String name) {
 288         assert type(id) == null;
 289         types.put(id, name);
 290     }
 291 
 292     Method method(String id) {
 293         Method result = methods.get(id);
 294         if (result == null) {
 295             throw new InternalError(id);
 296         }
 297         return result;
 298     }
 299 
 300     public String makeId(Attributes atts) {
 301         String id = atts.getValue("compile_id");
 302         String kind = atts.getValue("kind");
 303         if (kind != null && kind.equals("osr")) {
 304             id += "%";
 305         }
 306         return id;
 307     }
 308 
 309     @Override
 310     public void startElement(String uri,
 311             String localName,
 312             String qname,
 313             Attributes atts) {
 314         if (qname.equals("phase")) {
 315             Phase p = new Phase(search(atts, "name"),
 316                     Double.parseDouble(search(atts, "stamp")),
 317                     Integer.parseInt(search(atts, "nodes", "0")),
 318                     Integer.parseInt(search(atts, "live", "0")));
 319             phaseStack.push(p);
 320         } else if (qname.equals("phase_done")) {
 321             Phase p = phaseStack.pop();
 322             String phaseName = search(atts, "name", null);
 323             if (phaseName != null && !p.getId().equals(phaseName)) {
 324                 System.out.println("phase: " + p.getId());
 325                 throw new InternalError("phase name mismatch");
 326             }
 327             p.setEnd(Double.parseDouble(search(atts, "stamp")));
 328             p.setEndNodes(Integer.parseInt(search(atts, "nodes", "0")));
 329             p.setEndLiveNodes(Integer.parseInt(search(atts, "live", "0")));
 330             compile.getPhases().add(p);
 331         } else if (qname.equals("task")) {
 332             compile = new Compilation(Integer.parseInt(search(atts, "compile_id", "-1")));
 333             compile.setStart(Double.parseDouble(search(atts, "stamp")));
 334             compile.setICount(search(atts, "count", "0"));
 335             compile.setBCount(search(atts, "backedge_count", "0"));
 336 
 337             String method = atts.getValue("method");
 338             int space = method.indexOf(' ');
 339             method = method.substring(0, space) + "::" +
 340                     method.substring(space + 1, method.indexOf(' ', space + 1) + 1);
 341             String compiler = atts.getValue("compiler");
 342             if (compiler == null) {
 343                 compiler = "";
 344             }
 345             String kind = atts.getValue("compile_kind");
 346             if (kind == null) {
 347                 kind = "normal";
 348             }
 349             if (kind.equals("osr")) {
 350                 compile.setOsr(true);
 351                 compile.setOsr_bci(Integer.parseInt(search(atts, "osr_bci")));
 352             } else if (kind.equals("c2i")) {
 353                 compile.setSpecial("--- adapter " + method);
 354             } else {
 355                 compile.setSpecial(compile.getId() + " " + method + " (0 bytes)");
 356             }
 357             events.add(compile);
 358             compiles.put(makeId(atts), compile);
 359             site = compile.getCall();
 360         } else if (qname.equals("type")) {
 361             type(search(atts, "id"), search(atts, "name"));
 362         } else if (qname.equals("bc")) {
 363             bci = Integer.parseInt(search(atts, "bci"));
 364         } else if (qname.equals("klass")) {
 365             type(search(atts, "id"), search(atts, "name"));
 366         } else if (qname.equals("method")) {
 367             String id = search(atts, "id");
 368             Method m = new Method();
 369             m.setHolder(type(search(atts, "holder")));
 370             m.setName(search(atts, "name"));
 371             m.setReturnType(type(search(atts, "return")));
 372             m.setArguments(search(atts, "arguments", "void"));
 373 
 374             if (search(atts, "unloaded", "0").equals("0")) {
 375                m.setBytes(search(atts, "bytes"));
 376                m.setIICount(search(atts, "iicount"));
 377                m.setFlags(search(atts, "flags"));
 378             }
 379             methods.put(id, m);
 380         } else if (qname.equals("call")) {
 381             if (methodHandleSite != null) {
 382                 methodHandleSite = null;
 383             }
 384             Method m = method(search(atts, "method"));
 385             if (lateInlining && scopes.size() == 0) {
 386                 // re-attempting already seen call site (late inlining for MH invokes)
 387                 if (m != site.getMethod()) {
 388                     if (bci != site.getBci()) {
 389                         System.out.println(m + " bci: " + bci);
 390                         System.out.println(site.getMethod() +  " bci: " + site.getBci());
 391                         throw new InternalError("bci mismatch after late inlining");
 392                     }
 393                     site.setMethod(m);
 394                 }
 395             } else {
 396                 site = new CallSite(bci, m);
 397             }
 398             site.setCount(Integer.parseInt(search(atts, "count", "0")));
 399             String receiver = atts.getValue("receiver");
 400             if (receiver != null) {
 401                 site.setReceiver(type(receiver));
 402                 site.setReceiver_count(Integer.parseInt(search(atts, "receiver_count")));
 403             }
 404             int methodHandle = Integer.parseInt(search(atts, "method_handle_intrinsic", "0"));
 405             if (lateInlining && scopes.size() == 0) {
 406                 // The call was added before this round of late inlining
 407             } else if (methodHandle == 0) {
 408                 scopes.peek().add(site);
 409             } else {
 410                 // method handle call site can be followed by another
 411                 // call (in case it is inlined). If that happens we
 412                 // discard the method handle call site. So we keep
 413                 // track of it but don't add it to the list yet.
 414                 methodHandleSite = site;
 415             }
 416         } else if (qname.equals("regalloc")) {
 417             compile.setAttempts(Integer.parseInt(search(atts, "attempts")));
 418         } else if (qname.equals("inline_fail")) {
 419             if (methodHandleSite != null) {
 420                 scopes.peek().add(methodHandleSite);
 421                 methodHandleSite = null;
 422             }
 423             if (lateInlining && scopes.size() == 0) {
 424                 site.setReason(search(atts, "reason"));
 425                 lateInlining = false;
 426             } else {
 427                 scopes.peek().last().setReason(search(atts, "reason"));
 428             }
 429         } else if (qname.equals("inline_success")) {
 430             if (methodHandleSite != null) {
 431                 throw new InternalError("method handle site should have been replaced");
 432             }
 433             if (lateInlining && scopes.size() == 0) {
 434                 site.setReason(null);
 435             }
 436         } else if (qname.equals("failure")) {
 437             failureReason = search(atts, "reason");
 438         } else if (qname.equals("task_done")) {
 439             compile.setEnd(Double.parseDouble(search(atts, "stamp")));
 440             if (Integer.parseInt(search(atts, "success")) == 0) {
 441                 compile.setFailureReason(failureReason);
 442                 failureReason = null;
 443             }
 444         } else if (qname.equals("make_not_entrant")) {
 445             String id = makeId(atts);
 446             NMethod nm = nmethods.get(id);
 447             if (nm == null) throw new InternalError();
 448             LogEvent e = new MakeNotEntrantEvent(Double.parseDouble(search(atts, "stamp")), id,
 449                                                  atts.getValue("zombie") != null, nm);
 450             events.add(e);
 451         } else if (qname.equals("uncommon_trap")) {
 452             String id = atts.getValue("compile_id");
 453             if (id != null) {
 454                 id = makeId(atts);
 455                 currentTrap = new UncommonTrapEvent(Double.parseDouble(search(atts, "stamp")),
 456                         id,
 457                         atts.getValue("reason"),
 458                         atts.getValue("action"),
 459                         Integer.parseInt(search(atts, "count", "0")));
 460                 events.add(currentTrap);
 461             } else {
 462                 // uncommon trap inserted during parsing.
 463                 // ignore for now
 464             }
 465         } else if (qname.startsWith("eliminate_lock")) {
 466             String id = atts.getValue("compile_id");
 467             if (id != null) {
 468                 id = makeId(atts);
 469                 String kind = atts.getValue("kind");
 470                 String classId = atts.getValue("class_id");
 471                 currentLockElimination = new LockElimination(qname, Double.parseDouble(search(atts, "stamp")), id, kind, classId);
 472                 events.add(currentLockElimination);
 473             }
 474         } else if (qname.equals("late_inline")) {
 475             long inlineId = 0;
 476             try {
 477                 Long.parseLong(search(atts, "inline_id"));
 478             } catch (InternalError ex) {
 479                 // 0 is an acceptable default value.
 480             }
 481             lateInlineScope = new Stack<CallSite>();
 482             site = new CallSite(-999, method(search(atts, "method")));
 483             site.setInlineId(inlineId);
 484             lateInlineScope.push(site);
 485         } else if (qname.equals("jvms")) {
 486             // <jvms bci='4' method='java/io/DataInputStream readChar ()C' bytes='40' count='5815' iicount='20815'/>
 487             if (currentTrap != null) {
 488                 currentTrap.addJVMS(atts.getValue("method"), Integer.parseInt(atts.getValue("bci")));
 489             } else if (currentLockElimination != null) {
 490                   currentLockElimination.addJVMS(method(atts.getValue("method")), Integer.parseInt(atts.getValue("bci")));
 491             } else if (lateInlineScope != null) {
 492                 bci = Integer.parseInt(search(atts, "bci"));
 493                 site = new CallSite(bci, method(search(atts, "method")));
 494                 lateInlineScope.push(site);
 495             } else {
 496                 // Ignore <eliminate_allocation type='667'>,
 497                 //        <eliminate_lock lock='1'>,
 498                 //        <replace_string_concat arguments='2' string_alloc='0' multiple='0'>
 499             }
 500         } else if (qname.equals("inline_id")) {
 501             if (methodHandleSite != null) {
 502                 throw new InternalError("method handle site should have been replaced");
 503             }
 504             long id = Long.parseLong(search(atts, "id"));
 505             site.setInlineId(id);
 506         } else if (qname.equals("nmethod")) {
 507             String id = makeId(atts);
 508             NMethod nm = new NMethod(Double.parseDouble(search(atts, "stamp")),
 509                     id,
 510                     parseLong(atts.getValue("address")),
 511                     parseLong(atts.getValue("size")));
 512             nmethods.put(id, nm);
 513             events.add(nm);
 514         } else if (qname.equals("parse")) {
 515             if (failureReason != null && scopes.size() == 0 && !lateInlining) {
 516                 failureReason = null;
 517                 compile.reset();
 518                 site = compile.getCall();
 519             }
 520 
 521             if (methodHandleSite != null) {
 522                 throw new InternalError("method handle site should have been replaced");
 523             }
 524             Method m = method(search(atts, "method"));
 525             if (lateInlining && scopes.size() == 0) {
 526                 if (site.getMethod() != m) {
 527                     System.out.println(site.getMethod());
 528                     System.out.println(m);
 529                     throw new InternalError("Unexpected method mismatch during late inlining");
 530                 }
 531             }
 532             if (scopes.size() == 0 && !lateInlining) {
 533                 compile.setMethod(m);
 534                 scopes.push(site);
 535             } else {
 536                 if (site.getMethod() == m) {
 537                     scopes.push(site);
 538                 } else if (scopes.peek().getCalls().size() > 2 && m == scopes.peek().last(-2).getMethod()) {
 539                     scopes.push(scopes.peek().last(-2));
 540                 } else {
 541                     // C1 prints multiple method tags during inlining when it narrows method being inlinied.
 542                     // Example:
 543                     //   ...
 544                     //   <method id="813" holder="694" name="toString" return="695" flags="1" bytes="36" iicount="1"/>
 545                     //   <call method="813" instr="invokevirtual"/>
 546                     //   <inline_success reason="receiver is statically known"/>
 547                     //   <method id="814" holder="792" name="toString" return="695" flags="1" bytes="5" iicount="3"/>
 548                     //   <parse method="814">
 549                     //   ...
 550                     site.setMethod(m);
 551                     scopes.push(site);
 552                 }
 553             }
 554         } else if (qname.equals("parse_done")) {
 555             CallSite call = scopes.pop();
 556             call.setEndNodes(Integer.parseInt(search(atts, "nodes", "0")));
 557             call.setEndLiveNodes(Integer.parseInt(search(atts, "live", "0")));
 558             call.setTimeStamp(Double.parseDouble(search(atts, "stamp")));
 559             scopes.push(call);
 560         }
 561     }
 562 
 563     @Override
 564     public void endElement(String uri,
 565             String localName,
 566             String qname) {
 567         if (qname.equals("parse")) {
 568             indent -= 2;
 569             scopes.pop();
 570             if (scopes.size() == 0) {
 571                 lateInlining = false;
 572             }
 573         } else if (qname.equals("uncommon_trap")) {
 574             currentTrap = null;
 575         } else if (qname.startsWith("eliminate_lock")) {
 576             currentLockElimination = null;
 577         } else if (qname.equals("late_inline")) {
 578             // Populate late inlining info.
 579             if (scopes.size() != 0) {
 580                 throw new InternalError("scopes should be empty for late inline");
 581             }
 582             // late inline scopes are specified in reverse order:
 583             // compiled method should be on top of stack.
 584             CallSite caller = lateInlineScope.pop();
 585             Method m = compile.getMethod();
 586             if (m != caller.getMethod()) {
 587                 System.err.println(m);
 588                 System.err.println(caller.getMethod() + " bci: " + bci);
 589                 throw new InternalError("call site and late_inline info don't match");
 590             }
 591 
 592             // late_inline contains caller+bci info, convert it
 593             // to bci+callee info used by LogCompilation.
 594             CallSite lateInlineSite = compile.getLateInlineCall();
 595             ArrayDeque<CallSite> thisCallScopes = new ArrayDeque<CallSite>();
 596             do {
 597                 bci = caller.getBci();
 598                 // Next inlined call.
 599                 caller = lateInlineScope.pop();
 600                 CallSite callee =  new CallSite(bci, caller.getMethod());
 601                 callee.setInlineId(caller.getInlineId());
 602                 thisCallScopes.addLast(callee);
 603                 lateInlineSite.add(callee);
 604                 lateInlineSite = callee;
 605             } while (!lateInlineScope.empty());
 606 
 607             site = compile.getCall().findCallSite(thisCallScopes);
 608             if (site == null) {
 609                 System.out.println("call scopes:");
 610                 for (CallSite c : thisCallScopes) {
 611                     System.out.println(c.getMethod() + " " + c.getBci() + " " + c.getInlineId());
 612                 }
 613                 CallSite c = thisCallScopes.getLast();
 614                 if (c.getInlineId() != 0) {
 615                     System.out.println("Looking for call site in entire tree:");
 616                     ArrayDeque<CallSite> stack = compile.getCall().findCallSite2(c);
 617                     for (CallSite c2 : stack) {
 618                         System.out.println(c2.getMethod() + " " + c2.getBci() + " " + c2.getInlineId());
 619                     }
 620                 }
 621                 System.out.println(caller.getMethod() + " bci: " + bci);
 622                 throw new InternalError("couldn't find call site");
 623             }
 624             lateInlining = true;
 625 
 626             if (caller.getBci() != -999) {
 627                 System.out.println(caller.getMethod());
 628                 throw new InternalError("broken late_inline info");
 629             }
 630             if (site.getMethod() != caller.getMethod()) {
 631                 if (site.getInlineId() == caller.getInlineId()) {
 632                     site.setMethod(caller.getMethod());
 633                 } else {
 634                     System.out.println(site.getMethod());
 635                     System.out.println(caller.getMethod());
 636                     throw new InternalError("call site and late_inline info don't match");
 637                 }
 638             }
 639             // late_inline is followed by parse with scopes.size() == 0,
 640             // 'site' will be pushed to scopes.
 641             lateInlineScope = null;
 642         } else if (qname.equals("task")) {
 643             types.clear();
 644             methods.clear();
 645             site = null;
 646         }
 647     }
 648 
 649     @Override
 650     public void warning(org.xml.sax.SAXParseException e) {
 651         System.err.println(e.getMessage() + " at line " + e.getLineNumber() + ", column " + e.getColumnNumber());
 652         e.printStackTrace();
 653     }
 654 
 655     @Override
 656     public void error(org.xml.sax.SAXParseException e) {
 657         System.err.println(e.getMessage() + " at line " + e.getLineNumber() + ", column " + e.getColumnNumber());
 658         e.printStackTrace();
 659     }
 660 
 661     @Override
 662     public void fatalError(org.xml.sax.SAXParseException e) {
 663         System.err.println(e.getMessage() + " at line " + e.getLineNumber() + ", column " + e.getColumnNumber());
 664         e.printStackTrace();
 665     }
 666 }