Beispiel #1
0
/*
 * Allocate a new value from a function's memory pool.
 */
static jit_value_t
alloc_value(jit_function_t func, jit_type_t type)
{
	/* Ensure that we have a builder for this function */
	if(!_jit_function_ensure_builder(func))
	{
		return 0;
	}

	jit_value_t value = jit_memory_pool_alloc(&func->builder->value_pool, struct _jit_value);
	if(!value)
	{
		return 0;
	}
	value->block = func->builder->current_block;
	value->type = jit_type_copy(type);
	value->reg = -1;
	value->frame_offset = JIT_INVALID_FRAME_OFFSET;
	value->index = -1;

	return value;
}
Beispiel #2
0
PHP_METHOD(Type, __construct) {
	zval *ztype = NULL;
	zend_bool zpointer = 0;
	php_jit_type_t *ptype;
	
	if (php_jit_parameters("z|b", &ztype, &zpointer) != SUCCESS) {
		php_jit_exception("unexpected parameters, expected (int|Type of [, bool pointer = false])");
		return;
	}
	
	ptype = PHP_JIT_FETCH_TYPE(getThis());
	
	switch (Z_TYPE_P(ztype)) {
		case IS_LONG:
			if (zpointer) {
				ptype->type = jit_type_create_pointer(
					php_jit_type(Z_LVAL_P(ztype)), 1);
				ptype->pt   = 1;
			} else ptype->type = php_jit_type(Z_LVAL_P(ztype));
			ptype->id   = Z_LVAL_P(ztype);
		break;
		
		case IS_OBJECT: {
			php_jit_type_t *patype = PHP_JIT_FETCH_TYPE(ztype);
			if (zpointer) {
				ptype->type = jit_type_create_pointer(patype->type, 1);
				ptype->pt   = (patype->pt + 1);
			} else ptype->type = jit_type_copy(patype->type);
			ptype->id = patype->id;
			ptype->copied = 1;
		} break;
		
		default:
			php_jit_exception("unexpected parameters, expected (int|Type of [, bool pointer = false])");
	}
}
Beispiel #3
0
PHP_METHOD(Struct, __construct) {
	HashTable *zfields;
	HashPosition zposition;
	php_jit_struct_t *pstruct;
	zval *zmember;
	zend_ulong nfield = 0;
	jit_type_t *jfields;
	char **jnames = NULL;
	
	if (php_jit_parameters("H", &zfields) != SUCCESS) {
		php_jit_exception("unexpected parameters, expected (Type[] fields)");
		return;
	}
	
	pstruct = PHP_JIT_FETCH_STRUCT(getThis());
	
	pstruct->nfields = zend_hash_num_elements(zfields);
	pstruct->zfields  = 
		(zval*) ecalloc(pstruct->nfields, sizeof(zval));
	jfields = 
		(jit_type_t*) ecalloc(pstruct->nfields, sizeof(jit_type_t));
	
	for (zend_hash_internal_pointer_reset_ex(zfields, &zposition);
		(zmember = zend_hash_get_current_data_ex(zfields, &zposition));
		zend_hash_move_forward_ex(zfields, &zposition)) {
		zend_ulong znidx = 0L;
		zend_string *zname = NULL;
		php_jit_type_t *ptype;
		
		if (!zmember || 
			Z_TYPE_P(zmember) != IS_OBJECT || 
			!instanceof_function(Z_OBJCE_P(zmember), jit_type_ce)) {
			php_jit_exception("non type found in fields list at %d", nfield);
			return;
		}
		ZVAL_COPY(&pstruct->zfields[nfield], zmember);
		
		ptype = 
		    PHP_JIT_FETCH_TYPE(&pstruct->zfields[nfield]);
		
		jfields[nfield] = jit_type_copy(ptype->type);
		
		if (zend_hash_get_current_key_ex(zfields, &zname, &znidx, &zposition) == HASH_KEY_IS_STRING) {
			if (!zname || !ZSTR_LEN(zname)) {
				php_jit_exception("invalid name found in fields list at %d", nfield);
				efree(jfields);
				return;
			}
			
			if (!pstruct->names) {
				pstruct->names = ecalloc(pstruct->nfields, sizeof(zend_string*));
			}
			
			pstruct->names[nfield] = zend_string_copy(zname);
		} else {
			if (pstruct->names) {
				php_jit_exception("un-named type found in fields list at %d", nfield);
				efree(jfields);
				return;
			}
		}
		
		nfield++;
	}
	
	pstruct->type = jit_type_create_struct(jfields, pstruct->nfields, 0);
	
	if (pstruct->names) {
		jit_type_set_names(pstruct->type, (char**) pstruct->names, pstruct->nfields);	
	}
	
	efree(jfields);
}
Beispiel #4
0
/*@
 * @deftypefun jit_function_t jit_function_create (jit_context_t @var{context}, jit_type_t @var{signature})
 * Create a new function block and associate it with a JIT context.
 * Returns NULL if out of memory.
 *
 * A function persists for the lifetime of its containing context.
 * It initially starts life in the "building" state, where the user
 * constructs instructions that represents the function body.
 * Once the build process is complete, the user calls
 * @code{jit_function_compile} to convert it into its executable form.
 *
 * It is recommended that you call @code{jit_context_build_start} before
 * calling @code{jit_function_create}, and then call
 * @code{jit_context_build_end} after you have called
 * @code{jit_function_compile}.  This will protect the JIT's internal
 * data structures within a multi-threaded environment.
 * @end deftypefun
@*/
jit_function_t
jit_function_create(jit_context_t context, jit_type_t signature)
{
	jit_function_t func;
#if !defined(JIT_BACKEND_INTERP) && (defined(jit_redirector_size) || defined(jit_indirector_size))
	unsigned char *trampoline;
#endif

	/* Acquire the memory context */
	_jit_memory_lock(context);
	if(!_jit_memory_ensure(context))
	{
		_jit_memory_unlock(context);
		return 0;
	}

	/* Allocate memory for the function and clear it */
	func = _jit_memory_alloc_function(context);
	if(!func)
	{
		_jit_memory_unlock(context);
		return 0;
	}

#if !defined(JIT_BACKEND_INTERP) && (defined(jit_redirector_size) || defined(jit_indirector_size))
	trampoline = (unsigned char *) _jit_memory_alloc_trampoline(context);
	if(!trampoline)
	{
		_jit_memory_free_function(context, func);
		_jit_memory_unlock(context);
		return 0;
	}
# if defined(jit_redirector_size)
	func->redirector = trampoline;
	trampoline += jit_redirector_size;
# endif
# if defined(jit_indirector_size)
	func->indirector = trampoline;
# endif
#endif /* !defined(JIT_BACKEND_INTERP) && (defined(jit_redirector_size) || defined(jit_indirector_size)) */

	/* Release the memory context */
	_jit_memory_unlock(context);

	/* Initialize the function block */
	func->context = context;
	func->signature = jit_type_copy(signature);
	func->optimization_level = JIT_OPTLEVEL_NORMAL;

#if !defined(JIT_BACKEND_INTERP) && defined(jit_redirector_size)
	/* If we aren't using interpretation, then point the function's
	   initial entry point at the redirector, which in turn will
	   invoke the on-demand compiler */
	func->entry_point = _jit_create_redirector
		(func->redirector, (void *) context->on_demand_driver,
		 func, jit_type_get_abi(signature));
	_jit_flush_exec(func->redirector, jit_redirector_size);
#endif
#if !defined(JIT_BACKEND_INTERP) && defined(jit_indirector_size)
	_jit_create_indirector(func->indirector, (void**) &(func->entry_point));
	_jit_flush_exec(func->indirector, jit_indirector_size);
#endif

	/* Add the function to the context list */
	func->next = 0;
	func->prev = context->last_function;
	if(context->last_function)
	{
		context->last_function->next = func;
	}
	else
	{
		context->functions = func;
	}
	context->last_function = func;

	/* Return the function to the caller */
	return func;
}
Beispiel #5
0
/*@
 * @deftypefun jit_function_t jit_function_create (jit_context_t @var{context}, jit_type_t @var{signature})
 * Create a new function block and associate it with a JIT context.
 * Returns NULL if out of memory.
 *
 * A function persists for the lifetime of its containing context.
 * It initially starts life in the "building" state, where the user
 * constructs instructions that represents the function body.
 * Once the build process is complete, the user calls
 * @code{jit_function_compile} to convert it into its executable form.
 *
 * It is recommended that you call @code{jit_context_build_start} before
 * calling @code{jit_function_create}, and then call
 * @code{jit_context_build_end} after you have called
 * @code{jit_function_compile}.  This will protect the JIT's internal
 * data structures within a multi-threaded environment.
 * @end deftypefun
@*/
jit_function_t jit_function_create(jit_context_t context, jit_type_t signature)
{
	jit_function_t func;
#if !defined(JIT_BACKEND_INTERP) && (defined(jit_redirector_size) || defined(jit_indirector_size))
	jit_cache_t cache;
#endif

	/* Allocate memory for the function and clear it */
	func = jit_cnew(struct _jit_function);
	if(!func)
	{
		return 0;
	}

#if !defined(JIT_BACKEND_INTERP) && (defined(jit_redirector_size) || defined(jit_indirector_size))
	/* TODO: if the function is destroyed the redirector and indirector memory
	   is leaked */

	/* We need the cache lock while we are allocating redirector and indirector */
	jit_mutex_lock(&(context->cache_lock));

	/* Get the method cache */
	cache = _jit_context_get_cache(context);
	if(!cache)
	{
		jit_mutex_unlock(&(context->cache_lock));
		jit_free(func);
		return 0;
	}
    func->compilation_success_callback = 0;
    func->insn_compilation_callback = 0;
    func->current_code_location_start_column = 0;
    func->current_code_location_end_column = 0;
    func->current_code_location_start_line = 0;
    func->current_code_location_end_line = 0;

# if defined(jit_redirector_size)
	/* Allocate redirector buffer */
	func->redirector = _jit_cache_alloc_no_method(cache, jit_redirector_size, 1);
	if(!func->redirector)
	{
		jit_mutex_unlock(&(context->cache_lock));
		jit_free(func);
		return 0;
	}
# endif
# if defined(jit_indirector_size)
	/* Allocate indirector buffer */
	func->indirector = _jit_cache_alloc_no_method(cache, jit_indirector_size, 1);
	if(!func->indirector)
	{
		jit_mutex_unlock(&(context->cache_lock));
		jit_free(func);
		return 0;
	}
# endif

	jit_mutex_unlock(&(context->cache_lock));
#endif /* !defined(JIT_BACKEND_INTERP) && (defined(jit_redirector_size) || defined(jit_indirector_size)) */

	/* Initialize the function block */
	func->context = context;
	func->signature = jit_type_copy(signature);
	func->optimization_level = JIT_OPTLEVEL_NORMAL;

#if !defined(JIT_BACKEND_INTERP) && defined(jit_redirector_size)
	/* If we aren't using interpretation, then point the function's
	   initial entry point at the redirector, which in turn will
	   invoke the on-demand compiler */
	func->entry_point = _jit_create_redirector
		(func->redirector, (void *) context->on_demand_driver,
		 func, jit_type_get_abi(signature));
	jit_flush_exec(func->redirector, jit_redirector_size);
#endif
#if !defined(JIT_BACKEND_INTERP) && defined(jit_indirector_size)
	_jit_create_indirector(func->indirector, (void**) &(func->entry_point));
	jit_flush_exec(func->indirector, jit_indirector_size);
#endif

	/* Add the function to the context list */
	func->next = 0;
	func->prev = context->last_function;
	if(context->last_function)
	{
		context->last_function->next = func;
	}
	else
	{
		context->functions = func;
	}
	context->last_function = func;

	/* Return the function to the caller */
	return func;
}