Browse Source

array variance should be ok

Nicolas Cannasse 9 years ago
parent
commit
8d3abd40cc

+ 340 - 125
genhl.ml

@@ -56,6 +56,7 @@ and class_proto = {
 	mutable psuper : class_proto option;
 	mutable pvirtuals : int array;
 	mutable pproto : field_proto array;
+	mutable pnfields : int;
 	mutable pfields : (string * string index * ttype) array;
 	mutable pindex : (string, int * ttype) PMap.t;
 	mutable pfunctions : (string, int) PMap.t;
@@ -230,6 +231,8 @@ type method_context = {
 }
 
 type array_impl = {
+	abase : tclass;
+	adyn : tclass;
 	aobj : tclass;
 	ai32 : tclass;
 	af64 : tclass;
@@ -266,7 +269,7 @@ type access =
 	| AInstanceFun of texpr * fundecl index
 	| AInstanceProto of texpr * field index
 	| AInstanceField of texpr * field index
-	| AArray of texpr * texpr
+	| AArray of reg * ttype * reg
 	| AVirtualMethod of texpr * field index
 	| ADynamic of texpr * string index
 	| AEnum of field index
@@ -276,12 +279,6 @@ let list_iteri f l =
 	let p = ref 0 in
 	List.iter (fun v -> f !p v; incr p) l
 
-let field_type f =
-	match f with
-	| FInstance (_,_,f) | FStatic (_,f) | FAnon f | FClosure (_,f) -> f.cf_type
-	| FDynamic _ -> t_dynamic
-	| FEnum (_,f) -> f.ef_type
-
 let rec tstr ?(stack=[]) ?(detailed=false) t =
 	match t with
 	| HVoid -> "void"
@@ -391,6 +388,13 @@ let to_utf8 str =
 			String.iter (fun c -> UTF8.Buf.add_char b (UChar.of_char c)) str;
 			UTF8.Buf.contents b
 
+let type_size_bits = function
+	| HI8 | HBool -> 0
+	| HI16 -> 1
+	| HI32 | HF32 -> 2
+	| HF64 -> 3
+	| _ -> assert false
+
 let iteri f l =
 	let p = ref (-1) in
 	List.iter (fun v -> incr p; f !p v) l
@@ -410,6 +414,7 @@ let null_proto =
 		pvirtuals = [||];
 		pproto = [||];
 		pfields = [||];
+		pnfields = 0;
 		pindex = PMap.empty;
 		pfunctions = PMap.empty;
 	}
@@ -471,11 +476,30 @@ let alloc_i32 ctx i =
 let alloc_string ctx s =
 	lookup ctx.cstrings s (fun() -> s)
 
+let array_class ctx t =
+	match t with
+	| HI32 ->
+		ctx.array_impl.ai32
+	| HF64 ->
+		ctx.array_impl.af64
+	| HDyn ->
+		ctx.array_impl.adyn
+	| _ ->
+		ctx.array_impl.aobj
+
 let member_fun c t =
 	match follow t with
 	| TFun (args, ret) -> TFun (("this",false,TInst(c,[])) :: args, ret)
 	| _ -> assert false
 
+let rec get_index name p =
+	try
+		PMap.find name p.pindex
+	with Not_found ->
+		match p.psuper with
+		| None -> raise Not_found
+		| Some p -> get_index name p
+
 let rec unsigned t =
 	match follow t with
 	| TAbstract ({ a_path = ["hl";"types"],("UI32"|"UI16"|"UI8") },_) -> true
@@ -582,14 +606,14 @@ let rec to_type ctx t =
 			| [], "Enum" -> HType
 			| [], "EnumValue" -> HDyn
 			| ["hl";"types"], "Ref" -> HRef (to_type ctx (List.hd pl))
-			| ["hl";"types"], "Bytes" -> HBytes
+			| ["hl";"types"], ("Bytes" | "BytesAccess") -> HBytes
 			| ["hl";"types"], "Type" -> HType
 			| ["hl";"types"], "NativeArray" -> HArray
 			| _ -> failwith ("Unknown core type " ^ s_type_path a.a_path))
 		else
 			to_type ctx (Abstract.get_underlying_type a pl)
 
-and array_type ctx t =
+and native_array_type ctx t =
 	let et = to_type ctx t in
 	if is_dynamic et then et else HDyn
 
@@ -599,18 +623,29 @@ and resolve_class ctx c pl =
 	in
 	match c.cl_path, pl with
 	| ([],"Array"), [t] ->
-		(match to_type ctx t with
-		| HI32 ->
-			ctx.array_impl.ai32
-		| HF64 ->
-			ctx.array_impl.af64
-		| _ ->
-			ctx.array_impl.aobj)
+		array_class ctx (to_type ctx t)
 	| _, _ when c.cl_extern ->
 		not_supported()
 	| _ ->
 		c
 
+and field_type ctx f p =
+	match f with
+	| FInstance (c,pl,f) ->
+		let creal = resolve_class ctx c pl in
+		let rec loop c =
+			try
+				PMap.find f.cf_name c.cl_fields
+			with Not_found ->
+				match c.cl_super with
+				| Some (csup,_) -> loop csup
+				| None -> error (s_type_path creal.cl_path ^ " is missing field " ^ f.cf_name) p
+		in
+		(loop creal).cf_type
+	| FStatic (_,f) | FAnon f | FClosure (_,f) -> f.cf_type
+	| FDynamic _ -> t_dynamic
+	| FEnum (_,f) -> f.ef_type
+
 and class_type ctx c pl statics =
 	let c = if c.cl_extern && not statics then resolve_class ctx c pl else c in
 	let key_path = (if statics then fst c.cl_path, "$" ^ snd c.cl_path else c.cl_path) in
@@ -639,35 +674,45 @@ and class_type ctx c pl statics =
 			pindex = PMap.empty;
 			pvirtuals = [||];
 			pfunctions = PMap.empty;
+			pnfields = -1;
 		} in
 		let t = HObj p in
 		ctx.cached_types <- PMap.add key_path t ctx.cached_types;
-		if statics && c == ctx.base_class then assert false;
+		if c == ctx.base_class then begin
+			if statics then assert false;
+			p.pnfields <- 1;
+		end;
 		let csup = (if statics then Some (ctx.base_class,[]) else c.cl_super) in
 		let start_field, virtuals = (match csup with
 			| None -> 0, [||]
 			| Some (c,pl) ->
 				match class_type ctx c pl false with
 				| HObj psup ->
+					if psup.pnfields < 0 then assert false;
 					p.psuper <- Some psup;
-					p.pindex <- psup.pindex;
 					p.pfunctions <- psup.pfunctions;
-					Array.length p.pfields, p.pvirtuals
+					psup.pnfields, psup.pvirtuals
 				| _ -> assert false
 		) in
 		let fa = DynArray.create() and pa = DynArray.create() and virtuals = DynArray.of_array virtuals in
