Browse Source

js optimizations :
- moved Array extensions to HxOverrides
- added $iterator to perform runtime iterator lookup (Array still an Iterable)
- move most of __class__/__name__/__ename__ access to js.Boot (allow usage of __feature__)
- use many __feature__ to reduce hello world output
- disable haxe.Log inclusion when only doing a simple 'trace'

Nicolas Cannasse 13 years ago
parent
commit
96cc73b0ed
12 changed files with 299 additions and 121 deletions
  1. 108 31
      genjs.ml
  2. 29 48
      std/js/Boot.hx
  3. 60 0
      std/js/_std/Array.hx
  4. 2 2
      std/js/_std/Date.hx
  5. 43 5
      std/js/_std/HxOverrides.hx
  6. 2 2
      std/js/_std/Reflect.hx
  7. 31 15
      std/js/_std/Std.hx
  8. 5 3
      std/js/_std/String.hx
  9. 5 7
      std/js/_std/Type.hx
  10. 3 1
      typecore.ml
  11. 1 0
      typeload.ml
  12. 10 7
      typer.ml

+ 108 - 31
genjs.ml

@@ -41,8 +41,9 @@ type ctx = {
 	packages : (string list,unit) Hashtbl.t;
 	smap : sourcemap;
 	js_modern : bool;
+	all_features : bool;
 	mutable features : (string, bool) PMap.t;
-
+	mutable boot_init : texpr option;
 	mutable current : tclass;
 	mutable statics : (tclass * string * texpr) list;
 	mutable inits : texpr list;
@@ -87,6 +88,7 @@ let ident s = if Hashtbl.mem kwds s then "$" ^ s else s
 let anon_field s = if Hashtbl.mem kwds s || not (valid_js_ident s) then "'" ^ s ^ "'" else s
 
 let has_feature ctx f =
+	if ctx.all_features then true else
 	try
 		PMap.find f ctx.features
 	with Not_found ->
@@ -96,13 +98,17 @@ let has_feature ctx f =
 			let r = (try 
 				let path = List.rev pack, cl in
 				(match List.find (fun t -> t_path t = path) ctx.com.types with
+				| t when meth = "*" -> (not ctx.com.dead_code_elimination) || has_meta ":?used" (t_infos t).mt_meta
 				| TClassDecl c -> PMap.exists meth c.cl_statics || PMap.exists meth c.cl_fields
 				| _ -> false)
 			with Not_found ->
 				false
 			) in
 			ctx.features <- PMap.add f r ctx.features;
-			r	
+			r
+
+let add_feature ctx f =
+	ctx.features <- PMap.add f true ctx.features
 
 let handle_newlines ctx str =
 	if ctx.com.debug then
@@ -133,7 +139,9 @@ let print ctx =
 
 let unsupported p = error "This expression cannot be compiled to Javascript" p
 
-let add_mapping ctx pos =
+let add_mapping ctx e =
+	if not ctx.com.debug || e.epos.pmin < 0 then () else
+	let pos = e.epos in
 	let smap = ctx.smap in
 	let file = try
 		Hashtbl.find smap.sources_hash pos.pfile
@@ -324,7 +332,7 @@ let gen_constant ctx p = function
 	| TThis -> spr ctx (this ctx)
 	| TSuper -> assert false
 
-let rec gen_call ctx e el =
+let rec gen_call ctx e el in_value =
 	match e.eexpr , el with
 	| TConst TSuper , params ->
 		(match ctx.current.cl_super with
@@ -378,6 +386,20 @@ let rec gen_call ctx e el =
 			spr ctx "}"
 		) (Hashtbl.fold (fun name data acc -> (name,data) :: acc) ctx.com.resources []);
 		spr ctx "]";
+	| TLocal { v_name = "`trace" }, [e;infos] ->
+		if has_feature (if ctx.all_features then { ctx with all_features = false } else ctx) "haxe.Log.trace" then begin
+			let t = (try List.find (fun t -> t_path t = (["haxe"],"Log")) ctx.com.types with _ -> assert false) in
+			spr ctx (ctx.type_accessor t);
+			spr ctx ".trace(";
+			gen_value ctx e;
+			spr ctx ",";
+			gen_value ctx infos;
+			spr ctx ")";
+		end else begin
+			spr ctx "console.log(";
+			gen_value ctx e;
+			spr ctx ")";
+		end
 	| _ ->
 		gen_value ctx e;
 		spr ctx "(";
@@ -385,6 +407,7 @@ let rec gen_call ctx e el =
 		spr ctx ")"
 
 and gen_expr ctx e =
+	add_mapping ctx e;
 	match e.eexpr with
 	| TConst c -> gen_constant ctx e.epos c
 	| TLocal v -> spr ctx (ident v.v_name)
@@ -399,10 +422,16 @@ and gen_expr ctx e =
 		gen_value ctx e1;
 		print ctx " %s " (Ast.s_binop op);
 		gen_value ctx e2;
-	| TField (x,"iterator") when Common.defined ctx.com "js-iterator-wrap" ->
-		print ctx "$iterator(";
-		gen_value ctx x;
-		print ctx ")";
+	| TField (x,"iterator") when has_feature ctx "HxOverrides.iter" ->
+		(match follow x.etype with		
+		| TAnon _ | TDynamic _ | TMono _ ->
+			add_feature ctx "use.$iterator";
+			print ctx "$iterator(";
+			gen_value ctx x;
+			print ctx ")";
+		| _ ->
+			gen_value ctx x;
+			spr ctx (field "iterator"))			
 	| TField (x,s) ->
 		gen_value ctx x;
 		spr ctx (field s)
@@ -410,6 +439,7 @@ and gen_expr ctx e =
 		gen_value ctx x;
 		spr ctx (field s)
 	| TClosure (x,s) ->
+		add_feature ctx "use.$bind";
 		(match x.eexpr with
 		| TConst _ | TLocal _ ->  
 			gen_value ctx x; 
@@ -457,7 +487,7 @@ and gen_expr ctx e =
 		ctx.in_loop <- snd old;
 		ctx.separator <- true
 	| TCall (e,el) ->
-		gen_call ctx e el
+		gen_call ctx e el false
 	| TArrayDecl el ->
 		spr ctx "[";
 		concat ctx "," (gen_value ctx) el;
@@ -698,14 +728,24 @@ and gen_expr ctx e =
 		spr ctx ")"
 
 
-and gen_block ctx e =
+and gen_block ?(after=false) ctx e =
 	match e.eexpr with
-	| TBlock el -> List.iter (gen_block ctx) el
-	| _ -> newline ctx; gen_expr ctx e
+	| TBlock el ->
+		List.iter (gen_block ~after ctx) el
+	| TCall ({ eexpr = TLocal { v_name = "__feature__" } }, { eexpr = TConst (TString f) } :: eif :: eelse) ->
+		if has_feature ctx f then
+			gen_block ~after ctx eif
+		else (match eelse with
+			| [] -> ()
+			| [e] -> gen_block ~after ctx e
+			| _ -> assert false)
+	| _ ->
+		if not after then newline ctx;
+		gen_expr ctx e;
+		if after then newline ctx
 
 and gen_value ctx e =
-	if ctx.com.debug && e.epos.pmin >= 0 then
-		add_mapping ctx e.epos;
+	add_mapping ctx e;
 	let assign e =
 		mk (TBinop (Ast.OpAssign,
 			mk (TLocal (match ctx.in_value with None -> assert false | Some v -> v)) t_dynamic e.epos,
@@ -746,11 +786,12 @@ and gen_value ctx e =
 	| TParenthesis _
 	| TObjectDecl _
 	| TArrayDecl _
-	| TCall _
 	| TNew _
 	| TUnop _
 	| TFunction _ ->
 		gen_expr ctx e
+	| TCall (e,el) ->
+		gen_call ctx e el true
 	| TReturn _
 	| TBreak
 	| TContinue ->
@@ -916,8 +957,14 @@ let generate_class ctx c =
 		newline ctx;
 	end;
 	handle_expose ctx p c.cl_meta;
-	print ctx "%s.__name__ = [%s]" p (String.concat "," (List.map (fun s -> Printf.sprintf "\"%s\"" (Ast.s_escape s)) (fst c.cl_path @ [snd c.cl_path])));
-	newline ctx;
+	if has_feature ctx "js.Boot.isClass" then begin
+		print ctx "%s.__name__ = " p;
+		if has_feature ctx "Type.getClassName" then
+			print ctx "[%s]" (String.concat "," (List.map (fun s -> Printf.sprintf "\"%s\"" (Ast.s_escape s)) (fst c.cl_path @ [snd c.cl_path])))
+		else
+			print ctx "true";
+		newline ctx;
+	end;
 	(match c.cl_implements with
 	| [] -> ()
 	| l ->
@@ -951,8 +998,10 @@ let generate_class ctx c =
 
 	let bend = open_block ctx in
 	List.iter (fun f -> match f.cf_kind with Var { v_read = AccResolve } -> () | _ -> gen_class_field ctx c f) c.cl_ordered_fields;
-	newprop ctx;
-	print ctx "__class__: %s" p;
+	if has_feature ctx "js.Boot.getClass" then begin
+		newprop ctx;
+		print ctx "__class__: %s" p;
+	end;
 
 	if has_property_reflection then begin
 		let props = Codegen.get_properties c.cl_ordered_fields in
@@ -978,7 +1027,9 @@ let generate_enum ctx e =
 	let ename = List.map (fun s -> Printf.sprintf "\"%s\"" (Ast.s_escape s)) (fst e.e_path @ [snd e.e_path]) in
 	print ctx "%s = " p;
 	if has_feature ctx "Type.resolveEnum" then print ctx "$hxClasses[\"%s\"] = " p;
-	print ctx "{ __ename__ : [%s], __constructs__ : [%s] }" (String.concat "," ename) (String.concat "," (List.map (fun s -> Printf.sprintf "\"%s\"" s) e.e_names));
+	print ctx "{";
+	if has_feature ctx "js.Boot.isEnum" then print ctx " __ename__ : %s," (if has_feature ctx "Type.getEnumName" then "[" ^ String.concat "," ename ^ "]" else "true");
+	print ctx " __constructs__ : [%s] }" (String.concat "," (List.map (fun s -> Printf.sprintf "\"%s\"" s) e.e_names));
 	newline ctx;
 	List.iter (fun n ->
 		let f = PMap.find n e.e_constrs in
@@ -1012,7 +1063,10 @@ let generate_type ctx = function
 	| TClassDecl c ->
 		(match c.cl_init with
 		| None -> ()
-		| Some e -> ctx.inits <- e :: ctx.inits);
+		| Some e when c.cl_path = (["js"],"Boot") || List.exists (function (":real",[Ast.EConst (Ast.String "js.Boot"),_],_) -> true | _ -> false) c.cl_meta ->
+			ctx.boot_init <- Some e
+		| Some e ->
+			ctx.inits <- e :: ctx.inits);
 		if not c.cl_extern then generate_class ctx c
 	| TEnumDecl e when e.e_extern ->
 		()
@@ -1039,11 +1093,13 @@ let alloc_ctx com =
 			sources_hash = Hashtbl.create 0;
 			mappings = Buffer.create 16;
 		};
+		all_features = Common.defined com "all_features";
 		js_modern = Common.defined com "js_modern";
 		statics = [];
 		inits = [];
 		current = null_class;
 		tabs = "";
+		boot_init = None;
 		in_value = None;
 		in_loop = false;
 		handle_break = false;
@@ -1068,6 +1124,10 @@ let generate com =
 	| Some g -> g()
 	| None ->
 	let ctx = alloc_ctx com in
+	
+	if has_feature ctx "Class.*" || has_feature ctx "Type.getClassName" then add_feature ctx "js.Boot.isClass";
+	if has_feature ctx "Enum.*" || has_feature ctx "Type.getEnumName" then add_feature ctx "js.Boot.isEnum";
+
 	if ctx.js_modern then begin
 		(* Additional ES5 strict mode keywords. *)
 		List.iter (fun s -> Hashtbl.replace kwds s ()) [ "arguments"; "eval" ];
@@ -1091,20 +1151,36 @@ let generate com =
 	end;
 	newline ctx;
 	List.iter (generate_type ctx) com.types;
-	print ctx "js.Boot.__res = {}";
-	newline ctx;
-	print ctx "js.Boot.__init()";
-	newline ctx;
-	List.iter (fun e ->
-		gen_expr ctx e;
+	if has_feature ctx "haxe.Resource.content" then begin
+		print ctx "js.Boot.__res = {}";
+		newline ctx;
+	end;
+	let rec chk_features e =
+		match e.eexpr with
+		| TClosure _ -> add_feature ctx "use.$bind"
+		| TField (x,"iterator") when has_feature ctx "HxOverrides.iter" ->
+			(match follow x.etype with
+			| TAnon _ | TMono _ | TDynamic _ -> add_feature ctx "use.$iterator"
+			| _ -> ())
+		| _ -> Type.iter chk_features e
+	in
+	List.iter chk_features ctx.inits;
+	List.iter (fun (_,_,e) -> chk_features e) ctx.statics;
+	if has_feature ctx "use.$iterator" then begin
+		add_feature ctx "use.$bind";
+		print ctx "var $iterator = function(o) { if( o instanceof Array ) return function() { return HxOverrides.iter(o); }; return typeof(o.iterator) == 'function' ? o.iterator.$bind(o) : o.iterator; }";	
+		ctx.separator <- true;
 		newline ctx;
-	) (List.rev ctx.inits);
+	end;
+	(match ctx.boot_init with
+	| None -> ()
+	| Some e -> gen_block ~after:true ctx e);
+	List.iter (gen_block ~after:true ctx) (List.rev ctx.inits);
 	List.iter (generate_static ctx) (List.rev ctx.statics);
 	(match com.main with
 	| None -> ()
-	| Some e -> gen_expr ctx e);
+	| Some e -> gen_expr ctx e; newline ctx);
 	if ctx.found_expose then begin
-		newline ctx;
 		print ctx
 "function $hxExpose(src, path) {
 	var o = window;
@@ -1116,10 +1192,11 @@ let generate com =
 	}
 	o[parts[parts.length-1]] = src;
 }";
+		newline ctx;
 	end;
 	if ctx.js_modern then begin
-		newline ctx;
 		print ctx "})()";
+		newline ctx;
 	end;
 	if com.debug then write_mappings ctx;
 	let ch = open_out_bin com.file in

+ 29 - 48
std/js/Boot.hx

@@ -59,6 +59,19 @@ class Boot {
 		}
 	}
 
