Browse Source

disable alignment for stack args, partial SMod jit support, custom stack capture & display for JIT

Nicolas Cannasse 9 years ago
parent
commit
585c718774
4 changed files with 92 additions and 50 deletions
  1. 1 0
      src/hl.h
  2. 24 28
      src/jit.c
  3. 29 0
      src/module.c
  4. 38 22
      src/std/error.c

+ 1 - 0
src/hl.h

@@ -439,6 +439,7 @@ HL_API const uchar *hl_field_name( int hash );
 HL_API void hl_error_msg( const uchar *msg, ... );
 HL_API void hl_error_msg( const uchar *msg, ... );
 HL_API void hl_throw( vdynamic *v );
 HL_API void hl_throw( vdynamic *v );
 HL_API void hl_rethrow( vdynamic *v );
 HL_API void hl_rethrow( vdynamic *v );
+HL_API void hl_exception_setup( void *resolve_symbol, void *capture_stack );
 
 
 HL_API varray *hl_exception_stack();
 HL_API varray *hl_exception_stack();
 HL_API int hl_get_stack_hash();
 HL_API int hl_get_stack_hash();

+ 24 - 28
src/jit.c

@@ -1066,7 +1066,7 @@ static void discard_regs( jit_ctx *ctx, bool native_call ) {
 	}
 	}
 }
 }
 
 