+		let todo = ref [] in
 		List.iter (fun f ->
 			if is_extern_field f then () else
 			match f.cf_kind with
 			| Var _ | Method MethDynamic ->
-				let t = to_type ctx f.cf_type in
-				p.pindex <- PMap.add f.cf_name (DynArray.length fa + start_field, t) p.pindex;
-				DynArray.add fa (f.cf_name, alloc_string ctx f.cf_name, t);
+				let fid = DynArray.length fa in
+				p.pindex <- PMap.add f.cf_name (fid + start_field, t) p.pindex;
+				DynArray.add fa (f.cf_name, alloc_string ctx f.cf_name, HVoid);
+				todo := (fun() ->
+					let t = to_type ctx f.cf_type in
+					p.pindex <- PMap.add f.cf_name (fid + start_field, t) p.pindex;
+					Array.set p.pfields fid (f.cf_name, alloc_string ctx f.cf_name, t)
+				) :: !todo;
 			| Method _ ->
 				let g = alloc_fid ctx c f in
 				p.pfunctions <- PMap.add f.cf_name g p.pfunctions;
 				let virt = if List.memq f c.cl_overrides then
-					Some (try fst (PMap.find f.cf_name p.pindex) with Not_found -> assert false)
+					Some (try fst (get_index f.cf_name p) with Not_found -> assert false)
 				else if is_overriden ctx c f then begin
 					let vid = DynArray.length virtuals in
 					DynArray.add virtuals g;
@@ -684,9 +729,11 @@ and class_type ctx c pl statics =
 			DynArray.add pa { fname = "__string"; fid = alloc_string ctx "__string"; fmethod = alloc_fun_path ctx c.cl_path "__string"; fvirtual = None; }
 		with Not_found ->
 			());
+		p.pnfields <- DynArray.length fa + start_field;
 		p.pfields <- DynArray.to_array fa;
 		p.pproto <- DynArray.to_array pa;
 		p.pvirtuals <- DynArray.to_array virtuals;
+		List.iter (fun f -> f()) !todo;
 		if not statics && c != ctx.base_class then p.pclassglobal <- Some (fst (class_global ctx c));
 		t
 
@@ -786,6 +833,37 @@ let reg_int ctx v =
 	op ctx (OInt (r,alloc_i32 ctx (Int32.of_int v)));
 	r
 
+
+let read_mem ctx rdst bytes index t =
+	match t with
+	| HI8 ->
+		op ctx (OGetI8 (rdst,bytes,index))
+(*	| HI16 ->
+		op ctx (OGetI16 (rdst,bytes,index))*)
+	| HI32 ->
+		op ctx (OGetI32 (rdst,bytes,index))
+	| HF32 ->
+		op ctx (OGetF32 (rdst,bytes,index))
+	| HF64 ->
+		op ctx (OGetF64 (rdst,bytes,index))
+	| _ ->
+		assert false
+
+let write_mem ctx bytes index t r=
+	match t with
+	| HI8 ->
+		op ctx (OSetI8 (bytes,index,r))
+(*	| HI16 ->
+		op ctx (OSetI16 (bytes,index,r))*)
+	| HI32 ->
+		op ctx (OSetI32 (bytes,index,r))
+	| HF32 ->
+		op ctx (OSetF32 (bytes,index,r))
+	| HF64 ->
+		op ctx (OSetF64 (bytes,index,r))
+	| _ ->
+		assert false
+
 let common_type ctx e1 e2 for_eq p =
 	let t1 = to_type ctx e1.etype in
 	let t2 = to_type ctx e2.etype in
@@ -890,6 +968,10 @@ and cast_to ctx (r:reg) (t:ttype) p =
 		let fr = alloc_tmp ctx t in
 		op ctx (OClosure (fr,fid,r));
 		fr
+	| HObj ({ pname = "hl.types.ArrayBasic_Int" | "hl.types.ArrayBasic_Float" | "hl.types.ArrayObj" } as p), HObj { pname = "hl.types.ArrayDyn" } ->
+		let tmp = alloc_tmp ctx t in
+		op ctx (OCallMethod (tmp,(try fst (get_index "toDynamic" p) with Not_found -> assert false),[r])); (* call toDynamic() *)
+		tmp
 	| _ ->
 		invalid()
 
@@ -913,7 +995,7 @@ and object_access ctx eobj t f =
 	match t with
 	| HObj p ->
 		(try
-			let fid = fst (PMap.find f.cf_name p.pindex) in
+			let fid = fst (get_index f.cf_name p) in
 			if f.cf_kind = Method MethNormal then
 				AInstanceProto (eobj, fid)
 			else
@@ -963,7 +1045,13 @@ and get_access ctx e =
 	| TParenthesis e ->
 		get_access ctx e
 	| TArray (a,i) ->
-		AArray (a,i)
+		(match follow a.etype with
+		| TInst({ cl_path = [],"Array" },[t]) ->
+			let a = eval_null_check ctx a in
+			let i = eval_to ctx i HI32 in
+			AArray (a,to_type ctx t,i)
+		| _ ->
+			error ("Invalid array access on " ^ s_type (print_context()) a.etype) e.epos)
 	| _ ->
 		ANone
 
@@ -1001,7 +1089,7 @@ and jump_expr ctx e jcond =
 		if not jcond then j();
 		(fun() -> if jcond then j(); j2());
 	| _ ->
-		let r = eval_expr ctx e in
+		let r = eval_to ctx e HBool in
 		jump ctx (fun i -> if jcond then OJTrue (r,i) else OJFalse (r,i))
 
 and eval_args ctx el t =
@@ -1159,6 +1247,98 @@ and eval_expr ctx e =
 			let r = eval_to ctx v HF64 in
 			op ctx (OSetF64 (b, pos, r));
 			r
+		| "$bytes_sizebits", [eb] ->
+			(match follow eb.etype with
+			| TAbstract({a_path = ["hl";"types"],"BytesAccess"},[t]) ->
+				reg_int ctx (match to_type ctx t with
+				| HI8 -> 0
+				| HI16 -> 1
+				| HI32 -> 2
+				| HF32 -> 2
+				| HF64 -> 3
+				| t -> error ("Unsupported basic type " ^ tstr t) e.epos)
+			| _ ->
+				error "Invalid BytesAccess" eb.epos);
+		| "$bytes_nullvalue", [eb] ->
+			(match follow eb.etype with
+			| TAbstract({a_path = ["hl";"types"],"BytesAccess"},[t]) ->
+				let t = to_type ctx t in
+				let r = alloc_tmp ctx t in
+				(match t with
+				| HI8 | HI16 | HI32 ->
+					op ctx (OInt (r,alloc_i32 ctx 0l))
+				| HF32 | HF64 ->
+					op ctx (OFloat (r, alloc_float ctx 0.))
+				| t ->
+					error ("Unsupported basic type " ^ tstr t) e.epos);
+				r
+			| _ ->
+				error "Invalid BytesAccess" eb.epos);
+		| "$bget", [eb;pos] ->
+			(match follow eb.etype with
+			| TAbstract({a_path = ["hl";"types"],"BytesAccess"},[t]) ->
+				let b = eval_to ctx eb HBytes in
+				let pos = eval_to ctx pos HI32 in
+				let t = to_type ctx t in
+				(match t with
+				| HI8 ->
+					let r = alloc_tmp ctx HI32 in
+					op ctx (OGetI8 (r, b, pos));
+					r
+				(*| HI16 ->
+					let r = alloc_tmp ctx HI32 in
+					op ctx (OShl (pos,pos,alloc_i32 ctx 1l));
+					op ctx (OGetI16 (r, b, pos));
+					r*)
+				| HI32 ->
+					let r = alloc_tmp ctx HI32 in
+					op ctx (OShl (pos,pos,reg_int ctx 2));
+					op ctx (OGetI32 (r, b, pos));
+					r
+				| HF32 ->
+					let r = alloc_tmp ctx HF32 in
+					op ctx (OShl (pos,pos,reg_int ctx 2));
+					op ctx (OGetF32 (r, b, pos));
+					r
+				| HF64 ->
+					let r = alloc_tmp ctx HF64 in
+					op ctx (OShl (pos,pos,reg_int ctx 3));
+					op ctx (OGetF64 (r, b, pos));
+					r
+				| _ ->
+					error ("Unsupported basic type " ^ tstr t) e.epos)
+			| _ ->
+				error "Invalid BytesAccess" eb.epos);
+		| "$bset", [eb;pos;value] ->
+			(match follow eb.etype with
+			| TAbstract({a_path = ["hl";"types"],"BytesAccess"},[t]) ->
+				let b = eval_to ctx eb HBytes in
+				let pos = eval_to ctx pos HI32 in
+				let t = to_type ctx t in
+				(match t with
+				| HI8 ->
+					let v = eval_to ctx value HI32 in
+					op ctx (OSetI8 (b, pos, v));
+					v
+				| HI32 ->
+					let v = eval_to ctx value HI32 in
+					op ctx (OShl (pos,pos,reg_int ctx 2));
+					op ctx (OSetI32 (b, pos, v));
+					v
+				| HF32 ->
+					let v = eval_to ctx value HF32 in
+					op ctx (OShl (pos,pos,reg_int ctx 2));
+					op ctx (OSetF32 (b, pos, v));
+					v
+				| HF64 ->
+					let v = eval_to ctx value HF64 in
+					op ctx (OShl (pos,pos,reg_int ctx 3));
+					op ctx (OSetF64 (b, pos, v));
+					v
+				| _ ->
+					error ("Unsupported basic type " ^ tstr t) e.epos)
+			| _ ->
+				error "Invalid BytesAccess" eb.epos);
 		| "$bgeti8", [b;pos] ->
 			let b = eval_to ctx b HBytes in
 			let pos = eval_to ctx pos HI32 in
@@ -1188,7 +1368,7 @@ and eval_expr ctx e =
 			op ctx (OArraySize (r, eval_to ctx e HArray));
 			r
 		| "$aalloc", [esize] ->
-			let et = (match follow e.etype with TAbstract ({ a_path = ["hl";"types"],"NativeArray" },[t]) -> array_type ctx t | _ -> invalid()) in
+			let et = (match follow e.etype with TAbstract ({ a_path = ["hl";"types"],"NativeArray" },[t]) -> native_array_type ctx t | _ -> invalid()) in
 			let a = alloc_tmp ctx HArray in
 			let rt = alloc_tmp ctx HType in
 			op ctx (OType (rt,et));
@@ -1214,7 +1394,7 @@ and eval_expr ctx e =
 			in
 			cast_to ctx r (to_type ctx e.etype) e.epos
 		| "$aset", [a; pos; value] ->
-			let et = (match follow a.etype with TAbstract ({ a_path = ["hl";"types"],"NativeArray" },[t]) -> array_type ctx t | _ -> invalid()) in
+			let et = (match follow a.etype with TAbstract ({ a_path = ["hl";"types"],"NativeArray" },[t]) -> native_array_type ctx t | _ -> invalid()) in
 			let arr = eval_to ctx a HArray in
 			let pos = eval_to ctx pos HI32 in
 			let r = eval_to ctx value et in
@@ -1232,7 +1412,7 @@ and eval_expr ctx e =
 			error ("Unknown native call " ^ v.v_name) e.epos)
 	| TCall (ec,el) ->
 		let real_type = (match ec.eexpr with
-			| TField (_,f) -> field_type f
+			| TField (_,f) -> field_type ctx f ec.epos
 			| _ -> ec.etype
 		) in
 		let tfun = to_type ctx real_type in
