Jelajahi Sumber

fixed stack align, callthis ok

Nicolas Cannasse 10 tahun lalu
induk
melakukan
049bb59ba2
5 mengubah file dengan 178 tambahan dan 58 penghapusan
  1. 9 0
      src/alloc.c
  2. 1 0
      src/code.c
  3. 10 0
      src/hl.h
  4. 157 58
      src/jit.c
  5. 1 0
      src/opcodes.h

+ 9 - 0
src/alloc.c

@@ -149,6 +149,15 @@ vobj *hl_alloc_obj( hl_module *m, hl_type *t ) {
 vclosure *hl_alloc_closure_void( hl_module *m, int_val fid ) {
 	vclosure *c = (vclosure*)malloc(sizeof(vclosure));
 	c->fun = m->functions_ptrs[fid];
+	c->bits = 0;
+	return c;
+}
+
+vclosure *hl_alloc_closure_int( hl_module *m, int fid, int v ) {
+	vclosure *c = (vclosure*)malloc(sizeof(vclosure));
+	c->fun = m->functions_ptrs[fid];
+	c->bits = CL_HAS_V32;
+	c->v32 = v;
 	return c;
 }
 

+ 1 - 0
src/code.c

@@ -223,6 +223,7 @@ static void hl_read_opcode( hl_reader *r, hl_function *f, hl_opcode *o ) {
 		case OCallN:
 		case OCallClosure:
 		case OCallMethod:
+		case OCallThis:
 			{
 				int i;
 				o->p1 = INDEX();

+ 10 - 0
src/hl.h

@@ -243,8 +243,16 @@ struct vobj {
 	vobj_proto *proto;
 };
 
+#define CL_HAS_V32		1
+#define CL_HAS_V64		2
+
 struct vclosure {
 	void *fun;
+	int bits;
+	union {
+		int v32;
+		int_val v64;
+	};
 };
 
 struct hl_runtime_obj {
@@ -263,6 +271,8 @@ vdynamic *hl_alloc_dynamic( hl_type *t );
 vobj *hl_alloc_obj( hl_module *m, hl_type *t );
 
 vclosure *hl_alloc_closure_void( hl_module *m, int_val f );
+vclosure *hl_alloc_closure_int( hl_module *m, int f, int v );
+
 /*
 vclosure *hl_alloc_closure_int( hl_module *m, int_val f, int param );
 vclosure *hl_alloc_closure_double( hl_module *m, int_val f, double param );

+ 157 - 58
src/jit.c

@@ -172,6 +172,9 @@ static int RCPU_SCRATCH_REGS[] = { Eax, Ecx, Edx };
 #define R(id)		(ctx->vregs + (id))
 #define ASSERT(i)	{ printf("JIT ERROR %d (jic.c line %d)\n",i,__LINE__); jit_exit(); }
 #define IS_FLOAT(r)	((r)->t->kind == HF64)
+#define LOCK(r)		if( (r)->lock < ctx->currentPos ) (r)->lock = ctx->currentPos
+
+#define BREAK()		B(0xCC)
 
 static preg _unused = { 0, 0, RUNUSED, NULL };
 static preg *UNUSED = &_unused;
@@ -332,10 +335,10 @@ static const char *preg_str( jit_ctx *ctx, preg *r, bool mode64 ) {
 				sprintf(buf,"%s ptr[%c%Xh]",mode64 ? "qword" : "dword", regOrOffs<0?'-':'+',regOrOffs<0?-regOrOffs:regOrOffs);
 			} else if( mult == 0 ) {
 				int off = regOrOffs;
-				if( r->id < 8 )
-					sprintf(buf,"[%c%s %c %Xh]",mode64?'r':'e',REG_NAMES[r->id], off < 0 ? '-' : '+', off < 0 ? -off : off);
+				if( reg < 8 )
+					sprintf(buf,"[%c%s %c %Xh]",mode64?'r':'e',REG_NAMES[reg], off < 0 ? '-' : '+', off < 0 ? -off : off);
 				else
-					sprintf(buf,"[r%d%s %c %Xh]",r->id,mode64?"":"d",off < 0 ? '-' : '+', off < 0 ? -off : off);
+					sprintf(buf,"[r%d%s %c %Xh]",reg,mode64?"":"d",off < 0 ? '-' : '+', off < 0 ? -off : off);
 			} else {
 				return "TODO";
 			}
@@ -474,6 +477,35 @@ static void op( jit_ctx *ctx, CpuOp o, preg *a, preg *b, bool mode64 ) {
 			if( mode64 && IS_64 ) W64(cval); else W((int)cval);
 		}
 		break;
+	case ID2(RMEM,RUNUSED):
+		ERRIF( f->r_mem == 0 );
+		{
+			int mult = a->id & 0xF;
+			int regOrOffs = mult == 15 ? a->id >> 4 : a->id >> 8;  
+			CpuReg reg = (a->id >> 4) & 0xF;
+			if( mult == 15 ) {
+				ERRIF(1);
+			} else if( mult == 0 ) {
+				if( reg > 7 ) r64 |= 1;
+				OP(f->r_mem);
+				if( regOrOffs == 0 && (reg&7) != Ebp ) {
+					MOD_RM(0,GET_RM(f->r_mem)-1,reg);
+					if( (reg&7) == Esp ) B(0x24);
+				} else if( IS_SBYTE(regOrOffs) ) {
+					MOD_RM(1,GET_RM(f->r_mem)-1,reg);
+					if( (reg&7) == Esp ) B(0x24);
+					B(regOrOffs);
+				} else {
+					MOD_RM(2,GET_RM(f->r_mem)-1,reg);
+					if( (reg&7) == Esp ) B(0x24);
+					W(regOrOffs);
+				}
+			} else {
+				// [eax + ebx * M]
+				ERRIF(1);
+			}
+		}
+		break;
 	case ID2(RCPU, RMEM):
 	case ID2(RFPU, RMEM):
 		ERRIF( f->r_mem == 0 );
@@ -816,7 +848,7 @@ static CpuReg CALL_REGS[] = { Ecx, Edx, R8, R9 };
 static int prepare_call_args( jit_ctx *ctx, int count, int *args, bool isNative ) {
 	int i;
 	int stackRegs = count;
-	int size = 0;
+	int size = 0, paddedSize;
 	preg p;
 #ifdef HL_64
 	if( isNative ) {
@@ -845,55 +877,53 @@ static int prepare_call_args( jit_ctx *ctx, int count, int *args, bool isNative
 					break;
 				}
 			}
-			if( r->lock < ctx->currentPos )
-				r->lock = ctx->currentPos;
+			LOCK(r);
 		}
 		stackRegs = count - i;
 	}
 #endif
 	for(i=0;i<stackRegs;i++) {
-		vreg *r = R(args[count - (i + 1)]);
+		vreg *r = R(args[i]);
 		size += hl_pad_size(size,r->t);
 		size += r->size;
 	}
-	size = pad_stack(ctx,size);
-	{
-		int size2 = 0;
-		for(i=0;i<stackRegs;i++) {
-			// RTL
-			vreg *r = R(args[count - (i + 1)]);
-			int pad = hl_pad_size(size2,r->t);
-			if( (i & 7) == 0 ) jit_buf(ctx);
-			if( pad ) {
-				op64(ctx,SUB,PESP,pconst(&p,pad));
-				size2 += size;
-			}
-			switch( r->size ) {
-			case 4:
-				if( !IS_64 )
-					op32(ctx,PUSH,fetch(r),UNUSED);
-				else {
-					// pseudo push32 (not available)
-					op64(ctx,SUB,PESP,pconst(&p,4));
-					op32(ctx,MOV,pmem(&p,Esp,0,0),alloc_cpu(ctx,r,true));
-				}
-				break;
-			case 8:
-				if( fetch(r)->kind == RFPU ) {
-					op64(ctx,SUB,PESP,pconst(&p,8));
-					op64(ctx,MOVSD,pmem(&p,Esp,0,0),fetch(r));
-				} else if( IS_64 )
-					op64(ctx,PUSH,fetch(r),UNUSED);
-				else
-					ASSERT(r->t->kind);
-				break;
-			default:
-				ASSERT(r->size);
+	paddedSize = pad_stack(ctx,size);
+	size = paddedSize - size;
+	for(i=0;i<stackRegs;i++) {
+		// RTL
+		vreg *r = R(args[count - (i + 1)]);
+		int pad;
+		size += r->size;
+		pad = hl_pad_size(size,r->t);
+		if( (i & 7) == 0 ) jit_buf(ctx);
+		if( pad ) {
+			op64(ctx,SUB,PESP,pconst(&p,pad));
+			size += pad;
+		}
+		switch( r->size ) {
+		case 4:
+			if( !IS_64 )
+				op32(ctx,PUSH,fetch(r),UNUSED);
+			else {
+				// pseudo push32 (not available)
+				op64(ctx,SUB,PESP,pconst(&p,4));
+				op32(ctx,MOV,pmem(&p,Esp,0,0),alloc_cpu(ctx,r,true));
 			}
-			size2 += r->size;
+			break;
+		case 8:
+			if( fetch(r)->kind == RFPU ) {
+				op64(ctx,SUB,PESP,pconst(&p,8));
+				op64(ctx,MOVSD,pmem(&p,Esp,0,0),fetch(r));
+			} else if( IS_64 )
+				op64(ctx,PUSH,fetch(r),UNUSED);
+			else
+				ASSERT(r->t->kind);
+			break;
+		default:
+			ASSERT(r->size);
 		}
 	}
-	return size;
+	return paddedSize;
 }
 
 static void call_native( jit_ctx *ctx, void *nativeFun, int size ) {
@@ -916,11 +946,7 @@ static void op_call_fun( jit_ctx *ctx, vreg *dst, int findex, int count, int *ar
 	int i = 0, size = prepare_call_args(ctx,count,args,isNative);
 	preg p;
 	if( fid < 0 ) {
-		// closure
-		preg *r = alloc_cpu(ctx, R(-findex), true);
-		op64(ctx,MOV,PEAX,pmem(&p,(CpuReg)r->id,0,0));
-		op64(ctx,CALL,PEAX,UNUSED);
-		discard_regs(ctx, 1);
+		ASSERT(fid);
 	} else if( isNative ) {
 		call_native(ctx,ctx->m->functions_ptrs[findex],size);
 		size = 0;
@@ -1192,9 +1218,9 @@ int hl_jit_function( jit_ctx *ctx, hl_module *m, hl_function *f ) {
 	size = 0;
 	for(i=0;i<nargs;i++) {
 		vreg *r = R(i);
+		size += hl_pad_size(size,r->t);
 		r->stackPos = size + HL_WSIZE * 2;
 		size += r->size;
-		size += hl_pad_size(-size,r->t);
 	}
 	size = 0;
 	for(i=nargs;i<f->nregs;i++) {
@@ -1227,8 +1253,11 @@ int hl_jit_function( jit_ctx *ctx, hl_module *m, hl_function *f ) {
 				void *addr = m->globals_data + m->globals_indexes[o->p2];
 				if( IS_FLOAT(to) )
 					op64(ctx,MOVSD,r,paddr(&p,addr));
-				else
-					op32(ctx,MOV,r,paddr(&p,addr));
+				else if( IS_64 ) {
+					op64(ctx,MOV,r,pconst64(&p,(int_val)addr));
+					op32(ctx,MOV,r,pmem(&p,r->id,0,0));
+				} else
+					op64(ctx,MOV,r,paddr(&p,addr));
 				store(ctx, to, r, false);
 			}
 			break;
@@ -1237,9 +1266,14 @@ int hl_jit_function( jit_ctx *ctx, hl_module *m, hl_function *f ) {
 				vreg *r = R(o->p2);
 				preg *v = IS_FLOAT(r) ? alloc_fpu(ctx,r,true) : alloc_cpu(ctx,r,true);
 				void *addr = m->globals_data + m->globals_indexes[o->p1];
+				LOCK(v);
 				if( IS_FLOAT(r) )
 					op64(ctx,MOVSD,paddr(&p,addr),v);
-				else
+				else if( IS_64 ) {
+					preg *tmp = alloc_reg(ctx, RCPU);
+					op64(ctx,MOV,tmp,pconst64(&p,(int_val)addr));
+					op32(ctx,MOV,pmem(&p,(CpuReg)tmp->id,0,0),v);
+				} else
 					op32(ctx,MOV,paddr(&p,addr),v);
 			}
 			break;
@@ -1341,12 +1375,37 @@ int hl_jit_function( jit_ctx *ctx, hl_module *m, hl_function *f ) {
 				store(ctx, r, PEAX, true);
 			}
 			break;
+		case OClosure:
+			{
+				vreg *arg = R(o->p3);
+				if( arg->size == 8 ) {
+					TODO();
+				} else if( !IS_64 ) {
+					int size = pad_stack(ctx, HL_WSIZE*3);
+					op64(ctx,PUSH,fetch(arg),UNUSED);
+					op64(ctx,PUSH,pconst(&p,o->p2),UNUSED);
+					op64(ctx,PUSH,pconst(&p,(int)m),UNUSED);
+					call_native(ctx,hl_alloc_closure_int,size);
+				}
+				store(ctx, R(o->p1), PEAX, true);
+			}
+			break;
 		case OCallClosure:
-			// TODO : if closure has value ?
-			// TODO : if closure is native ?
-			// TODO : how to apply first value ?
-			// requires dynamic branching ?
-			op_call_fun(ctx,R(o->p1),-o->p2,o->p3,o->extra);
+			{
+				preg *r = alloc_cpu(ctx, R(o->p2), true);
+				preg *tmp;
+				LOCK(r);
+				BREAK();
+				tmp = alloc_reg(ctx, RCPU);
+				// read address
+				op64(ctx,MOV,PEAX,pmem(&p,(CpuReg)r->id,0,0));
+				// read bits
+				op32(ctx,MOV,tmp,pmem(&p,(CpuReg)r->id,HL_WSIZE,0));
+				// TODO : check bits
+				//	build args based on 3 cases (32,64,NoValue)
+				op64(ctx,CALL,PEAX,UNUSED);
+				discard_regs(ctx, 1);
+			}
 			break;
 		case OGetThis:
 			{
@@ -1354,7 +1413,7 @@ int hl_jit_function( jit_ctx *ctx, hl_module *m, hl_function *f ) {
 				hl_runtime_obj *rt = hl_get_obj_rt(m, r->t);
 				preg *rr = alloc_cpu(ctx,r, true);
 				preg *rv;
-				if( rr->lock < i ) rr->lock = i;
+				LOCK(rr);
 				rv = alloc_reg(ctx,RCPU);
 				if( rr == rv ) ASSERT(0);
 				// TODO : copy data
@@ -1368,13 +1427,53 @@ int hl_jit_function( jit_ctx *ctx, hl_module *m, hl_function *f ) {
 				hl_runtime_obj *rt = hl_get_obj_rt(m, r->t);
 				preg *rr = alloc_cpu(ctx, r, true);
 				preg *rv;
-				if( rr->lock < i ) rr->lock = i;
+				LOCK(rr);
 				rv = alloc_cpu(ctx, R(o->p2), true);
 				if( rr == rv ) ASSERT(0);
 				// TODO : copy data
 				op32(ctx, MOV, pmem(&p, (CpuReg)rr->id, rt->fields_indexes[o->p1], 0), rv);
 			}
 			break;
+		case OCallThis:
+			{
+				int nargs = o->p3 + 1;
+				int *args = (int*)hl_malloc(&ctx->falloc,sizeof(int) * nargs);
+				int size,k;
+				vreg *dst = R(o->p1);
+				preg *r = alloc_cpu(ctx, R(0), true);
+				preg *tmp;
+				LOCK(r);
+				tmp = alloc_reg(ctx, RCPU);
+				LOCK(tmp);
+				op64(ctx,MOV,tmp,pmem(&p,r->id,0,0)); // read proto
+				args[0] = 0;
+				for(k=1;k<nargs;k++)
+					args[k] = o->extra[k-1];
+				size = prepare_call_args(ctx,nargs,args,false);
+				op64(ctx,CALL,pmem(&p,tmp->id,(o->p2 + 1)*HL_WSIZE,0),UNUSED);
+				discard_regs(ctx, 1);
+				op64(ctx,ADD,PESP,pconst(&p,size));
+				store(ctx, dst, IS_FLOAT(dst) ? PXMM(0) : PEAX, true);
+			}
+			break;
+		case OCallMethod:
+			{
+				int size;
+				vreg *dst = R(o->p1);
+				preg *r = alloc_cpu(ctx, R(o->extra[0]), true);
+				preg *tmp;
+				LOCK(r);
+				tmp = alloc_reg(ctx, RCPU);
+				LOCK(tmp);
+				// TODO : check r == NULL
+				op64(ctx,MOV,tmp,pmem(&p,r->id,0,0)); // read proto
+				size = prepare_call_args(ctx,o->p3,o->extra,false);
+				op64(ctx,CALL,pmem(&p,tmp->id,(o->p2 + 1)*HL_WSIZE,0),UNUSED);
+				discard_regs(ctx, 1);
+				op64(ctx,ADD,PESP,pconst(&p,size));
+				store(ctx, dst, IS_FLOAT(dst) ? PXMM(0) : PEAX, true);
+			}
+			break;
 		default:
 			printf("Don't know how to jit %s\n",hl_op_name(o->op));
 			break;

+ 1 - 0
src/opcodes.h

@@ -47,6 +47,7 @@ OP_BEGIN
 	OP(OCall4,6)
 	OP(OCallN,-1)
 	OP(OCallMethod,-1)
+	OP(OCallThis,-1)
 	OP(OCallClosure,-1)
 	OP(OGetFunction,2)
 	OP(OClosure,3)