github.com/goccy/go-jit@v0.0.0-20200514131505-ff78d45cf6af/internal/ccall/jit-rules.c (about)

     1  /*
     2   * jit-rules.c - Rules that define the characteristics of the back-end.
     3   *
     4   * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
     5   *
     6   * This file is part of the libjit library.
     7   *
     8   * The libjit library is free software: you can redistribute it and/or
     9   * modify it under the terms of the GNU Lesser General Public License
    10   * as published by the Free Software Foundation, either version 2.1 of
    11   * the License, or (at your option) any later version.
    12   *
    13   * The libjit library is distributed in the hope that it will be useful,
    14   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    15   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    16   * Lesser General Public License for more details.
    17   *
    18   * You should have received a copy of the GNU Lesser General Public
    19   * License along with the libjit library.  If not, see
    20   * <http://www.gnu.org/licenses/>.
    21   */
    22  
    23  #include "jit-internal.h"
    24  #include "jit-rules.h"
    25  
    26  /*
    27   * The information blocks for all registers in the system.
    28   */
    29  jit_reginfo_t const _jit_reg_info[JIT_NUM_REGS] = {JIT_REG_INFO};
    30  
    31  #ifdef JIT_CDECL_WORD_REG_PARAMS
    32  
    33  /*
    34   * List of registers to use for simple parameter passing.
    35   */
    36  static int const cdecl_word_regs[] = JIT_CDECL_WORD_REG_PARAMS;
    37  #ifdef JIT_FASTCALL_WORD_REG_PARAMS
    38  static int const fastcall_word_regs[] = JIT_FASTCALL_WORD_REG_PARAMS;
    39  #endif
    40  
    41  /*
    42   * Structure that is used to help with parameter passing.
    43   */
    44  typedef struct
    45  {
    46  	jit_nint		offset;
    47  	unsigned int	index;
    48  	unsigned int	max_regs;
    49  	const int	   *word_regs;
    50  	jit_value_t		word_values[JIT_MAX_WORD_REG_PARAMS];
    51  
    52  } jit_param_passing_t;
    53  
    54  /*
    55   * Round a size up to a multiple of the stack word size.
    56   */
    57  #define	ROUND_STACK(size)	\
    58  		(((size) + (sizeof(void *) - 1)) & ~(sizeof(void *) - 1))
    59  #define	STACK_WORDS(size)	\
    60  		(((size) + (sizeof(void *) - 1)) / sizeof(void *))
    61  
    62  /*
    63   * Allocate a word register or incoming frame position to a value.
    64   */
    65  static int alloc_incoming_word
    66  	(jit_function_t func, jit_param_passing_t *passing,
    67  	 jit_value_t value, int extra_offset)
    68  {
    69  	int reg;
    70  	reg = passing->word_regs[passing->index];
    71  	if(reg != -1 && passing->word_values[passing->index] != 0)
    72  	{
    73  		/* The value was already forced out previously, so just copy it */
    74  		if(!jit_insn_store(func, value, passing->word_values[passing->index]))
    75  		{
    76  			return 0;
    77  		}
    78  		++(passing->index);
    79  	}
    80  	else if(reg != -1)
    81  	{
    82  		if(!jit_insn_incoming_reg(func, value, reg))
    83  		{
    84  			return 0;
    85  		}
    86  		++(passing->index);
    87  	}
    88  	else
    89  	{
    90  		if(!jit_insn_incoming_frame_posn
    91  				(func, value, passing->offset + extra_offset))
    92  		{
    93  			return 0;
    94  		}
    95  		passing->offset += sizeof(void *);
    96  	}
    97  	return 1;
    98  }
    99  
   100  /*
   101   * Force the remaining word registers out into temporary values,
   102   * to protect them from being accidentally overwritten by the code
   103   * that deals with multi-word parameters.
   104   */
   105  static int force_remaining_out
   106  	(jit_function_t func, jit_param_passing_t *passing)
   107  {
   108  	unsigned int index = passing->index;
   109  	jit_value_t value;
   110  	while(index < passing->max_regs && passing->word_regs[index] != -1)
   111  	{
   112  		if(passing->word_values[index] != 0)
   113  		{
   114  			/* We've already done this before */
   115  			return 1;
   116  		}
   117  		value = jit_value_create(func, jit_type_void_ptr);
   118  		if(!value)
   119  		{
   120  			return 0;
   121  		}
   122  		if(!jit_insn_incoming_reg(func, value, passing->word_regs[index]))
   123  		{
   124  			return 0;
   125  		}
   126  		passing->word_values[index] = value;
   127  		++index;
   128  	}
   129  	return 1;
   130  }
   131  
   132  int _jit_create_entry_insns(jit_function_t func)
   133  {
   134  	jit_type_t signature = func->signature;
   135  	jit_type_t type;
   136  	jit_value_t value;
   137  	jit_value_t temp;
   138  	jit_value_t addr_of;
   139  	unsigned int num_params;
   140  	unsigned int param;
   141  	unsigned int size;
   142  	jit_param_passing_t passing;
   143  	jit_nint partial_offset;
   144  
   145  	/* Reset the local variable frame size for this function */
   146  	func->builder->frame_size = JIT_INITIAL_FRAME_SIZE;
   147  
   148  	/* Initialize the parameter passing information block */
   149  	passing.offset = JIT_INITIAL_STACK_OFFSET;
   150  	passing.index = 0;
   151  #ifdef JIT_FASTCALL_WORD_REG_PARAMS
   152  	if(jit_type_get_abi(signature) == jit_abi_fastcall)
   153  	{
   154  		passing.word_regs = fastcall_word_regs;
   155  	}
   156  	else
   157  #endif
   158  	{
   159  		passing.word_regs = cdecl_word_regs;
   160  	}
   161  	for(size = 0; size < JIT_MAX_WORD_REG_PARAMS; ++size)
   162  	{
   163  		passing.word_values[size] = 0;
   164  	}
   165  
   166  	/* If the function is nested, then we need an extra parameter
   167  	   to pass the pointer to the parent's local variable frame */
   168  	if(func->nested_parent)
   169  	{
   170  		value = jit_value_create(func, jit_type_void_ptr);
   171  		if(!value)
   172  		{
   173  			return 0;
   174  		}
   175  
   176  		jit_function_set_parent_frame(func, value);
   177  		if(!alloc_incoming_word(func, &passing, value, 0))
   178  		{
   179  			return 0;
   180  		}
   181  	}
   182  
   183  	/* Allocate the structure return pointer */
   184  	value = jit_value_get_struct_pointer(func);
   185  	if(value)
   186  	{
   187  		if(!alloc_incoming_word(func, &passing, value, 0))
   188  		{
   189  			return 0;
   190  		}
   191  	}
   192  
   193  	/* Determine the maximum number of registers that may be needed
   194  	   to pass the function's parameters */
   195  	num_params = jit_type_num_params(signature);
   196  	passing.max_regs = passing.index;
   197  	for(param = 0; param < num_params; ++param)
   198  	{
   199  		value = jit_value_get_param(func, param);
   200  		if(value)
   201  		{
   202  			size = STACK_WORDS(jit_type_get_size(jit_value_get_type(value)));
   203  			passing.max_regs += size;
   204  		}
   205  	}
   206  
   207  	/* Allocate the parameter offsets */
   208  	for(param = 0; param < num_params; ++param)
   209  	{
   210  		value = jit_value_get_param(func, param);
   211  		if(!value)
   212  		{
   213  			continue;
   214  		}
   215  		type = jit_type_remove_tags(jit_value_get_type(value));
   216  		switch(type->kind)
   217  		{
   218  			case JIT_TYPE_SBYTE:
   219  			case JIT_TYPE_UBYTE:
   220  			{
   221  				if(!alloc_incoming_word
   222  					(func, &passing, value, _jit_nint_lowest_byte()))
   223  				{
   224  					return 0;
   225  				}
   226  			}
   227  			break;
   228  
   229  			case JIT_TYPE_SHORT:
   230  			case JIT_TYPE_USHORT:
   231  			{
   232  				if(!alloc_incoming_word
   233  					(func, &passing, value, _jit_nint_lowest_short()))
   234  				{
   235  					return 0;
   236  				}
   237  			}
   238  			break;
   239  
   240  			case JIT_TYPE_INT:
   241  			case JIT_TYPE_UINT:
   242  			{
   243  				if(!alloc_incoming_word
   244  					(func, &passing, value, _jit_nint_lowest_int()))
   245  				{
   246  					return 0;
   247  				}
   248  			}
   249  			break;
   250  
   251  			case JIT_TYPE_NINT:
   252  			case JIT_TYPE_NUINT:
   253  			case JIT_TYPE_SIGNATURE:
   254  			case JIT_TYPE_PTR:
   255  			{
   256  				if(!alloc_incoming_word(func, &passing, value, 0))
   257  				{
   258  					return 0;
   259  				}
   260  			}
   261  			break;
   262  
   263  			case JIT_TYPE_LONG:
   264  			case JIT_TYPE_ULONG:
   265  		#ifdef JIT_NATIVE_INT64
   266  			{
   267  				if(!alloc_incoming_word(func, &passing, value, 0))
   268  				{
   269  					return 0;
   270  				}
   271  			}
   272  			break;
   273  		#endif
   274  			/* Fall through on 32-bit platforms */
   275  
   276  			case JIT_TYPE_FLOAT32:
   277  			case JIT_TYPE_FLOAT64:
   278  			case JIT_TYPE_NFLOAT:
   279  			case JIT_TYPE_STRUCT:
   280  			case JIT_TYPE_UNION:
   281  			{
   282  				/* Force the remaining registers out into temporary copies */
   283  				if(!force_remaining_out(func, &passing))
   284  				{
   285  					return 0;
   286  				}
   287  
   288  				/* Determine how many words that we need to copy */
   289  				size = STACK_WORDS(jit_type_get_size(type));
   290  
   291  				/* If there are no registers left, then alloc on the stack */
   292  				if(passing.word_regs[passing.index] == -1)
   293  				{
   294  					if(!jit_insn_incoming_frame_posn
   295  						(func, value, passing.offset))
   296  					{
   297  						return 0;
   298  					}
   299  					passing.offset += size * sizeof(void *);
   300  					break;
   301  				}
   302  
   303  				/* Copy the register components across */
   304  				partial_offset = 0;
   305  				addr_of = jit_insn_address_of(func, value);
   306  				if(!addr_of)
   307  				{
   308  					return 0;
   309  				}
   310  				while(size > 0 && passing.word_regs[passing.index] != -1)
   311  				{
   312  					temp = passing.word_values[passing.index];
   313  					++(passing.index);
   314  					if(!jit_insn_store_relative
   315  							(func, addr_of, partial_offset, temp))
   316  					{
   317  						return 0;
   318  					}
   319  					partial_offset += sizeof(void *);
   320  					--size;
   321  				}
   322  
   323  				/* Copy the stack components across */
   324  				while(size > 0)
   325  				{
   326  					temp = jit_value_create(func, jit_type_void_ptr);
   327  					if(!temp)
   328  					{
   329  						return 0;
   330  					}
   331  					if(!jit_insn_incoming_frame_posn
   332  							(func, temp, passing.offset))
   333  					{
   334  						return 0;
   335  					}
   336  					if(!jit_insn_store_relative
   337  							(func, addr_of, partial_offset, temp))
   338  					{
   339  						return 0;
   340  					}
   341  					passing.offset += sizeof(void *);
   342  					partial_offset += sizeof(void *);
   343  					--size;
   344  				}
   345  			}
   346  			break;
   347  		}
   348  	}
   349  	return 1;
   350  }
   351  
   352  /*
   353   * Record that we need an outgoing register or stack slot for a word value.
   354   */
   355  static void need_outgoing_word(jit_param_passing_t *passing)
   356  {
   357  	if(passing->word_regs[passing->index] != -1)
   358  	{
   359  		++(passing->index);
   360  	}
   361  	else
   362  	{
   363  		passing->offset += sizeof(void *);
   364  	}
   365  }
   366  
   367  /*
   368   * Record that we need an outgoing register, containing a particular value.
   369   */
   370  static void need_outgoing_value
   371  	(jit_param_passing_t *passing, jit_value_t value)
   372  {
   373  	passing->word_values[passing->index] = value;
   374  	++(passing->index);
   375  }
   376  
   377  /*
   378   * Count the number of registers that are left for parameter passing.
   379   */
   380  static jit_nint count_regs_left(jit_param_passing_t *passing)
   381  {
   382  	int left = 0;
   383  	unsigned int index = passing->index;
   384  	while(passing->word_regs[index] != -1)
   385  	{
   386  		++left;
   387  		++index;
   388  	}
   389  	return left;
   390  }
   391  
   392  /*
   393   * Determine if a type corresponds to a structure or union.
   394   */
   395  static int is_struct_or_union(jit_type_t type)
   396  {
   397  	type = jit_type_normalize(type);
   398  	if(type)
   399  	{
   400  		if(type->kind == JIT_TYPE_STRUCT || type->kind == JIT_TYPE_UNION)
   401  		{
   402  			return 1;
   403  		}
   404  	}
   405  	return 0;
   406  }
   407  
   408  /*
   409   * Push a parameter onto the stack.
   410   */
   411  static int push_param
   412  	(jit_function_t func, jit_param_passing_t *passing,
   413  	 jit_value_t value, jit_type_t type)
   414  {
   415  	jit_nint size = (jit_nint)(jit_type_get_size(value->type));
   416  	passing->offset -= ROUND_STACK(size);
   417  	if(is_struct_or_union(type) && !is_struct_or_union(value->type))
   418  	{
   419  	#ifdef JIT_USE_PARAM_AREA
   420  		/* Copy the value into the outgoing parameter area, by pointer */
   421  		if(!jit_insn_set_param_ptr(func, value, type, passing->offset))
   422  		{
   423  			return 0;
   424  		}
   425  	#else
   426  		/* Push the parameter value onto the stack, by pointer */
   427  		if(!jit_insn_push_ptr(func, value, type))
   428  		{
   429  			return 0;
   430  		}
   431  	#endif
   432  	}
   433  	else
   434  	{
   435  	#ifdef JIT_USE_PARAM_AREA
   436  		/* Copy the value into the outgoing parameter area */
   437  		if(!jit_insn_set_param(func, value, passing->offset))
   438  		{
   439  			return 0;
   440  		}
   441  	#else
   442  		/* Push the parameter value onto the stack */
   443  		if(!jit_insn_push(func, value))
   444  		{
   445  			return 0;
   446  		}
   447  	#endif
   448  	}
   449  	return 1;
   450  }
   451  
   452  /*
   453   * Allocate an outgoing word register to a value.
   454   */
   455  static int alloc_outgoing_word
   456  	(jit_function_t func, jit_param_passing_t *passing, jit_value_t value)
   457  {
   458  	int reg;
   459  	--(passing->index);
   460  	reg = passing->word_regs[passing->index];
   461  	if(passing->word_values[passing->index] != 0)
   462  	{
   463  		/* We copied the value previously, so use the copy instead */
   464  		value = passing->word_values[passing->index];
   465  	}
   466  	if(!jit_insn_outgoing_reg(func, value, reg))
   467  	{
   468  		return 0;
   469  	}
   470  	return 1;
   471  }
   472  
   473  int _jit_create_call_setup_insns
   474  	(jit_function_t func, jit_type_t signature,
   475  	 jit_value_t *args, unsigned int num_args,
   476  	 int is_nested, jit_value_t parent_frame, jit_value_t *struct_return, int flags)
   477  {
   478  	jit_type_t type;
   479  	jit_value_t value;
   480  	jit_nint size;
   481  	jit_nint regs_left;
   482  	jit_nint rounded_size;
   483  	jit_nint partial_offset;
   484  	jit_param_passing_t passing;
   485  	jit_value_t return_ptr;
   486  	jit_value_t partial;
   487  	unsigned int param;
   488  
   489  	/* Initialize the parameter passing information block */
   490  	passing.offset = 0;
   491  	passing.index = 0;
   492  #ifdef JIT_FASTCALL_WORD_REG_PARAMS
   493  	if(jit_type_get_abi(signature) == jit_abi_fastcall)
   494  	{
   495  		passing.word_regs = fastcall_word_regs;
   496  	}
   497  	else
   498  #endif
   499  	{
   500  		passing.word_regs = cdecl_word_regs;
   501  	}
   502  	for(size = 0; size < JIT_MAX_WORD_REG_PARAMS; ++size)
   503  	{
   504  		passing.word_values[size] = 0;
   505  	}
   506  
   507  	/* Determine how many parameters are going to end up in word registers,
   508  	   and compute the largest stack size needed to pass stack parameters */
   509  	if(is_nested)
   510  	{
   511  		need_outgoing_word(&passing);
   512  	}
   513  	type = jit_type_get_return(signature);
   514  	if(jit_type_return_via_pointer(type))
   515  	{
   516  		value = jit_value_create(func, type);
   517  		if(!value)
   518  		{
   519  			return 0;
   520  		}
   521  		*struct_return = value;
   522  		return_ptr = jit_insn_address_of(func, value);
   523  		if(!return_ptr)
   524  		{
   525  			return 0;
   526  		}
   527  		need_outgoing_word(&passing);
   528  	}
   529  	else
   530  	{
   531  		*struct_return = 0;
   532  		return_ptr = 0;
   533  	}
   534  	partial = 0;
   535  	for(param = 0; param < num_args; ++param)
   536  	{
   537  		type = jit_type_get_param(signature, param);
   538  		size = STACK_WORDS(jit_type_get_size(type));
   539  		if(size <= 1)
   540  		{
   541  			/* Allocate a word register or stack position */
   542  			need_outgoing_word(&passing);
   543  		}
   544  		else
   545  		{
   546  			regs_left = count_regs_left(&passing);
   547  			if(regs_left > 0)
   548  			{
   549  				/* May be partly in registers and partly on the stack */
   550  				if(is_struct_or_union(type) &&
   551  				   !is_struct_or_union(jit_value_get_type(args[param])))
   552  				{
   553  					/* Passing a structure by pointer */
   554  					partial = args[param];
   555  				}
   556  				else if(jit_value_is_constant(args[param]))
   557  				{
   558  					if(size <= regs_left)
   559  					{
   560  						/* We can split the constant, without a temporary */
   561  						partial_offset = 0;
   562  						while(size > 0)
   563  						{
   564  							value = jit_value_create_nint_constant
   565  								(func, jit_type_void_ptr,
   566  								 *((jit_nint *)(args[param]->address +
   567  								 				partial_offset)));
   568  							need_outgoing_value(&passing, value);
   569  							partial_offset += sizeof(void *);
   570  							--size;
   571  						}
   572  						continue;
   573  					}
   574  					else
   575  					{
   576  						/* Copy the constant into a temporary local variable */
   577  						partial = jit_value_create(func, type);
   578  						if(!partial)
   579  						{
   580  							return 0;
   581  						}
   582  						if(!jit_insn_store(func, partial, args[param]))
   583  						{
   584  							return 0;
   585  						}
   586  						partial = jit_insn_address_of(func, partial);
   587  					}
   588  				}
   589  				else
   590  				{
   591  					/* Get the address of this parameter */
   592  					partial = jit_insn_address_of(func, args[param]);
   593  				}
   594  				if(!partial)
   595  				{
   596  					return 0;
   597  				}
   598  				partial_offset = 0;
   599  				while(size > 0 && regs_left > 0)
   600  				{
   601  					value = jit_insn_load_relative
   602  						(func, partial, partial_offset, jit_type_void_ptr);
   603  					if(!value)
   604  					{
   605  						return 0;
   606  					}
   607  					need_outgoing_value(&passing, value);
   608  					--size;
   609  					--regs_left;
   610  					partial_offset += sizeof(void *);
   611  				}
   612  				passing.offset += size * sizeof(void *);
   613  			}
   614  			else
   615  			{
   616  				/* Pass this parameter completely on the stack */
   617  				passing.offset += size * sizeof(void *);
   618  			}
   619  		}
   620  	}
   621  #ifdef JIT_USE_PARAM_AREA
   622  	if(passing.offset > func->builder->param_area_size)
   623  	{
   624  		func->builder->param_area_size = passing.offset;
   625  	}
   626  #else
   627  	/* Flush deferred stack pops from previous calls if too many
   628  	   parameters have collected up on the stack since last time */
   629  	if(!jit_insn_flush_defer_pop(func, 32 - passing.offset))
   630  	{
   631  		return 0;
   632  	}
   633  #endif
   634  
   635  	/* Move all of the parameters into their final locations */
   636  	param = num_args;
   637  	while(param > 0)
   638  	{
   639  		--param;
   640  		type = jit_type_get_param(signature, param);
   641  		size = (jit_nint)(jit_type_get_size(type));
   642  		rounded_size = ROUND_STACK(size);
   643  		size = STACK_WORDS(size);
   644  		if(rounded_size <= passing.offset)
   645  		{
   646  			/* This parameter is completely on the stack */
   647  			if(!push_param(func, &passing, args[param], type))
   648  			{
   649  				return 0;
   650  			}
   651  		}
   652  		else if(passing.offset > 0)
   653  		{
   654  			/* This parameter is split between the stack and registers */
   655  			while(passing.offset > 0)
   656  			{
   657  				rounded_size -= sizeof(void *);
   658  				value = jit_insn_load_relative
   659  					(func, partial, rounded_size, jit_type_void_ptr);
   660  				if(!value)
   661  				{
   662  					return 0;
   663  				}
   664  				if(!push_param(func, &passing, value, jit_type_void_ptr))
   665  				{
   666  					return 0;
   667  				}
   668  				--size;
   669  			}
   670  			while(size > 0)
   671  			{
   672  				if(!alloc_outgoing_word(func, &passing, 0))
   673  				{
   674  					return 0;
   675  				}
   676  				--size;
   677  			}
   678  		}
   679  		else
   680  		{
   681  			/* This parameter is completely in registers.  If the parameter
   682  			   occupies multiple registers, then it has already been split */
   683  			while(size > 0)
   684  			{
   685  				if(!alloc_outgoing_word(func, &passing, args[param]))
   686  				{
   687  					return 0;
   688  				}
   689  				--size;
   690  			}
   691  		}
   692  	}
   693  
   694  	/* Add nested scope information if required */
   695  	if(is_nested)
   696  	{
   697  		if(passing.index > 0)
   698  		{
   699  			if(!alloc_outgoing_word(func, &passing, parent_frame))
   700  			{
   701  				return 0;
   702  			}
   703  		}
   704  		else
   705  		{
   706  			if(!push_param
   707  				(func, &passing, parent_frame, jit_type_void_ptr))
   708  			{
   709  				return 0;
   710  			}
   711  		}
   712  	}
   713  
   714  	/* Add the structure return pointer if required */
   715  	if(return_ptr)
   716  	{
   717  		if(passing.index > 0)
   718  		{
   719  			if(!alloc_outgoing_word(func, &passing, return_ptr))
   720  			{
   721  				return 0;
   722  			}
   723  		}
   724  		else
   725  		{
   726  			if(!push_param
   727  				(func, &passing, return_ptr, jit_type_void_ptr))
   728  			{
   729  				return 0;
   730  			}
   731  		}
   732  	}
   733  
   734  	/* The call is ready to proceed */
   735  	return 1;
   736  }
   737  
   738  #endif /* JIT_CDECL_WORD_REG_PARAMS */
   739  
   740  void
   741  _jit_gen_check_space(jit_gencode_t gen, int space)
   742  {
   743  	if((gen->ptr + space) >= gen->mem_limit)
   744  	{
   745  		/* No space left on the current cache page. */
   746  		jit_exception_builtin(JIT_RESULT_MEMORY_FULL);
   747  	}
   748  }
   749  
   750  void *
   751  _jit_gen_alloc(jit_gencode_t gen, unsigned long size)
   752  {
   753  	void *ptr;
   754  	_jit_memory_set_break(gen->context, gen->ptr);
   755  	ptr = _jit_memory_alloc_data(gen->context, size, JIT_BEST_ALIGNMENT);
   756  	if(!ptr)
   757  	{
   758  		jit_exception_builtin(JIT_RESULT_MEMORY_FULL);
   759  	}
   760  	gen->mem_limit = _jit_memory_get_limit(gen->context);
   761  	return ptr;
   762  }
   763  
   764  int _jit_int_lowest_byte(void)
   765  {
   766  	union
   767  	{
   768  		unsigned char bytes[4];
   769  		jit_int value;
   770  	} volatile un;
   771  	int posn;
   772  	un.value = (jit_int)0x01020304;
   773  	posn = 0;
   774  	while(un.bytes[posn] != 0x04)
   775  	{
   776  		++posn;
   777  	}
   778  	return posn;
   779  }
   780  
   781  int _jit_int_lowest_short(void)
   782  {
   783  	union
   784  	{
   785  		unsigned char bytes[4];
   786  		jit_int value;
   787  	} volatile un;
   788  	int posn;
   789  	un.value = (jit_int)0x01020304;
   790  	posn = 0;
   791  	while(un.bytes[posn] != 0x03 && un.bytes[posn] != 0x04)
   792  	{
   793  		++posn;
   794  	}
   795  	return posn;
   796  }
   797  
   798  int _jit_nint_lowest_byte(void)
   799  {
   800  #ifdef JIT_NATIVE_INT32
   801  	return _jit_int_lowest_byte();
   802  #else
   803  	union
   804  	{
   805  		unsigned char bytes[8];
   806  		jit_long value;
   807  	} volatile un;
   808  	int posn;
   809  	un.value = (jit_long)0x0102030405060708;
   810  	posn = 0;
   811  	while(un.bytes[posn] != 0x08)
   812  	{
   813  		++posn;
   814  	}
   815  	return posn;
   816  #endif
   817  }
   818  
   819  int _jit_nint_lowest_short(void)
   820  {
   821  #ifdef JIT_NATIVE_INT32
   822  	return _jit_int_lowest_short();
   823  #else
   824  	union
   825  	{
   826  		unsigned char bytes[8];
   827  		jit_long value;
   828  	} volatile un;
   829  	int posn;
   830  	un.value = (jit_long)0x0102030405060708;
   831  	posn = 0;
   832  	while(un.bytes[posn] != 0x07 && un.bytes[posn] != 0x08)
   833  	{
   834  		++posn;
   835  	}
   836  	return posn;
   837  #endif
   838  }
   839  
   840  int _jit_nint_lowest_int(void)
   841  {
   842  #ifdef JIT_NATIVE_INT32
   843  	return 0;
   844  #else
   845  	union
   846  	{
   847  		unsigned char bytes[8];
   848  		jit_long value;
   849  	} volatile un;
   850  	int posn;
   851  	un.value = (jit_long)0x0102030405060708;
   852  	posn = 0;
   853  	while(un.bytes[posn] <= 0x04)
   854  	{
   855  		++posn;
   856  	}
   857  	return posn;
   858  #endif
   859  }