@@ -1268,7 +1448,7 @@ and eval_expr ctx e =
 		);
 		unsafe_cast_to ctx ret (to_type ctx e.etype) e.epos
 	| TField (ec,a) ->
-		let r = alloc_tmp ctx (to_type ctx (field_type a)) in
+		let r = alloc_tmp ctx (to_type ctx (field_type ctx a e.epos)) in
 		(match get_access ctx e with
 		| AGlobal g ->
 			op ctx (OGetGlobal (r,g));
@@ -1441,19 +1621,27 @@ and eval_expr ctx e =
 				let r = value() in
 				op ctx (OMov (l, r));
 				r
-			| AArray (a,idx) ->
-				let a = eval_null_check ctx a in
-				let idx = eval_to ctx idx HI32 in
+			| AArray (ra,at,ridx) ->
 				let v = value() in
 				(* bounds check against length *)
-				let len = alloc_tmp ctx HI32 in
-				op ctx (OField (len,a,1));
-				let j = jump ctx (fun i -> OJULt (idx,len,i)) in
-				op ctx (OCall2 (alloc_tmp ctx HVoid, alloc_fun_path ctx (["hl";"types"],"ArrayObj") "__expand", a, idx));
-				j();
-				let arr = alloc_tmp ctx HArray in
-				op ctx (OField (arr,a,0));
-				op ctx (OSetArray (arr,idx,v));
+				(match at with
+				| HDyn ->
+					(* call setDyn() *)
+					op ctx (OCallMethod (alloc_tmp ctx HVoid,1,[ra;ridx;v]));
+				| _ ->
+					let len = alloc_tmp ctx HI32 in
+					op ctx (OField (len,ra,0)); (* length *)
+					let j = jump ctx (fun i -> OJULt (ridx,len,i)) in
+					op ctx (OCall2 (alloc_tmp ctx HVoid, alloc_fun_path ctx (array_class ctx at).cl_path "__expand", ra, ridx));
+					j();
+					match at with
+					| HI32 | HF64 ->
+						assert false
+					| _ ->
+						let arr = alloc_tmp ctx HArray in
+						op ctx (OField (arr,ra,1));
+						op ctx (OSetArray (arr,ridx,v))
+				);
 				v
 			| ADynamic (ethis,f) ->
 				let obj = eval_null_check ctx ethis in
@@ -1503,6 +1691,35 @@ and eval_expr ctx e =
 				binop r r b;
 				op ctx (OSetField (robj,findex,r));
 				r
+			| AArray (ra,at,ridx) ->
+				(* bounds check against length *)
+				(match at with
+				| HDyn ->
+					(* call getDyn() *)
+					let r = alloc_tmp ctx HDyn in
+					op ctx (OCallMethod (r,0,[ra;ridx]));
+					binop r r (eval_to ctx e2 HDyn);
+					(* call setDyn() *)
+					op ctx (OCallMethod (alloc_tmp ctx HVoid,1,[ra;ridx;r]));
+					r
+				| _ ->
+					let len = alloc_tmp ctx HI32 in
+					op ctx (OField (len,ra,0)); (* length *)
+					let j = jump ctx (fun i -> OJULt (ridx,len,i)) in
+					op ctx (OCall2 (alloc_tmp ctx HVoid, alloc_fun_path ctx (array_class ctx at).cl_path "__expand", ra, ridx));
+					j();
+					match at with
+					| HI32 | HF64 ->
+						assert false
+					| _ ->
+						let arr = alloc_tmp ctx HArray in
+						op ctx (OField (arr,ra,1));
+						let r = alloc_tmp ctx at in
+						op ctx (OGetArray (r,arr,ridx));
+						binop r r (eval_to ctx e2 at);
+						op ctx (OSetArray (arr,ridx,r));
+						r
+				)
 			| _ ->
 				error ("TODO " ^ s_expr (s_type (print_context())) e) e.epos
 			)
@@ -1659,7 +1876,7 @@ and eval_expr ctx e =
 				let r = eval_to ctx e HI32 in
 				op ctx (OSetI32 (b,reg_int ctx (i * 4),r));
 			) el;
