< prev index next >

src/java.base/share/classes/jdk/internal/foreign/abi/x64/windows/CallingSequenceBuilderImpl.java

Print this page




   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 package jdk.internal.foreign.abi.x64.windows;
  24 
  25 import jdk.internal.foreign.Util;
  26 import jdk.internal.foreign.abi.*;
  27 import jdk.internal.foreign.abi.x64.CallingSequenceBuilder;
  28 import jdk.internal.foreign.abi.x64.ArgumentClass;
  29 import jdk.internal.foreign.abi.x64.SharedConstants;
  30 
  31 import java.foreign.layout.*;
  32 import java.util.ArrayList;
  33 import java.util.HashSet;
  34 import java.util.List;
  35 import java.util.Set;
  36 
  37 import static sun.security.action.GetBooleanAction.privilegedGetProperty;
  38 
  39 class CallingSequenceBuilderImpl extends CallingSequenceBuilder {
  40     private static final String[] INTEGER_ARGUMENT_REGISTER_NAMES = { "rcx", "rdx", "r8", "r9" };
  41     private static final String[] INTEGER_RETURN_REGISTERS_NAMES = { "rax" };
  42     private static final String[] X87_RETURN_REGISTERS_NAMES = { }; // TODO find out if Windows ABI actually uses these





  43 
  44     private static final boolean DEBUG =
  45             privilegedGetProperty("jdk.internal.foreign.abi.windows.x64.DEBUG");
  46 
  47     private int curArgIndex = 0;
  48 
  49     private final Argument returned;
  50     private final List<Argument> arguments = new ArrayList<>();;
  51     private final Set<Argument> varargs = new HashSet<>();
  52 
  53     public CallingSequenceBuilderImpl(Argument returned) {
  54         super(INTEGER_ARGUMENT_REGISTER_NAMES, INTEGER_RETURN_REGISTERS_NAMES, X87_RETURN_REGISTERS_NAMES,
  55                 Constants.MAX_VECTOR_ARGUMENT_REGISTERS, Constants.MAX_VECTOR_RETURN_REGISTERS);
  56         this.returned = returned;
  57     }
  58 
  59     public void addArgument(Layout type, boolean isVarArg, String name) {
  60         Argument arg = new Argument(curArgIndex++, type, name);
  61         arguments.add(arg);
  62         if(isVarArg) {
  63             varargs.add(arg);
  64         }




  65     }
  66 
  67     static class ArgumentInfo {
  68         private final List<ArgumentClass> classes;
  69         private final int nRegs;
  70         private final boolean inMemory;
  71 
  72         public ArgumentInfo(List<ArgumentClass> classes, int nRegs) {
  73             this.classes = classes;
  74 
  75             this.inMemory = false;
  76             this.nRegs = nRegs;

  77         }
  78 
  79         public ArgumentInfo(int n) {
  80             this.classes = new ArrayList<>();
  81             for (int i = 0; i < n; i++) {
  82                 classes.add(ArgumentClass.MEMORY);
  83             }
  84 
  85             this.inMemory = true;
  86             this.nRegs = 0;

  87         }
  88 
  89         public int getRegs() {
  90             return nRegs;


  91         }
  92 
  93         public boolean inMemory() {
  94             return inMemory;

  95         }
  96 
  97         public List<ArgumentClass> getClasses() {
  98             return classes;
  99         }
 100     }
 101 
 102     static List<ArgumentClass> classifyValueType(Value type) {
 103         ArrayList<ArgumentClass> classes = new ArrayList<>();
 104 
 105         switch (type.kind()) {
 106             case INTEGRAL_SIGNED: case INTEGRAL_UNSIGNED:
 107                 classes.add(ArgumentClass.INTEGER);
 108                 // int128
 109                 long left = (type.bitsSize() / 8) - 8;
 110                 while (left > 0) {
 111                     classes.add(ArgumentClass.INTEGER);
 112                     left -= 8;
 113                 }
 114                 return classes;


 118                     classes.add(ArgumentClass.X87UP);
 119                     return classes;
 120                 } else {
 121                     classes.add(ArgumentClass.SSE);
 122                     return classes;
 123                 }
 124             default:
 125                 throw new IllegalArgumentException("Type " + type + " is not yet supported");
 126         }
 127     }
 128 
 129     static boolean isRegisterAggregate(Layout type) {
 130         // FIXME handle bit size 1, 2, 4
 131         long size = type.bitsSize() / 8;
 132         return size == 1
 133             || size == 2
 134             || size == 4
 135             || size == 8;
 136     }
 137     
 138     private List<ArgumentClass> createMemoryClassArray(long n) {
 139         ArrayList<ArgumentClass> classes = new ArrayList<>();
 140         for (int i = 0; i < n; i++) {
 141             classes.add(ArgumentClass.MEMORY);
 142         }
 143 
 144         return classes;
 145     }
 146 
 147     private List<ArgumentClass> classifyStructType(Group type, boolean isReturn) {
 148         ArrayList<ArgumentClass> classes = new ArrayList<>();
 149         
 150         if(isRegisterAggregate(type)) {
 151             classes.add(ArgumentClass.INTEGER);
 152         } else {
 153             if(isReturn) {
 154                 return createMemoryClassArray(Util.alignUp((type.bitsSize() / 8), 8));
 155             } else {
 156                 classes.add(ArgumentClass.INTEGER);
 157             }
 158         }
 159 
 160         return classes;
 161     }
 162 
 163     private List<ArgumentClass> classifyType(Layout type, boolean isReturn) {
 164         if (type instanceof Value) {
 165             return classifyValueType((Value) type);
 166         } else if (type instanceof Address) {
 167             ArrayList<ArgumentClass> classes = new ArrayList<>();
 168             classes.add(ArgumentClass.INTEGER);
 169             return classes;
 170         } else if (type instanceof Sequence) {
 171             ArrayList<ArgumentClass> classes = new ArrayList<>();
 172             classes.add(ArgumentClass.INTEGER); // arrrays are always passed as pointers
 173             return classes;
 174         } else if (type instanceof Group) {
 175             return classifyStructType((Group) type, isReturn);
 176         } else {
 177             throw new IllegalArgumentException("Unhandled type " + type);
 178         }
 179     }
 180 
 181     private ArgumentInfo examineArgument(Layout type, boolean isReturn) {
 182         List<ArgumentClass> classes = classifyType(type, isReturn);
 183         if (classes.isEmpty()) {
 184             return null;
 185         }
 186 
 187         int nRegs = 0;
 188 
 189         for (ArgumentClass c : classes) {
 190             switch (c) {
 191             case INTEGER:
 192             case SSE:
 193                 nRegs++;
 194                 break;
 195             case X87:
 196             case X87UP:
 197                 return new ArgumentInfo(classes.size());
 198             default:
 199                 break;
 200             }
 201         }
 202 
 203         if (nRegs != 0) {
 204             return new ArgumentInfo(classes, nRegs);
 205         } else {
 206             return new ArgumentInfo(classes.size());
 207         }
 208     }
 209 
 210     class StorageCalculator {
 211         private final ArrayList<ArgumentBinding>[] bindings;
 212         private final boolean forArguments;
 213 
 214         private int nRegs = 0;
 215         private long stackOffset = 0;
 216 
 217         StorageCalculator(ArrayList<ArgumentBinding>[] bindings, boolean forArguments) {
 218             this.bindings = bindings;
 219             this.forArguments = forArguments;
 220         }
 221 
 222         void addBindings(Argument arg, ArgumentInfo info) {

 223             if (info.inMemory() ||
 224                 nRegs + info.getRegs() > (forArguments ? Constants.MAX_REGISTER_ARGUMENTS : Constants.MAX_REGISTER_RETURNS)) {
 225                 // stack
 226 
 227                 long alignment = Math.max(alignment(arg.getType(), true), 8);
 228 
 229                 long newStackOffset = Util.alignUp(stackOffset, alignment);
 230 
 231                 // fill holes on stack with nulls
 232                 for (int i = 0; i < (newStackOffset - stackOffset) / 8; i++) {
 233                     bindings[StorageClass.STACK_ARGUMENT_SLOT.ordinal()].add(null);
 234                 }
 235                 stackOffset = newStackOffset;
 236 
 237                 long tmpStackOffset = stackOffset;
 238                 for (int i = 0; i < info.getClasses().size(); i++) {
 239                     Storage storage = new Storage(StorageClass.STACK_ARGUMENT_SLOT, tmpStackOffset / 8, 8);
 240                     bindings[StorageClass.STACK_ARGUMENT_SLOT.ordinal()].add(new ArgumentBinding(storage, arg, i * 8));
 241 
 242                     if (DEBUG) {
 243                         System.out.println("Argument " + arg.getName() + " will be passed on stack at offset " + tmpStackOffset);
 244                     }
 245 
 246                     tmpStackOffset += 8;
 247                 }
 248 
 249                 stackOffset += arg.getType().bitsSize() / 8;
 250             } else {
 251                 // regs
 252                 for (int i = 0; i < info.getClasses().size(); i++) {
 253                     Storage storage;
 254 
 255                     ArgumentClass c = info.getClasses().get(i);
 256 
 257                     switch (c) {
 258                     case INTEGER:
 259                         storage = new Storage(forArguments ? StorageClass.INTEGER_ARGUMENT_REGISTER : StorageClass.INTEGER_RETURN_REGISTER, nRegs++, SharedConstants.INTEGER_REGISTER_SIZE);
 260                         bindings[storage.getStorageClass().ordinal()].add(new ArgumentBinding(storage, arg, i * 8));
 261 
 262                         if (DEBUG) {
 263                             System.out.println("Argument " + arg.getName() + " will be passed in register " + getStorageName(storage));

 264                         }
 265                         break;
 266 
 267                     case SSE:
 268                         int width = 8;
 269 
 270                         for (int j = i + 1; j < info.getClasses().size(); j++) {
 271                             if (info.getClasses().get(j) == ArgumentClass.SSEUP) {
 272                                 width += 8;
 273                             }
 274                         }
 275 
 276                         if (width > 64) {
 277                             throw new IllegalArgumentException((width * 8) + "-bit vector arguments not supported");
 278                         }
 279 
 280                         storage = new Storage(forArguments ? StorageClass.VECTOR_ARGUMENT_REGISTER : StorageClass.VECTOR_RETURN_REGISTER, nRegs, width);
 281                         bindings[storage.getStorageClass().ordinal()].add(new ArgumentBinding(storage, arg, i * 8));

 282 
 283                         if (DEBUG) {
 284                             System.out.println("Argument " + arg.getName() + " will be passed in register " + getStorageName(storage));

 285                         }
 286 
 287                         if(width == 8 && storage.getStorageClass() == StorageClass.VECTOR_ARGUMENT_REGISTER && varargs.contains(arg)) {
 288                             Storage extraStorage = new Storage(StorageClass.INTEGER_ARGUMENT_REGISTER, nRegs, SharedConstants.INTEGER_REGISTER_SIZE);
 289                             bindings[StorageClass.INTEGER_ARGUMENT_REGISTER.ordinal()].add(new ArgumentBinding(extraStorage, arg, i * 8));
 290 
 291                             if (DEBUG) {
 292                                 System.out.println("Argument " + arg.getName() + " will be passed in register " + getStorageName(extraStorage));

 293                             }
 294                         }
 295 
 296                         nRegs++;
 297                         break;
 298 
 299                     case SSEUP:
 300                         break;
 301 
 302                     default:
 303                         throw new UnsupportedOperationException("Unhandled class " + c);
 304                     }
 305                 }
 306             }
 307         }
 308     }
 309 
 310     private void addBindings(List<Argument> members, StorageCalculator calculator, boolean isReturn) {
 311         members.stream().forEach(arg -> calculator.addBindings(arg, examineArgument(arg.getType(), isReturn)));
 312     }
 313 
 314     public CallingSequence build() {
 315         List<Argument> returns = new ArrayList<>();
 316         List<Argument> args = this.arguments;
 317         boolean returnsInMemory = false;
 318 
 319         if (returned != null) {
 320             Layout returnType = returned.getType();
 321 
 322             returnsInMemory = examineArgument(returnType, true).inMemory();
 323 
 324             // In some cases the return is passed in as first implicit pointer argument, and a corresponding pointer type is returned
 325             if (returnsInMemory) {
 326                 args = new ArrayList<>();
 327 
 328                 Argument returnPointer = new Argument(-1, Address.ofLayout(64, returned.getType()), returned.getName());
 329                 args.add(returnPointer);
 330                 args.addAll(this.arguments);
 331 
 332                 returns.add(returnPointer);
 333             } else {
 334                 returns.add(returned);
 335             }
 336         }
 337 
 338         @SuppressWarnings("unchecked")
 339         ArrayList<ArgumentBinding>[] bindings = (ArrayList<ArgumentBinding>[]) new ArrayList<?>[StorageClass.values().length];
 340 
 341         for (int i = 0; i < StorageClass.values().length; i++) {
 342             bindings[i] = new ArrayList<>();
 343         }
 344 
 345         addBindings(args, new StorageCalculator(bindings, true), false);
 346         addBindings(returns, new StorageCalculator(bindings, false), true);
 347 
 348         return new CallingSequence(this.arguments.size(), bindings, returnsInMemory);
 349     }
 350 }


   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 package jdk.internal.foreign.abi.x64.windows;
  24 
  25 import jdk.internal.foreign.Util;
  26 import jdk.internal.foreign.abi.*;

  27 import jdk.internal.foreign.abi.x64.ArgumentClass;
  28 import jdk.internal.foreign.abi.x64.SharedUtils;
  29 
  30 import java.foreign.layout.*;
  31 import java.util.ArrayList;

  32 import java.util.List;
  33 import java.util.function.BiConsumer;
  34 
  35 import static sun.security.action.GetBooleanAction.privilegedGetProperty;
  36 
  37 class CallingSequenceBuilderImpl extends CallingSequenceBuilder {
  38 
  39     private static final SharedUtils.StorageDebugHelper storageDbgHelper = new SharedUtils.StorageDebugHelper(
  40             new String[] { "rcx", "rdx", "r8", "r9" },
  41             new String[] { "rax" },
  42             new String[0],
  43             Windowsx64ABI.MAX_VECTOR_ARGUMENT_REGISTERS,
  44             Windowsx64ABI.MAX_VECTOR_RETURN_REGISTERS
  45     );
  46 
  47     private static final boolean DEBUG =
  48             privilegedGetProperty("jdk.internal.foreign.abi.windows.x64.DEBUG");
  49 
  50     public CallingSequenceBuilderImpl(Layout layout) {
  51         this(layout, new StorageCalculator(false), new StorageCalculator(true));








  52     }
  53 
  54     private CallingSequenceBuilderImpl(Layout layout, StorageCalculator retCalculator, StorageCalculator argCalculator) {
  55         super(layout,
  56                 (a, c) -> retCalculator.addBindings(a, c, false),
  57                 (a, c) -> argCalculator.addBindings(a, c, false),
  58                 (a, c) -> argCalculator.addBindings(a, c, true));
  59     }
  60 
  61     @Override
  62     protected ArgumentInfo makeArgument(Layout layout, int pos, String name) {
  63         return new ArgumentInfo(layout, pos, name);
  64     }
  65 
  66     static class ArgumentInfo extends Argument {
  67         private final List<ArgumentClass> classes;





  68         
  69         ArgumentInfo(Layout layout, int argumentIndex, String debugName) {
  70             super(layout, argumentIndex, debugName);
  71             this.classes = classifyType(layout, argumentIndex == -1);
  72         }
  73 
  74         public int getRegs() {
  75             return (int)classes.stream()
  76                     .filter(this::isRegisterClass)
  77                     .count();
  78         }
  79 
  80         @Override
  81         public boolean inMemory() {
  82             return classes.stream().allMatch(this::isMemoryClass);
  83         }
  84 
  85         private boolean isMemoryClass(ArgumentClass cl) {
  86             return cl == ArgumentClass.MEMORY ||
  87                     cl == ArgumentClass.X87 ||
  88                     cl == ArgumentClass.X87UP;
  89         }
  90 
  91         private boolean isRegisterClass(ArgumentClass cl) {
  92             return cl == ArgumentClass.INTEGER ||
  93                     cl == ArgumentClass.SSE;
  94         }
  95 
  96         public List<ArgumentClass> getClasses() {
  97             return classes;
  98         }
  99     }
 100 
 101     static List<ArgumentClass> classifyValueType(Value type) {
 102         ArrayList<ArgumentClass> classes = new ArrayList<>();
 103 
 104         switch (type.kind()) {
 105             case INTEGRAL_SIGNED: case INTEGRAL_UNSIGNED:
 106                 classes.add(ArgumentClass.INTEGER);
 107                 // int128
 108                 long left = (type.bitsSize() / 8) - 8;
 109                 while (left > 0) {
 110                     classes.add(ArgumentClass.INTEGER);
 111                     left -= 8;
 112                 }
 113                 return classes;


 117                     classes.add(ArgumentClass.X87UP);
 118                     return classes;
 119                 } else {
 120                     classes.add(ArgumentClass.SSE);
 121                     return classes;
 122                 }
 123             default:
 124                 throw new IllegalArgumentException("Type " + type + " is not yet supported");
 125         }
 126     }
 127 
 128     static boolean isRegisterAggregate(Layout type) {
 129         // FIXME handle bit size 1, 2, 4
 130         long size = type.bitsSize() / 8;
 131         return size == 1
 132             || size == 2
 133             || size == 4
 134             || size == 8;
 135     }
 136     
 137     private static List<ArgumentClass> createMemoryClassArray(long n) {
 138         ArrayList<ArgumentClass> classes = new ArrayList<>();
 139         for (int i = 0; i < n; i++) {
 140             classes.add(ArgumentClass.MEMORY);
 141         }
 142 
 143         return classes;
 144     }
 145 
 146     private static List<ArgumentClass> classifyStructType(Group type, boolean isReturn) {
 147         ArrayList<ArgumentClass> classes = new ArrayList<>();
 148         
 149         if(isRegisterAggregate(type)) {
 150             classes.add(ArgumentClass.INTEGER);
 151         } else {
 152             if(isReturn) {
 153                 return createMemoryClassArray(Util.alignUp((type.bitsSize() / 8), 8));
 154             } else {
 155                 classes.add(ArgumentClass.INTEGER);
 156             }
 157         }
 158 
 159         return classes;
 160     }
 161 
 162     private static List<ArgumentClass> classifyType(Layout type, boolean isReturn) {
 163         if (type instanceof Value) {
 164             return classifyValueType((Value) type);
 165         } else if (type instanceof Address) {
 166             ArrayList<ArgumentClass> classes = new ArrayList<>();
 167             classes.add(ArgumentClass.INTEGER);
 168             return classes;
 169         } else if (type instanceof Sequence) {
 170             ArrayList<ArgumentClass> classes = new ArrayList<>();
 171             classes.add(ArgumentClass.INTEGER); // arrrays are always passed as pointers
 172             return classes;
 173         } else if (type instanceof Group) {
 174             return classifyStructType((Group) type, isReturn);
 175         } else {
 176             throw new IllegalArgumentException("Unhandled type " + type);
 177         }
 178     }
 179 
 180     static class StorageCalculator {






























 181         private final boolean forArguments;
 182 
 183         private int nRegs = 0;
 184         private long stackOffset = 0;
 185 
 186         StorageCalculator(boolean forArguments) {

 187             this.forArguments = forArguments;
 188         }
 189 
 190         void addBindings(Argument arg, BiConsumer<StorageClass, ArgumentBinding> bindingConsumer, boolean forVarargs) {
 191             ArgumentInfo info = (ArgumentInfo)arg;
 192             if (info.inMemory() ||
 193                 nRegs + info.getRegs() > (forArguments ? Windowsx64ABI.MAX_REGISTER_ARGUMENTS : Windowsx64ABI.MAX_REGISTER_RETURNS)) {
 194                 // stack
 195 
 196                 long alignment = Math.max(SharedUtils.alignment(info.layout(), true), 8);
 197 
 198                 long newStackOffset = Util.alignUp(stackOffset, alignment);





 199                 stackOffset = newStackOffset;
 200 
 201                 long tmpStackOffset = stackOffset;
 202                 for (int i = 0; i < info.getClasses().size(); i++) {
 203                     Storage storage = new Storage(StorageClass.STACK_ARGUMENT_SLOT, tmpStackOffset / 8, 8);
 204                     bindingConsumer.accept(StorageClass.STACK_ARGUMENT_SLOT, new ArgumentBinding(storage, info, i * 8));
 205 
 206                     if (DEBUG) {
 207                         System.out.println("Argument " + info.name() + " will be passed on stack at offset " + tmpStackOffset);
 208                     }
 209 
 210                     tmpStackOffset += 8;
 211                 }
 212 
 213                 stackOffset += info.layout().bitsSize() / 8;
 214             } else {
 215                 // regs
 216                 for (int i = 0; i < info.getClasses().size(); i++) {
 217                     Storage storage;
 218 
 219                     ArgumentClass c = info.getClasses().get(i);
 220 
 221                     switch (c) {
 222                     case INTEGER:
 223                         storage = new Storage(forArguments ? StorageClass.INTEGER_ARGUMENT_REGISTER : StorageClass.INTEGER_RETURN_REGISTER, nRegs++, SharedUtils.INTEGER_REGISTER_SIZE);
 224                         bindingConsumer.accept(storage.getStorageClass(), new ArgumentBinding(storage, info, i * 8));
 225 
 226                         if (DEBUG) {
 227                             System.out.println("Argument " + info.name() + " will be passed in register " +
 228                                     storageDbgHelper.getStorageName(storage));
 229                         }
 230                         break;
 231 
 232                     case SSE:
 233                         int width = 8;
 234 
 235                         for (int j = i + 1; j < info.getClasses().size(); j++) {
 236                             if (info.getClasses().get(j) == ArgumentClass.SSEUP) {
 237                                 width += 8;
 238                             }
 239                         }
 240 
 241                         if (width > 64) {
 242                             throw new IllegalArgumentException((width * 8) + "-bit vector arguments not supported");
 243                         }
 244 
 245                         storage = new Storage(forArguments ? StorageClass.VECTOR_ARGUMENT_REGISTER : StorageClass.VECTOR_RETURN_REGISTER,
 246                                 nRegs, width, SharedUtils.VECTOR_REGISTER_SIZE);
 247                         bindingConsumer.accept(storage.getStorageClass(), new ArgumentBinding(storage, info, i * 8));
 248 
 249                         if (DEBUG) {
 250                             System.out.println("Argument " + info.name() + " will be passed in register " +
 251                                     storageDbgHelper.getStorageName(storage));
 252                         }
 253 
 254                         if(width == 8 && storage.getStorageClass() == StorageClass.VECTOR_ARGUMENT_REGISTER && forVarargs) {
 255                             Storage extraStorage = new Storage(StorageClass.INTEGER_ARGUMENT_REGISTER, nRegs, SharedUtils.INTEGER_REGISTER_SIZE);
 256                             bindingConsumer.accept(storage.getStorageClass(), new ArgumentBinding(extraStorage, info, i * 8));
 257 
 258                             if (DEBUG) {
 259                                 System.out.println("Argument " + info.name() + " will be passed in register " +
 260                                         storageDbgHelper.getStorageName(extraStorage));
 261                             }
 262                         }
 263 
 264                         nRegs++;
 265                         break;
 266 
 267                     case SSEUP:
 268                         break;
 269 
 270                     default:
 271                         throw new UnsupportedOperationException("Unhandled class " + c);
 272                     }
 273                 }
 274             }
 275         }









































 276     }
 277 }
< prev index next >