Update Files

This commit is contained in:
2025-01-22 16:18:30 +01:00
parent ed4603cf95
commit a36294b518
16718 changed files with 2960346 additions and 0 deletions

View File

@ -0,0 +1,589 @@
/*
* Copyright (C)2005-2020 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "hl.h"
#ifdef HL_WIN
# include <intrin.h>
static unsigned int __inline TRAILING_ONES( unsigned int x ) {
DWORD msb = 0;
if( _BitScanForward( &msb, ~x ) )
return msb;
return 32;
}
static unsigned int __inline TRAILING_ZEROES( unsigned int x ) {
DWORD msb = 0;
if( _BitScanForward( &msb, x ) )
return msb;
return 32;
}
#else
static inline unsigned int TRAILING_ONES( unsigned int x ) {
return (~x) ? __builtin_ctz(~x) : 32;
}
static inline unsigned int TRAILING_ZEROES( unsigned int x ) {
return x ? __builtin_ctz(x) : 32;
}
#endif
#define GC_PARTITIONS 9
#define GC_PART_BITS 4
#define GC_FIXED_PARTS 5
#define GC_LARGE_PART (GC_PARTITIONS-1)
#define GC_LARGE_BLOCK (1 << 20)
static const int GC_SBITS[GC_PARTITIONS] = {0,0,0,0,0, 3,6,13,0};
#ifdef HL_64
static const int GC_SIZES[GC_PARTITIONS] = {8,16,24,32,40, 8,64,1<<13,0};
# define GC_ALIGN_BITS 3
#else
static const int GC_SIZES[GC_PARTITIONS] = {4,8,12,16,20, 8,64,1<<13,0};
# define GC_ALIGN_BITS 2
#endif
#define GC_ALL_PAGES (GC_PARTITIONS << PAGE_KIND_BITS)
#define GC_ALIGN (1 << GC_ALIGN_BITS)
static gc_pheader *gc_pages[GC_ALL_PAGES] = {NULL};
static gc_pheader *gc_free_pages[GC_ALL_PAGES] = {NULL};
#define MAX_FL_CACHED 16
typedef struct {
int count;
gc_fl *data[MAX_FL_CACHED];
} cached_slot;
static cached_slot cached_slots[32] = {0};
static int free_lists_size = 0;
static int free_lists_count = 0;
static void alloc_freelist( gc_freelist *fl, int size ) {
cached_slot *slot = &cached_slots[size];
if( slot->count ) {
fl->data = slot->data[--slot->count];
fl->size_bits = size;
fl->count = 0;
fl->current = 0;
return;
}
int bytes = (int)sizeof(gc_fl) * (1<<size);
free_lists_size += bytes;
free_lists_count++;
fl->data = (gc_fl*)malloc(bytes);
fl->count = 0;
fl->current = 0;
fl->size_bits = size;
}
static void free_freelist( gc_freelist *fl ) {
cached_slot *slot = &cached_slots[fl->size_bits];
if( slot->count == MAX_FL_CACHED ) {
free(fl->data);
free_lists_size -= (int)sizeof(gc_fl) * (1 << fl->size_bits);
return;
}
slot->data[slot->count++] = fl->data;
}
#define GET_FL(fl,pos) ((fl)->data + (pos))
static void freelist_append( gc_freelist *fl, int pos, int count ) {
if( fl->count == 1<<fl->size_bits ) {
# ifdef GC_DEBUG
if( fl->current ) hl_fatal("assert");
# endif
gc_freelist fl2;
alloc_freelist(&fl2, fl->size_bits + 1);
memcpy(GET_FL(&fl2,0),GET_FL(fl,0),sizeof(gc_fl)*fl->count);
free_freelist(fl);
fl->size_bits++;
fl->data = fl2.data;
}
gc_fl *p = GET_FL(fl,fl->count++);
p->pos = (fl_cursor)pos;
p->count = (fl_cursor)count;
}
static gc_pheader *gc_allocator_new_page( int pid, int block, int size, int kind, bool varsize ) {
// increase size based on previously allocated pages
if( block < 256 ) {
int num_pages = 0;
gc_pheader *ph = gc_pages[pid];
while( ph ) {
num_pages++;
ph = ph->next_page;
}
while( num_pages > 8 && (size<<1) / block <= GC_PAGE_SIZE ) {
size <<= 1;
num_pages /= 3;
}
}
int start_pos = 0;
int max_blocks = size / block;
gc_pheader *ph = gc_alloc_page(size, kind, max_blocks);
gc_allocator_page_data *p = &ph->alloc;
p->block_size = block;
p->max_blocks = max_blocks;
p->sizes = NULL;
if( p->max_blocks > GC_PAGE_SIZE )
hl_fatal("Too many blocks for this page");
if( varsize ) {
if( p->max_blocks <= 8 )
p->sizes = (unsigned char*)&p->sizes_ref;
else {
p->sizes = ph->base + start_pos;
start_pos += p->max_blocks;
start_pos += (-start_pos) & 63; // align on cache line
}
MZERO(p->sizes,p->max_blocks);
}
int m = start_pos % block;
if( m ) start_pos += block - m;
int fl_bits = 1;
while( fl_bits < 8 && (1<<fl_bits) < (p->max_blocks>>3) ) fl_bits++;
p->first_block = start_pos / block;
alloc_freelist(&p->free,fl_bits);
freelist_append(&p->free,p->first_block, p->max_blocks - p->first_block);
p->need_flush = false;
ph->next_page = gc_pages[pid];
gc_pages[pid] = ph;
return ph;
}
static void flush_free_list( gc_pheader *ph ) {
gc_allocator_page_data *p = &ph->alloc;
int bid = p->first_block;
int last = p->max_blocks;
gc_freelist new_fl;
alloc_freelist(&new_fl,p->free.size_bits);
gc_freelist old_fl = p->free;
gc_fl *cur_pos = NULL;
int reuse_index = old_fl.current;
gc_fl *reuse = reuse_index < old_fl.count ? GET_FL(&old_fl,reuse_index++) : NULL;
int next_bid = reuse ? reuse->pos : -1;
unsigned char *bmp = ph->bmp;
while( bid < last ) {
if( bid == next_bid ) {
if( cur_pos && cur_pos->pos + cur_pos->count == bid ) {
cur_pos->count += reuse->count;
} else {
freelist_append(&new_fl,reuse->pos,reuse->count);
cur_pos = GET_FL(&new_fl,new_fl.count - 1);
}
reuse = reuse_index < old_fl.count ? GET_FL(&old_fl,reuse_index++) : NULL;
bid = cur_pos->count + cur_pos->pos;
next_bid = reuse ? reuse->pos : -1;
continue;
}
fl_cursor count;
if( p->sizes ) {
count = p->sizes[bid];
if( !count ) count = 1;
} else
count = 1;
if( (bmp[bid>>3] & (1<<(bid&7))) == 0 ) {
if( p->sizes ) p->sizes[bid] = 0;
if( cur_pos && cur_pos->pos + cur_pos->count == bid )
cur_pos->count += count;
else {
freelist_append(&new_fl,bid,count);
cur_pos = GET_FL(&new_fl,new_fl.count - 1);
}
}
bid += count;
}
p->free = new_fl;
p->need_flush = false;
#ifdef __GC_DEBUG
if( ph->page_id == -1 ) {
int k;
for(k=0;k<p->free.count;k++) {
gc_fl *fl = GET_FL(&p->free,k);
printf("(%d-%d)",fl->pos,fl->pos+fl->count-1);
}
printf("\n");
}
if( reuse && reuse->count ) hl_fatal("assert");
for(bid=p->first_block;bid<p->max_blocks;bid++) {
int k;
bool is_free = false;
for(k=0;k<p->free.count;k++) {
gc_fl *fl = GET_FL(&p->free,k);
if( fl->pos < p->first_block || fl->pos + fl->count > p->max_blocks ) hl_fatal("assert");
if( bid >= fl->pos && bid < fl->pos + fl->count ) {
if( is_free ) hl_fatal("assert");
is_free = true;
}
}
bool is_marked = ((ph->bmp[bid>>3] & (1<<(bid&7))) != 0);
if( is_marked && is_free ) {
// check if it was already free before
for(k=0;k<old_fl.count;k++) {
gc_fl *fl = GET_FL(&old_fl,k);
if( bid >= fl->pos && bid < fl->pos+fl->count ) {
is_marked = false; // false positive
ph->bmp[bid>>3] &= ~(1<<(bid&7));
break;
}
}
}
if( is_free == is_marked )
hl_fatal("assert");
if( p->sizes && !is_free )
bid += p->sizes[bid]-1;
}
#endif
free_freelist(&old_fl);
}
static void *gc_alloc_fixed( int part, int kind ) {
int pid = (part << PAGE_KIND_BITS) | kind;
gc_pheader *ph = gc_free_pages[pid];
gc_allocator_page_data *p = NULL;
int bid = -1;
while( ph ) {
p = &ph->alloc;
if( p->need_flush )
flush_free_list(ph);
gc_freelist *fl = &p->free;
if( fl->current < fl->count ) {
gc_fl *c = GET_FL(fl,fl->current);
bid = c->pos++;
c->count--;
# ifdef GC_DEBUG
if( c->count < 0 ) hl_fatal("assert");
# endif
if( !c->count ) fl->current++;
break;
}
ph = ph->next_page;
}
if( ph == NULL ) {
ph = gc_allocator_new_page(pid, GC_SIZES[part], GC_PAGE_SIZE, kind, false);
p = &ph->alloc;
bid = p->free.data->pos++;
p->free.data->count--;
}
unsigned char *ptr = ph->base + bid * p->block_size;
# ifdef GC_DEBUG
{
int i;
if( bid < p->first_block || bid >= p->max_blocks )
hl_fatal("assert");
for(i=0;i<p->block_size;i++)
if( ptr[i] != 0xDD )
hl_fatal("assert");
}
# endif
gc_free_pages[pid] = ph;
return ptr;
}
static void *gc_alloc_var( int part, int size, int kind ) {
int pid = (part << PAGE_KIND_BITS) | kind;
gc_pheader *ph = gc_free_pages[pid];
gc_allocator_page_data *p = NULL;
unsigned char *ptr;
fl_cursor nblocks = (fl_cursor)(size >> GC_SBITS[part]);
int bid = -1;
while( ph ) {
p = &ph->alloc;
if( p->need_flush )
flush_free_list(ph);
gc_freelist *fl = &p->free;
int k;
for(k=fl->current;k<fl->count;k++) {
gc_fl *c = GET_FL(fl,k);
if( c->count >= nblocks ) {
bid = c->pos;
c->pos += nblocks;
c->count -= nblocks;
# ifdef GC_DEBUG
if( c->count < 0 ) hl_fatal("assert");
# endif
if( c->count == 0 ) fl->current++;
goto alloc_var;
}
}
ph = ph->next_page;
}
if( ph == NULL ) {
int psize = GC_PAGE_SIZE;
while( psize < size + 1024 )
psize <<= 1;
ph = gc_allocator_new_page(pid, GC_SIZES[part], psize, kind, true);
p = &ph->alloc;
bid = p->first_block;
p->free.data->pos += nblocks;
p->free.data->count -= nblocks;
}
alloc_var:
ptr = ph->base + bid * p->block_size;
# ifdef GC_DEBUG
{
int i;
if( bid < p->first_block || bid + nblocks > p->max_blocks )
hl_fatal("assert");
for(i=0;i<size;i++)
if( ptr[i] != 0xDD )
hl_fatal("assert");
}
# endif
if( ph->bmp ) {
# ifdef GC_DEBUG
int i;
for(i=0;i<nblocks;i++) {
int b = bid + i;
if( (ph->bmp[b>>3]&(1<<(b&7))) != 0 ) hl_fatal("Alloc on marked block");
}
# endif
ph->bmp[bid>>3] |= 1<<(bid&7);
}
if( nblocks > 1 ) MZERO(p->sizes + bid, nblocks);
p->sizes[bid] = (unsigned char)nblocks;
gc_free_pages[pid] = ph;
return ptr;
}
static void *gc_allocator_alloc( int *size, int page_kind ) {
int sz = *size;
sz += (-sz) & (GC_ALIGN - 1);
if( sz >= GC_LARGE_BLOCK ) {
sz += (-sz) & (GC_PAGE_SIZE - 1);
*size = sz;
gc_pheader *ph = gc_allocator_new_page((GC_LARGE_PART << PAGE_KIND_BITS) | page_kind,sz,sz,page_kind,false);
return ph->base;
}
if( sz <= GC_SIZES[GC_FIXED_PARTS-1] && page_kind != MEM_KIND_FINALIZER ) {
int part = (sz >> GC_ALIGN_BITS) - 1;
*size = GC_SIZES[part];
return gc_alloc_fixed(part, page_kind);
}
int p;
for(p=GC_FIXED_PARTS;p<GC_PARTITIONS;p++) {
int block = GC_SIZES[p];
int query = sz + ((-sz) & (block - 1));
if( query < block * 255 ) {
*size = query;
return gc_alloc_var(p, query, page_kind);
}
}
*size = -1;
return NULL;
}
static bool is_zero( void *ptr, int size ) {
static char ZEROMEM[256] = {0};
unsigned char *p = (unsigned char*)ptr;
while( size>>8 ) {
if( memcmp(p,ZEROMEM,256) ) return false;
p += 256;
size -= 256;
}
return memcmp(p,ZEROMEM,size) == 0;
}
static void gc_flush_empty_pages() {
int i;
for(i=0;i<GC_ALL_PAGES;i++) {
gc_pheader *ph = gc_pages[i];
gc_pheader *prev = NULL;
while( ph ) {
gc_allocator_page_data *p = &ph->alloc;
gc_pheader *next = ph->next_page;
if( ph->bmp && is_zero(ph->bmp+(p->first_block>>3),((p->max_blocks+7)>>3) - (p->first_block>>3)) ) {
if( prev )
prev->next_page = next;
else
gc_pages[i] = next;
if( gc_free_pages[i] == ph )
gc_free_pages[i] = next;
free_freelist(&p->free);
gc_free_page(ph, p->max_blocks);
} else
prev = ph;
ph = next;
}
}
}
#ifdef GC_DEBUG
static void gc_clear_unmarked_mem() {
int i;
for(i=0;i<GC_ALL_PAGES;i++) {
gc_pheader *ph = gc_pages[i];
while( ph ) {
int bid;
gc_allocator_page_data *p = &ph->alloc;
for(bid=p->first_block;bid<p->max_blocks;bid++) {
if( p->sizes && !p->sizes[bid] ) continue;
int size = p->sizes ? p->sizes[bid] * p->block_size : p->block_size;
unsigned char *ptr = ph->base + bid * p->block_size;
if( bid * p->block_size + size > ph->page_size ) hl_fatal("invalid block size");
# ifdef GC_MEMCHK
int_val eob = *(int_val*)(ptr + size - HL_WSIZE);
# ifdef HL_64
if( eob != 0xEEEEEEEEEEEEEEEE && eob != 0xDDDDDDDDDDDDDDDD )
# else
if( eob != 0xEEEEEEEE && eob != 0xDDDDDDDD )
# endif
hl_fatal("Block written out of bounds");
# endif
if( (ph->bmp[bid>>3] & (1<<(bid&7))) == 0 ) {
memset(ptr,0xDD,size);
if( p->sizes ) p->sizes[bid] = 0;
}
}
ph = ph->next_page;
}
}
}
#endif
static void gc_call_finalizers(){
int i;
for(i=MEM_KIND_FINALIZER;i<GC_ALL_PAGES;i+=1<<PAGE_KIND_BITS) {
gc_pheader *ph = gc_pages[i];
while( ph ) {
int bid;
gc_allocator_page_data *p = &ph->alloc;
for(bid=p->first_block;bid<p->max_blocks;bid++) {
int size = p->sizes[bid];
if( !size ) continue;
if( (ph->bmp[bid>>3] & (1<<(bid&7))) == 0 ) {
unsigned char *ptr = ph->base + bid * p->block_size;
void *finalizer = *(void**)ptr;
p->sizes[bid] = 0;
if( finalizer )
((void(*)(void *))finalizer)(ptr);
# ifdef GC_DEBUG
memset(ptr,0xDD,size*p->block_size);
# endif
}
}
ph = ph->next_page;
}
}
}
static void gc_allocator_before_mark( unsigned char *mark_cur ) {
int pid;
for(pid=0;pid<GC_ALL_PAGES;pid++) {
gc_pheader *p = gc_pages[pid];
gc_free_pages[pid] = p;
while( p ) {
p->bmp = mark_cur;
p->alloc.need_flush = true;
mark_cur += (p->alloc.max_blocks + 7) >> 3;
p = p->next_page;
}
}
}
#define gc_allocator_fast_block_size(page,block) \
(page->alloc.sizes ? page->alloc.sizes[(int)(((unsigned char*)(block)) - page->base) / page->alloc.block_size] * page->alloc.block_size : page->alloc.block_size)
static void gc_allocator_init() {
if( TRAILING_ONES(0x080003FF) != 10 || TRAILING_ONES(0) != 0 || TRAILING_ONES(0xFFFFFFFF) != 32 )
hl_fatal("Invalid builtin tl1");
if( TRAILING_ZEROES((unsigned)~0x080003FF) != 10 || TRAILING_ZEROES(0) != 32 || TRAILING_ZEROES(0xFFFFFFFF) != 0 )
hl_fatal("Invalid builtin tl0");
}
static int gc_allocator_get_block_id( gc_pheader *page, void *block ) {
int offset = (int)((unsigned char*)block - page->base);
if( offset%page->alloc.block_size != 0 )
return -1;
int bid = offset / page->alloc.block_size;
if( page->alloc.sizes && page->alloc.sizes[bid] == 0 ) return -1;
return bid;
}
#ifdef GC_INTERIOR_POINTERS
static int gc_allocator_get_block_interior( gc_pheader *page, void **block ) {
int offset = (int)((unsigned char*)*block - page->base);
int bid = offset / page->alloc.block_size;
if( page->alloc.sizes ) {
if( bid < page->alloc.first_block ) return -1;
while( page->alloc.sizes[bid] == 0 ) {
if( bid == page->alloc.first_block ) return -1;
bid--;
}
}
*block = page->base + bid * page->alloc.block_size;
return bid;
}
#endif
static void gc_allocator_after_mark() {
gc_call_finalizers();
# ifdef GC_DEBUG
gc_clear_unmarked_mem();
# endif
gc_flush_empty_pages();
}
static void gc_get_stats( int *page_count, int *private_data ) {
int count = 0;
int i;
for(i=0;i<GC_ALL_PAGES;i++) {
gc_pheader *p = gc_pages[i];
while( p ) {
count++;
p = p->next_page;
}
}
*page_count = count;
*private_data = 0; // no malloc
}
static void gc_iter_pages( gc_page_iterator iter ) {
int i;
for(i=0;i<GC_ALL_PAGES;i++) {
gc_pheader *p = gc_pages[i];
while( p ) {
int size = 0;
if( p->alloc.sizes && p->alloc.max_blocks > 8 ) size = p->alloc.max_blocks;
iter(p,size);
p = p->next_page;
}
}
}
static void gc_iter_live_blocks( gc_pheader *ph, gc_block_iterator iter ) {
int i;
gc_allocator_page_data *p = &ph->alloc;
for(i=0;i<p->max_blocks;i++) {
if( ph->bmp[(i>>3)] & (1<<(i&7)) )
iter(ph->base + i*p->block_size,p->sizes?p->sizes[i]*p->block_size:p->block_size);
}
}

View File

@ -0,0 +1,27 @@
typedef unsigned short fl_cursor;
typedef struct {
fl_cursor pos;
fl_cursor count;
} gc_fl;
typedef struct _gc_freelist {
int current;
int count;
int size_bits;
gc_fl *data;
} gc_freelist;
typedef struct {
int block_size;
int max_blocks;
int first_block;
bool need_flush;
// mutable
gc_freelist free;
unsigned char *sizes;
int sizes_ref;
int sizes_ref2;
} gc_allocator_page_data;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,157 @@
/*
* Copyright (C)2015-2016 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <hl.h>
#include <hlmodule.h>
struct _hl_socket;
typedef struct _hl_socket hl_socket;
HL_API void hl_socket_init();
HL_API hl_socket *hl_socket_new( bool udp );
HL_API bool hl_socket_bind( hl_socket *s, int host, int port );
HL_API bool hl_socket_listen( hl_socket *s, int n );
HL_API void hl_socket_close( hl_socket *s );
HL_API hl_socket *hl_socket_accept( hl_socket *s );
HL_API int hl_socket_send( hl_socket *s, vbyte *buf, int pos, int len );
HL_API int hl_socket_recv( hl_socket *s, vbyte *buf, int pos, int len );
HL_API void hl_sys_sleep( double t );
HL_API int hl_sys_getpid();
HL_API int hl_closure_stack_capture;
static hl_socket *debug_socket = NULL;
static hl_socket *client_socket = NULL;
static bool debugger_connected = false;
static bool debugger_stopped = false;
#define send hl_send_data
static void send( void *ptr, int size ) {
hl_socket_send(client_socket, ptr, 0, size);
}
static void hl_debug_loop( hl_module *m ) {
void *inf_addr = hl_gc_threads_info();
int flags = 0;
int hl_ver = HL_VERSION;
bool loop = false;
int pid = hl_sys_getpid();
# ifdef HL_64
flags |= 1;
# endif
if( sizeof(bool) == 4 ) flags |= 2;
# ifdef HL_THREADS
flags |= 4;
loop = true;
# endif
# ifdef HL_WIN_CALL
flags |= 8;
# endif
hl_get_thread()->flags |= HL_THREAD_INVISIBLE;
do {
int i;
vbyte cmd;
hl_socket *s = hl_socket_accept(debug_socket);
if( s == NULL ) break;
client_socket = s;
send("HLD1",4);
send(&flags,4);
send(&hl_ver, 4);
send(&pid,4);
send(&inf_addr, sizeof(void*));
send(&m->globals_data,sizeof(void*));
send(&m->jit_code,sizeof(void*));
send(&m->codesize,4);
send(&m->code->types,sizeof(void*));
for(i=1;i<=HBYTES;i++) {
hl_type t = {(hl_type_kind)i};
int k = 1 + hl_pad_struct(1,&t);
send(&k,4);
}
send(&m->code->nfunctions,4);
for(i=0;i<m->code->nfunctions;i++) {
hl_function *f = m->code->functions + i;
hl_debug_infos *d = m->jit_debug + i;
struct {
int nops;
int start;
unsigned char large;
} fdata;
fdata.nops = f->nops;
fdata.start = d->start;
fdata.large = (unsigned char)d->large;
send(&fdata,9);
send(d->offsets,(d->large ? sizeof(int) : sizeof(unsigned short)) * (f->nops + 1));
}
hl_closure_stack_capture = 8;
// wait answer
// for some reason, this is not working on windows (recv returns 0 ?)
hl_socket_recv(s,&cmd,0,1);
hl_socket_close(s);
debugger_connected = true;
client_socket = NULL;
} while( loop );
debugger_stopped = true;
}
h_bool hl_module_debug( hl_module *m, int port, h_bool wait ) {
hl_socket *s;
hl_socket_init();
s = hl_socket_new(false);
if( s == NULL ) return false;
if( !hl_socket_bind(s,0x0100007F/*127.0.0.1*/,port) || !hl_socket_listen(s, 10) ) {
hl_socket_close(s);
return false;
}
debug_socket = s;
# ifdef HL_THREADS
hl_add_root(&debug_socket);
hl_add_root(&client_socket);
if( !hl_thread_start(hl_debug_loop, m, true) ) {
hl_socket_close(s);
return false;
}
if( wait ) {
while( !debugger_connected )
hl_sys_sleep(0.01);
}
# else
// imply --debug-wait
hl_debug_loop(m);
hl_socket_close(debug_socket);
debug_socket = NULL;
# endif
return true;
}
void hl_module_debug_stop() {
if( !debug_socket ) return;
# ifdef HL_THREADS
hl_socket_close(debug_socket);
while( !debugger_stopped )
hl_sys_sleep(0.01);
hl_remove_root(&debug_socket);
hl_remove_root(&client_socket);
# endif
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,967 @@
/*
* Copyright (C)2005-2016 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef HL_H
#define HL_H
/**
Detailed documentation can be found here:
https://github.com/HaxeFoundation/hashlink/wiki/
**/
#define HL_VERSION 0x010D00
#if defined(_WIN32)
# define HL_WIN
# ifndef _DURANGO
# define HL_WIN_DESKTOP
# endif
#endif
#if defined(__APPLE__) || defined(__MACH__) || defined(macintosh)
#include <TargetConditionals.h>
#if TARGET_OS_IOS
#define HL_IOS
#elif TARGET_OS_TV
#define HL_TVOS
#elif TARGET_OS_MAC
#define HL_MAC
#endif
#endif
#ifdef __ANDROID__
# define HL_ANDROID
#endif
#if defined(linux) || defined(__linux__)
# define HL_LINUX
# ifndef _GNU_SOURCE
# define _GNU_SOURCE
# endif
#endif
#if defined(HL_IOS) || defined(HL_ANDROID) || defined(HL_TVOS)
# define HL_MOBILE
#endif
#ifdef __ORBIS__
# define HL_PS
#endif
#ifdef __NX__
# define HL_NX
#endif
#ifdef _DURANGO
# define HL_XBO
#endif
#if defined(HL_PS) || defined(HL_NX) || defined(HL_XBO)
# define HL_CONSOLE
#endif
#if (defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)) && !defined(HL_CONSOLE)
# define HL_BSD
#endif
#if defined(_64BITS) || defined(__x86_64__) || defined(_M_X64) || defined(__LP64__)
# define HL_64
#endif
#if defined(__GNUC__)
# define HL_GCC
#endif
#if defined(__MINGW32__)
# define HL_MINGW
#endif
#if defined(__CYGWIN__)
# define HL_CYGWIN
#endif
#if defined(__llvm__)
# define HL_LLVM
#endif
#if defined(__clang__)
# define HL_CLANG
#endif
#if defined(_MSC_VER) && !defined(HL_LLVM)
# define HL_VCC
# pragma warning(disable:4996) // remove deprecated C API usage warnings
# pragma warning(disable:4055) // void* - to - function cast
# pragma warning(disable:4152) // void* - to - function cast
# pragma warning(disable:4201) // anonymous struct
# pragma warning(disable:4127) // while( true )
# pragma warning(disable:4710) // inline disabled
# pragma warning(disable:4711) // inline activated
# pragma warning(disable:4255) // windows include
# pragma warning(disable:4820) // windows include
# pragma warning(disable:4668) // windows include
# pragma warning(disable:4738) // return float bad performances
# pragma warning(disable:4061) // explicit values in switch
# if (_MSC_VER >= 1920)
# pragma warning(disable:5045) // spectre
# endif
#endif
#if defined(HL_VCC) || defined(HL_MINGW) || defined(HL_CYGWIN)
# define HL_WIN_CALL
#endif
#ifdef _DEBUG
# define HL_DEBUG
#endif
#ifndef HL_CONSOLE
# define HL_TRACK_ENABLE
#endif
#ifndef HL_NO_THREADS
# define HL_THREADS
# ifdef HL_VCC
# define HL_THREAD_VAR __declspec( thread )
# define HL_THREAD_STATIC_VAR HL_THREAD_VAR static
# else
# define HL_THREAD_VAR __thread
# define HL_THREAD_STATIC_VAR static HL_THREAD_VAR
# endif
#else
# define HL_THREAD_VAR
# define HL_THREAD_STATIC_VAR static
#endif
#include <stddef.h>
#ifndef HL_VCC
# include <stdint.h>
#endif
#if defined(HL_VCC) || defined(HL_MINGW)
# define EXPORT __declspec( dllexport )
# define IMPORT __declspec( dllimport )
#else
#if defined(HL_GCC) || defined(HL_CLANG)
# define EXPORT __attribute__((visibility("default")))
#else
# define EXPORT
#endif
# define IMPORT extern
#endif
#ifdef HL_64
# define HL_WSIZE 8
# define IS_64 1
# ifdef HL_VCC
# define _PTR_FMT L"%IX"
# else
# define _PTR_FMT u"%lX"
# endif
#else
# define HL_WSIZE 4
# define IS_64 0
# ifdef HL_VCC
# define _PTR_FMT L"%IX"
# else
# define _PTR_FMT u"%X"
# endif
#endif
#ifdef __cplusplus
# define C_FUNCTION_BEGIN extern "C" {
# define C_FUNCTION_END };
#else
# define C_FUNCTION_BEGIN
# define C_FUNCTION_END
#endif
typedef intptr_t int_val;
typedef long long int64;
typedef unsigned long long uint64;
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <memory.h>
#if defined(LIBHL_EXPORTS)
#define HL_API extern EXPORT
#elif defined(LIBHL_STATIC)
#define HL_API extern
#else
#define HL_API IMPORT
#endif
#if defined(HL_VCC)
#define HL_INLINE __inline
#else
#define HL_INLINE inline
#endif
// -------------- UNICODE -----------------------------------
#if defined(HL_WIN) && !defined(HL_LLVM)
#if defined(HL_WIN_DESKTOP) && !defined(HL_MINGW)
# include <Windows.h>
#elif defined(HL_WIN_DESKTOP) && defined(HL_MINGW)
# include<windows.h>
#else
# include <xdk.h>
#endif
# include <wchar.h>
typedef wchar_t uchar;
# define USTR(str) L##str
# define HL_NATIVE_UCHAR_FUN
# define usprintf swprintf
# define uprintf wprintf
# define ustrlen wcslen
# define ustrdup _wcsdup
HL_API int uvszprintf( uchar *out, int out_size, const uchar *fmt, va_list arglist );
# define utod(s,end) wcstod(s,end)
# define utoi(s,end) wcstol(s,end,10)
# define ucmp(a,b) wcscmp(a,b)
# define utostr(out,size,str) wcstombs(out,str,size)
#elif defined(HL_MAC)
typedef uint16_t uchar;
# undef USTR
# define USTR(str) u##str
#else
# include <stdarg.h>
#if defined(HL_IOS) || defined(HL_TVOS) || defined(HL_MAC)
#include <stddef.h>
#include <stdint.h>
#if !defined(__cplusplus) || __cplusplus < 201103L
typedef uint16_t char16_t;
typedef uint32_t char32_t;
#endif
#else
# include <uchar.h>
#endif
typedef char16_t uchar;
# undef USTR
# define USTR(str) u##str
#endif
C_FUNCTION_BEGIN
#ifndef HL_NATIVE_UCHAR_FUN
HL_API double utod( const uchar *str, uchar **end );
HL_API int utoi( const uchar *str, uchar **end );
HL_API int ustrlen( const uchar *str );
HL_API uchar *ustrdup( const uchar *str );
HL_API int ucmp( const uchar *a, const uchar *b );
HL_API int utostr( char *out, int out_size, const uchar *str );
HL_API int usprintf( uchar *out, int out_size, const uchar *fmt, ... );
HL_API int uvszprintf( uchar *out, int out_size, const uchar *fmt, va_list arglist );
HL_API void uprintf( const uchar *fmt, const uchar *str );
#endif
C_FUNCTION_END
#if defined(HL_VCC)
# define hl_debug_break() if( IsDebuggerPresent() ) __debugbreak()
#elif defined(HL_PS) && defined(_DEBUG)
# define hl_debug_break() __debugbreak()
#elif defined(HL_NX)
C_FUNCTION_BEGIN
HL_API void hl_debug_break( void );
C_FUNCTION_END
#elif defined(HL_LINUX) && defined(__i386__)
# ifdef HL_64
# define hl_debug_break() \
if( hl_detect_debugger() ) \
__asm__("0: int3;" \
".pushsection embed-breakpoints;" \
".quad 0b;" \
".popsection")
# else
# define hl_debug_break() \
if( hl_detect_debugger() ) \
__asm__("0: int3;" \
".pushsection embed-breakpoints;" \
".long 0b;" \
".popsection")
# endif
#elif defined(HL_MAC)
#include <signal.h>
#include <mach/mach.h>
# define hl_debug_break() \
if( hl_detect_debugger() ) \
raise(SIGTRAP);//__builtin_trap();
#else
# define hl_debug_break()
#endif
#ifdef HL_VCC
# define HL_NO_RETURN(f) __declspec(noreturn) f
# define HL_UNREACHABLE
#else
# define HL_NO_RETURN(f) f __attribute__((noreturn))
# define HL_UNREACHABLE __builtin_unreachable()
#endif
// ---- TYPES -------------------------------------------
typedef enum {
HVOID = 0,
HUI8 = 1,
HUI16 = 2,
HI32 = 3,
HI64 = 4,
HF32 = 5,
HF64 = 6,
HBOOL = 7,
HBYTES = 8,
HDYN = 9,
HFUN = 10,
HOBJ = 11,
HARRAY = 12,
HTYPE = 13,
HREF = 14,
HVIRTUAL= 15,
HDYNOBJ = 16,
HABSTRACT=17,
HENUM = 18,
HNULL = 19,
HMETHOD = 20,
HSTRUCT = 21,
HPACKED = 22,
// ---------
HLAST = 23,
_H_FORCE_INT = 0x7FFFFFFF
} hl_type_kind;
typedef struct hl_type hl_type;
typedef struct hl_runtime_obj hl_runtime_obj;
typedef struct hl_alloc_block hl_alloc_block;
typedef struct { hl_alloc_block *cur; } hl_alloc;
typedef struct _hl_field_lookup hl_field_lookup;
typedef struct {
hl_alloc alloc;
void **functions_ptrs;
hl_type **functions_types;
} hl_module_context;
typedef struct {
hl_type **args;
hl_type *ret;
int nargs;
// storage for closure
hl_type *parent;
struct {
hl_type_kind kind;
void *p;
} closure_type;
struct {
hl_type **args;
hl_type *ret;
int nargs;
hl_type *parent;
} closure;
} hl_type_fun;
typedef struct {
const uchar *name;
hl_type *t;
int hashed_name;
} hl_obj_field;
typedef struct {
const uchar *name;
int findex;
int pindex;
int hashed_name;
} hl_obj_proto;
typedef struct {
int nfields;
int nproto;
int nbindings;
const uchar *name;
hl_type *super;
hl_obj_field *fields;
hl_obj_proto *proto;
int *bindings;
void **global_value;
hl_module_context *m;
hl_runtime_obj *rt;
} hl_type_obj;
typedef struct {
hl_obj_field *fields;
int nfields;
// runtime
int dataSize;
int *indexes;
hl_field_lookup *lookup;
} hl_type_virtual;
typedef struct {
const uchar *name;
int nparams;
hl_type **params;
int size;
bool hasptr;
int *offsets;
} hl_enum_construct;
typedef struct {
const uchar *name;
int nconstructs;
hl_enum_construct *constructs;
void **global_value;
} hl_type_enum;
struct hl_type {
hl_type_kind kind;
union {
const uchar *abs_name;
hl_type_fun *fun;
hl_type_obj *obj;
hl_type_enum *tenum;
hl_type_virtual *virt;
hl_type *tparam;
};
void **vobj_proto;
unsigned int *mark_bits;
};
C_FUNCTION_BEGIN
HL_API int hl_type_size( hl_type *t );
#define hl_pad_size(size,t) ((t)->kind == HVOID ? 0 : ((-(size)) & (hl_type_size(t) - 1)))
HL_API int hl_pad_struct( int size, hl_type *t );
HL_API hl_runtime_obj *hl_get_obj_rt( hl_type *ot );
HL_API hl_runtime_obj *hl_get_obj_proto( hl_type *ot );
HL_API void hl_flush_proto( hl_type *ot );
HL_API void hl_init_enum( hl_type *et, hl_module_context *m );
/* -------------------- VALUES ------------------------------ */
typedef unsigned char vbyte;
typedef struct {
hl_type *t;
# ifndef HL_64
int __pad; // force align on 16 bytes for double
# endif
union {
bool b;
unsigned char ui8;
unsigned short ui16;
int i;
float f;
double d;
vbyte *bytes;
void *ptr;
int64 i64;
} v;
} vdynamic;
typedef struct {
hl_type *t;
/* fields data */
} vobj;
typedef struct _vvirtual vvirtual;
struct _vvirtual {
hl_type *t;
vdynamic *value;
vvirtual *next;
};
#define hl_vfields(v) ((void**)(((vvirtual*)(v))+1))
typedef struct {
hl_type *t;
hl_type *at;
int size;
int __pad; // force align on 16 bytes for double
} varray;
typedef struct _vclosure {
hl_type *t;
void *fun;
int hasValue;
# ifdef HL_64
int stackCount;
# endif
void *value;
} vclosure;
typedef struct {
vclosure cl;
vclosure *wrappedFun;
} vclosure_wrapper;
struct _hl_field_lookup {
hl_type *t;
int hashed_name;
int field_index; // negative or zero : index in methods
};
typedef struct {
void *ptr;
hl_type *closure;
int fid;
} hl_runtime_binding;
struct hl_runtime_obj {
hl_type *t;
// absolute
int nfields;
int nproto;
int size;
int nmethods;
int nbindings;
bool hasPtr;
void **methods;
int *fields_indexes;
hl_runtime_binding *bindings;
hl_runtime_obj *parent;
const uchar *(*toStringFun)( vdynamic *obj );
int (*compareFun)( vdynamic *a, vdynamic *b );
vdynamic *(*castFun)( vdynamic *obj, hl_type *t );
vdynamic *(*getFieldFun)( vdynamic *obj, int hfield );
// relative
int nlookup;
int ninterfaces;
hl_field_lookup *lookup;
int *interfaces;
};
typedef struct {
hl_type *t;
hl_field_lookup *lookup;
char *raw_data;
void **values;
int nfields;
int raw_size;
int nvalues;
vvirtual *virtuals;
} vdynobj;
typedef struct _venum {
hl_type *t;
int index;
} venum;
HL_API hl_type hlt_void;
HL_API hl_type hlt_i32;
HL_API hl_type hlt_i64;
HL_API hl_type hlt_f64;
HL_API hl_type hlt_f32;
HL_API hl_type hlt_dyn;
HL_API hl_type hlt_array;
HL_API hl_type hlt_bytes;
HL_API hl_type hlt_dynobj;
HL_API hl_type hlt_bool;
HL_API hl_type hlt_abstract;
HL_API double hl_nan( void );
HL_API bool hl_is_dynamic( hl_type *t );
#define hl_is_ptr(t) ((t)->kind >= HBYTES)
HL_API bool hl_same_type( hl_type *a, hl_type *b );
HL_API bool hl_safe_cast( hl_type *t, hl_type *to );
#define hl_aptr(a,t) ((t*)(((varray*)(a))+1))
HL_API varray *hl_alloc_array( hl_type *t, int size );
HL_API vdynamic *hl_alloc_dynamic( hl_type *t );
HL_API vdynamic *hl_alloc_dynbool( bool b );
HL_API vdynamic *hl_alloc_obj( hl_type *t );
HL_API venum *hl_alloc_enum( hl_type *t, int index );
HL_API vvirtual *hl_alloc_virtual( hl_type *t );
HL_API vdynobj *hl_alloc_dynobj( void );
HL_API vbyte *hl_alloc_bytes( int size );
HL_API vbyte *hl_copy_bytes( const vbyte *byte, int size );
HL_API int hl_utf8_length( const vbyte *s, int pos );
HL_API int hl_from_utf8( uchar *out, int outLen, const char *str );
HL_API char *hl_to_utf8( const uchar *bytes );
HL_API uchar *hl_to_utf16( const char *str );
HL_API vdynamic *hl_virtual_make_value( vvirtual *v );
HL_API hl_obj_field *hl_obj_field_fetch( hl_type *t, int fid );
HL_API int hl_hash( vbyte *name );
HL_API int hl_hash_utf8( const char *str ); // no cache
HL_API int hl_hash_gen( const uchar *name, bool cache_name );
HL_API vbyte *hl_field_name( int hash );
#define hl_error(msg, ...) hl_throw(hl_alloc_strbytes(USTR(msg), ## __VA_ARGS__))
HL_API vdynamic *hl_alloc_strbytes( const uchar *msg, ... );
HL_API void hl_assert( void );
HL_API HL_NO_RETURN( void hl_throw( vdynamic *v ) );
HL_API HL_NO_RETURN( void hl_rethrow( vdynamic *v ) );
HL_API HL_NO_RETURN( void hl_null_access( void ) );
HL_API void hl_setup_longjump( void *j );
HL_API void hl_setup_exception( void *resolve_symbol, void *capture_stack );
HL_API void hl_dump_stack( void );
HL_API varray *hl_exception_stack( void );
HL_API bool hl_detect_debugger( void );
HL_API vvirtual *hl_to_virtual( hl_type *vt, vdynamic *obj );
HL_API void hl_init_virtual( hl_type *vt, hl_module_context *ctx );
HL_API hl_field_lookup *hl_lookup_find( hl_field_lookup *l, int size, int hash );
HL_API hl_field_lookup *hl_lookup_insert( hl_field_lookup *l, int size, int hash, hl_type *t, int index );
HL_API int hl_dyn_geti( vdynamic *d, int hfield, hl_type *t );
HL_API int64 hl_dyn_geti64( vdynamic *d, int hfield );
HL_API void *hl_dyn_getp( vdynamic *d, int hfield, hl_type *t );
HL_API float hl_dyn_getf( vdynamic *d, int hfield );
HL_API double hl_dyn_getd( vdynamic *d, int hfield );
HL_API int hl_dyn_casti( void *data, hl_type *t, hl_type *to );
HL_API int64 hl_dyn_casti64( void *data, hl_type *t );
HL_API void *hl_dyn_castp( void *data, hl_type *t, hl_type *to );
HL_API float hl_dyn_castf( void *data, hl_type *t );
HL_API double hl_dyn_castd( void *data, hl_type *t );
#define hl_invalid_comparison 0xAABBCCDD
HL_API int hl_dyn_compare( vdynamic *a, vdynamic *b );
HL_API vdynamic *hl_make_dyn( void *data, hl_type *t );
HL_API void hl_write_dyn( void *data, hl_type *t, vdynamic *v, bool is_tmp );
HL_API void hl_dyn_seti( vdynamic *d, int hfield, hl_type *t, int value );
HL_API void hl_dyn_seti64( vdynamic *d, int hfield, int64 value );
HL_API void hl_dyn_setp( vdynamic *d, int hfield, hl_type *t, void *ptr );
HL_API void hl_dyn_setf( vdynamic *d, int hfield, float f );
HL_API void hl_dyn_setd( vdynamic *d, int hfield, double v );
typedef enum {
OpAdd,
OpSub,
OpMul,
OpMod,
OpDiv,
OpShl,
OpShr,
OpUShr,
OpAnd,
OpOr,
OpXor,
OpLast
} DynOp;
HL_API vdynamic *hl_dyn_op( int op, vdynamic *a, vdynamic *b );
HL_API vclosure *hl_alloc_closure_void( hl_type *t, void *fvalue );
HL_API vclosure *hl_alloc_closure_ptr( hl_type *fullt, void *fvalue, void *ptr );
HL_API vclosure *hl_make_fun_wrapper( vclosure *c, hl_type *to );
HL_API void *hl_wrapper_call( void *value, void **args, vdynamic *ret );
HL_API void *hl_dyn_call_obj( vdynamic *obj, hl_type *ft, int hfield, void **args, vdynamic *ret );
HL_API vdynamic *hl_dyn_call( vclosure *c, vdynamic **args, int nargs );
HL_API vdynamic *hl_dyn_call_safe( vclosure *c, vdynamic **args, int nargs, bool *isException );
/*
These macros should be only used when the closure `cl` has been type checked beforehand
so you are sure it's of the used typed. Otherwise use hl_dyn_call
*/
#define hl_call0(ret,cl) \
(cl->hasValue ? ((ret(*)(vdynamic*))cl->fun)((vdynamic*)cl->value) : ((ret(*)())cl->fun)())
#define hl_call1(ret,cl,t,v) \
(cl->hasValue ? ((ret(*)(vdynamic*,t))cl->fun)((vdynamic*)cl->value,v) : ((ret(*)(t))cl->fun)(v))
#define hl_call2(ret,cl,t1,v1,t2,v2) \
(cl->hasValue ? ((ret(*)(vdynamic*,t1,t2))cl->fun)((vdynamic*)cl->value,v1,v2) : ((ret(*)(t1,t2))cl->fun)(v1,v2))
#define hl_call3(ret,cl,t1,v1,t2,v2,t3,v3) \
(cl->hasValue ? ((ret(*)(vdynamic*,t1,t2,t3))cl->fun)((vdynamic*)cl->value,v1,v2,v3) : ((ret(*)(t1,t2,t3))cl->fun)(v1,v2,v3))
#define hl_call4(ret,cl,t1,v1,t2,v2,t3,v3,t4,v4) \
(cl->hasValue ? ((ret(*)(vdynamic*,t1,t2,t3,t4))cl->fun)((vdynamic*)cl->value,v1,v2,v3,v4) : ((ret(*)(t1,t2,t3,t4))cl->fun)(v1,v2,v3,v4))
// ----------------------- THREADS --------------------------------------------------
struct _hl_thread;
struct _hl_mutex;
struct _hl_semaphore;
struct _hl_condition;
struct _hl_tls;
typedef struct _hl_thread hl_thread;
typedef struct _hl_mutex hl_mutex;
typedef struct _hl_semaphore hl_semaphore;
typedef struct _hl_condition hl_condition;
typedef struct _hl_tls hl_tls;
HL_API hl_thread *hl_thread_start( void *callback, void *param, bool withGC );
HL_API hl_thread *hl_thread_current( void );
HL_API void hl_thread_yield(void);
HL_API void hl_register_thread( void *stack_top );
HL_API void hl_unregister_thread( void );
HL_API hl_mutex *hl_mutex_alloc( bool gc_thread );
HL_API void hl_mutex_acquire( hl_mutex *l );
HL_API bool hl_mutex_try_acquire( hl_mutex *l );
HL_API void hl_mutex_release( hl_mutex *l );
HL_API void hl_mutex_free( hl_mutex *l );
HL_API hl_semaphore *hl_semaphore_alloc(int value);
HL_API void hl_semaphore_acquire(hl_semaphore *sem);
HL_API bool hl_semaphore_try_acquire(hl_semaphore *sem, vdynamic *timeout);
HL_API void hl_semaphore_release(hl_semaphore *sem);
HL_API void hl_semaphore_free(hl_semaphore *sem);
HL_API hl_condition *hl_condition_alloc();
HL_API void hl_condition_acquire(hl_condition *cond);
HL_API bool hl_condition_try_acquire(hl_condition *cond);
HL_API void hl_condition_release(hl_condition *cond);
HL_API void hl_condition_wait(hl_condition *cond);
HL_API bool hl_condition_timed_wait(hl_condition *cond, double timeout);
HL_API void hl_condition_signal(hl_condition *cond);
HL_API void hl_condition_broadcast(hl_condition *cond);
HL_API void hl_condition_free(hl_condition *cond);
HL_API hl_tls *hl_tls_alloc( bool gc_value );
HL_API void hl_tls_set( hl_tls *l, void *value );
HL_API void *hl_tls_get( hl_tls *l );
HL_API void hl_tls_free( hl_tls *l );
// ----------------------- ALLOC --------------------------------------------------
#define MEM_HAS_PTR(kind) (!((kind)&2))
#define MEM_KIND_DYNAMIC 0
#define MEM_KIND_RAW 1
#define MEM_KIND_NOPTR 2
#define MEM_KIND_FINALIZER 3
#define MEM_ALIGN_DOUBLE 128
#define MEM_ZERO 256
HL_API void *hl_gc_alloc_gen( hl_type *t, int size, int flags );
HL_API void hl_add_root( void *ptr );
HL_API void hl_remove_root( void *ptr );
HL_API void hl_gc_major( void );
HL_API bool hl_is_gc_ptr( void *ptr );
HL_API int hl_gc_get_memsize( void *ptr );
HL_API void hl_blocking( bool b );
HL_API bool hl_is_blocking( void );
typedef void (*hl_types_dump)( void (*)( void *, int) );
HL_API void hl_gc_set_dump_types( hl_types_dump tdump );
#define hl_gc_alloc_noptr(size) hl_gc_alloc_gen(&hlt_bytes,size,MEM_KIND_NOPTR)
#define hl_gc_alloc(t,size) hl_gc_alloc_gen(t,size,MEM_KIND_DYNAMIC)
#define hl_gc_alloc_raw(size) hl_gc_alloc_gen(&hlt_abstract,size,MEM_KIND_RAW)
#define hl_gc_alloc_finalizer(size) hl_gc_alloc_gen(&hlt_abstract,size,MEM_KIND_FINALIZER)
HL_API void hl_alloc_init( hl_alloc *a );
HL_API void *hl_malloc( hl_alloc *a, int size );
HL_API void *hl_zalloc( hl_alloc *a, int size );
HL_API void hl_free( hl_alloc *a );
HL_API void hl_global_init( void );
HL_API void hl_global_free( void );
HL_API void hl_global_lock( bool lock );
HL_API void *hl_alloc_executable_memory( int size );
HL_API void hl_free_executable_memory( void *ptr, int size );
// ----------------------- BUFFER --------------------------------------------------
typedef struct hl_buffer hl_buffer;
HL_API hl_buffer *hl_alloc_buffer( void );
HL_API void hl_buffer_val( hl_buffer *b, vdynamic *v );
HL_API void hl_buffer_char( hl_buffer *b, uchar c );
HL_API void hl_buffer_str( hl_buffer *b, const uchar *str );
HL_API void hl_buffer_cstr( hl_buffer *b, const char *str );
HL_API void hl_buffer_str_sub( hl_buffer *b, const uchar *str, int len );
HL_API int hl_buffer_length( hl_buffer *b );
HL_API uchar *hl_buffer_content( hl_buffer *b, int *len );
HL_API uchar *hl_to_string( vdynamic *v );
HL_API const uchar *hl_type_str( hl_type *t );
HL_API void hl_throw_buffer( hl_buffer *b );
// ----------------------- FFI ------------------------------------------------------
// match GNU C++ mangling
#define TYPE_STR "vcsilfdbBDPOATR??X?N?S"
#undef _VOID
#define _NO_ARG
#define _VOID "v"
#define _I8 "c"
#define _I16 "s"
#define _I32 "i"
#define _I64 "l"
#define _F32 "f"
#define _F64 "d"
#define _BOOL "b"
#define _BYTES "B"
#define _DYN "D"
#define _FUN(t, args) "P" args "_" t
#define _OBJ(fields) "O" fields "_"
#define _ARR "A"
#define _TYPE "T"
#define _REF(t) "R" t
#define _ABSTRACT(name) "X" #name "_"
#undef _NULL
#define _NULL(t) "N" t
#define _STRUCT "S"
#undef _STRING
#define _STRING _OBJ(_BYTES _I32)
typedef struct {
hl_type *t;
uchar *bytes;
int length;
} vstring;
#define DEFINE_PRIM(t,name,args) DEFINE_PRIM_WITH_NAME(t,name,args,name)
#define _DEFINE_PRIM_WITH_NAME(t,name,args,realName) C_FUNCTION_BEGIN EXPORT void *hlp_##realName( const char **sign ) { *sign = _FUN(t,args); return (void*)(&HL_NAME(name)); } C_FUNCTION_END
#if !defined(HL_NAME)
# define HL_NAME(p) p
# ifdef LIBHL_EXPORTS
# define HL_PRIM EXPORT
# undef DEFINE_PRIM
# define DEFINE_PRIM(t,name,args) _DEFINE_PRIM_WITH_NAME(t,hl_##name,args,name)
# define DEFINE_PRIM_WITH_NAME _DEFINE_PRIM_WITH_NAME
# else
# define HL_PRIM
# define DEFINE_PRIM_WITH_NAME(t,name,args,realName)
# endif
#elif defined(LIBHL_STATIC)
# ifdef __cplusplus
# define HL_PRIM extern "C"
# else
# define HL_PRIM
# endif
#define DEFINE_PRIM_WITH_NAME(t,name,args,realName)
#else
# ifdef __cplusplus
# define HL_PRIM extern "C" EXPORT
# else
# define HL_PRIM EXPORT
# endif
# define DEFINE_PRIM_WITH_NAME _DEFINE_PRIM_WITH_NAME
#endif
#if defined(HL_GCC) && !defined(HL_CONSOLE)
# ifdef HL_CLANG
# define HL_NO_OPT __attribute__ ((optnone))
# else
# define HL_NO_OPT __attribute__((optimize("-O0")))
# endif
#else
# define HL_NO_OPT
#endif
// -------------- EXTRA ------------------------------------
#define hl_fatal(msg) hl_fatal_error(msg,__FILE__,__LINE__)
#define hl_fatal1(msg,p0) hl_fatal_fmt(__FILE__,__LINE__,msg,p0)
#define hl_fatal2(msg,p0,p1) hl_fatal_fmt(__FILE__,__LINE__,msg,p0,p1)
#define hl_fatal3(msg,p0,p1,p2) hl_fatal_fmt(__FILE__,__LINE__,msg,p0,p1,p2)
#define hl_fatal4(msg,p0,p1,p2,p3) hl_fatal_fmt(__FILE__,__LINE__,msg,p0,p1,p2,p3)
HL_API void *hl_fatal_error( const char *msg, const char *file, int line );
HL_API void hl_fatal_fmt( const char *file, int line, const char *fmt, ...);
HL_API void hl_sys_init(void **args, int nargs, void *hlfile);
HL_API void hl_setup_callbacks(void *sc, void *gw);
HL_API void hl_setup_callbacks2(void *sc, void *gw, int flags);
HL_API void hl_setup_reload_check( void *freload, void *param );
#include <setjmp.h>
typedef struct _hl_trap_ctx hl_trap_ctx;
struct _hl_trap_ctx {
jmp_buf buf;
hl_trap_ctx *prev;
vdynamic *tcheck;
};
#define hl_trap(ctx,r,label) { hl_thread_info *__tinf = hl_get_thread(); ctx.tcheck = NULL; ctx.prev = __tinf->trap_current; __tinf->trap_current = &ctx; if( setjmp(ctx.buf) ) { r = __tinf->exc_value; goto label; } }
#define hl_endtrap(ctx) hl_get_thread()->trap_current = ctx.prev
#define HL_EXC_MAX_STACK 0x100
#define HL_EXC_RETHROW 1
#define HL_EXC_CATCH_ALL 2
#define HL_EXC_IS_THROW 4
#define HL_THREAD_INVISIBLE 16
#define HL_THREAD_PROFILER_PAUSED 32
#define HL_TREAD_TRACK_SHIFT 16
#define HL_TRACK_ALLOC 1
#define HL_TRACK_CAST 2
#define HL_TRACK_DYNFIELD 4
#define HL_TRACK_DYNCALL 8
#define HL_TRACK_MASK (HL_TRACK_ALLOC | HL_TRACK_CAST | HL_TRACK_DYNFIELD | HL_TRACK_DYNCALL)
#define HL_MAX_EXTRA_STACK 64
typedef struct {
int thread_id;
// gc vars
volatile int gc_blocking;
void *stack_top;
void *stack_cur;
// exception handling
hl_trap_ctx *trap_current;
hl_trap_ctx *trap_uncaught;
vclosure *exc_handler;
vdynamic *exc_value;
int flags;
int exc_stack_count;
// extra
char thread_name[128];
jmp_buf gc_regs;
void *exc_stack_trace[HL_EXC_MAX_STACK];
void *extra_stack_data[HL_MAX_EXTRA_STACK];
int extra_stack_size;
#ifdef HL_MAC
thread_t mach_thread_id;
pthread_t pthread_id;
#endif
} hl_thread_info;
typedef struct {
int count;
bool stopping_world;
hl_thread_info **threads;
hl_mutex *global_lock;
hl_mutex *exclusive_lock;
} hl_threads_info;
HL_API hl_thread_info *hl_get_thread();
HL_API hl_threads_info *hl_gc_threads_info();
#ifdef HL_TRACK_ENABLE
typedef struct {
int flags;
void (*on_alloc)(hl_type *,int,int,void*);
void (*on_cast)(hl_type *, hl_type*);
void (*on_dynfield)( vdynamic *, int );
void (*on_dyncall)( vdynamic *, int );
} hl_track_info;
#define hl_is_tracking(flag) ((hl_track.flags&(flag)) && (hl_get_thread()->flags & (flag<<HL_TREAD_TRACK_SHIFT)))
#define hl_track_call(flag,call) if( hl_is_tracking(flag) ) hl_track.call
HL_API hl_track_info hl_track;
#else
#define hl_is_tracking(_) false
#define hl_track_call(a,b)
#endif
C_FUNCTION_END
#endif

View File

@ -0,0 +1,92 @@
/*
* Copyright (C)2005-2016 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef HLC_H
#define HLC_H
#include <math.h>
#include <hl.h>
#ifdef HL_64
# define PAD_64_VAL ,0
#else
# define PAD_64_VAL
#endif
#ifdef HLC_BOOT
// undefine some commonly used names that can clash with class/var name
#undef CONST
#undef stdin
#undef stdout
#undef stderr
#undef DELETE
#undef NO_ERROR
#undef EOF
#undef STRICT
#undef TRUE
#undef FALSE
#undef CW_USEDEFAULT
#undef HIDDEN
#undef RESIZABLE
#undef __SIGN
#undef far
#undef FAR
// disable some warnings triggered by HLC code generator
#ifdef HL_VCC
# pragma warning(disable:4100) // unreferenced param
# pragma warning(disable:4101) // unreferenced local var
# pragma warning(disable:4102) // unreferenced label
# pragma warning(disable:4204) // nonstandard extension
# pragma warning(disable:4221) // nonstandard extension
# pragma warning(disable:4244) // possible loss of data
# pragma warning(disable:4700) // uninitialized local variable used
# pragma warning(disable:4701) // potentially uninitialized local variable
# pragma warning(disable:4702) // unreachable code
# pragma warning(disable:4703) // potentially uninitialized local
# pragma warning(disable:4715) // control paths must return a value
# pragma warning(disable:4716) // must return a value (ends with throw)
# pragma warning(disable:4723) // potential divide by 0
#else
# pragma GCC diagnostic ignored "-Wunused-variable"
# pragma GCC diagnostic ignored "-Wunused-function"
# pragma GCC diagnostic ignored "-Wcomment" // comment in comment
# ifdef HL_CLANG
# pragma GCC diagnostic ignored "-Wreturn-type"
# pragma GCC diagnostic ignored "-Wsometimes-uninitialized"
# else
# pragma GCC diagnostic ignored "-Wunused-but-set-variable"
# pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
# endif
#endif
#endif
extern void *hlc_static_call(void *fun, hl_type *t, void **args, vdynamic *out);
extern void *hlc_get_wrapper(hl_type *t);
extern void hl_entry_point();
#define HL__ENUM_CONSTRUCT__ hl_type *t; int index;
#define HL__ENUM_INDEX__(v) ((venum*)(v))->index
#endif

View File

@ -0,0 +1,139 @@
/*
* Copyright (C)2015-2016 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <hlc.h>
#if defined(HL_MOBILE) && defined(sdl__Sdl__val)
# include <SDL_main.h>
#endif
#ifdef HL_WIN_DESKTOP
# ifndef CONST
# define CONST
# endif
# pragma warning(disable:4091)
#if !defined(HL_MINGW)
# include <DbgHelp.h>
#else
# include <dbghelp.h>
#endif
# pragma comment(lib, "Dbghelp.lib")
# undef CONST
#endif
#ifdef HL_CONSOLE
extern void sys_global_init();
extern void sys_global_exit();
#else
#define sys_global_init()
#define sys_global_exit()
#endif
#ifdef HL_VCC
# include <crtdbg.h>
#else
# define _CrtSetDbgFlag(x)
# define _CrtCheckMemory()
#endif
static uchar *hlc_resolve_symbol( void *addr, uchar *out, int *outSize ) {
#ifdef HL_WIN_DESKTOP
static HANDLE stack_process_handle = NULL;
DWORD64 index;
IMAGEHLP_LINEW64 line;
struct {
SYMBOL_INFOW sym;
uchar buffer[256];
} data;
data.sym.SizeOfStruct = sizeof(data.sym);
data.sym.MaxNameLen = 255;
if( !stack_process_handle ) {
stack_process_handle = GetCurrentProcess();
SymSetOptions(SYMOPT_LOAD_LINES);
SymInitialize(stack_process_handle,NULL,(BOOL)1);
}
if( SymFromAddrW(stack_process_handle,(DWORD64)(int_val)addr,&index,&data.sym) ) {
DWORD offset = 0;
line.SizeOfStruct = sizeof(line);
line.FileName = USTR("\\?");
line.LineNumber = 0;
SymGetLineFromAddrW64(stack_process_handle, (DWORD64)(int_val)addr, &offset, &line);
*outSize = usprintf(out,*outSize,USTR("%s(%s:%d)"),data.sym.Name,wcsrchr(line.FileName,'\\')+1,(int)line.LineNumber);
return out;
}
#endif
return NULL;
}
static int hlc_capture_stack( void **stack, int size ) {
int count = 0;
# ifdef HL_WIN_DESKTOP
count = CaptureStackBackTrace(2, size, stack, NULL) - 8; // 8 startup
if( count < 0 ) count = 0;
# endif
return count;
}
#if defined( HL_VCC )
static int throw_handler( int code ) {
#if !defined(HL_XBO)
switch( code ) {
case EXCEPTION_ACCESS_VIOLATION: hl_error("Access violation");
case EXCEPTION_STACK_OVERFLOW: hl_error("Stack overflow");
default: hl_error("Unknown runtime error");
}
return EXCEPTION_CONTINUE_SEARCH;
#else
return 0;
#endif
}
#endif
int kickstart(int argc, char *argv[]) {
vdynamic *ret;
bool isExc = false;
hl_type_fun tf = { 0 };
hl_type clt = { 0 };
vclosure cl = { 0 };
sys_global_init();
hl_global_init();
hl_register_thread(&ret);
hl_setup_exception(hlc_resolve_symbol,hlc_capture_stack);
hl_setup_callbacks(hlc_static_call, hlc_get_wrapper);
hl_sys_init((void**)(argv + 1),argc - 1,NULL);
tf.ret = &hlt_void;
clt.kind = HFUN;
clt.fun = &tf;
cl.t = &clt;
cl.fun = hl_entry_point;
ret = hl_dyn_call_safe(&cl, NULL, 0, &isExc);
if( isExc ) {
varray *a = hl_exception_stack();
int i;
uprintf(USTR("Uncaught exception: %s\n"), hl_to_string(ret));
for (i = 0; i<a->size; i++)
uprintf(USTR("Called from %s\n"), hl_aptr(a, uchar*)[i]);
}
hl_global_free();
sys_global_exit();
return (int)isExc;
}

View File

@ -0,0 +1,161 @@
/*
* Copyright (C)2005-2016 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <hl.h>
#include "opcodes.h"
typedef struct {
const char *lib;
const char *name;
hl_type *t;
int findex;
} hl_native;
typedef struct {
hl_op op;
int p1;
int p2;
int p3;
int *extra;
} hl_opcode;
typedef struct hl_function hl_function;
struct hl_function {
int findex;
int nregs;
int nops;
int ref;
hl_type *type;
hl_type **regs;
hl_opcode *ops;
int *debug;
hl_type_obj *obj;
union {
const uchar *name;
hl_function *ref; // obj = NULL
} field;
};
#define fun_obj(f) ((f)->obj ? (f)->obj : (f)->field.ref ? (f)->field.ref->obj : NULL)
#define fun_field_name(f) ((f)->obj ? (f)->field.name : (f)->field.ref ? (f)->field.ref->field.name : NULL)
typedef struct {
int global;
int nfields;
int *fields;
} hl_constant;
typedef struct {
int version;
int nints;
int nfloats;
int nstrings;
int nbytes;
int ntypes;
int nglobals;
int nnatives;
int nfunctions;
int nconstants;
int entrypoint;
int ndebugfiles;
bool hasdebug;
int* ints;
double* floats;
char** strings;
int* strings_lens;
char* bytes;
int* bytes_pos;
char** debugfiles;
int* debugfiles_lens;
uchar** ustrings;
hl_type* types;
hl_type** globals;
hl_native* natives;
hl_function*functions;
hl_constant*constants;
hl_alloc alloc;
hl_alloc falloc;
} hl_code;
typedef struct {
void *offsets;
int start;
bool large;
} hl_debug_infos;
typedef struct jit_ctx jit_ctx;
typedef struct {
hl_code *code;
int *types_hashes;
int *globals_signs;
int *functions_signs;
int *functions_hashes;
int *functions_indexes;
} hl_code_hash;
typedef struct {
hl_code *code;
int codesize;
int globals_size;
int *globals_indexes;
unsigned char *globals_data;
void **functions_ptrs;
int *functions_indexes;
void *jit_code;
hl_code_hash *hash;
hl_debug_infos *jit_debug;
jit_ctx *jit_ctx;
hl_module_context ctx;
} hl_module;
hl_code *hl_code_read( const unsigned char *data, int size, char **error_msg );
hl_code_hash *hl_code_hash_alloc( hl_code *c );
void hl_code_hash_finalize( hl_code_hash *h );
void hl_code_hash_free( hl_code_hash *h );
void hl_code_free( hl_code *c );
int hl_code_hash_type( hl_code_hash *h, hl_type *t );
void hl_code_hash_remap_globals( hl_code_hash *hnew, hl_code_hash *hold );
const uchar *hl_get_ustring( hl_code *c, int index );
const char* hl_op_name( int op );
typedef unsigned char h_bool;
hl_module *hl_module_alloc( hl_code *code );
int hl_module_init( hl_module *m, h_bool hot_reload );
h_bool hl_module_patch( hl_module *m, hl_code *code );
void hl_module_free( hl_module *m );
h_bool hl_module_debug( hl_module *m, int port, h_bool wait );
void hl_profile_setup( int sample_count );
void hl_profile_end();
jit_ctx *hl_jit_alloc();
void hl_jit_free( jit_ctx *ctx, h_bool can_reset );
void hl_jit_reset( jit_ctx *ctx, hl_module *m );
void hl_jit_init( jit_ctx *ctx, hl_module *m );
int hl_jit_function( jit_ctx *ctx, hl_module *m, hl_function *f );
void *hl_jit_code( jit_ctx *ctx, hl_module *m, int *codesize, hl_debug_infos **debug, hl_module *previous );
void hl_jit_patch_method( void *old_fun, void **new_fun_table );

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,252 @@
/*
* Copyright (C)2015-2016 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <hl.h>
#include <hlmodule.h>
#ifdef HL_WIN
# include <locale.h>
typedef uchar pchar;
#define pprintf(str,file) uprintf(USTR(str),file)
#define pfopen(file,ext) _wfopen(file,USTR(ext))
#define pcompare wcscmp
#define ptoi(s) wcstol(s,NULL,10)
#define PSTR(x) USTR(x)
#else
# include <sys/stat.h>
typedef char pchar;
#define pprintf printf
#define pfopen fopen
#define pcompare strcmp
#define ptoi atoi
#define PSTR(x) x
#endif
typedef struct {
pchar *file;
hl_code *code;
hl_module *m;
vdynamic *ret;
int file_time;
} main_context;
static int pfiletime( pchar *file ) {
#ifdef HL_WIN
struct _stat32 st;
_wstat32(file,&st);
return (int)st.st_mtime;
#else
struct stat st;
stat(file,&st);
return (int)st.st_mtime;
#endif
}
static hl_code *load_code( const pchar *file, char **error_msg, bool print_errors ) {
hl_code *code;
FILE *f = pfopen(file,"rb");
int pos, size;
char *fdata;
if( f == NULL ) {
if( print_errors ) pprintf("File not found '%s'\n",file);
return NULL;
}
fseek(f, 0, SEEK_END);
size = (int)ftell(f);
fseek(f, 0, SEEK_SET);
fdata = (char*)malloc(size);
pos = 0;
while( pos < size ) {
int r = (int)fread(fdata + pos, 1, size-pos, f);
if( r <= 0 ) {
if( print_errors ) pprintf("Failed to read '%s'\n",file);
return NULL;
}
pos += r;
}
fclose(f);
code = hl_code_read((unsigned char*)fdata, size, error_msg);
free(fdata);
return code;
}
static bool check_reload( main_context *m ) {
int time = pfiletime(m->file);
bool changed;
if( time == m->file_time )
return false;
char *error_msg = NULL;
hl_code *code = load_code(m->file, &error_msg, false);
if( code == NULL )
return false;
changed = hl_module_patch(m->m, code);
m->file_time = time;
hl_code_free(code);
return changed;
}
#ifdef HL_VCC
// this allows some runtime detection to switch to high performance mode
__declspec(dllexport) DWORD NvOptimusEnablement = 1;
__declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
#endif
#if defined(HL_LINUX) || defined(HL_MAC)
#include <signal.h>
static void handle_signal( int signum ) {
signal(signum, SIG_DFL);
printf("SIGNAL %d\n",signum);
hl_dump_stack();
fflush(stdout);
raise(signum);
}
static void setup_handler() {
struct sigaction act;
act.sa_sigaction = NULL;
act.sa_handler = handle_signal;
act.sa_flags = 0;
sigemptyset(&act.sa_mask);
signal(SIGPIPE, SIG_IGN);
sigaction(SIGSEGV,&act,NULL);
sigaction(SIGTERM,&act,NULL);
}
#else
static void setup_handler() {
}
#endif
#ifdef HL_WIN
int wmain(int argc, pchar *argv[]) {
#else
int main(int argc, pchar *argv[]) {
#endif
static vclosure cl;
pchar *file = NULL;
char *error_msg = NULL;
int debug_port = -1;
bool debug_wait = false;
bool hot_reload = false;
int profile_count = -1;
main_context ctx;
bool isExc = false;
int first_boot_arg = -1;
argv++;
argc--;
while( argc ) {
pchar *arg = *argv++;
argc--;
if( pcompare(arg,PSTR("--debug")) == 0 ) {
if( argc-- == 0 ) break;
debug_port = ptoi(*argv++);
continue;
}
if( pcompare(arg,PSTR("--debug-wait")) == 0 ) {
debug_wait = true;
continue;
}
if( pcompare(arg,PSTR("--version")) == 0 ) {
printf("%d.%d.%d",HL_VERSION>>16,(HL_VERSION>>8)&0xFF,HL_VERSION&0xFF);
return 0;
}
if( pcompare(arg,PSTR("--hot-reload")) == 0 ) {
hot_reload = true;
continue;
}
if( pcompare(arg,PSTR("--profile")) == 0 ) {
if( argc-- == 0 ) break;
profile_count = ptoi(*argv++);
continue;
}
if( *arg == '-' || *arg == '+' ) {
if( first_boot_arg < 0 ) first_boot_arg = argc + 1;
// skip value
if( argc && **argv != '+' && **argv != '-' ) {
argc--;
argv++;
}
continue;
}
file = arg;
break;
}
if( file == NULL ) {
FILE *fchk;
file = PSTR("hlboot.dat");
fchk = pfopen(file,"rb");
if( fchk == NULL ) {
printf("HL/JIT %d.%d.%d (c)2015-2022 Haxe Foundation\n Usage : hl [--debug <port>] [--debug-wait] <file>\n",HL_VERSION>>16,(HL_VERSION>>8)&0xFF,HL_VERSION&0xFF);
return 1;
}
fclose(fchk);
if( first_boot_arg >= 0 ) {
argv -= first_boot_arg;
argc = first_boot_arg;
}
}
hl_global_init();
hl_sys_init((void**)argv,argc,file);
hl_register_thread(&ctx);
ctx.file = file;
ctx.code = load_code(file, &error_msg, true);
if( ctx.code == NULL ) {
if( error_msg ) printf("%s\n", error_msg);
return 1;
}
ctx.m = hl_module_alloc(ctx.code);
if( ctx.m == NULL )
return 2;
if( !hl_module_init(ctx.m,hot_reload) )
return 3;
if( hot_reload ) {
ctx.file_time = pfiletime(ctx.file);
hl_setup_reload_check(check_reload,&ctx);
}
hl_code_free(ctx.code);
if( debug_port > 0 && !hl_module_debug(ctx.m,debug_port,debug_wait) ) {
fprintf(stderr,"Could not start debugger on port %d",debug_port);
return 4;
}
cl.t = ctx.code->functions[ctx.m->functions_indexes[ctx.m->code->entrypoint]].type;
cl.fun = ctx.m->functions_ptrs[ctx.m->code->entrypoint];
cl.hasValue = 0;
setup_handler();
hl_profile_setup(profile_count);
ctx.ret = hl_dyn_call_safe(&cl,NULL,0,&isExc);
hl_profile_end();
if( isExc ) {
varray *a = hl_exception_stack();
int i;
uprintf(USTR("Uncaught exception: %s\n"), hl_to_string(ctx.ret));
for(i=0;i<a->size;i++)
uprintf(USTR("Called from %s\n"), hl_aptr(a,uchar*)[i]);
hl_debug_break();
hl_global_free();
return 1;
}
hl_module_free(ctx.m);
hl_free(&ctx.code->alloc);
// do not call hl_unregister_thread() or hl_global_free will display error
// on global_lock if there are threads that are still running (such as debugger)
hl_global_free();
return 0;
}

View File

@ -0,0 +1,863 @@
/*
* Copyright (C)2015-2016 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <hl.h>
#include <hlmodule.h>
#ifdef HL_WIN
# include <windows.h>
EXTERN_C IMAGE_DOS_HEADER __ImageBase;
# define dlopen(l,p) (void*)( (l) ? LoadLibraryA(l) : (HMODULE)&__ImageBase)
# define dlsym(h,n) GetProcAddress((HANDLE)h,n)
#else
# include <dlfcn.h>
#endif
#define HOT_RELOAD_EXTRA_GLOBALS 4096
HL_API void hl_prim_not_loaded( const uchar *err );
static hl_module **cur_modules = NULL;
static int modules_count = 0;
static bool module_resolve_pos( hl_module *m, void *addr, int *fidx, int *fpos ) {
int code_pos = ((int)(int_val)((unsigned char*)addr - (unsigned char*)m->jit_code));
int min, max;
hl_debug_infos *dbg;
hl_function *fdebug;
if( m->jit_debug == NULL )
return false;
// lookup function from code pos
min = 0;
max = m->code->nfunctions;
while( min < max ) {
int mid = (min + max) >> 1;
hl_debug_infos *p = m->jit_debug + mid;
if( p->start <= code_pos )
min = mid + 1;
else
max = mid;
}
if( min == 0 )
return false; // hl_callback
do {
min--;
*fidx = min;
dbg = m->jit_debug + min;
fdebug = m->code->functions + min;
} while( !dbg->offsets );
// lookup inside function
min = 0;
max = fdebug->nops;
code_pos -= dbg->start;
while( min < max ) {
int mid = (min + max) >> 1;
int offset = dbg->large ? ((int*)dbg->offsets)[mid] : ((unsigned short*)dbg->offsets)[mid];
if( offset <= code_pos )
min = mid + 1;
else
max = mid;
}
if( min == 0 )
return false; // ???
*fpos = min - 1;
return true;
}
uchar *hl_module_resolve_symbol_full( void *addr, uchar *out, int *outSize, int **r_debug_addr ) {
int *debug_addr;
int file, line;
int pos = 0;
int fidx, fpos;
hl_function *fdebug;
int i;
hl_module *m = NULL;
for(i=0;i<modules_count;i++) {
m = cur_modules[i];
if( addr >= m->jit_code && addr <= (void*)((char*)m->jit_code + m->codesize) ) break;
}
if( i == modules_count )
return NULL;
if( !module_resolve_pos(m,addr,&fidx,&fpos) )
return NULL;
// extract debug info
fdebug = m->code->functions + fidx;
debug_addr = fdebug->debug + ((fpos&0xFFFF) * 2);
file = debug_addr[0];
line = debug_addr[1];
if( r_debug_addr ) {
*r_debug_addr = debug_addr;
if( file < 0 ) return NULL; // already cached
}
if( !out )
return NULL;
int size = *outSize;
if( fdebug->obj )
pos += usprintf(out,size - pos,USTR("%s.%s("),fdebug->obj->name,fdebug->field.name);
else if( fdebug->field.ref )
pos += usprintf(out,size - pos,USTR("%s.~%s.%d("),fdebug->field.ref->obj->name, fdebug->field.ref->field.name, fdebug->ref);
else
pos += usprintf(out,size - pos,USTR("fun$%d("),fdebug->findex);
pos += hl_from_utf8(out + pos,size - pos,m->code->debugfiles[file&0x7FFFFFFF]);
pos += usprintf(out + pos, size - pos, USTR(":%d)"), line);
*outSize = pos;
return out;
}
static uchar *module_resolve_symbol( void *addr, uchar *out, int *outSize ) {
return hl_module_resolve_symbol_full(addr,out,outSize,NULL);
}
int hl_module_capture_stack_range( void *stack_top, void **stack_ptr, void **out, int size ) {
#if defined(HL_64) && defined(HL_WIN)
#else
void *stack_bottom = stack_ptr;
#endif
int count = 0;
if( modules_count == 1 ) {
hl_module *m = cur_modules[0];
unsigned char *code = m->jit_code;
int code_size = m->codesize;
if( m->jit_debug ) {
int s = m->jit_debug[0].start;
code += s;
code_size -= s;
}
while( stack_ptr < (void**)stack_top ) {
#if defined(HL_64) && defined(HL_WIN)
void *module_addr = *stack_ptr++; // EIP
if( module_addr >= (void*)code && module_addr < (void*)(code + code_size) ) {
if( out ) {
if( count == size ) break;
out[count++] = module_addr;
} else
count++;
}
#else
void *stack_addr = *stack_ptr++; // EBP
if( stack_addr > stack_bottom && stack_addr < stack_top ) {
void *module_addr = *stack_ptr; // EIP
if( module_addr >= (void*)code && module_addr < (void*)(code + code_size) ) {
if( out ) {
if( count == size ) break;
out[count++] = module_addr;
} else {
count++;
}
}
}
#endif
}
} else {
while( stack_ptr < (void**)stack_top ) {
#if defined(HL_64) && defined(HL_WIN)
void *module_addr = *stack_ptr++; // EIP
{
#else
void *stack_addr = *stack_ptr++; // EBP
if( stack_addr > stack_bottom && stack_addr < stack_top ) {
void *module_addr = *stack_ptr; // EIP
#endif
int i;
for(i=0;i<modules_count;i++) {
hl_module *m = cur_modules[i];
unsigned char *code = m->jit_code;
int code_size = m->codesize;
if( module_addr >= (void*)code && module_addr < (void*)(code + code_size) ) {
if( out && count == size ) {
stack_ptr = stack_top;
break;
}
if( m->jit_debug ) {
int s = m->jit_debug[0].start;
code += s;
code_size -= s;
if( module_addr < (void*)code || module_addr >= (void*)(code + code_size) ) continue;
}
if( out )
out[count++] = module_addr;
else
count++;
break;
}
}
}
}
}
return count;
}
static int module_capture_stack( void **stack, int size ) {
return hl_module_capture_stack_range(hl_get_thread()->stack_top, (void**)&stack, stack, size);
}
static void hl_module_types_dump( void (*fdump)( void *, int) ) {
int ntypes = 0;
int i, j, fcount = 0;
for(i=0;i<modules_count;i++)
ntypes += cur_modules[i]->code->ntypes;
fdump(&ntypes,4);
for(i=0;i<modules_count;i++) {
hl_module *m = cur_modules[i];
for(j=0;j<m->code->ntypes;j++) {
hl_type *t = m->code->types + j;
fdump(&t,sizeof(void*));
if( t->kind == HFUN ) fcount++;
}
}
fdump(&fcount,4);
for(i=0;i<modules_count;i++) {
hl_module *m = cur_modules[i];
for(j=0;j<m->code->ntypes;j++) {
hl_type *t = m->code->types + j;
if( t->kind == HFUN ) {
hl_type *ct = (hl_type*)&t->fun->closure_type;
fdump(&ct,sizeof(void*));
}
}
}
}
hl_module *hl_module_alloc( hl_code *c ) {
int i;
int gsize = 0;
hl_module *m = (hl_module*)malloc(sizeof(hl_module));
if( m == NULL )
return NULL;
memset(m,0,sizeof(hl_module));
m->code = c;
m->globals_indexes = (int*)malloc(sizeof(int)*c->nglobals);
if( m->globals_indexes == NULL ) {
hl_module_free(m);
return NULL;
}
for(i=0;i<c->nglobals;i++) {
gsize += hl_pad_size(gsize, c->globals[i]);
m->globals_indexes[i] = gsize;
gsize += hl_type_size(c->globals[i]);
}
m->globals_size = gsize;
m->globals_data = (unsigned char*)malloc(gsize);
if( m->globals_data == NULL ) {
hl_module_free(m);
return NULL;
}
memset(m->globals_data,0,gsize);
m->functions_ptrs = (void**)malloc(sizeof(void*)*(c->nfunctions + c->nnatives));
m->functions_indexes = (int*)malloc(sizeof(int)*(c->nfunctions + c->nnatives));
m->ctx.functions_types = (hl_type**)malloc(sizeof(void*)*(c->nfunctions + c->nnatives));
if( m->functions_ptrs == NULL || m->functions_indexes == NULL || m->ctx.functions_types == NULL ) {
hl_module_free(m);
return NULL;
}
memset(m->functions_ptrs,0,sizeof(void*)*(c->nfunctions + c->nnatives));
memset(m->functions_indexes,0xFF,sizeof(int)*(c->nfunctions + c->nnatives));
memset(m->ctx.functions_types,0,sizeof(void*)*(c->nfunctions + c->nnatives));
hl_alloc_init(&m->ctx.alloc);
m->ctx.functions_ptrs = m->functions_ptrs;
return m;
}
static void null_function() {
hl_error("Null function ptr");
}
static void append_fields( char **p, hl_type *t );
static void append_type( char **p, hl_type *t ) {
*(*p)++ = TYPE_STR[t->kind];
switch( t->kind ) {
case HFUN:
{
int i;
for(i=0;i<t->fun->nargs;i++)
append_type(p,t->fun->args[i]);
*(*p)++ = '_';
append_type(p,t->fun->ret);
break;
}
case HREF:
case HNULL:
append_type(p,t->tparam);
break;
case HOBJ:
{
append_fields(p, t);
*(*p)++ = '_';
}
break;
case HABSTRACT:
*p += utostr(*p,100,t->abs_name);
*(*p)++ = '_';
break;
default:
break;
}
}
static void append_fields( char **p, hl_type *t ) {
int i;
if( t->obj->super )
append_fields(p, t->obj->super);
for(i=0;i<t->obj->nfields;i++)
append_type(p,t->obj->fields[i].t);
}
#define DISABLED_LIB_PTR ((void*)(int_val)2)
static void *resolve_library( const char *lib, bool is_opt ) {
char tmp[256];
void *h;
# ifndef HL_CONSOLE
static char *DISABLED_LIBS = NULL;
if( !DISABLED_LIBS ) {
DISABLED_LIBS = getenv("HL_DISABLED_LIBS");
if( !DISABLED_LIBS ) DISABLED_LIBS = "";
}
char *disPart = strstr(DISABLED_LIBS, lib);
if( disPart ) {
disPart += strlen(lib);
if( *disPart == 0 || *disPart == ',' )
return DISABLED_LIB_PTR;
}
# endif
if( strcmp(lib,"builtin") == 0 )
return dlopen(NULL,RTLD_LAZY);
if( strcmp(lib,"std") == 0 ) {
# ifdef HL_WIN
# ifdef HL_64
h = dlopen("libhl64.dll",RTLD_LAZY);
if( h == NULL ) h = dlopen("libhl.dll",RTLD_LAZY);
# else
h = dlopen("libhl.dll",RTLD_LAZY);
# endif
if( h == NULL && !is_opt ) hl_fatal1("Failed to load library %s","libhl.dll");
return h;
# else
return RTLD_DEFAULT;
# endif
}
strcpy(tmp,lib);
# ifdef HL_64
strcpy(tmp+strlen(lib),"64.hdll");
h = dlopen(tmp,RTLD_LAZY);
if( h != NULL ) return h;
# endif
strcpy(tmp+strlen(lib),".hdll");
h = dlopen(tmp,RTLD_LAZY);
if( h == NULL && !is_opt )
hl_fatal1("Failed to load library %s",tmp);
return h;
}
static void disabled_primitive() {
hl_error("This library primitive has been disabled");
}
static void hl_module_init_indexes( hl_module *m ) {
int i;
for(i=0;i<m->code->nfunctions;i++) {
hl_function *f = m->code->functions + i;
m->functions_indexes[f->findex] = i;
m->ctx.functions_types[f->findex] = f->type;
}
for(i=0;i<m->code->nnatives;i++) {
hl_native *n = m->code->natives + i;
m->functions_indexes[n->findex] = i + m->code->nfunctions;
m->ctx.functions_types[n->findex] = n->t;
}
for(i=0;i<m->code->ntypes;i++) {
hl_type *t = m->code->types + i;
switch( t->kind ) {
case HOBJ:
case HSTRUCT:
t->obj->m = &m->ctx;
t->obj->global_value = ((int)(int_val)t->obj->global_value) ? (void**)(int_val)(m->globals_data + m->globals_indexes[(int)(int_val)t->obj->global_value-1]) : NULL;
{
int j;
for(j=0;j<t->obj->nproto;j++) {
hl_obj_proto *p = t->obj->proto + j;
hl_function *f = m->code->functions + m->functions_indexes[p->findex];
f->obj = t->obj;
f->field.name = p->name;
}
for(j=0;j<t->obj->nbindings;j++) {
int fid = t->obj->bindings[j<<1];
int mid = t->obj->bindings[(j<<1)|1];
hl_obj_field *of = hl_obj_field_fetch(t,fid);
switch( of->t->kind ) {
case HFUN:
case HDYN:
{
hl_function *f = m->code->functions + m->functions_indexes[mid];
f->obj = t->obj;
f->field.name = of->name;
}
break;
default:
break;
}
}
}
break;
case HENUM:
hl_init_enum(t,&m->ctx);
t->tenum->global_value = ((int)(int_val)t->tenum->global_value) ? (void**)(int_val)(m->globals_data + m->globals_indexes[(int)(int_val)t->tenum->global_value-1]) : NULL;
break;
case HVIRTUAL:
hl_init_virtual(t,&m->ctx);
break;
default:
break;
}
}
for(i=0;i<m->code->nfunctions;i++) {
int k;
hl_function *f = m->code->functions + i;
hl_function *real_f = f;
while( real_f && !real_f->obj ) real_f = real_f->field.ref;
if( real_f == NULL ) continue;
for(k=0;k<f->nops;k++) {
hl_opcode *op = f->ops + k;
switch( op->op ) {
case OCall0:
case OCall1:
case OCall2:
case OCall3:
case OCall4:
case OCallN:
case OStaticClosure:
case OInstanceClosure:
if( m->functions_indexes[op->p2] < m->code->nfunctions ) {
hl_function *floc = m->code->functions + m->functions_indexes[op->p2];
if( floc->obj ) continue;
floc->field.ref = real_f;
floc->ref = real_f->ref++;
}
break;
default:
break;
}
}
}
static hl_type_obj obj_entry = {0};
hl_function *fent = m->code->functions + m->functions_indexes[m->code->entrypoint];
obj_entry.name = USTR("");
fent->obj = &obj_entry;
fent->field.name = USTR("init");
}
static void hl_module_init_natives( hl_module *m ) {
char tmp[256];
int i;
void *libHandler = NULL;
const char *curlib = NULL, *sign;
for(i=0;i<m->code->nnatives;i++) {
hl_native *n = m->code->natives + i;
const char *lib = n->lib;
bool is_opt = *lib == '?';
char *p = tmp;
void *f;
if( is_opt ) lib++;
if( curlib != lib ) {
curlib = lib;
libHandler = resolve_library(lib, is_opt);
}
if( libHandler == DISABLED_LIB_PTR ) {
m->functions_ptrs[n->findex] = disabled_primitive;
continue;
}
strcpy(p,"hlp_");
p += 4;
strcpy(p,n->name);
p += strlen(n->name);
*p++ = 0;
f = dlsym(libHandler,tmp);
if( f == NULL ) {
if( is_opt ) {
m->functions_ptrs[n->findex] = hl_prim_not_loaded;
continue;
}
hl_fatal2("Failed to load function %s@%s",n->lib,n->name);
}
m->functions_ptrs[n->findex] = ((void *(*)( const char **p ))f)(&sign);
p = tmp;
append_type(&p,n->t);
*p++ = 0;
if( memcmp(sign,tmp,strlen(sign)+1) != 0 )
hl_fatal4("Invalid signature for function %s@%s : %s required but %s found in hdll",n->lib,n->name,tmp,sign);
}
}
static void hl_module_init_constant( hl_module *m, hl_constant *c ) {
hl_type *t = m->code->globals[c->global];
hl_runtime_obj *rt;
vdynamic **global = (vdynamic**)(m->globals_data + m->globals_indexes[c->global]);
vdynamic *v = NULL;
switch (t->kind) {
case HOBJ:
case HSTRUCT:
rt = hl_get_obj_rt(t);
v = (vdynamic*)hl_malloc(&m->ctx.alloc,rt->size);
v->t = t;
for(int i=0;i<c->nfields;i++) {
int idx = c->fields[i];
hl_type *ft = t->obj->fields[i].t;
void *addr = (char*)v + rt->fields_indexes[i];
switch (ft->kind) {
case HI32:
*(int*)addr = m->code->ints[idx];
break;
case HBOOL:
*(bool*)addr = idx != 0;
break;
case HF64:
*(double*)addr = m->code->floats[idx];
break;
case HBYTES:
*(const void**)addr = hl_get_ustring(m->code, idx);
break;
case HTYPE:
*(hl_type**)addr = m->code->types + idx;
break;
default:
*(void**)addr = *(void**)(m->globals_data + m->globals_indexes[idx]);
break;
}
}
break;
default:
hl_fatal("assert");
}
*global = v;
hl_remove_root(global);
}
static void hl_module_add( hl_module *m ) {
hl_module **old_modules = cur_modules;
hl_module **new_modules = (hl_module**)malloc(sizeof(void*)*(modules_count + 1));
memcpy(new_modules, old_modules, sizeof(void*)*modules_count);
new_modules[modules_count] = m;
cur_modules = new_modules;
modules_count++;
free(old_modules);
}
int hl_module_init( hl_module *m, h_bool hot_reload ) {
int i;
jit_ctx *ctx;
// expand globals
if( hot_reload ) {
int nsize = m->globals_size + HOT_RELOAD_EXTRA_GLOBALS * sizeof(void*);
int *nindexes = malloc(sizeof(int) * (m->code->nglobals + HOT_RELOAD_EXTRA_GLOBALS));
memcpy(nindexes,m->globals_indexes,sizeof(int)*m->code->nglobals);
memset(nindexes + m->code->nglobals,0xFF,HOT_RELOAD_EXTRA_GLOBALS * sizeof(int));
free(m->globals_indexes);
free(m->globals_data);
m->globals_indexes = nindexes;
m->globals_data = malloc(nsize);
memset(m->globals_data,0,m->globals_size);
memset(m->globals_data + m->globals_size,0xFF,HOT_RELOAD_EXTRA_GLOBALS * sizeof(void*));
}
// RESET globals
for(i=0;i<m->code->nglobals;i++) {
hl_type *t = m->code->globals[i];
if( t->kind == HFUN ) *(void**)(m->globals_data + m->globals_indexes[i]) = null_function;
if( hl_is_ptr(t) )
hl_add_root(m->globals_data+m->globals_indexes[i]);
}
// inits
if( hot_reload ) m->hash = hl_code_hash_alloc(m->code);
hl_module_init_natives(m);
hl_module_init_indexes(m);
// JIT
ctx = hl_jit_alloc();
if( ctx == NULL )
return 0;
hl_jit_init(ctx, m);
for(i=0;i<m->code->nfunctions;i++) {
hl_function *f = m->code->functions + i;
int fpos = hl_jit_function(ctx, m, f);
if( fpos < 0 ) {
hl_jit_free(ctx, false);
return 0;
}
m->functions_ptrs[f->findex] = (void*)(int_val)fpos;
}
m->jit_code = hl_jit_code(ctx, m, &m->codesize, &m->jit_debug, NULL);
for(i=0;i<m->code->nfunctions;i++) {
hl_function *f = m->code->functions + i;
m->functions_ptrs[f->findex] = ((unsigned char*)m->jit_code) + ((int_val)m->functions_ptrs[f->findex]);
}
// INIT constants
for(i=0;i<m->code->nconstants;i++) {
hl_constant *c = m->code->constants + i;
hl_module_init_constant(m, c);
}
hl_module_add(m);
hl_setup_exception(module_resolve_symbol, module_capture_stack);
hl_gc_set_dump_types(hl_module_types_dump);
hl_jit_free(ctx, hot_reload);
if( hot_reload ) {
hl_code_hash_finalize(m->hash);
m->jit_ctx = ctx;
}
return 1;
}
h_bool hl_module_patch( hl_module *m1, hl_code *c ) {
int i,i1,i2;
bool has_changes = false;
int changes_count = 0;
jit_ctx *ctx = m1->jit_ctx;
hl_module *m2 = hl_module_alloc(c);
m2->hash = hl_code_hash_alloc(c);
hl_code_hash_remap_globals(m2->hash,m1->hash);
// share global data
free(m2->globals_data);
free(m2->globals_indexes);
m2->globals_data = m1->globals_data;
m2->globals_indexes = m1->globals_indexes;
int gsize = m1->globals_size;
for(i=m1->code->nglobals;i<m2->code->nglobals;i++) {
hl_type *t = c->globals[i];
gsize += hl_pad_size(gsize, t);
m2->globals_indexes[i] = gsize;
gsize += hl_type_size(t);
if( hl_is_ptr(t) )
hl_add_root(m2->globals_data+m2->globals_indexes[i]);
}
memset(m2->globals_data+m1->globals_size,0,gsize - m1->globals_size);
m2->globals_size = gsize;
hl_module_init_natives(m2);
hl_module_init_indexes(m2);
hl_jit_reset(ctx, m2);
hl_code_hash_finalize(m2->hash);
for(i=0;i<m2->code->nconstants;i++) {
hl_constant *c = m2->code->constants + i;
if( c->global >= m1->code->nglobals )
hl_module_init_constant(m2, c);
}
for(i2=0;i2<m2->code->nfunctions;i2++) {
hl_function *f2 = m2->code->functions + i2;
int sign2 = m2->hash->functions_signs[i2];
if( f2->field.name == NULL ) {
m2->hash->functions_hashes[i2] = -1;
continue;
}
for(i1=0;i1<m1->code->nfunctions;i1++) {
int sign1 = m1->hash->functions_signs[i1];
if( sign1 == sign2 ) {
hl_function *f1 = m1->code->functions + i1;
if( (f1->obj != NULL) != (f2->obj != NULL) || !f1->field.name || !f2->field.name ) {
printf("[HotReload] Signature conflict\n");
continue;
}
if( ucmp(fun_obj(f1)->name,fun_obj(f2)->name) != 0 || ucmp(fun_field_name(f1),fun_field_name(f2)) != 0 ) {
printf("[HotReload] Signature conflict\n");
continue;
}
int hash2 = m2->hash->functions_hashes[i2];
int hash1 = m1->hash->functions_hashes[i1];
m2->hash->functions_hashes[i2] = i1; // index reference
if( hash1 == hash2 )
break;
# ifdef HL_DEBUG
uprintf(USTR("%s."), fun_obj(f1)->name);
uprintf(USTR("%s"), fun_field_name(f1));
if( !f1->obj )
printf("~%d", f1->ref);
printf(" has been modified [%d]\n", f1->nops);
# endif
changes_count++;
m1->hash->functions_hashes[i1] = hash2; // update hash
int fpos = hl_jit_function(ctx, m2, f2);
if( fpos < 0 ) return false;
m2->functions_ptrs[f2->findex] = (void*)(int_val)fpos;
has_changes = true;
break;
}
}
if( i1 == m1->code->nfunctions ) {
// not found (signature changed or new method) : inject new method!
int fpos = hl_jit_function(ctx, m2, f2);
if( fpos < 0 ) return false;
m2->hash->functions_hashes[i2] = -1;
m2->functions_ptrs[f2->findex] = (void*)(int_val)fpos;
# ifdef HL_DEBUG
uprintf(USTR("%s."), fun_obj(f2)->name);
uprintf(USTR("%s"), fun_field_name(f2));
if( !f2->obj )
printf("~%d", f2->ref);
printf(" has been added\n");
# endif
changes_count++;
has_changes = true;
// should be added to m1 functions for later reload?
}
}
if( !has_changes ) {
printf("[HotReload] No changes found\n");
fflush(stdout);
hl_jit_free(ctx, true);
return false;
}
// patch same types
for(i1=0;i1<m1->code->ntypes;i1++) {
hl_type *p = m1->code->types + i1;
switch( p->kind ) {
case HOBJ:
case HSTRUCT:
break;
case HENUM:
if( !p->tenum->global_value ) continue;
break;
default:
continue;
}
for(i2=0;i2<c->ntypes;i2++) {
hl_type *t = c->types + i2;
if( p->kind != t->kind ) continue;
switch( p->kind ) {
case HOBJ:
case HSTRUCT:
if( ucmp(p->obj->name,t->obj->name) != 0 ) continue;
if( hl_code_hash_type(m1->hash,p) == hl_code_hash_type(m2->hash,t) ) {
t->obj = p->obj; // alias the types ! they are different pointers but have the same layout
t->vobj_proto = p->vobj_proto;
} else {
uprintf(USTR("[HotReload] Type %s has changed\n"),t->obj->name);
changes_count++;
}
break;
case HENUM:
if( ucmp(p->tenum->name,t->tenum->name) != 0 ) continue;
if( hl_code_hash_type(m1->hash,p) == hl_code_hash_type(m2->hash,t) ) {
t->tenum = p->tenum; // alias the types ! they are different pointers but have the same layout
} else {
uprintf(USTR("[HotReload] Type %s has changed\n"),t->tenum->name);
changes_count++;
}
break;
default:
break;
}
break;
}
}
m2->jit_code = hl_jit_code(ctx, m2, &m2->codesize, &m2->jit_debug, m1);
// patch missing debug info
int start = -1;
if( m2->jit_debug ) {
for(i=0;i<c->nfunctions;i++) {
if( m2->jit_debug[i].start < 0 ) {
m2->jit_debug[i].start = start;
m2->jit_debug[i].offsets = NULL;
} else {
start = m2->jit_debug[i].start;
}
}
}
hl_jit_free(ctx,true);
if( m2->jit_code == NULL ) {
printf("[HotReload] Couldn't JIT result\n");
fflush(stdout);
return false;
}
for(i=0;i<m2->code->nfunctions;i++) {
hl_function *f2 = m2->code->functions + i;
if( m2->hash->functions_hashes[i] < -1 ) continue;
if( m2->functions_ptrs[f2->findex] == NULL ) continue;
void *ptr = ((unsigned char*)m2->jit_code) + ((int_val)m2->functions_ptrs[f2->findex]);
m2->functions_ptrs[f2->findex] = ptr;
// update real function ptr
if( m2->hash->functions_hashes[i] < 0 ) continue;
hl_function *f1 = m1->code->functions + m2->hash->functions_hashes[i];
hl_jit_patch_method(m1->functions_ptrs[f1->findex], m1->functions_ptrs + f1->findex);
m1->functions_ptrs[f1->findex] = ptr;
}
for(i=0;i<m1->code->ntypes;i++) {
hl_type *t = m1->code->types + i;
if( t->kind == HOBJ || t->kind == HSTRUCT ) hl_flush_proto(t);
}
if( changes_count > 0 ) {
printf("[HotReload] %d changes\n", changes_count);
fflush(stdout);
}
hl_module_add(m2);
// call entry point (will only update types)
if( m2->functions_ptrs[c->entrypoint] ) {
vclosure cl;
cl.t = c->functions[m2->functions_indexes[c->entrypoint]].type;
cl.fun = m2->functions_ptrs[c->entrypoint];
cl.hasValue = 0;
hl_dyn_call(&cl,NULL,0);
}
return true;
}
void hl_module_free( hl_module *m ) {
for(int i=0;i<m->code->nglobals;i++) {
if( hl_is_ptr(m->code->globals[i]) )
hl_remove_root(m->globals_data+m->globals_indexes[i]);
}
hl_free(&m->ctx.alloc);
hl_free_executable_memory(m->code, m->codesize);
if( m->hash ) hl_code_hash_free(m->hash);
free(m->functions_indexes);
free(m->functions_ptrs);
free(m->ctx.functions_types);
free(m->globals_indexes);
free(m->globals_data);
if( m->jit_debug ) {
int i;
for(i=0;i<m->code->nfunctions;i++)
free(m->jit_debug[i].offsets);
free(m->jit_debug);
}
if( m->jit_ctx )
hl_jit_free(m->jit_ctx,false);
free(m);
}

View File

@ -0,0 +1,151 @@
/*
* Copyright (C)2005-2016 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef OP_BEGIN
# define OP_BEGIN typedef enum {
# define OP_END } hl_op;
#endif
#ifndef OP
# define OP(o,_) o,
#endif
OP_BEGIN
OP(OMov,2)
OP(OInt,2)
OP(OFloat,2)
OP(OBool,2)
OP(OBytes,2)
OP(OString,2)
OP(ONull,1)
OP(OAdd,3)
OP(OSub,3)
OP(OMul,3)
OP(OSDiv,3)
OP(OUDiv,3)
OP(OSMod,3)
OP(OUMod,3)
OP(OShl,3)
OP(OSShr,3)
OP(OUShr,3)
OP(OAnd,3)
OP(OOr,3)
OP(OXor,3)
OP(ONeg,2)
OP(ONot,2)
OP(OIncr,1)
OP(ODecr,1)
OP(OCall0,2)
OP(OCall1,3)
OP(OCall2,4)
OP(OCall3,5)
OP(OCall4,6)
OP(OCallN,-1)
OP(OCallMethod,-1)
OP(OCallThis,-1)
OP(OCallClosure,-1)
OP(OStaticClosure,2)
OP(OInstanceClosure,3)
OP(OVirtualClosure,3)
OP(OGetGlobal, 2)
OP(OSetGlobal,2)
OP(OField,3)
OP(OSetField,3)
OP(OGetThis,2)
OP(OSetThis,2)
OP(ODynGet,3)
OP(ODynSet,3)
OP(OJTrue,2)
OP(OJFalse,2)
OP(OJNull,2)
OP(OJNotNull,2)
OP(OJSLt,3)
OP(OJSGte,3)
OP(OJSGt,3)
OP(OJSLte,3)
OP(OJULt,3)
OP(OJUGte,3)
OP(OJNotLt,3)
OP(OJNotGte,3)
OP(OJEq,3)
OP(OJNotEq,3)
OP(OJAlways,1)
OP(OToDyn,2)
OP(OToSFloat,2)
OP(OToUFloat,2)
OP(OToInt,2)
OP(OSafeCast,2)
OP(OUnsafeCast,2)
OP(OToVirtual,2)
OP(OLabel,0)
OP(ORet,1)
OP(OThrow,1)
OP(ORethrow,1)
OP(OSwitch,-1)
OP(ONullCheck,1)
OP(OTrap,2)
OP(OEndTrap,1)
OP(OGetI8,3)
OP(OGetI16,3)
OP(OGetMem,3)
OP(OGetArray,3)
OP(OSetI8,3)
OP(OSetI16,3)
OP(OSetMem,3)
OP(OSetArray,3)
OP(ONew,1)
OP(OArraySize,2)
OP(OType,2)
OP(OGetType,2)
OP(OGetTID,2)
OP(ORef,2)
OP(OUnref,2)
OP(OSetref,2)
OP(OMakeEnum,-1)
OP(OEnumAlloc,2)
OP(OEnumIndex,2)
OP(OEnumField,4)
OP(OSetEnumField,3)
OP(OAssert,0)
OP(ORefData,2)
OP(ORefOffset,3)
OP(ONop,0)
// --
OP(OLast,0)
OP_END
#undef OP_BEGIN
#undef OP_END
#undef OP

View File

@ -0,0 +1,572 @@
/*
* Copyright (C)2015-2019 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <hl.h>
#include <hlmodule.h>
#ifdef HL_LINUX
#include <semaphore.h>
#include <signal.h>
#include <sys/syscall.h>
#include <unistd.h>
#endif
#if defined(HL_MAC)
#include <sys/stat.h>
#include <mach/mach.h>
#include <mach/mach_vm.h>
#include <dlfcn.h>
#include <objc/runtime.h>
#include <dispatch/dispatch.h>
#include <execinfo.h>
#include <stdio.h>
#include <stdlib.h>
#endif
#if defined(__GLIBC__)
#if __GLIBC_PREREQ(2, 30)
// tgkill is present
#else
// int tgkill(pid_t tgid, pid_t tid, int sig)
#define tgkill(tgid, tid, sig) syscall(SYS_tgkill, tgid, tid, sig)
#endif
#endif
#define MAX_STACK_SIZE (8 << 20)
#define MAX_STACK_COUNT 2048
HL_API double hl_sys_time( void );
HL_API void hl_setup_profiler( void *, void * );
int hl_module_capture_stack_range( void *stack_top, void **stack_ptr, void **out, int size );
uchar *hl_module_resolve_symbol_full( void *addr, uchar *out, int *outSize, int **r_debug_addr );
typedef struct _thread_handle thread_handle;
typedef struct _profile_data profile_data;
struct _thread_handle {
int tid;
# ifdef HL_WIN_DESKTOP
HANDLE h;
# endif
hl_thread_info *inf;
char name[128];
thread_handle *next;
};
struct _profile_data {
int currentPos;
int dataSize;
unsigned char *data;
profile_data *next;
};
typedef struct {
profile_data *r;
int pos;
} profile_reader;
static struct {
int sample_count;
volatile int profiling_pause;
volatile bool stopLoop;
volatile bool waitLoop;
thread_handle *handles;
thread_handle *olds;
void **tmpMemory;
void *stackOut[MAX_STACK_COUNT];
profile_data *record;
profile_data *first_record;
} data = {0};
#ifdef HL_LINUX
static struct
{
sem_t msg2;
sem_t msg3;
sem_t msg4;
ucontext_t context;
} shared_context;
static void sigprof_handler(int sig, siginfo_t *info, void *ucontext)
{
ucontext_t *ctx = ucontext;
shared_context.context = *ctx;
sem_post(&shared_context.msg2);
sem_wait(&shared_context.msg3);
sem_post(&shared_context.msg4);
}
#elif defined(HL_MAC)
static struct
{
dispatch_semaphore_t msg2;
dispatch_semaphore_t msg3;
dispatch_semaphore_t msg4;
ucontext_t context;
} shared_context;
static void sigprof_handler(int sig, siginfo_t *info, void *ucontext)
{
ucontext_t *ctx = ucontext;
shared_context.context = *ctx;
dispatch_semaphore_signal(shared_context.msg2);
dispatch_semaphore_wait(shared_context.msg3, DISPATCH_TIME_FOREVER);
dispatch_semaphore_signal(shared_context.msg4);
}
#endif
static void *get_thread_stackptr( thread_handle *t, void **eip ) {
#ifdef HL_WIN_DESKTOP
CONTEXT c;
c.ContextFlags = CONTEXT_CONTROL;
if( !GetThreadContext(t->h,&c) ) return NULL;
# ifdef HL_64
*eip = (void*)c.Rip;
return (void*)c.Rsp;
# else
*eip = (void*)c.Eip;
return (void*)c.Esp;
# endif
#elif defined(HL_LINUX)
# ifdef HL_64
*eip = (void*)shared_context.context.uc_mcontext.gregs[REG_RIP];
return (void*)shared_context.context.uc_mcontext.gregs[REG_RSP];
# else
*eip = (void*)shared_context.context.uc_mcontext.gregs[REG_EIP];
return (void*)shared_context.context.uc_mcontext.gregs[REG_ESP];
# endif
#elif defined(HL_MAC)
# ifdef HL_64
struct __darwin_mcontext64 *mcontext = shared_context.context.uc_mcontext;
if (mcontext != NULL) {
*eip = (void*)mcontext->__ss.__rip;
return (void*)mcontext->__ss.__rsp;
}
return NULL;
# else
return NULL;
# endif
#else
return NULL;
#endif
}
static void thread_data_init( thread_handle *t ) {
#ifdef HL_WIN
t->h = OpenThread(THREAD_ALL_ACCESS,FALSE, t->tid);
#endif
}
static void thread_data_free( thread_handle *t ) {
#ifdef HL_WIN
CloseHandle(t->h);
#endif
}
static bool pause_thread( thread_handle *t, bool b ) {
#ifdef HL_WIN
if( b )
return (int)SuspendThread(t->h) >= 0;
else {
ResumeThread(t->h);
return true;
}
#elif defined(HL_LINUX)
if( b ) {
tgkill(getpid(), t->tid, SIGPROF);
return sem_wait(&shared_context.msg2) == 0;
} else {
sem_post(&shared_context.msg3);
return sem_wait(&shared_context.msg4) == 0;
}
#elif defined(HL_MAC)
if( b ) {
pthread_kill( t->inf->pthread_id, SIGPROF);
return dispatch_semaphore_wait(shared_context.msg2, DISPATCH_TIME_FOREVER) == 0;
} else {
dispatch_semaphore_signal(shared_context.msg3);
return dispatch_semaphore_wait(shared_context.msg4, DISPATCH_TIME_FOREVER) == 0;
}
return false;
#else
return false;
#endif
}
static void record_data( void *ptr, int size ) {
profile_data *r = data.record;
if( !r || r->currentPos + size > r->dataSize ) {
r = malloc(sizeof(profile_data));
r->currentPos = 0;
r->dataSize = 1 << 20;
r->data = malloc(r->dataSize);
r->next = NULL;
if( data.record )
data.record->next = r;
else
data.first_record = r;
data.record = r;
fflush(stdout);
}
memcpy(r->data + r->currentPos, ptr, size);
r->currentPos += size;
}
static void read_thread_data( thread_handle *t ) {
if( !pause_thread(t,true) )
return;
void *eip;
void *stack = get_thread_stackptr(t,&eip);
if( !stack ) {
pause_thread(t,false);
return;
}
#if defined(HL_LINUX) || defined(HL_MAC)
int count = hl_module_capture_stack_range(t->inf->stack_top, stack, data.stackOut, MAX_STACK_COUNT);
pause_thread(t, false);
#else
int size = (int)((unsigned char*)t->inf->stack_top - (unsigned char*)stack);
if( size > MAX_STACK_SIZE-32 ) size = MAX_STACK_SIZE-32;
memcpy(data.tmpMemory + 2,stack,size);
pause_thread(t, false);
data.tmpMemory[0] = eip;
data.tmpMemory[1] = stack;
size += sizeof(void*) * 2;
int count = hl_module_capture_stack_range((char*)data.tmpMemory+size, (void**)data.tmpMemory, data.stackOut, MAX_STACK_COUNT);
#endif
int eventId = count | 0x80000000;
double time = hl_sys_time();
hl_threads_info *gc = hl_gc_threads_info();
if( gc->stopping_world ) eventId |= 0x40000000;
record_data(&time,sizeof(double));
record_data(&t->tid,sizeof(int));
record_data(&eventId,sizeof(int));
record_data(data.stackOut,sizeof(void*)*count);
if( *t->inf->thread_name && !*t->name )
memcpy(t->name, t->inf->thread_name, sizeof(t->name));
}
static void hl_profile_loop( void *_ ) {
double wait_time = 1. / data.sample_count;
double next = hl_sys_time();
data.tmpMemory = malloc(MAX_STACK_SIZE);
while( !data.stopLoop ) {
double t = hl_sys_time();
if( t < next || data.profiling_pause ) {
if( !(t < next) ) next = t;
data.waitLoop = false;
continue;
}
hl_threads_info *threads = hl_gc_threads_info();
int i;
thread_handle *prev = NULL;
thread_handle *cur = data.handles;
for(i=0;i<threads->count;i++) {
hl_thread_info *t = threads->threads[i];
if( t->flags & HL_THREAD_INVISIBLE ) continue;
if( !cur || cur->tid != t->thread_id ) {
// have we lost a thread ?
thread_handle *h = cur;
thread_handle *hprev = prev;
while( h ) {
if( h->tid == t->thread_id ) {
// remove from previous queue
if( hprev ) {
hprev->next = h->next;
} else {
data.handles = h->next;
}
// insert at current position
if( prev ) {
h->next = prev->next;
prev->next = h;
} else {
h->next = data.handles;
data.handles = h;
}
break;
}
hprev = h;
h = h->next;
}
if( !h ) {
h = malloc(sizeof(thread_handle));
memset(h,0,sizeof(thread_handle));
h->tid = t->thread_id;
h->inf = t;
thread_data_init(h);
h->next = cur;
cur = h;
if( prev == NULL ) data.handles = h; else prev->next = h;
}
}
if( (t->flags & HL_THREAD_PROFILER_PAUSED) == 0 )
read_thread_data(cur);
prev = cur;
cur = cur->next;
}
if( prev ) prev->next = NULL; else data.handles = NULL;
while( cur != NULL ) {
thread_handle *n;
thread_data_free(cur);
n = cur->next;
if( *cur->name ) {
cur->next = data.olds;
data.olds = cur;
} else
free(cur);
cur = n;
}
next += wait_time;
}
free(data.tmpMemory);
data.tmpMemory = NULL;
data.sample_count = 0;
data.stopLoop = false;
}
static void profile_event( int code, vbyte *data, int dataLen );
void hl_profile_setup( int sample_count ) {
# if defined(HL_THREADS) && (defined(HL_WIN_DESKTOP) || defined(HL_LINUX) || defined (HL_MAC))
hl_setup_profiler(profile_event,hl_profile_end);
if( data.sample_count ) return;
if( sample_count < 0 ) {
// was not started with --profile : pause until we get start event
data.profiling_pause++;
return;
}
data.sample_count = sample_count;
# ifdef HL_LINUX
sem_init(&shared_context.msg2, 0, 0);
sem_init(&shared_context.msg3, 0, 0);
sem_init(&shared_context.msg4, 0, 0);
struct sigaction action = {0};
action.sa_sigaction = sigprof_handler;
action.sa_flags = SA_SIGINFO;
sigaction(SIGPROF, &action, NULL);
# elif defined(HL_MAC)
shared_context.context.uc_mcontext = NULL;
shared_context.msg2 = dispatch_semaphore_create(0);
shared_context.msg3 = dispatch_semaphore_create(0);
shared_context.msg4 = dispatch_semaphore_create(0);
struct sigaction action = {0};
action.sa_sigaction = sigprof_handler;
action.sa_flags = SA_SIGINFO;
sigaction(SIGPROF, &action, NULL);
# endif
hl_thread_start(hl_profile_loop,NULL,false);
# endif
}
static bool read_profile_data( profile_reader *r, void *ptr, int size ) {
while( size ) {
if( r->r == NULL ) return false;
int bytes = r->r->currentPos - r->pos;
if( bytes > size ) bytes = size;
if( ptr ) memcpy(ptr, r->r->data + r->pos, bytes);
size -= bytes;
r->pos += bytes;
if( r->pos == r->r->currentPos ) {
r->r = r->r->next;
r->pos = 0;
}
}
return true;
}
static int write_names( thread_handle *h, FILE *f ) {
int count = 0;
while( h ) {
if( *h->name ) {
if( f ) {
int len = (int)strlen(h->name);
fwrite(&h->tid,1,4,f);
fwrite(&len,1,4,f);
fwrite(h->name,1,len,f);
} else
count++;
}
h = h->next;
}
return count;
}
static void profile_dump() {
if( !data.first_record ) return;
data.profiling_pause++;
printf("Writing profiling data...\n");
fflush(stdout);
FILE *f = fopen("hlprofile.dump","wb");
int version = HL_VERSION;
fwrite("PROF",1,4,f);
fwrite(&version,1,4,f);
fwrite(&data.sample_count,1,4,f);
profile_reader r;
r.r = data.first_record;
r.pos = 0;
int samples = 0;
while( true ) {
double time;
int i, tid, eventId;
if( !read_profile_data(&r,&time, sizeof(double)) ) break;
read_profile_data(&r,&tid,sizeof(int));
read_profile_data(&r,&eventId,sizeof(int));
fwrite(&time,1,8,f);
fwrite(&tid,1,4,f);
fwrite(&eventId,1,4,f);
if( eventId < 0 ) {
int count = eventId & 0x3FFFFFFF;
read_profile_data(&r,data.stackOut,sizeof(void*)*count);
for(i=0;i<count;i++) {
uchar outStr[256];
int outSize = 256;
int *debug_addr = NULL;
hl_module_resolve_symbol_full(data.stackOut[i],outStr,&outSize,&debug_addr);
if( debug_addr == NULL ) {
int bad = -1;
fwrite(&bad,1,4,f);
} else {
fwrite(debug_addr,1,8,f);
if( (debug_addr[0] & 0x80000000) == 0 ) {
debug_addr[0] |= 0x80000000;
fwrite(&outSize,1,4,f);
fwrite(outStr,1,outSize*sizeof(uchar),f);
}
}
}
samples++;
} else {
int size;
read_profile_data(&r,&size, sizeof(int));
fwrite(&size,1,4,f);
while( size ) {
int k = size > MAX_STACK_SIZE ? MAX_STACK_SIZE : size;
read_profile_data(&r,data.tmpMemory,k);
fwrite(data.tmpMemory,1,k,f);
size -= k;
}
}
}
double tend = -1;
fwrite(&tend,1,8,f);
// reset debug_addr flags (allow further dumps)
r.r = data.first_record;
r.pos = 0;
while( true ) {
int i, eventId;
if( !read_profile_data(&r,NULL, sizeof(double) + sizeof(int)) ) break;
read_profile_data(&r,&eventId,sizeof(int));
if( eventId < 0 ) {
int count = eventId & 0x3FFFFFFF;
read_profile_data(&r,data.stackOut,sizeof(void*)*count);
for(i=0;i<count;i++) {
int *debug_addr = NULL;
hl_module_resolve_symbol_full(data.stackOut[i],NULL,NULL,&debug_addr);
if( debug_addr )
debug_addr[0] &= 0x7FFFFFFF;
}
} else {
int size;
read_profile_data(&r,&size,sizeof(int));
read_profile_data(&r,NULL,size);
}
}
// dump threads names
int names_count = write_names(data.handles,NULL) + write_names(data.olds,NULL);
fwrite(&names_count,1,4,f);
write_names(data.handles,f);
write_names(data.olds,f);
// done
fclose(f);
printf("%d profile samples saved\n", samples);
data.profiling_pause--;
}
void hl_profile_end() {
profile_dump();
if( !data.sample_count ) return;
data.stopLoop = true;
while( data.stopLoop ) {};
}
static void profile_event( int code, vbyte *ptr, int dataLen ) {
switch( code ) {
case -1:
hl_get_thread()->flags |= HL_THREAD_PROFILER_PAUSED;
break;
case -2:
hl_get_thread()->flags &= ~HL_THREAD_PROFILER_PAUSED;
break;
case -3:
data.profiling_pause++;
data.waitLoop = true;
while( data.waitLoop ) {}
profile_data *d = data.first_record;
while( d ) {
profile_data *n = d->next;
free(d->data);
free(d);
d = n;
}
data.first_record = NULL;
data.record = NULL;
data.profiling_pause--;
break;
case -4:
data.profiling_pause++;
break;
case -5:
data.profiling_pause--;
break;
case -6:
profile_dump();
break;
case -7:
{
uchar *end = NULL;
hl_profile_setup( ptr ? utoi((uchar*)ptr,&end) : 1000);
}
break;
case -8:
hl_get_thread()->flags |= HL_THREAD_INVISIBLE;
break;
default:
if( code < 0 ) return;
if( data.profiling_pause || (code != 0 && (hl_get_thread()->flags & HL_THREAD_PROFILER_PAUSED)) ) return;
data.profiling_pause++;
data.waitLoop = true;
while( data.waitLoop ) {}
double time = hl_sys_time();
record_data(&time,sizeof(double));
record_data(&hl_get_thread()->thread_id,sizeof(int));
record_data(&code,sizeof(int));
record_data(&dataLen,sizeof(int));
record_data(ptr,dataLen);
data.profiling_pause--;
break;
}
}

View File

@ -0,0 +1,111 @@
/*
* Copyright (C)2005-2016 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <hl.h>
HL_PRIM varray *hl_alloc_array( hl_type *at, int size ) {
if( size == 0 && at->kind == HDYN ) {
static varray empty_array = { &hlt_array, &hlt_dyn };
return &empty_array;
}
int esize = hl_type_size(at);
varray *a;
if( size < 0 ) hl_error("Invalid array size");
a = (varray*)hl_gc_alloc_gen(&hlt_array, sizeof(varray) + esize*size, (hl_is_ptr(at) ? MEM_KIND_DYNAMIC : MEM_KIND_NOPTR) | MEM_ZERO);
a->t = &hlt_array;
a->at = at;
a->size = size;
return a;
}
HL_PRIM void hl_array_blit( varray *dst, int dpos, varray *src, int spos, int len ) {
int size = hl_type_size(dst->at);
memmove( hl_aptr(dst,vbyte) + dpos * size, hl_aptr(src,vbyte) + spos * size, len * size);
}
HL_PRIM hl_type *hl_array_type( varray *a ) {
return a->at;
}
DEFINE_PRIM(_ARR,alloc_array,_TYPE _I32);
DEFINE_PRIM(_VOID,array_blit,_ARR _I32 _ARR _I32 _I32);
DEFINE_PRIM(_TYPE,array_type,_ARR);
typedef struct {
hl_type *at;
int osize;
int size;
} hl_carray;
HL_PRIM void *hl_alloc_carray( hl_type *at, int size ) {
if( at->kind != HOBJ && at->kind != HSTRUCT )
hl_error("Invalid array type");
if( size < 0 )
hl_error("Invalid array size");
hl_runtime_obj *rt = at->obj->rt;
if( rt == NULL || rt->methods == NULL ) rt = hl_get_obj_proto(at);
int osize = rt->size;
if( osize & (HL_WSIZE-1) ) osize += HL_WSIZE - (osize & (HL_WSIZE-1));
hl_carray *arr;
int header = sizeof(hl_carray);
if( at->kind == HSTRUCT ) {
header += sizeof(vdynamic) * size;
arr = (hl_carray*)hl_gc_alloc_gen(at, header + size * osize, (rt->hasPtr ? MEM_KIND_RAW : MEM_KIND_NOPTR) | MEM_ZERO);
arr->osize = sizeof(vdynamic);
} else {
arr = (hl_carray*)hl_gc_alloc_gen(at, header + size * osize, (rt->hasPtr ? MEM_KIND_DYNAMIC : MEM_KIND_NOPTR) | MEM_ZERO);
arr->osize = osize;
}
arr->size = size;
arr->at = at;
int i,k;
for(k=0;k<size;k++) {
vobj *o = (vobj*)((char*)arr + header + osize * k);
if( at->kind == HOBJ )
o->t = at;
else {
vdynamic *d = (vdynamic*)((char*)(arr + 1) + k * sizeof(vdynamic));
d->t = at;
d->v.ptr = o;
}
for(i=0;i<rt->nbindings;i++) {
hl_runtime_binding *b = rt->bindings + i;
*(void**)(((char*)o) + rt->fields_indexes[b->fid]) = b->closure ? hl_alloc_closure_ptr(b->closure,b->ptr,o) : b->ptr;
}
}
return arr;
}
HL_PRIM int hl_carray_length( hl_carray *arr ) {
return arr->size;
}
HL_PRIM vdynamic *hl_carray_get( hl_carray *arr, int pos ) {
if( pos < 0 || pos >= arr->size ) return NULL;
return (vdynamic*)((char*)(arr + 1) + pos * arr->osize);
}
#define _CARRAY _ABSTRACT(hl_carray)
DEFINE_PRIM(_CARRAY,alloc_carray,_TYPE _I32);
DEFINE_PRIM(_DYN,carray_get,_CARRAY _I32);
DEFINE_PRIM(_I32,carray_length,_CARRAY);

View File

@ -0,0 +1,396 @@
/*
* Copyright (C)2005-2016 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <hl.h>
#ifdef PRId64
# define PR_I64 USTR("%" PRId64)
#else
# define PR_I64 USTR("%lld")
#endif
typedef struct _stringitem {
uchar *str;
int size;
int len;
struct _stringitem *next;
} * stringitem;
struct hl_buffer {
int totlen;
int blen;
stringitem data;
};
HL_PRIM hl_buffer *hl_alloc_buffer() {
hl_buffer *b = (hl_buffer*)hl_gc_alloc_raw(sizeof(hl_buffer));
b->totlen = 0;
b->blen = 16;
b->data = NULL;
return b;
}
static void buffer_append_new( hl_buffer *b, const uchar *s, int len ) {
int size;
stringitem it;
while( b->totlen >= (b->blen << 2) )
b->blen <<= 1;
size = (len < b->blen)?b->blen:len;
it = (stringitem)hl_gc_alloc_raw(sizeof(struct _stringitem));
it->str = (uchar*)hl_gc_alloc_noptr(size<<1);
memcpy(it->str,s,len<<1);
it->size = size;
it->len = len;
it->next = b->data;
b->data = it;
}
HL_PRIM void hl_buffer_str_sub( hl_buffer *b, const uchar *s, int len ) {
stringitem it;
int offset = 0;
if( s == NULL || len <= 0 )
return;
b->totlen += len;
it = b->data;
if( it ) {
int free = it->size - it->len;
if( free >= len ) {
memcpy(it->str + it->len,s,len<<1);
it->len += len;
return;
} else {
memcpy(it->str + it->len,s,free<<1);
it->len += free;
offset = free;
len -= free;
}
}
buffer_append_new(b,s + offset,len);
}
HL_PRIM void hl_buffer_str( hl_buffer *b, const uchar *s ) {
if( s ) hl_buffer_str_sub(b,s,(int)ustrlen(s)); else hl_buffer_str_sub(b,USTR("NULL"),4);
}
HL_PRIM void hl_buffer_cstr( hl_buffer *b, const char *s ) {
if( s ) {
int len = (int)hl_utf8_length((vbyte*)s,0);
uchar *out = (uchar*)malloc(sizeof(uchar)*(len+1));
hl_from_utf8(out,len,s);
hl_buffer_str_sub(b,out,len);
free(out);
} else hl_buffer_str_sub(b,USTR("NULL"),4);
}
HL_PRIM void hl_buffer_char( hl_buffer *b, uchar c ) {
stringitem it;
b->totlen++;
it = b->data;
if( it && it->len != it->size ) {
it->str[it->len++] = c;
return;
}
buffer_append_new(b,(uchar*)&c,1);
}
HL_PRIM uchar *hl_buffer_content( hl_buffer *b, int *len ) {
uchar *buf = (uchar*)hl_gc_alloc_noptr((b->totlen+1)<<1);
stringitem it = b->data;
uchar *s = ((uchar*)buf) + b->totlen;
*s = 0;
while( it != NULL ) {
stringitem tmp;
s -= it->len;
memcpy(s,it->str,it->len<<1);
tmp = it->next;
it = tmp;
}
if( len ) *len = b->totlen;
return buf;
}
int hl_buffer_length( hl_buffer *b ) {
return b->totlen;
}
typedef struct vlist {
vdynamic *v;
struct vlist *next;
} vlist;
static void hl_buffer_rec( hl_buffer *b, vdynamic *v, vlist *stack );
static void hl_buffer_addr( hl_buffer *b, void *data, hl_type *t, vlist *stack ) {
uchar buf[32];
switch( t->kind ) {
case HUI8:
hl_buffer_str_sub(b,buf,usprintf(buf,32,USTR("%d"),(int)*(unsigned char*)data));
break;
case HUI16:
hl_buffer_str_sub(b,buf,usprintf(buf,32,USTR("%d"),(int)*(unsigned short*)data));
break;
case HI32:
hl_buffer_str_sub(b,buf,usprintf(buf,32,USTR("%d"),*(int*)data));
break;
case HI64:
hl_buffer_str_sub(b,buf,usprintf(buf,32,PR_I64,*(int64*)data));
break;
case HF32:
hl_buffer_str_sub(b,buf,usprintf(buf,32,USTR("%.9f"),*(float*)data));
break;
case HF64:
hl_buffer_str_sub(b,buf,usprintf(buf,32,USTR("%.17g"),*(double*)data));
break;
case HBYTES:
hl_buffer_str(b,*(uchar**)data);
break;
case HTYPE:
case HREF:
case HABSTRACT:
{
vdynamic tmp;
tmp.t = t;
tmp.v.ptr = *(void**)data;
hl_buffer_rec(b, tmp.v.ptr ? &tmp : NULL, stack);
}
break;
case HBOOL:
if( *(unsigned char*)data )
hl_buffer_str_sub(b,USTR("true"),4);
else
hl_buffer_str_sub(b,USTR("false"),5);
break;
default:
hl_buffer_rec(b, *(vdynamic**)data, stack);
break;
}
}
static void hl_buffer_rec( hl_buffer *b, vdynamic *v, vlist *stack ) {
uchar buf[32];
if( v == NULL ) {
hl_buffer_str_sub(b,USTR("null"),4);
return;
}
switch( v->t->kind ) {
case HVOID:
hl_buffer_str_sub(b,USTR("void"),4);
break;
case HUI8:
hl_buffer_str_sub(b,buf,usprintf(buf,32,USTR("%d"),v->v.ui8));
break;
case HUI16:
hl_buffer_str_sub(b,buf,usprintf(buf,32,USTR("%d"),v->v.ui16));
break;
case HI32:
hl_buffer_str_sub(b,buf,usprintf(buf,32,USTR("%d"),v->v.i));
break;
case HI64:
hl_buffer_str_sub(b,buf,usprintf(buf,32,PR_I64,v->v.i64));
break;
case HF32:
hl_buffer_str_sub(b,buf,usprintf(buf,32,USTR("%.9f"),v->v.f));
break;
case HF64:
hl_buffer_str_sub(b,buf,usprintf(buf,32,USTR("%.17g"),v->v.d));
break;
case HBOOL:
if( v->v.b )
hl_buffer_str_sub(b,USTR("true"),4);
else
hl_buffer_str_sub(b,USTR("false"),5);
break;
case HBYTES:
hl_buffer_str(b,(uchar*)v->v.bytes);
break;
case HFUN:
hl_buffer_str_sub(b,USTR("function#"),9);
hl_buffer_str_sub(b, buf, usprintf(buf, 32, _PTR_FMT,(int_val)v));
break;
case HMETHOD:
hl_buffer_str_sub(b,USTR("method#"),7);
hl_buffer_str_sub(b, buf, usprintf(buf, 32, _PTR_FMT,(int_val)v->v.ptr));
break;
case HOBJ:
case HSTRUCT:
{
hl_type_obj *o = v->t->obj;
if( o->rt == NULL || hl_get_obj_proto(v->t)->toStringFun == NULL ) {
if( v->t->kind == HSTRUCT ) hl_buffer_char(b,'@');
hl_buffer_str(b,o->name);
} else
hl_buffer_str(b,o->rt->toStringFun(v->t->kind == HSTRUCT ? (vdynamic*)v->v.ptr : v));
}
break;
case HARRAY:
{
int i;
varray *a = (varray*)v;
hl_type *at = a->at;
int stride = hl_type_size(at);
vlist l;
vlist *vtmp = stack;
while( vtmp != NULL ) {
if( vtmp->v == v ) {
hl_buffer_str_sub(b,USTR("..."),3);
return;
}
vtmp = vtmp->next;
}
l.v = v;
l.next = stack;
hl_buffer_char(b,'[');
for(i=0;i<a->size;i++) {
if( i )
hl_buffer_str_sub(b,USTR(", "),2);
hl_buffer_addr(b,hl_aptr(a,char) + i * stride,at,&l);
}
hl_buffer_char(b,']');
}
break;
case HTYPE:
hl_buffer_str(b, hl_type_str((hl_type*)v->v.ptr));
break;
case HREF:
hl_buffer_str_sub(b, USTR("ref"), 3);
break;
case HVIRTUAL:
{
vvirtual *vv = (vvirtual*)v;
int i;
vlist l;
vlist *vtmp = stack;
if( vv->value ) {
hl_buffer_rec(b, vv->value, stack);
return;
}
while( vtmp != NULL ) {
if( vtmp->v == v ) {
hl_buffer_str_sub(b,USTR("..."),3);
return;
}
vtmp = vtmp->next;
}
l.v = v;
l.next = stack;
hl_buffer_char(b, '{');
for(i=0;i<vv->t->virt->nfields;i++) {
hl_field_lookup *f = vv->t->virt->lookup + i;
if( i ) hl_buffer_str_sub(b,USTR(", "),2);
hl_buffer_str(b,(uchar*)hl_field_name(f->hashed_name));
hl_buffer_str_sub(b,USTR(" : "),3);
hl_buffer_addr(b, (char*)v + vv->t->virt->indexes[f->field_index], f->t, &l);
}
hl_buffer_char(b, '}');
}
break;
case HDYNOBJ:
{
vdynobj *o = (vdynobj*)v;
int i;
vlist l;
vlist *vtmp = stack;
hl_field_lookup *f;
while( vtmp != NULL ) {
if( vtmp->v == v ) {
hl_buffer_str_sub(b,USTR("..."),3);
return;
}
vtmp = vtmp->next;
}
l.v = v;
l.next = stack;
f = hl_lookup_find(o->lookup,o->nfields,hl_hash_gen(USTR("__string"),false));
if( f && f->t->kind == HFUN && f->t->fun->nargs == 0 && f->t->fun->ret->kind == HBYTES ) {
vclosure *v = (vclosure*)o->values[f->field_index];
if( v ) {
hl_buffer_str(b, v->hasValue ? ((uchar*(*)(void*))v->fun)(v->value) : ((uchar*(*)())v->fun)());
break;
}
}
hl_buffer_char(b, '{');
for(i=0;i<o->nfields;i++) {
hl_field_lookup *f = o->lookup + i;
if( i ) hl_buffer_str_sub(b,USTR(", "),2);
hl_buffer_str(b,(uchar*)hl_field_name(f->hashed_name));
hl_buffer_str_sub(b,USTR(" : "),3);
hl_buffer_addr(b, hl_is_ptr(f->t) ? (void*)(o->values + f->field_index) : (void*)(o->raw_data + f->field_index), f->t, &l);
}
hl_buffer_char(b, '}');
}
break;
case HABSTRACT:
hl_buffer_char(b, '~');
hl_buffer_str(b, v->t->abs_name);
hl_buffer_char(b, ':');
hl_buffer_str_sub(b, buf, usprintf(buf, 32, _PTR_FMT,(int_val)v->v.ptr));
break;
case HENUM:
{
int i;
vlist l;
vlist *vtmp = stack;
hl_enum_construct *c = v->t->tenum->constructs + ((venum*)v)->index;
if( !c->nparams ) {
hl_buffer_str(b, c->name);
break;
}
while( vtmp != NULL ) {
if( vtmp->v == v ) {
hl_buffer_str_sub(b,USTR("..."),3);
return;
}
vtmp = vtmp->next;
}
l.v = v;
l.next = stack;
hl_buffer_str(b, c->name);
hl_buffer_char(b,'(');
for(i=0;i<c->nparams;i++) {
if( i ) hl_buffer_char(b,',');
hl_buffer_addr(b,(char*)v + c->offsets[i],c->params[i], &l);
}
hl_buffer_char(b,')');
}
break;
case HNULL:
hl_buffer_str_sub(b, USTR("_null_"), 6);
break;
default:
hl_buffer_str_sub(b, buf, usprintf(buf, 32, _PTR_FMT USTR("H"),(int_val)v));
break;
}
}
HL_PRIM void hl_buffer_val( hl_buffer *b, vdynamic *v ) {
hl_buffer_rec(b,v,NULL);
}
HL_PRIM uchar *hl_to_string( vdynamic *v ) {
if( v == NULL )
return USTR("null");
if( v->t->kind == HBOOL )
return v->v.b ? USTR("true") : USTR("false");
hl_buffer *b = hl_alloc_buffer();
hl_buffer_val(b,v);
hl_buffer_char(b,0);
return hl_buffer_content(b,NULL);
}

View File

@ -0,0 +1,280 @@
/*
* Copyright (C)2005-2016 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <hl.h>
HL_PRIM vbyte *hl_alloc_bytes( int size ) {
return (vbyte*)hl_gc_alloc_noptr(size);
}
HL_PRIM vbyte *hl_copy_bytes( const vbyte *ptr, int size ) {
vbyte *b = hl_alloc_bytes(size);
memcpy(b,ptr,size);
return b;
}
HL_PRIM void hl_bytes_blit( char *dst, int dpos, char *src, int spos, int len ) {
memmove(dst + dpos,src+spos,len);
}
HL_PRIM int hl_bytes_compare( vbyte *a, int apos, vbyte *b, int bpos, int len ) {
return memcmp(a+apos,b+bpos,len);
}
HL_PRIM int hl_bytes_compare16( vbyte *a, vbyte *b, int len ) {
unsigned short *s1 = (unsigned short *)a;
unsigned short *s2 = (unsigned short *)b;
int i;
for(i=0;i<len;i++)
if( s1[i] != s2[i] )
return ((int)s1[i]) - ((int)s2[i]);
return 0;
}
typedef unsigned char byte;
static void *
memfind_rb (const void *in_block, /* Block containing data */
size_t block_size, /* Size of block in bytes */
const void *in_pattern, /* Pattern to search for */
size_t pattern_size, /* Size of pattern block */
size_t *shift, /* Shift table (search buffer) */
bool *repeat_find) /* TRUE: search buffer already init */
{
size_t
byte_nbr, /* Distance through block */
match_size; /* Size of matched part */
const byte
*match_base = NULL, /* Base of match of pattern */
*match_ptr = NULL, /* Point within current match */
*limit = NULL; /* Last potiental match point */
const byte
*block = (byte *) in_block, /* Concrete pointer to block data */
*pattern = (byte *) in_pattern; /* Concrete pointer to search value */
if (block == NULL || pattern == NULL || shift == NULL)
return (NULL);
/* Pattern must be smaller or equal in size to string */
if (block_size < pattern_size)
return (NULL); /* Otherwise it's not found */
if (pattern_size == 0) /* Empty patterns match at start */
return ((void *)block);
/* Build the shift table unless we're continuing a previous search */
/* The shift table determines how far to shift before trying to match */
/* again, if a match at this point fails. If the byte after where the */
/* end of our pattern falls is not in our pattern, then we start to */
/* match again after that byte; otherwise we line up the last occurence */
/* of that byte in our pattern under that byte, and try match again. */
if (!repeat_find || !*repeat_find)
{
for (byte_nbr = 0; byte_nbr < 256; byte_nbr++)
shift [byte_nbr] = pattern_size + 1;
for (byte_nbr = 0; byte_nbr < pattern_size; byte_nbr++)
shift [(byte) pattern [byte_nbr]] = pattern_size - byte_nbr;
if (repeat_find)
*repeat_find = true;
}
/* Search for the block, each time jumping up by the amount */
/* computed in the shift table */
limit = block + (block_size - pattern_size + 1);
for (match_base = block;
match_base < limit;
match_base += shift [*(match_base + pattern_size)])
{
match_ptr = match_base;
match_size = 0;
/* Compare pattern until it all matches, or we find a difference */
while (*match_ptr++ == pattern [match_size++])
{
/* If we found a match, return the start address */
if (match_size >= pattern_size)
return ((void*)(match_base));
}
}
return NULL;
}
HL_PRIM int hl_bytes_find( vbyte *where, int pos, int len, vbyte *which, int wpos, int wlen ) {
size_t searchbuf [256];
bool repeat_find = false;
vbyte *found = (vbyte*)memfind_rb(where + pos,len,which+wpos,wlen,searchbuf,&repeat_find);
if( found == NULL ) return -1;
return (int)(size_t)(found - where);
}
HL_PRIM int hl_bytes_rfind( vbyte *where, int len, vbyte *which, int wlen ) {
if( wlen > len ) return -1;
if( wlen == 0 ) return len; // at end
int pos = len - wlen;
while( pos >= 0 ) {
if( memcmp(where+pos,which,wlen) == 0 )
return pos;
pos--;
}
return -1;
}
HL_PRIM void hl_bytes_fill( vbyte *bytes, int pos, int len, int value ) {
memset(bytes+pos,value,len);
}
static int ms_gcd( int m, int n ) {
while( n != 0 ) {
int t = m % n;
m=n; n=t;
}
return m;
}
#define TSORT int
#define TID(t) t##_i32
#include "sort.h"
#define TSORT double
#define TID(t) t##_f64
#include "sort.h"
HL_PRIM void hl_bsort_i32( vbyte *bytes, int pos, int len, vclosure *cmp ) {
m_sort_i32 m;
m.arr = (int*)(bytes + pos);
m.c = cmp;
merge_sort_rec_i32(&m,0,len);
}
HL_PRIM void hl_bsort_f64( vbyte *bytes, int pos, int len, vclosure *cmp ) {
m_sort_f64 m;
m.arr = (double*)(bytes + pos);
m.c = cmp;
merge_sort_rec_f64(&m,0,len);
}
static inline bool is_space_char(uchar c) {
return c == 32 || (c > 8 && c < 14);
}
HL_PRIM double hl_parse_float( vbyte *bytes, int pos, int len ) {
const uchar *str = (uchar*)(bytes+pos);
uchar *end = NULL;
while( is_space_char(*str) ) str++;
double d = utod(str,&end);
if( end == str )
return hl_nan();
return d;
}
static inline bool has_hex_prefix( const uchar *c, int len, bool is_signed ) {
if (is_signed)
return len >= 3 && c[1] == '0' && (c[2] == 'x' || c[2] == 'X');
return len >= 2 && c[0] == '0' && (c[1] == 'x' || c[1] == 'X');
}
HL_PRIM vdynamic *hl_parse_int( vbyte *bytes, int pos, int len ) {
const uchar *c = (uchar*)(bytes + pos);
const uchar *start = c;
int h;
while( is_space_char(*c) ) c++;
uchar sign = c[0];
bool is_signed = sign == '-' || sign == '+';
if( has_hex_prefix(c,(int)(len+start-c),is_signed) ) {
h = 0;
c += is_signed ? 3 : 2;
while( *c ) {
uchar k = *c++;
if( k >= '0' && k <= '9' )
h = (h << 4) | (k - '0');
else if( k >= 'A' && k <= 'F' )
h = (h << 4) | ((k - 'A') + 10);
else if( k >= 'a' && k <= 'f' )
h = (h << 4) | ((k - 'a') + 10);
else
break;
}
if( sign == '-' ) h = -h;
} else {
uchar *end = NULL;
h = utoi(c,&end);
if( c == end )
return NULL;
}
return hl_make_dyn(&h,&hlt_i32);
}
// pointer manipulation
HL_PRIM vbyte *hl_bytes_offset( vbyte *src, int offset ) {
return src + offset;
}
HL_PRIM int hl_bytes_subtract( vbyte *a, vbyte *b ) {
return (int)(a - b);
}
HL_PRIM int hl_bytes_address( vbyte *a, int *high ) {
# ifdef HL_64
*high = (int)(((uint64)a)>>32);
# else
*high = 0;
# endif
return (int)(int_val)a;
}
HL_PRIM vbyte *hl_bytes_from_address( int low, int high ) {
# ifdef HL_64
// MSVC does overflow on <<32 even on uint64...
struct { int low; int high; } i64;
i64.low = low;
i64.high = high;
return *(vbyte**)&i64;
# else
return (vbyte*)low;
# endif
}
HL_PRIM int hl_string_compare( vbyte *a, vbyte *b, int len ) {
return memcmp(a,b,len * sizeof(uchar));
}
DEFINE_PRIM(_BYTES,alloc_bytes,_I32);
DEFINE_PRIM(_VOID,bytes_blit,_BYTES _I32 _BYTES _I32 _I32);
DEFINE_PRIM(_I32,bytes_compare,_BYTES _I32 _BYTES _I32 _I32);
DEFINE_PRIM(_I32,bytes_compare16,_BYTES _BYTES _I32);
DEFINE_PRIM(_I32,string_compare,_BYTES _BYTES _I32);
DEFINE_PRIM(_I32,bytes_find,_BYTES _I32 _I32 _BYTES _I32 _I32);
DEFINE_PRIM(_I32,bytes_rfind,_BYTES _I32 _BYTES _I32);
DEFINE_PRIM(_VOID,bytes_fill,_BYTES _I32 _I32 _I32);
DEFINE_PRIM(_F64, parse_float,_BYTES _I32 _I32);
DEFINE_PRIM(_NULL(_I32), parse_int, _BYTES _I32 _I32);
DEFINE_PRIM(_VOID,bsort_i32,_BYTES _I32 _I32 _FUN(_I32,_I32 _I32));
DEFINE_PRIM(_VOID,bsort_f64,_BYTES _I32 _I32 _FUN(_I32,_F64 _F64));
DEFINE_PRIM(_BYTES,bytes_offset, _BYTES _I32);
DEFINE_PRIM(_I32,bytes_subtract, _BYTES _BYTES);
DEFINE_PRIM(_I32,bytes_address, _BYTES _REF(_I32));
DEFINE_PRIM(_BYTES,bytes_from_address, _I32 _I32);

View File

@ -0,0 +1,574 @@
/*
* Copyright (C)2005-2016 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <hl.h>
#include <math.h>
#define TK2(a,b) ((a) | ((b)<<5))
static void invalid_cast( hl_type *from, hl_type *to ) {
hl_error("Can't cast %s to %s",hl_type_str(from),hl_type_str(to));
}
HL_PRIM vdynamic *hl_make_dyn( void *data, hl_type *t ) {
vdynamic *v;
switch( t->kind ) {
case HUI8:
v = (vdynamic*)hl_gc_alloc_noptr(sizeof(vdynamic));
v->t = t;
v->v.i = *(unsigned char*)data;
return v;
case HUI16:
v = (vdynamic*)hl_gc_alloc_noptr(sizeof(vdynamic));
v->t = t;
v->v.i = *(unsigned short*)data;
return v;
case HI32:
v = (vdynamic*)hl_gc_alloc_noptr(sizeof(vdynamic));
v->t = t;
v->v.i = *(int*)data;
return v;
case HI64:
v = (vdynamic*)hl_gc_alloc_noptr(sizeof(vdynamic));
v->t = t;
v->v.i64 = *(int64*)data;
return v;
case HF32:
v = (vdynamic*)hl_gc_alloc_noptr(sizeof(vdynamic));
v->t = t;
v->v.f = *(float*)data;
return v;
case HF64:
v = (vdynamic*)hl_gc_alloc_noptr(sizeof(vdynamic));
v->t = t;
v->v.d = *(double*)data;
return v;
case HBOOL:
return hl_alloc_dynbool(*(bool*)data);
case HBYTES:
case HTYPE:
case HREF:
case HABSTRACT:
{
void *p = *(void**)data;
if( p == NULL ) return NULL;
v = hl_alloc_dynamic(t);
v->v.ptr = p;
return v;
}
default:
return *(vdynamic**)data;
}
}
HL_PRIM int hl_dyn_casti( void *data, hl_type *t, hl_type *to ) {
hl_track_call(HL_TRACK_CAST, on_cast(t,to));
if( t->kind == HDYN ) {
vdynamic *v = *((vdynamic**)data);
if( v == NULL ) return 0;
t = v->t;
if( !hl_is_dynamic(t) ) data = &v->v;
}
switch( t->kind ) {
case HUI8:
return *(unsigned char*)data;
case HUI16:
return *(unsigned short*)data;
case HI32:
return *(int*)data;
case HI64:
return (int)*(int64*)data;
case HF32:
return (int)*(float*)data;
case HF64:
return (int)*(double*)data;
case HBOOL:
return *(bool*)data;
case HNULL:
{
vdynamic *v = *(vdynamic**)data;
if( v == NULL ) return 0;
return hl_dyn_casti(&v->v,t->tparam,to);
}
default:
break;
}
invalid_cast(t,to);
return 0;
}
HL_PRIM int64 hl_dyn_casti64( void *data, hl_type *t ) {
hl_track_call(HL_TRACK_CAST, on_cast(t,&hlt_i64));
if( t->kind == HDYN ) {
vdynamic *v = *((vdynamic**)data);
if( v == NULL ) return 0;
t = v->t;
if( !hl_is_dynamic(t) ) data = &v->v;
}
switch( t->kind ) {
case HUI8:
return *(unsigned char*)data;
case HUI16:
return *(unsigned short*)data;
case HI32:
return *(int*)data;
case HI64:
return *(int64*)data;
case HF32:
return (int64)*(float*)data;
case HF64:
return (int64)*(double*)data;
case HBOOL:
return *(bool*)data;
case HNULL:
{
vdynamic *v = *(vdynamic**)data;
if( v == NULL ) return 0;
return hl_dyn_casti64(&v->v,t->tparam);
}
default:
break;
}
invalid_cast(t,&hlt_i64);
return 0;
}
HL_PRIM void *hl_dyn_castp( void *data, hl_type *t, hl_type *to ) {
hl_track_call(HL_TRACK_CAST, on_cast(t,to));
if( to->kind == HDYN && hl_is_dynamic(t) )
return *(vdynamic**)data;
if( t->kind == HDYN || t->kind == HNULL ) {
vdynamic *v = *(vdynamic**)data;
if( v == NULL )
return NULL;
if( to->kind == HNULL && v->t == to->tparam && hl_is_gc_ptr(v) )
return v; // v might be a vdynamic on the stack
t = v->t;
if( !hl_is_dynamic(t) ) data = &v->v;
} else if( hl_is_dynamic(t) ) {
vdynamic *v = *(vdynamic**)data;
if( v == NULL ) return NULL;
t = v->t;
}
if( t == to || hl_safe_cast(t,to) )
return *(void**)data;
switch( TK2(t->kind,to->kind) ) {
case TK2(HOBJ,HOBJ):
case TK2(HSTRUCT,HSTRUCT):
{
hl_type_obj *t1 = t->obj;
hl_type_obj *t2 = to->obj;
while( true ) {
if( t1 == t2 )
return *(void**)data;
if( t1->super == NULL )
break;
t1 = t1->super->obj;
}
if( t->obj->rt->castFun ) {
vdynamic *v = t->obj->rt->castFun(*(vdynamic**)data,to);
if( v ) return v;
}
break;
}
case TK2(HFUN,HFUN):
{
vclosure *c = *(vclosure**)data;
if( c == NULL ) return NULL;
c = hl_make_fun_wrapper(c,to);
if( c ) return c;
}
break;
case TK2(HOBJ,HVIRTUAL):
case TK2(HDYNOBJ,HVIRTUAL):
case TK2(HVIRTUAL,HVIRTUAL):
return hl_to_virtual(to,*(vdynamic**)data);
case TK2(HVIRTUAL,HOBJ):
{
vvirtual *v = *(vvirtual**)data;
if( v->value == NULL ) break;
return hl_dyn_castp( &v->value, v->value->t, to);
}
case TK2(HOBJ,HDYN):
case TK2(HDYNOBJ,HDYN):
case TK2(HFUN,HDYN):
case TK2(HNULL,HDYN):
case TK2(HARRAY,HDYN):
// NO(HSTRUCT,HDYN)
return *(void**)data;
}
if( to->kind == HDYN )
return hl_make_dyn(data,t);
if( to->kind == HNULL ) {
if( to->tparam->kind == t->kind )
return hl_make_dyn(data,t);
switch( to->tparam->kind ) {
case HUI8:
case HUI16:
case HI32:
case HBOOL:
{
int v = hl_dyn_casti(data,t,to->tparam);
return hl_make_dyn(&v,to->tparam);
}
case HI64:
{
int64 v = hl_dyn_casti64(data,t);
return hl_make_dyn(&v,to->tparam);
}
case HF32:
{
float f = hl_dyn_castf(data,t);
return hl_make_dyn(&f,to->tparam);
}
case HF64:
{
double d = hl_dyn_castd(data,t);
return hl_make_dyn(&d,to->tparam);
}
default:
break;
}
}
if( to->kind == HREF ) {
switch( to->tparam->kind ) {
case HUI8:
case HUI16:
case HI32:
case HBOOL:
{
int *v = (int*)hl_gc_alloc_noptr(sizeof(int));
*v = hl_dyn_casti(data,t,to->tparam);
return v;
}
case HI64:
{
int64 *d = (int64*)hl_gc_alloc_noptr(sizeof(int64));
*d = hl_dyn_casti64(data,t);
return d;
}
case HF32:
{
float *f = (float*)hl_gc_alloc_noptr(sizeof(float));
*f = hl_dyn_castf(data,t);
return f;
}
case HF64:
{
double *d = (double*)hl_gc_alloc_noptr(sizeof(double));
*d = hl_dyn_castd(data,t);
return d;
}
default:
{
void **p = (void**)hl_gc_alloc_raw(sizeof(void*));
*p = hl_dyn_castp(data,t,to->tparam);
return p;
}
break;
}
}
invalid_cast(t,to);
return 0;
}
HL_PRIM double hl_dyn_castd( void *data, hl_type *t ) {
hl_track_call(HL_TRACK_CAST, on_cast(t,&hlt_f64));
if( t->kind == HDYN ) {
vdynamic *v = *((vdynamic**)data);
if( v == NULL ) return 0;
t = v->t;
if( !hl_is_dynamic(t) ) data = &v->v;
}
switch( t->kind ) {
case HF32:
return *(float*)data;
case HF64:
return *(double*)data;
case HUI8:
return *(unsigned char*)data;
case HUI16:
return *(unsigned short*)data;
case HI32:
return *(int*)data;
case HI64:
return (double)*(int64*)data;
case HBOOL:
return *(bool*)data;
case HNULL:
{
vdynamic *v = *(vdynamic**)data;
if( v == NULL ) return 0;
return hl_dyn_castd(&v->v,t->tparam);
}
default:
break;
}
invalid_cast(t,&hlt_f64);
return 0.;
}
HL_PRIM float hl_dyn_castf( void *data, hl_type *t ) {
hl_track_call(HL_TRACK_CAST, on_cast(t,&hlt_f32));
if( t->kind == HDYN ) {
vdynamic *v = *((vdynamic**)data);
if( v == NULL ) return 0;
t = v->t;
if( !hl_is_dynamic(t) ) data = &v->v;
}
switch( t->kind ) {
case HF32:
return *(float*)data;
case HF64:
return (float)*(double*)data;
case HUI8:
return *(unsigned char*)data;
case HUI16:
return *(unsigned short*)data;
case HI32:
return (float)*(int*)data;
case HI64:
return (float)*(int64*)data;
case HBOOL:
return *(bool*)data;
case HNULL:
{
vdynamic *v = *(vdynamic**)data;
if( v == NULL ) return 0;
return hl_dyn_castf(&v->v,t->tparam);
}
default:
break;
}
invalid_cast(t,&hlt_f32);
return 0;
}
static int fcompare( float a, float b ) {
float d = a - b;
if( d != d )
return a == b ? 0 : hl_invalid_comparison; // +INF=+INF
return d == 0.f ? 0 : (d > 0.f ? 1 : -1);
}
static int dcompare( double a, double b ) {
double d = a - b;
if( d != d )
return a == b ? 0 : hl_invalid_comparison; // +INF=+INF
return d == 0. ? 0 : (d > 0. ? 1 : -1);
}
HL_PRIM int hl_ptr_compare( vdynamic *a, vdynamic *b ) {
if( a == b )
return 0;
return a > b ? 1 : -1;
}
HL_PRIM int hl_dyn_compare( vdynamic *a, vdynamic *b ) {
hl_track_call(HL_TRACK_CAST, on_cast(a?a->t:&hlt_dyn,b?b->t:&hlt_dyn));
if( a == b )
return 0;
if( a == NULL )
return -1;
if( b == NULL )
return 1;
switch( TK2(a->t->kind,b->t->kind) ) {
case TK2(HUI8,HUI8):
return (int)a->v.ui8 - (int)b->v.ui8;
case TK2(HUI16,HUI16):
return (int)a->v.ui16 - (int)b->v.ui16;
case TK2(HI32,HI32):
{
int d = a->v.i - b->v.i;
return d == hl_invalid_comparison ? -1 : d;
}
case TK2(HI64,HI64):
{
int64 d = a->v.i64 - b->v.i64;
return d == 0 ? 0 : (d > 0 ? 1 : -1);
}
case TK2(HF32,HF32):
return fcompare(a->v.f,b->v.f);
case TK2(HF64,HF64):
return dcompare(a->v.d,b->v.d);
case TK2(HBOOL,HBOOL):
return (int)a->v.b - (int)b->v.b;
case TK2(HF64, HI32):
return dcompare(a->v.d,(double)b->v.i);
case TK2(HI32, HF64):
return dcompare((double)a->v.i,b->v.d);
case TK2(HF64, HF32):
return dcompare(a->v.d,(double)b->v.f);
case TK2(HF32, HF64):
return dcompare((double)a->v.f,b->v.d);
case TK2(HOBJ,HOBJ):
case TK2(HSTRUCT,HSTRUCT):
if( a->t->obj->rt->compareFun )
return a->t->obj->rt->compareFun(a,b);
return a > b ? 1 : -1;
case TK2(HENUM,HENUM):
return a > b ? 1 : -1;
case TK2(HTYPE,HTYPE):
case TK2(HBYTES,HBYTES):
return a->v.ptr != b->v.ptr;
case TK2(HOBJ,HVIRTUAL):
case TK2(HDYNOBJ,HVIRTUAL):
return hl_dyn_compare(a,((vvirtual*)b)->value);
case TK2(HVIRTUAL,HOBJ):
case TK2(HVIRTUAL,HDYNOBJ):
return hl_dyn_compare(((vvirtual*)a)->value,b);
case TK2(HFUN,HFUN):
if( ((vclosure*)a)->hasValue == 2 )
return hl_dyn_compare((vdynamic*)((vclosure_wrapper*)a)->wrappedFun,b);
if( ((vclosure*)b)->hasValue == 2 )
return hl_dyn_compare(a,(vdynamic*)((vclosure_wrapper*)b)->wrappedFun);
if( ((vclosure*)a)->fun != ((vclosure*)b)->fun )
return hl_invalid_comparison;
return hl_dyn_compare(((vclosure*)a)->value,((vclosure*)b)->value);
case TK2(HVIRTUAL,HVIRTUAL):
if( ((vvirtual*)a)->value && ((vvirtual*)b)->value )
return hl_dyn_compare(((vvirtual*)a)->value,((vvirtual*)b)->value);
return hl_invalid_comparison;
}
return hl_invalid_comparison;
}
HL_PRIM void hl_write_dyn( void *data, hl_type *t, vdynamic *v, bool is_tmp ) {
hl_track_call(HL_TRACK_CAST, on_cast(v?v->t:&hlt_dyn,t));
switch( t->kind ) {
case HUI8:
*(unsigned char*)data = (unsigned char)hl_dyn_casti(&v,&hlt_dyn,t);
break;
case HBOOL:
*(bool*)data = hl_dyn_casti(&v,&hlt_dyn,t) != 0;
break;
case HUI16:
*(unsigned short*)data = (unsigned short)hl_dyn_casti(&v,&hlt_dyn,t);
break;
case HI32:
*(int*)data = hl_dyn_casti(&v,&hlt_dyn,t);
break;
case HI64:
*(int64*)data = hl_dyn_casti64(&v,&hlt_dyn);
break;
case HF32:
*(float*)data = hl_dyn_castf(&v,&hlt_dyn);
break;
case HF64:
*(double*)data = hl_dyn_castd(&v,&hlt_dyn);
break;
default:
{
void *ret = (v && hl_same_type(t,v->t)) ? v : hl_dyn_castp(&v,&hlt_dyn,t);
if( is_tmp && ret == v ) {
ret = hl_alloc_dynamic(v->t);
((vdynamic*)ret)->v = v->v;
}
*(void**)data = ret;
}
break;
}
}
HL_PRIM vdynamic* hl_value_cast( vdynamic *v, hl_type *t ) {
hl_track_call(HL_TRACK_CAST, on_cast(v?v->t:&hlt_dyn,t));
if( t->kind == HDYN || v == NULL || hl_safe_cast(v->t,t) )
return v;
invalid_cast(v->t,t);
return NULL;
}
HL_PRIM bool hl_type_safe_cast( hl_type *a, hl_type *b ) {
return hl_safe_cast(a,b);
}
#define NULL_VAL HLAST
#define OP(op,t1,t2) (TK2(t1,t2) | (op << 10))
#define OP_ADD 0
#define OP_SUB 1
#define OP_MUL 2
#define OP_MOD 3
#define OP_DIV 4
#define OP_SHL 5
#define OP_SHR 6
#define OP_USHR 7
#define OP_AND 8
#define OP_OR 9
#define OP_XOR 10
static vdynamic *hl_dynf64( double v ) {
vdynamic *d = hl_alloc_dynamic(&hlt_f64);
d->v.d = v;
return d;
}
static vdynamic *hl_dyni32( int v ) {
vdynamic *d = hl_alloc_dynamic(&hlt_i32);
d->v.i = v;
return d;
}
static bool is_number( hl_type *t ) {
return t->kind >= HUI8 && t->kind <= HBOOL;
}
#define FOP(op) { double va = hl_dyn_castd(&a,&hlt_dyn); double vb = hl_dyn_castd(&b,&hlt_dyn); return hl_dynf64(va op vb); }
#define IOP(op) { int va = hl_dyn_casti(&a,&hlt_dyn,&hlt_i32); int vb = hl_dyn_casti(&b,&hlt_dyn,&hlt_i32); return hl_dyni32(va op vb); }
HL_PRIM vdynamic *hl_dyn_op( int op, vdynamic *a, vdynamic *b ) {
static uchar *op_names[] = { USTR("+"), USTR("-"), USTR("*"), USTR("%"), USTR("/"), USTR("<<"), USTR(">>"), USTR(">>>"), USTR("&"), USTR("|"), USTR("^") };
if( op < 0 || op >= OpLast ) hl_error("Invalid op %d",op);
hl_track_call(HL_TRACK_CAST, on_cast(a?a->t:&hlt_dyn,b?b->t:&hlt_dyn));
if( !a && !b ) return op == OP_DIV || op == OP_MOD ? hl_dynf64(hl_nan()) : NULL;
if( (!a || is_number(a->t)) && (!b || is_number(b->t)) ) {
switch( op ) {
case OP_ADD: FOP(+);
case OP_SUB: FOP(-);
case OP_MUL: FOP(*);
case OP_MOD: {
double va = hl_dyn_castd(&a,&hlt_dyn);
double vb = hl_dyn_castd(&b,&hlt_dyn);
return hl_dynf64(fmod(va,vb));
}
case OP_DIV: FOP(/);
case OP_SHL: IOP(<<);
case OP_SHR: IOP(>>);
case OP_USHR: {
int va = hl_dyn_casti(&a,&hlt_dyn,&hlt_i32);
int vb = hl_dyn_casti(&b,&hlt_dyn,&hlt_i32);
return hl_dyni32( ((unsigned)va) >> ((unsigned)vb) );
}
case OP_AND: IOP(&);
case OP_OR: IOP(|);
case OP_XOR: IOP(^);
}
}
hl_error("Can't perform dyn op %s %s %s",hl_type_str(a->t),op_names[op],hl_type_str(b->t));
return NULL;
}
DEFINE_PRIM(_I32, dyn_compare, _DYN _DYN);
DEFINE_PRIM(_DYN, value_cast, _DYN _TYPE);
DEFINE_PRIM(_BOOL, type_safe_cast, _TYPE _TYPE);
DEFINE_PRIM(_DYN, dyn_op, _I32 _DYN _DYN);
DEFINE_PRIM(_I32, ptr_compare, _DYN _DYN);

View File

@ -0,0 +1,155 @@
/*
* Copyright (C)2005-2016 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <hl.h>
#ifdef HL_CONSOLE
# include <posix/posix.h>
#else
# include <time.h>
#endif
#ifdef HL_WIN
static struct tm *localtime_r( time_t *t, struct tm *r ) {
struct tm *r2 = localtime(t);
if( r2 == NULL ) return NULL;
*r = *r2;
return r;
}
static struct tm *gmtime_r( time_t *t, struct tm *r ) {
struct tm *r2 = gmtime(t);
if( r2 == NULL ) return NULL;
*r = *r2;
return r;
}
#endif
HL_PRIM int hl_date_now() {
return (int)time(NULL);
}
HL_PRIM vbyte *hl_date_to_string( int date, int *len ) {
char buf[127];
struct tm t;
time_t d = (time_t)(unsigned)date;
int size;
uchar *out;
if( !localtime_r(&d,&t) )
hl_error("Invalid date");
size = (int)strftime(buf,127,"%Y-%m-%d %H:%M:%S",&t);
out = (uchar*)hl_gc_alloc_noptr((size + 1) << 1);
hl_from_utf8(out,size,buf);
*len = size;
return (vbyte*)out;
}
HL_PRIM double hl_date_get_time( int date ) {
return ((unsigned)date) * 1000.;
}
HL_PRIM int hl_date_from_time( double time ) {
return (int)(unsigned int)(time / 1000.);
}
HL_PRIM int hl_date_from_string( vbyte *b, int len ) {
struct tm t;
int o = 0;
const char *str = hl_to_utf8((uchar*)b);
bool recal = true;
memset(&t,0,sizeof(struct tm));
switch( strlen(str) ) {
case 19:
sscanf(str,"%4d-%2d-%2d %2d:%2d:%2d",&t.tm_year,&t.tm_mon,&t.tm_mday,&t.tm_hour,&t.tm_min,&t.tm_sec);
t.tm_isdst = -1;
break;
case 8:
sscanf(str,"%2d:%2d:%2d",&t.tm_hour,&t.tm_min,&t.tm_sec);
o = t.tm_sec + t.tm_min * 60 + t.tm_hour * 60 * 60;
recal = false;
break;
case 10:
sscanf(str,"%4d-%2d-%2d",&t.tm_year,&t.tm_mon,&t.tm_mday);
t.tm_isdst = -1;
break;
default:
hl_error("Invalid date format");
break;
}
if( recal ) {
t.tm_year -= 1900;
t.tm_mon--;
o = (int)mktime(&t);
}
return o;
}
HL_PRIM int hl_date_new( int y, int mo, int d, int h, int m, int s ) {
struct tm t;
memset(&t,0,sizeof(struct tm));
t.tm_year = y - 1900;
t.tm_mon = mo;
t.tm_mday = d;
t.tm_hour = h;
t.tm_min = m;
t.tm_sec = s;
t.tm_isdst = -1;
return (int)mktime(&t);
}
HL_PRIM void hl_date_get_inf( int date, int *y, int *mo, int *day, int *h, int *m, int *s, int *wday ) {
struct tm t;
time_t d = (time_t)(unsigned)date;
if( !localtime_r(&d,&t) )
hl_error("invalid date");
if( y ) *y = t.tm_year + 1900;
if( mo ) *mo = t.tm_mon;
if( day ) *day = t.tm_mday;
if( h ) *h = t.tm_hour;
if( m ) *m = t.tm_min;
if( s ) *s = t.tm_sec;
if( wday ) *wday = t.tm_wday;
}
HL_PRIM void hl_date_get_utc_inf( int date, int *y, int *mo, int *day, int *h, int *m, int *s, int *wday ) {
struct tm t;
time_t d = (time_t)(unsigned)date;
if( !gmtime_r(&d,&t) )
hl_error("invalid date");
if( y ) *y = t.tm_year + 1900;
if( mo ) *mo = t.tm_mon;
if( day ) *day = t.tm_mday;
if( h ) *h = t.tm_hour;
if( m ) *m = t.tm_min;
if( s ) *s = t.tm_sec;
if( wday ) *wday = t.tm_wday;
}
DEFINE_PRIM(_I32, date_now, _NO_ARG);
DEFINE_PRIM(_BYTES, date_to_string, _I32 _REF(_I32));
DEFINE_PRIM(_F64, date_get_time, _I32);
DEFINE_PRIM(_I32, date_from_time, _F64);
DEFINE_PRIM(_I32, date_from_string, _BYTES _I32);
DEFINE_PRIM(_I32, date_new, _I32 _I32 _I32 _I32 _I32 _I32);
DEFINE_PRIM(_VOID, date_get_inf, _I32 _REF(_I32) _REF(_I32) _REF(_I32) _REF(_I32) _REF(_I32) _REF(_I32) _REF(_I32));
DEFINE_PRIM(_VOID, date_get_utc_inf, _I32 _REF(_I32) _REF(_I32) _REF(_I32) _REF(_I32) _REF(_I32) _REF(_I32) _REF(_I32));

View File

@ -0,0 +1,413 @@
/*
* Copyright (C)2005-2016 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <hl.h>
#if defined(HL_LINUX) && (defined(__i386__) || defined(__x86_64__))
# include <sys/ptrace.h>
# include <sys/wait.h>
# include <sys/user.h>
# include <signal.h>
# define USE_PTRACE
#endif
#ifdef HL_MAC
# include <mdbg/mdbg.h>
#endif
#if defined(HL_WIN)
static HANDLE last_process = NULL, last_thread = NULL;
static int last_pid = -1;
static int last_tid = -1;
static HANDLE OpenPID( int pid ) {
if( pid == last_pid )
return last_process;
CloseHandle(last_process);
last_pid = pid;
last_process = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
return last_process;
}
static HANDLE OpenTID( int tid ) {
if( tid == last_tid )
return last_thread;
CloseHandle(last_thread);
last_tid = tid;
last_thread = OpenThread(THREAD_ALL_ACCESS, FALSE, tid);
return last_thread;
}
static void CleanHandles() {
last_pid = -1;
last_tid = -1;
CloseHandle(last_process);
CloseHandle(last_thread);
last_process = NULL;
last_thread = NULL;
}
#endif
HL_API bool hl_debug_start( int pid ) {
# if defined(HL_WIN)
last_pid = -1;
return (bool)DebugActiveProcess(pid);
# elif defined(HL_MAC)
return mdbg_session_attach(pid);
# elif defined(USE_PTRACE)
return ptrace(PTRACE_ATTACH,pid,0,0) >= 0;
# else
return false;
# endif
}
HL_API bool hl_debug_stop( int pid ) {
# if defined(HL_WIN)
BOOL b = DebugActiveProcessStop(pid);
CleanHandles();
return (bool)b;
# elif defined(HL_MAC)
return mdbg_session_detach(pid);
# elif defined(USE_PTRACE)
return ptrace(PTRACE_DETACH,pid,0,0) >= 0;
# else
return false;
# endif
}
HL_API bool hl_debug_breakpoint( int pid ) {
# if defined(HL_WIN)
return (bool)DebugBreakProcess(OpenPID(pid));
# elif defined(HL_MAC)
return mdbg_session_pause(pid);
# elif defined(USE_PTRACE)
return kill(pid,SIGTRAP) == 0;
# else
return false;
# endif
}
HL_API bool hl_debug_read( int pid, vbyte *addr, vbyte *buffer, int size ) {
# if defined(HL_WIN)
return (bool)ReadProcessMemory(OpenPID(pid),addr,buffer,size,NULL);
# elif defined(HL_MAC)
return mdbg_read_memory(pid, addr, buffer, size);
# elif defined(USE_PTRACE)
while( size ) {
long v = ptrace(PTRACE_PEEKDATA,pid,addr,0);
if( size >= sizeof(long) )
*(long*)buffer = v;
else {
memcpy(buffer,&v,size);
break;
}
addr += sizeof(long);
size -= sizeof(long);
buffer += sizeof(long);
}
return true;
# else
return false;
# endif
}
HL_API bool hl_debug_write( int pid, vbyte *addr, vbyte *buffer, int size ) {
# if defined(HL_WIN)
return (bool)WriteProcessMemory(OpenPID(pid),addr,buffer,size,NULL);
# elif defined(HL_MAC)
return mdbg_write_memory(pid, addr, buffer, size);
# elif defined(USE_PTRACE)
while( size ) {
int sz = size >= sizeof(long) ? sizeof(long) : size;
long v = *(long*)buffer;
if( sz != sizeof(long) ) {
long cur = ptrace(PTRACE_PEEKDATA,pid,addr);
memcpy((char*)&v+sz,(char*)&cur+sz,sizeof(long)-sz);
}
if( ptrace(PTRACE_POKEDATA,pid,addr,v) < 0 )
return false;
addr += sz;
size -= sz;
buffer += sz;
}
return true;
# else
return false;
# endif
}
HL_API bool hl_debug_flush( int pid, vbyte *addr, int size ) {
# if defined(HL_WIN)
return (bool)FlushInstructionCache(OpenPID(pid),addr,size);
# elif defined(HL_MAC)
return true;
# elif defined(USE_PTRACE)
return true;
# else
return false;
# endif
}
#ifdef HL_MAC
static int get_reg( int r ) {
switch( r ) {
case 0: return REG_RSP;
case 1: return REG_RBP;
case 2: return REG_RIP;
case 3: return REG_RFLAGS;
case 4: return REG_DR0;
case 5: return REG_DR1;
case 6: return REG_DR2;
case 7: return REG_DR3;
case 8: return REG_DR6;
case 9: return REG_DR7;
case 10: return REG_RAX;
}
return -1;
}
#endif
#ifdef USE_PTRACE
static void *get_reg( int r ) {
struct user_regs_struct *regs = NULL;
struct user *user = NULL;
struct user_fpregs_struct *fp = NULL;
switch( r ) {
case -1: return &user->u_fpstate;
# ifdef HL_64
case 0: return &regs->rsp;
case 1: return &regs->rbp;
case 2: return &regs->rip;
case 10: return &regs->rax;
case 11: return (void*)(-((int_val)&fp->xmm_space[0])-1);
# else
case 0: return &regs->esp;
case 1: return &regs->ebp;
case 2: return &regs->eip;
case 10: return &regs->eax;
case 11: return -1;
# endif
case 3: return &regs->eflags;
default: return &user->u_debugreg[r-4];
}
return NULL;
}
#endif
HL_API int hl_debug_wait( int pid, int *thread, int timeout ) {
# if defined(HL_WIN)
DEBUG_EVENT e;
if( !WaitForDebugEvent(&e,timeout) )
return -1;
*thread = e.dwThreadId;
switch( e.dwDebugEventCode ) {
case EXCEPTION_DEBUG_EVENT:
switch( e.u.Exception.ExceptionRecord.ExceptionCode ) {
case EXCEPTION_BREAKPOINT:
case 0x4000001F: // STATUS_WX86_BREAKPOINT
return 1;
case EXCEPTION_SINGLE_STEP:
case 0x4000001E: // STATUS_WX86_SINGLE_STEP
return 2;
case 0x406D1388: // MS_VC_EXCEPTION (see SetThreadName)
ContinueDebugEvent(e.dwProcessId, e.dwThreadId, DBG_CONTINUE);
break;
case 0xE06D7363: // C++ EH EXCEPTION
case 0x6BA: // File Dialog EXCEPTION
ContinueDebugEvent(e.dwProcessId, e.dwThreadId, DBG_EXCEPTION_NOT_HANDLED);
break;
case EXCEPTION_STACK_OVERFLOW:
return 5;
default:
return 3;
}
break;
case EXIT_PROCESS_DEBUG_EVENT:
return 0;
default:
ContinueDebugEvent(e.dwProcessId, e.dwThreadId, DBG_CONTINUE);
break;
}
return 4;
# elif defined(HL_MAC)
return mdbg_session_wait(pid, thread, timeout);
# elif defined(USE_PTRACE)
int status;
int ret = waitpid(pid,&status,0);
//printf("WAITPID=%X %X\n",ret,status);
*thread = ret;
if( WIFEXITED(status) )
return 0;
if( WIFSTOPPED(status) ) {
int sig = WSTOPSIG(status);
//printf(" STOPSIG=%d\n",sig);
if( sig == SIGSTOP || sig == SIGTRAP )
return 1;
return 3;
}
return 4;
# else
return 0;
# endif
}
HL_API bool hl_debug_resume( int pid, int thread ) {
# if defined(HL_WIN)
return (bool)ContinueDebugEvent(pid, thread, DBG_CONTINUE);
# elif defined(HL_MAC)
return mdbg_session_resume(pid);
# elif defined(USE_PTRACE)
return ptrace(PTRACE_CONT,pid,0,0) >= 0;
# else
return false;
# endif
}
#ifdef HL_WIN
#define DefineGetReg(type,GetFun) \
REGDATA *GetFun( type *c, int reg ) { \
switch( reg ) { \
case 0: return GET_REG(sp); \
case 1: return GET_REG(bp); \
case 2: return GET_REG(ip); \
case 4: return &c->Dr0; \
case 5: return &c->Dr1; \
case 6: return &c->Dr2; \
case 7: return &c->Dr3; \
case 8: return &c->Dr6; \
case 9: return &c->Dr7; \
case 10: return GET_REG(ax); \
default: return GET_REG(ax); \
} \
}
#define GET_REG(x) &c->E##x
#define REGDATA DWORD
#ifdef HL_64
DefineGetReg(WOW64_CONTEXT,GetContextReg32);
# undef GET_REG
# undef REGDATA
# define GET_REG(x) &c->R##x
# define REGDATA DWORD64
# endif
DefineGetReg(CONTEXT,GetContextReg);
#endif
HL_API void *hl_debug_read_register( int pid, int thread, int reg, bool is64 ) {
# if defined(HL_WIN)
# ifdef HL_64
if( !is64 ) {
WOW64_CONTEXT c;
c.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
if( !Wow64GetThreadContext(OpenTID(thread),&c) )
return NULL;
if( reg == 3 )
return (void*)(int_val)c.EFlags;
if( reg == 11 )
return NULL; // TODO
return (void*)(int_val)*GetContextReg32(&c,reg);
}
# else
if( is64 ) return NULL;
# endif
CONTEXT c;
c.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
if( !GetThreadContext(OpenTID(thread),&c) )
return NULL;
if( reg == 3 )
return (void*)(int_val)c.EFlags;
if( reg == 11 )
#ifdef HL_64
return (void*)(int_val)c.FltSave.XmmRegisters[0].Low;
#else
return (void*)*(int_val*)&c.ExtendedRegisters[10*16];
#endif
return (void*)*GetContextReg(&c,reg);
# elif defined(HL_MAC)
return mdbg_read_register(pid, thread, get_reg(reg), is64);
# elif defined(USE_PTRACE)
void *r = get_reg(reg);
if( ((int_val)r) < 0 ) {
// peek FP ptr
char *addr = (char*)ptrace(PTRACE_PEEKUSER,thread,get_reg(-1),0);
void *out = NULL;
hl_debug_read(pid, addr + (-((int_val)r)-1), (vbyte*)&out, sizeof(void*));
return out;
}
return (void*)ptrace(PTRACE_PEEKUSER,thread,r,0);
# else
return NULL;
# endif
}
HL_API bool hl_debug_write_register( int pid, int thread, int reg, void *value, bool is64 ) {
# if defined(HL_WIN)
# ifdef HL_64
if( !is64 ) {
WOW64_CONTEXT c;
c.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
if( !Wow64GetThreadContext(OpenTID(thread),&c) )
return false;
if( reg == 3 )
c.EFlags = (int)(int_val)value;
else if( reg == 11 )
return false; // TODO
else
*GetContextReg32(&c,reg) = (DWORD)(int_val)value;
return (bool)Wow64SetThreadContext(OpenTID(thread),&c);
}
# else
if( is64 ) return false;
# endif
CONTEXT c;
c.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
if( !GetThreadContext(OpenTID(thread),&c) )
return false;
if( reg == 3 )
c.EFlags = (int)(int_val)value;
else if( reg == 11 )
# ifdef HL_64
c.FltSave.XmmRegisters[0].Low = (int_val)value;
# else
*(int_val*)&c.ExtendedRegisters[10*16] = (int_val)value;
# endif
else
*GetContextReg(&c,reg) = (REGDATA)value;
return (bool)SetThreadContext(OpenTID(thread),&c);
# elif defined(HL_MAC)
return mdbg_write_register(pid, thread, get_reg(reg), value, is64);
# elif defined(USE_PTRACE)
return ptrace(PTRACE_POKEUSER,thread,get_reg(reg),value) >= 0;
# else
return false;
# endif
}
DEFINE_PRIM(_BOOL, debug_start, _I32);
DEFINE_PRIM(_VOID, debug_stop, _I32);
DEFINE_PRIM(_BOOL, debug_breakpoint, _I32);
DEFINE_PRIM(_BOOL, debug_read, _I32 _BYTES _BYTES _I32);
DEFINE_PRIM(_BOOL, debug_write, _I32 _BYTES _BYTES _I32);
DEFINE_PRIM(_BOOL, debug_flush, _I32 _BYTES _I32);
DEFINE_PRIM(_I32, debug_wait, _I32 _REF(_I32) _I32);
DEFINE_PRIM(_BOOL, debug_resume, _I32 _I32);
DEFINE_PRIM(_BYTES, debug_read_register, _I32 _I32 _I32 _BOOL);
DEFINE_PRIM(_BOOL, debug_write_register, _I32 _I32 _I32 _BYTES _BOOL);

View File

@ -0,0 +1,265 @@
/*
* Copyright (C)2005-2016 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <hl.h>
#include <stdarg.h>
#include <string.h>
#ifdef HL_CONSOLE
#include <posix/posix.h>
#endif
HL_PRIM void *hl_fatal_error( const char *msg, const char *file, int line ) {
hl_blocking(true);
# ifdef HL_WIN_DESKTOP
HWND consoleWnd = GetConsoleWindow();
DWORD pid;
GetWindowThreadProcessId(consoleWnd, &pid);
if( consoleWnd == NULL || GetActiveWindow() != NULL || GetCurrentProcessId() == pid ) {
char buf[256];
sprintf(buf,"%s\n\n%s(%d)",msg,file,line);
MessageBoxA(NULL,buf,"Fatal Error", MB_OK | MB_ICONERROR);
}
# endif
printf("%s(%d) : FATAL ERROR : %s\n",file,line,msg);
hl_blocking(false);
hl_debug_break();
exit(1);
return NULL;
}
typedef uchar *(*resolve_symbol_type)( void *addr, uchar *out, int *outSize );
typedef int (*capture_stack_type)( void **stack, int size );
static resolve_symbol_type resolve_symbol_func = NULL;
static capture_stack_type capture_stack_func = NULL;
int hl_internal_capture_stack( void **stack, int size ) {
return capture_stack_func(stack,size);
}
HL_PRIM uchar *hl_resolve_symbol( void *addr, uchar *out, int *outSize ) {
return resolve_symbol_func(addr, out, outSize);
}
static void (*throw_jump)( jmp_buf, int ) = NULL;
HL_PRIM void hl_setup_longjump( void *j ) {
throw_jump = j;
}
HL_PRIM void hl_setup_exception( void *resolve_symbol, void *capture_stack ) {
resolve_symbol_func = resolve_symbol;
capture_stack_func = capture_stack;
}
HL_PRIM void hl_set_error_handler( vclosure *d ) {
hl_thread_info *t = hl_get_thread();
t->trap_uncaught = t->trap_current;
t->exc_handler = d;
}
static bool break_on_trap( hl_thread_info *t, hl_trap_ctx *trap, vdynamic *v ) {
while( true ) {
if( trap == NULL || trap == t->trap_uncaught || t->trap_current == NULL || trap->prev == NULL ) return true;
if( !trap->tcheck || !v ) return false;
hl_type *ot = ((hl_type**)trap->tcheck)[1]; // it's an obj with first field is a hl_type
if( !ot || hl_safe_cast(v->t,ot) ) return false;
trap = trap->prev;
}
return false;
}
HL_PRIM void hl_throw( vdynamic *v ) {
hl_thread_info *t = hl_get_thread();
hl_trap_ctx *trap = t->trap_current;
bool call_handler = false;
if( !(t->flags & HL_EXC_RETHROW) )
t->exc_stack_count = capture_stack_func(t->exc_stack_trace, HL_EXC_MAX_STACK);
t->exc_value = v;
t->trap_current = trap->prev;
call_handler = trap == t->trap_uncaught || t->trap_current == NULL;
if( (t->flags&HL_EXC_CATCH_ALL) || break_on_trap(t,trap,v) ) {
if( trap == t->trap_uncaught ) t->trap_uncaught = NULL;
t->flags |= HL_EXC_IS_THROW;
hl_debug_break();
t->flags &= ~HL_EXC_IS_THROW;
}
t->flags &= ~HL_EXC_RETHROW;
if( t->exc_handler && call_handler ) hl_dyn_call_safe(t->exc_handler,&v,1,&call_handler);
if( throw_jump == NULL ) throw_jump = longjmp;
throw_jump(trap->buf,1);
HL_UNREACHABLE;
}
HL_PRIM void hl_null_access() {
hl_error("Null access");
HL_UNREACHABLE;
}
HL_PRIM void hl_throw_buffer( hl_buffer *b ) {
vdynamic *d = hl_alloc_dynamic(&hlt_bytes);
d->v.ptr = hl_buffer_content(b,NULL);
hl_throw(d);
}
HL_PRIM void hl_dump_stack() {
void *stack[0x1000];
int count = capture_stack_func(stack, 0x1000);
int i;
for(i=0;i<count;i++) {
void *addr = stack[i];
uchar sym[512];
int size = 512;
uchar *str = resolve_symbol_func(addr, sym, &size);
if( str == NULL ) {
int iaddr = (int)(int_val)addr;
usprintf(sym,512,USTR("@0x%X"),iaddr);
str = sym;
}
uprintf(USTR("%s\n"),str);
}
fflush(stdout);
}
HL_PRIM varray *hl_exception_stack() {
hl_thread_info *t = hl_get_thread();
varray *a = hl_alloc_array(&hlt_bytes, t->exc_stack_count);
int i, pos = 0;
for(i=0;i<t->exc_stack_count;i++) {
void *addr = t->exc_stack_trace[i];
uchar sym[512];
int size = 512;
uchar *str = resolve_symbol_func(addr, sym, &size);
if( str == NULL ) continue;
hl_aptr(a,vbyte*)[pos++] = hl_copy_bytes((vbyte*)str,sizeof(uchar)*(size+1));
}
a->size = pos;
return a;
}
HL_PRIM int hl_exception_stack_raw( varray *arr ) {
hl_thread_info *t = hl_get_thread();
if( arr ) memcpy(hl_aptr(arr,void*), t->exc_stack_trace, t->exc_stack_count*sizeof(void*));
return t->exc_stack_count;
}
HL_PRIM int hl_call_stack_raw( varray *arr ) {
if( !arr )
return capture_stack_func(NULL,0);
return capture_stack_func(hl_aptr(arr,void*), arr->size);
}
HL_PRIM void hl_rethrow( vdynamic *v ) {
hl_get_thread()->flags |= HL_EXC_RETHROW;
hl_throw(v);
}
HL_PRIM vdynamic *hl_alloc_strbytes( const uchar *fmt, ... ) {
uchar _buf[256];
vdynamic *d;
int len;
uchar *buf = _buf;
int bsize = sizeof(_buf) / sizeof(uchar);
va_list args;
while( true ) {
va_start(args, fmt);
len = uvszprintf(buf,bsize,fmt,args);
va_end(args);
if( (len + 2) << 1 < bsize ) break;
if( buf != _buf ) free(buf);
bsize <<= 1;
buf = (uchar*)malloc(bsize * sizeof(uchar));
}
d = hl_alloc_dynamic(&hlt_bytes);
d->v.ptr = hl_copy_bytes((vbyte*)buf,(len + 1) << 1);
if( buf != _buf ) free(buf);
return d;
}
HL_PRIM void hl_fatal_fmt( const char *file, int line, const char *fmt, ...) {
char buf[256];
va_list args;
va_start(args, fmt);
vsprintf(buf,fmt, args);
va_end(args);
hl_fatal_error(buf,file,line);
}
#ifdef HL_VCC
# pragma optimize( "", off )
#endif
HL_PRIM HL_NO_OPT void hl_breakpoint() {
hl_debug_break();
}
#ifdef HL_VCC
# pragma optimize( "", on )
#endif
#ifdef HL_LINUX__
#include <signal.h>
static int debugger_present = -1;
static void _sigtrap_handler(int signum) {
debugger_present = 0;
signal(SIGTRAP,SIG_DFL);
}
#endif
#ifdef HL_MAC
extern bool kinc_debugger_attached(void);
#endif
HL_PRIM bool hl_detect_debugger() {
# if defined(HL_WIN)
return (bool)IsDebuggerPresent();
# elif defined(HL_LINUX__)
if( debugger_present == -1 ) {
debugger_present = 1;
signal(SIGTRAP,_sigtrap_handler);
raise(SIGTRAP);
}
return (bool)debugger_present;
# elif defined(HL_MAC)
return kinc_debugger_attached();
# else
return false;
# endif
}
#ifdef HL_VCC
# pragma optimize( "", off )
#endif
HL_PRIM HL_NO_OPT void hl_assert() {
hl_debug_break();
hl_error("assert");
}
#ifdef HL_VCC
# pragma optimize( "", on )
#endif
#define _SYMBOL _ABSTRACT(hl_symbol)
DEFINE_PRIM(_ARR,exception_stack,_NO_ARG);
DEFINE_PRIM(_I32,exception_stack_raw,_ARR);
DEFINE_PRIM(_I32,call_stack_raw,_ARR);
DEFINE_PRIM(_VOID,set_error_handler,_FUN(_VOID,_DYN));
DEFINE_PRIM(_VOID,breakpoint,_NO_ARG);
DEFINE_PRIM(_BYTES,resolve_symbol, _SYMBOL _BYTES _REF(_I32));

View File

@ -0,0 +1,276 @@
/*
* Copyright (C)2005-2016 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#if defined(__GNUC__) && !defined(__APPLE__)
# define _FILE_OFFSET_BITS 64
#endif
#include <hl.h>
#include <stdio.h>
#ifdef HL_CONSOLE
# include <posix/posix.h>
#endif
#ifdef HL_WIN
#ifdef HL_WIN_DESKTOP
# include <windows.h>
# include <io.h>
# include <fcntl.h>
#else
# include<xdk.h>
#endif
# define fopen(name,mode) _wfopen(name,mode)
# define HL_UFOPEN
#else
#include <errno.h>
#endif
#ifdef HL_WIN_DESKTOP
# define SET_IS_STD(f,b) (f)->is_std = b
#else
# define SET_IS_STD(f,b)
#endif
typedef struct _hl_fdesc hl_fdesc;
struct _hl_fdesc {
void (*finalize)( hl_fdesc * );
FILE *f;
# ifdef HL_WIN_DESKTOP
bool is_std;
# endif
};
static void fdesc_finalize( hl_fdesc *f ) {
if( f->f ) fclose(f->f);
}
HL_PRIM hl_fdesc *hl_file_open( vbyte *name, int mode, bool binary ) {
# ifdef HL_UFOPEN
static const uchar *MODES[] = { USTR("r"), USTR("w"), USTR("a"), USTR("r+"), USTR("rb"), USTR("wb"), USTR("ab"), USTR("rb+") };
FILE *f = fopen((uchar*)name,MODES[mode|(binary?4:0)]);
# else
static const char *MODES[] = { "r", "w", "a", "r+", "rb", "wb", "ab", "rb+" };
FILE *f = fopen((char*)name,MODES[mode|(binary?4:0)]);
# endif
hl_fdesc *fd;
if( f == NULL ) return NULL;
fd = (hl_fdesc*)hl_gc_alloc_finalizer(sizeof(hl_fdesc));
fd->finalize = fdesc_finalize;
fd->f = f;
SET_IS_STD(fd, false);
return fd;
}
HL_PRIM bool hl_file_is_locked( vbyte *name ) {
# ifdef HL_WIN
HANDLE h = CreateFile((uchar*)name,GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if( h == INVALID_HANDLE_VALUE ) return true;
CloseHandle(h);
return false;
# else
return false;
# endif
}
HL_PRIM void hl_file_close( hl_fdesc *f ) {
if( !f ) return;
if( f->f ) fclose(f->f);
f->f = NULL;
f->finalize = NULL;
}
HL_PRIM int hl_file_write( hl_fdesc *f, vbyte *buf, int pos, int len ) {
int ret;
if( !f ) return -1;
hl_blocking(true);
# ifdef HL_WIN_DESKTOP
if( f->is_std ) {
// except utf8, handle the case where it's not \0 terminated
uchar *out = (uchar*)malloc((len+1)*2);
vbyte prev = buf[pos+len-1];
if( buf[pos+len] ) buf[pos+len-1] = 0;
int olen = hl_from_utf8(out,len,(const char*)(buf+pos));
buf[pos+len-1] = prev;
_setmode(fileno(f->f),_O_U8TEXT);
ret = _write(fileno(f->f),out,olen<<1);
_setmode(fileno(f->f),_O_TEXT);
if( ret > 0 ) ret = len;
free(out);
} else
# endif
ret = (int)fwrite(buf+pos,1,len,f->f);
hl_blocking(false);
return ret;
}
HL_PRIM int hl_file_read( hl_fdesc *f, vbyte *buf, int pos, int len ) {
int ret;
if( !f ) return -1;
hl_blocking(true);
ret = (int)fread((char*)buf+pos,1,len,f->f);
hl_blocking(false);
return ret;
}
HL_PRIM bool hl_file_write_char( hl_fdesc *f, int c ) {
size_t ret;
unsigned char cc = (unsigned char)c;
if( !f ) return false;
hl_blocking(true);
# ifdef HL_WIN_DESKTOP
if( f->is_std ) {
uchar wcc = cc;
_setmode(fileno(f->f),_O_U8TEXT);
ret = _write(fileno(f->f),&wcc,2);
_setmode(fileno(f->f),_O_TEXT);
if( ret > 0 ) ret = 1;
} else
# endif
ret = fwrite(&cc,1,1,f->f);
hl_blocking(false);
return ret == 1;
}
HL_PRIM int hl_file_read_char( hl_fdesc *f ) {
unsigned char cc;
hl_blocking(true);
if( !f || fread(&cc,1,1,f->f) != 1 ) {
hl_blocking(false);
return -2;
}
hl_blocking(false);
return cc;
}
HL_PRIM bool hl_file_seek( hl_fdesc *f, int pos, int kind ) {
if( !f ) return false;
return fseek(f->f,pos,kind) == 0;
}
HL_PRIM int hl_file_tell( hl_fdesc *f ) {
if( !f ) return -1;
return (int)ftell(f->f);
}
HL_PRIM bool hl_file_seek2( hl_fdesc *f, double pos, int kind ) {
if( !f ) return false;
# ifdef HL_WIN
return _fseeki64(f->f,(__int64)pos,kind) == 0;
# else
return fseek(f->f,(int64)pos,kind) == 0;
# endif
}
HL_PRIM double hl_file_tell2( hl_fdesc *f ) {
if( !f ) return -1;
# ifdef HL_WIN
return (double)_ftelli64(f->f);
# else
return (double)ftell(f->f);
# endif
}
HL_PRIM bool hl_file_eof( hl_fdesc *f ) {
if( !f ) return true;
return (bool)feof(f->f);
}
HL_PRIM int hl_file_error_code() {
return errno;
}
HL_PRIM bool hl_file_flush( hl_fdesc *f ) {
int ret;
if( !f ) return false;
hl_blocking(true);
ret = fflush( f->f );
hl_blocking(false);
return ret == 0;
}
#define MAKE_STDIO(k) \
HL_PRIM hl_fdesc *hl_file_##k() { \
hl_fdesc *f; \
f = (hl_fdesc*)hl_gc_alloc_noptr(sizeof(hl_fdesc)); \
f->f = k; \
f->finalize = NULL; \
SET_IS_STD(f, true); \
return f; \
}
MAKE_STDIO(stdin);
MAKE_STDIO(stdout);
MAKE_STDIO(stderr);
HL_PRIM vbyte *hl_file_contents( vbyte *name, int *size ) {
int len;
int p = 0;
vbyte *content;
# ifdef HL_UFOPEN
FILE *f = fopen((uchar*)name,USTR("rb"));
# else
FILE *f = fopen((char*)name,"rb");
# endif
if( f == NULL )
return NULL;
hl_blocking(true);
fseek(f,0,SEEK_END);
len = ftell(f);
if( size ) *size = len;
fseek(f,0,SEEK_SET);
hl_blocking(false);
content = (vbyte*)hl_gc_alloc_noptr(size ? len : len+1);
hl_blocking(true);
if( !size ) content[len] = 0; else if( !len ) content = (vbyte*)""; // final 0 for UTF8
while( len > 0 ) {
int d = (int)fread((char*)content + p,1,len,f);
if( d <= 0 ) {
hl_blocking(false);
fclose(f);
return NULL;
}
p += d;
len -= d;
}
fclose(f);
hl_blocking(false);
return content;
}
#define _FILE _ABSTRACT(hl_fdesc)
DEFINE_PRIM(_FILE, file_open, _BYTES _I32 _BOOL);
DEFINE_PRIM(_VOID, file_close, _FILE);
DEFINE_PRIM(_I32, file_write, _FILE _BYTES _I32 _I32);
DEFINE_PRIM(_I32, file_read, _FILE _BYTES _I32 _I32);
DEFINE_PRIM(_BOOL, file_write_char, _FILE _I32);
DEFINE_PRIM(_I32, file_read_char, _FILE);
DEFINE_PRIM(_BOOL, file_seek, _FILE _I32 _I32);
DEFINE_PRIM(_I32, file_tell, _FILE);
DEFINE_PRIM(_BOOL, file_seek2, _FILE _F64 _I32);
DEFINE_PRIM(_F64, file_tell2, _FILE);
DEFINE_PRIM(_BOOL, file_eof, _FILE);
DEFINE_PRIM(_BOOL, file_flush, _FILE);
DEFINE_PRIM(_FILE, file_stdin, _NO_ARG);
DEFINE_PRIM(_FILE, file_stdout, _NO_ARG);
DEFINE_PRIM(_FILE, file_stderr, _NO_ARG);
DEFINE_PRIM(_BYTES, file_contents, _BYTES _REF(_I32));
DEFINE_PRIM(_BOOL, file_is_locked, _BYTES);
DEFINE_PRIM(_I32, file_error_code, _NO_ARG);

View File

@ -0,0 +1,479 @@
/*
* Copyright (C)2005-2016 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <hl.h>
HL_PRIM int hl_closure_stack_capture = 0;
static void fun_var_args() {
hl_error("Variable fun args was not cast to typed function");
}
HL_PRIM vclosure *hl_alloc_closure_void( hl_type *t, void *fvalue ) {
vclosure *c = (vclosure*)hl_gc_alloc_noptr(sizeof(vclosure));
c->t = t;
c->fun = fvalue;
c->hasValue = 0;
c->value = NULL;
return c;
}
static hl_type *hl_get_closure_type( hl_type *t ) {
hl_type_fun *ft = t->fun;
if( ft->closure_type.kind != HFUN ) {
if( ft->nargs == 0 ) hl_fatal("assert");
ft->closure_type.kind = HFUN;
ft->closure_type.p = &ft->closure;
ft->closure.nargs = ft->nargs - 1;
ft->closure.args = ft->closure.nargs ? ft->args + 1 : NULL;
ft->closure.ret = ft->ret;
ft->closure.parent = t;
}
return (hl_type*)&ft->closure_type;
}
int hl_internal_capture_stack( void **stack, int size );
HL_PRIM vclosure *hl_alloc_closure_ptr( hl_type *fullt, void *fvalue, void *v ) {
hl_type *t = hl_get_closure_type(fullt);
vclosure *c = (vclosure*)hl_gc_alloc(t, sizeof(vclosure) + sizeof(void*) * hl_closure_stack_capture);
c->t = t;
c->fun = fvalue;
c->hasValue = 1;
# ifdef HL_64
int stack = 0;
if( hl_closure_stack_capture ) stack = hl_internal_capture_stack((void**)(c + 1), hl_closure_stack_capture);
c->stackCount = stack;
# endif
c->value = v;
return c;
}
HL_PRIM vdynamic *hl_no_closure( vdynamic *c ) {
vclosure *cl = (vclosure*)c;
if( !cl->hasValue ) return c;
if( cl->hasValue == 2 )
return hl_no_closure((vdynamic*)((vclosure_wrapper*)c)->wrappedFun);
return (vdynamic*)hl_alloc_closure_void(cl->t->fun->parent,cl->fun);
}
HL_PRIM vdynamic *hl_make_closure( vdynamic *c, vdynamic *v ) {
vclosure *cl = (vclosure*)c;
hl_type *t = cl->hasValue ? cl->t->fun->parent : cl->t;
if( cl->hasValue == 2 )
return hl_make_closure((vdynamic*)((vclosure_wrapper*)c)->wrappedFun, v);
if( t->fun->nargs == 0 || !v || !hl_safe_cast(v->t,t->fun->args[0]) )
return NULL;
return (vdynamic*)hl_alloc_closure_ptr( t, cl->fun, v );
}
HL_PRIM vdynamic* hl_get_closure_value( vdynamic *c ) {
vclosure *cl = (vclosure*)c;
if( !cl->hasValue )
return NULL;
if( cl->hasValue == 2 )
return hl_get_closure_value((vdynamic*)((vclosure_wrapper*)c)->wrappedFun);
if( cl->fun == fun_var_args )
return NULL;
return hl_make_dyn(&cl->value, cl->t->fun->parent->fun->args[0]);
}
HL_PRIM bool hl_fun_compare( vdynamic *a, vdynamic *b ) {
vclosure *ca, *cb;
if( a == b )
return true;
if( !a || !b )
return false;
if( a->t->kind != b->t->kind || a->t->kind != HFUN )
return false;
ca = (vclosure*)a;
cb = (vclosure*)b;
if( ca->fun != cb->fun )
return false;
if( ca->hasValue && ca->value != cb->value )
return false;
return true;
}
// ------------ DYNAMIC CALLS
typedef void *(*fptr_static_call)(void *fun, hl_type *t, void **args, vdynamic *out);
typedef void *(*fptr_get_wrapper)(hl_type *t);
static fptr_static_call hlc_static_call = NULL;
static fptr_get_wrapper hlc_get_wrapper = NULL;
static int hlc_call_flags = 0;
HL_PRIM void hl_setup_callbacks2( void *c, void *w, int flags ) {
hlc_static_call = (fptr_static_call)c;
hlc_get_wrapper = (fptr_get_wrapper)w;
hlc_call_flags = flags;
}
HL_PRIM void hl_setup_callbacks( void *c, void *w ) {
hl_setup_callbacks2(c,w,0);
}
#define HL_MAX_ARGS 9
HL_PRIM vdynamic* hl_call_method( vdynamic *c, varray *args ) {
vclosure *cl = (vclosure*)c;
vdynamic **vargs = hl_aptr(args,vdynamic*);
void *pargs[HL_MAX_ARGS];
void *ret;
union { double d; int i; float f; int64 i64; } tmp[HL_MAX_ARGS];
hl_type *tret;
vdynamic *dret;
vdynamic out;
int i;
if( args->size > HL_MAX_ARGS )
hl_error("Too many arguments");
if( cl->hasValue ) {
if( cl->fun == fun_var_args ) {
cl = (vclosure*)cl->value;
return cl->hasValue ? ((vdynamic* (*)(vdynamic*, varray*))cl->fun)(cl->value, args) : ((vdynamic* (*)(varray*))cl->fun)(args);
}
hl_error("Can't call closure with value");
}
if( args->size < cl->t->fun->nargs )
hl_error("Missing arguments : %d expected but %d passed",cl->t->fun->nargs, args->size);
for(i=0;i<cl->t->fun->nargs;i++) {
vdynamic *v = vargs[i];
hl_type *t = cl->t->fun->args[i];
void *p;
if( v == NULL ) {
if( hl_is_ptr(t) )
p = NULL;
else {
tmp[i].d = 0;
p = &tmp[i].d;
}
} else switch( t->kind ) {
case HBOOL:
case HUI8:
case HUI16:
case HI32:
tmp[i].i = hl_dyn_casti(vargs + i, &hlt_dyn,t);
p = &tmp[i].i;
break;
case HI64:
tmp[i].i64 = hl_dyn_casti64(vargs + i, &hlt_dyn);
p = &tmp[i].i64;
break;
case HF32:
tmp[i].f = hl_dyn_castf(vargs + i, &hlt_dyn);
p = &tmp[i].f;
break;
case HF64:
tmp[i].d = hl_dyn_castd(vargs + i, &hlt_dyn);
p = &tmp[i].d;
break;
default:
p = hl_dyn_castp(vargs + i,&hlt_dyn,t);
break;
}
pargs[i] = p;
}
ret = hlc_static_call(hlc_call_flags & 1 ? &cl->fun : cl->fun,cl->t,pargs,&out);
tret = cl->t->fun->ret;
if( !hl_is_ptr(tret) ) {
vdynamic *r;
switch( tret->kind ) {
case HVOID:
return NULL;
case HBOOL:
return hl_alloc_dynbool(out.v.b);
default:
r = hl_alloc_dynamic(tret);
r->t = tret;
r->v.d = out.v.d; // copy
return r;
}
}
if( ret == NULL || hl_is_dynamic(tret) )
return (vdynamic*)ret;
dret = hl_alloc_dynamic(tret);
dret->v.ptr = ret;
return dret;
}
HL_PRIM vdynamic *hl_dyn_call( vclosure *c, vdynamic **args, int nargs ) {
struct {
varray a;
vdynamic *args[HL_MAX_ARGS+1];
} tmp;
vclosure ctmp;
int i = 0;
if( nargs > HL_MAX_ARGS ) hl_error("Too many arguments");
tmp.a.t = &hlt_array;
tmp.a.at = &hlt_dyn;
tmp.a.size = nargs;
if( c->hasValue && c->t->fun->nargs >= 0 ) {
ctmp.t = c->t->fun->parent;
ctmp.hasValue = 0;
ctmp.fun = c->fun;
tmp.args[0] = hl_make_dyn(&c->value,ctmp.t->fun->args[0]);
tmp.a.size++;
for(i=0;i<nargs;i++)
tmp.args[i+1] = args[i];
c = &ctmp;
} else {
for(i=0;i<nargs;i++)
tmp.args[i] = args[i];
}
return hl_call_method((vdynamic*)c,&tmp.a);
}
HL_PRIM void *hl_wrapper_call( void *_c, void **args, vdynamic *ret ) {
vclosure_wrapper *c = (vclosure_wrapper*)_c;
hl_type_fun *tfun = c->cl.t->fun;
union { double d; int i; float f; int64 i64; } tmp[HL_MAX_ARGS];
void *vargs[HL_MAX_ARGS+1];
vdynamic out;
vclosure *w = c->wrappedFun;
int i;
int p = 0;
void *pret, *aret;
if( ret == NULL )
ret = &out;
if( w->fun == fun_var_args ) {
varray *a;
w = (vclosure*)w->value; // the real callback
a = hl_alloc_array(&hlt_dyn,tfun->nargs);
for(i=0;i<tfun->nargs;i++) {
hl_type *t = tfun->args[i];
void *v = hl_is_ptr(t) ? args + i : args[i];
hl_aptr(a,void*)[i] = hl_make_dyn(v,t);
}
if( w->hasValue )
vargs[p++] = (vdynamic*)w->value;
vargs[p++] = (vdynamic*)a;
} else {
if( w->hasValue )
vargs[p++] = (vdynamic*)w->value;
for(i=0;i<w->t->fun->nargs;i++) {
hl_type *t = tfun->args[i];
hl_type *to = w->t->fun->args[i];
void *v = hl_is_ptr(t) ? args + i : args[i];
switch( to->kind ) {
case HUI8:
case HUI16:
case HI32:
case HBOOL:
tmp[i].i = hl_dyn_casti(v,t,to);
v = &tmp[i].i;
break;
case HI64:
tmp[i].i64 = hl_dyn_casti64(v,t);
v = &tmp[i].i64;
break;
case HF32:
tmp[i].f = hl_dyn_castf(v,t);
v = &tmp[i].f;
break;
case HF64:
tmp[i].d = hl_dyn_castd(v,t);
v = &tmp[i].d;
break;
default:
v = hl_dyn_castp(v,t,to);
break;
}
vargs[p++] = v;
}
}
pret = hlc_static_call(hlc_call_flags & 1 ? &w->fun : w->fun,w->hasValue ? w->t->fun->parent : w->t,vargs,ret);
aret = hl_is_ptr(w->t->fun->ret) ? &pret : pret;
if( aret == NULL ) aret = &pret;
switch( tfun->ret->kind ) {
case HVOID:
return NULL;
case HUI8:
case HUI16:
case HI32:
case HBOOL:
ret->v.i = hl_dyn_casti(aret,w->t->fun->ret,tfun->ret);
break;
case HI64:
ret->v.i64 = hl_dyn_casti64(aret,w->t->fun->ret);
break;
case HF32:
ret->v.f = hl_dyn_castf(aret,w->t->fun->ret);
break;
case HF64:
ret->v.d = hl_dyn_castd(aret,w->t->fun->ret);
break;
default:
pret = hl_dyn_castp(aret,w->t->fun->ret,tfun->ret);
break;
}
return pret;
}
HL_PRIM void *hl_dyn_call_obj( vdynamic *o, hl_type *ft, int hfield, void **args, vdynamic *ret ) {
switch( o->t->kind ) {
case HDYNOBJ:
{
vdynobj *d = (vdynobj*)o;
hl_field_lookup *l = hl_lookup_find(d->lookup,d->nfields, hfield);
if( l != NULL && l->t->kind != HFUN )
hl_error("Field %s is of type %s and cannot be called", hl_field_name(hfield), hl_type_str(l->t));
vclosure *tmp = (vclosure*)d->values[l->field_index];
if( tmp ) {
vclosure_wrapper w;
w.cl.t = ft;
w.cl.fun = hlc_get_wrapper(ft);
w.cl.hasValue = 2;
# ifdef HL_64
w.cl.stackCount = 0;
# endif
w.cl.value = &w;
w.wrappedFun = tmp;
return hl_wrapper_call(&w,args,ret);
}
hl_error("%s has no method %s",hl_type_str(o->t),hl_field_name(hfield));
}
break;
case HOBJ:
{
hl_runtime_obj *rt = o->t->obj->rt;
while( true ) {
hl_field_lookup *l = hl_lookup_find(rt->lookup,rt->nlookup, hfield);
if( l != NULL && l->t->kind != HFUN )
hl_error("Field %s is of type %s and cannot be called", hl_field_name(hfield), hl_type_str(l->t));
if( l != NULL ) {
vclosure_wrapper w;
vclosure tmp;
w.cl.t = ft;
w.cl.fun = hlc_get_wrapper(ft);
w.cl.hasValue = 2;
# ifdef HL_64
w.cl.stackCount = 0;
# endif
w.cl.value = &w;
if( l->field_index < 0 ) {
tmp.t = hl_get_closure_type(l->t);
tmp.fun = o->t->obj->rt->methods[-l->field_index-1];
tmp.hasValue = 1;
# ifdef HL_64
tmp.stackCount = 0;
# endif
tmp.value = o;
w.wrappedFun = &tmp;
} else {
vclosure *tmp = *(vclosure**)((char*)o + l->field_index);
if( !tmp ) break;
w.wrappedFun = tmp;
}
return hl_wrapper_call(&w,args,ret);
}
rt = rt->parent;
if( rt == NULL ) break;
}
hl_error("%s has no method %s",o->t->obj->name,hl_field_name(hfield));
}
break;
default:
hl_error("Invalid field access");
break;
}
return NULL;
}
HL_PRIM vclosure *hl_make_fun_wrapper( vclosure *v, hl_type *to ) {
vclosure_wrapper *c;
void *wrap = hlc_get_wrapper(to);
if( wrap == NULL ) return NULL;
if( v->fun != fun_var_args && v->t->fun->nargs != to->fun->nargs )
return NULL;
c = (vclosure_wrapper*)hl_gc_alloc(to, sizeof(vclosure_wrapper));
c->cl.t = to;
c->cl.fun = wrap;
c->cl.hasValue = 2;
# ifdef HL_64
c->cl.stackCount = 0;
# endif
c->cl.value = c;
c->wrappedFun = v;
return (vclosure*)c;
}
static hl_type hlt_var_args = { HFUN };
static hl_type_fun hlt_var_fun = { NULL, &hlt_void, -1, &hlt_var_args, { HFUN, NULL }, { NULL, &hlt_void, -1, &hlt_var_args} };
HL_PRIM vdynamic *hl_make_var_args( vclosure *c ) {
hlt_var_args.fun = &hlt_var_fun;
hlt_var_fun.closure_type.p = &hlt_var_fun;
return (vdynamic*)hl_alloc_closure_ptr(&hlt_var_args,fun_var_args,c);
}
HL_PRIM void hl_prim_not_loaded() {
hl_error("Primitive or library is missing");
}
HL_PRIM bool hl_is_prim_loaded( vdynamic *f ) {
return f && f->t->kind == HFUN && ((vclosure*)f)->fun != hl_prim_not_loaded;
}
DEFINE_PRIM(_DYN, no_closure, _DYN);
DEFINE_PRIM(_DYN, make_closure, _DYN _DYN);
DEFINE_PRIM(_DYN, get_closure_value, _DYN);
DEFINE_PRIM(_BOOL, fun_compare, _DYN _DYN);
DEFINE_PRIM(_DYN, make_var_args, _FUN(_DYN,_ARR));
DEFINE_PRIM(_DYN, call_method, _DYN _ARR);
DEFINE_PRIM(_BOOL, is_prim_loaded, _DYN);
#if defined(HL_VCC) && !defined(HL_XBO)
static LONG CALLBACK global_handler( PEXCEPTION_POINTERS inf ) {
switch( inf->ExceptionRecord->ExceptionCode ) {
case EXCEPTION_ACCESS_VIOLATION: hl_error("Access violation");
case EXCEPTION_STACK_OVERFLOW: hl_error("Stack overflow");
default: break;
}
return EXCEPTION_CONTINUE_SEARCH;
}
#endif
HL_PRIM vdynamic *hl_dyn_call_safe( vclosure *c, vdynamic **args, int nargs, bool *isException ) {
hl_trap_ctx trap;
vdynamic *ret, *exc;
*isException = false;
hl_trap(trap, exc, on_exception);
# if defined(HL_VCC) && !defined(HL_XBO)
ULONG size = 32<<10;
SetThreadStackGuarantee(&size);
static bool first = true;
if( first && !hl_detect_debugger() ) {
first = false;
AddVectoredExceptionHandler(1,global_handler);
}
# endif
ret = hl_dyn_call(c,args,nargs);
hl_endtrap(trap);
return ret;
on_exception:
hl_endtrap(trap);
*isException = true;
return exc;
}

View File

@ -0,0 +1,291 @@
/*
* Copyright (C)2005-2016 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <hl.h>
#ifdef HL_VCC
# pragma warning(disable:4034) // sizeof(void) == 0
#endif
#define H_SIZE_INIT 3
// successive primes that double every time
static int H_PRIMES[] = {
7,17,37,79,163,331,673,1361,2729,5471,10949,21911,43853,87613,175229,350459,700919,1401857,2803727,5607457,11214943,22429903,44859823,89719661,179424673,373587883,776531401,1611623773
};
// ----- FREE LIST ---------------------------------
typedef struct {
int pos;
int count;
} hl_free_bucket;
typedef struct {
hl_free_bucket *buckets;
int head;
int nbuckets;
} hl_free_list;
static void hl_freelist_resize( hl_free_list *f, int newsize ) {
hl_free_bucket *buckets = (hl_free_bucket*)hl_gc_alloc_noptr(sizeof(hl_free_bucket)*newsize);
memcpy(buckets,f->buckets,f->head * sizeof(hl_free_bucket));
f->buckets = buckets;
f->nbuckets = newsize;
}
static void hl_freelist_init( hl_free_list *f ) {
memset(f,0,sizeof(hl_free_list));
}
static void hl_freelist_add_range( hl_free_list *f, int pos, int count ) {
hl_free_bucket *b = f->buckets;
hl_free_bucket *prev = NULL;
if( !b ) {
// special handling for countinuous space
if( f->nbuckets == 0 ) {
f->head = pos;
f->nbuckets = count;
return;
} else if( f->head + f->nbuckets == pos ) {
f->nbuckets += count;
return;
} else if( pos + count == f->head ) {
f->head -= count;
f->nbuckets += count;
return;
} else {
int cur_pos = f->head, cur_count = f->nbuckets;
f->head = 0;
f->nbuckets = 0;
hl_freelist_resize(f,2);
if( cur_count ) hl_freelist_add_range(f,cur_pos,cur_count);
b = f->buckets;
}
}
while( b < f->buckets + f->head ) {
if( b->pos > pos ) break;
prev = b;
b++;
}
if( b < f->buckets + f->head && b->pos == pos + count ) {
b->pos -= count;
b->count += count;
// merge
if( prev && prev->pos + prev->count == b->pos ) {
prev->count += b->count;
memmove(b,b+1,((f->buckets + f->head) - (b+1)) * sizeof(hl_free_bucket));
f->head--;
}
return;
}
if( prev && prev->pos + prev->count == pos ) {
prev->count += count;
return;
}
// insert
if( f->head == f->nbuckets ) {
int pos = (int)(b - f->buckets);
hl_freelist_resize(f,((f->nbuckets * 3) + 1) >> 1);
b = f->buckets + pos;
}
memmove(b+1,b,((f->buckets + f->head) - b) * sizeof(hl_free_bucket));
b->pos = pos;
b->count = count;
f->head++;
}
static void hl_freelist_add( hl_free_list *f, int pos ) {
hl_freelist_add_range(f,pos,1);
}
static int hl_freelist_get( hl_free_list *f ) {
hl_free_bucket *b;
int p;
if( !f->buckets ) {
if( f->nbuckets == 0 ) return -1;
f->nbuckets--;
return f->head++;
}
if( f->head == 0 )
return -1;
b = f->buckets + f->head - 1;
b->count--;
p = b->pos + b->count;
if( b->count == 0 ) {
f->head--;
if( f->head < (f->nbuckets>>1) )
hl_freelist_resize(f,f->nbuckets>>1);
}
return p;
}
// ----- INT MAP ---------------------------------
typedef struct {
int key;
} hl_hi_entry;
typedef struct {
vdynamic *value;
} hl_hi_value;
#define hlt_key hlt_i32
#define hl_hifilter(key) key
#define hl_hihash(h) ((unsigned)(h))
#define _MKEY_TYPE int
#define _MNAME(n) hl_hi##n
#define _MMATCH(c) m->entries[c].key == key
#define _MKEY(m,c) m->entries[c].key
#define _MSET(c) m->entries[c].key = key
#define _MERASE(c)
#include "maps.h"
// ----- INT64 MAP ---------------------------------
typedef struct {
int64 key;
} hl_hi64_entry;
typedef struct {
vdynamic *value;
} hl_hi64_value;
#define hlt_key hlt_i64
#define hl_hi64filter(key) key
#define hl_hi64hash(h) (((unsigned int)h) ^ ((unsigned int)(h>>32)))
#define _MKEY_TYPE int64
#define _MNAME(n) hl_hi64##n
#define _MMATCH(c) m->entries[c].key == key
#define _MKEY(m,c) m->entries[c].key
#define _MSET(c) m->entries[c].key = key
#define _MERASE(c)
#include "maps.h"
// ----- BYTES MAP ---------------------------------
typedef struct {
unsigned int hash;
} hl_hb_entry;
typedef struct {
uchar *key;
vdynamic *value;
} hl_hb_value;
#define hlt_key hlt_bytes
#define hl_hbfilter(key) key
#define hl_hbhash(key) ((unsigned)hl_hash_gen(key,false))
#define _MKEY_TYPE uchar*
#define _MNAME(n) hl_hb##n
#define _MMATCH(c) m->entries[c].hash == hash && ucmp(m->values[c].key,key) == 0
#define _MKEY(m,c) m->values[c].key
#define _MSET(c) m->entries[c].hash = hash; m->values[c].key = key
#define _MERASE(c) m->values[c].key = NULL
#include "maps.h"
// ----- OBJECT MAP ---------------------------------
typedef void hl_ho_entry;
typedef struct {
vdynamic *key;
vdynamic *value;
} hl_ho_value;
static vdynamic *hl_hofilter( vdynamic *key ) {
if( key )
switch( key->t->kind ) {
// erase virtual (prevent mismatch once virtualized)
case HVIRTUAL:
key = hl_virtual_make_value((vvirtual*)key);
break;
// store real pointer instead of dynamic wrapper
case HBYTES:
case HTYPE:
case HABSTRACT:
case HREF:
case HENUM:
key = (vdynamic*)key->v.ptr;
break;
default:
break;
}
return key;
}
#define hlt_key hlt_dyn
#define hl_hohash(key) ((unsigned int)(int_val)(key))
#define _MKEY_TYPE vdynamic*
#define _MNAME(n) hl_ho##n
#define _MMATCH(c) m->values[c].key == key
#define _MKEY(m,c) m->values[c].key
#define _MSET(c) m->values[c].key = key
#define _MERASE(c) m->values[c].key = NULL
#include "maps.h"
#define _IMAP _ABSTRACT(hl_int_map)
DEFINE_PRIM( _IMAP, hialloc, _NO_ARG );
DEFINE_PRIM( _VOID, hiset, _IMAP _I32 _DYN );
DEFINE_PRIM( _BOOL, hiexists, _IMAP _I32 );
DEFINE_PRIM( _DYN, higet, _IMAP _I32 );
DEFINE_PRIM( _BOOL, hiremove, _IMAP _I32 );
DEFINE_PRIM( _ARR, hikeys, _IMAP );
DEFINE_PRIM( _ARR, hivalues, _IMAP );
DEFINE_PRIM( _VOID, hiclear, _IMAP );
DEFINE_PRIM( _I32, hisize, _IMAP );
#define _I64MAP _ABSTRACT(hl_int64_map)
DEFINE_PRIM( _I64MAP, hi64alloc, _NO_ARG );
DEFINE_PRIM( _VOID, hi64set, _I64MAP _I64 _DYN );
DEFINE_PRIM( _BOOL, hi64exists, _I64MAP _I64 );
DEFINE_PRIM( _DYN, hi64get, _I64MAP _I64 );
DEFINE_PRIM( _BOOL, hi64remove, _I64MAP _I64 );
DEFINE_PRIM( _ARR, hi64keys, _I64MAP );
DEFINE_PRIM( _ARR, hi64values, _I64MAP );
DEFINE_PRIM( _VOID, hi64clear, _I64MAP );
DEFINE_PRIM( _I32, hi64size, _I64MAP );
#define _BMAP _ABSTRACT(hl_bytes_map)
DEFINE_PRIM( _BMAP, hballoc, _NO_ARG );
DEFINE_PRIM( _VOID, hbset, _BMAP _BYTES _DYN );
DEFINE_PRIM( _BOOL, hbexists, _BMAP _BYTES );
DEFINE_PRIM( _DYN, hbget, _BMAP _BYTES );
DEFINE_PRIM( _BOOL, hbremove, _BMAP _BYTES );
DEFINE_PRIM( _ARR, hbkeys, _BMAP );
DEFINE_PRIM( _ARR, hbvalues, _BMAP );
DEFINE_PRIM( _VOID, hbclear, _BMAP );
DEFINE_PRIM( _I32, hbsize, _BMAP );
#define _OMAP _ABSTRACT(hl_obj_map)
DEFINE_PRIM( _OMAP, hoalloc, _NO_ARG );
DEFINE_PRIM( _VOID, hoset, _OMAP _DYN _DYN );
DEFINE_PRIM( _BOOL, hoexists, _OMAP _DYN );
DEFINE_PRIM( _DYN, hoget, _OMAP _DYN );
DEFINE_PRIM( _BOOL, horemove, _OMAP _DYN );
DEFINE_PRIM( _ARR, hokeys, _OMAP );
DEFINE_PRIM( _ARR, hovalues, _OMAP );
DEFINE_PRIM( _VOID, hoclear, _OMAP );
DEFINE_PRIM( _I32, hosize, _OMAP );

View File

@ -0,0 +1,224 @@
#undef t_map
#undef t_entry
#undef t_value
#undef t_key
#define t_key _MKEY_TYPE
#define t_map _MNAME(_map)
#define t_entry _MNAME(_entry)
#define t_value _MNAME(_value)
#define _MLIMIT 128
#define _MINDEX(m,ckey) ((m)->maxentries < _MLIMIT ? (int)((signed char*)(m)->cells)[ckey] : ((int*)(m)->cells)[ckey])
#define _MNEXT(m,ckey) ((m)->maxentries < _MLIMIT ? (int)((signed char*)(m)->nexts)[ckey] : ((int*)(m)->nexts)[ckey])
typedef struct {
void *cells;
void *nexts;
t_entry *entries;
t_value *values;
hl_free_list lfree;
int ncells;
int nentries;
int maxentries;
} t_map;
HL_PRIM t_map *_MNAME(alloc)() {
t_map *m = (t_map*)hl_gc_alloc_raw(sizeof(t_map));
memset(m,0,sizeof(t_map));
return m;
}
static vdynamic **_MNAME(find)( t_map *m, t_key key ) {
int c, ckey;
unsigned int hash;
if( !m->values ) return NULL;
hash = _MNAME(hash)(key);
ckey = hash % ((unsigned)m->ncells);
c = _MINDEX(m,ckey);
while( c >= 0 ) {
if( _MMATCH(c) )
return &m->values[c].value;
c = _MNEXT(m,c);
}
return NULL;
}
static void _MNAME(resize)( t_map *m );
static void _MNAME(set_impl)( t_map *m, t_key key, vdynamic *value ) {
int c, ckey = 0;
unsigned int hash = _MNAME(hash)(key);
if( m->values ) {
ckey = hash % ((unsigned)m->ncells);
c = _MINDEX(m,ckey);
while( c >= 0 ) {
if( _MMATCH(c) ) {
m->values[c].value = value;
return;
}
c = _MNEXT(m,c);
}
}
c = hl_freelist_get(&m->lfree);
if( c < 0 ) {
_MNAME(resize)(m);
ckey = hash % ((unsigned)m->ncells);
c = hl_freelist_get(&m->lfree);
}
_MSET(c);
if( m->maxentries < _MLIMIT ) {
((signed char*)m->nexts)[c] = ((signed char*)m->cells)[ckey];
((signed char*)m->cells)[ckey] = (signed char)c;
} else {
((int*)m->nexts)[c] = ((int*)m->cells)[ckey];
((int*)m->cells)[ckey] = c;
}
m->values[c].value = value;
m->nentries++;
}
static void _MNAME(resize)( t_map *m ) {
// save
t_map old = *m;
if( m->nentries != m->maxentries ) hl_error("assert");
// resize
int i = 0;
int nentries = m->maxentries ? ((m->maxentries * 3) + 1) >> 1 : H_SIZE_INIT;
int ncells = nentries >> 2;
while( H_PRIMES[i] < ncells ) i++;
ncells = H_PRIMES[i];
int ksize = nentries < _MLIMIT ? 1 : sizeof(int);
m->entries = (t_entry*)hl_gc_alloc_noptr(nentries * sizeof(t_entry));
m->values = (t_value*)hl_gc_alloc_raw(nentries * sizeof(t_value));
m->maxentries = nentries;
if( old.ncells == ncells && (nentries < _MLIMIT || old.maxentries >= _MLIMIT) ) {
// simply expand
m->nexts = hl_gc_alloc_noptr(nentries * ksize);
memcpy(m->entries,old.entries,old.maxentries * sizeof(t_entry));
memcpy(m->values,old.values,old.maxentries * sizeof(t_value));
memcpy(m->nexts,old.nexts,old.maxentries * ksize);
memset(m->values + old.maxentries, 0, (nentries - old.maxentries) * sizeof(t_value));
hl_freelist_add_range(&m->lfree,old.maxentries,m->maxentries - old.maxentries);
} else {
// expand and remap
m->cells = hl_gc_alloc_noptr((ncells + nentries) * ksize);
m->nexts = (signed char*)m->cells + ncells * ksize;
m->ncells = ncells;
m->nentries = 0;
memset(m->cells,0xFF,ncells * ksize);
memset(m->values, 0, nentries * sizeof(t_value));
hl_freelist_init(&m->lfree);
hl_freelist_add_range(&m->lfree,0,m->maxentries);
for(i=0;i<old.ncells;i++) {
int c = old.maxentries < _MLIMIT ? ((signed char*)old.cells)[i] : ((int*)old.cells)[i];
while( c >= 0 ) {
_MNAME(set_impl)(m,_MKEY((&old),c),old.values[c].value);
c = _MNEXT(&old,c);
}
}
}
}
HL_PRIM void _MNAME(set)( t_map *m, t_key key, vdynamic *value ) {
_MNAME(set_impl)(m,_MNAME(filter)(key),value);
}
HL_PRIM bool _MNAME(exists)( t_map *m, t_key key ) {
return _MNAME(find)(m,_MNAME(filter)(key)) != NULL;
}
HL_PRIM vdynamic* _MNAME(get)( t_map *m, t_key key ) {
vdynamic **v = _MNAME(find)(m,_MNAME(filter)(key));
if( v == NULL ) return NULL;
return *v;
}
HL_PRIM bool _MNAME(remove)( t_map *m, t_key key ) {
int c, prev = -1, ckey;
unsigned int hash;
if( !m->cells ) return false;
key = _MNAME(filter)(key);
hash = _MNAME(hash)(key);
ckey = hash % ((unsigned)m->ncells);
c = _MINDEX(m,ckey);
while( c >= 0 ) {
if( _MMATCH(c) ) {
hl_freelist_add(&m->lfree,c);
m->nentries--;
_MERASE(c);
m->values[c].value = NULL;
if( m->maxentries < _MLIMIT ) {
if( prev >= 0 )
((signed char*)m->nexts)[prev] = ((signed char*)m->nexts)[c];
else
((signed char*)m->cells)[ckey] = ((signed char*)m->nexts)[c];
} else {
if( prev >= 0 )
((int*)m->nexts)[prev] = ((int*)m->nexts)[c];
else
((int*)m->cells)[ckey] = ((int*)m->nexts)[c];
}
return true;
}
prev = c;
c = _MNEXT(m,c);
}
return false;
}
HL_PRIM varray* _MNAME(keys)( t_map *m ) {
varray *a = hl_alloc_array(&hlt_key,m->nentries);
t_key *keys = hl_aptr(a,t_key);
int p = 0;
int i;
for(i=0;i<m->ncells;i++) {
int c = _MINDEX(m,i);
while( c >= 0 ) {
keys[p++] = _MKEY(m,c);
c = _MNEXT(m,c);
}
}
return a;
}
HL_PRIM varray* _MNAME(values)( t_map *m ) {
varray *a = hl_alloc_array(&hlt_dyn,m->nentries);
vdynamic **values = hl_aptr(a,vdynamic*);
int p = 0;
int i;
for(i=0;i<m->ncells;i++) {
int c = _MINDEX(m,i);
while( c >= 0 ) {
values[p++] = m->values[c].value;
c = _MNEXT(m,c);
}
}
return a;
}
HL_PRIM void _MNAME(clear)( t_map *m ) {
memset(m,0,sizeof(t_map));
}
HL_PRIM int _MNAME(size)( t_map *m ) {
return m->nentries;
}
#undef hlt_key
#undef hl_hbhash
#undef _MKEY_TYPE
#undef _MNAME
#undef _MMATCH
#undef _MKEY
#undef _MSET
#undef _MERASE
#undef _MOLD_KEY
#undef _MINDEX
#undef _MNEXT

View File

@ -0,0 +1,155 @@
/*
* Copyright (C)2005-2016 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <hl.h>
#include <math.h>
#ifndef NAN
static const unsigned long __nan[2] = {0xffffffff, 0x7fffffff};
#define NAN (*(const float *) __nan)
#endif
HL_PRIM double hl_nan() {
return NAN;
}
HL_PRIM double hl_math_abs( double a ) {
return fabs(a);
}
HL_PRIM bool hl_math_isnan( double a ) {
#ifdef HL_WIN
return isnan(a);
#else
return a != a; //does not work on some platforms
#endif
}
typedef union {
double d;
struct {
unsigned int l;
unsigned int h;
} i;
} qw;
HL_PRIM bool hl_math_isfinite( double a ) {
qw q;
unsigned int h, l;
if( a != a )
return false;
q.d = a;
h = q.i.h;
l = q.i.l;
l = l | (h & 0xFFFFF);
h = h & 0x7FF00000;
return h != 0x7FF00000 || l;
}
HL_PRIM double hl_math_fceil( double d ) {
return ceil(d);
}
HL_PRIM double hl_math_fround( double d ) {
return floor(d + 0.5);
}
HL_PRIM double hl_math_ffloor( double d ) {
return floor(d);
}
HL_PRIM int hl_math_round( double d ) {
return (int)hl_math_fround(d);
}
HL_PRIM int hl_math_ceil( double d ) {
return (int)hl_math_fceil(d);
}
HL_PRIM int hl_math_floor( double d ) {
return (int)hl_math_ffloor(d);
}
HL_PRIM double hl_math_cos( double a ) {
return cos(a);
}
HL_PRIM double hl_math_sin( double a ) {
return sin(a);
}
HL_PRIM double hl_math_tan( double a ) {
return tan(a);
}
HL_PRIM double hl_math_acos( double a ) {
return acos(a);
}
HL_PRIM double hl_math_asin( double a ) {
return asin(a);
}
HL_PRIM double hl_math_atan( double a ) {
return atan(a);
}
HL_PRIM double hl_math_atan2( double a, double b ) {
return atan2(a,b);
}
HL_PRIM double hl_math_pow( double a, double b ) {
return pow(a,b);
}
HL_PRIM double hl_math_log( double a ) {
return log(a);
}
HL_PRIM double hl_math_exp( double a ) {
return exp(a);
}
HL_PRIM double hl_math_sqrt( double a ) {
return sqrt(a);
}
DEFINE_PRIM(_F64, nan, _NO_ARG);
DEFINE_PRIM(_F64, math_abs, _F64);
DEFINE_PRIM(_BOOL, math_isnan, _F64);
DEFINE_PRIM(_BOOL, math_isfinite, _F64);
DEFINE_PRIM(_F64, math_fceil, _F64);
DEFINE_PRIM(_F64, math_fround, _F64);
DEFINE_PRIM(_F64, math_ffloor, _F64);
DEFINE_PRIM(_I32, math_round, _F64);
DEFINE_PRIM(_I32, math_ceil, _F64);
DEFINE_PRIM(_I32, math_floor, _F64);
DEFINE_PRIM(_F64, math_cos, _F64);
DEFINE_PRIM(_F64, math_sin, _F64);
DEFINE_PRIM(_F64, math_tan, _F64);
DEFINE_PRIM(_F64, math_acos, _F64);
DEFINE_PRIM(_F64, math_asin, _F64);
DEFINE_PRIM(_F64, math_atan, _F64);
DEFINE_PRIM(_F64, math_atan2, _F64 _F64);
DEFINE_PRIM(_F64, math_pow, _F64 _F64);
DEFINE_PRIM(_F64, math_log, _F64);
DEFINE_PRIM(_F64, math_exp, _F64);
DEFINE_PRIM(_F64, math_sqrt, _F64);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,306 @@
/*
* Copyright (C)2005-2016 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <hl.h>
#if defined(HL_CONSOLE)
# include <posix/posix.h>
#elif !defined(HL_WIN)
# include <sys/types.h>
# include <unistd.h>
# include <errno.h>
# include <signal.h>
# if !defined(HL_MAC)
# if defined(HL_BSD) || defined (HL_IOS) || defined (HL_TVOS)
# include <sys/wait.h>
# else
# include <wait.h>
# endif
# endif
#endif
#include <stdio.h>
#include <stdlib.h>
typedef struct _vprocess vprocess;
struct _vprocess {
void (*finalize)( vprocess * );
#ifdef HL_WIN
HANDLE oread;
HANDLE eread;
HANDLE iwrite;
PROCESS_INFORMATION pinf;
#else
int oread;
int eread;
int iwrite;
int pid;
#endif
};
static void process_finalize( vprocess *p ) {
# ifdef HL_WIN
CloseHandle(p->eread);
CloseHandle(p->oread);
CloseHandle(p->iwrite);
CloseHandle(p->pinf.hProcess);
CloseHandle(p->pinf.hThread);
# else
close(p->eread);
close(p->oread);
close(p->iwrite);
# endif
}
HL_PRIM vprocess *hl_process_run( vbyte *cmd, varray *vargs, bool detached ) {
vprocess *p;
# ifdef HL_WIN
SECURITY_ATTRIBUTES sattr;
STARTUPINFO sinf;
HANDLE proc = GetCurrentProcess();
HANDLE oread,eread,iwrite;
if( vargs )
return NULL; // should have been pre-processed by toplevel
p = (vprocess*)hl_gc_alloc_finalizer(sizeof(vprocess));
p->finalize = process_finalize;
// startup process
sattr.nLength = sizeof(sattr);
sattr.bInheritHandle = detached ? FALSE : TRUE;
sattr.lpSecurityDescriptor = NULL;
memset(&sinf,0,sizeof(sinf));
sinf.cb = sizeof(sinf);
sinf.dwFlags = detached ? 0 : STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
sinf.wShowWindow = SW_HIDE;
if( !detached ) {
CreatePipe(&oread,&sinf.hStdOutput,&sattr,0);
CreatePipe(&eread,&sinf.hStdError,&sattr,0);
CreatePipe(&sinf.hStdInput,&iwrite,&sattr,0);
DuplicateHandle(proc,oread,proc,&p->oread,0,FALSE,DUPLICATE_SAME_ACCESS);
DuplicateHandle(proc,eread,proc,&p->eread,0,FALSE,DUPLICATE_SAME_ACCESS);
DuplicateHandle(proc,iwrite,proc,&p->iwrite,0,FALSE,DUPLICATE_SAME_ACCESS);
CloseHandle(oread);
CloseHandle(eread);
CloseHandle(iwrite);
} else {
p->oread = NULL;
p->eread = NULL;
p->iwrite = NULL;
}
if( !CreateProcess(NULL,(uchar*)cmd,NULL,NULL,detached?FALSE:TRUE,detached?CREATE_NEW_CONSOLE:0,NULL,NULL,&sinf,&p->pinf) ) {
// handles will be finalized
return NULL;
}
// close unused pipes
if( !detached ) {
CloseHandle(sinf.hStdOutput);
CloseHandle(sinf.hStdError);
CloseHandle(sinf.hStdInput);
}
# else
char **argv;
if( !vargs ) {
argv = (char**)malloc(sizeof(char*)*4);
argv[0] = "/bin/sh";
argv[1] = "-c";
argv[2] = (char*)cmd;
argv[3] = NULL;
} else {
int i;
if( vargs->at->kind != HBYTES )
return NULL;
argv = (char**)malloc(sizeof(char*)*(vargs->size+2));
argv[0] = (char*)cmd;
for(i=0;i<vargs->size;i++)
argv[i+1] = hl_aptr(vargs,char*)[i];
argv[i+1] = NULL;
}
int input[2], output[2], error[2];
if( pipe(input) || pipe(output) || pipe(error) )
return NULL;
p = (vprocess*)hl_gc_alloc_finalizer(sizeof(vprocess));
#ifdef HL_TVOS
hl_error("hl_process_run() not available for this platform");
p->pid = -1;
#else
p->pid = fork();
#endif
if( p->pid == -1 ) {
close(input[0]);
close(input[1]);
close(output[0]);
close(output[1]);
close(error[0]);
close(error[1]);
return NULL;
}
// child
if( p->pid == 0 ) {
close(input[1]);
close(output[0]);
close(error[0]);
dup2(input[0],0);
dup2(output[1],1);
dup2(error[1],2);
#ifdef HL_TVOS
hl_error("hl_process_run() not available for this platform");
#else
execvp(argv[0],argv);
#endif
fprintf(stderr,"Command not found : %s\n",cmd);
exit(1);
}
// parent
close(input[0]);
close(output[1]);
close(error[1]);
p->iwrite = input[1];
p->oread = output[0];
p->eread = error[0];
# endif
p->finalize = process_finalize;
return p;
}
HL_PRIM int hl_process_stdout_read( vprocess *p, vbyte *str, int pos, int len ) {
# ifdef HL_WIN
DWORD nbytes;
if( !ReadFile(p->oread,str+pos,len,&nbytes,NULL) )
return -1;
return nbytes;
# else
int nbytes = read(p->oread,str+pos,len);
if( nbytes <= 0 )
return -1;
return nbytes;
# endif
}
HL_PRIM int hl_process_stderr_read( vprocess *p, vbyte *str, int pos, int len ) {
# ifdef HL_WIN
DWORD nbytes;
if( !ReadFile(p->eread,str+pos,len,&nbytes,NULL) )
return -1;
return nbytes;
# else
int nbytes = read(p->eread,str+pos,len);
if( nbytes <= 0 )
return -1;
return nbytes;
# endif
}
HL_PRIM int hl_process_stdin_write( vprocess *p, vbyte *str, int pos, int len ) {
# ifdef HL_WIN
DWORD nbytes;
if( !WriteFile(p->iwrite,str+pos,len,&nbytes,NULL) )
return -1;
return nbytes;
# else
int nbytes = write(p->iwrite,str+pos,len);
if( nbytes < 0 )
return -1;
return nbytes;
# endif
}
HL_PRIM bool hl_process_stdin_close( vprocess *p ) {
# ifdef HL_WIN
if( !CloseHandle(p->iwrite) )
return false;
# else
if( close(p->iwrite) )
return false;
p->iwrite = -1;
# endif
return true;
}
HL_PRIM int hl_process_exit( vprocess *p, bool *running ) {
# ifdef HL_WIN
DWORD rval;
if( !running )
WaitForSingleObject(p->pinf.hProcess,INFINITE);
if( !GetExitCodeProcess(p->pinf.hProcess,&rval) )
return -1;
if( running ) {
*running = rval == STILL_ACTIVE;
if( *running ) rval = 0;
}
return rval;
# else
int rval = 0;
int wret = waitpid(p->pid,&rval,running ? WNOHANG : 0);
if( running ) *running = false;
if( wret != p->pid ) {
if( running ) {
if( wret == 0 )
*running = true;
return 0;
} else
return -1;
}
if( !WIFEXITED(rval) ) {
if( WIFSIGNALED(rval) )
return 0x40000000 | WTERMSIG(rval);
return -2;
}
return WEXITSTATUS(rval);
# endif
}
HL_PRIM int hl_process_pid( vprocess *p ) {
# ifdef HL_WIN
return p->pinf.dwProcessId;
# else
return p->pid;
# endif
}
HL_PRIM void hl_process_close( vprocess *p ) {
if( !p->finalize ) return;
p->finalize = NULL;
process_finalize(p);
}
HL_PRIM void hl_process_kill( vprocess *p ) {
# ifdef HL_WIN
TerminateProcess(p->pinf.hProcess,0xCDCDCDCD);
# elif defined(HL_IOS) || defined(HL_TVOS)
hl_error("hl_process_kill() not available on this platform");
# else
kill(p->pid,9);
# endif
}
#define _PROCESS _ABSTRACT(hl_process)
DEFINE_PRIM( _PROCESS, process_run, _BYTES _ARR _BOOL);
DEFINE_PRIM( _I32, process_stdout_read, _PROCESS _BYTES _I32 _I32);
DEFINE_PRIM( _I32, process_stderr_read, _PROCESS _BYTES _I32 _I32);
DEFINE_PRIM( _BOOL, process_stdin_close, _PROCESS);
DEFINE_PRIM( _I32, process_stdin_write, _PROCESS _BYTES _I32 _I32);
DEFINE_PRIM( _I32, process_exit, _PROCESS _REF(_BOOL));
DEFINE_PRIM( _I32, process_pid, _PROCESS);
DEFINE_PRIM( _VOID, process_close, _PROCESS);
DEFINE_PRIM( _VOID, process_kill, _PROCESS);
/* ************************************************************************ */

View File

@ -0,0 +1,120 @@
/*
* Copyright (C)2005-2016 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <hl.h>
#include <time.h>
#include <string.h>
#if defined(HL_WIN_DESKTOP)
# include <windows.h>
# include <process.h>
#elif defined(HL_CONSOLE)
# include <posix/posix.h>
#else
# include <sys/time.h>
# include <sys/types.h>
# include <unistd.h>
#endif
#define NSEEDS 25
#define MAX 7
typedef struct _rnd rnd;
struct _rnd {
unsigned long seeds[NSEEDS];
unsigned long cur;
};
static unsigned long mag01[2]={
0x0, 0x8ebfd028 // magic, don't change
};
static const unsigned long init_seeds[] = {
0x95f24dab, 0x0b685215, 0xe76ccae7, 0xaf3ec239, 0x715fad23,
0x24a590ad, 0x69e4b5ef, 0xbf456141, 0x96bc1b7b, 0xa7bdf825,
0xc1de75b7, 0x8858a9c9, 0x2da87693, 0xb657f9dd, 0xffdc8a9f,
0x8121da71, 0x8b823ecb, 0x885d05f5, 0x4e20cd47, 0x5a9ad5d9,
0x512c0c03, 0xea857ccd, 0x4cc1d30f, 0x8891a8a1, 0xa6b7aadb
};
HL_PRIM rnd *hl_rnd_alloc() {
return (rnd*)hl_gc_alloc_noptr(sizeof(rnd));
}
HL_PRIM void hl_rnd_set_seed( rnd *r, int s ) {
int i;
r->cur = 0;
memcpy(r->seeds,init_seeds,sizeof(init_seeds));
for(i=0;i<NSEEDS;i++)
r->seeds[i] ^= s;
}
HL_PRIM rnd *hl_rnd_init_system() {
rnd *r = hl_rnd_alloc();
int pid = getpid();
unsigned int time;
#ifdef HL_WIN
time = GetTickCount();
#else
struct timeval t;
gettimeofday(&t,NULL);
time = t.tv_sec * 1000000 + t.tv_usec;
#endif
#ifdef HL_DEBUG_REPRO
// fixed random seed
time = 4644546;
pid = 0;
#endif
hl_rnd_set_seed(r,time ^ (pid | (pid << 16)));
return r;
}
HL_PRIM unsigned int hl_rnd_int( rnd *r ) {
unsigned int y;
int pos = r->cur++;
if( pos >= NSEEDS ) {
int kk;
for(kk=0;kk<NSEEDS-MAX;kk++)
r->seeds[kk] = r->seeds[kk+MAX] ^ (r->seeds[kk] >> 1) ^ mag01[r->seeds[kk] % 2];
for(;kk<NSEEDS;kk++)
r->seeds[kk] = r->seeds[kk+(MAX-NSEEDS)] ^ (r->seeds[kk] >> 1) ^ mag01[r->seeds[kk] % 2];
r->cur = 1;
pos = 0;
}
y = r->seeds[pos];
y ^= (y << 7) & 0x2b5b2500;
y ^= (y << 15) & 0xdb8b0000;
y ^= (y >> 16);
return y;
}
HL_PRIM double hl_rnd_float( rnd *r ) {
double big = 4294967296.0;
return ((hl_rnd_int(r) / big + hl_rnd_int(r)) / big + hl_rnd_int(r)) / big;
}
#define _RND _ABSTRACT(hl_random)
DEFINE_PRIM(_RND,rnd_alloc,_NO_ARG);
DEFINE_PRIM(_RND,rnd_init_system, _NO_ARG);
DEFINE_PRIM(_VOID,rnd_set_seed, _RND _I32);
DEFINE_PRIM(_I32,rnd_int, _RND);
DEFINE_PRIM(_F64,rnd_float, _RND);

View File

@ -0,0 +1,131 @@
/*
* Copyright (C)2005-2016 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <hl.h>
#define PCRE2_STATIC
#include <pcre2.h>
typedef struct _ereg ereg;
struct _ereg {
void (*finalize)( ereg * );
/* The compiled regex code */
pcre2_code *regex;
/* Pointer to the allocated memory for match data */
pcre2_match_data *match_data;
/* Number of capture groups */
int n_groups;
/* Whether the last string was matched successfully */
bool matched;
};
static void regexp_finalize( ereg *e ) {
pcre2_code_free(e->regex);
pcre2_match_data_free(e->match_data);
}
HL_PRIM ereg *hl_regexp_new_options( vbyte *str, vbyte *opts ) {
ereg *r;
int error_code;
size_t error_offset;
pcre2_code *p;
uchar *o = (uchar*)opts;
int options = PCRE2_UCP | PCRE2_UTF | PCRE2_ALT_BSUX | PCRE2_ALLOW_EMPTY_CLASS | PCRE2_MATCH_UNSET_BACKREF;
while( *o ) {
switch( *o++ ) {
case 'i':
options |= PCRE2_CASELESS;
break;
case 's':
options |= PCRE2_DOTALL;
break;
case 'm':
options |= PCRE2_MULTILINE;
break;
case 'u':
break;
case 'g':
options |= PCRE2_UNGREEDY;
break;
default:
return NULL;
}
}
p = pcre2_compile((PCRE2_SPTR)str,PCRE2_ZERO_TERMINATED,options,&error_code,&error_offset,NULL);
if( p == NULL ) {
hl_buffer *b = hl_alloc_buffer();
vdynamic *d = hl_alloc_dynamic(&hlt_bytes);
PCRE2_UCHAR error_buffer[256];
pcre2_get_error_message(error_code,error_buffer,sizeof(error_buffer));
hl_buffer_str(b,USTR("Regexp compilation error : "));
hl_buffer_str(b,error_buffer);
hl_buffer_str(b,USTR(" in "));
hl_buffer_str(b,(uchar*)str);
d->v.bytes = (vbyte*)hl_buffer_content(b,NULL);
hl_throw(d);
}
r = (ereg*)hl_gc_alloc_finalizer(sizeof(ereg));
r->finalize = regexp_finalize;
r->regex = p;
r->matched = 0;
r->n_groups = 0;
pcre2_pattern_info(p,PCRE2_INFO_CAPTURECOUNT,&r->n_groups);
r->n_groups++;
r->match_data = pcre2_match_data_create_from_pattern(r->regex,NULL);
return r;
}
HL_PRIM int hl_regexp_matched_pos( ereg *e, int m, int *len ) {
int start;
size_t *matches = pcre2_get_ovector_pointer(e->match_data);
if( !e->matched )
hl_error("Calling regexp_matched_pos() on an unmatched regexp");
if( m < 0 || m >= e->n_groups )
hl_error("Matched index %d outside bounds",m);
start = matches[m*2];
if( len ) *len = matches[m*2+1] - start;
return start;
}
HL_PRIM int hl_regexp_matched_num( ereg *e ) {
if( !e->matched )
return -1;
else
return e->n_groups;
}
HL_PRIM bool hl_regexp_match( ereg *e, vbyte *s, int pos, int len ) {
int res = pcre2_match(e->regex,(PCRE2_SPTR)s,pos+len,pos,PCRE2_NO_UTF_CHECK,e->match_data,NULL);
e->matched = res >= 0;
if( res >= 0 )
return true;
if( res != PCRE2_ERROR_NOMATCH )
hl_error("An error occurred while running pcre2_match()");
return false;
}
#define _EREG _ABSTRACT(ereg)
DEFINE_PRIM( _EREG, regexp_new_options, _BYTES _BYTES);
DEFINE_PRIM( _I32, regexp_matched_pos, _EREG _I32 _REF(_I32));
DEFINE_PRIM( _I32, regexp_matched_num, _EREG );
DEFINE_PRIM( _BOOL, regexp_match, _EREG _BYTES _I32 _I32);

View File

@ -0,0 +1,504 @@
/*
* Copyright (C)2005-2016 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifdef _WIN32
#define FD_SETSIZE 65536
#pragma warning(disable:4548)
# include <string.h>
# define _WINSOCKAPI_
# include <hl.h>
# include <winsock2.h>
# define FDSIZE(n) (sizeof(void*) + (n) * sizeof(SOCKET))
# define SHUT_WR SD_SEND
# define SHUT_RD SD_RECEIVE
# define SHUT_RDWR SD_BOTH
typedef int _sockaddr;
typedef int socklen_t;
#else
#if defined(__ORBIS__) || defined(__NX__)
# include <hl.h>
# include <posix/posix.h>
#else
# define _GNU_SOURCE
# include <string.h>
# include <sys/types.h>
# include <sys/socket.h>
# include <sys/time.h>
# include <netinet/in.h>
# include <netinet/tcp.h>
# include <arpa/inet.h>
# include <unistd.h>
# include <netdb.h>
# include <poll.h>
# include <fcntl.h>
# include <errno.h>
# include <stdio.h>
#endif
typedef int SOCKET;
# define closesocket close
# define SOCKET_ERROR (-1)
# define INVALID_SOCKET (-1)
typedef unsigned int _sockaddr;
#endif
#ifdef HL_LINUX
# include <linux/version.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,44)
# include <sys/epoll.h>
# define HAS_EPOLL
#endif
#endif
#ifndef HAS_EPOLL
# define EPOLLIN 0x001
# define EPOLLOUT 0x004
#endif
#include <hl.h>
#if defined(HL_WIN) || defined(HL_MAC) || defined(HL_IOS) || defined(HL_TVOS)
# define MSG_NOSIGNAL 0
#endif
typedef struct _hl_socket {
SOCKET sock;
} hl_socket;
static int block_error() {
#ifdef HL_WIN
int err = WSAGetLastError();
if( err == WSAEWOULDBLOCK || err == WSAEALREADY || err == WSAETIMEDOUT )
#else
if( errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS || errno == EALREADY )
#endif
return -1;
return -2;
}
HL_PRIM void hl_socket_init() {
#ifdef HL_WIN
static bool init_done = false;
static WSADATA init_data;
if( !init_done ) {
WSAStartup(MAKEWORD(2,0),&init_data);
init_done = true;
}
#endif
}
HL_PRIM hl_socket *hl_socket_new( bool udp ) {
SOCKET s;
if( udp )
s = socket(AF_INET,SOCK_DGRAM,0);
else
s = socket(AF_INET,SOCK_STREAM,0);
if( s == INVALID_SOCKET )
return NULL;
# ifdef HL_MAC
setsockopt(s,SOL_SOCKET,SO_NOSIGPIPE,NULL,0);
# endif
# ifdef HL_POSIX
// we don't want sockets to be inherited in case of exec
{
int old = fcntl(s,F_GETFD,0);
if( old >= 0 ) fcntl(s,F_SETFD,old|FD_CLOEXEC);
}
# endif
{
hl_socket *hs = hl_gc_alloc_noptr(sizeof(hl_socket));
hs->sock = s;
return hs;
}
}
HL_PRIM void hl_socket_close( hl_socket *s ) {
if( !s ) return;
closesocket(s->sock);
s->sock = INVALID_SOCKET;
}
HL_PRIM int hl_socket_send_char( hl_socket *s, int c ) {
char cc;
cc = (char)(unsigned char)c;
if( !s )
return -2;
if( send(s->sock,&cc,1,MSG_NOSIGNAL) == SOCKET_ERROR )
return block_error();
return 1;
}
HL_PRIM int hl_socket_send( hl_socket *s, vbyte *buf, int pos, int len ) {
int r;
if( !s )
return -2;
r = send(s->sock, (char*)buf + pos, len, MSG_NOSIGNAL);
if( r == SOCKET_ERROR )
return block_error();
return len;
}
HL_PRIM int hl_socket_recv( hl_socket *s, vbyte *buf, int pos, int len ) {
int ret;
if( !s )
return -2;
hl_blocking(true);
ret = recv(s->sock, (char*)buf + pos, len, MSG_NOSIGNAL);
hl_blocking(false);
if( ret == SOCKET_ERROR )
return block_error();
return ret;
}
HL_PRIM int hl_socket_recv_char( hl_socket *s ) {
char cc;
int ret;
if( !s ) return -2;
hl_blocking(true);
ret = recv(s->sock,&cc,1,MSG_NOSIGNAL);
hl_blocking(false);
if( ret == SOCKET_ERROR )
return block_error();
if( ret == 0 )
return -2;
return (unsigned char)cc;
}
HL_PRIM int hl_host_resolve( vbyte *host ) {
unsigned int ip;
hl_blocking(true);
ip = inet_addr((char*)host);
if( ip == INADDR_NONE ) {
struct hostent *h;
# if defined(HL_WIN) || defined(HL_MAC) || defined(HL_IOS) || defined(HL_TVOS) || defined (HL_CYGWIN) || defined(HL_CONSOLE)
h = gethostbyname((char*)host);
# else
struct hostent hbase;
char buf[1024];
int errcode;
gethostbyname_r((char*)host,&hbase,buf,1024,&h,&errcode);
# endif
if( h == NULL ) {
hl_blocking(false);
return -1;
}
ip = *((unsigned int*)h->h_addr_list[0]);
}
hl_blocking(false);
return ip;
}
HL_PRIM vbyte *hl_host_to_string( int ip ) {
struct in_addr i;
*(int*)&i = ip;
return (vbyte*)inet_ntoa(i);
}
HL_PRIM vbyte *hl_host_reverse( int ip ) {
struct hostent *h;
hl_blocking(true);
# if defined(HL_WIN) || defined(HL_MAC) || defined(HL_IOS) || defined(HL_TVOS) || defined(HL_CYGWIN) || defined(HL_CONSOLE)
h = gethostbyaddr((char *)&ip,4,AF_INET);
# elif defined(__ANDROID__)
hl_error("hl_host_reverse() not available for this platform");
# else
struct hostent htmp;
int errcode;
char buf[1024];
gethostbyaddr_r((char*)&ip,4,AF_INET,&htmp,buf,1024,&h,&errcode);
# endif
hl_blocking(false);
if( h == NULL )
return NULL;
return (vbyte*)h->h_name;
}
HL_PRIM vbyte *hl_host_local() {
char buf[256];
if( gethostname(buf,256) == SOCKET_ERROR )
return NULL;
return hl_copy_bytes((vbyte*)buf,(int)strlen(buf)+1);
}
HL_PRIM bool hl_socket_connect( hl_socket *s, int host, int port ) {
struct sockaddr_in addr;
memset(&addr,0,sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons((unsigned short)port);
*(int*)&addr.sin_addr.s_addr = host;
if( !s ) return false;
hl_blocking(true);
if( connect(s->sock,(struct sockaddr*)&addr,sizeof(addr)) != 0 ) {
int err = block_error();
hl_blocking(false);
if( err == -1 ) return true; // in progress
return false;
}
hl_blocking(false);
return true;
}
HL_PRIM bool hl_socket_listen( hl_socket *s, int n ) {
if( !s ) return false;
return listen(s->sock,n) != SOCKET_ERROR;
}
HL_PRIM bool hl_socket_bind( hl_socket *s, int host, int port ) {
struct sockaddr_in addr;
if( !s ) return false;
memset(&addr,0,sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons((unsigned short)port);
*(int*)&addr.sin_addr.s_addr = host;
#ifndef HL_WIN
int opt = 1;
setsockopt(s->sock,SOL_SOCKET,SO_REUSEADDR,(char*)&opt,sizeof(opt));
#endif
return bind(s->sock,(struct sockaddr*)&addr,sizeof(addr)) != SOCKET_ERROR;
}
HL_PRIM hl_socket *hl_socket_accept( hl_socket *s ) {
struct sockaddr_in addr;
_sockaddr addrlen = sizeof(addr);
SOCKET nsock;
hl_socket *hs;
if( !s ) return NULL;
hl_blocking(true);
nsock = accept(s->sock,(struct sockaddr*)&addr,&addrlen);
hl_blocking(false);
if( nsock == INVALID_SOCKET )
return NULL;
hs = (hl_socket*)hl_gc_alloc_noptr(sizeof(hl_socket));
hs->sock = nsock;
return hs;
}
HL_PRIM bool hl_socket_peer( hl_socket *s, int *host, int *port ) {
struct sockaddr_in addr;
_sockaddr addrlen = sizeof(addr);
if( !s || getpeername(s->sock,(struct sockaddr*)&addr,&addrlen) == SOCKET_ERROR )
return false;
*host = *(int*)&addr.sin_addr;
*port = ntohs(addr.sin_port);
return true;
}
HL_PRIM bool hl_socket_host( hl_socket *s, int *host, int *port ) {
struct sockaddr_in addr;
_sockaddr addrlen = sizeof(addr);
if( !s || getsockname(s->sock,(struct sockaddr*)&addr,&addrlen) == SOCKET_ERROR )
return false;
*host = *(int*)&addr.sin_addr;
*port = ntohs(addr.sin_port);
return true;
}
static void init_timeval( double f, struct timeval *t ) {
t->tv_usec = (int)((f - (int)f) * 1000000);
t->tv_sec = (int)f;
}
HL_PRIM bool hl_socket_set_timeout( hl_socket *s, double t ) {
#ifdef HL_WIN
int time = (int)(t * 1000);
#else
struct timeval time;
init_timeval(t,&time);
#endif
if( !s ) return false;
if( setsockopt(s->sock,SOL_SOCKET,SO_SNDTIMEO,(char*)&time,sizeof(time)) != 0 )
return false;
if( setsockopt(s->sock,SOL_SOCKET,SO_RCVTIMEO,(char*)&time,sizeof(time)) != 0 )
return false;
return true;
}
HL_PRIM bool hl_socket_shutdown( hl_socket *s, bool r, bool w ) {
if( !s )
return false;
if( !r && !w )
return true;
return shutdown(s->sock,r?(w?SHUT_RDWR:SHUT_RD):SHUT_WR) == 0;
}
HL_PRIM bool hl_socket_set_blocking( hl_socket *s, bool b ) {
#ifdef HL_WIN
unsigned long arg = b?0:1;
if( !s ) return false;
return ioctlsocket(s->sock,FIONBIO,&arg) == 0;
#else
int rights;
if( !s ) return false;
rights = fcntl(s->sock,F_GETFL);
if( rights == -1 )
return false;
if( b )
rights &= ~O_NONBLOCK;
else
rights |= O_NONBLOCK;
return fcntl(s->sock,F_SETFL,rights) != -1;
#endif
}
HL_PRIM bool hl_socket_set_fast_send( hl_socket *s, bool b ) {
int fast = b;
if( !s ) return false;
return setsockopt(s->sock,IPPROTO_TCP,TCP_NODELAY,(char*)&fast,sizeof(fast)) == 0;
}
HL_PRIM int hl_socket_send_to( hl_socket *s, char *data, int len, int host, int port ) {
struct sockaddr_in addr;
if( !s ) return -2;
memset(&addr,0,sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons((unsigned short)port);
*(int*)&addr.sin_addr.s_addr = host;
len = sendto(s->sock, data, len, MSG_NOSIGNAL, (struct sockaddr*)&addr, sizeof(addr));
if( len == SOCKET_ERROR )
return block_error();
return len;
}
HL_PRIM int hl_socket_recv_from( hl_socket *s, char *data, int len, int *host, int *port ) {
struct sockaddr_in saddr;
socklen_t slen = sizeof(saddr);
if( !s ) return -2;
hl_blocking(true);
len = recvfrom(s->sock, data, len, MSG_NOSIGNAL, (struct sockaddr*)&saddr, &slen);
hl_blocking(false);
if( len == SOCKET_ERROR ) {
#ifdef HL_WIN
if( WSAGetLastError() == WSAECONNRESET )
len = 0;
else
#endif
return block_error();
}
*host = *(int*)&saddr.sin_addr;
*port = ntohs(saddr.sin_port);
return len;
}
HL_PRIM int hl_socket_fd_size( int size ) {
if( size > FD_SETSIZE )
return -1;
# ifdef HL_WIN
return FDSIZE(size);
# else
return sizeof(fd_set);
# endif
}
static fd_set *make_socket_set( varray *a, char **tmp, int *tmp_size, unsigned int *max ) {
fd_set *set = (fd_set*)*tmp;
int i, req;
if( a == NULL )
return set;
req = hl_socket_fd_size(a->size);
if( *tmp_size < req )
return NULL;
*tmp_size -= req;
*tmp += req;
FD_ZERO(set);
for(i=0;i<a->size;i++) {
hl_socket *s= hl_aptr(a,hl_socket*)[i];
if( s== NULL ) break;
if( s->sock > *max ) *max = (int)s->sock;
FD_SET(s->sock,set);
}
return set;
}
static void make_array_result( fd_set *set, varray *a ) {
int i;
int pos = 0;
hl_socket **aptr = hl_aptr(a,hl_socket*);
if( a == NULL )
return;
for(i=0;i<a->size;i++) {
hl_socket *s = aptr[i];
if( s == NULL )
break;
if( FD_ISSET(s->sock,set) )
aptr[pos++] = s;
}
if( pos < a->size )
aptr[pos++] = NULL;
}
HL_PRIM bool hl_socket_select( varray *ra, varray *wa, varray *ea, char *tmp, int tmp_size, double timeout ) {
struct timeval tval, *tt;
fd_set *rs, *ws, *es;
unsigned int max = 0;
rs = make_socket_set(ra,&tmp,&tmp_size,&max);
ws = make_socket_set(wa,&tmp,&tmp_size,&max);
es = make_socket_set(ea,&tmp,&tmp_size,&max);
if( rs == NULL || ws == NULL || es == NULL )
return false;
if( timeout < 0 )
tt = NULL;
else {
tt = &tval;
init_timeval(timeout,tt);
}
hl_blocking(true);
if( select((int)(max+1),ra?rs:NULL,wa?ws:NULL,ea?es:NULL,tt) == SOCKET_ERROR ) {
hl_blocking(false);
return false;
}
hl_blocking(false);
make_array_result(rs,ra);
make_array_result(ws,wa);
make_array_result(es,ea);
return true;
}
#define _SOCK _ABSTRACT(hl_socket)
DEFINE_PRIM(_VOID,socket_init,_NO_ARG);
DEFINE_PRIM(_SOCK,socket_new,_BOOL);
DEFINE_PRIM(_VOID,socket_close,_SOCK);
DEFINE_PRIM(_I32,socket_send_char,_SOCK _I32);
DEFINE_PRIM(_I32,socket_send,_SOCK _BYTES _I32 _I32 );
DEFINE_PRIM(_I32,socket_recv,_SOCK _BYTES _I32 _I32 );
DEFINE_PRIM(_I32,socket_recv_char, _SOCK);
DEFINE_PRIM(_I32,host_resolve,_BYTES);
DEFINE_PRIM(_BYTES,host_to_string,_I32);
DEFINE_PRIM(_BYTES,host_reverse,_I32);
DEFINE_PRIM(_BYTES,host_local,_NO_ARG);
DEFINE_PRIM(_BOOL,socket_connect,_SOCK _I32 _I32);
DEFINE_PRIM(_BOOL,socket_listen,_SOCK _I32);
DEFINE_PRIM(_BOOL,socket_bind,_SOCK _I32 _I32);
DEFINE_PRIM(_SOCK,socket_accept,_SOCK);
DEFINE_PRIM(_BOOL,socket_peer,_SOCK _REF(_I32) _REF(_I32));
DEFINE_PRIM(_BOOL,socket_host,_SOCK _REF(_I32) _REF(_I32));
DEFINE_PRIM(_BOOL,socket_set_timeout,_SOCK _F64);
DEFINE_PRIM(_BOOL,socket_shutdown,_SOCK _BOOL _BOOL);
DEFINE_PRIM(_BOOL,socket_set_blocking,_SOCK _BOOL);
DEFINE_PRIM(_BOOL,socket_set_fast_send,_SOCK _BOOL);
DEFINE_PRIM(_I32, socket_send_to, _SOCK _BYTES _I32 _I32 _I32);
DEFINE_PRIM(_I32, socket_recv_from, _SOCK _BYTES _I32 _REF(_I32) _REF(_I32));
DEFINE_PRIM(_I32, socket_fd_size, _I32 );
DEFINE_PRIM(_BOOL, socket_select, _ARR _ARR _ARR _BYTES _I32 _F64);

View File

@ -0,0 +1,130 @@
#define m_sort TID(m_sort)
#define ms_compare TID(ms_compare)
#define ms_swap TID(ms_swap)
#define ms_lower TID(ms_lower)
#define ms_upper TID(ms_upper)
#define ms_rotate TID(ms_rotate)
#define ms_do_merge TID(ms_do_merge)
#define merge_sort_rec TID(merge_sort_rec)
typedef struct {
TSORT *arr;
vclosure *c;
} m_sort;
static int ms_compare( m_sort *m, int a, int b ) {
return m->c->hasValue ? ((int(*)(void*,TSORT,TSORT))m->c->fun)(m->c->value,m->arr[a],m->arr[b]) : ((int(*)(TSORT,TSORT))m->c->fun)(m->arr[a],m->arr[b]);
}
static void ms_swap( m_sort *m, int a, int b ) {
TSORT tmp = m->arr[a];
m->arr[a] = m->arr[b];
m->arr[b] = tmp;
}
static int ms_lower( m_sort *m, int from, int to, int val ) {
int len = to - from, half, mid;
while( len > 0 ) {
half = len>>1;
mid = from + half;
if( ms_compare(m, mid, val) < 0 ) {
from = mid+1;
len = len - half -1;
} else
len = half;
}
return from;
}
static int ms_upper( m_sort *m, int from, int to, int val ) {
int len = to - from, half, mid;
while( len > 0 ) {
half = len>>1;
mid = from + half;
if( ms_compare(m, val, mid) < 0 )
len = half;
else {
from = mid+1;
len = len - half -1;
}
}
return from;
}
static void ms_rotate( m_sort *m, int from, int mid, int to ) {
int n;
if( from==mid || mid==to ) return;
n = ms_gcd(to - from, mid - from);
while (n-- != 0) {
TSORT val = m->arr[from+n];
int shift = mid - from;
int p1 = from+n, p2=from+n+shift;
while (p2 != from + n) {
m->arr[p1] = m->arr[p2];
p1=p2;
if( to - p2 > shift) p2 += shift;
else p2=from + (shift - (to - p2));
}
m->arr[p1] = val;
}
}
static void ms_do_merge( m_sort *m, int from, int pivot, int to, int len1, int len2 ) {
int first_cut, second_cut, len11, len22, new_mid;
if( len1 == 0 || len2==0 )
return;
if( len1+len2 == 2 ) {
if( ms_compare(m, pivot, from) < 0 )
ms_swap(m, pivot, from);
return;
}
if (len1 > len2) {
len11=len1>>1;
first_cut = from + len11;
second_cut = ms_lower(m, pivot, to, first_cut);
len22 = second_cut - pivot;
} else {
len22 = len2>>1;
second_cut = pivot + len22;
first_cut = ms_upper(m, from, pivot, second_cut);
len11=first_cut - from;
}
ms_rotate(m, first_cut, pivot, second_cut);
new_mid=first_cut+len22;
ms_do_merge(m, from, first_cut, new_mid, len11, len22);
ms_do_merge(m, new_mid, second_cut, to, len1 - len11, len2 - len22);
}
static void merge_sort_rec( m_sort *m, int from, int to ) {
int middle;
if( to - from < 12 ) {
// insert sort
int i;
if( to <= from ) return;
for(i=from+1;i<to;i++) {
int j = i;
while( j > from ) {
if( ms_compare(m,j,j-1) < 0 )
ms_swap(m,j-1,j);
else
break;
j--;
}
}
return;
}
middle = (from + to)>>1;
merge_sort_rec(m, from, middle);
merge_sort_rec(m, middle, to);
ms_do_merge(m, from, middle, to, middle-from, to - middle);
}
#undef ms_compare
#undef ms_swap
#undef ms_lower
#undef ms_upper
#undef ms_rotate
#undef ms_do_merge
#undef merge_sort_rec
#undef m_sort
#undef TSORT
#undef TID

View File

@ -0,0 +1,383 @@
/*
* Copyright (C)2005-2016 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <hl.h>
HL_PRIM vbyte *hl_itos( int i, int *len ) {
uchar tmp[24];
int k = (int)usprintf(tmp,24,USTR("%d"),i);
*len = k;
return hl_copy_bytes((vbyte*)tmp,(k + 1)<<1);
}
HL_PRIM vbyte *hl_ftos( double d, int *len ) {
uchar tmp[24];
int k;
if( d != d ) {
*len = 3;
return hl_copy_bytes((vbyte*)USTR("NaN"),8);
}
// don't use the last digit (eg 5.1 = 5.09999..996)
// also cut one more digit for some numbers (eg 86.57 and 85.18) <- to fix since we lose one PI digit
k = (int)usprintf(tmp,24,USTR("%.15g"),d);
# if defined(HL_WIN) && _MSC_VER <= 1800
// fix for window : 1e-5 is printed as 1e-005 whereas it's 1e-05 on other platforms
// note : this is VS2013 std bug, VS2015 works correctly
{
int i;
for(i=0;i<k;i++)
if( tmp[i] == 'e' ) {
if( tmp[i+1] == '+' || tmp[i+1] == '-' ) i++;
if( tmp[i+1] != '0' || tmp[i+2] != '0' ) break;
memmove(tmp+i+1,tmp+i+2,(k-(i+1))*2);
k--;
break;
}
}
# endif
*len = k;
return hl_copy_bytes((vbyte*)tmp,(k + 1) << 1);
}
HL_PRIM vbyte *hl_value_to_string( vdynamic *d, int *len ) {
if( d == NULL ) {
*len = 4;
return (vbyte*)USTR("null");
}
switch( d->t->kind ) {
case HI32:
return hl_itos(d->v.i,len);
case HF64:
return hl_ftos(d->v.d,len);
default:
{
hl_buffer *b = hl_alloc_buffer();
hl_buffer_val(b, d);
return (vbyte*)hl_buffer_content(b,len);
}
}
}
HL_PRIM int hl_ucs2length( vbyte *str, int pos ) {
return (int)ustrlen((uchar*)(str + pos));
}
HL_PRIM int hl_utf8_length( const vbyte *s, int pos ) {
int len = 0;
s += pos;
while( true ) {
unsigned char c = (unsigned)*s;
len++;
if( c < 0x80 ) {
if( c == 0 ) {
len--;
break;
}
s++;
} else if( c < 0xC0 )
return len - 1;
else if( c < 0xE0 ) {
if( (s[1]&0x80) == 0 ) return len - 1;
s += 2;
} else if( c < 0xF0 ) {
if( ((s[1]&s[2])&0x80) == 0 ) return len - 1;
s+=3;
} else if( c < 0xF8 ) {
if( ((s[1]&s[2]&s[3])&0x80) == 0 ) return len - 1;
len++; // surrogate pair
s+=4;
} else
return len;
}
return len;
}
HL_PRIM int hl_from_utf8( uchar *out, int outLen, const char *str ) {
int p = 0;
unsigned int c, c2, c3;
while( p++ < outLen ) {
c = *(unsigned char *)str++;
if( c < 0x80 ) {
if( c == 0 ) break;
// nothing
} else if( c < 0xE0 ) {
c = ((c & 0x3F) << 6) | ((*str++)&0x7F);
} else if( c < 0xF0 ) {
c2 = (unsigned)*str++;
c = ((c & 0x1F) << 12) | ((c2 & 0x7F) << 6) | ((*str++) & 0x7F);
} else {
c2 = (unsigned)*str++;
c3 = (unsigned)*str++;
c = (((c & 0x0F) << 18) | ((c2 & 0x7F) << 12) | ((c3 & 0x7F) << 6) | ((*str++) & 0x7F)) - 0x10000;
// surrogate pair
if( p++ == outLen ) break;
*out++ = (uchar)((c >> 10) + 0xD800);
*out++ = (uchar)((c & 0x3FF) | 0xDC00);
continue;
}
*out++ = (uchar)c;
}
*out = 0;
return --p;
}
HL_PRIM uchar *hl_to_utf16( const char *str ) {
int len = hl_utf8_length((vbyte*)str,0);
uchar *out = (uchar*)hl_gc_alloc_noptr((len + 1) * sizeof(uchar));
hl_from_utf8(out,len,str);
return out;
}
HL_PRIM vbyte* hl_utf8_to_utf16( vbyte *str, int pos, int *size ) {
int ulen = hl_utf8_length(str, pos);
uchar *s = (uchar*)hl_gc_alloc_noptr((ulen + 1)*sizeof(uchar));
hl_from_utf8(s,ulen,(char*)(str+pos));
*size = ulen << 1;
return (vbyte*)s;
}
#include "unicase.h"
HL_PRIM vbyte* hl_ucs2_upper( vbyte *str, int pos, int len ) {
uchar *cstr = (uchar*)(str + pos);
uchar *out = (uchar*)hl_gc_alloc_noptr((len + 1) * sizeof(uchar));
int i;
uchar *cout = out;
memcpy(out,cstr,len << 1);
for(i=0;i<len;i++) {
unsigned int c = *cstr++;
int up = c >> UL_BITS;
if( up < UMAX ) {
unsigned int c2 = UPPER[up][c&((1<<UL_BITS)-1)];
if( c2 != 0 ) *cout = (uchar)c2;
}
cout++;
}
*cout = 0;
return (vbyte*)out;
}
HL_PRIM vbyte* hl_ucs2_lower( vbyte *str, int pos, int len ) {
uchar *cstr = (uchar*)(str + pos);
uchar *out = (uchar*)hl_gc_alloc_noptr((len + 1) * sizeof(uchar));
uchar *cout = out;
int i;
memcpy(out,cstr,len << 1);
for(i=0;i<len;i++) {
unsigned int c = *cstr++;
int up = c >> UL_BITS;
if( up < LMAX ) {
unsigned int c2 = LOWER[up][c&((1<<UL_BITS)-1)];
if( c2 != 0 ) *cout = (uchar)c2;
}
cout++;
}
*cout = 0;
return (vbyte*)out;
}
HL_PRIM vbyte *hl_utf16_to_utf8( vbyte *str, int len, int *size ) {
vbyte *out;
uchar *c = (uchar*)str;
uchar *end = len == 0 ? NULL : c + len;
int utf8bytes = 0;
int p = 0;
while( c != end ) {
unsigned int v = (unsigned int)*c;
if( v == 0 && end == NULL ) break;
if( v < 0x80 )
utf8bytes++;
else if( v < 0x800 )
utf8bytes += 2;
else if( v >= 0xD800 && v <= 0xDFFF ) {
utf8bytes += 4;
c++;
} else
utf8bytes += 3;
c++;
}
out = hl_gc_alloc_noptr(utf8bytes + 1);
c = (uchar*)str;
while( c != end ) {
unsigned int v = (unsigned int)*c;
if( v < 0x80 ) {
out[p++] = (vbyte)v;
if( v == 0 && end == NULL ) break;
} else if( v < 0x800 ) {
out[p++] = (vbyte)(0xC0|(v>>6));
out[p++] = (vbyte)(0x80|(v&63));
} else if( v >= 0xD800 && v <= 0xDFFF ) {
int k = ((((int)v - 0xD800) << 10) | (((int)*++c) - 0xDC00)) + 0x10000;
out[p++] = (vbyte)(0xF0|(k>>18));
out[p++] = (vbyte)(0x80 | ((k >> 12) & 63));
out[p++] = (vbyte)(0x80 | ((k >> 6) & 63));
out[p++] = (vbyte)(0x80 | (k & 63));
} else {
out[p++] = (vbyte)(0xE0|(v>>12));
out[p++] = (vbyte)(0x80|((v>>6)&63));
out[p++] = (vbyte)(0x80|(v&63));
}
c++;
}
if( size ) *size = utf8bytes;
return out;
}
HL_PRIM char *hl_to_utf8( const uchar *bytes ) {
int size;
return (char*)hl_utf16_to_utf8((vbyte*)bytes, 0, &size);
}
static void hl_buffer_hex( hl_buffer *b, int c ) {
static const uchar *hex = USTR("0123456789ABCDEF");
hl_buffer_char(b,'%');
hl_buffer_char(b,hex[c>>4]);
hl_buffer_char(b,hex[c&0xF]);
}
HL_PRIM vbyte *hl_url_encode( vbyte *str, int *len ) {
hl_buffer *b = hl_alloc_buffer();
uchar *cstr = (uchar*)str;
unsigned int sur;
while( true ) {
unsigned int c = (unsigned)*cstr++;
if( c == 0 ) break;
if( (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_' || c == '-' || c == '.' )
hl_buffer_char(b,(uchar)c);
else {
if( c < 0x80 ) {
hl_buffer_hex(b,c);
} else if( c < 0x800 ) {
hl_buffer_hex(b, 0xC0|(c>>6));
hl_buffer_hex(b, 0x80|(c&63));
} else if( c >= 0xD800 && c <= 0xDBFF ) {
sur = (unsigned)*cstr;
if( sur >= 0xDC00 && sur < 0xDFFF ) {
cstr++;
c = ((((int)c - 0xD800) << 10) | ((int)sur - 0xDC00)) + 0x10000;
hl_buffer_hex(b, 0xF0|(c>>18));
hl_buffer_hex(b, 0x80|((c >> 12) & 63));
hl_buffer_hex(b, 0x80|((c >> 6) & 63));
hl_buffer_hex(b, 0x80|(c & 63));
} else {
hl_buffer_hex(b, 0xE0|(c>>12));
hl_buffer_hex(b, 0x80|((c>>6)&63));
hl_buffer_hex(b, 0x80|(c&63));
}
} else {
hl_buffer_hex(b, 0xE0|(c>>12));
hl_buffer_hex(b, 0x80|((c>>6)&63));
hl_buffer_hex(b, 0x80|(c&63));
}
}
}
return (vbyte*)hl_buffer_content(b,len);
}
static uchar decode_hex_char( uchar c ) {
if( c >= '0' && c <= '9' )
c -= '0';
else if( c >= 'a' && c <= 'f' )
c -= 'a' - 10;
else if( c >= 'A' && c <= 'F' )
c -= 'A' - 10;
else
return (uchar)-1;
return c;
}
static uchar decode_hex( uchar **cstr ) {
uchar *c = *cstr;
uchar p1 = decode_hex_char(c[0]);
uchar p2;
if( p1 == (uchar)-1 ) return p1;
p2 = decode_hex_char(c[1]);
if( p2 == (uchar)-1 ) return p2;
*cstr = c + 2;
return (p1 << 4) | p2;
}
HL_PRIM vbyte *hl_url_decode( vbyte *str, int *len ) {
hl_buffer *b = hl_alloc_buffer();
uchar *cstr = (uchar*)str;
while( true ) {
uchar c = *cstr++;
if( c == 0 )
return (vbyte*)hl_buffer_content(b,len);
if( c == '+' )
c = ' ';
else if( c == '%' ) {
uchar p1 = decode_hex(&cstr);
if( p1 == (uchar)-1 ) {
hl_buffer_char(b,'%');
continue;
}
if( p1 < 0x80 ) {
c = p1;
} else if( p1 < 0xE0 ) {
uchar p2;
if( *cstr++ != '%' ) break;
p2 = decode_hex(&cstr);
if( p2 < 0 ) break;
c = ((p1 & 0x3F) << 6) | (p2&0x7F);
} else if( p1 < 0xF0 ) {
uchar p2, p3;
if( *cstr++ != '%' ) break;
p2 = decode_hex(&cstr);
if( p2 < 0 ) break;
if( *cstr++ != '%' ) break;
p3 = decode_hex(&cstr);
if( p3 < 0 ) break;
c = ((p1 & 0x1F) << 12) | ((p2 & 0x7F) << 6) | (p3 & 0x7F);
} else {
int k;
uchar p2, p3, p4;
if( *cstr++ != '%' ) break;
p2 = decode_hex(&cstr);
if( p2 < 0 ) break;
if( *cstr++ != '%' ) break;
p3 = decode_hex(&cstr);
if( p3 < 0 ) break;
if( *cstr++ != '%' ) break;
p4 = decode_hex(&cstr);
if( p4 < 0 ) break;
k = (((p1 & 0x0F) << 18) | ((p2 & 0x7F) << 12) | ((p3 & 0x7F) << 6) | (p4 & 0x7F)) - 0x10000;
hl_buffer_char(b,(uchar)((k >> 10) + 0xD800));
c = (uchar)((k & 0x3FF) | 0xDC00);
}
}
hl_buffer_char(b,c);
}
hl_error("Malformed URL encoded");
return NULL;
}
DEFINE_PRIM(_BYTES,itos,_I32 _REF(_I32));
DEFINE_PRIM(_BYTES,ftos,_F64 _REF(_I32));
DEFINE_PRIM(_BYTES,value_to_string,_DYN _REF(_I32));
DEFINE_PRIM(_I32,ucs2length,_BYTES _I32);
DEFINE_PRIM(_BYTES,utf8_to_utf16,_BYTES _I32 _REF(_I32));
DEFINE_PRIM(_BYTES,utf16_to_utf8,_BYTES _I32 _REF(_I32));
DEFINE_PRIM(_BYTES,ucs2_upper,_BYTES _I32 _I32);
DEFINE_PRIM(_BYTES,ucs2_lower,_BYTES _I32 _I32);
DEFINE_PRIM(_BYTES,url_encode,_BYTES _REF(_I32));
DEFINE_PRIM(_BYTES,url_decode,_BYTES _REF(_I32));

View File

@ -0,0 +1,720 @@
/*
* Copyright (C)2005-2016 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <hl.h>
#ifdef HL_CONSOLE
# include <posix/posix.h>
#endif
#if !defined(HL_CONSOLE) || defined(HL_WIN_DESKTOP)
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <locale.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#if defined(HL_WIN)
# include <windows.h>
# include <direct.h>
# include <conio.h>
# include <fcntl.h>
# include <io.h>
# define getenv _wgetenv
# define putenv _wputenv
# define getcwd(buf,size) (void*)(int_val)GetCurrentDirectoryW(size,buf)
# define chdir !SetCurrentDirectoryW
# define system _wsystem
typedef struct _stat32 pstat;
# define stat _wstat32
# define unlink _wunlink
# define rename _wrename
# define mkdir(path,mode) _wmkdir(path)
# define rmdir _wrmdir
#else
# include <errno.h>
# include <unistd.h>
# include <limits.h>
# include <sys/time.h>
# include <dirent.h>
# include <termios.h>
# include <sys/times.h>
# include <sys/wait.h>
# include <locale.h>
# define HL_UTF8PATH
typedef struct stat pstat;
#endif
#endif
#ifdef HL_UTF8PATH
typedef char pchar;
#define pstrchr strchr
#define pstrlen strlen
#else
typedef uchar pchar;
#define pstrchr wcschr
#define pstrlen ustrlen
#endif
#ifdef HL_MAC
# include <sys/syslimits.h>
# include <limits.h>
# include <mach-o/dyld.h>
#endif
#ifndef CLK_TCK
# define CLK_TCK 100
#endif
static pchar *pstrdup( const pchar *s, int len ) {
pchar *ret;
if( len < 0 ) len = (int)pstrlen(s);
ret = (pchar*)hl_copy_bytes((vbyte*)s,sizeof(pchar)*(len+1));;
ret[len] = 0;
return ret;
}
HL_PRIM bool hl_sys_utf8_path() {
#ifdef HL_UTF8PATH
return true;
#else
return false;
#endif
}
HL_PRIM vbyte *hl_sys_string() {
#if defined(HL_CONSOLE)
return (vbyte*)sys_platform_name();
#elif defined(HL_WIN) || defined(HL_CYGWIN) || defined(HL_MINGW)
return (vbyte*)USTR("Windows");
#elif defined(HL_BSD)
return (vbyte*)USTR("BSD");
#elif defined(HL_MAC)
return (vbyte*)USTR("Mac");
#elif defined(HL_IOS)
return (vbyte*)USTR("iOS");
#elif defined(HL_TVOS)
return (vbyte*)USTR("tvOS");
#elif defined(HL_ANDROID)
return (vbyte*)USTR("Android");
#elif defined(HL_GNUKBSD)
return (vbyte*)USTR("GNU/kFreeBSD");
#elif defined(HL_LINUX)
return (vbyte*)USTR("Linux");
#else
#error Unknown system string
#endif
}
HL_PRIM vbyte *hl_sys_locale() {
#if defined(HL_WIN_DESKTOP)
wchar_t loc[LOCALE_NAME_MAX_LENGTH];
int len = GetSystemDefaultLocaleName(loc,LOCALE_NAME_MAX_LENGTH);
return len == 0 ? NULL : hl_copy_bytes((vbyte*)loc,(len+1)*2);
#elif defined(HL_CONSOLE)
return (vbyte*)sys_get_user_lang();
#else
return (vbyte*)getenv("LANG");
#endif
}
#define PR_WIN_UTF8 1
#define PR_AUTO_FLUSH 2
static int print_flags = PR_AUTO_FLUSH;
HL_PRIM int hl_sys_set_flags( int flags ) {
return print_flags = flags;
}
HL_PRIM void hl_sys_print( vbyte *msg ) {
hl_blocking(true);
# ifdef HL_XBO
OutputDebugStringW((LPCWSTR)msg);
# else
# ifdef HL_WIN_DESKTOP
if( print_flags & PR_WIN_UTF8 ) _setmode(_fileno(stdout),_O_U8TEXT);
# endif
uprintf(USTR("%s"),(uchar*)msg);
if( print_flags & PR_AUTO_FLUSH ) fflush(stdout);
# ifdef HL_WIN_DESKTOP
if( print_flags & PR_WIN_UTF8 ) _setmode(_fileno(stdout),_O_TEXT);
# endif
# endif
hl_blocking(false);
}
static void *f_before_exit = NULL;
static void *f_profile_event = NULL;
HL_PRIM void hl_setup_profiler( void *profile_event, void *before_exit ) {
f_before_exit = before_exit;
f_profile_event = profile_event;
}
HL_PRIM void hl_sys_profile_event( int code, vbyte *data, int dataLen ) {
if( f_profile_event ) ((void(*)(int,vbyte*,int))f_profile_event)(code,data,dataLen);
}
HL_PRIM void hl_sys_exit( int code ) {
if( f_before_exit ) ((void(*)())f_before_exit)();
exit(code);
}
#ifdef HL_DEBUG_REPRO
static double CURT = 0;
#endif
HL_PRIM double hl_sys_time() {
#ifdef HL_DEBUG_REPRO
CURT += 0.001;
return CURT;
#endif
#ifdef HL_WIN
#define EPOCH_DIFF (134774*24*60*60.0)
static double time_diff = 0.;
static double freq = 0.;
LARGE_INTEGER time;
if( freq == 0 ) {
QueryPerformanceFrequency(&time);
freq = (double)time.QuadPart;
}
QueryPerformanceCounter(&time);
if( time_diff == 0 ) {
FILETIME ft;
LARGE_INTEGER start_time;
GetSystemTimeAsFileTime(&ft);
start_time.LowPart = ft.dwLowDateTime;
start_time.HighPart = ft.dwHighDateTime;
time_diff = (((double)start_time.QuadPart) / 10000000.0) - (((double)time.QuadPart) / freq) - EPOCH_DIFF;
}
return time_diff + ((double)time.QuadPart) / freq;
#else
struct timeval tv;
if( gettimeofday(&tv,NULL) != 0 )
return 0.;
return tv.tv_sec + ((double)tv.tv_usec) / 1000000.0;
#endif
}
HL_PRIM vbyte *hl_sys_get_env( vbyte *v ) {
return (vbyte*)getenv((pchar*)v);
}
HL_PRIM bool hl_sys_put_env( vbyte *e, vbyte *v ) {
#if defined(HL_WIN)
hl_buffer *b = hl_alloc_buffer();
hl_buffer_str(b,(uchar*)e);
hl_buffer_char(b,'=');
if( v ) hl_buffer_str(b,(uchar*)v);
return putenv(hl_buffer_content(b,NULL)) == 0;
#else
if( v == NULL ) return unsetenv((char*)e) == 0;
return setenv((char*)e,(char*)v,1) == 0;
#endif
}
#ifdef HL_MAC
# define environ (*_NSGetEnviron())
#endif
#ifdef HL_WIN_DESKTOP
# undef environ
# define environ _wenviron
#else
extern pchar **environ;
#endif
HL_PRIM varray *hl_sys_env() {
varray *a;
pchar **e = environ;
pchar **arr;
int count = 0;
# ifdef HL_WIN_DESKTOP
if( e == NULL ) {
_wgetenv(L"");
e = environ;
}
# endif
while( *e ) {
pchar *x = pstrchr(*e,'=');
if( x == NULL ) {
e++;
continue;
}
count++;
e++;
}
a = hl_alloc_array(&hlt_bytes,count*2);
e = environ;
arr = hl_aptr(a,pchar*);
while( *e ) {
pchar *x = pstrchr(*e,'=');
if( x == NULL ) {
e++;
continue;
}
*arr++ = pstrdup(*e,(int)(x - *e));
*arr++ = pstrdup(x+1,-1);
e++;
}
return a;
}
HL_PRIM void hl_sys_sleep( double f ) {
hl_blocking(true);
#if defined(HL_WIN)
Sleep((DWORD)(f * 1000));
#else
struct timespec t;
t.tv_sec = (int)f;
t.tv_nsec = (int)((f - t.tv_sec) * 1e9);
nanosleep(&t,NULL);
#endif
hl_blocking(false);
}
HL_PRIM bool hl_sys_set_time_locale( vbyte *l ) {
#ifdef HL_POSIX
locale_t lc, old;
lc = newlocale(LC_TIME_MASK,(char*)l,NULL);
if( lc == NULL ) return false;
old = uselocale(lc);
if( old == NULL ) {
freelocale(lc);
return false;
}
if( old != LC_GLOBAL_LOCALE )
freelocale(old);
return true;
#else
return setlocale(LC_TIME,(char*)l) != NULL;
#endif
}
HL_PRIM vbyte *hl_sys_get_cwd() {
pchar buf[256];
int l;
if( getcwd(buf,256) == NULL )
return NULL;
l = (int)pstrlen(buf);
if( buf[l-1] != '/' && buf[l-1] != '\\' ) {
buf[l] = '/';
buf[l+1] = 0;
}
return (vbyte*)pstrdup(buf,-1);
}
HL_PRIM bool hl_sys_set_cwd( vbyte *dir ) {
return chdir((pchar*)dir) == 0;
}
HL_PRIM bool hl_sys_is64() {
#ifdef HL_64
return true;
#else
return false;
#endif
}
HL_PRIM int hl_sys_command( vbyte *cmd ) {
#if defined(HL_WIN)
int ret;
hl_blocking(true);
ret = system((pchar*)cmd);
hl_blocking(false);
return ret;
#else
int status;
hl_blocking(true);
#if defined(HL_IOS) || defined(HL_TVOS)
status = 0;
hl_error("hl_sys_command() not available on this platform");
#else
status = system((pchar*)cmd);
#endif
hl_blocking(false);
return WEXITSTATUS(status) | (WTERMSIG(status) << 8);
#endif
}
HL_PRIM bool hl_sys_exists( vbyte *path ) {
pstat st;
return stat((pchar*)path,&st) == 0;
}
HL_PRIM bool hl_sys_delete( vbyte *path ) {
return unlink((pchar*)path) == 0;
}
HL_PRIM bool hl_sys_rename( vbyte *path, vbyte *newname ) {
return rename((pchar*)path,(pchar*)newname) == 0;
}
HL_PRIM varray *hl_sys_stat( vbyte *path ) {
pstat s;
varray *a;
int *i;
if( stat((pchar*)path,&s) != 0 )
return NULL;
a = hl_alloc_array(&hlt_i32,12);
i = hl_aptr(a,int);
*i++ = s.st_gid;
*i++ = s.st_uid;
*i++ = s.st_atime;
*i++ = s.st_mtime;
*i++ = s.st_ctime;
*i++ = s.st_size;
*i++ = s.st_dev;
*i++ = s.st_ino;
*i++ = s.st_nlink;
*i++ = s.st_rdev;
*i++ = s.st_mode;
return a;
}
HL_PRIM bool hl_sys_is_dir( vbyte *path ) {
pstat s;
if( stat((pchar*)path,&s) != 0 )
return false;
return (s.st_mode & S_IFDIR) != 0;
}
HL_PRIM bool hl_sys_create_dir( vbyte *path, int mode ) {
return mkdir((pchar*)path,mode) == 0;
}
HL_PRIM bool hl_sys_remove_dir( vbyte *path ) {
return rmdir((pchar*)path) == 0;
}
HL_PRIM int hl_sys_getpid() {
#ifdef HL_WIN
return GetCurrentProcessId();
#else
return getpid();
#endif
}
HL_PRIM double hl_sys_cpu_time() {
#if defined(HL_WIN)
FILETIME unused;
FILETIME stime;
FILETIME utime;
if( !GetProcessTimes(GetCurrentProcess(),&unused,&unused,&stime,&utime) )
return 0.;
return ((double)(utime.dwHighDateTime+stime.dwHighDateTime)) * 65.536 * 6.5536 + (((double)utime.dwLowDateTime + (double)stime.dwLowDateTime) / 10000000);
#else
struct tms t = {0};
times(&t);
return ((double)(t.tms_utime + t.tms_stime)) / CLK_TCK;
#endif
}
HL_PRIM double hl_sys_thread_cpu_time() {
#if defined(HL_WIN)
FILETIME unused;
FILETIME utime;
if( !GetThreadTimes(GetCurrentThread(),&unused,&unused,&unused,&utime) )
return 0.;
return ((double)utime.dwHighDateTime) * 65.536 * 6.5536 + (((double)utime.dwLowDateTime) / 10000000);
#elif defined(HL_MAC) || defined(HL_CONSOLE)
hl_error("sys_thread_cpu_time not implemented on this platform");
return 0.;
#else
struct timespec t;
if( clock_gettime(CLOCK_THREAD_CPUTIME_ID,&t) )
return 0.;
return t.tv_sec + t.tv_nsec * 1e-9;
#endif
}
HL_PRIM varray *hl_sys_read_dir( vbyte *_path ) {
pchar *path = (pchar*)_path;
int count = 0;
int pos = 0;
varray *a = NULL;
pchar **current = NULL;
#ifdef HL_WIN
WIN32_FIND_DATAW d;
HANDLE handle;
hl_buffer *b = hl_alloc_buffer();
int len = (int)pstrlen(path);
hl_buffer_str(b,path);
if( len && path[len-1] != '/' && path[len-1] != '\\' )
hl_buffer_str(b,USTR("/*.*"));
else
hl_buffer_str(b,USTR("*.*"));
path = hl_buffer_content(b,NULL);
handle = FindFirstFileW(path,&d);
if( handle == INVALID_HANDLE_VALUE )
return NULL;
while( true ) {
// skip magic dirs
if( d.cFileName[0] != '.' || (d.cFileName[1] != 0 && (d.cFileName[1] != '.' || d.cFileName[2] != 0)) ) {
if( pos == count ) {
int ncount = count == 0 ? 16 : count * 2;
varray *narr = hl_alloc_array(&hlt_bytes,ncount);
pchar **ncur = hl_aptr(narr,pchar*);
memcpy(ncur,current,count*sizeof(void*));
current = ncur;
a = narr;
count = ncount;
}
current[pos++] = pstrdup(d.cFileName,-1);
}
if( !FindNextFileW(handle,&d) )
break;
}
FindClose(handle);
#else
DIR *d;
struct dirent *e;
d = opendir(path);
if( d == NULL )
return NULL;
while( true ) {
e = readdir(d);
if( e == NULL )
break;
// skip magic dirs
if( e->d_name[0] == '.' && (e->d_name[1] == 0 || (e->d_name[1] == '.' && e->d_name[2] == 0)) )
continue;
if( pos == count ) {
int ncount = count == 0 ? 16 : count * 2;
varray *narr = hl_alloc_array(&hlt_bytes,ncount);
pchar **ncur = hl_aptr(narr,pchar*);
memcpy(ncur,current,count*sizeof(void*));
current = ncur;
a = narr;
count = ncount;
}
current[pos++] = pstrdup(e->d_name,-1);
}
closedir(d);
#endif
if( a == NULL ) a = hl_alloc_array(&hlt_bytes,0);
a->size = pos;
return a;
}
HL_PRIM vbyte *hl_sys_full_path( vbyte *path ) {
#if defined(HL_WIN)
pchar out[MAX_PATH+1];
int len, i, last;
HANDLE handle;
WIN32_FIND_DATA data;
const char sep = '\\';
if( GetFullPathNameW((pchar*)path,MAX_PATH+1,out,NULL) == 0 )
return NULL;
len = (int)ustrlen(out);
i = 0;
if (len >= 2 && out[1] == ':') {
// convert drive letter to uppercase
if (out[0] >= 'a' && out[0] <= 'z')
out[0] += (pchar)('A' - 'a');
if (len >= 3 && out[2] == sep)
i = 3;
else
i = 2;
}
last = i;
while (i < len) {
// skip until separator
while (i < len && out[i] != sep)
i++;
// temporarily strip string to last found component
out[i] = 0;
// get actual file/dir name with proper case
if ((handle = FindFirstFileW(out, &data)) != INVALID_HANDLE_VALUE) {
// replace the component with proper case
memcpy(out + last, data.cFileName, i - last);
FindClose(handle);
}
// if we're not at the end, restore the path
if (i < len)
out[i] = sep;
// advance
i++;
last = i;
}
return (vbyte*)pstrdup(out,len);
#else
pchar buf[PATH_MAX];
if( realpath((pchar*)path,buf) == NULL )
return NULL;
return (vbyte*)pstrdup(buf,-1);
#endif
}
HL_PRIM vbyte *hl_sys_exe_path() {
#if defined(HL_WIN)
pchar path[MAX_PATH];
if( GetModuleFileNameW(NULL,path,MAX_PATH) == 0 )
return NULL;
return (vbyte*)pstrdup(path,-1);
#elif defined(HL_MAC)
pchar path[PATH_MAX+1];
uint32_t path_len = PATH_MAX;
if( _NSGetExecutablePath(path, &path_len) )
return NULL;
return (vbyte*)pstrdup(path,-1);
#elif defined(HL_CONSOLE)
return sys_exe_path();
#else
const pchar *p = getenv("_");
if( p != NULL )
return (vbyte*)pstrdup(p,-1);
{
pchar path[PATH_MAX];
int length = readlink("/proc/self/exe", path, sizeof(path));
if( length < 0 )
return NULL;
path[length] = '\0';
return (vbyte*)pstrdup(path,-1);
}
#endif
}
HL_PRIM int hl_sys_get_char( bool b ) {
# if defined(HL_WIN_DESKTOP)
return b?getche():getch();
# elif defined(HL_CONSOLE)
return -1;
# else
// took some time to figure out how to do that
// without relying on ncurses, which clear the
// terminal on initscr()
int c;
struct termios term, old;
tcgetattr(fileno(stdin), &old);
term = old;
cfmakeraw(&term);
tcsetattr(fileno(stdin), 0, &term);
c = getchar();
tcsetattr(fileno(stdin), 0, &old);
if( b ) fputc(c,stdout);
return c;
# endif
}
static pchar **sys_args;
static int sys_nargs;
HL_PRIM varray *hl_sys_args() {
varray *a = hl_alloc_array(&hlt_bytes,sys_nargs);
int i;
for(i=0;i<sys_nargs;i++)
hl_aptr(a,pchar*)[i] = sys_args[i];
return a;
}
static void *hl_file = NULL;
HL_PRIM void hl_sys_init(void **args, int nargs, void *hlfile) {
sys_args = (pchar**)args;
sys_nargs = nargs;
hl_file = hlfile;
# ifdef HL_WIN_DESKTOP
setlocale(LC_CTYPE, ""); // printf to current locale
# endif
}
HL_PRIM vbyte *hl_sys_hl_file() {
return (vbyte*)hl_file;
}
static void *reload_fun = NULL;
static void *reload_param = NULL;
HL_PRIM void hl_setup_reload_check( void *freload, void *param ) {
reload_fun = freload;
reload_param = param;
}
HL_PRIM bool hl_sys_check_reload( vbyte *debug_alt_file ) {
if( debug_alt_file && reload_param ) {
*((vbyte**)reload_param) = debug_alt_file;
}
return reload_fun && ((bool(*)(void*))reload_fun)(reload_param);
}
extern int hl_closure_stack_capture;
HL_PRIM bool hl_sys_has_debugger() {
return hl_closure_stack_capture != 0;
}
#ifndef HL_MOBILE
const char *hl_sys_special( const char *key ) {
hl_error("Unknown sys_special key");
return NULL;
}
DEFINE_PRIM(_BYTES, sys_special, _BYTES);
#endif
DEFINE_PRIM(_BYTES, sys_hl_file, _NO_ARG);
DEFINE_PRIM(_BOOL, sys_utf8_path, _NO_ARG);
DEFINE_PRIM(_BYTES, sys_string, _NO_ARG);
DEFINE_PRIM(_BYTES, sys_locale, _NO_ARG);
DEFINE_PRIM(_VOID, sys_print, _BYTES);
DEFINE_PRIM(_VOID, sys_exit, _I32);
DEFINE_PRIM(_F64, sys_time, _NO_ARG);
DEFINE_PRIM(_BYTES, sys_get_env, _BYTES);
DEFINE_PRIM(_BOOL, sys_put_env, _BYTES _BYTES);
DEFINE_PRIM(_ARR, sys_env, _NO_ARG);
DEFINE_PRIM(_VOID, sys_sleep, _F64);
DEFINE_PRIM(_BOOL, sys_set_time_locale, _BYTES);
DEFINE_PRIM(_BYTES, sys_get_cwd, _NO_ARG);
DEFINE_PRIM(_BOOL, sys_set_cwd, _BYTES);
DEFINE_PRIM(_BOOL, sys_is64, _NO_ARG);
DEFINE_PRIM(_I32, sys_command, _BYTES);
DEFINE_PRIM(_BOOL, sys_exists, _BYTES);
DEFINE_PRIM(_BOOL, sys_delete, _BYTES);
DEFINE_PRIM(_BOOL, sys_rename, _BYTES _BYTES);
DEFINE_PRIM(_ARR, sys_stat, _BYTES);
DEFINE_PRIM(_BOOL, sys_is_dir, _BYTES);
DEFINE_PRIM(_BOOL, sys_create_dir, _BYTES _I32);
DEFINE_PRIM(_BOOL, sys_remove_dir, _BYTES);
DEFINE_PRIM(_F64, sys_cpu_time, _NO_ARG);
DEFINE_PRIM(_F64, sys_thread_cpu_time, _NO_ARG);
DEFINE_PRIM(_ARR, sys_read_dir, _BYTES);
DEFINE_PRIM(_BYTES, sys_full_path, _BYTES);
DEFINE_PRIM(_BYTES, sys_exe_path, _NO_ARG);
DEFINE_PRIM(_I32, sys_get_char, _BOOL);
DEFINE_PRIM(_ARR, sys_args, _NO_ARG);
DEFINE_PRIM(_I32, sys_getpid, _NO_ARG);
DEFINE_PRIM(_BOOL, sys_check_reload, _BYTES);
DEFINE_PRIM(_VOID, sys_profile_event, _I32 _BYTES _I32);
DEFINE_PRIM(_I32, sys_set_flags, _I32);
DEFINE_PRIM(_BOOL, sys_has_debugger, _NO_ARG);

View File

@ -0,0 +1,242 @@
/*
* Copyright (C)2005-2018 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <hl.h>
#if defined(HL_MOBILE) && defined(HL_ANDROID)
#ifndef HL_ANDROID_ACTIVITY
# define HL_ANDROID_ACTIVITY "org/haxe/HashLinkActivity"
#endif
#include <jni.h>
#include <android/log.h>
#include <pthread.h>
#include <sys/types.h>
#include <unistd.h>
#ifndef HL_JNI_LOG_TAG
#define HL_JNI_LOG_TAG "HL_JNI"
#endif
#define HL_ANDROID_EXTERNAL_STORAGE_NOT_MOUNTED (0)
#define HL_ANDROID_EXTERNAL_STORAGE_MOUNTED_RO (1)
#define HL_ANDROID_EXTERNAL_STORAGE_MOUNTED_RW (2 | HL_ANDROID_EXTERNAL_STORAGE_MOUNTED_RO)
/* #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,HL_JNI_LOG_TAG,__VA_ARGS__) */
/* #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,HL_JNI_LOG_TAG,__VA_ARGS__) */
#define LOGI(...) do {} while (0)
#define LOGE(...) do {} while (0)
/* Forward declaration for JNI thread management */
static void hl_android_jni_thread_destructor(void*);
/* pthread key for proper JVM thread handling */
static pthread_key_t hl_java_thread_key;
/* Java VM reference */
static JavaVM* hl_java_vm;
/* Main activity */
static jclass hl_java_activity_class;
/* Method signatures */
static jmethodID hl_java_method_id_get_context;
/* Paths */
static char *hl_android_external_files_path = NULL;
static char *hl_android_internal_files_path = NULL;
/* Function to retrieve JNI environment, and dealing with threading */
static JNIEnv* hl_android_jni_get_env(void)
{
/* Always try to attach if calling from a non-attached thread */
JNIEnv *env;
if((*hl_java_vm)->AttachCurrentThread(hl_java_vm, &env, NULL) < 0) {
LOGE("failed to attach current thread");
return 0;
}
pthread_setspecific(hl_java_thread_key, (void*) env);
return env;
}
/* JNI_OnLoad is automatically called when loading shared library through System.loadLibrary() Java call */
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved)
{
JNIEnv *env;
jclass cls;
hl_java_vm = vm;
if ((*hl_java_vm)->GetEnv(hl_java_vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) {
__android_log_print(ANDROID_LOG_ERROR, HL_JNI_LOG_TAG, "Failed to get the environment using GetEnv()");
return -1;
}
/* Create pthread "destructor" pthread key to detach properly all threads */
if (pthread_key_create(&hl_java_thread_key, hl_android_jni_thread_destructor) != 0) {
__android_log_print(ANDROID_LOG_ERROR, HL_JNI_LOG_TAG, "Error initializing pthread key");
}
/* Make sure we are attached (we should) and setup pthread destructor */
env = hl_android_jni_get_env();
/* Try to retrieve local reference to our Activity class */
cls = (*env)->FindClass(env, HL_ANDROID_ACTIVITY);
if (!cls) {
__android_log_print(ANDROID_LOG_ERROR, HL_JNI_LOG_TAG, "Error cannot find HashLink Activity class");
}
/* Create a global reference for our Activity class */
hl_java_activity_class = (jclass)((*env)->NewGlobalRef(env, cls));
/* Retrieve the getContext() method id */
hl_java_method_id_get_context = (*env)->GetStaticMethodID(env, hl_java_activity_class, "getContext","()Landroid/content/Context;");
if (!hl_java_method_id_get_context) {
__android_log_print(ANDROID_LOG_ERROR, HL_JNI_LOG_TAG, "Error cannot get getContext() method on specified Activity class (not an Activity ?)");
}
return JNI_VERSION_1_4;
}
static void hl_android_jni_thread_destructor(void* value)
{
/* The thread is being destroyed, detach it from the Java VM and set the hl_java_thread_key value to NULL as required */
JNIEnv *env = (JNIEnv*) value;
if (env != NULL) {
(*hl_java_vm)->DetachCurrentThread(hl_java_vm);
pthread_setspecific(hl_java_thread_key, NULL);
}
}
static int hl_sys_android_get_external_storage_state(void)
{
jmethodID mid;
jclass cls;
jstring stateString;
const char *state;
int status = HL_ANDROID_EXTERNAL_STORAGE_NOT_MOUNTED;
JNIEnv *env = hl_android_jni_get_env();
if (!env) {
LOGE("Couldn't get Android JNIEnv !");
return status;
}
cls = (*env)->FindClass(env, "android/os/Environment");
mid = (*env)->GetStaticMethodID(env, cls, "getExternalStorageState", "()Ljava/lang/String;");
stateString = (jstring)(*env)->CallStaticObjectMethod(env, cls, mid);
if (!stateString) {
LOGE("Call to getExternalStorageState failed");
return status;
}
state = (*env)->GetStringUTFChars(env, stateString, NULL);
if (strcmp(state, "mounted") == 0) {
status = HL_ANDROID_EXTERNAL_STORAGE_MOUNTED_RW;
} else if (strcmp(state, "mounted_ro") == 0) {
status = HL_ANDROID_EXTERNAL_STORAGE_MOUNTED_RO;
}
(*env)->ReleaseStringUTFChars(env, stateString, state);
return status;
}
static char* hl_sys_android_get_absolute_path_from(const char* method, const char* signature)
{
jmethodID mid;
jobject context;
jobject fileObject;
jstring pathString;
const char *path;
char* retrievedPath = NULL;
JNIEnv *env = hl_android_jni_get_env();
if (!env) {
LOGE("Couldn't get Android JNIEnv !");
return NULL;
}
context = (*env)->CallStaticObjectMethod(env, hl_java_activity_class, hl_java_method_id_get_context);
if (!context) {
LOGE("Couldn't get Android context!");
return NULL;
}
mid = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, context), method, signature);
fileObject = (*env)->CallObjectMethod(env, context, mid, NULL);
if (!fileObject) {
LOGE("Couldn't call %s%s on the specified context", method, signature);
return NULL;
}
mid = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, fileObject), "getAbsolutePath", "()Ljava/lang/String;");
pathString = (jstring)(*env)->CallObjectMethod(env, fileObject, mid);
if (!pathString) {
LOGE("Couldn't retrieve absolute path");
return NULL;
}
/* Retrieve as C string */
path = (*env)->GetStringUTFChars(env, pathString, NULL);
retrievedPath = strdup(path);
(*env)->ReleaseStringUTFChars(env, pathString, path);
return retrievedPath;
}
static const char* hl_sys_android_get_external_storage_path(void)
{
/* Make sure external storage is mounted (at least read-only) */
if (hl_sys_android_get_external_storage_state()==HL_ANDROID_EXTERNAL_STORAGE_NOT_MOUNTED)
return NULL;
if (!hl_android_external_files_path) {
hl_android_external_files_path = hl_sys_android_get_absolute_path_from("getExternalFilesDir", "(Ljava/lang/String;)Ljava/io/File;");
}
return hl_android_external_files_path;
}
static const char* hl_sys_android_get_internal_storage_path(void)
{
/* Internal storage is always available */
if (!hl_android_internal_files_path) {
hl_android_internal_files_path = hl_sys_android_get_absolute_path_from("getFilesDir", "(Ljava/lang/String;)Ljava/io/File;");
}
return hl_android_internal_files_path;
}
const char *hl_sys_special( const char *key ) {
if (strcmp(key, "android_external_storage_path")==0)
return hl_sys_android_get_external_storage_path();
else if (strcmp(key, "android_internal_storage_path")==0)
return hl_sys_android_get_internal_storage_path();
else
hl_error("Unknown sys_special key");
return NULL;
}
DEFINE_PRIM(_BYTES, sys_special, _BYTES);
#endif

View File

@ -0,0 +1,73 @@
/*
* Copyright (C)2005-2018 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <hl.h>
#if defined(HL_MOBILE) && defined(HL_IOS)
#include <sys/utsname.h>
#include <Foundation/Foundation.h>
#include <UIKit/UIKit.h>
static const char* ios_get_document_path()
{
NSString* string = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
const char* path = strdup([string fileSystemRepresentation]);
return path;
}
static const char* ios_get_resource_path()
{
NSString* string = [[NSBundle mainBundle] resourcePath];
const char* path = strdup([string UTF8String]);
return path;
}
static const char* ios_get_device_name()
{
struct utsname systemInfo;
uname(&systemInfo);
return strdup(systemInfo.machine);
}
static int ios_get_retina_scale_factor()
{
return [[UIScreen mainScreen] scale];
}
const char *hl_sys_special( const char *key ) {
if (strcmp(key, "ios_resource_path")==0)
return ios_get_resource_path();
else if (strcmp(key, "ios_document_path")==0)
return ios_get_document_path();
else if (strcmp(key, "ios_retina_scale_factor")==0)
return ios_get_retina_scale_factor();
else if (strcmp(key, "ios_device_name")==0)
return ios_get_device_name();
else
hl_error("Unknown sys_special key");
return NULL;
}
DEFINE_PRIM(_BYTES, sys_special, _BYTES);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,299 @@
/*
* Copyright (C)2005-2017 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "hl.h"
#include <stdio.h>
static int track_depth = 10;
static int max_depth = 0;
#ifdef HL_TRACK_ENABLE
hl_track_info hl_track = {0};
#endif
typedef enum {
KALLOC,
KCAST,
KDYNFIELD,
KDYNCALL,
_KLAST
} bucket_kind;
typedef struct {
hl_type *t;
void **stack;
int stack_count;
int hit_count;
int info;
} bucket;
typedef struct {
unsigned int *hashes;
bucket *buckets;
int bcount;
int max_buckets;
unsigned int prev_hash;
unsigned int prev_hash2;
bucket *prev_b;
bucket *prev_b2;
} bucket_list;
static bucket_list all_data[_KLAST] = {{0}};
static hl_mutex *track_lock = NULL;
int hl_internal_capture_stack( void **stack, int size );
static bucket *bucket_find_insert( bucket_list *data, unsigned int hash, void **stack, int count ) {
int min = 0, mid;
int max = data->bcount;
bucket *b;
while( min < max ) {
mid = (min + max) >> 1;
if( data->hashes[mid] < hash )
min = mid + 1;
else if( data->hashes[mid] > hash )
max = mid;
else {
b = data->buckets + mid;
if( b->stack_count != count ) {
if( b->stack_count < count )
min = mid + 1;
else
max = mid;
} else {
int i;
for(i=0;i<count;i++)
if( b->stack[i] != stack[i] ) {
if( b->stack[i] < stack[i] )
min = mid + 1;
else
max = mid;
break;
}
if( i == count )
return b;
}
}
}
mid = (min + max) >> 1;
if( data->bcount == data->max_buckets ) {
int nbuckets = data->max_buckets ? data->max_buckets << 1 : 256;
bucket *bnew = (bucket*)malloc(sizeof(bucket)*nbuckets);
unsigned int *hnew = (unsigned int*)malloc(sizeof(int)*nbuckets);
memcpy(bnew,data->buckets,data->bcount*sizeof(bucket));
memcpy(hnew,data->hashes,data->bcount*sizeof(int));
free(data->buckets);
free(data->hashes);
data->buckets = bnew;
data->hashes = hnew;
data->max_buckets = nbuckets;
}
b = data->buckets + mid;
if( data->hashes[mid] == hash && b->stack_count == count ) {
int i;
for(i=0;i<count;i++)
if( b->stack[i] != stack[i] )
break;
if( i == count )
return b;
}
memmove(data->buckets + (mid + 1), data->buckets + mid, (data->bcount - mid) * sizeof(bucket));
memmove(data->hashes + (mid + 1), data->hashes + mid, (data->bcount - mid) * sizeof(int));
memset(b, 0, sizeof(bucket));
b->stack = malloc(sizeof(void*)*count);
memcpy(b->stack, stack, sizeof(void*)*count);
b->stack_count = count;
data->hashes[mid] = hash;
data->bcount++;
return b;
}
static void init_lock() {
hl_thread_info *tinf = hl_get_thread();
int flags = tinf->flags;
tinf->flags &= ~(HL_TRACK_ALLOC<<HL_TREAD_TRACK_SHIFT);
track_lock = hl_mutex_alloc(true);
hl_add_root(&track_lock);
tinf->flags = flags;
}
static bucket *fetch_bucket( bucket_kind kind ) {
int count, i;
unsigned int hash;
hl_thread_info *tinf = hl_get_thread();
bucket_list *data = &all_data[kind];
bucket *b;
if( track_lock == NULL ) init_lock();
count = hl_internal_capture_stack(tinf->exc_stack_trace,track_depth);
if( count > max_depth ) max_depth = count;
hash = -count;
for(i=0;i<count;i++)
hash = (hash * 31) + (((unsigned int)(int_val)tinf->exc_stack_trace[i]) >> 1);
// look for bucket
hl_mutex_acquire(track_lock);
if( hash == data->prev_hash && data->prev_b ) {
b = data->prev_b;
} else if( hash == data->prev_hash2 && data->prev_b2 ) {
b = data->prev_b2;
} else {
b = bucket_find_insert(data, hash, tinf->exc_stack_trace, count);
data->prev_hash2 = data->prev_hash;
data->prev_b2 = data->prev_b;
data->prev_hash = hash;
data->prev_b = b;
}
return b;
}
static void on_alloc( hl_type *t, int size, int flags, void *ptr ) {
bucket *b = fetch_bucket(KALLOC);
b->t = t;
b->hit_count++;
b->info += size;
hl_mutex_release(track_lock);
}
static void on_cast( hl_type *t1, hl_type *t2 ) {
bucket *b = fetch_bucket(KCAST);
b->t = t1;
b->hit_count++;
b->info = t2->kind;
hl_mutex_release(track_lock);
}
static void on_dynfield( vdynamic *d, int hfield ) {
bucket *b = fetch_bucket(KDYNFIELD);
b->t = d?d->t:&hlt_dyn;
b->hit_count++;
b->info = hfield;
hl_mutex_release(track_lock);
}
static void on_dyncall( vdynamic *d, int hfield ) {
bucket *b = fetch_bucket(KDYNCALL);
b->t = d?d->t:&hlt_dyn;
b->hit_count++;
b->info = hfield;
hl_mutex_release(track_lock);
}
HL_PRIM void hl_track_init() {
#ifdef HL_TRACK_ENABLE
char *env = getenv("HL_TRACK");
if( env )
hl_track.flags = atoi(env);
hl_track.on_alloc = on_alloc;
hl_track.on_cast = on_cast;
hl_track.on_dynfield = on_dynfield;
hl_track.on_dyncall = on_dyncall;
#endif
}
HL_PRIM void hl_track_lock( bool lock ) {
#ifdef HL_TRACK_ENABLE
if( !track_lock ) init_lock();
if( lock )
hl_mutex_acquire(track_lock);
else
hl_mutex_release(track_lock);
#endif
}
HL_PRIM int hl_track_count( int *depth ) {
int value = 0;
int i;
for(i=0;i<_KLAST;i++)
value += all_data[i].bcount;
*depth = max_depth;
return value;
}
HL_PRIM int hl_track_entry( int id, hl_type **t, int *count, int *info, varray *stack ) {
static bucket_list *cur = NULL;
static int prev_id = -10;
static int count_before = 0;
bucket *b = NULL;
if( id == prev_id + 1 ) {
if( id - count_before == cur->bcount ) {
if( cur - all_data == _KLAST ) return -1;
count_before += cur->bcount;
cur++;
}
b = cur->buckets + (id - count_before);
prev_id++;
} else {
int i;
count_before = 0;
for(i=0;i<_KLAST;i++) {
bucket_list *data = &all_data[i];
if( id - count_before < data->bcount ) break;
count_before += data->bcount;
}
if( i == _KLAST ) return -1; // out of range
prev_id = id;
cur = &all_data[i];
b = cur->buckets;
}
*t = b->t;
*count = b->hit_count;
*info = b->info;
stack->size = b->stack_count;
memcpy(hl_aptr(stack,void*), b->stack, b->stack_count * sizeof(void*));
return (int)(cur - all_data);
}
HL_PRIM int hl_track_get_bits( bool thread ) {
# ifdef HL_TRACK_ENABLE
return (thread ? (hl_get_thread()->flags>>HL_TREAD_TRACK_SHIFT) : hl_track.flags) & HL_TRACK_MASK;
# else
return 0;
# endif
}
HL_PRIM void hl_track_set_depth( int d ) {
track_depth = d;
}
HL_PRIM void hl_track_set_bits( int flags, bool thread ) {
# ifdef HL_TRACK_ENABLE
if( thread ) {
hl_thread_info *t = hl_get_thread();
if( t ) t->flags = (t->flags & ~(HL_TRACK_MASK<<HL_TREAD_TRACK_SHIFT)) | ((flags & HL_TRACK_MASK) << HL_TREAD_TRACK_SHIFT);
} else {
hl_track.flags = (hl_track.flags & ~HL_TRACK_MASK) | (flags & HL_TRACK_MASK);
}
# endif
}
HL_PRIM void hl_track_reset() {
int i;
for(i=0;i<_KLAST;i++)
all_data[i].bcount = 0;
}
DEFINE_PRIM(_VOID, track_init, _NO_ARG);
DEFINE_PRIM(_I32, track_count, _REF(_I32));
DEFINE_PRIM(_I32, track_entry, _I32 _REF(_TYPE) _REF(_I32) _REF(_I32) _ARR);
DEFINE_PRIM(_VOID, track_lock, _BOOL);
DEFINE_PRIM(_VOID, track_set_depth, _I32);
DEFINE_PRIM(_I32, track_get_bits, _BOOL);
DEFINE_PRIM(_VOID, track_set_bits, _I32 _BOOL);
DEFINE_PRIM(_VOID, track_reset, _NO_ARG);

View File

@ -0,0 +1,973 @@
/*
* Copyright (C)2005-2016 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <hl.h>
HL_PRIM hl_type hlt_array = { HARRAY };
HL_PRIM hl_type hlt_bytes = { HBYTES };
HL_PRIM hl_type hlt_dynobj = { HDYNOBJ };
HL_PRIM hl_type hlt_dyn = { HDYN };
HL_PRIM hl_type hlt_i32 = { HI32 };
HL_PRIM hl_type hlt_i64 = { HI64 };
HL_PRIM hl_type hlt_f32 = { HF32 };
HL_PRIM hl_type hlt_f64 = { HF64 };
HL_PRIM hl_type hlt_void = { HVOID };
HL_PRIM hl_type hlt_bool = { HBOOL };
HL_PRIM hl_type hlt_abstract = { HABSTRACT, {USTR("<abstract>")} };
static const uchar *TSTR[] = {
USTR("void"), USTR("i8"), USTR("i16"), USTR("i32"), USTR("i64"), USTR("f32"), USTR("f64"),
USTR("bool"), USTR("bytes"), USTR("dynamic"), NULL, NULL,
USTR("array"), USTR("type"), NULL, NULL, USTR("dynobj"),
NULL, NULL, NULL, NULL, NULL, NULL
};
static int T_SIZES[] = {
0, // VOID
1, // I8
2, // I16
4, // I32
8, // I64
4, // F32
8, // F64
sizeof(bool), // BOOL
HL_WSIZE, // BYTES
HL_WSIZE, // DYN
HL_WSIZE, // FUN
HL_WSIZE, // OBJ
HL_WSIZE, // ARRAY
HL_WSIZE, // TYPE
HL_WSIZE, // REF
HL_WSIZE, // VIRTUAL
HL_WSIZE, // DYNOBJ
HL_WSIZE, // ABSTRACT
HL_WSIZE, // ENUM
HL_WSIZE, // NULL
HL_WSIZE, // METHOD
HL_WSIZE, // STRUCT
0, // PACKED
};
HL_PRIM int hl_type_size( hl_type *t ) {
return T_SIZES[t->kind];
}
HL_PRIM int hl_pad_struct( int size, hl_type *t ) {
int align = sizeof(void*);
# define GET_ALIGN(type) { struct { unsigned char a; type b; } s = {0}; align = (int)((unsigned char *)&s.b - (unsigned char*)&s); }
switch( t->kind ) {
case HVOID:
return 0;
case HUI8:
GET_ALIGN(unsigned char);
break;
case HUI16:
GET_ALIGN(unsigned short);
break;
case HI32:
GET_ALIGN(unsigned int);
break;
case HI64:
GET_ALIGN(int64);
break;
case HF32:
GET_ALIGN(float);
break;
case HF64:
GET_ALIGN(double);
break;
case HBOOL:
GET_ALIGN(bool);
break;
default:
break;
}
return (-size) & (align - 1);
}
HL_PRIM bool hl_same_type( hl_type *a, hl_type *b ) {
if( a == b )
return true;
if( a->kind != b->kind )
return false;
switch( a->kind ) {
case HVOID:
case HUI8:
case HUI16:
case HI32:
case HI64:
case HF32:
case HF64:
case HBOOL:
case HTYPE:
case HBYTES:
case HDYN:
case HARRAY:
case HDYNOBJ:
return true;
case HREF:
case HNULL:
case HPACKED:
return hl_same_type(a->tparam, b->tparam);
case HFUN:
case HMETHOD:
{
int i;
if( a->fun->nargs != b->fun->nargs )
return false;
for(i=0;i<a->fun->nargs;i++)
if( !hl_same_type(a->fun->args[i],b->fun->args[i]) )
return false;
return hl_same_type(a->fun->ret, b->fun->ret);
}
case HOBJ:
case HSTRUCT:
return a->obj == b->obj;
case HVIRTUAL:
return a->virt == b->virt;
case HABSTRACT:
return a->abs_name == b->abs_name;
case HENUM:
return a->tenum == b->tenum;
default:
break;
}
return false;
}
HL_PRIM bool hl_is_dynamic( hl_type *t ) {
static bool T_IS_DYNAMIC[] = {
false, // HVOID,
false, // HI8
false, // HI16
false, // HI32
false, // HI64
false, // HF32
false, // HF64
false, // HBOOL
false, // HBYTES
true, // HDYN
true, // HFUN
true, // HOBJ
true, // HARRAY
false, // HTYPE
false, // HREF
true, // HVIRTUAL
true, // HDYNOBJ
false, // HABSTRACT
true, // HENUM
true, // HNULL
false, // HMETHOD
false, // HSTRUCT
false, // HPACKED
};
return T_IS_DYNAMIC[t->kind];
}
HL_PRIM bool hl_safe_cast( hl_type *t, hl_type *to ) {
if( t == to )
return true;
if( to->kind == HDYN )
return hl_is_dynamic(t);
if( t->kind != to->kind )
return false;
switch( t->kind ) {
case HVIRTUAL:
if( to->virt->nfields < t->virt->nfields ) {
int i;
for(i=0;i<to->virt->nfields;i++) {
hl_obj_field *f1 = t->virt->fields + i;
hl_obj_field *f2 = to->virt->fields + i;
if( f1->hashed_name != f2->hashed_name || !hl_same_type(f1->t,f2->t) )
break;
}
if( i == to->virt->nfields )
return true;
}
break;
case HOBJ:
case HSTRUCT:
{
hl_type_obj *o = t->obj;
hl_type_obj *oto = to->obj;
while( true ) {
if( o == oto ) return true;
if( o->super == NULL ) return false;
o = o->super->obj;
}
}
case HFUN:
case HMETHOD:
if( t->fun->nargs == to->fun->nargs ) {
int i;
if( !hl_safe_cast(t->fun->ret,to->fun->ret) )
return false;
for(i=0;i<t->fun->nargs;i++) {
hl_type *t1 = t->fun->args[i];
hl_type *t2 = to->fun->args[i];
if( !hl_safe_cast(t2,t1) && (t1->kind != HDYN || !hl_is_dynamic(t2)) )
return false;
}
return true;
}
break;
case HPACKED:
return hl_safe_cast(t->tparam, to);
default:
break;
}
return hl_same_type(t,to);
}
typedef struct tlist {
hl_type *t;
struct tlist *next;
} tlist;
static void hl_type_str_rec( hl_buffer *b, hl_type *t, tlist *parents ) {
const uchar *c = TSTR[t->kind];
tlist *l, cur;
int i;
if( c != NULL ) {
hl_buffer_str(b,c);
return;
}
l = parents;
while( l ) {
if( l->t == t ) {
hl_buffer_str(b,USTR("<...>"));
return;
}
l = l->next;
}
cur.t = t;
cur.next = parents;
l = &cur;
switch( t->kind ) {
case HFUN:
case HMETHOD:
hl_buffer_char(b,'(');
hl_type_str_rec(b,t->fun->ret,l);
hl_buffer_char(b,' ');
hl_buffer_char(b,'(');
for(i=0; i<t->fun->nargs; i++) {
if( i ) hl_buffer_char(b,',');
hl_type_str_rec(b,t->fun->args[i],l);
}
hl_buffer_char(b,')');
hl_buffer_char(b,')');
break;
case HSTRUCT:
hl_buffer_char(b,'@');
case HOBJ:
hl_buffer_str(b,t->obj->name);
break;
case HREF:
hl_buffer_str(b,USTR("ref<"));
hl_type_str_rec(b,t->tparam,l);
hl_buffer_char(b,'>');
break;
case HVIRTUAL:
hl_buffer_str(b,USTR("virtual<"));
for(i=0; i<t->virt->nfields; i++) {
hl_obj_field *f = t->virt->fields + i;
if( i ) hl_buffer_char(b,',');
hl_buffer_str(b,f->name);
hl_buffer_char(b,':');
hl_type_str_rec(b,f->t,l);
}
hl_buffer_char(b,'>');
break;
case HABSTRACT:
hl_buffer_str(b,t->abs_name);
break;
case HENUM:
hl_buffer_str(b,USTR("enum"));
if( t->tenum->name ) {
hl_buffer_char(b,'<');
hl_buffer_str(b,t->tenum->name);
hl_buffer_char(b,'>');
}
break;
case HNULL:
hl_buffer_str(b,USTR("null<"));
hl_type_str_rec(b,t->tparam,l);
hl_buffer_char(b,'>');
break;
case HPACKED:
hl_buffer_str(b, USTR("packed<"));
hl_type_str_rec(b,t->tparam,l);
hl_buffer_char(b,'>');
break;
default:
hl_buffer_str(b,USTR("???"));
break;
}
}
HL_PRIM const uchar *hl_type_str( hl_type *t ) {
const uchar *c = TSTR[t->kind];
hl_buffer *b;
if( c != NULL )
return c;
b = hl_alloc_buffer();
hl_type_str_rec(b,t,NULL);
return hl_buffer_content(b,NULL);
}
HL_PRIM vbyte* hl_type_name( hl_type *t ) {
switch( t->kind ) {
case HOBJ:
case HSTRUCT:
return (vbyte*)t->obj->name;
case HENUM:
return (vbyte*)t->tenum->name;
case HABSTRACT:
return (vbyte*)t->abs_name;
default:
break;
}
return NULL;
}
HL_PRIM int hl_mark_size( int data_size );
HL_PRIM void hl_init_enum( hl_type *et, hl_module_context *m ) {
int i, j;
int mark_size = 0;
unsigned int *mark;
for(i=0;i<et->tenum->nconstructs;i++) {
hl_enum_construct *c = et->tenum->constructs + i;
c->hasptr = false;
c->size = sizeof(void*)+sizeof(int); // t + index
for(j=0;j<c->nparams;j++) {
hl_type *t = c->params[j];
c->size += hl_pad_struct(c->size,t);
c->offsets[j] = c->size;
if( hl_is_ptr(t) ) c->hasptr = true;
c->size += hl_type_size(t);
}
if( c->hasptr ) {
int max_pos = i * sizeof(int) + hl_mark_size(c->size - HL_WSIZE*2);
if( max_pos > mark_size ) mark_size = max_pos;
}
}
mark = (unsigned int*)hl_zalloc(&m->alloc,mark_size);
for(i=0;i<et->tenum->nconstructs;i++) {
hl_enum_construct *c = et->tenum->constructs + i;
if( !c->hasptr ) continue;
for(j=0;j<c->nparams;j++)
if( hl_is_ptr(c->params[j]) ) {
int pos = (c->offsets[j] / HL_WSIZE) - 2;
mark[i + (pos >> 5)] |= 1 << (pos & 31);
}
}
et->mark_bits = mark;
}
HL_PRIM varray* hl_type_enum_fields( hl_type *t ) {
varray *a = hl_alloc_array(&hlt_bytes,t->tenum->nconstructs);
int i;
for( i=0; i<t->tenum->nconstructs;i++)
hl_aptr(a,vbyte*)[i] = (vbyte*)t->tenum->constructs[i].name;
return a;
}
HL_PRIM varray* hl_type_enum_values( hl_type *t ) {
varray *a = hl_alloc_array(&hlt_dyn,t->tenum->nconstructs);
int i;
for( i=0; i<t->tenum->nconstructs;i++) {
hl_enum_construct *c = t->tenum->constructs + i;
if(c->nparams == 0)
hl_aptr(a,venum*)[i] = hl_alloc_enum(t, i);
}
return a;
}
HL_PRIM int hl_type_args_count( hl_type *t ) {
if( t->kind == HFUN || t->kind == HMETHOD )
return t->fun->nargs;
return 0;
}
HL_PRIM varray *hl_type_instance_fields( hl_type *t ) {
varray *a;
const uchar **names;
int mcount = 0;
int out = 0;
hl_type_obj *o;
hl_runtime_obj *rt;
if( t->kind == HVIRTUAL ) {
int i;
a = hl_alloc_array(&hlt_bytes,t->virt->nfields);
names = hl_aptr(a,const uchar *);
for(i=0;i<t->virt->nfields;i++)
names[i] = t->virt->fields[i].name;
return a;
}
if( t->kind != HOBJ && t->kind != HSTRUCT )
return NULL;
o = t->obj;
while( true ) {
int i;
for(i=0;i<o->nproto;i++) {
hl_obj_proto *p = o->proto + i;
if( p->pindex < 0 ) mcount++;
}
if( o->super == NULL ) break;
o = o->super->obj;
}
rt = hl_get_obj_rt(t);
a = hl_alloc_array(&hlt_bytes,mcount + rt->nproto + rt->nfields);
names = hl_aptr(a,const uchar*);
o = t->obj;
while( true ) {
int i;
int pproto = rt->parent ? rt->parent->nproto : 0;
for(i=0;i<o->nproto;i++) {
hl_obj_proto *p = o->proto + i;
if( p->pindex < 0 || p->pindex >= pproto )
names[out++] = p->name;
}
for(i=0;i<o->nfields;i++) {
hl_obj_field *f = o->fields + i;
names[out++] = f->name;
}
if( o->super == NULL ) break;
o = o->super->obj;
rt = o->rt;
}
return a;
}
HL_PRIM hl_type *hl_type_super( hl_type *t ) {
if( (t->kind == HOBJ || t->kind == HSTRUCT) && t->obj->super )
return t->obj->super;
return &hlt_void;
}
HL_PRIM vdynamic *hl_type_get_global( hl_type *t ) {
switch( t->kind ) {
case HOBJ:
case HSTRUCT:
return t->obj->global_value ? *(vdynamic**)t->obj->global_value : NULL;
case HENUM:
return *(vdynamic**)t->tenum->global_value;
default:
break;
}
return NULL;
}
HL_PRIM bool hl_type_set_global( hl_type *t, vdynamic *v ) {
switch( t->kind ) {
case HOBJ:
case HSTRUCT:
if( t->obj->global_value ) {
*(vdynamic**)t->obj->global_value = v;
return true;
}
break;
case HENUM:
if( t->tenum->global_value ) {
*(vdynamic**)t->tenum->global_value = v;
return true;
}
break;
default:
break;
}
return false;
}
HL_PRIM bool hl_type_enum_eq( venum *a, venum *b ) {
int i;
hl_enum_construct *c;
if( a == b )
return true;
if( !a || !b || a->t != b->t )
return false;
if( a->index != b->index )
return false;
c = a->t->tenum->constructs + a->index;
for(i=0;i<c->nparams;i++) {
hl_type *t = c->params[i];
switch( t->kind ) {
case HENUM:
{
venum *pa = *(venum**)((char*)a + c->offsets[i]);
venum *pb = *(venum**)((char*)b + c->offsets[i]);
if( !hl_type_enum_eq(pa,pb) )
return false;
}
break;
default:
{
vdynamic *pa = hl_make_dyn((char*)a + c->offsets[i],t);
vdynamic *pb = hl_make_dyn((char*)b + c->offsets[i],t);
if( pa && pb && pa->t->kind == HENUM && pb->t->kind == HENUM ) {
if( !hl_type_enum_eq((venum*)pa,(venum*)pb) )
return false;
continue;
}
if( hl_dyn_compare(pa,pb) )
return false;
}
break;
}
}
return true;
}
HL_PRIM venum *hl_alloc_enum( hl_type *t, int index ) {
hl_enum_construct *c = t->tenum->constructs + index;
venum *v = (venum*)hl_gc_alloc_gen(t, c->size, MEM_KIND_DYNAMIC | (c->hasptr ? 0 : MEM_KIND_NOPTR) | MEM_ZERO);
v->t = t;
v->index = index;
return v;
}
HL_PRIM venum *hl_alloc_enum_dyn( hl_type *t, int index, varray *args, int nargs ) {
hl_enum_construct *c = t->tenum->constructs + index;
venum *e;
int i;
if( c->nparams < nargs || args->size < nargs )
return NULL;
if( nargs < c->nparams ) {
// allow missing params if they are null-able
for(i=nargs;i<c->nparams;i++)
if( !hl_is_ptr(c->params[i]) )
return NULL;
}
e = hl_alloc_enum(t, index);
for(i=0;i<nargs;i++)
hl_write_dyn((char*)e+c->offsets[i],c->params[i],hl_aptr(args,vdynamic*)[i],false);
return e;
}
HL_PRIM varray *hl_enum_parameters( venum *e ) {
varray *a;
hl_enum_construct *c = e->t->tenum->constructs + e->index;
int i;
a = hl_alloc_array(&hlt_dyn,c->nparams);
for(i=0;i<c->nparams;i++)
hl_aptr(a,vdynamic*)[i] = hl_make_dyn((char*)e+c->offsets[i],c->params[i]);
return a;
}
DEFINE_PRIM(_BYTES, type_str, _TYPE);
DEFINE_PRIM(_BYTES, type_name, _TYPE);
DEFINE_PRIM(_I32, type_args_count, _TYPE);
DEFINE_PRIM(_ARR, type_instance_fields, _TYPE);
DEFINE_PRIM(_TYPE, type_super, _TYPE);
DEFINE_PRIM(_DYN, type_get_global, _TYPE);
DEFINE_PRIM(_ARR, type_enum_fields, _TYPE);
DEFINE_PRIM(_ARR, type_enum_values, _TYPE);
DEFINE_PRIM(_BOOL, type_enum_eq, _DYN _DYN);
DEFINE_PRIM(_DYN, alloc_enum_dyn, _TYPE _I32 _ARR _I32);
DEFINE_PRIM(_ARR, enum_parameters, _DYN);
DEFINE_PRIM(_BOOL, type_set_global, _TYPE _DYN);
typedef struct {
char *buf;
int buf_pos;
int buf_size;
int *offsets;
int offsets_pos;
int offsets_size;
void **lookup;
int *lookup_index;
int lookup_pos;
int lookup_size;
int *remap_target;
int remap_pos;
int remap_size;
void **todos;
int todos_pos;
int todos_size;
int flags;
} mem_context;
#define compact_grow(buf,pos,size,req,type) \
if( ctx->pos + req > ctx->size ) { \
int nsize = ctx->size; \
if( nsize == 0 ) nsize = 256 /sizeof(type); \
while( nsize < ctx->pos + req ) nsize = (nsize * 3) / 2; \
type *nbuf = (type*)malloc(nsize * sizeof(type)); \
memcpy(nbuf,ctx->buf,ctx->pos * sizeof(type)); \
free(ctx->buf); \
ctx->buf = nbuf; \
ctx->size = nsize; \
}
static void compact_write_mem( mem_context *ctx, void *mem, int size ) {
compact_grow(buf,buf_pos,buf_size,size,char);
memcpy(ctx->buf + ctx->buf_pos, mem, size);
ctx->buf_pos += size;
}
static void compact_write_ptr( mem_context *ctx, void *ptr ) {
compact_write_mem(ctx,&ptr,sizeof(void*));
}
static void compact_write_int( mem_context *ctx, int v ) {
compact_write_mem(ctx,&v,4);
}
static void compact_write_offset( mem_context *ctx, int position ) {
compact_grow(offsets,offsets_pos,offsets_size,1,int);
ctx->offsets[ctx->offsets_pos++] = ctx->buf_pos;
compact_write_ptr(ctx,(void*)(int_val)position);
}
static int compact_lookup_index( mem_context *ctx, void *addr ) {
int min = 0;
int max = ctx->lookup_pos;
while( min < max ) {
int mid = (min + max) >> 1;
void *a = ctx->lookup[mid];
if( a < addr ) min = mid + 1; else if( a > addr ) max = mid; else return mid;
}
return -1;
}
#define BYTE_MARK 0x40000000
static int compact_lookup_ref( mem_context *ctx, void *addr, bool is_bytes ) {
int min = 0;
int max = ctx->lookup_pos;
while( min < max ) {
int mid = (min + max) >> 1;
void *a = ctx->lookup[mid];
if( a < addr ) min = mid + 1; else if( a > addr ) max = mid; else return ctx->remap_target[ctx->lookup_index[mid]&~BYTE_MARK];
}
if( ctx->lookup_pos == ctx->lookup_size ) {
int nsize = ctx->lookup_size == 0 ? 128 : (ctx->lookup_size * 3) / 2;
void **nlookup = (void**)malloc(nsize * sizeof(void*));
int *nindex = (int*)malloc(nsize * sizeof(int));
memcpy(nlookup,ctx->lookup,ctx->lookup_pos * sizeof(void*));
memcpy(nindex,ctx->lookup_index,ctx->lookup_pos * sizeof(int));
free(ctx->lookup);
free(ctx->lookup_index);
ctx->lookup = nlookup;
ctx->lookup_index = nindex;
ctx->lookup_size = nsize;
}
int pos = (min + max) >> 1;
memmove(ctx->lookup + pos + 1, ctx->lookup + pos, (ctx->lookup_pos - pos) * sizeof(void*));
memmove(ctx->lookup_index + pos + 1, ctx->lookup_index + pos, (ctx->lookup_pos - pos) * sizeof(int));
int id = ctx->lookup_pos++;
ctx->lookup[pos] = addr;
ctx->lookup_index[pos] = id | (is_bytes ? BYTE_MARK : 0);
compact_grow(todos,todos_pos,todos_size,1,void*);
ctx->todos[ctx->todos_pos++] = addr;
compact_grow(remap_target,remap_pos,remap_size,1,int);
int target = -id-1;
ctx->remap_target[ctx->remap_pos++] = target;
return target;
}
static void compact_write_ref( mem_context *ctx, void *ptr, bool is_bytes ) {
if( !ptr ) {
compact_write_ptr(ctx, NULL);
return;
}
int ref = compact_lookup_ref(ctx,ptr,is_bytes);
compact_write_offset(ctx, ref);
}
static void compact_write_data( mem_context *ctx, hl_type *t, void *addr ) {
if( hl_is_dynamic(t) ) {
vdynamic *v = *(vdynamic**)addr;
if( v == NULL || (v->t->kind == HENUM && v->t->tenum->constructs[((venum*)v)->index].nparams == 0) ) {
compact_write_ptr(ctx,v);
return;
}
compact_write_ref(ctx,v,false);
return;
}
switch( t->kind ) {
case HUI8:
compact_write_mem(ctx, addr, 1);
break;
case HUI16:
compact_write_mem(ctx, addr, 2);
break;
case HI32:
case HF32:
compact_write_mem(ctx, addr, 4);
break;
case HF64:
case HI64:
compact_write_mem(ctx, addr, 8);
break;
case HBOOL:
compact_write_mem(ctx, addr, sizeof(bool));
break;
case HBYTES:
{
void *bytes = *(void**)addr;
if( bytes == NULL || !hl_is_gc_ptr(bytes) ) {
compact_write_ptr(ctx, bytes);
break;
}
compact_write_ref(ctx, bytes, true);
}
break;
case HABSTRACT:
hl_error("Unsupported abstract %s", t->abs_name);
break;
default:
hl_error("Unsupported type %d", t->kind);
break;
}
}
static void compact_pad( mem_context *ctx, hl_type *t ) {
int sz = hl_pad_size(ctx->buf_pos,t);
ctx->buf_pos += sz;
}
static void compact_write_content( mem_context *ctx, vdynamic *d ) {
int i;
hl_type *t = d->t;
if( !hl_is_ptr(t) ) {
compact_write_ptr(ctx, t);
compact_write_mem(ctx,&d->v,hl_type_size(t));
return;
}
switch( t->kind ) {
case HOBJ: {
char *obj_data = (char*)d;
hl_runtime_obj *rt = hl_get_obj_rt(t);
compact_grow(buf,buf_pos,buf_size,rt->size,char);
memset(ctx->buf + ctx->buf_pos, 0xCD, rt->size);
int buf_start = ctx->buf_pos;
int fstart = rt->nfields;
compact_write_ptr(ctx,t);
while( t ) {
fstart -= t->obj->nfields;
for(i=0;i<t->obj->nfields;i++) {
int fid = i + fstart;
ctx->buf_pos = buf_start + rt->fields_indexes[fid];
compact_write_data(ctx, t->obj->fields[i].t, obj_data + rt->fields_indexes[fid]);
}
t = t->obj->super;
}
ctx->buf_pos = buf_start + rt->size;
break;
}
case HVIRTUAL: {
vvirtual *v = (vvirtual*)d;
int start = ctx->buf_pos;
compact_write_ptr(ctx, t);
if( ctx->flags & 4 )
compact_write_offset(ctx, start); // virtual self value
else if( ctx->flags & 2 )
compact_write_ptr(ctx, NULL); // optimize virtuals
else
compact_write_data(ctx, &hlt_dyn, &v->value);
compact_write_data(ctx, &hlt_dyn, &v->next);
if( !v->value || (ctx->flags&6) ) {
int target = ctx->buf_pos + t->virt->nfields * sizeof(void*);
for(i=0;i<t->virt->nfields;i++) {
hl_type *ft = t->virt->fields[i].t;
target += hl_pad_size(target, ft);
compact_write_offset(ctx, target);
target += hl_type_size(ft);
}
for(i=0;i<t->virt->nfields;i++) {
void *addr = ((void**)(v + 1))[i];
hl_type *ft = t->virt->fields[i].t;
compact_pad(ctx,ft);
if( !addr ) {
if( !hl_is_ptr(ft) ) hl_error("assert");
compact_write_ptr(ctx,NULL);
} else
compact_write_data(ctx,ft,addr);
}
} else {
vdynobj *obj = (vdynobj*)v->value;
if( obj->t->kind != HDYNOBJ ) hl_error("assert");
int todo_save = ctx->todos_pos;
for(i=0;i<t->virt->nfields;i++) {
void *addr = ((void**)(v + 1))[i];
compact_write_ref(ctx, addr, false);
}
ctx->todos_pos = todo_save;
}
break;
}
case HDYNOBJ: {
vdynobj *obj = (vdynobj*)d;
int lookup_data = ctx->buf_pos + sizeof(vdynobj);
int raw_data = lookup_data + obj->nfields * sizeof(hl_field_lookup);
int values_data = raw_data + obj->raw_size;
values_data += hl_pad_size(values_data,&hlt_dyn);
compact_write_ptr(ctx, t);
if( obj->lookup )
compact_write_offset(ctx, lookup_data);
else
compact_write_ptr(ctx, NULL);
if( obj->raw_data )
compact_write_offset(ctx, raw_data);
else
compact_write_ptr(ctx, NULL);
if( obj->values )
compact_write_offset(ctx, values_data);
else
compact_write_ptr(ctx, NULL);
compact_write_int(ctx,obj->nfields);
compact_write_int(ctx,obj->raw_size);
compact_write_int(ctx,obj->nvalues);
# ifdef HL_64
compact_write_int(ctx,0);
# endif
compact_write_ref(ctx,obj->virtuals,false);
if( obj->lookup )
compact_write_mem(ctx,obj->lookup,sizeof(hl_field_lookup) * obj->nfields);
if( obj->raw_data )
compact_write_mem(ctx,obj->raw_data,obj->raw_size);
if( obj->values ) {
compact_pad(ctx,&hlt_dyn);
for(i=0;i<obj->nvalues;i++) {
int j;
for(j=0;i<obj->nfields;j++) {
if( obj->lookup[j].field_index == i && hl_is_ptr(obj->lookup[j].t) ) {
compact_write_data(ctx, obj->lookup[j].t, obj->values + i);
break;
}
}
}
}
int save_pos = ctx->todos_pos;
for(i=0;i<obj->nfields;i++) {
hl_field_lookup *f = obj->lookup + i;
int idx = compact_lookup_ref(ctx, hl_is_ptr(f->t) ? (char*)(obj->values + f->field_index) : (char*)(obj->raw_data + f->field_index), false);
idx = -idx-1;
ctx->remap_target[idx] = hl_is_ptr(f->t) ? values_data + sizeof(void*)*f->field_index : raw_data + f->field_index;
}
ctx->todos_pos = save_pos;
break;
}
case HARRAY: {
varray *a = (varray*)d;
compact_write_ptr(ctx, a->t);
compact_write_ptr(ctx, a->at);
compact_write_int(ctx, a->size);
compact_write_int(ctx, 0);
char *array_data = (char*)(a + 1);
int stride = hl_type_size(a->at);
for(i=0;i<a->size;i++) {
compact_write_data(ctx,a->at, array_data + stride * i);
}
break;
}
case HENUM: {
venum *e = (venum*)d;
hl_enum_construct *c = &t->tenum->constructs[e->index];
int buf_start = ctx->buf_pos;
compact_write_ptr(ctx, e->t);
compact_write_int(ctx, e->index);
for(i=0;i<c->nparams;i++) {
compact_pad(ctx,c->params[i]);
compact_write_data(ctx,c->params[i],(char*)e+(ctx->buf_pos-buf_start));
}
break;
}
default:
hl_error("Unsupported type %d", t->kind);
}
}
HL_PRIM vdynamic *hl_mem_compact( vdynamic *d, varray *exclude, int flags, int *outCount ) {
mem_context _ctx;
mem_context *ctx = &_ctx;
int i;
int object_count = 0;
memset(ctx,0,sizeof(mem_context));
ctx->flags = flags;
compact_lookup_ref(ctx,d,false);
if( exclude ) {
for(i=0;i<exclude->size;i++) {
vdynamic *ptr = (vdynamic*)hl_aptr(exclude,void*)[i];
compact_lookup_ref(ctx,ptr,false);
ctx->todos_pos--;
}
}
while( ctx->todos_pos > 0 ) {
void *addr = ctx->todos[--ctx->todos_pos];
int pos = compact_lookup_index(ctx, addr);
int index = ctx->lookup_index[pos];
compact_pad(ctx, &hlt_dyn);
ctx->remap_target[index&~BYTE_MARK] = ctx->buf_pos;
if( index & BYTE_MARK ) {
int size = hl_gc_get_memsize(addr);
if( size < 0 ) hl_error("assert");
compact_write_mem(ctx, addr, size);
} else
compact_write_content(ctx, (vdynamic*)addr);
object_count++;
}
vbyte *data = NULL;
# ifdef HL_WIN
if( flags & 1 )
data = (vbyte*)VirtualAlloc(NULL,ctx->buf_pos,MEM_COMMIT|MEM_RESERVE,PAGE_READWRITE);
# endif
if( data == NULL )
data = hl_gc_alloc_noptr(ctx->buf_pos);
memcpy(data,ctx->buf,ctx->buf_pos);
int exclude_count = exclude ? exclude->size : 0;
for(i=0;i<ctx->offsets_pos;i++) {
int pos = ctx->offsets[i];
int target = *(int*)(data + pos);
if( target < 0 ) {
int eid = -target-1;
if( eid > 0 && eid <= exclude_count ) {
*(void**)(data+pos) = hl_aptr(exclude,void*)[eid-1];
continue;
}
target = ctx->remap_target[eid];
}
*(void**)(data+pos) = data + target;
}
free(ctx->buf);
free(ctx->offsets);
free(ctx->lookup);
free(ctx->lookup_index);
free(ctx->remap_target);
free(ctx->todos);
# ifdef HL_WIN
if( flags & 1 ) {
DWORD old = 0;
VirtualProtect(data,ctx->buf_pos,PAGE_READONLY,&old);
}
# endif
if( outCount )
*outCount = object_count;
return (vdynamic*)data;
}
DEFINE_PRIM(_DYN, mem_compact, _DYN _ARR _I32 _REF(_I32));

View File

@ -0,0 +1,274 @@
/*
* Copyright (C)2005-2016 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <hl.h>
#include <stdarg.h>
#ifndef HL_NATIVE_UCHAR_FUN
#ifdef HL_ANDROID
# include <android/log.h>
# ifndef HL_ANDROID_LOG_TAG
# define HL_ANDROID_LOG_TAG "hl"
# endif
# ifndef HL_ANDROID_LOG_LEVEL
# define HL_ANDROID_LOG_LEVEL ANDROID_LOG_DEBUG
# endif
# define LOG_ANDROID(cfmt,cstr) __android_log_print(HL_ANDROID_LOG_LEVEL, HL_ANDROID_LOG_TAG, cfmt, cstr);
#endif
int ustrlen( const uchar *str ) {
const uchar *p = str;
while( *p ) p++;
return (int)(p - str);
}
static int ustrlen_utf8( const uchar *str ) {
int size = 0;
while(1) {
uchar c = *str++;
if( c == 0 ) break;
if( c < 0x80 )
size++;
else if( c < 0x800 )
size += 2;
else if( c >= 0xD800 && c <= 0xDFFF ) {
str++;
size += 4;
} else
size += 3;
}
return size;
}
uchar *ustrdup( const uchar *str ) {
int len = ustrlen(str);
int size = (len + 1) << 1;
uchar *d = (uchar*)malloc(size);
memcpy(d,str,size);
return d;
}
double utod( const uchar *str, uchar **end ) {
char buf[31];
char *bend;
double result;
int i = 0;
while( i < 30 ) {
int c = str[i];
if( (c < '0' || c > '9') && c != '.' && c != 'e' && c != 'E' && c != '-' && c != '+' )
break;
buf[i++] = (char)c;
}
buf[i] = 0;
result = strtod(buf,&bend);
*end = str + (bend - buf);
return result;
}
int utoi( const uchar *str, uchar **end ) {
char buf[17];
char *bend;
int result;
int i = 0;
uchar sign = str[0];
if( sign == '-' || sign == '+' ) {
buf[i++] = (char)sign;
}
while( i < 16 ) {
int c = str[i];
if( c < '0' || c > '9' )
break;
buf[i++] = (char)c;
}
buf[i] = 0;
result = strtol(buf,&bend,10);
*end = str + (bend - buf);
return result;
}
int ucmp( const uchar *a, const uchar *b ) {
while(true) {
int d = (unsigned)*a - (unsigned)*b;
if( d ) return d;
if( !*a ) return 0;
a++;
b++;
}
}
int usprintf( uchar *out, int out_size, const uchar *fmt, ... ) {
va_list args;
int ret;
va_start(args, fmt);
ret = uvszprintf(out, out_size, fmt, args);
va_end(args);
return ret;
}
// USE UTF-8 encoding
int utostr( char *out, int out_size, const uchar *str ) {
char *start = out;
char *end = out + out_size - 1; // final 0
if( out_size <= 0 ) return 0;
while( out < end ) {
unsigned int c = *str++;
if( c == 0 ) break;
if( c < 0x80 )
*out++ = (char)c;
else if( c < 0x800 ) {
if( out + 2 > end ) break;
*out++ = (char)(0xC0|(c>>6));
*out++ = 0x80|(c&63);
} else if( c >= 0xD800 && c <= 0xDFFF ) { // surrogate pair
if( out + 4 > end ) break;
unsigned int full = (((c - 0xD800) << 10) | ((*str++) - 0xDC00)) + 0x10000;
*out++ = (char)(0xF0|(full>>18));
*out++ = 0x80|((full>>12)&63);
*out++ = 0x80|((full>>6)&63);
*out++ = 0x80|(full&63);
} else {
if( out + 3 > end ) break;
*out++ = (char)(0xE0|(c>>12));
*out++ = 0x80|((c>>6)&63);
*out++ = 0x80|(c&63);
}
}
*out = 0;
return (int)(out - start);
}
static char *utos( const uchar *s ) {
int len = ustrlen_utf8(s);
char *out = (char*)malloc(len + 1);
if( utostr(out,len+1,s) < 0 )
*out = 0;
return out;
}
void uprintf( const uchar *fmt, const uchar *str ) {
char *cfmt = utos(fmt);
char *cstr = utos(str);
#ifdef HL_ANDROID
LOG_ANDROID(cfmt,cstr);
#else
printf(cfmt,cstr);
#endif
free(cfmt);
free(cstr);
}
#endif
#if !defined(HL_NATIVE_UCHAR_FUN) || defined(HL_WIN)
#ifdef HL_VCC
#pragma warning(disable:4774)
#endif
HL_PRIM int uvszprintf( uchar *out, int out_size, const uchar *fmt, va_list arglist ) {
uchar *start = out;
uchar *end = out + out_size - 1;
char cfmt[20];
char tmp[32];
uchar c;
while(true) {
sprintf_loop:
c = *fmt++;
if( out == end ) c = 0;
switch( c ) {
case 0:
*out = 0;
return (int)(out - start);
case '%':
{
int i = 0, size = 0;
cfmt[i++] = '%';
while( true ) {
c = *fmt++;
cfmt[i++] = (char)c;
switch( c ) {
case 'd':
cfmt[i++] = 0;
if( cfmt[i-3] == 'l' ) {
size = sprintf(tmp,cfmt,va_arg(arglist,int64));
} else {
size = sprintf(tmp,cfmt,va_arg(arglist,int));
}
goto sprintf_add;
case 'f':
cfmt[i++] = 0;
size = sprintf(tmp,cfmt,va_arg(arglist,double)); // according to GCC warning, float is promoted to double in var_args
goto sprintf_add;
case 'g':
cfmt[i++] = 0;
size = sprintf(tmp,cfmt,va_arg(arglist,double));
goto sprintf_add;
case 'x':
case 'X':
cfmt[i++] = 0;
if( cfmt[i-3] == 'l' )
size = sprintf(tmp,cfmt,va_arg(arglist,void*));
else
size = sprintf(tmp,cfmt,va_arg(arglist,int));
goto sprintf_add;
case 's':
if( i != 2 ) hl_fatal("Unsupported printf format"); // no support for precision qualifier
{
uchar *s = va_arg(arglist,uchar *);
while( *s && out < end )
*out++ = *s++;
goto sprintf_loop;
}
case '.':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case 'l':
break;
default:
hl_fatal("Unsupported printf format");
break;
}
}
sprintf_add:
// copy from c string to u string
i = 0;
while( i < size && out < end )
*out++ = tmp[i++];
}
break;
default:
*out++ = c;
break;
}
}
return 0;
}
#endif

View File

@ -0,0 +1,97 @@
#define UL_BITS 6
#define UL_SIZE 64
static uchar _E[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
static uchar L1[UL_SIZE] = {0,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
static uchar L3[UL_SIZE] = {224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,0,248,249,250,251,252,253,254,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
static uchar L4[UL_SIZE] = {257,0,259,0,261,0,263,0,265,0,267,0,269,0,271,0,273,0,275,0,277,0,279,0,281,0,283,0,285,0,287,0,289,0,291,0,293,0,295,0,297,0,299,0,301,0,303,0,105,0,307,0,309,0,311,0,0,314,0,316,0,318,0,320};
static uchar L5[UL_SIZE] = {0,322,0,324,0,326,0,328,0,0,331,0,333,0,335,0,337,0,339,0,341,0,343,0,345,0,347,0,349,0,351,0,353,0,355,0,357,0,359,0,361,0,363,0,365,0,367,0,369,0,371,0,373,0,375,0,255,378,0,380,0,382,0,0};
static uchar L6[UL_SIZE] = {0,595,387,0,389,0,596,392,0,598,599,396,0,0,477,601,603,402,0,608,611,0,617,616,409,0,0,0,623,626,0,629,417,0,419,0,421,0,640,424,0,643,0,0,429,0,648,432,0,650,651,436,0,438,0,658,441,0,0,0,445,0,0,0};
static uchar L7[UL_SIZE] = {0,0,0,0,454,454,0,457,457,0,460,460,0,462,0,464,0,466,0,468,0,470,0,472,0,474,0,476,0,0,479,0,481,0,483,0,485,0,487,0,489,0,491,0,493,0,495,0,0,499,499,0,501,0,405,447,505,0,507,0,509,0,511,0};
static uchar L8[UL_SIZE] = {513,0,515,0,517,0,519,0,521,0,523,0,525,0,527,0,529,0,531,0,533,0,535,0,537,0,539,0,541,0,543,0,414,0,547,0,549,0,551,0,553,0,555,0,557,0,559,0,561,0,563,0,0,0,0,0,0,0,11365,572,0,410,11366,0};
static uchar L9[UL_SIZE] = {0,578,0,384,649,652,583,0,585,0,587,0,589,0,591,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
static uchar L13[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,881,0,883,0,0,0,887,0,0,0,0,0,0,0,0,1011};
static uchar L14[UL_SIZE] = {0,0,0,0,0,0,940,0,941,942,943,0,972,0,973,974,0,945,946,947,948,949,950,951,952,953,954,955,956,957,958,959,960,961,0,963,964,965,966,967,968,969,970,971,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
static uchar L15[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,983,0,0,0,0,0,0,0,0,985,0,987,0,989,0,991,0,993,0,995,0,997,0,999,0,1001,0,1003,0,1005,0,1007,0,0,0,0,0,952,0,0,1016,0,1010,1019,0,0,891,892,893};
static uchar L16[UL_SIZE] = {1104,1105,1106,1107,1108,1109,1110,1111,1112,1113,1114,1115,1116,1117,1118,1119,1072,1073,1074,1075,1076,1077,1078,1079,1080,1081,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1093,1094,1095,1096,1097,1098,1099,1100,1101,1102,1103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
static uchar L17[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1121,0,1123,0,1125,0,1127,0,1129,0,1131,0,1133,0,1135,0,1137,0,1139,0,1141,0,1143,0,1145,0,1147,0,1149,0,1151,0};
static uchar L18[UL_SIZE] = {1153,0,0,0,0,0,0,0,0,0,1163,0,1165,0,1167,0,1169,0,1171,0,1173,0,1175,0,1177,0,1179,0,1181,0,1183,0,1185,0,1187,0,1189,0,1191,0,1193,0,1195,0,1197,0,1199,0,1201,0,1203,0,1205,0,1207,0,1209,0,1211,0,1213,0,1215,0};
static uchar L19[UL_SIZE] = {1231,1218,0,1220,0,1222,0,1224,0,1226,0,1228,0,1230,0,0,1233,0,1235,0,1237,0,1239,0,1241,0,1243,0,1245,0,1247,0,1249,0,1251,0,1253,0,1255,0,1257,0,1259,0,1261,0,1263,0,1265,0,1267,0,1269,0,1271,0,1273,0,1275,0,1277,0,1279,0};
static uchar L20[UL_SIZE] = {1281,0,1283,0,1285,0,1287,0,1289,0,1291,0,1293,0,1295,0,1297,0,1299,0,1301,0,1303,0,1305,0,1307,0,1309,0,1311,0,1313,0,1315,0,1317,0,1319,0,1321,0,1323,0,1325,0,1327,0,0,1377,1378,1379,1380,1381,1382,1383,1384,1385,1386,1387,1388,1389,1390,1391};
static uchar L21[UL_SIZE] = {1392,1393,1394,1395,1396,1397,1398,1399,1400,1401,1402,1403,1404,1405,1406,1407,1408,1409,1410,1411,1412,1413,1414,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
static uchar L66[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11520,11521,11522,11523,11524,11525,11526,11527,11528,11529,11530,11531,11532,11533,11534,11535,11536,11537,11538,11539,11540,11541,11542,11543,11544,11545,11546,11547,11548,11549,11550,11551};
static uchar L67[UL_SIZE] = {11552,11553,11554,11555,11556,11557,0,11559,0,0,0,0,0,11565,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
static uchar L78[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,43888,43889,43890,43891,43892,43893,43894,43895,43896,43897,43898,43899,43900,43901,43902,43903,43904,43905,43906,43907,43908,43909,43910,43911,43912,43913,43914,43915,43916,43917,43918,43919};
static uchar L79[UL_SIZE] = {43920,43921,43922,43923,43924,43925,43926,43927,43928,43929,43930,43931,43932,43933,43934,43935,43936,43937,43938,43939,43940,43941,43942,43943,43944,43945,43946,43947,43948,43949,43950,43951,43952,43953,43954,43955,43956,43957,43958,43959,43960,43961,43962,43963,43964,43965,43966,43967,5112,5113,5114,5115,5116,5117,0,0,0,0,0,0,0,0,0,0};
static uchar L120[UL_SIZE] = {7681,0,7683,0,7685,0,7687,0,7689,0,7691,0,7693,0,7695,0,7697,0,7699,0,7701,0,7703,0,7705,0,7707,0,7709,0,7711,0,7713,0,7715,0,7717,0,7719,0,7721,0,7723,0,7725,0,7727,0,7729,0,7731,0,7733,0,7735,0,7737,0,7739,0,7741,0,7743,0};
static uchar L121[UL_SIZE] = {7745,0,7747,0,7749,0,7751,0,7753,0,7755,0,7757,0,7759,0,7761,0,7763,0,7765,0,7767,0,7769,0,7771,0,7773,0,7775,0,7777,0,7779,0,7781,0,7783,0,7785,0,7787,0,7789,0,7791,0,7793,0,7795,0,7797,0,7799,0,7801,0,7803,0,7805,0,7807,0};
static uchar L122[UL_SIZE] = {7809,0,7811,0,7813,0,7815,0,7817,0,7819,0,7821,0,7823,0,7825,0,7827,0,7829,0,0,0,0,0,0,0,0,0,223,0,7841,0,7843,0,7845,0,7847,0,7849,0,7851,0,7853,0,7855,0,7857,0,7859,0,7861,0,7863,0,7865,0,7867,0,7869,0,7871,0};
static uchar L123[UL_SIZE] = {7873,0,7875,0,7877,0,7879,0,7881,0,7883,0,7885,0,7887,0,7889,0,7891,0,7893,0,7895,0,7897,0,7899,0,7901,0,7903,0,7905,0,7907,0,7909,0,7911,0,7913,0,7915,0,7917,0,7919,0,7921,0,7923,0,7925,0,7927,0,7929,0,7931,0,7933,0,7935,0};
static uchar L124[UL_SIZE] = {0,0,0,0,0,0,0,0,7936,7937,7938,7939,7940,7941,7942,7943,0,0,0,0,0,0,0,0,7952,7953,7954,7955,7956,7957,0,0,0,0,0,0,0,0,0,0,7968,7969,7970,7971,7972,7973,7974,7975,0,0,0,0,0,0,0,0,7984,7985,7986,7987,7988,7989,7990,7991};
static uchar L125[UL_SIZE] = {0,0,0,0,0,0,0,0,8000,8001,8002,8003,8004,8005,0,0,0,0,0,0,0,0,0,0,0,8017,0,8019,0,8021,0,8023,0,0,0,0,0,0,0,0,8032,8033,8034,8035,8036,8037,8038,8039,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
static uchar L126[UL_SIZE] = {0,0,0,0,0,0,0,0,8064,8065,8066,8067,8068,8069,8070,8071,0,0,0,0,0,0,0,0,8080,8081,8082,8083,8084,8085,8086,8087,0,0,0,0,0,0,0,0,8096,8097,8098,8099,8100,8101,8102,8103,0,0,0,0,0,0,0,0,8112,8113,8048,8049,8115,0,0,0};
static uchar L127[UL_SIZE] = {0,0,0,0,0,0,0,0,8050,8051,8052,8053,8131,0,0,0,0,0,0,0,0,0,0,0,8144,8145,8054,8055,0,0,0,0,0,0,0,0,0,0,0,0,8160,8161,8058,8059,8165,0,0,0,0,0,0,0,0,0,0,0,8056,8057,8060,8061,8179,0,0,0};
static uchar L132[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,969,0,0,0,107,229,0,0,0,0,0,0,8526,0,0,0,0,0,0,0,0,0,0,0,0,0};
static uchar L133[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8560,8561,8562,8563,8564,8565,8566,8567,8568,8569,8570,8571,8572,8573,8574,8575,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
static uchar L134[UL_SIZE] = {0,0,0,8580,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
static uchar L146[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9424,9425,9426,9427,9428,9429,9430,9431,9432,9433};
static uchar L147[UL_SIZE] = {9434,9435,9436,9437,9438,9439,9440,9441,9442,9443,9444,9445,9446,9447,9448,9449,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
static uchar L176[UL_SIZE] = {11312,11313,11314,11315,11316,11317,11318,11319,11320,11321,11322,11323,11324,11325,11326,11327,11328,11329,11330,11331,11332,11333,11334,11335,11336,11337,11338,11339,11340,11341,11342,11343,11344,11345,11346,11347,11348,11349,11350,11351,11352,11353,11354,11355,11356,11357,11358,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
static uchar L177[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11361,0,619,7549,637,0,0,11368,0,11370,0,11372,0,593,625,592,594,0,11379,0,0,11382,0,0,0,0,0,0,0,0,575,576};
static uchar L178[UL_SIZE] = {11393,0,11395,0,11397,0,11399,0,11401,0,11403,0,11405,0,11407,0,11409,0,11411,0,11413,0,11415,0,11417,0,11419,0,11421,0,11423,0,11425,0,11427,0,11429,0,11431,0,11433,0,11435,0,11437,0,11439,0,11441,0,11443,0,11445,0,11447,0,11449,0,11451,0,11453,0,11455,0};
static uchar L179[UL_SIZE] = {11457,0,11459,0,11461,0,11463,0,11465,0,11467,0,11469,0,11471,0,11473,0,11475,0,11477,0,11479,0,11481,0,11483,0,11485,0,11487,0,11489,0,11491,0,0,0,0,0,0,0,0,11500,0,11502,0,0,0,0,11507,0,0,0,0,0,0,0,0,0,0,0,0,0};
static uchar L665[UL_SIZE] = {42561,0,42563,0,42565,0,42567,0,42569,0,42571,0,42573,0,42575,0,42577,0,42579,0,42581,0,42583,0,42585,0,42587,0,42589,0,42591,0,42593,0,42595,0,42597,0,42599,0,42601,0,42603,0,42605,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
static uchar L666[UL_SIZE] = {42625,0,42627,0,42629,0,42631,0,42633,0,42635,0,42637,0,42639,0,42641,0,42643,0,42645,0,42647,0,42649,0,42651,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
static uchar L668[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42787,0,42789,0,42791,0,42793,0,42795,0,42797,0,42799,0,0,0,42803,0,42805,0,42807,0,42809,0,42811,0,42813,0,42815,0};
static uchar L669[UL_SIZE] = {42817,0,42819,0,42821,0,42823,0,42825,0,42827,0,42829,0,42831,0,42833,0,42835,0,42837,0,42839,0,42841,0,42843,0,42845,0,42847,0,42849,0,42851,0,42853,0,42855,0,42857,0,42859,0,42861,0,42863,0,0,0,0,0,0,0,0,0,0,42874,0,42876,0,7545,42879,0};
static uchar L670[UL_SIZE] = {42881,0,42883,0,42885,0,42887,0,0,0,0,42892,0,613,0,0,42897,0,42899,0,0,0,42903,0,42905,0,42907,0,42909,0,42911,0,42913,0,42915,0,42917,0,42919,0,42921,0,614,604,609,620,0,0,670,647,669,43859,42933,0,42935,0,0,0,0,0,0,0,0,0};
static uchar L1020[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,65345,65346,65347,65348,65349,65350,65351,65352,65353,65354,65355,65356,65357,65358,65359,65360,65361,65362,65363,65364,65365,65366,65367,65368,65369,65370,0,0,0,0,0};
static uchar U1[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,0,0,0,0,0};
static uchar U2[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,924,0,0,0,0,0,0,0,0,0,0};
static uchar U3[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,0,216,217,218,219,220,221,222,376};
static uchar U4[UL_SIZE] = {0,256,0,258,0,260,0,262,0,264,0,266,0,268,0,270,0,272,0,274,0,276,0,278,0,280,0,282,0,284,0,286,0,288,0,290,0,292,0,294,0,296,0,298,0,300,0,302,0,73,0,306,0,308,0,310,0,0,313,0,315,0,317,0};
static uchar U5[UL_SIZE] = {319,0,321,0,323,0,325,0,327,0,0,330,0,332,0,334,0,336,0,338,0,340,0,342,0,344,0,346,0,348,0,350,0,352,0,354,0,356,0,358,0,360,0,362,0,364,0,366,0,368,0,370,0,372,0,374,0,0,377,0,379,0,381,83};
static uchar U6[UL_SIZE] = {579,0,0,386,0,388,0,0,391,0,0,0,395,0,0,0,0,0,401,0,0,502,0,0,0,408,573,0,0,0,544,0,0,416,0,418,0,420,0,0,423,0,0,0,0,428,0,0,431,0,0,0,435,0,437,0,0,440,0,0,0,444,0,503};
static uchar U7[UL_SIZE] = {0,0,0,0,453,453,453,456,456,456,459,459,459,0,461,0,463,0,465,0,467,0,469,0,471,0,473,0,475,398,0,478,0,480,0,482,0,484,0,486,0,488,0,490,0,492,0,494,0,498,498,498,0,500,0,0,0,504,0,506,0,508,0,510};
static uchar U8[UL_SIZE] = {0,512,0,514,0,516,0,518,0,520,0,522,0,524,0,526,0,528,0,530,0,532,0,534,0,536,0,538,0,540,0,542,0,0,0,546,0,548,0,550,0,552,0,554,0,556,0,558,0,560,0,562,0,0,0,0,0,0,0,0,571,0,0,11390};
static uchar U9[UL_SIZE] = {11391,0,577,0,0,0,0,582,0,584,0,586,0,588,0,590,11375,11373,11376,385,390,0,393,394,0,399,0,400,42923,0,0,0,403,42924,0,404,0,42893,42922,0,407,406,0,11362,42925,0,0,412,0,11374,413,0,0,415,0,0,0,0,0,0,0,11364,0,0};
static uchar U10[UL_SIZE] = {422,0,0,425,0,0,0,42929,430,580,433,434,581,0,0,0,0,0,439,0,0,0,0,0,0,0,0,0,0,42930,42928,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
static uchar U13[UL_SIZE] = {0,0,0,0,0,921,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,880,0,882,0,0,0,886,0,0,0,1021,1022,1023,0,0};
static uchar U14[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,902,904,905,906,0,913,914,915,916,917,918,919,920,921,922,923,924,925,926,927};
static uchar U15[UL_SIZE] = {928,929,931,931,932,933,934,935,936,937,938,939,908,910,911,0,914,920,0,0,0,934,928,975,0,984,0,986,0,988,0,990,0,992,0,994,0,996,0,998,0,1000,0,1002,0,1004,0,1006,922,929,1017,895,0,917,0,0,1015,0,0,1018,0,0,0,0};
static uchar U16[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1040,1041,1042,1043,1044,1045,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055};
static uchar U17[UL_SIZE] = {1056,1057,1058,1059,1060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,1024,1025,1026,1027,1028,1029,1030,1031,1032,1033,1034,1035,1036,1037,1038,1039,0,1120,0,1122,0,1124,0,1126,0,1128,0,1130,0,1132,0,1134,0,1136,0,1138,0,1140,0,1142,0,1144,0,1146,0,1148,0,1150};
static uchar U18[UL_SIZE] = {0,1152,0,0,0,0,0,0,0,0,0,1162,0,1164,0,1166,0,1168,0,1170,0,1172,0,1174,0,1176,0,1178,0,1180,0,1182,0,1184,0,1186,0,1188,0,1190,0,1192,0,1194,0,1196,0,1198,0,1200,0,1202,0,1204,0,1206,0,1208,0,1210,0,1212,0,1214};
static uchar U19[UL_SIZE] = {0,0,1217,0,1219,0,1221,0,1223,0,1225,0,1227,0,1229,1216,0,1232,0,1234,0,1236,0,1238,0,1240,0,1242,0,1244,0,1246,0,1248,0,1250,0,1252,0,1254,0,1256,0,1258,0,1260,0,1262,0,1264,0,1266,0,1268,0,1270,0,1272,0,1274,0,1276,0,1278};
static uchar U20[UL_SIZE] = {0,1280,0,1282,0,1284,0,1286,0,1288,0,1290,0,1292,0,1294,0,1296,0,1298,0,1300,0,1302,0,1304,0,1306,0,1308,0,1310,0,1312,0,1314,0,1316,0,1318,0,1320,0,1322,0,1324,0,1326,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
static uchar U21[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1329,1330,1331,1332,1333,1334,1335,1336,1337,1338,1339,1340,1341,1342,1343,1344,1345,1346,1347,1348,1349,1350,1351,1352,1353,1354,1355,1356,1357,1358,1359};
static uchar U22[UL_SIZE] = {1360,1361,1362,1363,1364,1365,1366,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
static uchar U79[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5104,5105,5106,5107,5108,5109,0,0};
static uchar U117[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42877,0,0,0,11363,0,0};
static uchar U120[UL_SIZE] = {0,7680,0,7682,0,7684,0,7686,0,7688,0,7690,0,7692,0,7694,0,7696,0,7698,0,7700,0,7702,0,7704,0,7706,0,7708,0,7710,0,7712,0,7714,0,7716,0,7718,0,7720,0,7722,0,7724,0,7726,0,7728,0,7730,0,7732,0,7734,0,7736,0,7738,0,7740,0,7742};
static uchar U121[UL_SIZE] = {0,7744,0,7746,0,7748,0,7750,0,7752,0,7754,0,7756,0,7758,0,7760,0,7762,0,7764,0,7766,0,7768,0,7770,0,7772,0,7774,0,7776,0,7778,0,7780,0,7782,0,7784,0,7786,0,7788,0,7790,0,7792,0,7794,0,7796,0,7798,0,7800,0,7802,0,7804,0,7806};
static uchar U122[UL_SIZE] = {0,7808,0,7810,0,7812,0,7814,0,7816,0,7818,0,7820,0,7822,0,7824,0,7826,0,7828,0,0,0,0,0,7776,0,0,0,0,0,7840,0,7842,0,7844,0,7846,0,7848,0,7850,0,7852,0,7854,0,7856,0,7858,0,7860,0,7862,0,7864,0,7866,0,7868,0,7870};
static uchar U123[UL_SIZE] = {0,7872,0,7874,0,7876,0,7878,0,7880,0,7882,0,7884,0,7886,0,7888,0,7890,0,7892,0,7894,0,7896,0,7898,0,7900,0,7902,0,7904,0,7906,0,7908,0,7910,0,7912,0,7914,0,7916,0,7918,0,7920,0,7922,0,7924,0,7926,0,7928,0,7930,0,7932,0,7934};
static uchar U124[UL_SIZE] = {7944,7945,7946,7947,7948,7949,7950,7951,0,0,0,0,0,0,0,0,7960,7961,7962,7963,7964,7965,0,0,0,0,0,0,0,0,0,0,7976,7977,7978,7979,7980,7981,7982,7983,0,0,0,0,0,0,0,0,7992,7993,7994,7995,7996,7997,7998,7999,0,0,0,0,0,0,0,0};
static uchar U125[UL_SIZE] = {8008,8009,8010,8011,8012,8013,0,0,0,0,0,0,0,0,0,0,0,8025,0,8027,0,8029,0,8031,0,0,0,0,0,0,0,0,8040,8041,8042,8043,8044,8045,8046,8047,0,0,0,0,0,0,0,0,8122,8123,8136,8137,8138,8139,8154,8155,8184,8185,8170,8171,8186,8187,0,0};
static uchar U126[UL_SIZE] = {8072,8073,8074,8075,8076,8077,8078,8079,0,0,0,0,0,0,0,0,8088,8089,8090,8091,8092,8093,8094,8095,0,0,0,0,0,0,0,0,8104,8105,8106,8107,8108,8109,8110,8111,0,0,0,0,0,0,0,0,8120,8121,0,8124,0,0,0,0,0,0,0,0,0,0,921,0};
static uchar U127[UL_SIZE] = {0,0,0,8140,0,0,0,0,0,0,0,0,0,0,0,0,8152,8153,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8168,8169,0,0,0,8172,0,0,0,0,0,0,0,0,0,0,0,0,0,8188,0,0,0,0,0,0,0,0,0,0,0,0};
static uchar U133[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,8498,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8544,8545,8546,8547,8548,8549,8550,8551,8552,8553,8554,8555,8556,8557,8558,8559};
static uchar U134[UL_SIZE] = {0,0,0,0,8579,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
static uchar U147[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9398,9399,9400,9401,9402,9403,9404,9405,9406,9407,9408,9409,9410,9411,9412,9413,9414,9415,9416,9417,9418,9419,9420,9421,9422,9423,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
static uchar U176[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11264,11265,11266,11267,11268,11269,11270,11271,11272,11273,11274,11275,11276,11277,11278,11279};
static uchar U177[UL_SIZE] = {11280,11281,11282,11283,11284,11285,11286,11287,11288,11289,11290,11291,11292,11293,11294,11295,11296,11297,11298,11299,11300,11301,11302,11303,11304,11305,11306,11307,11308,11309,11310,0,0,11360,0,0,0,570,574,0,11367,0,11369,0,11371,0,0,0,0,0,0,11378,0,0,11381,0,0,0,0,0,0,0,0,0};
static uchar U178[UL_SIZE] = {0,11392,0,11394,0,11396,0,11398,0,11400,0,11402,0,11404,0,11406,0,11408,0,11410,0,11412,0,11414,0,11416,0,11418,0,11420,0,11422,0,11424,0,11426,0,11428,0,11430,0,11432,0,11434,0,11436,0,11438,0,11440,0,11442,0,11444,0,11446,0,11448,0,11450,0,11452,0,11454};
static uchar U179[UL_SIZE] = {0,11456,0,11458,0,11460,0,11462,0,11464,0,11466,0,11468,0,11470,0,11472,0,11474,0,11476,0,11478,0,11480,0,11482,0,11484,0,11486,0,11488,0,11490,0,0,0,0,0,0,0,0,11499,0,11501,0,0,0,0,11506,0,0,0,0,0,0,0,0,0,0,0,0};
static uchar U180[UL_SIZE] = {4256,4257,4258,4259,4260,4261,4262,4263,4264,4265,4266,4267,4268,4269,4270,4271,4272,4273,4274,4275,4276,4277,4278,4279,4280,4281,4282,4283,4284,4285,4286,4287,4288,4289,4290,4291,4292,4293,0,4295,0,0,0,0,0,4301,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
static uchar U665[UL_SIZE] = {0,42560,0,42562,0,42564,0,42566,0,42568,0,42570,0,42572,0,42574,0,42576,0,42578,0,42580,0,42582,0,42584,0,42586,0,42588,0,42590,0,42592,0,42594,0,42596,0,42598,0,42600,0,42602,0,42604,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
static uchar U666[UL_SIZE] = {0,42624,0,42626,0,42628,0,42630,0,42632,0,42634,0,42636,0,42638,0,42640,0,42642,0,42644,0,42646,0,42648,0,42650,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
static uchar U668[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42786,0,42788,0,42790,0,42792,0,42794,0,42796,0,42798,0,0,0,42802,0,42804,0,42806,0,42808,0,42810,0,42812,0,42814};
static uchar U669[UL_SIZE] = {0,42816,0,42818,0,42820,0,42822,0,42824,0,42826,0,42828,0,42830,0,42832,0,42834,0,42836,0,42838,0,42840,0,42842,0,42844,0,42846,0,42848,0,42850,0,42852,0,42854,0,42856,0,42858,0,42860,0,42862,0,0,0,0,0,0,0,0,0,0,42873,0,42875,0,0,42878};
static uchar U670[UL_SIZE] = {0,42880,0,42882,0,42884,0,42886,0,0,0,0,42891,0,0,0,0,42896,0,42898,0,0,0,42902,0,42904,0,42906,0,42908,0,42910,0,42912,0,42914,0,42916,0,42918,0,42920,0,0,0,0,0,0,0,0,0,0,0,42932,0,42934,0,0,0,0,0,0,0,0};
static uchar U685[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42931,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5024,5025,5026,5027,5028,5029,5030,5031,5032,5033,5034,5035,5036,5037,5038,5039};
static uchar U686[UL_SIZE] = {5040,5041,5042,5043,5044,5045,5046,5047,5048,5049,5050,5051,5052,5053,5054,5055,5056,5057,5058,5059,5060,5061,5062,5063,5064,5065,5066,5067,5068,5069,5070,5071,5072,5073,5074,5075,5076,5077,5078,5079,5080,5081,5082,5083,5084,5085,5086,5087,5088,5089,5090,5091,5092,5093,5094,5095,5096,5097,5098,5099,5100,5101,5102,5103};
static uchar U1021[UL_SIZE] = {0,65313,65314,65315,65316,65317,65318,65319,65320,65321,65322,65323,65324,65325,65326,65327,65328,65329,65330,65331,65332,65333,65334,65335,65336,65337,65338,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
#define LMAX 1021
#define UMAX 1022
static uchar *LOWER[LMAX] = {_E,L1,_E,L3,L4,L5,L6,L7,L8,L9,_E,_E,_E,L13,L14,L15,L16,L17,L18,L19,L20,L21,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,L66,L67,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,L78,L79,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,L120,L121,L122,L123,L124,L125,L126,L127,_E,_E,_E,_E,L132,L133,L134,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,L146,L147,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,L176,L177,L178,L179,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,L665,L666,_E,L668,L669,L670,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,L1020};
static uchar *UPPER[UMAX] = {_E,U1,U2,U3,U4,U5,U6,U7,U8,U9,U10,_E,_E,U13,U14,U15,U16,U17,U18,U19,U20,U21,U22,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,U79,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,U117,_E,_E,U120,U121,U122,U123,U124,U125,U126,U127,_E,_E,_E,_E,_E,U133,U134,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,U147,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,U176,U177,U178,U179,U180,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,U665,U666,_E,U668,U669,U670,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,U685,U686,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,U1021};