-			op ctx (OCall2 (r, alloc_fun_path ctx (["hl";"types"],"ArrayI32") "alloc", b, reg_int ctx (List.length el)));
+			op ctx (OCall2 (r, alloc_fun_path ctx (["hl";"types"],"ArrayBase") "allocI32", b, reg_int ctx (List.length el)));
 		| HF64 ->
 			let b = alloc_tmp ctx HBytes in
 			let size = reg_int ctx ((List.length el) * 8) in
@@ -1668,7 +1885,7 @@ and eval_expr ctx e =
 				let r = eval_to ctx e HF64 in
 				op ctx (OSetF64 (b,reg_int ctx (i * 8),r));
 			) el;
-			op ctx (OCall2 (r, alloc_fun_path ctx (["hl";"types"],"ArrayF64") "alloc", b, reg_int ctx (List.length el)));
+			op ctx (OCall2 (r, alloc_fun_path ctx (["hl";"types"],"ArrayBase") "allocF64", b, reg_int ctx (List.length el)));
 		| _ ->
 			let at = if is_dynamic et then et else HDyn in
 			let a = alloc_tmp ctx HArray in
@@ -1680,77 +1897,64 @@ and eval_expr ctx e =
 				let r = eval_to ctx e at in
 				op ctx (OSetArray (a,reg_int ctx i,r));
 			) el;
-			op ctx (OCall1 (r, alloc_fun_path ctx (["hl";"types"],"ArrayObj") "alloc", a)));
+			let tmp = if et = HDyn then alloc_tmp ctx (class_type ctx ctx.array_impl.aobj [] false) else r in
+			op ctx (OCall1 (tmp, alloc_fun_path ctx (["hl";"types"],"ArrayObj") "alloc", a));
+			if tmp <> r then op ctx (OCallMethod (r, 2, [tmp])); (* call toDynamic() *)
+		);
 		r
-	| TArray (a,i) ->
-		let ra = eval_null_check ctx a in
-		let ri = eval_to ctx i HI32 in
-		let ra, at = (match follow a.etype with
-			| TInst ({ cl_path = [],"Array" },[t]) -> ra, to_type ctx t
-			| t when t == t_dynamic ->
-				let at = e.etype in
-				let aa = alloc_tmp ctx (to_type ctx (ctx.com.basic.tarray at)) in
-				op ctx (OSafeCast (aa,ra));
-				aa, to_type ctx at
+	| TArray _ ->
+		(match get_access ctx e with
+		| AArray (ra,at,ridx) ->
+			(match at with
+			| HI8 | HI16 | HI32 | HF32 | HF64 ->
+				(* check bounds *)
+				let length = alloc_tmp ctx HI32 in
+				op ctx (OField (length, ra, 0));
+				let r = alloc_tmp ctx at in
+				let j = jump ctx (fun i -> OJULt (ridx,length,i)) in
+				(match at with
+				| HI8 | HI16 | HI32 ->
+					op ctx (OInt (r,alloc_i32 ctx 0l));
+				| HF32 | HF64 ->
+					op ctx (OFloat (r,alloc_float ctx 0.));
+				| _ ->
+					assert false);
+				let jend = jump ctx (fun i -> OJAlways i) in
+				j();
+				let r2 = alloc_tmp ctx HI32 in
+				let bits = type_size_bits at in
+				if bits > 0 then begin
+					op ctx (OInt (r2,alloc_i32 ctx (Int32.of_int bits)));
+					op ctx (OShl (ridx,ridx,r2));
+				end;
+				let hbytes = alloc_tmp ctx HBytes in
+				op ctx (OField (hbytes, ra, 1));
+				read_mem ctx r hbytes ridx at;
+				jend();
+				r
+			| HDyn ->
+				(* call getDyn *)
+				let r = alloc_tmp ctx HDyn in
+				op ctx (OCallMethod (r,0,[ra;ridx]));
+				unsafe_cast_to ctx r at e.epos
 			| _ ->
-				error ("Invalid array access on " ^ s_type (print_context()) a.etype) a.epos
-		) in
-		(match at with
-		| HI32 ->
-			let hbytes = alloc_tmp ctx HBytes in
-			op ctx (OField (hbytes, ra, 0));
-
-			(* check bounds *)
-			let size = alloc_tmp ctx HI32 in
-			op ctx (OField (size, ra, 2));
-			let r = alloc_tmp ctx at in
-			let j = jump ctx (fun i -> OJULt (ri,size,i)) in
-			op ctx (OInt (r,alloc_i32 ctx 0l));
-			let jend = jump ctx (fun i -> OJAlways i) in
-			j();
-			let r2 = alloc_tmp ctx HI32 in
-			op ctx (OInt (r2,alloc_i32 ctx 2l));
-			op ctx (OShl (ri,ri,r2));
-			op ctx (OGetI32 (r,hbytes,ri));
-			jend();
-			r
-		| HF64 ->
-			let hbytes = alloc_tmp ctx HBytes in
-			op ctx (OField (hbytes, ra, 0));
-
-			(* check bounds *)
-			let size = alloc_tmp ctx HI32 in
-			op ctx (OField (size, ra, 2));
-			let r = alloc_tmp ctx at in
-			let j = jump ctx (fun i -> OJULt (ri,size,i)) in
-			op ctx (OFloat (r,alloc_float ctx 0.));
-			let jend = jump ctx (fun i -> OJAlways i) in
-			j();
-			let r2 = alloc_tmp ctx HI32 in
-			op ctx (OInt (r2,alloc_i32 ctx 3l));
-			op ctx (OShl (ri,ri,r2));
-			op ctx (OGetF64 (r,hbytes,ri));
-			jend();
-			r
+				(* check bounds *)
+				let length = alloc_tmp ctx HI32 in
+				op ctx (OField (length,ra,0));
+				let r = alloc_tmp ctx at in
+				let j = jump ctx (fun i -> OJULt (ridx,length,i)) in
+				op ctx (ONull r);
+				let jend = jump ctx (fun i -> OJAlways i) in
+				j();
+				let tmp = alloc_tmp ctx HDyn in
+				let harr = alloc_tmp ctx HArray in
+				op ctx (OField (harr,ra,1));
+				op ctx (OGetArray (tmp,harr,ridx));
+				op ctx (OMov (r,unsafe_cast_to ctx tmp at e.epos));
+				jend();
+				r);
 		| _ ->
-			let harr = alloc_tmp ctx HArray in
-			op ctx (OField (harr, ra, 0));
-
-			(* check bounds *)
-			let size = alloc_tmp ctx HI32 in
-			op ctx (OArraySize (size,harr));
-			let r = alloc_tmp ctx at in
-			let j = jump ctx (fun i -> OJULt (ri,size,i)) in
-			op ctx (ONull r);
-			let jend = jump ctx (fun i -> OJAlways i) in
-			j();
-			let tmp = alloc_tmp ctx HDyn in
-			op ctx (OGetArray (tmp,harr,ri));
-			let r2 = unsafe_cast_to ctx tmp at e.epos in
-			op ctx (OMov (r,r2));
-			jend();
-			r
-		);
+			assert false);
 	| TMeta (_,e) ->
 		eval_expr ctx e
 	| TFor _ ->
@@ -2052,8 +2256,6 @@ let generate_static ctx c f =
 	match f.cf_kind with
 	| Var _ | Method MethDynamic ->
 		()
-	| Method m when f.cf_expr = None ->
-		() (* ? *)
 	| Method m ->
 		let rec loop = function
 			| (Meta.Custom ":hlNative",[(EConst(String(lib)),_);(EConst(String(name)),_)] ,_ ) :: _ ->
@@ -2065,7 +2267,11 @@ let generate_static ctx c f =
 			| (Meta.Custom ":hlNative",_ ,p) :: _ ->
 				error "Invalid @:hlNative decl" p
 			| [] ->
