5 // Cesar Lopez Nataren (cesar@ciencias.unam.mx)
7 // (C) 2003, 2004 Cesar Lopez Nataren
11 using System.Reflection;
12 using System.Reflection.Emit;
13 using System.Threading;
14 using Microsoft.JScript.Vsa;
15 using System.Runtime.CompilerServices;
17 namespace Microsoft.JScript {
19 internal class EmitContext {
21 internal TypeBuilder type_builder;
22 internal ILGenerator ig;
23 internal ModuleBuilder mod_builder;
25 internal Label LoopBegin, LoopEnd;
27 internal EmitContext (TypeBuilder type)
31 if (type_builder != null) {
32 MethodBuilder global_code = type_builder.DefineMethod (
34 MethodAttributes.Public,
35 typeof (System.Object),
37 ig = global_code.GetILGenerator ();
41 internal EmitContext (TypeBuilder type_builder, ModuleBuilder mod_builder, ILGenerator ig)
43 this.type_builder = type_builder;
44 this.mod_builder = mod_builder;
49 public class CodeGenerator {
51 private static string MODULE = "JScript Module";
53 internal static string mod_name;
54 internal static AppDomain app_domain;
55 internal static AssemblyName assembly_name;
56 internal static AssemblyBuilder assembly_builder;
57 internal static ModuleBuilder module_builder;
59 internal static void Init (string file_name)
61 app_domain = Thread.GetDomain ();
63 assembly_name = new AssemblyName ();
64 assembly_name.Name = trim_extension (file_name);
68 assembly_builder = app_domain.DefineDynamicAssembly (
70 AssemblyBuilderAccess.RunAndSave);
72 ConstructorInfo ctr_info = typeof (Microsoft.JScript.ReferenceAttribute).GetConstructor (new Type [] { typeof (string) });
73 // FIXME: find out which is the blob.
74 byte [] blob = new byte [] {};
75 assembly_builder.SetCustomAttribute (ctr_info, blob);
77 module_builder = assembly_builder.DefineDynamicModule (
79 assembly_name.Name + ".exe",
83 internal static string trim_extension (string file_name)
85 int index = file_name.LastIndexOf ('.');
90 return file_name.Substring (0, index);
93 internal static void Save (string target_name)
95 assembly_builder.Save (target_name);
98 internal static void Emit (AST prog)
103 TypeBuilder type_builder;
104 type_builder = module_builder.DefineType ("JScript 0", TypeAttributes.Public);
106 type_builder.SetParent (typeof (GlobalScope));
107 type_builder.SetCustomAttribute (new CustomAttributeBuilder
108 (typeof (CompilerGlobalScopeAttribute).GetConstructor (new Type [] {}), new object [] {}));
110 EmitContext ec = new EmitContext (type_builder);
111 ec.mod_builder = module_builder;
112 ILGenerator global_code = ec.ig;
114 emit_default_script_constructor (ec);
115 emit_default_init_global_code (global_code);
117 emit_default_end_global_code (global_code);
118 ec.type_builder.CreateType ();
121 // Build the default 'JScript Main' class
123 ec.type_builder = module_builder.DefineType ("JScript Main");
124 emit_jscript_main (ec.type_builder);
125 ec.type_builder.CreateType ();
128 internal static void emit_default_init_global_code (ILGenerator ig)
130 ig.Emit (OpCodes.Ldarg_0);
131 ig.Emit (OpCodes.Ldfld, typeof (ScriptObject).GetField ("engine"));
132 ig.Emit (OpCodes.Ldarg_0);
133 ig.Emit (OpCodes.Call,
134 typeof (VsaEngine).GetMethod ("PushScriptObject",
135 new Type [] { typeof (ScriptObject)}));
138 internal static void emit_default_end_global_code (ILGenerator ig)
140 ig.Emit (OpCodes.Ldnull);
141 ig.Emit (OpCodes.Ldarg_0);
142 ig.Emit (OpCodes.Ldfld, typeof (ScriptObject).GetField ("engine"));
143 ig.Emit (OpCodes.Call, typeof (VsaEngine).GetMethod ("PopScriptObject"));
144 ig.Emit (OpCodes.Pop);
145 ig.Emit (OpCodes.Ret);
148 internal static void emit_default_script_constructor (EmitContext ec)
150 ConstructorBuilder cons_builder;
151 TypeBuilder tb = ec.type_builder;
152 cons_builder = tb.DefineConstructor (MethodAttributes.Public,
153 CallingConventions.Standard,
154 new Type [] { typeof (GlobalScope) });
156 ILGenerator ig = cons_builder.GetILGenerator ();
157 ig.Emit (OpCodes.Ldarg_0);
158 ig.Emit (OpCodes.Ldarg_1);
159 ig.Emit (OpCodes.Dup);
160 ig.Emit (OpCodes.Ldfld,
161 typeof (ScriptObject).GetField ("engine"));
163 ig.Emit (OpCodes.Call,
164 typeof (GlobalScope).GetConstructor (new Type [] {typeof (GlobalScope),
165 typeof (VsaEngine)}));
166 ig.Emit (OpCodes.Ret);
169 internal static void emit_jscript_main (TypeBuilder tb)
171 emit_jscript_main_constructor (tb);
172 emit_jscript_main_entry_point (tb);
175 internal static void emit_jscript_main_constructor (TypeBuilder tb)
177 ConstructorBuilder cons = tb.DefineConstructor (MethodAttributes.Public,
178 CallingConventions.Standard,
180 ILGenerator ig = cons.GetILGenerator ();
181 ig.Emit (OpCodes.Ldarg_0);
182 ig.Emit (OpCodes.Call, typeof (Object).GetConstructor (new Type [] {}));
183 ig.Emit (OpCodes.Ret);
186 internal static void emit_jscript_main_entry_point (TypeBuilder tb)
188 MethodBuilder method;
189 method = tb.DefineMethod ("Main",
190 MethodAttributes.Public | MethodAttributes.Static,
191 typeof (void), new Type [] {typeof (String [])});
193 method.SetCustomAttribute (new CustomAttributeBuilder
194 (typeof (STAThreadAttribute).GetConstructor (
198 ILGenerator ig = method.GetILGenerator ();
200 ig.DeclareLocal (typeof (GlobalScope));
202 ig.Emit (OpCodes.Ldc_I4_1);
203 ig.Emit (OpCodes.Ldc_I4_1);
204 ig.Emit (OpCodes.Newarr, typeof (string));
205 ig.Emit (OpCodes.Dup);
206 ig.Emit (OpCodes.Ldc_I4_0);
208 ig.Emit (OpCodes.Ldstr,
209 "mscorlib, Version=1.0.3300.0, Culture=neutral, Pub" +
210 "licKeyToken=b77a5c561934e089");
212 ig.Emit (OpCodes.Stelem_Ref);
214 ig.Emit (OpCodes.Call,
215 typeof (VsaEngine).GetMethod ("CreateEngineAndGetGlobalScope",
216 new Type [] {typeof (bool),
217 typeof (string [])}));
218 ig.Emit (OpCodes.Stloc_0);
219 ig.Emit (OpCodes.Ldloc_0);
221 ig.Emit (OpCodes.Newobj,
222 assembly_builder.GetType ("JScript 0").GetConstructor (
223 new Type [] {typeof (GlobalScope)}));
224 ig.Emit (OpCodes.Call,
225 assembly_builder.GetType ("JScript 0").GetMethod (
226 "Global Code", new Type [] {}));
227 ig.Emit (OpCodes.Pop);
228 ig.Emit (OpCodes.Ret);
230 assembly_builder.SetEntryPoint (method);
233 public static void Run (string file_name, AST prog)
235 CodeGenerator.Init (file_name);
236 CodeGenerator.Emit (prog);
237 CodeGenerator.Save (trim_extension (file_name) + ".exe");
240 internal static void fall_true (EmitContext ec, AST ast, Label lbl)
242 ILGenerator ig = ec.ig;
244 Binary b = ast as Binary;
245 switch (b.current_op) {
246 case JSToken.LogicalOr:
247 Label ftLb = ig.DefineLabel ();
248 fall_false (ec, b.left, ftLb);
249 fall_true (ec, b.right, lbl);
252 case JSToken.LogicalAnd:
253 fall_true (ec, b.left, lbl);
254 fall_true (ec, b.right, lbl);
259 if (need_convert_to_boolean (ast))
260 emit_to_boolean (ast, ig, 0);
261 ig.Emit (OpCodes.Brfalse, lbl);
265 internal static void fall_false (EmitContext ec, AST ast, Label lbl)
267 ILGenerator ig = ec.ig;
269 Binary b = ast as Binary;
270 switch (b.current_op) {
271 case JSToken.LogicalOr:
272 fall_false (ec, b.left, lbl);
273 fall_false (ec, b.right, lbl);
275 case JSToken.LogicalAnd:
276 Label ftLb = ig.DefineLabel ();
277 fall_true (ec, b.left, ftLb);
278 fall_false (ec, b.right, lbl);
284 if (need_convert_to_boolean (ast))
285 emit_to_boolean (ast, ig, 0);
286 ig.Emit (OpCodes.Brtrue, lbl);
290 internal static void emit_to_boolean (AST ast, ILGenerator ig, int i)
292 ig.Emit (OpCodes.Ldc_I4, i);
293 ig.Emit (OpCodes.Call, typeof (Convert).GetMethod ("ToBoolean",
294 new Type [] { typeof (object), typeof (Boolean)}));
297 internal static bool need_convert_to_boolean (AST ast)
302 if (ast is Identifier)
304 else if (ast is Expression) {
305 Expression exp = ast as Expression;
306 int n = exp.exprs.Count - 1;
307 AST tmp = (AST) exp.exprs [n];
308 if (tmp is Equality || tmp is Relational || tmp is BooleanLiteral)