changeset 4134:ead8152d9341

7178145: Change constMethodOop::_exception_table to optionally inlined u2 table. Summary: Change constMethodOop::_exception_table to optionally inlined u2 table. Reviewed-by: bdelsart, coleenp, kamg
author jiangli
date Wed, 16 Nov 2016 05:05:35 +0000
parents 6686cfcf4aa1
children 83a11fe60ae1
files agent/src/share/classes/sun/jvm/hotspot/oops/ConstMethod.java agent/src/share/classes/sun/jvm/hotspot/oops/ExceptionTableElement.java agent/src/share/classes/sun/jvm/hotspot/oops/GenerateOopMap.java agent/src/share/classes/sun/jvm/hotspot/oops/Method.java agent/src/share/classes/sun/jvm/hotspot/tools/jcore/ClassWriter.java agent/src/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java src/share/vm/ci/ciMethod.cpp src/share/vm/classfile/classFileParser.cpp src/share/vm/classfile/classFileParser.hpp src/share/vm/classfile/systemDictionary.cpp src/share/vm/classfile/verifier.cpp src/share/vm/classfile/verifier.hpp src/share/vm/interpreter/interpreterRuntime.cpp src/share/vm/memory/dump.cpp src/share/vm/memory/oopFactory.cpp src/share/vm/memory/oopFactory.hpp src/share/vm/oops/constMethodKlass.cpp src/share/vm/oops/constMethodKlass.hpp src/share/vm/oops/constMethodOop.cpp src/share/vm/oops/constMethodOop.hpp src/share/vm/oops/generateOopMap.cpp src/share/vm/oops/methodOop.cpp src/share/vm/oops/methodOop.hpp src/share/vm/prims/jvm.cpp src/share/vm/prims/jvmtiClassFileReconstituter.cpp src/share/vm/prims/jvmtiRedefineClasses.cpp src/share/vm/prims/methodHandleWalk.cpp src/share/vm/runtime/relocator.cpp src/share/vm/runtime/vmStructs.cpp
diffstat 29 files changed, 584 insertions(+), 342 deletions(-) [+]
line wrap: on
line diff
--- a/agent/src/share/classes/sun/jvm/hotspot/oops/ConstMethod.java	Fri Oct 14 03:13:25 2016 +0100
+++ b/agent/src/share/classes/sun/jvm/hotspot/oops/ConstMethod.java	Wed Nov 16 05:05:35 2016 +0000
@@ -47,15 +47,12 @@
   private static int HAS_LINENUMBER_TABLE;
   private static int HAS_CHECKED_EXCEPTIONS;
   private static int HAS_LOCALVARIABLE_TABLE;
+  private static int HAS_EXCEPTION_TABLE;
 
   private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
     Type type                  = db.lookupType("constMethodOopDesc");
     // Backpointer to non-const methodOop
     method                     = new OopField(type.getOopField("_method"), 0);
-    // The exception handler table. 4-tuples of ints [start_pc, end_pc,
-    // handler_pc, catch_type index] For methods with no exceptions the
-    // table is pointing to Universe::the_empty_int_array
-    exceptionTable             = new OopField(type.getOopField("_exception_table"), 0);
     constMethodSize            = new CIntField(type.getCIntegerField("_constMethod_size"), 0);
     flags                      = new ByteField(type.getJByteField("_flags"), 0);
 
@@ -63,6 +60,7 @@
     HAS_LINENUMBER_TABLE      = db.lookupIntConstant("constMethodOopDesc::_has_linenumber_table").intValue();
     HAS_CHECKED_EXCEPTIONS     = db.lookupIntConstant("constMethodOopDesc::_has_checked_exceptions").intValue();
     HAS_LOCALVARIABLE_TABLE   = db.lookupIntConstant("constMethodOopDesc::_has_localvariable_table").intValue();
+    HAS_EXCEPTION_TABLE       = db.lookupIntConstant("constMethodOopDesc::_has_exception_table").intValue();
 
     // Size of Java bytecodes allocated immediately after constMethodOop.
     codeSize                   = new CIntField(type.getCIntegerField("_code_size"), 0);
@@ -78,6 +76,9 @@
 
     type                       = db.lookupType("LocalVariableTableElement");
     localVariableTableElementSize = type.getSize();