+	static inline function isClass(o:Dynamic) : Bool {
+		return o.__name__;
+	}
+
+	static inline function isEnum(e:Dynamic) : Bool {
+		return e.__ename__;
+	}
+
+	static inline function getClass(o:Dynamic) : Dynamic {
+		return o.__class__;
+	}
+
+	@:feature("has_enum")
 	private static function __string_rec(o,s) {
 		untyped {
 			if( o == null )
@@ -66,12 +79,12 @@ class Boot {
 			if( s.length >= 5 )
 				return "<...>"; // too much deep recursion
 			var t = __js__("typeof(o)");
-			if( t == "function" && (o.__name__ != null || o.__ename__ != null) )
+			if( t == "function" && (isClass(o) || isEnum(o)) )
 				t = "object";
 			switch( t ) {
 			case "object":
 				if( __js__("o instanceof Array") ) {
-					if( o.__enum__ != null ) {
+					if( o.__enum__ ) {
 						if( o.length == 2 )
 							return o[0];
 						var str = o[0]+"(";
@@ -154,7 +167,7 @@ class Boot {
 						return (o.__enum__ == null);
 					return true;
 				}
-				if( __interfLoop(o.__class__,cl) )
+				if( __interfLoop(js.Boot.getClass(o),cl) )
 					return true;
 			} catch( e : Dynamic ) {
 				if( cl == null )
@@ -174,7 +187,10 @@ class Boot {
 			default:
 				if( o == null )
 					return false;
-				return o.__enum__ == cl || ( cl == Class && o.__name__ != null ) || ( cl == Enum && o.__ename__ != null );
+				// do not use isClass/isEnum here
+				__feature__("Class.*",if( cl == Class && o.__name__ != null ) return true);
+				__feature__("Enum.*",if( cl == Enum && o.__ename__ != null ) return true);
+				return o.__enum__ == cl;
 			}
 		}
 	}
@@ -183,51 +199,16 @@ class Boot {
 		if (__instanceof(o, t)) return o;
 		else throw "Cannot cast " +Std.string(o) + " to " +Std.string(t);
 	}
-	
-	private static function __init() {
-		untyped {
-			Array.prototype.copy = Array.prototype.slice;
-			Array.prototype.insert = function(i,x) {
-				__this__.splice(i,0,x);
-			};
-			Array.prototype.remove = if( Array.prototype.indexOf ) function(obj) {
-				var idx = __this__.indexOf(obj);
-				if( idx == -1 ) return false;
-				__this__.splice(idx,1);
-				return true;
-			} else function(obj) {
-				var i = 0;
-				var l = __this__.length;
-				while( i < l ) {
-					if( __this__[i] == obj ) {
-						__this__.splice(i,1);
-						return true;
-					}
-					i++;
-				}
-				return false;
-			};
-			Array.prototype.iterator = function() {
-				return {
-					cur : 0,
-					arr : __this__,
-					hasNext : function() {
-						return __this__.cur < __this__.arr.length;
-					},
-					next : function() {
-						return __this__.arr[__this__.cur++];
-					}
-				}
-			};
-			Function.prototype["$bind"] = function(o){
-				var f = function(){
-					return f.method.apply(f.scope, untyped __js__("arguments"));
-				}
-				f.scope = o;
-				f.method = __this__;
-				return f;
+
+	static function __init__() untyped {
+		__feature__("use.$bind",Function.prototype["$bind"] = function(o){
+			var f = function(){
+				return f.method.apply(f.scope, untyped __js__("arguments"));
 			}
-		}
+			f.scope = o;
+			f.method = __this__;
+			return f;
+		});
 	}
 
 }

+ 60 - 0
std/js/_std/Array.hx

@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2012, The haXe Project Contributors
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ */
+
+@:core_api
+extern class Array<T> {
+
+	var length(default,null) : Int;
+
+	function new() : Void;
+	function concat( a : Array<T> ) : Array<T>;
+	function join( sep : String ) : String;
+	function pop() : Null<T>;
+	function push(x : T) : Int;
+	function reverse() : Void;
+	function shift() : Null<T>;
+	function slice( pos : Int, ?end : Int ) : Array<T>;
+	function sort( f : T -> T -> Int ) : Void;
+	function splice( pos : Int, len : Int ) : Array<T>;
+	function toString() : String;
+	function unshift( x : T ) : Void;
+
+	inline function insert( pos : Int, x : T ) : Void {
+		(untyped this).splice(pos,0,x);
+	}
+
+	inline function remove( x : T ) : Bool {
+		return untyped HxOverrides.remove(this,x);
+	}
+
+	inline function copy() : Array<T> {
+		return (untyped this).slice();
+	}
+
+	@:runtime inline function iterator() : Iterator<T> {
+		return untyped HxOverrides.iter(this);
+	}
+
+}

+ 2 - 2
std/js/_std/Date.hx

@@ -36,7 +36,7 @@
 	function getDay() : Int;
 
 	inline function toString() : String {
-		return HxOverrides.Date_toString(this);
+		return untyped HxOverrides.dateStr(this);
 	}
 
 	static inline function now() : Date {
@@ -50,6 +50,6 @@
 	}
 
 	static inline function fromString( s : String ) : Date {
-		return HxOverrides.Date_fromString(s);
+		return untyped HxOverrides.strDate(s);
 	}
 }

+ 43 - 5
std/js/_std/HxOverrides.hx

@@ -29,7 +29,7 @@
  */
 class HxOverrides {
 
-	public static function Date_toString( date :Date ) : String {
+	static function dateStr( date :Date ) : String {
 		var m = date.getMonth() + 1;
 		var d = date.getDate();
 		var h = date.getHours();
@@ -43,7 +43,7 @@ class HxOverrides {
 			+":"+(if( s < 10 ) "0"+s else ""+s);
 	}
 
-	public static function Date_fromString( s : String ) : Date {
+	static function strDate( s : String ) : Date {
 		switch( s.length ) {
 		case 8: // hh:mm:ss
 			var k = s.split(":");
@@ -66,14 +66,14 @@ class HxOverrides {
 		}
 	}
 
-	public static function String_charCodeAt( s : String, index : Int ) : Null<Int> {
-		var x = (untyped s).charCodeAt(index);
+	static function cca( s : String, index : Int ) : Null<Int> {
+		var x = (cast s).charCodeAt(index);
 		if( x != x ) // fast isNaN
 			return untyped undefined; // isNaN will still return true
 		return x;
 	}
 
-	public static function String_substr( s : String, pos : Int, ?len : Int ) : String {
+	static function substr( s : String, pos : Int, ?len : Int ) : String {
 		if( pos != null && pos != 0 && len != null && len < 0 ) return "";
 		if( len == null ) len = s.length;
 		if( pos < 0 ){
@@ -85,4 +85,42 @@ class HxOverrides {
 
 		return (untyped s).substr(pos, len);
 	}
+
+	static function remove<T>( a : Array<T>, obj : T ) {
+		var i = 0;
+		var l = a.length;
+		while( i < l ) {
+			if( a[i] == obj ) {
+				a.splice(i,1);
+				return true;
+			}
+			i++;
+		}
+		return false;
+	}
+
+	static function iter<T>( a : Array<T> ) : Iterator<T> untyped {
+		return {
+			cur : 0,
+			arr : a,
+			hasNext : function() {
+				return __this__.cur < __this__.arr.length;
+			},
+			next : function() {
+				return __this__.arr[__this__.cur++];
+			}
+		};
+	}
+
+	static function __init__() untyped {
+		__feature__('HxOverrides.remove',
+			if( Array.prototype.indexOf ) __js__('HxOverrides').remove = function(a,o) {
+				var i = a.indexOf(o);
+				if( i == -1 ) return false;
+				a.splice(i,1);
+				return true;
+			}
+		);
+	}
+
 }

+ 2 - 2
std/js/_std/Reflect.hx

@@ -68,7 +68,7 @@
 	}
 
 	public static function isFunction( f : Dynamic ) : Bool untyped {
-		return __js__("typeof(f)") == "function" && f.__name__ == null;
+		return __js__("typeof(f)") == "function" && !(js.Boot.isClass(f) || js.Boot.isEnum(f));
 	}
 
 	public static function compare<T>( a : T, b : T ) : Int {
@@ -87,7 +87,7 @@
 		if( v == null )
 			return false;
 		var t = __js__("typeof(v)");
-		return (t == "string" || (t == "object" && !v.__enum__) || (t == "function" && v.__name__ != null));
+		return (t == "string" || (t == "object" && !v.__enum__) || (t == "function" && (js.Boot.isClass(v) || js.Boot.isEnum(v))));
 	}
 
 	public static function deleteField( o : Dynamic, f : String ) : Bool untyped {

+ 31 - 15
std/js/_std/Std.hx

@@ -61,21 +61,37 @@ import js.Boot;
 	}
 
 	static function __init__() : Void untyped {
-		String.prototype.__class__ = __feature__("Type.resolveClass",$hxClasses["String"] = String,String);
-		String.__name__ = ["String"];
-		Array.prototype.__class__ = __feature__("Type.resolveClass",$hxClasses["Array"] = Array,Array);
-		Array.__name__ = ["Array"];
-		Date.prototype.__class__ = __feature__("Type.resolveClass",$hxClasses["Date"] = Date,Date);
-		Date.__name__ = ["Date"];
-		var Int = __feature__("Type.resolveClass", $hxClasses["Int"] = { __name__ : ["Int"] }, { __name__ : ["Int"] });
-		var Dynamic = __feature__("Type.resolveClass", $hxClasses["Dynamic"] = { __name__ : ["Dynamic"] }, { __name__ : ["Dynamic"] });
-		var Float = __feature__("Type.resolveClass", $hxClasses["Float"] = __js__("Number"), __js__("Number"));
-		Float.__name__ = ["Float"];
-		var Bool = __feature__("Type.resolveEnum",$hxClasses["Bool"] = __js__("Boolean"), __js__("Boolean"));
-		Bool.__ename__ = ["Bool"];
-		var Class = __feature__("Type.resolveClass", $hxClasses["Class"] = { __name__ : ["Class"] }, { __name__ : ["Class"] });
-		var Enum = {};
-		var Void = __feature__("Type.resolveEnum", $hxClasses["Void"] = { __ename__ : ["Void"] }, { __ename__ : ["Void"] });
+		__feature__("js.Boot.getClass",String.prototype.__class__ = __feature__("Type.resolveClass",$hxClasses["String"] = String,String));
+		__feature__("js.Boot.isClass",String.__name__ = __feature__("Type.getClassName",["String"],true));
+		__feature__("js.Boot.getClass",Array.prototype.__class__ = __feature__("Type.resolveClass",$hxClasses["Array"] = Array,Array));
+		__feature__("js.Boot.isClass",Array.__name__ = __feature__("Type.getClassName",["Array"],true));
+		__feature__("Date.*", {
+			__feature__("js.Boot.getClass",__js__('Date').prototype.__class__ = __feature__("Type.resolveClass",$hxClasses["Date"] = __js__('Date'),__js__('Date')));
+			__feature__("js.Boot.isClass",__js__('Date').__name__ = ["Date"]);
+		});
+		__feature__("Int.*",{
+			var Int = __feature__("Type.resolveClass", $hxClasses["Int"] = { __name__ : ["Int"] }, { __name__ : ["Int"] });
+		});
+		__feature__("Dynamic.*",{
+			var Dynamic = __feature__("Type.resolveClass", $hxClasses["Dynamic"] = { __name__ : ["Dynamic"] }, { __name__ : ["Dynamic"] });
+		});
+		__feature__("Float.*",{
+			var Float = __feature__("Type.resolveClass", $hxClasses["Float"] = __js__("Number"), __js__("Number"));
+			Float.__name__ = ["Float"];
+		});
+		__feature__("Bool.*",{
+			var Bool = __feature__("Type.resolveEnum",$hxClasses["Bool"] = __js__("Boolean"), __js__("Boolean"));
+			Bool.__ename__ = ["Bool"];
+		});
+		__feature__("Class.*",{
+			var Class = __feature__("Type.resolveClass", $hxClasses["Class"] = { __name__ : ["Class"] }, { __name__ : ["Class"] });
+		});
+		__feature__("Enum.*",{
+			var Enum = {};
+		});
+		__feature__("Void.*",{
+			var Void = __feature__("Type.resolveEnum", $hxClasses["Void"] = { __ename__ : ["Void"] }, { __ename__ : ["Void"] });
+		});
 	}
 
 }

+ 5 - 3
std/js/_std/String.hx

@@ -25,6 +25,7 @@
 
 @:core_api extern class String {
 	var length(default,null) : Int;
+
 	function new(string:String) : Void;
 	function toUpperCase() : String;
 	function toLowerCase() : String;
@@ -33,14 +34,15 @@
 	function lastIndexOf( str : String, ?startIndex : Int ) : Int;
 	function split( delimiter : String ) : Array<String>;
 	function toString() : String;
-	static function fromCharCode( code : Int ) : String;
 	function substring( startIndex : Int, ?endIndex : Int ) : String;
 
 	inline function charCodeAt( index : Int) : Null<Int> {
-		return HxOverrides.String_charCodeAt(this, index);
+		return untyped HxOverrides.cca(this, index);
 	}
 
 	inline function substr( pos : Int, ?len : Int ) : String {
-		return HxOverrides.String_substr(this, pos, len);
+		return untyped HxOverrides.substr(this, pos, len);
 	}
+
+	static function fromCharCode( code : Int ) : String;
 }

+ 5 - 7
std/js/_std/Type.hx

@@ -40,9 +40,7 @@ enum ValueType {
 	public static function getClass<T>( o : T ) : Class<T> untyped {
 		if( o == null )
 			return null;
-		if( o.__enum__ != null )
-			return null;
-		return o.__class__;
+		return js.Boot.getClass(o);
 	}
 
 	public static function getEnum( o : EnumValue ) : Enum<Dynamic> untyped {
@@ -69,7 +67,7 @@ enum ValueType {
 	public static function resolveClass( name : String ) : Class<Dynamic> untyped {
 		var cl : Class<Dynamic> = $hxClasses[name];
 		// ensure that this is a class
-		if( cl == null || cl.__name__ == null )
+		if( cl == null || !js.Boot.isClass(cl) )
 			return null;
 		return cl;
 	}
@@ -77,7 +75,7 @@ enum ValueType {
 	public static function resolveEnum( name : String ) : Enum<Dynamic> untyped {
 		var e : Dynamic = $hxClasses[name];
 		// ensure that this is an enum
-		if( e == null || e.__ename__ == null )
+		if( e == null || !js.Boot.isEnum(e) )
 			return null;
 		return e;
 	}
@@ -169,12 +167,12 @@ enum ValueType {
 			var e = v.__enum__;
 			if( e != null )
 				return TEnum(e);
-			var c = v.__class__;
+			var c = js.Boot.getClass(v);
 			if( c != null )
 				return TClass(c);
 			return TObject;
 		case "function":
-			if( v.__name__ != null )
+			if( js.Boot.isClass(v) || js.Boot.isEnum(v) )
 				return TObject;
 			return TFunction;
 		case "undefined":

+ 3 - 1
typecore.ml

@@ -39,6 +39,7 @@ type macro_mode =
 type feature =
 	| FtTypedCast
 	| FtTypedCatch
+	| FtHasEnum
 
 type typer_globals = {
 	types_module : (path, path) Hashtbl.t;
@@ -246,6 +247,7 @@ let create_fake_module ctx file =
 let feature_name = function
 	| FtTypedCast -> "typed_cast"
 	| FtTypedCatch -> "typed_catch"
+	| FtHasEnum -> "has_enum"
 
 let activate_feature ctx ft = Hashtbl.replace ctx.g.features (feature_name ft) ft
-let has_feature ctx s = Hashtbl.mem ctx.g.features s
+let has_feature ctx s = Hashtbl.mem ctx.g.features s

+ 1 - 0
typeload.ml

@@ -1457,6 +1457,7 @@ let type_module ctx m file tdecls loadp =
 			) (!constructs);
 			e.e_names <- List.rev !names;
 			e.e_extern <- e.e_extern || e.e_names = [];
+			if not e.e_extern then activate_feature ctx FtHasEnum;
 		| ETypedef d ->
 			let t = get_tdef d.d_name in
 			let ctx = { ctx with type_params = t.t_types } in

+ 10 - 7
typer.ml

@@ -2041,7 +2041,12 @@ and type_call ctx e el t p =
 		else
 		let params = (match el with [] -> [] | _ -> ["customParams",(EArrayDecl el , p)]) in
 		let infos = mk_infos ctx p params in
-		type_expr ctx (ECall ((EField ((EField ((EConst (Ident "haxe"),p),"Log"),p),"trace"),p),[e;EUntyped infos,p]),p)
+		if platform ctx.com Js && el = [] then
+			let e = type_expr ctx e in	
+			let infos = type_expr ctx infos in
+			mk (TCall (mk (TLocal (alloc_var "`trace" t_dynamic)) t_dynamic p,[e;infos])) ctx.t.tvoid p
+		else
+			type_expr ctx (ECall ((EField ((EField ((EConst (Ident "haxe"),p),"Log"),p),"trace"),p),[e;EUntyped infos,p]),p)
 	| (EConst (Ident "callback"),p) , e :: params ->
 		type_callback ctx e params p
 	| (EConst (Ident "$type"),_) , [e] ->
@@ -2178,7 +2183,7 @@ let dce_check_metadata ctx meta =
 	) meta
 
 let dce_check_class ctx c =
-	let keep_whole_class = c.cl_interface || has_meta ":keep" c.cl_meta || (match c.cl_path with ["php"],"Boot" | ["neko"],"Boot" | ["flash"],"Boot" | [],"Array" | [],"String" -> true | _ -> false)  in
+	let keep_whole_class = c.cl_interface || has_meta ":keep" c.cl_meta || (match c.cl_path with ["php"],"Boot" | ["neko"],"Boot" | ["flash"],"Boot" | [],"Array" | [],"String" -> not (platform ctx.com Js) | _ -> false)  in
 	let keep stat f =
 		keep_whole_class
 		|| (c.cl_extern && (match f.cf_kind with Method MethInline -> false | _ -> true))
@@ -2187,10 +2192,8 @@ let dce_check_class ctx c =
 		|| (not stat && f.cf_name = "resolve" && (match c.cl_dynamic with Some _ -> true | None -> false))
 		|| (f.cf_name = "new" && has_meta ":?used" c.cl_meta)
 		|| match String.concat "." (fst c.cl_path @ [snd c.cl_path;f.cf_name]) with
-		| "EReg.new"
-		| "js.Boot.__init" | "flash._Boot.RealBoot.new"
-		| "js.Boot.__string_rec" (* used by $estr *)
-			-> true
+		| "EReg.new" -> true
+		| "flash._Boot.RealBoot.new" -> true
 		| _ -> false
 	in
 	keep
@@ -2237,7 +2240,7 @@ let dce_optimize ctx =
 			| _ ->
 				Common.log ctx.com ("Removing " ^ s_type_path c.cl_path);
 				c.cl_extern <- true;
-				(match c.cl_path with [],"Std" -> () | _ -> c.cl_init <- None);
+				(match c.cl_path with [],"Std"|["js"],"Boot" -> () | _ -> c.cl_init <- None);
 				c.cl_meta <- [":native",[(EConst (String "Dynamic"),c.cl_pos)],c.cl_pos]; (* make sure the type will not be referenced *)
 	in
 	Common.log ctx.com "Performing dead code optimization";