001 /* 002 * This file is part of the Jikes RVM project (http://jikesrvm.org). 003 * 004 * This file is licensed to You under the Eclipse Public License (EPL); 005 * You may not use this file except in compliance with the License. You 006 * may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/eclipse-1.0.php 009 * 010 * See the COPYRIGHT.txt file distributed with this work for information 011 * regarding copyright ownership. 012 */ 013 package org.jikesrvm.ia32; 014 015 import org.jikesrvm.ArchitectureSpecific; 016 import org.jikesrvm.VM; 017 import org.jikesrvm.classloader.RVMMethod; 018 import org.jikesrvm.compilers.common.assembler.ia32.Assembler; 019 import org.jikesrvm.objectmodel.ObjectModel; 020 import org.jikesrvm.runtime.ArchEntrypoints; 021 import org.jikesrvm.runtime.Magic; 022 import org.vmmagic.unboxed.Offset; 023 024 /** 025 * An interface conflict resolution stub uses a hidden parameter to 026 * distinguish among multiple interface methods of a class that map to 027 * the same slot in the class's IMT. </p> 028 * 029 * <p><STRONG>Assumption:</STRONG> 030 * Register EAX contains the "this" parameter of the 031 * method being called invoked. 032 * 033 * <p><STRONG>Assumption:</STRONG> 034 * Register ECX is available as a scratch register (we need one!) 035 */ 036 public abstract class InterfaceMethodConflictResolver implements RegisterConstants { 037 038 // Create a conflict resolution stub for the set of interface method signatures l. 039 // 040 public static ArchitectureSpecific.CodeArray createStub(int[] sigIds, RVMMethod[] targets) { 041 int numEntries = sigIds.length; 042 // (1) Create an assembler. 043 Assembler asm = new ArchitectureSpecific.Assembler(numEntries); 044 045 // (2) signatures must be in ascending order (to build binary search tree). 046 if (VM.VerifyAssertions) { 047 for (int i = 1; i < sigIds.length; i++) { 048 VM._assert(sigIds[i - 1] < sigIds[i]); 049 } 050 } 051 052 // (3) Assign synthetic bytecode numbers to each switch such that we'll generate them 053 // in ascending order. This lets us use the general forward branching mechanisms 054 // of the Assembler. 055 int[] bcIndices = new int[numEntries]; 056 assignBytecodeIndices(0, bcIndices, 0, numEntries - 1); 057 058 // (4) Generate the stub. 059 insertStubPrologue(asm); 060 insertStubCase(asm, sigIds, targets, bcIndices, 0, numEntries - 1); 061 062 return asm.getMachineCodes(); 063 } 064 065 // Assign ascending bytecode indices to each case (in the order they will be generated) 066 private static int assignBytecodeIndices(int bcIndex, int[] bcIndices, int low, int high) { 067 int middle = (high + low) / 2; 068 bcIndices[middle] = bcIndex++; 069 if (low == middle && middle == high) { 070 return bcIndex; 071 } else { 072 // Recurse. 073 if (low < middle) { 074 bcIndex = assignBytecodeIndices(bcIndex, bcIndices, low, middle - 1); 075 } 076 if (middle < high) { 077 bcIndex = assignBytecodeIndices(bcIndex, bcIndices, middle + 1, high); 078 } 079 return bcIndex; 080 } 081 } 082 083 // Make a stub prologue: get TIB into ECX 084 // factor out to reduce code space in each call. 085 // 086 private static void insertStubPrologue(Assembler asm) { 087 ObjectModel.baselineEmitLoadTIB((ArchitectureSpecific.Assembler) asm, ECX.value(), EAX.value()); 088 } 089 090 // Generate a subtree covering from low to high inclusive. 091 private static void insertStubCase(Assembler asm, int[] sigIds, RVMMethod[] targets, int[] bcIndices, int low, 092 int high) { 093 int middle = (high + low) / 2; 094 asm.resolveForwardReferences(bcIndices[middle]); 095 if (low == middle && middle == high) { 096 // a leaf case; can simply invoke the method directly. 097 RVMMethod target = targets[middle]; 098 if (target.isStatic()) { // an error case... 099 asm.emitJMP_Abs(Magic.getTocPointer().plus(target.getOffset())); 100 } else { 101 asm.emitJMP_RegDisp(ECX, target.getOffset()); 102 } 103 } else { 104 Offset disp = ArchEntrypoints.hiddenSignatureIdField.getOffset(); 105 ThreadLocalState.emitCompareFieldWithImm(asm, disp, sigIds[middle]); 106 if (low < middle) { 107 asm.emitJCC_Cond_Label(Assembler.LT, bcIndices[(low + middle - 1) / 2]); 108 } 109 if (middle < high) { 110 asm.emitJCC_Cond_Label(Assembler.GT, bcIndices[(middle + 1 + high) / 2]); 111 } 112 // invoke the method for middle. 113 RVMMethod target = targets[middle]; 114 if (target.isStatic()) { // an error case... 115 asm.emitJMP_Abs(Magic.getTocPointer().plus(target.getOffset())); 116 } else { 117 asm.emitJMP_RegDisp(ECX, target.getOffset()); 118 } 119 // Recurse. 120 if (low < middle) { 121 insertStubCase(asm, sigIds, targets, bcIndices, low, middle - 1); 122 } 123 if (middle < high) { 124 insertStubCase(asm, sigIds, targets, bcIndices, middle + 1, high); 125 } 126 } 127 } 128 }