+
+    type                       = db.lookupType("ExceptionTableElement");
+    exceptionTableElementSize = type.getSize();
   }
 
   ConstMethod(OopHandle handle, ObjectHeap heap) {
@@ -86,7 +87,6 @@
 
   // Fields
   private static OopField  method;
-  private static OopField  exceptionTable;
   private static CIntField constMethodSize;
   private static ByteField flags;
   private static CIntField codeSize;
@@ -99,16 +99,13 @@
 
   private static long checkedExceptionElementSize;
   private static long localVariableTableElementSize;
+  private static long exceptionTableElementSize;
 
   // Accessors for declared fields
   public Method getMethod() {
     return (Method) method.getValue(this);
   }
 
-  public TypeArray getExceptionTable() {
-    return (TypeArray) exceptionTable.getValue(this);
-  }
-
   public long getConstMethodSize() {
     return constMethodSize.getValue(this);
   }
@@ -224,7 +221,6 @@
     super.iterateFields(visitor, doVMFields);
     if (doVMFields) {
       visitor.doOop(method, true);
-      visitor.doOop(exceptionTable, true);
       visitor.doCInt(constMethodSize, true);
       visitor.doByte(flags, true);
       visitor.doCInt(codeSize, true);
@@ -315,6 +311,23 @@
     return ret;
   }
 
+  public boolean hasExceptionTable() {
+    return (getFlags() & HAS_EXCEPTION_TABLE) != 0;
+  }
+
+  public ExceptionTableElement[] getExceptionTable() {
+    if (Assert.ASSERTS_ENABLED) {
+      Assert.that(hasExceptionTable(), "should only be called if table is present");
+    }
+    ExceptionTableElement[] ret = new ExceptionTableElement[getExceptionTableLength()];
+    long offset = offsetOfExceptionTable();
+    for (int i = 0; i < ret.length; i++) {
+      ret[i] = new ExceptionTableElement(getHandle(), offset);
+      offset += exceptionTableElementSize;
+    }
+    return ret;
+  }
+
   public boolean hasCheckedExceptions() {
     return (getFlags() & HAS_CHECKED_EXCEPTIONS) != 0;
   }
@@ -404,7 +417,10 @@
     if (Assert.ASSERTS_ENABLED) {
       Assert.that(hasLocalVariableTable(), "should only be called if table is present");
     }
-    if (hasCheckedExceptions()) {
+
+    if (hasExceptionTable()) {
+      return offsetOfExceptionTable() - 2;
+    } else if (hasCheckedExceptions()) {
       return offsetOfCheckedExceptions() - 2;
     } else {
       return offsetOfLastU2Element();
@@ -421,4 +437,33 @@
     return offset;
   }
 
+  private int getExceptionTableLength() {
+    if (hasExceptionTable()) {
+      return (int) getHandle().getCIntegerAt(offsetOfExceptionTableLength(), 2, true);
+    } else {
+      return 0;
+    }
+  }
+
+  private long offsetOfExceptionTableLength() {
+    if (Assert.ASSERTS_ENABLED) {
+      Assert.that(hasExceptionTable(), "should only be called if table is present");
+    }
+    if (hasCheckedExceptions()) {
+      return offsetOfCheckedExceptions() - 2;
+    } else {
+      return offsetOfLastU2Element();
+    }
+  }
+
+  private long offsetOfExceptionTable() {
+    long offset = offsetOfExceptionTableLength();
+    long length = getExceptionTableLength();
+    if (Assert.ASSERTS_ENABLED) {
+      Assert.that(length > 0, "should only be called if table is present");
+    }
+    offset -= length * exceptionTableElementSize;
+    return offset;
+  }
+
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/src/share/classes/sun/jvm/hotspot/oops/ExceptionTableElement.java	Wed Nov 16 05:05:35 2016 +0000
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package sun.jvm.hotspot.oops;
+
+import java.io.*;
+import java.util.*;
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.interpreter.*;
+import sun.jvm.hotspot.runtime.*;
+import sun.jvm.hotspot.types.*;
+import sun.jvm.hotspot.utilities.*;
+
+public class ExceptionTableElement {
+  static {
+    VM.registerVMInitializedObserver(new Observer() {
+        public void update(Observable o, Object data) {
+          initialize(VM.getVM().getTypeDataBase());
+        }
+      });
+  }
+
+  private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
+    Type type            = db.lookupType("ExceptionTableElement");
+    offsetOfStartPC      = type.getCIntegerField("start_pc").getOffset();
+    offsetOfEndPC        = type.getCIntegerField("end_pc").getOffset();
+    offsetOfHandlerPC    = type.getCIntegerField("handler_pc").getOffset();
+    offsetOfCatchTypeIndex = type.getCIntegerField("catch_type_index").getOffset();
+  }
+
+  private static long offsetOfStartPC;
+  private static long offsetOfEndPC;
+  private static long offsetOfHandlerPC;
+  private static long offsetOfCatchTypeIndex;
+
+  private OopHandle handle;
+  private long      offset;
+
+  public ExceptionTableElement(OopHandle handle, long offset) {
+    this.handle = handle;
+    this.offset = offset;
+  }
+
+  public int getStartPC() {
+    return (int) handle.getCIntegerAt(offset + offsetOfStartPC, 2, true);
+  }
+
+  public int getEndPC() {
+    return (int) handle.getCIntegerAt(offset + offsetOfEndPC, 2, true);
+  }
+
+  public int getHandlerPC() {
+    return (int) handle.getCIntegerAt(offset + offsetOfHandlerPC, 2, true);
+  }
+
+  public int getCatchTypeIndex() {
+    return (int) handle.getCIntegerAt(offset + offsetOfCatchTypeIndex, 2, true);
+  }
+}
+
--- a/agent/src/share/classes/sun/jvm/hotspot/oops/GenerateOopMap.java	Fri Oct 14 03:13:25 2016 +0100
+++ b/agent/src/share/classes/sun/jvm/hotspot/oops/GenerateOopMap.java	Wed Nov 16 05:05:35 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -651,10 +651,11 @@
     boolean fellThrough = false;  // False to get first BB marked.
 
     // First mark all exception handlers as start of a basic-block
-    TypeArray excps = method().getExceptionTable();
-    for(int i = 0; i < excps.getLength(); i += 4) {
-      int handler_pc_idx = i+2;
-      markBB(excps.getIntAt(handler_pc_idx), null);
+    if (method().hasExceptionTable()) {
+      ExceptionTableElement[] excps = method().getExceptionTable();
+      for(int i = 0; i < excps.length; i++) {
+        markBB(excps[i].getHandlerPC(), null);
+      }
     }
 
     // Then iterate through the code
@@ -891,14 +892,15 @@
 
     // Mark entry basic block as alive and all exception handlers
     _basic_blocks[0].markAsAlive();
-    TypeArray excps = method().getExceptionTable();
-    for(int i = 0; i < excps.getLength(); i += 4) {
-      int handler_pc_idx = i+2;
-      BasicBlock bb = getBasicBlockAt(excps.getIntAt(handler_pc_idx));
-      // If block is not already alive (due to multiple exception handlers to same bb), then
-      // make it alive
-      if (bb.isDead())
-        bb.markAsAlive();
+    if (method().hasExceptionTable()) {
+      ExceptionTableElement[] excps = method().getExceptionTable();
+      for(int i = 0; i < excps.length; i ++) {
+        BasicBlock bb = getBasicBlockAt(excps[i].getHandlerPC());
+        // If block is not already alive (due to multiple exception handlers to same bb), then
+        // make it alive
+        if (bb.isDead())
+          bb.markAsAlive();
+      }
     }
 
     BytecodeStream bcs = new BytecodeStream(_method);
@@ -1468,12 +1470,12 @@
 
     if (_has_exceptions) {
       int bci = itr.bci();
-      TypeArray exct   = method().getExceptionTable();
-      for(int i = 0; i< exct.getLength(); i+=4) {
-        int start_pc   = exct.getIntAt(i);
-        int end_pc     = exct.getIntAt(i+1);
-        int handler_pc = exct.getIntAt(i+2);
-        int catch_type = exct.getIntAt(i+3);
+      ExceptionTableElement[] exct   = method().getExceptionTable();
+      for(int i = 0; i< exct.length; i++) {
+        int start_pc   = exct[i].getStartPC();
+        int end_pc     = exct[i].getEndPC();
+        int handler_pc = exct[i].getHandlerPC();
+        int catch_type = exct[i].getCatchTypeIndex();
 
         if (start_pc <= bci && bci < end_pc) {
           BasicBlock excBB = getBasicBlockAt(handler_pc);
@@ -2151,7 +2153,7 @@
     _conflict       = false;
     _max_locals     = (int) method().getMaxLocals();
     _max_stack      = (int) method().getMaxStack();
-    _has_exceptions = (method().getExceptionTable().getLength() > 0);
+    _has_exceptions = (method().hasExceptionTable());
     _nof_refval_conflicts = 0;
     _init_vars      = new ArrayList(5);  // There are seldom more than 5 init_vars
     _report_result  = false;
--- a/agent/src/share/classes/sun/jvm/hotspot/oops/Method.java	Fri Oct 14 03:13:25 2016 +0100
+++ b/agent/src/share/classes/sun/jvm/hotspot/oops/Method.java	Wed Nov 16 05:05:35 2016 +0000
@@ -127,7 +127,6 @@
   public ConstMethod  getConstMethod()                { return (ConstMethod)  constMethod.getValue(this);       }
   public ConstantPool getConstants()                  { return (ConstantPool) constants.getValue(this);         }
   public MethodData   getMethodData()                 { return (MethodData) methodData.getValue(this);          }
-  public TypeArray    getExceptionTable()             { return getConstMethod().getExceptionTable();            }
   /** WARNING: this is in words, not useful in this system; use getObjectSize() instead */
   public long         getMethodSize()                 { return                methodSize.getValue(this);        }
   public long         getMaxStack()                   { return                maxStack.getValue(this);          }
@@ -329,6 +328,14 @@
     return null;
   }
 
+  public boolean hasExceptionTable() {
+    return getConstMethod().hasExceptionTable();
+  }
+
+  public ExceptionTableElement[] getExceptionTable() {
+    return getConstMethod().getExceptionTable();
+  }
+
   public boolean hasCheckedExceptions() {
     return getConstMethod().hasCheckedExceptions();
   }
--- a/agent/src/share/classes/sun/jvm/hotspot/tools/jcore/ClassWriter.java	Fri Oct 14 03:13:25 2016 +0100
+++ b/agent/src/share/classes/sun/jvm/hotspot/tools/jcore/ClassWriter.java	Wed Nov 16 05:05:35 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -504,11 +504,14 @@
                             2           /* exp. table len.  */ +
                             2           /* code attr. count */;
 
-            TypeArray exceptionTable = m.getExceptionTable();
-            final int exceptionTableLen = (int) exceptionTable.getLength();
-            if (exceptionTableLen != 0) {
+            boolean hasExceptionTable = m.hasExceptionTable();
+            ExceptionTableElement[] exceptionTable = null;
+            int exceptionTableLen = 0;
+            if (hasExceptionTable) {
+                exceptionTable = m.getExceptionTable();
+                exceptionTableLen = exceptionTable.length;
                 if (DEBUG) debugMessage("\tmethod has exception table");
-                codeSize += (exceptionTableLen / 4) /* exception table is 4-tuple array */
+                codeSize += exceptionTableLen /* exception table is 4-tuple array */
                                          * (2 /* start_pc     */ +
                                             2 /* end_pc       */ +
                                             2 /* handler_pc   */ +
@@ -586,15 +589,15 @@
             dos.write(code);
 
             // write exception table size
-            dos.writeShort((short) (exceptionTableLen / 4));
-            if (DEBUG) debugMessage("\texception table length = " + (exceptionTableLen / 4));
+            dos.writeShort((short) exceptionTableLen);
+            if (DEBUG) debugMessage("\texception table length = " + exceptionTableLen);
 
             if (exceptionTableLen != 0) {
-                for (int e = 0; e < exceptionTableLen; e += 4) {
-                     dos.writeShort((short) exceptionTable.getIntAt(e));
-                     dos.writeShort((short) exceptionTable.getIntAt(e + 1));
-                     dos.writeShort((short) exceptionTable.getIntAt(e + 2));
-                     dos.writeShort((short) exceptionTable.getIntAt(e + 3));
+                for (int e = 0; e < exceptionTableLen; e++) {
+                     dos.writeShort((short) exceptionTable[e].getStartPC());
+                     dos.writeShort((short) exceptionTable[e].getEndPC());
+                     dos.writeShort((short) exceptionTable[e].getHandlerPC());
+                     dos.writeShort((short) exceptionTable[e].getCatchTypeIndex());
                 }
             }
 
--- a/agent/src/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java	Fri Oct 14 03:13:25 2016 +0100
+++ b/agent/src/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java	Wed Nov 16 05:05:35 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -783,37 +783,39 @@
                        });
 
          // display exception table for this method
-         TypeArray exceptionTable = method.getExceptionTable();
-         // exception table is 4 tuple array of shorts
-         int numEntries = (int)exceptionTable.getLength() / 4;
-         if (numEntries != 0) {
-            buf.h4("Exception Table");
-            buf.beginTable(1);
-            buf.beginTag("tr");
-            buf.headerCell("start bci");
-            buf.headerCell("end bci");
-            buf.headerCell("handler bci");
-            buf.headerCell("catch type");
-            buf.endTag("tr");
-
-            for (int e = 0; e < numEntries; e += 4) {
+         boolean hasException = method.hasExceptionTable();
+         if (hasException) {
+            ExceptionTableElement[] exceptionTable = method.getExceptionTable();
+            int numEntries = exceptionTable.length;
+            if (numEntries != 0) {
+               buf.h4("Exception Table");
+               buf.beginTable(1);
                buf.beginTag("tr");
-               buf.cell(Integer.toString(exceptionTable.getIntAt(e)));
-               buf.cell(Integer.toString(exceptionTable.getIntAt(e + 1)));
-               buf.cell(Integer.toString(exceptionTable.getIntAt(e + 2)));
-               short cpIndex = (short) exceptionTable.getIntAt(e + 3);
-               ConstantPool.CPSlot obj = cpIndex == 0? null : cpool.getSlotAt(cpIndex);
-               if (obj == null) {
-                  buf.cell("Any");
-               } else if (obj.isMetaData()) {
-                 buf.cell(obj.getSymbol().asString().replace('/', '.'));
-               } else {
-                 buf.cell(genKlassLink((InstanceKlass)obj.getOop()));
+               buf.headerCell("start bci");
+               buf.headerCell("end bci");
+               buf.headerCell("handler bci");
+               buf.headerCell("catch type");
+               buf.endTag("tr");
+
+               for (int e = 0; e < numEntries; e ++) {
+                  buf.beginTag("tr");
+                  buf.cell(Integer.toString(exceptionTable[e].getStartPC()));
+                  buf.cell(Integer.toString(exceptionTable[e].getEndPC()));
+                  buf.cell(Integer.toString(exceptionTable[e].getHandlerPC()));
+                  short cpIndex = (short) exceptionTable[e].getCatchTypeIndex();
+                  ConstantPool.CPSlot obj = cpIndex == 0? null : cpool.getSlotAt(cpIndex);
+                  if (obj == null) {
+                     buf.cell("Any");
+                  } else if (obj.isMetaData()) {
+                     buf.cell(obj.getSymbol().asString().replace('/', '.'));
+                  } else {
+                     buf.cell(genKlassLink((InstanceKlass)obj.getOop()));
+                  }
+                  buf.endTag("tr");
                }
-               buf.endTag("tr");
+
+               buf.endTable();
             }
-
-            buf.endTable();
          }
 
          // display constant pool hyperlink
--- a/src/share/vm/ci/ciMethod.cpp	Fri Oct 14 03:13:25 2016 +0100
+++ b/src/share/vm/ci/ciMethod.cpp	Wed Nov 16 05:05:35 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -79,7 +79,7 @@
   _max_locals         = h_m()->max_locals();
   _code_size          = h_m()->code_size();
   _intrinsic_id       = h_m()->intrinsic_id();
-  _handler_count      = h_m()->exception_table()->length() / 4;
+  _handler_count      = h_m()->exception_table_length();
   _uses_monitors      = h_m()->access_flags().has_monitor_bytecodes();
   _balanced_monitors  = !_uses_monitors || h_m()->access_flags().is_monitor_matching();
   _is_c1_compilable   = !h_m()->is_not_c1_compilable();
@@ -198,7 +198,7 @@
   }
 
   // And load the exception table.
-  typeArrayOop exc_table = me->exception_table();
+  ExceptionTable exc_table(me);
 
   // Allocate one extra spot in our list of exceptions.  This
   // last entry will be used to represent the possibility that
@@ -209,13 +209,12 @@
                                          * (_handler_count + 1));
   if (_handler_count > 0) {
     for (int i=0; i<_handler_count; i++) {
-      int base = i*4;
       _exception_handlers[i] = new (arena) ciExceptionHandler(
                                 holder(),
-            /* start    */      exc_table->int_at(base),
-            /* limit    */      exc_table->int_at(base+1),
-            /* goto pc  */      exc_table->int_at(base+2),
-            /* cp index */      exc_table->int_at(base+3));
+            /* start    */      exc_table.start_pc(i),
+            /* limit    */      exc_table.end_pc(i),
+            /* goto pc  */      exc_table.handler_pc(i),
+            /* cp index */      exc_table.catch_type_index(i));
     }
   }
 
--- a/src/share/vm/classfile/classFileParser.cpp	Fri Oct 14 03:13:25 2016 +0100
+++ b/src/share/vm/classfile/classFileParser.cpp	Wed Nov 16 05:05:35 2016 +0000
@@ -1246,42 +1246,38 @@
 }
 
 
-typeArrayHandle ClassFileParser::parse_exception_table(u4 code_length,
-                                                       u4 exception_table_length,
-                                                       constantPoolHandle cp,
-                                                       TRAPS) {
+u2* ClassFileParser::parse_exception_table(u4 code_length,
+                                           u4 exception_table_length,
+                                           constantPoolHandle cp,
+                                           TRAPS) {
   ClassFileStream* cfs = stream();
-  typeArrayHandle nullHandle;
-
-  // 4-tuples of ints [start_pc, end_pc, handler_pc, catch_type index]
-  typeArrayOop eh = oopFactory::new_permanent_intArray(exception_table_length*4, CHECK_(nullHandle));
-  typeArrayHandle exception_handlers = typeArrayHandle(THREAD, eh);
-
-  int index = 0;
-  cfs->guarantee_more(8 * exception_table_length, CHECK_(nullHandle)); // start_pc, end_pc, handler_pc, catch_type_index
-  for (unsigned int i = 0; i < exception_table_length; i++) {
-    u2 start_pc = cfs->get_u2_fast();
-    u2 end_pc = cfs->get_u2_fast();
-    u2 handler_pc = cfs->get_u2_fast();
-    u2 catch_type_index = cfs->get_u2_fast();
-    // Will check legal target after parsing code array in verifier.
-    if (_need_verify) {
+
+  u2* exception_table_start = cfs->get_u2_buffer();
+  assert(exception_table_start != NULL, "null exception table");
+  cfs->guarantee_more(8 * exception_table_length, CHECK_NULL); // start_pc, end_pc, handler_pc, catch_type_index
+  // Will check legal target after parsing code array in verifier.
+  if (_need_verify) {
+    for (unsigned int i = 0; i < exception_table_length; i++) {
+      u2 start_pc = cfs->get_u2_fast();
+      u2 end_pc = cfs->get_u2_fast();
+      u2 handler_pc = cfs->get_u2_fast();
+      u2 catch_type_index = cfs->get_u2_fast();
       guarantee_property((start_pc < end_pc) && (end_pc <= code_length),
-                         "Illegal exception table range in class file %s", CHECK_(nullHandle));
+                         "Illegal exception table range in class file %s",
+                         CHECK_NULL);
       guarantee_property(handler_pc < code_length,
-                         "Illegal exception table handler in class file %s", CHECK_(nullHandle));
+                         "Illegal exception table handler in class file %s",
+                         CHECK_NULL);
       if (catch_type_index != 0) {
         guarantee_property(valid_cp_range(catch_type_index, cp->length()) &&
                            is_klass_reference(cp, catch_type_index),
-                           "Catch type in exception table has bad constant type in class file %s", CHECK_(nullHandle));
+                           "Catch type in exception table has bad constant type in class file %s", CHECK_NULL);
       }
     }
-    exception_handlers->int_at_put(index++, start_pc);
-    exception_handlers->int_at_put(index++, end_pc);
-    exception_handlers->int_at_put(index++, handler_pc);
-    exception_handlers->int_at_put(index++, catch_type_index);
+  } else {
+    cfs->skip_u2_fast(exception_table_length * 4);
   }
-  return exception_handlers;
+  return exception_table_start;
 }
 
 void ClassFileParser::parse_linenumber_table(
@@ -1674,6 +1670,7 @@
   u4 code_length = 0;
   u1* code_start = 0;
   u2 exception_table_length = 0;
+  u2* exception_table_start = NULL;
   typeArrayHandle exception_handlers(THREAD, Universe::the_empty_int_array());
   u2 checked_exceptions_length = 0;
   u2* checked_exceptions_start = NULL;
@@ -1760,7 +1757,7 @@
       cfs->guarantee_more(2, CHECK_(nullHandle));  // exception_table_length
       exception_table_length = cfs->get_u2_fast();
       if (exception_table_length > 0) {
-        exception_handlers =
+        exception_table_start =
               parse_exception_table(code_length, exception_table_length, cp, CHECK_(nullHandle));
       }
 
@@ -1963,9 +1960,13 @@
   }
 
   // All sizing information for a methodOop is finally available, now create it
-  methodOop m_oop  = oopFactory::new_method(code_length, access_flags, linenumber_table_length,
-                                            total_lvt_length, checked_exceptions_length,
-                                            oopDesc::IsSafeConc, CHECK_(nullHandle));
+  methodOop m_oop  = oopFactory::new_method(code_length, access_flags,
+                                            linenumber_table_length,
+                                            total_lvt_length,
+                                            exception_table_length,
+                                            checked_exceptions_length,
+                                            oopDesc::IsSafeConc,
+                                            CHECK_(nullHandle));
   methodHandle m (THREAD, m_oop);
 
   ClassLoadingService::add_class_method_size(m_oop->size()*HeapWordSize);
@@ -1994,16 +1995,15 @@
   // Fill in code attribute information
   m->set_max_stack(max_stack);
   m->set_max_locals(max_locals);
-  m->constMethod()->set_stackmap_data(stackmap_data());
 
   /**
-   * The exception_table field is the flag used to indicate
+   * The stackmap_data field is the flag used to indicate
    * that the methodOop and it's associated constMethodOop are partially
    * initialized and thus are exempt from pre/post GC verification.  Once
    * the field is set, the oops are considered fully initialized so make
    * sure that the oops can pass verification when this field is set.
    */
-  m->set_exception_table(exception_handlers());
+  m->constMethod()->set_stackmap_data(stackmap_data());
 
   // Copy byte codes
   m->set_code(code_start);
@@ -2014,6 +2014,14 @@
            linenumber_table->buffer(), linenumber_table_length);
   }
 
+  // Copy exception table
+  if (exception_table_length > 0) {
+    int size =
+      exception_table_length * sizeof(ExceptionTableElement) / sizeof(u2);
+    copy_u2_with_conversion((u2*) m->exception_table_start(),
+                             exception_table_start, size);
+  }
+
   // Copy checked exceptions
   if (checked_exceptions_length > 0) {
     int size = checked_exceptions_length * sizeof(CheckedExceptionElement) / sizeof(u2);
--- a/src/share/vm/classfile/classFileParser.hpp	Fri Oct 14 03:13:25 2016 +0100
+++ b/src/share/vm/classfile/classFileParser.hpp	Wed Nov 16 05:05:35 2016 +0000
@@ -112,8 +112,8 @@
                                 objArrayHandle methods_parameter_annotations,
                                 objArrayHandle methods_default_annotations,
                                 TRAPS);
-  typeArrayHandle parse_exception_table(u4 code_length, u4 exception_table_length,
-                                        constantPoolHandle cp, TRAPS);
+  u2* parse_exception_table(u4 code_length, u4 exception_table_length,
+                            constantPoolHandle cp, TRAPS);
   void parse_linenumber_table(
       u4 code_attribute_length, u4 code_length,
       CompressedLineNumberWriteStream** write_stream, TRAPS);
--- a/src/share/vm/classfile/systemDictionary.cpp	Fri Oct 14 03:13:25 2016 +0100
+++ b/src/share/vm/classfile/systemDictionary.cpp	Wed Nov 16 05:05:35 2016 +0000
@@ -2802,7 +2802,6 @@
     nmethods++;
     method_size += m->size();
     // class loader uses same objArray for empty vectors, so don't count these
-    if (m->exception_table()->length() != 0)   method_size += m->exception_table()->size();
     if (m->has_stackmap_table()) {
       method_size += m->stackmap_data()->size();
     }
--- a/src/share/vm/classfile/verifier.cpp	Fri Oct 14 03:13:25 2016 +0100
+++ b/src/share/vm/classfile/verifier.cpp	Wed Nov 16 05:05:35 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -1369,47 +1369,48 @@
 }
 
 void ClassVerifier::verify_exception_handler_table(u4 code_length, char* code_data, int& min, int& max, TRAPS) {
-  typeArrayHandle exhandlers (THREAD, _method->exception_table());
+  ExceptionTable exhandlers(_method());
+  int exlength = exhandlers.length();
   constantPoolHandle cp (THREAD, _method->constants());
 
-  if (exhandlers() != NULL) {
-    for(int i = 0; i < exhandlers->length();) {
-      u2 start_pc = exhandlers->int_at(i++);
-      u2 end_pc = exhandlers->int_at(i++);
-      u2 handler_pc = exhandlers->int_at(i++);
-      if (start_pc >= code_length || code_data[start_pc] == 0) {
-        class_format_error("Illegal exception table start_pc %d", start_pc);
+  for(int i = 0; i < exlength; i++) {
+    //reacquire the table in case a GC happened
+    ExceptionTable exhandlers(_method());
+    u2 start_pc = exhandlers.start_pc(i);
+    u2 end_pc = exhandlers.end_pc(i);
+    u2 handler_pc = exhandlers.handler_pc(i);
+    if (start_pc >= code_length || code_data[start_pc] == 0) {
+      class_format_error("Illegal exception table start_pc %d", start_pc);
+      return;
+    }
+    if (end_pc != code_length) {   // special case: end_pc == code_length
+      if (end_pc > code_length || code_data[end_pc] == 0) {
+        class_format_error("Illegal exception table end_pc %d", end_pc);
         return;
       }
-      if (end_pc != code_length) {   // special case: end_pc == code_length
-        if (end_pc > code_length || code_data[end_pc] == 0) {
-          class_format_error("Illegal exception table end_pc %d", end_pc);
-          return;
-        }
-      }
-      if (handler_pc >= code_length || code_data[handler_pc] == 0) {
-        class_format_error("Illegal exception table handler_pc %d", handler_pc);
+    }
+    if (handler_pc >= code_length || code_data[handler_pc] == 0) {
+      class_format_error("Illegal exception table handler_pc %d", handler_pc);
+      return;
+    }
+    int catch_type_index = exhandlers.catch_type_index(i);
+    if (catch_type_index != 0) {
+      VerificationType catch_type = cp_index_to_type(
+        catch_type_index, cp, CHECK_VERIFY(this));
+      VerificationType throwable =
+        VerificationType::reference_type(vmSymbols::java_lang_Throwable());
+      bool is_subclass = throwable.is_assignable_from(
+        catch_type, this, CHECK_VERIFY(this));
+      if (!is_subclass) {
+        // 4286534: should throw VerifyError according to recent spec change
+        verify_error(
+          "Catch type is not a subclass of Throwable in handler %d",
+          handler_pc);
         return;
       }
-      int catch_type_index = exhandlers->int_at(i++);
-      if (catch_type_index != 0) {
-        VerificationType catch_type = cp_index_to_type(
-          catch_type_index, cp, CHECK_VERIFY(this));
-        VerificationType throwable =
-          VerificationType::reference_type(vmSymbols::java_lang_Throwable());
-        bool is_subclass = throwable.is_assignable_from(
-          catch_type, this, CHECK_VERIFY(this));
-        if (!is_subclass) {
-          // 4286534: should throw VerifyError according to recent spec change
-          verify_error(
-            "Catch type is not a subclass of Throwable in handler %d",
-            handler_pc);
-          return;
-        }
-      }
-      if (start_pc < min) min = start_pc;
-      if (end_pc > max) max = end_pc;
     }
+    if (start_pc < min) min = start_pc;
+    if (end_pc > max) max = end_pc;
   }
 }
 
@@ -1475,35 +1476,36 @@
 void ClassVerifier::verify_exception_handler_targets(u2 bci, bool this_uninit, StackMapFrame* current_frame,
                                                      StackMapTable* stackmap_table, TRAPS) {
   constantPoolHandle cp (THREAD, _method->constants());
-  typeArrayHandle exhandlers (THREAD, _method->exception_table());
-  if (exhandlers() != NULL) {
-    for(int i = 0; i < exhandlers->length();) {
-      u2 start_pc = exhandlers->int_at(i++);
-      u2 end_pc = exhandlers->int_at(i++);
-      u2 handler_pc = exhandlers->int_at(i++);
-      int catch_type_index = exhandlers->int_at(i++);
-      if(bci >= start_pc && bci < end_pc) {
-        u1 flags = current_frame->flags();
-        if (this_uninit) {  flags |= FLAG_THIS_UNINIT; }
-        StackMapFrame* new_frame = current_frame->frame_in_exception_handler(flags);
-        if (catch_type_index != 0) {
-          // We know that this index refers to a subclass of Throwable
-          VerificationType catch_type = cp_index_to_type(
-            catch_type_index, cp, CHECK_VERIFY(this));
-          new_frame->push_stack(catch_type, CHECK_VERIFY(this));
-        } else {
-          VerificationType throwable =
-            VerificationType::reference_type(vmSymbols::java_lang_Throwable());
-          new_frame->push_stack(throwable, CHECK_VERIFY(this));
-        }
-        bool match = stackmap_table->match_stackmap(
-          new_frame, handler_pc, true, false, true, CHECK_VERIFY(this));
-        if (!match) {
-          verify_error(bci,
-            "Stack map does not match the one at exception handler %d",
-            handler_pc);
-          return;
-        }
+  ExceptionTable exhandlers(_method());
+  int exlength = exhandlers.length();
+  for(int i = 0; i < exlength; i++) {
+    //reacquire the table in case a GC happened
+    ExceptionTable exhandlers(_method());
+    u2 start_pc = exhandlers.start_pc(i);
+    u2 end_pc = exhandlers.end_pc(i);
+    u2 handler_pc = exhandlers.handler_pc(i);
+    int catch_type_index = exhandlers.catch_type_index(i);
+    if(bci >= start_pc && bci < end_pc) {
+      u1 flags = current_frame->flags();
+      if (this_uninit) {  flags |= FLAG_THIS_UNINIT; }
+      StackMapFrame* new_frame = current_frame->frame_in_exception_handler(flags);
+      if (catch_type_index != 0) {
+        // We know that this index refers to a subclass of Throwable
+        VerificationType catch_type = cp_index_to_type(
+          catch_type_index, cp, CHECK_VERIFY(this));
+        new_frame->push_stack(catch_type, CHECK_VERIFY(this));
+      } else {
+        VerificationType throwable =
+          VerificationType::reference_type(vmSymbols::java_lang_Throwable());
+        new_frame->push_stack(throwable, CHECK_VERIFY(this));
+      }
+      bool match = stackmap_table->match_stackmap(
+        new_frame, handler_pc, true, false, true, CHECK_VERIFY(this));
+      if (!match) {
+        verify_error(bci,
+          "Stack map does not match the one at exception handler %d",
+          handler_pc);
+        return;
       }
     }
   }
@@ -1879,24 +1881,20 @@
 
 // Look at the method's handlers.  If the bci is in the handler's try block
 // then check if the handler_pc is already on the stack.  If not, push it.
-void ClassVerifier::push_handlers(typeArrayHandle exhandlers,
+void ClassVerifier::push_handlers(ExceptionTable* exhandlers,
                                   GrowableArray<u4>* handler_stack,
                                   u4 bci) {
   int exlength = exhandlers->length();
   for(int x = 0; x < exlength; x++) {
-    u2 start_pc = exhandlers->int_at(x++);
-    u2 end_pc = exhandlers->int_at(x++);
-    u2 handler_pc = exhandlers->int_at(x++);
-
-    if (bci >= start_pc && bci < end_pc) {
-      handler_stack->append_if_missing(handler_pc);
+    if (bci >= exhandlers->start_pc(x) && bci < exhandlers->end_pc(x)) {
+      handler_stack->append_if_missing(exhandlers->handler_pc(x));
     }
   }
 }
 
 // Return TRUE if all code paths starting with start_bc_offset end in
 // bytecode athrow or loop.
-bool ClassVerifier::ends_in_athrow(u4 start_bc_offset, TRAPS) {
+bool ClassVerifier::ends_in_athrow(u4 start_bc_offset) {
   ResourceMark rm;
   // Create bytecode stream.
   RawBytecodeStream bcs(method());
@@ -1909,7 +1907,7 @@
   GrowableArray<u4>* handler_stack = new GrowableArray<u4>(30);
   // Create list of visited branch opcodes (goto* and if*).
   GrowableArray<u4>* visited_branches = new GrowableArray<u4>(30);
-  typeArrayHandle exhandlers(THREAD, _method->exception_table());
+  ExceptionTable exhandlers(_method());
 
   while (true) {
     if (bcs.is_last_bytecode()) {
@@ -1925,7 +1923,7 @@
 
     // If the bytecode is in a TRY block, push its handlers so they
     // will get parsed.
-    push_handlers(exhandlers, handler_stack, bci);
+    push_handlers(&exhandlers, handler_stack, bci);
 
     switch (opcode) {
       case Bytecodes::_if_icmpeq:
@@ -2093,29 +2091,24 @@
     // sure that all catch clause paths end in a throw.  Otherwise, this can
     // result in returning an incomplete object.
     if (in_try_block) {
-      typeArrayHandle exhandlers (THREAD, _method->exception_table());
-      int exlength = exhandlers->length();
+      ExceptionTable exhandlers(_method());
+      int exlength = exhandlers.length();
       for(int i = 0; i < exlength; i++) {
-        /*
-         * Skip reading catch_type_index.
-         * Looks like this if you need all of them:
-         * u2 start_pc = exhandlers->int_at(i++);
-         * u2 end_pc = exhandlers->int_at(i++);
-         * u2 handler_pc = exhandlers->int_at(i++);
-         * int catch_type_index = exhandlers->int_at(i++);
-         */
         // Reacquire the table in case a GC happened
-        typeArrayHandle exhandlers (THREAD, _method->exception_table());
-        u2 start_pc = exhandlers->int_at(i++);
-        u2 end_pc = exhandlers->int_at(i++);
-        u2 handler_pc = exhandlers->int_at(i++);
+        ExceptionTable exhandlers(_method());
+        u2 start_pc = exhandlers.start_pc(i);
+        u2 end_pc = exhandlers.end_pc(i);
 
         if (bci >= start_pc && bci < end_pc) {
-          bool athrow_check = ends_in_athrow(handler_pc, CHECK_VERIFY(this));
-          if (!athrow_check) {
-            verify_error(
+          if (!ends_in_athrow(exhandlers.handler_pc(i))) {
+	    verify_error(
               "Bad <init> method call from after the start of a try block");
             return;
+          } else if (_verify_verbose) {
+            ResourceMark rm;
+            tty->print_cr(
+              "Survived call to ends_in_athrow(): %s",
+              current_class()->name()->as_C_string());
           }
         }
       }
--- a/src/share/vm/classfile/verifier.hpp	Fri Oct 14 03:13:25 2016 +0100
+++ b/src/share/vm/classfile/verifier.hpp	Wed Nov 16 05:05:35 2016 +0000
@@ -145,13 +145,13 @@
 
   // Used by ends_in_athrow() to push all handlers that contain bci onto
   // the handler_stack, if the handler is not already on the stack.
-  void push_handlers(typeArrayHandle exhandlers,
+  void push_handlers(ExceptionTable* exhandlers,
                      GrowableArray<u4>* handler_stack,
                      u4 bci);
 
   // Returns true if all paths starting with start_bc_offset end in athrow
   // bytecode or loop.
-  bool ends_in_athrow(u4 start_bc_offset, TRAPS);
+  bool ends_in_athrow(u4 start_bc_offset);
 
   void verify_invoke_instructions(
     RawBytecodeStream* bcs, u4 code_length, StackMapFrame* current_frame,
--- a/src/share/vm/interpreter/interpreterRuntime.cpp	Fri Oct 14 03:13:25 2016 +0100
+++ b/src/share/vm/interpreter/interpreterRuntime.cpp	Wed Nov 16 05:05:35 2016 +0000
@@ -375,7 +375,6 @@
   Handle             h_exception(thread, exception);
   methodHandle       h_method   (thread, method(thread));
   constantPoolHandle h_constants(thread, h_method->constants());
-  typeArrayHandle    h_extable  (thread, h_method->exception_table());
   bool               should_repeat;
   int                handler_bci;
   int                current_bci = bci(thread);
--- a/src/share/vm/memory/dump.cpp	Fri Oct 14 03:13:25 2016 +0100
+++ b/src/share/vm/memory/dump.cpp	Wed Nov 16 05:05:35 2016 +0000
@@ -231,8 +231,6 @@
     if (obj->is_constMethod()) {
       mark_object(obj);
       mark_object(constMethodOop(obj)->stackmap_data());
-      // Exception tables are needed by ci code during compilation.
-      mark_object(constMethodOop(obj)->exception_table());
     }
 
     // Mark objects referenced by klass objects which are read-only.
@@ -515,7 +513,6 @@
       for(i = 0; i < methods->length(); i++) {
         methodOop m = methodOop(methods->obj_at(i));
         mark_and_move_for_policy(OP_favor_startup, m->constMethod(), _move_ro);
-        mark_and_move_for_policy(OP_favor_runtime, m->constMethod()->exception_table(), _move_ro);
         mark_and_move_for_policy(OP_favor_runtime, m->constMethod()->stackmap_data(), _move_ro);
       }
 
--- a/src/share/vm/memory/oopFactory.cpp	Fri Oct 14 03:13:25 2016 +0100
+++ b/src/share/vm/memory/oopFactory.cpp	Wed Nov 16 05:05:35 2016 +0000
@@ -136,14 +136,15 @@
 constMethodOop oopFactory::new_constMethod(int byte_code_size,
                                            int compressed_line_number_size,
                                            int localvariable_table_length,
+                                           int exception_table_length,
                                            int checked_exceptions_length,
                                            bool is_conc_safe,
                                            TRAPS) {
   klassOop cmkObj = Universe::constMethodKlassObj();
   constMethodKlass* cmk = constMethodKlass::cast(cmkObj);
   return cmk->allocate(byte_code_size, compressed_line_number_size,
-                       localvariable_table_length, checked_exceptions_length,
-                       is_conc_safe,
+                       localvariable_table_length, exception_table_length,
+                       checked_exceptions_length, is_conc_safe,
                        CHECK_NULL);
 }
 
@@ -151,6 +152,7 @@
 methodOop oopFactory::new_method(int byte_code_size, AccessFlags access_flags,
                                  int compressed_line_number_size,
                                  int localvariable_table_length,
+                                 int exception_table_length,
                                  int checked_exceptions_length,
                                  bool is_conc_safe,
                                  TRAPS) {
@@ -160,6 +162,7 @@
   constMethodOop cm = new_constMethod(byte_code_size,
                                       compressed_line_number_size,
                                       localvariable_table_length,
+                                      exception_table_length,
                                       checked_exceptions_length,
                                       is_conc_safe, CHECK_NULL);
   constMethodHandle rw(THREAD, cm);
--- a/src/share/vm/memory/oopFactory.hpp	Fri Oct 14 03:13:25 2016 +0100
+++ b/src/share/vm/memory/oopFactory.hpp	Wed Nov 16 05:05:35 2016 +0000
@@ -84,6 +84,7 @@
   static constMethodOop  new_constMethod(int byte_code_size,
                                          int compressed_line_number_size,
                                          int localvariable_table_length,
+                                         int exception_table_length,
                                          int checked_exceptions_length,
                                          bool is_conc_safe,
                                          TRAPS);
@@ -95,6 +96,7 @@
                                     AccessFlags access_flags,
                                     int compressed_line_number_size,
                                     int localvariable_table_length,
+                                    int exception_table_length,
                                     int checked_exceptions_length,
                                     bool is_conc_safe,
                                     TRAPS);
--- a/src/share/vm/oops/constMethodKlass.cpp	Fri Oct 14 03:13:25 2016 +0100
+++ b/src/share/vm/oops/constMethodKlass.cpp	Wed Nov 16 05:05:35 2016 +0000
@@ -65,6 +65,7 @@
 constMethodOop constMethodKlass::allocate(int byte_code_size,
                                           int compressed_line_number_size,
                                           int localvariable_table_length,
+                                          int exception_table_length,
                                           int checked_exceptions_length,
                                           bool is_conc_safe,
                                           TRAPS) {
@@ -72,6 +73,7 @@
   int size = constMethodOopDesc::object_size(byte_code_size,
                                              compressed_line_number_size,
                                              localvariable_table_length,
+                                             exception_table_length,
                                              checked_exceptions_length);
   KlassHandle h_k(THREAD, as_klassOop());
   constMethodOop cm = (constMethodOop)
@@ -82,13 +84,13 @@
   cm->init_fingerprint();
   cm->set_method(NULL);
   cm->set_stackmap_data(NULL);
-  cm->set_exception_table(NULL);
   cm->set_code_size(byte_code_size);
   cm->set_constMethod_size(size);
   cm->set_result_type(T_VOID);
   cm->set_inlined_tables_length(checked_exceptions_length,
                                 compressed_line_number_size,
-                                localvariable_table_length);
+                                localvariable_table_length,
+                                exception_table_length);
   assert(cm->size() == size, "wrong size for object");
   cm->set_is_conc_safe(is_conc_safe);
   cm->set_partially_loaded();
@@ -101,7 +103,6 @@
   constMethodOop cm = constMethodOop(obj);
   MarkSweep::mark_and_push(cm->adr_method());
   MarkSweep::mark_and_push(cm->adr_stackmap_data());
-  MarkSweep::mark_and_push(cm->adr_exception_table());
   // Performance tweak: We skip iterating over the klass pointer since we
   // know that Universe::constMethodKlassObj never moves.
 }
@@ -113,7 +114,6 @@
   constMethodOop cm_oop = constMethodOop(obj);
   PSParallelCompact::mark_and_push(cm, cm_oop->adr_method());
   PSParallelCompact::mark_and_push(cm, cm_oop->adr_stackmap_data());
-  PSParallelCompact::mark_and_push(cm, cm_oop->adr_exception_table());
   // Performance tweak: We skip iterating over the klass pointer since we
   // know that Universe::constMethodKlassObj never moves.
 }
@@ -124,7 +124,6 @@
   constMethodOop cm = constMethodOop(obj);
   blk->do_oop(cm->adr_method());
   blk->do_oop(cm->adr_stackmap_data());
-  blk->do_oop(cm->adr_exception_table());
   // Get size before changing pointers.
   // Don't call size() or oop_size() since that is a virtual call.
   int size = cm->object_size();
@@ -140,8 +139,6 @@
   if (mr.contains(adr)) blk->do_oop(adr);
   adr = cm->adr_stackmap_data();
   if (mr.contains(adr)) blk->do_oop(adr);
-  adr = cm->adr_exception_table();
-  if (mr.contains(adr)) blk->do_oop(adr);
   // Get size before changing pointers.
   // Don't call size() or oop_size() since that is a virtual call.
   int size = cm->object_size();
@@ -156,7 +153,6 @@
   constMethodOop cm = constMethodOop(obj);
   MarkSweep::adjust_pointer(cm->adr_method());
   MarkSweep::adjust_pointer(cm->adr_stackmap_data());
-  MarkSweep::adjust_pointer(cm->adr_exception_table());
   // Get size before changing pointers.
   // Don't call size() or oop_size() since that is a virtual call.
   int size = cm->object_size();
@@ -191,7 +187,6 @@
   constMethodOop m = constMethodOop(obj);
   st->print(" - method:       " INTPTR_FORMAT " ", (address)m->method());
   m->method()->print_value_on(st); st->cr();
-  st->print(" - exceptions:   " INTPTR_FORMAT "\n", (address)m->exception_table());
   if (m->has_stackmap_table()) {
     st->print(" - stackmap data:       ");
     m->stackmap_data()->print_value_on(st);
@@ -229,8 +224,6 @@
     typeArrayOop stackmap_data = m->stackmap_data();
     guarantee(stackmap_data == NULL ||
               stackmap_data->is_perm(),  "should be in permspace");
-    guarantee(m->exception_table()->is_perm(), "should be in permspace");
-    guarantee(m->exception_table()->is_typeArray(), "should be type array");
 
     address m_end = (address)((oop*) m + m->size());
     address compressed_table_start = m->code_end();
@@ -245,11 +238,15 @@
       compressed_table_end += stream.position();
     }
     guarantee(compressed_table_end <= m_end, "invalid method layout");
-    // Verify checked exceptions and local variable tables
+    // Verify checked exceptions, exception table and local variable tables
     if (m->has_checked_exceptions()) {
       u2* addr = m->checked_exceptions_length_addr();
       guarantee(*addr > 0 && (address) addr >= compressed_table_end && (address) addr < m_end, "invalid method layout");
     }
+    if (m->has_exception_handler()) {
+      u2* addr = m->exception_table_length_addr();
+      guarantee(*addr > 0 && (address) addr >= compressed_table_end && (address) addr < m_end, "invalid method layout");
+    }
     if (m->has_localvariable_table()) {
       u2* addr = m->localvariable_table_length_addr();
       guarantee(*addr > 0 && (address) addr >= compressed_table_end && (address) addr < m_end, "invalid method layout");
@@ -258,12 +255,12 @@
     u2* uncompressed_table_start;
     if (m->has_localvariable_table()) {
       uncompressed_table_start = (u2*) m->localvariable_table_start();
-    } else {
-      if (m->has_checked_exceptions()) {
+    } else if (m->has_exception_handler()) {
+      uncompressed_table_start = (u2*) m->exception_table_start();
+    } else if (m->has_checked_exceptions()) {
         uncompressed_table_start = (u2*) m->checked_exceptions_start();
-      } else {
+    } else {
         uncompressed_table_start = (u2*) m_end;
-      }
     }
     int gap = (intptr_t) uncompressed_table_start - (intptr_t) compressed_table_end;
     int max_gap = align_object_size(1)*BytesPerWord;
@@ -274,8 +271,8 @@
 bool constMethodKlass::oop_partially_loaded(oop obj) const {
   assert(obj->is_constMethod(), "object must be klass");
   constMethodOop m = constMethodOop(obj);
-  // check whether exception_table points to self (flag for partially loaded)
-  return m->exception_table() == (typeArrayOop)obj;
+  // check whether stackmap_data points to self (flag for partially loaded)
+  return m->stackmap_data() == (typeArrayOop)obj;
 }
 
 
@@ -283,6 +280,6 @@
 void constMethodKlass::oop_set_partially_loaded(oop obj) {
   assert(obj->is_constMethod(), "object must be klass");
   constMethodOop m = constMethodOop(obj);
-  // Temporarily set exception_table to point to self
-  m->set_exception_table((typeArrayOop)obj);
+  // Temporarily set stackmap_data to point to self
+  m->set_stackmap_data((typeArrayOop)obj);
 }
--- a/src/share/vm/oops/constMethodKlass.hpp	Fri Oct 14 03:13:25 2016 +0100
+++ b/src/share/vm/oops/constMethodKlass.hpp	Wed Nov 16 05:05:35 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -46,6 +46,7 @@
   DEFINE_ALLOCATE_PERMANENT(constMethodKlass);
   constMethodOop allocate(int byte_code_size, int compressed_line_number_size,
                           int localvariable_table_length,
+                          int exception_table_length,
                           int checked_exceptions_length,
                           bool is_conc_safe,
                           TRAPS);
--- a/src/share/vm/oops/constMethodOop.cpp	Fri Oct 14 03:13:25 2016 +0100
+++ b/src/share/vm/oops/constMethodOop.cpp	Wed Nov 16 05:05:35 2016 +0000
@@ -35,6 +35,7 @@
 int constMethodOopDesc::object_size(int code_size,
                                     int compressed_line_number_size,
                                     int local_variable_table_length,
+                                    int exception_table_length,
                                     int checked_exceptions_length) {
   int extra_bytes = code_size;
   if (compressed_line_number_size > 0) {
@@ -49,6 +50,10 @@
     extra_bytes +=
               local_variable_table_length * sizeof(LocalVariableTableElement);
   }
+  if (exception_table_length > 0) {
+    extra_bytes += sizeof(u2);
+    extra_bytes += exception_table_length * sizeof(ExceptionTableElement);
+  }
   int extra_words = align_size_up(extra_bytes, BytesPerWord) / BytesPerWord;
   return align_object_size(header_size() + extra_words);
 }
@@ -69,23 +74,40 @@
   return last_u2_element();
 }
 
-u2* constMethodOopDesc::localvariable_table_length_addr() const {
-  assert(has_localvariable_table(), "called only if table is present");
+u2* constMethodOopDesc::exception_table_length_addr() const {
+  assert(has_exception_handler(), "called only if table is present");
   if (has_checked_exceptions()) {
     // If checked_exception present, locate immediately before them.
     return (u2*) checked_exceptions_start() - 1;
   } else {
-    // Else, the linenumber table is at the end of the constMethod.
+    // Else, the exception table is at the end of the constMethod.
     return last_u2_element();
   }
 }
 
+u2* constMethodOopDesc::localvariable_table_length_addr() const {
+  assert(has_localvariable_table(), "called only if table is present");
+  if (has_exception_handler()) {
+    // If exception_table present, locate immediately before them.
+    return (u2*) exception_table_start() - 1;
+  } else {
+    if (has_checked_exceptions()) {
+      // If checked_exception present, locate immediately before them.
+      return (u2*) checked_exceptions_start() - 1;
+    } else {
+      // Else, the linenumber table is at the end of the constMethod.
+      return last_u2_element();
+    }
+  }
+}
+
 
 // Update the flags to indicate the presence of these optional fields.
 void constMethodOopDesc::set_inlined_tables_length(
                                               int checked_exceptions_len,
                                               int compressed_line_number_size,
-                                              int localvariable_table_len) {
+                                              int localvariable_table_len,
+                                              int exception_table_len) {
   // Must be done in the order below, otherwise length_addr accessors
   // will not work. Only set bit in header if length is positive.
   assert(_flags == 0, "Error");
@@ -96,6 +118,10 @@
     _flags |= _has_checked_exceptions;
     *(checked_exceptions_length_addr()) = checked_exceptions_len;
   }
+  if (exception_table_len > 0) {
+    _flags |= _has_exception_table;
+    *(exception_table_length_addr()) = exception_table_len;
+  }
   if (localvariable_table_len > 0) {
     _flags |= _has_localvariable_table;
     *(localvariable_table_length_addr()) = localvariable_table_len;
@@ -129,3 +155,15 @@
   addr -= length * sizeof(LocalVariableTableElement) / sizeof(u2);
   return (LocalVariableTableElement*) addr;
 }
+
+int constMethodOopDesc::exception_table_length() const {
+  return has_exception_handler() ? *(exception_table_length_addr()) : 0;
+}
+
+ExceptionTableElement* constMethodOopDesc::exception_table_start() const {
+  u2* addr = exception_table_length_addr();
+  u2 length = *addr;
+  assert(length > 0, "should only be called if table is present");
+  addr -= length * sizeof(ExceptionTableElement) / sizeof(u2);
+  return (ExceptionTableElement*)addr;
+}
--- a/src/share/vm/oops/constMethodOop.hpp	Fri Oct 14 03:13:25 2016 +0100
+++ b/src/share/vm/oops/constMethodOop.hpp	Wed Nov 16 05:05:35 2016 +0000
@@ -43,7 +43,6 @@
 // | fingerprint 2                                        |
 // | method                         (oop)                 |
 // | stackmap_data                  (oop)                 |
-// | exception_table                (oop)                 |
 // | constMethod_size                                     |
 // | interp_kind  | flags    | code_size                  |
 // | name index              | signature index            |
@@ -64,7 +63,13 @@
 // |  (length is u2, elements are 6-tuples of u2)         |
 // |  (see class LocalVariableTableElement)               |
 // |  (access flags bit tells whether table is present)   |
-// |  (indexed from end of contMethodOop)                 |
+// |  (indexed from end of constMethodOop)                |
+// |------------------------------------------------------|
+// | exception table + length (length last)               |
+// |  (length is u2, elements are 4-tuples of u2)         |
+// |  (see class ExceptionTableElement)                   |
+// |  (access flags bit tells whether table is present)   |
+// |  (indexed from end of constMethodOop)                |
 // |------------------------------------------------------|
 // | checked exceptions elements + length (length last)   |
 // |  (length is u2, elements are u2)                     |
@@ -93,6 +98,15 @@
 };
 
 
+// Utitily class describing elements in exception table
+class ExceptionTableElement VALUE_OBJ_CLASS_SPEC {
+ public:
+  u2 start_pc;
+  u2 end_pc;
+  u2 handler_pc;
+  u2 catch_type_index;
+};
+
 class constMethodOopDesc : public oopDesc {
   friend class constMethodKlass;
   friend class VMStructs;
@@ -100,7 +114,8 @@
   enum {
     _has_linenumber_table = 1,
     _has_checked_exceptions = 2,
-    _has_localvariable_table = 4
+    _has_localvariable_table = 4,
+    _has_exception_table = 8
   };
 
   // Bit vector of signature
@@ -114,7 +129,7 @@
 
 public:
   oop* oop_block_beg() const { return adr_method(); }
-  oop* oop_block_end() const { return adr_exception_table() + 1; }
+  oop* oop_block_end() const { return adr_stackmap_data() + 1; }
 
 private:
   //
@@ -127,11 +142,6 @@
   // Raw stackmap data for the method
   typeArrayOop      _stackmap_data;
 
-  // The exception handler table. 4-tuples of ints [start_pc, end_pc,
-  // handler_pc, catch_type index] For methods with no exceptions the
-  // table is pointing to Universe::the_empty_int_array
-  typeArrayOop      _exception_table;
-
   //
   // End of the oop block.
   //
@@ -154,7 +164,8 @@
   // Inlined tables
   void set_inlined_tables_length(int checked_exceptions_len,
                                  int compressed_line_number_size,
-                                 int localvariable_table_len);
+                                 int localvariable_table_len,
+                                 int exception_table_len);
 
   bool has_linenumber_table() const
     { return (_flags & _has_linenumber_table) != 0; }
@@ -165,6 +176,9 @@
   bool has_localvariable_table() const
     { return (_flags & _has_localvariable_table) != 0; }
 
+  bool has_exception_handler() const
+    { return (_flags & _has_exception_table) != 0; }
+
   void set_interpreter_kind(int kind)      { _interpreter_kind = kind; }
   int  interpreter_kind(void) const        { return _interpreter_kind; }
 
@@ -180,11 +194,6 @@
   }
   bool has_stackmap_table() const { return _stackmap_data != NULL; }
 
-  // exception handler table
-  typeArrayOop exception_table() const           { return _exception_table; }
-  void set_exception_table(typeArrayOop e)       { oop_store_without_check((oop*) &_exception_table, (oop) e); }
-  bool has_exception_handler() const             { return exception_table() != NULL && exception_table()->length() > 0; }
-
   void init_fingerprint() {
     const uint64_t initval = CONST64(0x8000000000000000);
     _fingerprint = initval;
@@ -234,6 +243,7 @@
   // Object size needed
   static int object_size(int code_size, int compressed_line_number_size,
                          int local_variable_table_length,
+                         int exception_table_length,
                          int checked_exceptions_length);
 
   int object_size() const                 { return _constMethod_size; }
@@ -255,6 +265,7 @@
   u_char* compressed_linenumber_table() const;         // not preserved by gc
   u2* checked_exceptions_length_addr() const;
   u2* localvariable_table_length_addr() const;
+  u2* exception_table_length_addr() const;
 
   // checked exceptions
   int checked_exceptions_length() const;
@@ -264,6 +275,10 @@
   int localvariable_table_length() const;
   LocalVariableTableElement* localvariable_table_start() const;
 
+  // exception table
+  int exception_table_length() const;
+  ExceptionTableElement* exception_table_start() const;
+
   // byte codes
   void    set_code(address code) {
     if (code_size() > 0) {
@@ -279,8 +294,6 @@
                             { return in_ByteSize(sizeof(constMethodOopDesc)); }
 
   // interpreter support
-  static ByteSize exception_table_offset()
-               { return byte_offset_of(constMethodOopDesc, _exception_table); }
   static ByteSize result_type_offset()
                { return byte_offset_of(constMethodOopDesc, _result_type); }
   void set_result_type(BasicType rt) { assert(rt < 16, "result type too large");
@@ -289,7 +302,6 @@
   // Garbage collection support
   oop*  adr_method() const             { return (oop*)&_method;          }
   oop*  adr_stackmap_data() const      { return (oop*)&_stackmap_data;   }
-  oop*  adr_exception_table() const    { return (oop*)&_exception_table; }
   bool is_conc_safe() { return _is_conc_safe; }
   void set_is_conc_safe(bool v) { _is_conc_safe = v; }
 
--- a/src/share/vm/oops/generateOopMap.cpp	Fri Oct 14 03:13:25 2016 +0100
+++ b/src/share/vm/oops/generateOopMap.cpp	Wed Nov 16 05:05:35 2016 +0000
@@ -400,10 +400,9 @@
   bool fellThrough = false;  // False to get first BB marked.
 
   // First mark all exception handlers as start of a basic-block
-  typeArrayOop excps = method()->exception_table();
-  for(int i = 0; i < excps->length(); i += 4) {
-    int handler_pc_idx = i+2;
-    bb_mark_fct(this, excps->int_at(handler_pc_idx), NULL);
+  ExceptionTable excps(method());
+  for(int i = 0; i < excps.length(); i ++) {
+    bb_mark_fct(this, excps.handler_pc(i), NULL);
   }
 
   // Then iterate through the code
@@ -450,10 +449,9 @@
 
   // Mark entry basic block as alive and all exception handlers
   _basic_blocks[0].mark_as_alive();
-  typeArrayOop excps = method()->exception_table();
-  for(int i = 0; i < excps->length(); i += 4) {
-    int handler_pc_idx = i+2;
-    BasicBlock *bb = get_basic_block_at(excps->int_at(handler_pc_idx));
+  ExceptionTable excps(method());
+  for(int i = 0; i < excps.length(); i++) {
+    BasicBlock *bb = get_basic_block_at(excps.handler_pc(i));
     // If block is not already alive (due to multiple exception handlers to same bb), then
     // make it alive
     if (bb->is_dead()) bb->mark_as_alive();
@@ -1190,12 +1188,12 @@
 
   if (_has_exceptions) {
     int bci = itr->bci();
-    typeArrayOop exct  = method()->exception_table();
-    for(int i = 0; i< exct->length(); i+=4) {
-      int start_pc   = exct->int_at(i);
-      int end_pc     = exct->int_at(i+1);
-      int handler_pc = exct->int_at(i+2);
-      int catch_type = exct->int_at(i+3);
+    ExceptionTable exct(method());
+    for(int i = 0; i< exct.length(); i++) {
+      int start_pc   = exct.start_pc(i);
+      int end_pc     = exct.end_pc(i);
+      int handler_pc = exct.handler_pc(i);
+      int catch_type = exct.catch_type_index(i);
 
       if (start_pc <= bci && bci < end_pc) {
         BasicBlock *excBB = get_basic_block_at(handler_pc);
@@ -2064,7 +2062,7 @@
   _conflict       = false;
   _max_locals     = method()->max_locals();
   _max_stack      = method()->max_stack();
-  _has_exceptions = (method()->exception_table()->length() > 0);
+  _has_exceptions = (method()->has_exception_handler());
   _nof_refval_conflicts = 0;
   _init_vars      = new GrowableArray<intptr_t>(5);  // There are seldom more than 5 init_vars
   _report_result  = false;
@@ -2079,9 +2077,10 @@
     if (Verbose) {
       _method->print_codes();
       tty->print_cr("Exception table:");
-      typeArrayOop excps = method()->exception_table();
-      for(int i = 0; i < excps->length(); i += 4) {
-        tty->print_cr("[%d - %d] -> %d", excps->int_at(i + 0), excps->int_at(i + 1), excps->int_at(i + 2));
+      ExceptionTable excps(method());
+      for(int i = 0; i < excps.length(); i ++) {
+        tty->print_cr("[%d - %d] -> %d",
+                      excps.start_pc(i), excps.end_pc(i), excps.handler_pc(i));
       }
     }
   }
--- a/src/share/vm/oops/methodOop.cpp	Fri Oct 14 03:13:25 2016 +0100
+++ b/src/share/vm/oops/methodOop.cpp	Wed Nov 16 05:05:35 2016 +0000
@@ -111,25 +111,21 @@
 
 int  methodOopDesc::fast_exception_handler_bci_for(KlassHandle ex_klass, int throw_bci, TRAPS) {
   // exception table holds quadruple entries of the form (beg_bci, end_bci, handler_bci, klass_index)
-  const int beg_bci_offset     = 0;
-  const int end_bci_offset     = 1;
-  const int handler_bci_offset = 2;
-  const int klass_index_offset = 3;
-  const int entry_size         = 4;
   // access exception table
-  typeArrayHandle table (THREAD, constMethod()->exception_table());
-  int length = table->length();
-  assert(length % entry_size == 0, "exception table format has changed");
+  ExceptionTable table(this);
+  int length = table.length();
   // iterate through all entries sequentially
   constantPoolHandle pool(THREAD, constants());
-  for (int i = 0; i < length; i += entry_size) {
-    int beg_bci = table->int_at(i + beg_bci_offset);
-    int end_bci = table->int_at(i + end_bci_offset);
+  for (int i = 0; i < length; i ++) {
+    //reacquire the table in case a GC happened
+    ExceptionTable table(this);
+    int beg_bci = table.start_pc(i);
+    int end_bci = table.end_pc(i);
     assert(beg_bci <= end_bci, "inconsistent exception table");
     if (beg_bci <= throw_bci && throw_bci < end_bci) {
       // exception handler bci range covers throw_bci => investigate further
-      int handler_bci = table->int_at(i + handler_bci_offset);
-      int klass_index = table->int_at(i + klass_index_offset);
+      int handler_bci = table.handler_pc(i);
+      int klass_index = table.catch_type_index(i);
       if (klass_index == 0) {
         return handler_bci;
       } else if (ex_klass.is_null()) {
@@ -978,7 +974,7 @@
   {
     int flags_bits = (JVM_MH_INVOKE_BITS | JVM_ACC_PUBLIC | JVM_ACC_FINAL);
     methodOop m_oop = oopFactory::new_method(0, accessFlags_from(flags_bits),
-                                             0, 0, 0, IsSafeConc, CHECK_(empty));
+                                             0, 0, 0, 0, IsSafeConc, CHECK_(empty));
     m = methodHandle(THREAD, m_oop);
   }
   m->set_constants(cp());
@@ -992,7 +988,6 @@
   m->set_result_index(rtf.type());
 #endif
   m->compute_size_of_parameters(THREAD);
-  m->set_exception_table(Universe::the_empty_int_array());
   m->init_intrinsic_id();
   assert(m->intrinsic_id() == vmIntrinsics::_invokeExact ||
          m->intrinsic_id() == vmIntrinsics::_invokeGeneric, "must be an invoker");
@@ -1036,6 +1031,7 @@
   AccessFlags flags = m->access_flags();
   int checked_exceptions_len = m->checked_exceptions_length();
   int localvariable_len = m->localvariable_table_length();
+  int exception_table_len = m->exception_table_length();
   // Allocate newm_oop with the is_conc_safe parameter set
   // to IsUnsafeConc to indicate that newm_oop is not yet
   // safe for concurrent processing by a GC.
@@ -1043,6 +1039,7 @@
                                               flags,
                                               new_compressed_linenumber_size,
                                               localvariable_len,
+                                              exception_table_len,
                                               checked_exceptions_len,
                                               IsUnsafeConc,
                                               CHECK_(methodHandle()));
--- a/src/share/vm/oops/methodOop.hpp	Fri Oct 14 03:13:25 2016 +0100
+++ b/src/share/vm/oops/methodOop.hpp	Wed Nov 16 05:05:35 2016 +0000
@@ -284,12 +284,12 @@
   }
 
   // exception handler table
-  typeArrayOop exception_table() const
-                                   { return constMethod()->exception_table(); }
-  void set_exception_table(typeArrayOop e)
-                                     { constMethod()->set_exception_table(e); }
   bool has_exception_handler() const
                              { return constMethod()->has_exception_handler(); }
+  int exception_table_length() const
+                             { return constMethod()->exception_table_length(); }
+  ExceptionTableElement* exception_table_start() const
+                             { return constMethod()->exception_table_start(); }
 
   // Finds the first entry point bci of an exception handler for an
   // exception of klass ex_klass thrown at throw_bci. A value of NULL
@@ -839,4 +839,66 @@
   void clear(methodOop method);
 };
 
+// Utility class for access exception handlers
+class ExceptionTable : public StackObj {
+ private:
+  ExceptionTableElement* _table;
+  u2  _length;
+
+ public:
+  ExceptionTable(methodOop m) {
+    if (m->has_exception_handler()) {
+      _table = m->exception_table_start();
+      _length = m->exception_table_length();
+    } else {
+      _table = NULL;
+      _length = 0;
+    }
+  }
+
+  int length() const {
+    return _length;
+  }
+
+  u2 start_pc(int idx) const {
+    assert(idx < _length, "out of bounds");
+    return _table[idx].start_pc;
+  }
+
+  void set_start_pc(int idx, u2 value) {
+    assert(idx < _length, "out of bounds");
+    _table[idx].start_pc = value;
+  }
+
+  u2 end_pc(int idx) const {
+    assert(idx < _length, "out of bounds");
+    return _table[idx].end_pc;
+  }
+
+  void set_end_pc(int idx, u2 value) {
+    assert(idx < _length, "out of bounds");
+    _table[idx].end_pc = value;
+  }
+
+  u2 handler_pc(int idx) const {
+    assert(idx < _length, "out of bounds");
+    return _table[idx].handler_pc;
+  }
+
+  void set_handler_pc(int idx, u2 value) {
+    assert(idx < _length, "out of bounds");
+    _table[idx].handler_pc = value;
+  }
+
+  u2 catch_type_index(int idx) const {
+    assert(idx < _length, "out of bounds");
+    return _table[idx].catch_type_index;
+  }
+
+  void set_catch_type_index(int idx, u2 value) {
+    assert(idx < _length, "out of bounds");
+    _table[idx].catch_type_index = value;
+  }
+};
+
 #endif // SHARE_VM_OOPS_METHODOOP_HPP
--- a/src/share/vm/prims/jvm.cpp	Fri Oct 14 03:13:25 2016 +0100
+++ b/src/share/vm/prims/jvm.cpp	Wed Nov 16 05:05:35 2016 +0000
@@ -35,6 +35,7 @@
 #include "oops/fieldStreams.hpp"
 #include "oops/instanceKlass.hpp"
 #include "oops/objArrayKlass.hpp"
+#include "oops/methodOop.hpp"
 #include "prims/jvm.h"
 #include "prims/jvm_misc.hpp"
 #include "prims/jvmtiExport.hpp"
@@ -2292,11 +2293,11 @@
   klassOop k = java_lang_Class::as_klassOop(JNIHandles::resolve_non_null(cls));
   k = JvmtiThreadState::class_to_verify_considering_redefinition(k, thread);
   oop method = instanceKlass::cast(k)->methods()->obj_at(method_index);
-  typeArrayOop extable = methodOop(method)->exception_table();
-  entry->start_pc   = extable->int_at(entry_index * 4);
-  entry->end_pc     = extable->int_at(entry_index * 4 + 1);
-  entry->handler_pc = extable->int_at(entry_index * 4 + 2);
-  entry->catchType  = extable->int_at(entry_index * 4 + 3);
+  ExceptionTable extable((methodOop(method)));
+  entry->start_pc   = extable.start_pc(entry_index);
+  entry->end_pc     = extable.end_pc(entry_index);
+  entry->handler_pc = extable.handler_pc(entry_index);
+  entry->catchType  = extable.catch_type_index(entry_index);
 JVM_END
 
 
@@ -2305,7 +2306,7 @@
   klassOop k = java_lang_Class::as_klassOop(JNIHandles::resolve_non_null(cls));
   k = JvmtiThreadState::class_to_verify_considering_redefinition(k, thread);
   oop method = instanceKlass::cast(k)->methods()->obj_at(method_index);
-  return methodOop(method)->exception_table()->length() / 4;
+  return methodOop(method)->exception_table_length();
 JVM_END
 
 
--- a/src/share/vm/prims/jvmtiClassFileReconstituter.cpp	Fri Oct 14 03:13:25 2016 +0100
+++ b/src/share/vm/prims/jvmtiClassFileReconstituter.cpp	Wed Nov 16 05:05:35 2016 +0000
@@ -191,15 +191,14 @@
     }
   }
 
-  typeArrayHandle exception_table(thread(), const_method->exception_table());
-  int exception_table_length = exception_table->length();
-  int exception_table_entries = exception_table_length / 4;
+  ExceptionTable exception_table(method());
+  int exception_table_length = exception_table.length();
   int code_size = const_method->code_size();
   int size =
     2+2+4 +                                // max_stack, max_locals, code_length
     code_size +                            // code
     2 +                                    // exception_table_length
-    (2+2+2+2) * exception_table_entries +  // exception_table
+    (2+2+2+2) * exception_table_length +   // exception_table
     2 +                                    // attributes_count
     attr_size;                             // attributes
 
@@ -209,12 +208,12 @@
   write_u2(method->max_locals());
   write_u4(code_size);
   copy_bytecodes(method, (unsigned char*)writeable_address(code_size));
-  write_u2(exception_table_entries);
-  for (int index = 0; index < exception_table_length; ) {
-    write_u2(exception_table->int_at(index++));
-    write_u2(exception_table->int_at(index++));
-    write_u2(exception_table->int_at(index++));
-    write_u2(exception_table->int_at(index++));
+  write_u2(exception_table_length);
+  for (int index = 0; index < exception_table_length; index++) {
+    write_u2(exception_table.start_pc(index));
+    write_u2(exception_table.end_pc(index));
+    write_u2(exception_table.handler_pc(index));
+    write_u2(exception_table.catch_type_index(index));
   }
   write_u2(attr_count);
   if (line_num_cnt != 0) {
--- a/src/share/vm/prims/jvmtiRedefineClasses.cpp	Fri Oct 14 03:13:25 2016 +0100
+++ b/src/share/vm/prims/jvmtiRedefineClasses.cpp	Wed Nov 16 05:05:35 2016 +0000
@@ -2496,23 +2496,17 @@
     // to use new constant pool indices as needed. The exception table
     // holds quadruple entries of the form:
     //   (beg_bci, end_bci, handler_bci, klass_index)
-    const int beg_bci_offset     = 0;
-    const int end_bci_offset     = 1;
-    const int handler_bci_offset = 2;
-    const int klass_index_offset = 3;
-    const int entry_size         = 4;
-
-    typeArrayHandle ex_table (THREAD, method->exception_table());
-    int ext_length = ex_table->length();
-    assert(ext_length % entry_size == 0, "exception table format has changed");
-
-    for (int j = 0; j < ext_length; j += entry_size) {
-      int cur_index = ex_table->int_at(j + klass_index_offset);
+
+    ExceptionTable ex_table(method());
+    int ext_length = ex_table.length();
+
+    for (int j = 0; j < ext_length; j ++) {
+      int cur_index = ex_table.catch_type_index(j);
       int new_index = find_new_index(cur_index);
       if (new_index != 0) {
         RC_TRACE_WITH_THREAD(0x00080000, THREAD,
           ("ext-klass_index change: %d to %d", cur_index, new_index));
-        ex_table->int_at_put(j + klass_index_offset, new_index);
+        ex_table.set_catch_type_index(j, new_index);
       }
     } // end for each exception table entry
 
--- a/src/share/vm/prims/methodHandleWalk.cpp	Fri Oct 14 03:13:25 2016 +0100
+++ b/src/share/vm/prims/methodHandleWalk.cpp	Wed Nov 16 05:05:35 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -1796,7 +1796,7 @@
   {
     methodOop m_oop = oopFactory::new_method(bytecode_length(),
                                              accessFlags_from(flags_bits),
-                                             0, 0, 0, oopDesc::IsSafeConc, CHECK_(empty));
+                                             0, 0, 0, 0, oopDesc::IsSafeConc, CHECK_(empty));
     m = methodHandle(THREAD, m_oop);
   }
 
@@ -1812,9 +1812,6 @@
   m->set_max_locals(max_locals());
   m->set_size_of_parameters(_num_params);
 
-  typeArrayHandle exception_handlers(THREAD, Universe::the_empty_int_array());
-  m->set_exception_table(exception_handlers());
-
   // Rewrite the method and set up the constant pool cache.
   objArrayOop m_array = oopFactory::new_system_objArray(1, CHECK_(empty));
   objArrayHandle methods(THREAD, m_array);
--- a/src/share/vm/runtime/relocator.cpp	Fri Oct 14 03:13:25 2016 +0100
+++ b/src/share/vm/runtime/relocator.cpp	Wed Nov 16 05:05:35 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -392,16 +392,16 @@
 // The width of instruction at "pc" is changing by "delta".  Adjust the
 // exception table, if any, of "rc->mb".
 void Relocator::adjust_exception_table(int bci, int delta) {
-  typeArrayOop table = method()->exception_table();
-  for (int index = 0; index < table->length(); index +=4) {
-    if (table->int_at(index) > bci) {
-      table->int_at_put(index+0, table->int_at(index+0) + delta);
-      table->int_at_put(index+1, table->int_at(index+1) + delta);
-    } else if (bci < table->int_at(index+1)) {
-      table->int_at_put(index+1, table->int_at(index+1) + delta);
+  ExceptionTable table(_method());
+  for (int index = 0; index < table.length(); index ++) {
+    if (table.start_pc(index) > bci) {
+      table.set_start_pc(index, table.start_pc(index) + delta);
+      table.set_end_pc(index, table.end_pc(index) + delta);
+    } else if (bci < table.end_pc(index)) {
+      table.set_end_pc(index, table.end_pc(index) + delta);
     }
-    if (table->int_at(index+2) > bci)
-      table->int_at_put(index+2, table->int_at(index+2) + delta);
+    if (table.handler_pc(index) > bci)
+      table.set_handler_pc(index, table.handler_pc(index) + delta);
   }
 }
 
--- a/src/share/vm/runtime/vmStructs.cpp	Fri Oct 14 03:13:25 2016 +0100
+++ b/src/share/vm/runtime/vmStructs.cpp	Wed Nov 16 05:05:35 2016 +0000
@@ -383,7 +383,6 @@
   volatile_nonstatic_field(constMethodOopDesc, _fingerprint,                                  uint64_t)                              \
   nonstatic_field(constMethodOopDesc,          _method,                                       methodOop)                             \
   nonstatic_field(constMethodOopDesc,          _stackmap_data,                                typeArrayOop)                          \
-  nonstatic_field(constMethodOopDesc,          _exception_table,                              typeArrayOop)                          \
   nonstatic_field(constMethodOopDesc,          _constMethod_size,                             int)                                   \
   nonstatic_field(constMethodOopDesc,          _interpreter_kind,                             jbyte)                                 \
   nonstatic_field(constMethodOopDesc,          _flags,                                        jbyte)                                 \
@@ -420,6 +419,10 @@
   nonstatic_field(LocalVariableTableElement,   descriptor_cp_index,                           u2)                                    \
   nonstatic_field(LocalVariableTableElement,   signature_cp_index,                            u2)                                    \
   nonstatic_field(LocalVariableTableElement,   slot,                                          u2)                                    \
+  nonstatic_field(ExceptionTableElement,       start_pc,                                      u2)                                    \
+  nonstatic_field(ExceptionTableElement,       end_pc,                                        u2)                                    \
+  nonstatic_field(ExceptionTableElement,       handler_pc,                                    u2)                                    \
+  nonstatic_field(ExceptionTableElement,       catch_type_index,                              u2)                                    \
   nonstatic_field(BreakpointInfo,              _orig_bytecode,                                Bytecodes::Code)                       \
   nonstatic_field(BreakpointInfo,              _bci,                                          int)                                   \
   nonstatic_field(BreakpointInfo,              _name_index,                                   u2)                                    \
@@ -1456,6 +1459,7 @@
                                                                           \
   declare_toplevel_type(CheckedExceptionElement)                          \
   declare_toplevel_type(LocalVariableTableElement)                        \
+  declare_toplevel_type(ExceptionTableElement)                            \
                                                                           \
   /******************************************/                            \
   /* Generation and space hierarchies       */                            \
@@ -2340,6 +2344,7 @@
   declare_constant(constMethodOopDesc::_has_linenumber_table)             \
   declare_constant(constMethodOopDesc::_has_checked_exceptions)           \
   declare_constant(constMethodOopDesc::_has_localvariable_table)          \
+  declare_constant(constMethodOopDesc::_has_exception_table)              \
                                                                           \
   /*************************************/                                 \
   /* instanceKlass enum                */                                 \