1 /*
   2  * Copyright (c) 2002, 2006, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *  
  23  */
  24 
  25 #include <stdio.h>
  26 #include <string.h>
  27 
  28 static const int R_O0_num = 1000;
  29 static const int R_I0_num = 2000;
  30 static const int R_F0_num = 3000;
  31 static const int R_F1_num = R_F0_num + 1;
  32 static const int R_F2_num = R_F0_num + 2;
  33 static const int STACK_num= 4000;
  34 
  35 static bool LP64 = false;
  36 static bool LONGS_IN_ONE_ENTRY = false;
  37 
  38 static const int Op_RegI = 'I';
  39 static const int Op_RegP = 'P';
  40 static const int Op_RegF = 'F';
  41 static const int Op_RegD = 'D';
  42 static const int Op_RegL = 'L';
  43 static const int SPARC_ARGS_IN_REGS_NUM=6;
  44 
  45 static void print_reg( int reg ) {
  46   if( reg == 0 )
  47     printf("__");               // halve's
  48   else if( reg >= STACK_num && reg < STACK_num+100 )
  49     printf("S%d_",reg - STACK_num);
  50   else if( reg >= R_F0_num && reg < R_F0_num+100 )
  51     printf("F%d_",reg - R_F0_num);
  52   else if( reg >= R_O0_num && reg < R_O0_num+100 ) {
  53     if( LONGS_IN_ONE_ENTRY ) {
  54       reg -= R_O0_num;
  55       printf("O%d",reg>>1);
  56       printf(reg&1 ? "H" : "L");
  57     } else
  58       printf("O%d_",reg - R_O0_num);
  59   } else
  60     printf("Wretched: %d\n", reg);
  61 }
  62 
  63 static void print_convention( int *sig, const char *s, int length ) {
  64   // Print it out
  65   for( int i = 0; i < length; i++) {
  66     if( sig[i] == 0 ) continue; // do not print 'halves'
  67     print_reg( sig[i] & 0xFFFF );
  68     int reg = sig[i] >> 16;
  69     if( reg ) {
  70       printf(":");
  71       print_reg( reg );
  72     } else {
  73       printf("    ");
  74     }
  75     printf("  ");
  76   }
  77   printf("\n");
  78 }
  79 
  80 static int INT_SCALE( int x ) {
  81   return LONGS_IN_ONE_ENTRY ? (x<<1) : x;
  82 }
  83 
  84 static void java_convention( int *sig, const char *s, int length ) {
  85   if( LP64 && !LONGS_IN_ONE_ENTRY ) {
  86     printf("LP64 and 2-reg longs not supported\n");
  87     return;
  88   }
  89   for( int i = 0; i < length; i++ )
  90     sig[i] = s[i];              // Reset sig array
  91   bool is_outgoing = true;
  92 
  93   int int_base = (is_outgoing ? R_O0_num : R_I0_num);
  94 
  95   // Convention is to pack the first 6 int/oop args into the first 6
  96   // registers (I0-I5), extras spill to the stack.  Then pack the first
  97   // 32 float args into F0-F31, extras spill to the stack.  Then pad
  98   // all register sets to align.  Then put longs and doubles into the
  99   // same registers as they fit, else spill to the stack.
 100   int int_reg_max = SPARC_ARGS_IN_REGS_NUM;
 101   int flt_reg_max = 32;
 102   
 103   // Count int/oop and float args.  See how many stack slots we'll need
 104   // and where the longs & doubles will go.
 105   int int_reg_cnt   = 0;
 106   int flt_reg_cnt   = 0;
 107   int stk_reg_pairs = 0;
 108   for( int i = 0; i < length; i++) {
 109     switch( sig[i] ) {
 110     case Op_RegL:               // Longs-in-1-reg compete with int args
 111       if( LONGS_IN_ONE_ENTRY ) { 
 112         if( int_reg_cnt < int_reg_max ) int_reg_cnt++;
 113       }
 114       break;
 115     case Op_RegP:
 116       if( int_reg_cnt < int_reg_max ) int_reg_cnt++;
 117       else if( !LP64 )                stk_reg_pairs++;
 118       break;
 119     case Op_RegI:
 120       if( int_reg_cnt < int_reg_max ) int_reg_cnt++;
 121       else                            stk_reg_pairs++;
 122       break;
 123     case Op_RegF:
 124       if( flt_reg_cnt < flt_reg_max ) flt_reg_cnt++;
 125       else                            stk_reg_pairs++;
 126       break;
 127     }
 128   }
 129 
 130   // This is where the longs/doubles start on the stack.
 131   stk_reg_pairs = (stk_reg_pairs+1) & ~1; // Round
 132   
 133   int int_reg_pairs = (int_reg_cnt+1) & ~1; // 32-bit 2-reg longs only
 134   int flt_reg_pairs = (flt_reg_cnt+1) & ~1;
 135 
 136   int stk_reg = 0;
 137   int int_reg = 0;
 138   int flt_reg = 0;
 139   
 140   // Now do the signature layout
 141   for( int i = 0; i < length; i++) {
 142     int tmp = sig[i];
 143     if( tmp == Op_RegP )
 144       tmp = LP64 ? Op_RegL : Op_RegI;   // Treat ptrs and ints or long accordingly
 145     switch( tmp ) {
 146     case Op_RegI:
 147 //  case Op_RegP: 
 148       if( int_reg < int_reg_max) tmp = INT_SCALE(int_reg++) + int_base;
 149       else                       tmp = STACK_num + stk_reg++;
 150       sig[i] = tmp;
 151       break;
 152 
 153     case Op_RegL: 
 154       if( sig[i] != Op_RegP && sig[i+1] != 'h' ) { printf("expecting (h)alf, found %c\n", sig[i+1]); return; }
 155 //  case Op_RegP: 
 156       if( LONGS_IN_ONE_ENTRY ) {
 157         if( int_reg < int_reg_max ) {
 158           tmp = INT_SCALE(int_reg++) + int_base;
 159         } else {
 160           tmp = STACK_num + stk_reg_pairs;
 161           stk_reg_pairs += 2;
 162         }
 163       } else {
 164         if( int_reg_pairs < int_reg_max ) {
 165           tmp = int_reg_pairs + int_base;
 166           int_reg_pairs += 2;
 167         } else {
 168           tmp = STACK_num + stk_reg_pairs;
 169           stk_reg_pairs += 2;
 170         }
 171       }
 172       sig[i] = tmp | (tmp+1)<<16; // Smear to pair
 173       break;
 174 
 175     case Op_RegF: 
 176       sig[i] = (flt_reg < flt_reg_max) ? (R_F0_num + flt_reg++) : STACK_num + stk_reg++;
 177       break;
 178     case Op_RegD: 
 179       if( sig[i+1] != 'h' ) { printf("expecting (h)alf, found %c\n", sig[i+1]); return; }
 180       if( flt_reg_pairs < flt_reg_max ) {
 181         tmp = R_F0_num + flt_reg_pairs;
 182         flt_reg_pairs += 2;
 183       } else {
 184         tmp = STACK_num + stk_reg_pairs;
 185         stk_reg_pairs += 2;
 186       }
 187       sig[i] = tmp | (tmp+1)<<16; // Smear to pair
 188       break;
 189     case 'h': sig[i] = 0; break;
 190     default:
 191       printf("Bad character: %c\n", sig[i] );
 192       return;
 193     }
 194   }
 195 
 196   printf("java ");
 197   printf(LP64 ? "LP64 " : "LP32 ");
 198   printf(LONGS_IN_ONE_ENTRY ? "long1: " : "long2: ");
 199   print_convention(sig,s,length);
 200 }
 201 
 202 static int int_stk_helper( int i ) {
 203   if( i < 6 ) return R_O0_num + (LONGS_IN_ONE_ENTRY ? i<<1 : i);
 204   else        return STACK_num + (LP64              ? i<<1 : i);
 205 }
 206 
 207 static void native_convention( int *sig, const char *s, int length ) {
 208   if( LP64 && !LONGS_IN_ONE_ENTRY ) {
 209     printf("LP64 and 2-reg longs not supported\n");
 210     return;
 211   }
 212   for( int i = 0; i < length; i++ )
 213     sig[i] = s[i];              // Reset sig array
 214 
 215   // The native convention is V8 if !LP64, which means the V8 convention is
 216   // used both with and without LONGS_IN_ONE_ENTRY, an unfortunate split.  The
 217   // same actual machine registers are used, but they are named differently in
 218   // the LONGS_IN_ONE_ENTRY mode.  The LP64 convention is the V9 convention
 219   // which is slightly more sane.
 220   
 221   if( LP64 ) {
 222     // V9 convention: All things "as-if" on double-wide stack slots.
 223     // Hoist any int/ptr/long's in the first 6 to int regs.
 224     // Hoist any flt/dbl's in the first 16 dbl regs.
 225     int j = 0;                  // Count of actual args, not HALVES
 226     for( int i=0; i<length; i++, j++ ) {
 227       int tmp;
 228       switch( sig[i] ) {
 229       case Op_RegI:
 230         sig[i] = int_stk_helper( j );
 231         break;
 232       case Op_RegL:
 233         if( sig[i+1] != 'h' ) { printf("expecting (h)alf, found %c\n", sig[i+1]); return; }
 234       case Op_RegP:
 235         tmp = int_stk_helper( j );
 236         sig[i] = tmp | ((tmp+1) << 16); // Smear to pair
 237         break;
 238       case Op_RegF:                 // V9ism: floats go in ODD registers
 239         sig[i] = ((j < 16) ? R_F1_num : (STACK_num + 1)) + (j<<1);
 240         break;
 241       case Op_RegD:                 // V9ism: doubles go in EVEN/ODD regs
 242         tmp    = ((j < 16) ? R_F0_num : STACK_num) + (j<<1);
 243         sig[i] = tmp | ((tmp+1) << 16); // Smear to pair
 244         break;
 245       case 'h': sig[i] = 0; j--; break; // Do not count HALVES
 246       default:
 247         printf("Bad character: %c\n", sig[i] );
 248         return;
 249       }
 250     }
 251 
 252   } else {
 253     // V8 convention: first 6 things in O-regs, rest on stack.
 254     // Alignment is willy-nilly.
 255     for( int i=0; i<length; i++ ) {
 256       int tmp;
 257       switch( sig[i] ) {
 258       case Op_RegI:
 259       case Op_RegP:
 260       case Op_RegF:
 261         sig[i] = int_stk_helper( i );
 262         break;
 263       case Op_RegL:
 264       case Op_RegD:
 265         if( sig[i+1] != 'h' ) { printf("expecting (h)alf, found %c\n", sig[i+1]); return; }
 266         tmp = int_stk_helper( i );
 267         sig[i] = tmp | (int_stk_helper( i+1 ) << 16);
 268         break;
 269       case 'h': sig[i] = 0; break;
 270       default:
 271         printf("Bad character: %c\n", sig[i] );
 272         return;
 273       }
 274     }
 275   }
 276 
 277   printf("natv ");
 278   printf(LP64 ? "LP64 " : "LP32 ");
 279   printf(LONGS_IN_ONE_ENTRY ? "long1: " : "long2: ");
 280   print_convention(sig,s,length);
 281 }
 282 
 283 int main( int argc, char **argv ) {
 284 
 285   if( argc != 2 ) {
 286     printf("Usage: args IPFLhDh... (Java argument string)\n");
 287     printf("Returns argument layout\n");
 288     return -1;
 289   }
 290 
 291   const char *s = argv[1];
 292   int length = strlen(s);
 293   int sig[1000];
 294 
 295   LP64 = false; LONGS_IN_ONE_ENTRY = false;
 296   java_convention( sig, s, length );
 297   LP64 = false; LONGS_IN_ONE_ENTRY = true;
 298   java_convention( sig, s, length );
 299   LP64 = true ; LONGS_IN_ONE_ENTRY = true;
 300   java_convention( sig, s, length );
 301 
 302   LP64 = false; LONGS_IN_ONE_ENTRY = false;
 303   native_convention( sig, s, length );
 304   LP64 = false; LONGS_IN_ONE_ENTRY = true;
 305   native_convention( sig, s, length );
 306   LP64 = true ; LONGS_IN_ONE_ENTRY = true;
 307   native_convention( sig, s, length );
 308 }
 309