-static int pad_stack( jit_ctx *ctx, int size ) {
+static int pad_before_call( jit_ctx *ctx, int size ) {
 	int total = size + ctx->totalRegsSize + HL_WSIZE * 2; // EIP+EBP
 	int total = size + ctx->totalRegsSize + HL_WSIZE * 2; // EIP+EBP
 	if( total & 15 ) {
 	if( total & 15 ) {
 		int pad = 16 - (total & 15);
 		int pad = 16 - (total & 15);
@@ -1104,22 +1104,13 @@ static int prepare_call_args( jit_ctx *ctx, int count, int *args, vreg *vregs, b
 #endif
 #endif
 	for(i=count - stackRegs;i<count;i++) {
 	for(i=count - stackRegs;i<count;i++) {
 		vreg *r = vregs + args[i];
 		vreg *r = vregs + args[i];
-		size += hl_pad_size(size,r->t);
 		size += r->size;
 		size += r->size;
 	}
 	}
-	paddedSize = pad_stack(ctx,size);
-	size = ctx->totalRegsSize + (paddedSize - size);
+	paddedSize = pad_before_call(ctx,size);
 	for(i=0;i<stackRegs;i++) {
 	for(i=0;i<stackRegs;i++) {
 		// RTL
 		// RTL
 		vreg *r = vregs + args[count - (i + 1)];
 		vreg *r = vregs + args[count - (i + 1)];
-		int pad;
-		size += r->size;
-		pad = hl_pad_size(size,r->t);
 		if( (i & 7) == 0 ) jit_buf(ctx);
 		if( (i & 7) == 0 ) jit_buf(ctx);
-		if( pad ) {
-			op64(ctx,SUB,PESP,pconst(&p,pad));
-			size += pad;
-		}
 		switch( r->size ) {
 		switch( r->size ) {
 		case 1:
 		case 1:
 			op64(ctx,SUB,PESP,pconst(&p,1));
 			op64(ctx,SUB,PESP,pconst(&p,1));
@@ -1253,7 +1244,7 @@ static void op_ret( jit_ctx *ctx, vreg *r ) {
 }
 }
 
 
 static void call_native_consts( jit_ctx *ctx, void *nativeFun, int_val *args, int nargs ) {
 static void call_native_consts( jit_ctx *ctx, void *nativeFun, int_val *args, int nargs ) {
-	int size = pad_stack(ctx, IS_64 ? 0 : HL_WSIZE*nargs);
+	int size = pad_before_call(ctx, IS_64 ? 0 : HL_WSIZE*nargs);
 	preg p;
 	preg p;
 	int i;
 	int i;
 #	ifdef HL_64
 #	ifdef HL_64
@@ -1300,6 +1291,9 @@ static preg *op_binop( jit_ctx *ctx, vreg *dst, vreg *a, vreg *b, hl_opcode *op
 		case OJNotEq:
 		case OJNotEq:
 			o = COMISD;
 			o = COMISD;
 			break;
 			break;
+		case OSMod:
+			jit_error("TODO:fmod call");
+			return PXMM(0);
 		default:
 		default:
 			printf("%s\n", hl_op_name(op->op));
 			printf("%s\n", hl_op_name(op->op));
 			ASSERT(op->op);
 			ASSERT(op->op);
@@ -1330,13 +1324,15 @@ static preg *op_binop( jit_ctx *ctx, vreg *dst, vreg *a, vreg *b, hl_opcode *op
 			return pa;
 			return pa;
 		case OSDiv:
 		case OSDiv:
 		case OUDiv:
 		case OUDiv:
+		case OSMod:			
 			{
 			{
+				preg *out = op->op == OSMod ? REG_AT(Edx) : PEAX;
 				preg *r = alloc_cpu(ctx,b,true);
 				preg *r = alloc_cpu(ctx,b,true);
 				int jz, jend;
 				int jz, jend;
 				// integer div 0 => 0
 				// integer div 0 => 0
 				op32(ctx,TEST,r,r);
 				op32(ctx,TEST,r,r);
 				XJump_small(JNotZero,jz);
 				XJump_small(JNotZero,jz);
-				op32(ctx,XOR,PEAX,PEAX);
+				op32(ctx,XOR,out,out);
 				XJump_small(JAlways,jend);
 				XJump_small(JAlways,jend);
 				patch_jump(ctx,jz);
 				patch_jump(ctx,jz);
 				if( pa->kind != RCPU || pa->id != Eax ) {
 				if( pa->kind != RCPU || pa->id != Eax ) {
@@ -1348,11 +1344,11 @@ static preg *op_binop( jit_ctx *ctx, vreg *dst, vreg *a, vreg *b, hl_opcode *op
 					op32(ctx, XOR, REG_AT(Edx), REG_AT(Edx));
 					op32(ctx, XOR, REG_AT(Edx), REG_AT(Edx));
 				else
 				else
 					op32(ctx, CDQ, UNUSED, UNUSED); // sign-extend Eax into Eax:Edx
 					op32(ctx, CDQ, UNUSED, UNUSED); // sign-extend Eax into Eax:Edx
-				op32(ctx, op->op == OUDiv ? DIV : IDIV, pb, UNUSED);
+				op32(ctx, op->op == OUDiv ? DIV : IDIV, fetch(b), UNUSED);
 				patch_jump(ctx, jend);
 				patch_jump(ctx, jend);
+				if( dst ) store(ctx, dst, out, true);
+				return out;
 			}
 			}
-			if( dst ) store(ctx, dst, PEAX, true);
-			return PEAX;
 		case OJSLt:
 		case OJSLt:
 		case OJSGte:
 		case OJSGte:
 		case OJSLte:
 		case OJSLte:
@@ -1871,7 +1867,6 @@ int hl_jit_function( jit_ctx *ctx, hl_module *m, hl_function *f ) {
 	size = 0;
 	size = 0;
 	for(i=0;i<nargs;i++) {
 	for(i=0;i<nargs;i++) {
 		vreg *r = R(i);
 		vreg *r = R(i);
-		size += hl_pad_size(size,r->t);
 		r->stackPos = size + HL_WSIZE * 2;
 		r->stackPos = size + HL_WSIZE * 2;
 		size += r->size;
 		size += r->size;
 	}
 	}
@@ -1965,6 +1960,7 @@ int hl_jit_function( jit_ctx *ctx, hl_module *m, hl_function *f ) {
 		case OAnd:
 		case OAnd:
 		case OOr:
 		case OOr:
 		case OXor:
 		case OXor:
+		case OSMod:
 			op_binop(ctx, dst, ra, rb, o);
 			op_binop(ctx, dst, ra, rb, o);
 			break;
 			break;
 		case ONeg:
 		case ONeg:
@@ -2165,7 +2161,7 @@ int hl_jit_function( jit_ctx *ctx, hl_module *m, hl_function *f ) {
 #				else
 #				else
 				preg *r = alloc_cpu(ctx, rb, true);
 				preg *r = alloc_cpu(ctx, rb, true);
 				jlist *j = (jlist*)hl_malloc(&ctx->galloc,sizeof(jlist));
 				jlist *j = (jlist*)hl_malloc(&ctx->galloc,sizeof(jlist));
-				size = pad_stack(ctx,HL_WSIZE*3);
+				size = pad_before_call(ctx,HL_WSIZE*3);
 				op64(ctx,PUSH,r,UNUSED);
 				op64(ctx,PUSH,r,UNUSED);
 
 
 				j->pos = BUF_POS();
 				j->pos = BUF_POS();
@@ -2255,7 +2251,7 @@ int hl_jit_function( jit_ctx *ctx, hl_module *m, hl_function *f ) {
 #						ifdef HL_64
 #						ifdef HL_64
 						jit_error("TODO");
 						jit_error("TODO");
 #						else
 #						else
-						size = pad_stack(ctx,HL_WSIZE*3);
+						size = pad_before_call(ctx,HL_WSIZE*3);
 						op64(ctx,MOV,r,pconst64(&p,(int_val)dst->t));
 						op64(ctx,MOV,r,pconst64(&p,(int_val)dst->t));
 						op64(ctx,PUSH,r,UNUSED);
 						op64(ctx,PUSH,r,UNUSED);
 						op64(ctx,MOV,r,pconst64(&p,(int_val)ra->t->virt->fields[o->p3].hashed_name));
 						op64(ctx,MOV,r,pconst64(&p,(int_val)ra->t->virt->fields[o->p3].hashed_name));
@@ -2305,7 +2301,7 @@ int hl_jit_function( jit_ctx *ctx, hl_module *m, hl_function *f ) {
 							break;
 							break;
 						default:
 						default:
 							size = HL_WSIZE * 4;
 							size = HL_WSIZE * 4;
-							pad_stack(ctx,HL_WSIZE*4);
+							pad_before_call(ctx,HL_WSIZE*4);
 							op64(ctx,PUSH,fetch(rb),UNUSED);
 							op64(ctx,PUSH,fetch(rb),UNUSED);
 							op64(ctx,MOV,r,pconst64(&p,(int_val)rb->t));
 							op64(ctx,MOV,r,pconst64(&p,(int_val)rb->t));
 							break;
 							break;
@@ -2411,7 +2407,7 @@ int hl_jit_function( jit_ctx *ctx, hl_module *m, hl_function *f ) {
 						}
 						}
 					}
 					}
 
 
-					size = pad_stack(ctx,HL_WSIZE*5);
+					size = pad_before_call(ctx,HL_WSIZE*5);
 
 
 					if( hl_is_ptr(dst->t) || dst->t->kind == HVOID )
 					if( hl_is_ptr(dst->t) || dst->t->kind == HVOID )
 						op64(ctx,PUSH,pconst(&p,0),UNUSED);
 						op64(ctx,PUSH,pconst(&p,0),UNUSED);
@@ -2548,11 +2544,11 @@ int hl_jit_function( jit_ctx *ctx, hl_module *m, hl_function *f ) {
 		case OToVirtual:
 		case OToVirtual:
 			{
 			{
 #				ifdef HL_64
 #				ifdef HL_64
-				int size = pad_stack(ctx, 0);
+				int size = pad_before_call(ctx, 0);
 				op64(ctx,MOV,REG_AT(CALL_REGS[1]),fetch(ra));
 				op64(ctx,MOV,REG_AT(CALL_REGS[1]),fetch(ra));
 				op64(ctx,MOV,REG_AT(CALL_REGS[0]),pconst64(&p,(int_val)dst->t));
 				op64(ctx,MOV,REG_AT(CALL_REGS[0]),pconst64(&p,(int_val)dst->t));
 #				else
 #				else
-				int size = pad_stack(ctx, HL_WSIZE*2);
+				int size = pad_before_call(ctx, HL_WSIZE*2);
 				op32(ctx,PUSH,fetch(ra),UNUSED);
 				op32(ctx,PUSH,fetch(ra),UNUSED);
 				op32(ctx,PUSH,pconst(&p,(int)(int_val)dst->t),UNUSED);
 				op32(ctx,PUSH,pconst(&p,(int)(int_val)dst->t),UNUSED);
 #				endif
 #				endif
@@ -2645,7 +2641,7 @@ int hl_jit_function( jit_ctx *ctx, hl_module *m, hl_function *f ) {
 				switch( dst->t->kind ) {
 				switch( dst->t->kind ) {
 				case HF32:
 				case HF32:
 				case HF64:
 				case HF64:
-					size = pad_stack(ctx, HL_WSIZE*2);
+					size = pad_before_call(ctx, HL_WSIZE*2);
 					op32(ctx,PUSH,pconst64(&p,(int_val)ra->t),UNUSED);
 					op32(ctx,PUSH,pconst64(&p,(int_val)ra->t),UNUSED);
 					op32(ctx,MOV,PEAX,REG_AT(Ebp));
 					op32(ctx,MOV,PEAX,REG_AT(Ebp));
 					op32(ctx,ADD,PEAX,pconst(&p,ra->stackPos));
 					op32(ctx,ADD,PEAX,pconst(&p,ra->stackPos));
@@ -2654,7 +2650,7 @@ int hl_jit_function( jit_ctx *ctx, hl_module *m, hl_function *f ) {
 					store(ctx, dst, PXMM(0), true);
 					store(ctx, dst, PXMM(0), true);
 					break;
 					break;
 				default:
 				default:
-					size = pad_stack(ctx, HL_WSIZE*3);
+					size = pad_before_call(ctx, HL_WSIZE*3);
 					op32(ctx,PUSH,pconst64(&p,(int_val)dst->t),UNUSED);
 					op32(ctx,PUSH,pconst64(&p,(int_val)dst->t),UNUSED);
 					op32(ctx,PUSH,pconst64(&p,(int_val)ra->t),UNUSED);
 					op32(ctx,PUSH,pconst64(&p,(int_val)ra->t),UNUSED);
 					op32(ctx,MOV,PEAX,REG_AT(Ebp));
 					op32(ctx,MOV,PEAX,REG_AT(Ebp));
@@ -2681,7 +2677,7 @@ int hl_jit_function( jit_ctx *ctx, hl_module *m, hl_function *f ) {
 					break;
 					break;
 				default:
 				default:
 					r = alloc_reg(ctx,RCPU);
 					r = alloc_reg(ctx,RCPU);
-					size = pad_stack(ctx,HL_WSIZE*3);
+					size = pad_before_call(ctx,HL_WSIZE*3);
 					op64(ctx,MOV,r,pconst64(&p,(int_val)dst->t));
 					op64(ctx,MOV,r,pconst64(&p,(int_val)dst->t));
 					op64(ctx,PUSH,r,UNUSED);
 					op64(ctx,PUSH,r,UNUSED);
 					op64(ctx,MOV,r,pconst64(&p,(int_val)hl_hash_utf8(m->code->strings[o->p3])));
 					op64(ctx,MOV,r,pconst64(&p,(int_val)hl_hash_utf8(m->code->strings[o->p3])));
@@ -2706,7 +2702,7 @@ int hl_jit_function( jit_ctx *ctx, hl_module *m, hl_function *f ) {
 					jit_error("TODO");
 					jit_error("TODO");
 					break;
 					break;
 				default:
 				default:
-					size = pad_stack(ctx, HL_WSIZE*4);
+					size = pad_before_call(ctx, HL_WSIZE*4);
 					op32(ctx,PUSH,fetch(rb),UNUSED);
 					op32(ctx,PUSH,fetch(rb),UNUSED);
 					op32(ctx,PUSH,pconst64(&p,(int_val)rb->t),UNUSED);
 					op32(ctx,PUSH,pconst64(&p,(int_val)rb->t),UNUSED);
 					op32(ctx,PUSH,pconst64(&p,hl_hash_utf8(m->code->strings[o->p2])),UNUSED);
 					op32(ctx,PUSH,pconst64(&p,hl_hash_utf8(m->code->strings[o->p2])),UNUSED);
@@ -2728,7 +2724,7 @@ int hl_jit_function( jit_ctx *ctx, hl_module *m, hl_function *f ) {
 				op64(ctx,SUB,PESP,pconst(&p,sizeof(hl_trap_ctx) - HL_WSIZE));
 				op64(ctx,SUB,PESP,pconst(&p,sizeof(hl_trap_ctx) - HL_WSIZE));
 				op64(ctx,MOV,PEAX,PESP);
 				op64(ctx,MOV,PEAX,PESP);
 				op64(ctx,MOV,paddr(&p,&hl_current_trap),PEAX);
 				op64(ctx,MOV,paddr(&p,&hl_current_trap),PEAX);
-				size = pad_stack(ctx, HL_WSIZE);
+				size = pad_before_call(ctx, HL_WSIZE);
 				op64(ctx,PUSH,PEAX,UNUSED);
 				op64(ctx,PUSH,PEAX,UNUSED);
 				call_native(ctx,setjmp,size);
 				call_native(ctx,setjmp,size);
 				op64(ctx,TEST,PEAX,PEAX);
 				op64(ctx,TEST,PEAX,PEAX);

+ 29 - 0
src/module.c

@@ -31,6 +31,32 @@
 
 
 extern void hl_callback_init( void *e );
 extern void hl_callback_init( void *e );
 
 
+static hl_module *cur_module;
+static void *stack_top;
+
+static uchar *module_resolve_symbol( void *addr, uchar *out, int *outSize ) {
+	return NULL;
+}
+
+static int module_capture_stack( void **stack, int size ) {
+	void **stack_ptr = (void**)&stack;
+	void *stack_bottom = stack_ptr;
+	int count = 0;
+	unsigned char *code = cur_module->jit_code;
+	int code_size = cur_module->codesize;
+	while( stack_ptr < (void**)stack_top ) {
+		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( count == size ) break;
+				stack[count++] = module_addr;
+			}
+		}
+	}
+	return count;
+}
+
 static void hl_init_enum( hl_type_enum *e ) {
 static void hl_init_enum( hl_type_enum *e ) {
 	int i, j;
 	int i, j;
 	for(i=0;i<e->nconstructs;i++) {
 	for(i=0;i<e->nconstructs;i++) {
@@ -216,6 +242,9 @@ int hl_module_init( hl_module *m ) {
 		m->functions_ptrs[f->findex] = ((unsigned char*)m->jit_code) + ((int_val)m->functions_ptrs[f->findex]);
 		m->functions_ptrs[f->findex] = ((unsigned char*)m->jit_code) + ((int_val)m->functions_ptrs[f->findex]);
 	}
 	}
 	hl_callback_init(((unsigned char*)m->jit_code) + entry);
 	hl_callback_init(((unsigned char*)m->jit_code) + entry);
+	cur_module = m;
+	stack_top = &m;
+	hl_exception_setup(module_resolve_symbol, module_capture_stack);
 	hl_jit_free(ctx);
 	hl_jit_free(ctx);
 	return 1;
 	return 1;
 }
 }

+ 38 - 22
src/std/error.c

@@ -85,20 +85,6 @@ HL_PRIM int hl_get_stack_hash() {
 	return hash;
 	return hash;
 }
 }
 
 
-HL_PRIM void hl_throw( vdynamic *v ) {
-	hl_trap_ctx *t = hl_current_trap;
-#ifdef _WIN32
-	if( v != stack_last_exc ) {
-		stack_last_exc = v;
-		stack_count = CaptureStackBackTrace(1, 0x1000, stack_trace, NULL) - 8; // 8 startup
-		if( stack_count < 0 ) stack_count = 0;
-	}
-#endif
-	hl_current_exc = v;
-	hl_current_trap = t->prev;
-	if( hl_current_trap == NULL ) hl_debug_break();
-	longjmp(t->buf,1);
-}
 
 
 HL_PRIM uchar *hl_resolve_symbol( void *addr, uchar *out, int *outSize ) {
 HL_PRIM uchar *hl_resolve_symbol( void *addr, uchar *out, int *outSize ) {
 #ifdef _WIN32
 #ifdef _WIN32
@@ -110,6 +96,11 @@ HL_PRIM uchar *hl_resolve_symbol( void *addr, uchar *out, int *outSize ) {
 	} data;
 	} data;
 	data.sym.SizeOfStruct = sizeof(data.sym);
 	data.sym.SizeOfStruct = sizeof(data.sym);
 	data.sym.MaxNameLen = 255;
 	data.sym.MaxNameLen = 255;
+	if( !stack_process_handle ) {
+		stack_process_handle = GetCurrentProcess();
+		SymSetOptions(SYMOPT_LOAD_LINES);
+		SymInitialize(stack_process_handle,NULL,TRUE);
+	}
 	if( SymFromAddrW(stack_process_handle,(DWORD64)(int_val)addr,&index,&data.sym) ) {
 	if( SymFromAddrW(stack_process_handle,(DWORD64)(int_val)addr,&index,&data.sym) ) {
 		DWORD offset = 0;
 		DWORD offset = 0;
 		line.SizeOfStruct = sizeof(line);
 		line.SizeOfStruct = sizeof(line);
@@ -123,21 +114,46 @@ HL_PRIM uchar *hl_resolve_symbol( void *addr, uchar *out, int *outSize ) {
 	return NULL;
 	return NULL;
 }
 }
 
 
+static int hl_capture_stack( void **stack, int size ) {
+	int count = 0;
+#	ifdef _WIN32
+	count = CaptureStackBackTrace(2, size, stack, NULL) - 8; // 8 startup
+	if( count < 0 ) count = 0;
+#	endif
+	return count;
+}
+
+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 = hl_resolve_symbol;
+static capture_stack_type capture_stack_func = hl_capture_stack;
+
+HL_PRIM void hl_exception_setup( void *resolve_symbol, void *capture_stack ) {
+	resolve_symbol_func = resolve_symbol;
+	capture_stack_func = capture_stack;
+}
+
+HL_PRIM void hl_throw( vdynamic *v ) {
+	hl_trap_ctx *t = hl_current_trap;
+	if( v != stack_last_exc ) {
+		stack_last_exc = v;
+		stack_count = capture_stack_func(stack_trace, 0x1000);
+	}
+	hl_current_exc = v;
+	hl_current_trap = t->prev;
+	if( hl_current_trap == NULL ) hl_debug_break();
+	longjmp(t->buf,1);
+}
+
 HL_PRIM varray *hl_exception_stack() {
 HL_PRIM varray *hl_exception_stack() {
 	varray *a = hl_alloc_array(&hlt_bytes, stack_count);
 	varray *a = hl_alloc_array(&hlt_bytes, stack_count);
 	int i;
 	int i;
-#ifdef _WIN32
-	if( !stack_process_handle ) {
-		stack_process_handle = GetCurrentProcess();
-		SymSetOptions(SYMOPT_LOAD_LINES);
-		SymInitialize(stack_process_handle,NULL,TRUE);
-	}
-#endif
 	for(i=0;i<stack_count;i++) {
 	for(i=0;i<stack_count;i++) {
 		void *addr = stack_trace[i];
 		void *addr = stack_trace[i];
 		uchar sym[512];
 		uchar sym[512];
 		int size = 512;
 		int size = 512;
-		uchar *str = hl_resolve_symbol(addr, sym, &size);
+		uchar *str = resolve_symbol_func(addr, sym, &size);
 		if( str == NULL ) {
 		if( str == NULL ) {
 			int iaddr = (int)(int_val)addr;
 			int iaddr = (int)(int_val)addr;
 			str = sym;
 			str = sym;