-				ignore(make_fun ctx (alloc_fid ctx c f) (match f.cf_expr with Some { eexpr = TFunction f } -> f | _ -> error "Missing method body" f.cf_pos) None None)
+				let null_fun() =
+					let t_void = ctx.com.basic.tvoid in
+					{ tf_expr = mk (TBlock []) t_void f.cf_pos; tf_type = t_void; tf_args = []; }
+				in
+				ignore(make_fun ctx (alloc_fid ctx c f) (match f.cf_expr with Some { eexpr = TFunction f } -> f | _ -> null_fun()) None None)
 			| _ :: l ->
 				loop l
 		in
@@ -2176,12 +2382,9 @@ let check code =
 
 	let check_fun f =
 		let pos = ref 0 in
-		let debug() =
-			let dfile, dline = f.debug.(!pos) in
-			Printf.sprintf "%s(%d)" code.debugfiles.(dfile) dline
-		in
 		let error msg =
-			failwith ("Check failure " ^ msg ^ "\nAt " ^ string_of_int f.findex ^ "@" ^ string_of_int (!pos) ^ " " ^ debug())
+			let dfile, dline = f.debug.(!pos) in
+			failwith (Printf.sprintf "\n%s:%d: Check failure at %d@%d - %s" code.debugfiles.(dfile) dline f.findex (!pos) msg)
 		in
 		let targs, tret = (match f.ftype with HFun (args,ret) -> args, ret | _ -> assert false) in
 		let rtype i = f.regs.(i) in
@@ -2327,6 +2530,7 @@ let check code =
 			| OCallClosure (r,f,rl) ->
 				(match rtype f with
 				| HFun (targs,tret) when List.length targs = List.length rl -> List.iter2 reg rl targs; reg r tret
+				| HDyn -> List.iter (fun r -> ignore(rtype r)) rl;
 				| _ -> reg f (HFun(List.map rtype rl,rtype r)))
 			| OGetGlobal (r,g) | OSetGlobal (g,r) ->
 				reg r code.globals.(g)
@@ -2811,7 +3015,7 @@ let interp code =
 		| VObj o ->
 			let rec loop p =
 				try
-					let idx, t = PMap.find field p.pindex in
+					let idx, t = get_index field p in
 					set_with o.ofields.(idx) t
 				with Not_found -> try
 					let fid = PMap.find field p.pfunctions in
@@ -2909,6 +3113,10 @@ let interp code =
 
 
 	and call f args =
+		let fret = (match f.ftype with
+			| HFun (fargs,fret) -> if List.length fargs <> List.length args then error "Invalid args"; fret
+			| _ -> assert false
+		) in
 		let regs = Array.create (Array.length f.regs) VUndef in
 		let pos = ref 0 in
 		stack := (f,pos) :: !stack;
@@ -3101,7 +3309,9 @@ let interp code =
 				| VObj v as o -> set r (fcall v.oproto.pmethods.(m) (o :: List.map get rl))
 				| _ -> assert false)
 			| OCallClosure (r,v,rl) ->
-				(match get v with
+				if rtype v = HDyn then
+					set r (dyn_call (get v) (List.map (fun r -> get r, rtype r) rl) (rtype r))
+				else (match get v with
 				| VClosure (f,None) -> set r (fcall f (List.map get rl))
 				| VClosure (f,Some arg) -> set r (fcall f (arg :: List.map get rl))
 				| VNull -> null_access()
@@ -3208,7 +3418,7 @@ let interp code =
 				| VObj o, HVirtual vp ->
 					let indexes = Array.mapi (fun i (n,_,t) ->
 						try
-							let idx, ft = PMap.find n o.oproto.pclass.pindex in
+							let idx, ft = get_index n o.oproto.pclass in
 							if not (tsame t ft) then error ("Can't cast " ^ tstr (rtype rv) ^ " to " ^ tstr (rtype r) ^ "(" ^ n ^ " type differ)");
 							VFIndex idx
 						with Not_found ->
@@ -3297,7 +3507,10 @@ let interp code =
 			try
 				loop()
 			with
-				| Return v -> stack := List.tl !stack; v
+				| Return v ->
+					check v fret (fun() -> "return value");
+					stack := List.tl !stack;
+					v
 				| InterpThrow v ->
 					match !traps with
 					| [] ->
@@ -3940,9 +4153,11 @@ let generate com =
 		cfids = new_lookup();
 		defined_funs = Hashtbl.create 0;
 		array_impl = {
+			abase = get_class "ArrayBase";
+			adyn = get_class "ArrayDyn";
 			aobj = get_class "ArrayObj";
-			ai32 = get_class "ArrayI32";
-			af64 = get_class "ArrayF64";
+			ai32 = get_class "ArrayBasic_Int";
+			af64 = get_class "ArrayBasic_Float";
 		};
 		base_class = get_class "Class";
 		base_type = get_class "TypeDecl";

+ 1 - 3
std/hl/Boot.hx

@@ -1,8 +1,6 @@
 package hl;
 
-import hl.types.ArrayObj;
-import hl.types.ArrayI32;
-import hl.types.ArrayF64;
+import hl.types.ArrayDyn;
 import hl.types.Class;
 
 extern class Boot {

+ 6 - 4
std/hl/_std/Reflect.hx

@@ -20,7 +20,7 @@
  * DEALINGS IN THE SOFTWARE.
  */
 
-@:coreApi 
+@:coreApi
 class Reflect {
 
 	public static function hasField( o : Dynamic, field : String ) : Bool {
@@ -48,16 +48,18 @@ class Reflect {
 	}
 
 	public static function callMethod( o : Dynamic, func : haxe.Constraints.Function, args : Array<Dynamic> ) : Dynamic {
+		var args : hl.types.ArrayDyn = cast args;
 		var count = args.length;
 		var nargs = o == null ? count : count + 1;
-		var args : hl.types.ArrayObj<Dynamic> = cast args;
 		var a = new hl.types.NativeArray<Dynamic>(nargs);
 		if( o == null ) {
-			a.blit(1,@:privateAccess args.array,0,count);
+			for( i in 0...count )
+				a[i] = args.getDyn(i);
 		} else {
 			func = hl.types.Api.noClosure(func);
 			a[0] = o;
-			a.blit(1,@:privateAccess args.array,0,count);
+			for( i in 0...count )
+				a[i+1] = args.getDyn(i);
 		}
 		return hl.types.Api.callMethod(func,a);
 	}

+ 1 - 1
std/hl/types/Api.hx

@@ -5,6 +5,6 @@ extern class Api {
 	@:hlNative("std","get_field") static function getField( obj : Dynamic, hash : Int ) : Dynamic;
 	@:hlNative("std","call_method") static function callMethod( f : haxe.Constraints.Function, args : NativeArray<Dynamic> ) : Dynamic;
 	@:hlNative("std","no_closure") static function noClosure( f : haxe.Constraints.Function ) : haxe.Constraints.Function;
+	@:hlNative("std", "safe_cast") static function safeCast( v : Dynamic, t : Type ) : Dynamic;
 
 }
-	

+ 260 - 0
std/hl/types/ArrayBase.hx

@@ -0,0 +1,260 @@
+package hl.types;
+
+@:keep
+class ArrayAccess {
+
+	public function getDyn( pos : Int ) : Dynamic {
+		throw "Not implemented";
+		return 0;
+	}
+
+	public function setDyn( pos : Int, v : Dynamic ) {
+		throw "Not implemented";
+	}
+
+}
+
+@:keep
+class ArrayBase extends ArrayAccess {
+
+	public var length(default,null) : Int;
+
+	public function toDynamic() : ArrayDyn {
+		throw "Not implemented";
+		return null;
+	}
+
+	public function pushDyn( v : Dynamic ) : Int {
+		throw "Not implemented";
+		return 0;
+	}
+
+	public function popDyn() : Null<Dynamic> {
+		throw "Not implemented";
+		return null;
+	}
+
+	public function shiftDyn() : Null<Dynamic> {
+		throw "Not implemented";
+		return null;
+	}
+
+	public function unshiftDyn( v : Dynamic ) : Void {
+		throw "Not implemented";
+	}
+
+	public function insertDyn( v : Dynamic, pos : Int ) : Void {
+		throw "Not implemented";
+	}
+
+	public function removeDyn( v : Dynamic ) : Bool {
+		throw "Not implemented";
+		return false;
+	}
+
+	public function sortDyn( f : Dynamic -> Dynamic -> Int ) : Void {
+		throw "Not implemented";
+	}
+
+	public function spliceDyn( pos : Int, len : Int ) : ArrayObj<Dynamic> {
+		throw "Not implemented";
+		return null;
+	}
+
+	public function join( sep : String ) : String {
+		throw "Not implemented";
+		return null;
+	}
+
+	public function reverse() {
+		throw "Not implemented";
+	}
+
+	public function toString() : String {
+		throw "Not implemented";
+		return null;
+	}
+
+
+	public static function allocI32( bytes : BytesAccess<Int>, length : Int ) @:privateAccess {
+		var a : ArrayI32 = untyped $new(ArrayI32);
+		a.length = length;
+		a.bytes = bytes;
+		a.size = length;
+		return a;
+	}
+
+	public static function allocF64( bytes : BytesAccess<Float>, length : Int ) @:privateAccess {
+		var a : ArrayF64 = untyped $new(ArrayF64);
+		a.length = length;
+		a.bytes = bytes;
+		a.size = length;
+		return a;
+	}
+
+}
+
+@:generic class ArrayBasic<T> extends ArrayBase {
+
+	var bytes : hl.types.BytesAccess<T>;
+	var size : Int;
+
+	public function new() {
+		size = length = 0;
+		bytes = new Bytes(0);
+	}
+
+	public function concat( a : ArrayBasic<T> ) : ArrayBasic<T> {
+		throw "TODO";
+		return null;
+	}
+
+	override function join( sep : String ) : String {
+		throw "TODO";
+		return null;
+	}
+
+	public function pop() : Null<T> {
+		if( length == 0 )
+			return null;
+		length--;
+		return bytes[length];
+	}
+
+	public function push(x : T) : Int {
+		var len = length;
+		if( size == len )
+			__expand(len);
+		else
+			length++;
+		bytes[len] = x;
+		return length;
+	}
+
+	override function reverse() : Void {
+		throw "TODO";
+	}
+
+	public function shift() : Null<T> {
+		throw "TODO";
+		return null;
+	}
+
+	public function slice( pos : Int, ?end : Int ) : ArrayBasic<T> {
+		throw "TODO";
+		return null;
+	}
+
+	public function sort( f : T -> T -> Int ) : Void {
+		throw "TODO";
+	}
+
+	public function splice( pos : Int, len : Int ) : ArrayBasic<T> {
+		throw "TODO";
+		return null;
+	}
+
+	override function toString() : String {
+		var b = new StringBuf();
+		b.addChar("[".code);
+		for( i in 0...length ) {
+			if( i > 0 ) b.addChar(",".code);
+			b.add(bytes[i]);
+		}
+		b.addChar("]".code);
+		return b.toString();
+	}
+
+	public function unshift( x : T ) : Void {
+		throw "TODO";
+	}
+
+	public function insert( pos : Int, x : T ) : Void {
+		throw "TODO";
+	}
+
+	public function remove( x : T ) : Bool {
+		throw "TODO";
+		return false;
+	}
+
+	public function indexOf( x : T, ?fromIndex:Int ) : Int {
+		throw "TODO";
+		return -1;
+	}
+
+	public function lastIndexOf( x : T, ?fromIndex:Int ) : Int {
+		throw "TODO";
+		return -1;
+	}
+
+	public function copy() : ArrayBasic<T> {
+		throw "TODO";
+		return null;
+	}
+
+	public function iterator() : Iterator<T> {
+		throw "TODO";
+		return null;
+	}
+
+	public function map<S>( f : T -> S ) : ArrayDyn {
+		throw "TODO";
+		return null;
+	}
+
+	public function filter( f : Int -> Bool ) : ArrayBasic<T> {
+		throw "TODO";
+		return null;
+	}
+
+	override function toDynamic() : ArrayDyn {
+		throw "TODO";
+		return null;
+	}
+
+	override function getDyn( pos : Int ) : Dynamic {
+		var pos : UInt = pos;
+		if( pos >= length )
+			return bytes.nullValue;
+		return bytes[pos];
+	}
+
+	override function setDyn( pos : Int, v : Dynamic ) {
+		var pos : UInt = pos;
+		if( pos >= length )
+			__expand(pos);
+		bytes[pos] = v;
+	}
+
+	override function pushDyn( v : Dynamic ) return push(v);
+	override function popDyn() : Null<Dynamic> return pop();
+	override function shiftDyn() : Null<Dynamic> return shift();
+	override function unshiftDyn( v : Dynamic ) unshift(v);
+	override function insertDyn( pos : Int, v : Dynamic ) insert(pos, v);
+	override function removeDyn( v : Dynamic ) return remove(v);
+	override function sortDyn( f : Dynamic -> Dynamic -> Int ) sort(f);
+	override function spliceDyn( pos : Int, len : Int ) : ArrayObj<Dynamic> {
+		throw "Not implemented";
+		return null;
+	}
+
+	// called by compiler when accessing the array outside of its bounds, might trigger resize
+	function __expand( index : Int ) {
+		if( index < 0 ) throw "Invalid array access";
+		var newlen = index + 1;
+		if( newlen > size ) {
+			var next = (size * 3) >> 1;
+			if( next < newlen ) next = newlen;
+			var bytes2 = new hl.types.Bytes(next << bytes.sizeBits);
+			bytes2.blit(0,bytes,0,length << bytes.sizeBits);
+			bytes = bytes2;
+			size = next;
+		}
+		length = newlen;
+	}
+
+}
+
+typedef ArrayI32 = ArrayBasic<Int>;
+typedef ArrayF64 = ArrayBasic<Float>;

+ 139 - 0
std/hl/types/ArrayDyn.hx

@@ -0,0 +1,139 @@
+package hl.types;
+
+@:keep
+class ArrayDyn extends ArrayBase.ArrayAccess {
+
+	// TODO : for Dynamic access, we need to support __getField(hash("length")) !
+	public var length(get,never) : Int;
+	var array : ArrayBase;
+	var allowReinterpret : Bool;
+
+	public function new() {
+		array = new ArrayObj<Dynamic>();
+		allowReinterpret = true;
+	}
+
+	inline function get_length() return array.length;
+
+	override function getDyn(i) {
+		return array.getDyn(i);
+	}
+
+	override function setDyn(pos,value) {
+		array.setDyn(pos, value);
+	}
+
+	public function concat( a : ArrayDyn ) : ArrayDyn {
+		var a1 = array;
+		var a2 = a.array;
+		var alen = a1.length;
+		var anew = new NativeArray<Dynamic>(alen + a2.length);
+		for( i in 0...alen )
+			anew[i] = a1.getDyn(i);
+		for( i in 0...a2.length )
+			anew[i+alen] = a2.getDyn(i);
+		return alloc(ArrayObj.alloc(anew),true);
+	}
+
+	public function join( sep : String ) : String {
+		return array.join(sep);
+	}
+
+	public function pop() : Null<Dynamic> {
+		return array.popDyn();
+	}
+
+	public function push(x : Dynamic) : Int {
+		return array.pushDyn(x);
+	}
+
+	public function reverse() : Void {
+		array.reverse();
+	}
+
+	public function shift() : Null<Dynamic> {
+		return array.shiftDyn();
+	}
+
+	public function slice( pos : Int, ?end : Int ) : ArrayDyn {
+		throw "TODO";
+		return null;
+	}
+
+	public function sort( f : Dynamic -> Dynamic -> Int ) : Void {
+		array.sortDyn(f);
+	}
+
+	public function splice( pos : Int, len : Int ) : ArrayDyn {
+		return alloc(array.spliceDyn(pos,len),true);
+	}
+
+	public function toString() : String {
+		return array.toString();
+	}
+
+	public function unshift( x : Dynamic ) : Void {
+		array.unshiftDyn(x);
+	}
+
+	public function insert( pos : Int, x : Dynamic ) : Void {
+		array.insertDyn(pos,x);
+	}
+
+	public function remove( x : Dynamic ) : Bool {
+		return array.removeDyn(x);
+	}
+
+	public function indexOf( x : Dynamic, ?fromIndex:Int ) : Int {
+		var i : Int = fromIndex;
+		var length = length;
+		var array = array;
+		while( i < length ) {
+			if( array.getDyn(i) == x )
+				return i;
+			i++;
+		}
+		return -1;
+	}
+
+	public function lastIndexOf( x : Dynamic, ?fromIndex:Int ) : Int {
+		throw "TODO";
+		return -1;
+	}
+
+	public function copy() : ArrayDyn {
+		var a = new NativeArray<Dynamic>(length);
+		for( i in 0...length )
+			a[i] = array.getDyn(i);
+		return alloc(ArrayObj.alloc(a),true);
+	}
+
+	public function iterator() : Iterator<Dynamic> {
+		throw "TODO";
+		return null;
+	}
+
+	public function map( f : Dynamic -> Dynamic ) : ArrayDyn {
+		var a = new NativeArray<Dynamic>(length);
+		for( i in 0...length )
+			a[i] = f(array.getDyn(i));
+		return alloc(ArrayObj.alloc(a),true);
+	}
+
+	public function filter( f : Dynamic -> Bool ) : ArrayDyn {
+		var a = new ArrayObj<Dynamic>();
+		for( i in 0...length ) {
+			var v = array.getDyn(i);
+			if( f(v) ) a.push(v);
+		}
+		return alloc(a,true);
+	}
+
+	public static function alloc( a : ArrayBase, allowReinterpret = false ) : ArrayDyn {
+		var arr : ArrayDyn = untyped $new(ArrayDyn);
+		arr.array = a;
+		arr.allowReinterpret = allowReinterpret;
+		return arr;
+	}
+
+}

+ 0 - 142
std/hl/types/ArrayF64.hx

@@ -1,142 +0,0 @@
-package hl.types;
-
-@:keep
-class ArrayF64 {
-
-	var bytes : hl.types.Bytes;
-	var size : Int;
-	public var length(default,null) : Int;
-
-	public function new() {
-		size = length = 0;
-		bytes = new Bytes(0);
-	}
-
-	public function concat( a : ArrayF64 ) : ArrayF64 {
-		throw "TODO";
-		return null;
-	}
-
-	public function join( sep : String ) : String {
-		throw "TODO";
-		return null;
-	}
-
-	public function pop() : Null<Float> {
-		if( length == 0 )
-			return null;
-		length--;
-		return bytes.getF64(length << 3);
-	}
-
-	public function push(x : Float) : Int {
-		var len = length;
-		if( size == len )
-			__expand(len);
-		else
-			length++;
-		bytes.setF64(len<<3,x);
-		return length;
-	}
-
-	public function reverse() : Void {
-		throw "TODO";
-	}
-
-	public function shift() : Null<Float> {
-		throw "TODO";
-		return null;
-	}
-
-	public function slice( pos : Int, ?end : Int ) : ArrayF64 {
-		throw "TODO";
-		return null;
-	}
-
-	public function sort( f : Float -> Float -> Int ) : Void {
-		throw "TODO";
-	}
-
-	public function splice( pos : Int, len : Int ) : ArrayF64 {
-		throw "TODO";
-		return null;
-	}
-
-	public function toString() : String {
-		var b = new StringBuf();
-		b.addChar("[".code);
-		for( i in 0...length ) {
-			if( i > 0 ) b.addChar(",".code);
-			b.add(bytes.getF64(i<<3));
-		}
-		b.addChar("]".code);
-		return b.toString();
-	}
-
-	public function unshift( x : Float ) : Void {
-		throw "TODO";
-	}
-
-	public function insert( pos : Int, x : Float ) : Void {
-		throw "TODO";
-	}
-
-	public function remove( x : Float ) : Bool {
-		throw "TODO";
-		return false;
-	}
-
-	public function indexOf( x : Float, ?fromIndex:Int ) : Int {
-		throw "TODO";
-		return -1;
-	}
-
-	public function lastIndexOf( x : Float, ?fromIndex:Int ) : Int {
-		throw "TODO";
-		return -1;
-	}
-
-	public function copy() : ArrayF64 {
-		throw "TODO";
-		return null;
-	}
-
-	public function iterator() : Iterator<Float> {
-		throw "TODO";
-		return null;
-	}
-
-	public function map<S>( f : Float -> S ) : ArrayObj<S> {
-		throw "TODO";
-		return null;
-	}
-
-	public function filter( f : Float -> Bool ) : ArrayF64 {
-		throw "TODO";
-		return null;
-	}
-	
-	// called by compiler when accessing the array outside of its bounds, might trigger resize
-	function __expand( index : Int ) {
-		if( index < 0 ) throw "Invalid array access";
-		var newlen = index + 1;
-		if( newlen > size ) {
-			var next = (size * 3) >> 1;
-			if( next < newlen ) next = newlen;
-			var bytes2 = new hl.types.Bytes(next<<3);
-			if( length > 0 ) bytes2.blit(0,bytes,0,length<<3);
-			bytes = bytes2;
-			size = next;
-		}
-		length = newlen;
-	}
-	
-	public static function alloc( a : hl.types.Bytes, length : Int ) {
-		var arr : ArrayF64 = untyped $new(ArrayF64);
-		arr.bytes = a;
-		arr.length = length;
-		arr.size = length;
-		return arr;
-	}
-
-}

+ 0 - 142
std/hl/types/ArrayI32.hx

@@ -1,142 +0,0 @@
-package hl.types;
-
-@:keep
-class ArrayI32 {
-
-	var bytes : hl.types.Bytes;
-	var size : Int;
-	public var length(default,null) : Int;
-
-	public function new() {
-		size = length = 0;
-		bytes = new Bytes(0);
-	}
-
-	public function concat( a : ArrayI32 ) : ArrayI32 {
-		throw "TODO";
-		return null;
-	}
-
-	public function join( sep : String ) : String {
-		throw "TODO";
-		return null;
-	}
-
-	public function pop() : Null<Int> {
-		if( length == 0 )
-			return null;
-		length--;
-		return bytes.getI32(length<<2);
-	}
-
-	public function push(x : Int) : Int {
-		var len = length;
-		if( size == len )
-			__expand(len);
-		else
-			length++;
-		bytes.setI32(len<<2,x);
-		return length;
-	}
-
-	public function reverse() : Void {
-		throw "TODO";
-	}
-
-	public function shift() : Null<Int> {
-		throw "TODO";
-		return null;
-	}
-
-	public function slice( pos : Int, ?end : Int ) : ArrayI32 {
-		throw "TODO";
-		return null;
-	}
-
-	public function sort( f : Int -> Int -> Int ) : Void {
-		throw "TODO";
-	}
-
-	public function splice( pos : Int, len : Int ) : ArrayI32 {
-		throw "TODO";
-		return null;
-	}
-
-	public function toString() : String {
-		var b = new StringBuf();
-		b.addChar("[".code);
-		for( i in 0...length ) {
-			if( i > 0 ) b.addChar(",".code);
-			b.add(bytes.getI32(i<<2));
-		}
-		b.addChar("]".code);
-		return b.toString();
-	}
-
-	public function unshift( x : Int ) : Void {
-		throw "TODO";
-	}
-
-	public function insert( pos : Int, x : Int ) : Void {
-		throw "TODO";
-	}
-
-	public function remove( x : Int ) : Bool {
-		throw "TODO";
-		return false;
-	}
-
-	public function indexOf( x : Int, ?fromIndex:Int ) : Int {
-		throw "TODO";
-		return -1;
-	}
-
-	public function lastIndexOf( x : Int, ?fromIndex:Int ) : Int {
-		throw "TODO";
-		return -1;
-	}
-
-	public function copy() : ArrayI32 {
-		throw "TODO";
-		return null;
-	}
-
-	public function iterator() : Iterator<Int> {
-		throw "TODO";
-		return null;
-	}
-
-	public function map<S>( f : Int -> S ) : ArrayObj<S> {
-		throw "TODO";
-		return null;
-	}
-
-	public function filter( f : Int -> Bool ) : ArrayI32 {
-		throw "TODO";
-		return null;
-	}
-	
-	// called by compiler when accessing the array outside of its bounds, might trigger resize
-	function __expand( index : Int ) {
-		if( index < 0 ) throw "Invalid array access";
-		var newlen = index + 1;
-		if( newlen > size ) {
-			var next = (size * 3) >> 1;
-			if( next < newlen ) next = newlen;
-			var bytes2 = new hl.types.Bytes(next<<2);
-			if( length > 0 ) bytes2.blit(0,bytes,0,length<<2);
-			bytes = bytes2;
-			size = next;
-		}
-		length = newlen;
-	}
-	
-	public static function alloc( a : hl.types.Bytes, length : Int ) {
-		var arr : ArrayI32 = untyped $new(ArrayI32);
-		arr.bytes = a;
-		arr.length = length;
-		arr.size = length;
-		return arr;
-	}
-
-}

+ 29 - 5
std/hl/types/ArrayObj.hx

@@ -1,10 +1,9 @@
 package hl.types;
 
 @:keep
-class ArrayObj<T> {
+class ArrayObj<T> extends ArrayBase {
 
 	var array : hl.types.NativeArray<Dynamic>;
-	public var length(default,null) : Int;
 
 	public function new() {
 		length = 0;
@@ -16,7 +15,7 @@ class ArrayObj<T> {
 		return null;
 	}
 
-	public function join( sep : String ) : String {
+	override function join( sep : String ) : String {
 		throw "TODO";
 		return null;
 	}
@@ -40,7 +39,7 @@ class ArrayObj<T> {
 		return length;
 	}
 
-	public function reverse() : Void {
+	override function reverse() : Void {
 		throw "TODO";
 	}
 
@@ -63,7 +62,7 @@ class ArrayObj<T> {
 		return null;
 	}
 
-	public function toString() : String {
+	override function toString() : String {
 		var b = new StringBuf();
 		b.addChar("[".code);
 		for( i in 0...length ) {
@@ -143,6 +142,31 @@ class ArrayObj<T> {
 		length = newlen;
 	}
 
+	override function getDyn( pos : Int ) : Dynamic {
+		var pos : UInt = pos;
+		if( pos >= length )
+			return null;
+		return array[pos];
+	}
+	override function setDyn( pos : Int, v : Dynamic ) {
+		var pos : UInt = pos;
+		if( pos >= length )
+			__expand(pos);
+		array[pos] = Api.safeCast(v,array.getType());
+	}
+
+	override function toDynamic() : ArrayDyn {
+		return ArrayDyn.alloc(this, false);
+	}
+	override function pushDyn( v : Dynamic ) return push(v);
+	override function popDyn() : Null<Dynamic> return pop();
+	override function shiftDyn() : Null<Dynamic> return shift();
+	override function unshiftDyn( v : Dynamic ) unshift(v);
+	override function insertDyn( pos : Int, v : Dynamic ) insert(pos, v);
+	override function removeDyn( v : Dynamic ) return remove(v);
+	override function sortDyn( f : Dynamic -> Dynamic -> Int ) sort(f);
+	override function spliceDyn( pos : Int, len : Int ) return splice(pos, len);
+
 	public static function alloc( a : hl.types.NativeArray<Dynamic> ) {
 		var arr : ArrayObj<Dynamic> = untyped $new(ArrayObj);
 		arr.array = a;

+ 26 - 0
std/hl/types/BytesAccess.hx

@@ -0,0 +1,26 @@
+package hl.types;
+
+@:coreType abstract BytesAccess<T> from Bytes to Bytes {
+
+	public var sizeBits(get, never) : Int;
+	public var nullValue(get, never) : T;
+
+
+	@:isExtern inline function get_sizeBits() {
+		return untyped $bytes_sizebits(this);
+	}
+
+	@:isExtern inline function get_nullValue() {
+		return untyped $bytes_nullvalue(this);
+	}
+
+	@:arrayAccess public inline function get( pos : Int ) : T {
+		return untyped $bget(this,pos);
+	}
+
+	@:arrayAccess public inline function set( pos : Int, value : T ) : T {
+		untyped $bset(this,pos,value);
+		return value;
+	}
+
+}

+ 16 - 5
std/hl/types/NativeArray.hx

@@ -4,37 +4,48 @@ package hl.types;
 	var arr : NativeArray<T>;
 	var pos : Int;
 	var length : Int;
-	
+
 	public inline function new(arr:NativeArray<T>) {
 		this.arr = arr;
 		pos = 0;
 		length = arr.length;
 	}
-	
+
 	public inline function hasNext() {
 		return pos < length;
 	}
-	
+
 	public inline function next() {
 		return arr[pos++];
 	}
 }
 
 @:coreType abstract NativeArray<T> {
-	public var length(get,never):Int;	
+
+	public var length(get,never):Int;
+
 	@:extern public inline function new( length : Int ) {
 		this = untyped $aalloc(length);
 	}
+
 	@:extern inline function get_length() : Int {
 		return untyped $asize(this);
 	}
+
 	@:extern @:arrayAccess inline function get( pos : Int ) : T {
 		return untyped $aget(this,pos);
 	}
+
 	@:extern @:arrayAccess inline function set( pos : Int, value : T ) : T {
 		untyped $aset(this,pos,value);
 		return value;
 	}
-	@:hlNative("std","ablit") public function blit( pos : Int, src : NativeArray<T>, srcPos : Int, srcLen : Int ) : Void {
+
+	@:hlNative("std","atype") public function getType() : Type {
+		return null;
+	}
+
+ 	@:hlNative("std","ablit") public function blit( pos : Int, src : NativeArray<T>, srcPos : Int, srcLen : Int ) : Void {
 	}
+
 }