5 // Cesar Lopez Nataren (cesar@ciencias.unam.mx)
7 // (C) 2003, 2004 Cesar Lopez Nataren
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 using System.Reflection;
34 using System.Reflection.Emit;
35 using System.Threading;
36 using Microsoft.JScript.Vsa;
37 using System.Runtime.CompilerServices;
39 namespace Microsoft.JScript {
41 internal class EmitContext {
43 internal TypeBuilder type_builder;
44 internal ILGenerator ig;
45 internal ModuleBuilder mod_builder;
47 internal Label LoopBegin, LoopEnd;
49 internal EmitContext (TypeBuilder type)
53 if (type_builder != null) {
54 MethodBuilder global_code = type_builder.DefineMethod (
56 MethodAttributes.Public,
57 typeof (System.Object),
59 ig = global_code.GetILGenerator ();
63 internal EmitContext (TypeBuilder type_builder, ModuleBuilder mod_builder, ILGenerator ig)
65 this.type_builder = type_builder;
66 this.mod_builder = mod_builder;
71 public class CodeGenerator {
73 private static string MODULE = "JScript Module";
75 internal static string mod_name;
76 internal static AppDomain app_domain;
77 internal static AssemblyName assembly_name;
78 internal static AssemblyBuilder assembly_builder;
79 internal static ModuleBuilder module_builder;
81 internal static string Basename (string name)
83 int pos = name.LastIndexOf ('/');
86 return name.Substring (pos + 1);
88 pos = name.LastIndexOf ('\\');
90 return name.Substring (pos + 1);
95 internal static string Dirname (string name)
97 int pos = name.LastIndexOf ('/');
100 return name.Substring (0, pos);
102 pos = name.LastIndexOf ('\\');
104 return name.Substring (0, pos);
109 internal static void Init (string file_name)
111 app_domain = Thread.GetDomain ();
113 assembly_name = new AssemblyName ();
114 assembly_name.Name = Path.GetFileNameWithoutExtension (file_name);
117 assembly_builder = app_domain.DefineDynamicAssembly (
119 AssemblyBuilderAccess.RunAndSave,
120 Dirname (file_name));
122 ConstructorInfo ctr_info = typeof (Microsoft.JScript.ReferenceAttribute).GetConstructor (new Type [] { typeof (string) });
123 // FIXME: find out which is the blob.
124 byte [] blob = new byte [] {};
125 assembly_builder.SetCustomAttribute (ctr_info, blob);
127 module_builder = assembly_builder.DefineDynamicModule (
129 Basename (assembly_name.Name + ".exe"),
133 internal static string trim_extension (string file_name)
135 int index = file_name.LastIndexOf ('.');
140 return file_name.Substring (0, index);
143 internal static void Save (string target_name)
145 assembly_builder.Save (CodeGenerator.Basename (target_name));
148 internal static void Emit (AST prog)
153 TypeBuilder type_builder;
154 type_builder = module_builder.DefineType ("JScript 0", TypeAttributes.Public);
156 type_builder.SetParent (typeof (GlobalScope));
157 type_builder.SetCustomAttribute (new CustomAttributeBuilder
158 (typeof (CompilerGlobalScopeAttribute).GetConstructor (new Type [] {}), new object [] {}));
160 EmitContext ec = new EmitContext (type_builder);
161 ec.mod_builder = module_builder;
162 ILGenerator global_code = ec.ig;
164 emit_default_script_constructor (ec);
165 emit_default_init_global_code (global_code);
167 emit_default_end_global_code (global_code);
168 ec.type_builder.CreateType ();
171 // Build the default 'JScript Main' class
173 ec.type_builder = module_builder.DefineType ("JScript Main");
174 emit_jscript_main (ec.type_builder);
175 ec.type_builder.CreateType ();
178 internal static void emit_default_init_global_code (ILGenerator ig)
180 ig.Emit (OpCodes.Ldarg_0);
181 ig.Emit (OpCodes.Ldfld, typeof (ScriptObject).GetField ("engine"));
182 ig.Emit (OpCodes.Ldarg_0);
183 ig.Emit (OpCodes.Call,
184 typeof (VsaEngine).GetMethod ("PushScriptObject",
185 new Type [] { typeof (ScriptObject)}));
188 internal static void emit_default_end_global_code (ILGenerator ig)
190 ig.Emit (OpCodes.Ldnull);
191 ig.Emit (OpCodes.Ldarg_0);
192 ig.Emit (OpCodes.Ldfld, typeof (ScriptObject).GetField ("engine"));
193 ig.Emit (OpCodes.Call, typeof (VsaEngine).GetMethod ("PopScriptObject"));
194 ig.Emit (OpCodes.Pop);
195 ig.Emit (OpCodes.Ret);
198 internal static void emit_default_script_constructor (EmitContext ec)
200 ConstructorBuilder cons_builder;
201 TypeBuilder tb = ec.type_builder;
202 cons_builder = tb.DefineConstructor (MethodAttributes.Public,
203 CallingConventions.Standard,
204 new Type [] { typeof (GlobalScope) });
206 ILGenerator ig = cons_builder.GetILGenerator ();
207 ig.Emit (OpCodes.Ldarg_0);
208 ig.Emit (OpCodes.Ldarg_1);
209 ig.Emit (OpCodes.Dup);
210 ig.Emit (OpCodes.Ldfld,
211 typeof (ScriptObject).GetField ("engine"));
213 ig.Emit (OpCodes.Call,
214 typeof (GlobalScope).GetConstructor (new Type [] {typeof (GlobalScope),
215 typeof (VsaEngine)}));
216 ig.Emit (OpCodes.Ret);
219 internal static void emit_jscript_main (TypeBuilder tb)
221 emit_jscript_main_constructor (tb);
222 emit_jscript_main_entry_point (tb);
225 internal static void emit_jscript_main_constructor (TypeBuilder tb)
227 ConstructorBuilder cons = tb.DefineConstructor (MethodAttributes.Public,
228 CallingConventions.Standard,
230 ILGenerator ig = cons.GetILGenerator ();
231 ig.Emit (OpCodes.Ldarg_0);
232 ig.Emit (OpCodes.Call, typeof (Object).GetConstructor (new Type [] {}));
233 ig.Emit (OpCodes.Ret);
236 internal static void emit_jscript_main_entry_point (TypeBuilder tb)
238 MethodBuilder method;
239 method = tb.DefineMethod ("Main",
240 MethodAttributes.Public | MethodAttributes.Static,
241 typeof (void), new Type [] {typeof (String [])});
243 method.SetCustomAttribute (new CustomAttributeBuilder
244 (typeof (STAThreadAttribute).GetConstructor (
248 ILGenerator ig = method.GetILGenerator ();
250 ig.DeclareLocal (typeof (GlobalScope));
252 ig.Emit (OpCodes.Ldc_I4_1);
253 ig.Emit (OpCodes.Ldc_I4_1);
254 ig.Emit (OpCodes.Newarr, typeof (string));
255 ig.Emit (OpCodes.Dup);
256 ig.Emit (OpCodes.Ldc_I4_0);
258 ig.Emit (OpCodes.Ldstr,
259 "mscorlib, Version=1.0.3300.0, Culture=neutral, Pub" +
260 "licKeyToken=b77a5c561934e089");
262 ig.Emit (OpCodes.Stelem_Ref);
264 ig.Emit (OpCodes.Call,
265 typeof (VsaEngine).GetMethod ("CreateEngineAndGetGlobalScope",
266 new Type [] {typeof (bool),
267 typeof (string [])}));
268 ig.Emit (OpCodes.Stloc_0);
269 ig.Emit (OpCodes.Ldloc_0);
271 ig.Emit (OpCodes.Newobj,
272 assembly_builder.GetType ("JScript 0").GetConstructor (
273 new Type [] {typeof (GlobalScope)}));
274 ig.Emit (OpCodes.Call,
275 assembly_builder.GetType ("JScript 0").GetMethod (
276 "Global Code", new Type [] {}));
277 ig.Emit (OpCodes.Pop);
278 ig.Emit (OpCodes.Ret);
280 assembly_builder.SetEntryPoint (method);
283 public static void Run (string file_name, AST prog)
285 CodeGenerator.Init (file_name);
286 CodeGenerator.Emit (prog);
287 CodeGenerator.Save (trim_extension (file_name) + ".exe");
290 static void emit_default_case (EmitContext ec, AST ast, OpCode op, Label lbl)
293 if (need_convert_to_boolean (ast))
294 emit_to_boolean (ast, ec.ig, 0);
295 ec.ig.Emit (op, lbl);
298 static void ft_binary_recursion (EmitContext ec, AST ast, Label lbl)
300 ILGenerator ig = ec.ig;
302 Binary b = ast as Binary;
304 case JSToken.LogicalOr:
305 Label ftLb = ig.DefineLabel ();
306 fall_false (ec, b.left, ftLb);
307 fall_true (ec, b.right, lbl);
310 case JSToken.LogicalAnd:
311 fall_true (ec, b.left, lbl);
312 fall_true (ec, b.right, lbl);
315 case JSToken.LessThan:
316 ig.Emit (OpCodes.Ldc_I4_0);
317 ig.Emit (OpCodes.Conv_R8);
318 ig.Emit (OpCodes.Blt, lbl);
324 static void ft_emit_equality (EmitContext ec, AST ast, Label lbl)
326 ILGenerator ig = ec.ig;
327 Equality eq = ast as Equality;
330 case JSToken.NotEqual:
331 ig.Emit (OpCodes.Brtrue, lbl);
334 ig.Emit (OpCodes.Brfalse, lbl);
339 internal static void fall_true (EmitContext ec, AST ast, Label lbl)
341 Type type = ast.GetType ();
343 if (type == typeof (Expression)) {
344 Expression exp = ast as Expression;
346 AST last_exp = (AST) exp.exprs [exp.exprs.Count - 1];
348 if (last_exp is Binary)
349 ft_binary_recursion (ec, last_exp, lbl);
350 else if (last_exp is Equality)
351 ft_emit_equality (ec, last_exp, lbl);
352 } else if (type == typeof (Binary))
353 ft_binary_recursion (ec, ast, lbl);
355 emit_default_case (ec, ast, OpCodes.Brfalse, lbl);
358 static void ff_emit_relational (EmitContext ec, AST ast, Label lbl)
360 ILGenerator ig = ec.ig;
361 Relational r = ast as Relational;
365 case JSToken.LessThan:
366 ig.Emit (OpCodes.Ldc_I4_0);
367 ig.Emit (OpCodes.Conv_R8);
368 ig.Emit (OpCodes.Blt, lbl);
373 static void ff_binary_recursion (EmitContext ec, AST ast, Label lbl)
375 ILGenerator ig = ec.ig;
376 Binary b = ast as Binary;
379 case JSToken.LogicalOr:
380 fall_false (ec, b.left, lbl);
381 fall_false (ec, b.right, lbl);
384 case JSToken.LogicalAnd:
385 Label ftLb = ig.DefineLabel ();
386 fall_true (ec, b.left, ftLb);
387 fall_false (ec, b.right, lbl);
393 static void ff_emit_equality_cond (EmitContext ec, AST ast, Label lbl)
395 ILGenerator ig = ec.ig;
396 Equality eq = ast as Equality;
400 case JSToken.NotEqual:
402 ig.Emit (OpCodes.Brfalse, lbl);
407 internal static void fall_false (EmitContext ec, AST ast, Label lbl)
409 Type type = ast.GetType ();
411 if (type == typeof (Expression)) {
412 Expression exp = ast as Expression;
417 AST last_exp = (AST) exp.exprs [exp.exprs.Count - 1];
419 if (last_exp is Relational)
420 ff_emit_relational (ec, last_exp, lbl);
421 else if (last_exp is Binary)
422 ff_binary_recursion (ec, last_exp, lbl);
423 else if (last_exp is Identifier || last_exp is BooleanLiteral)
424 emit_default_case (ec, last_exp, OpCodes.Brtrue, lbl);
425 else if (last_exp is Equality)
426 ff_emit_equality_cond (ec, last_exp, lbl);
428 Console.WriteLine ("fall_false, last_exp.GetType () == {0}", last_exp);
429 throw new Exception ("uknown type: " + last_exp.GetType ().ToString ());
431 } else if (type == typeof (Binary))
432 ff_binary_recursion (ec, ast, lbl);
434 emit_default_case (ec, ast, OpCodes.Brtrue, lbl);
437 internal static void emit_to_boolean (AST ast, ILGenerator ig, int i)
439 ig.Emit (OpCodes.Ldc_I4, i);
440 ig.Emit (OpCodes.Call, typeof (Convert).GetMethod ("ToBoolean",
441 new Type [] { typeof (object), typeof (Boolean)}));
444 internal static bool need_convert_to_boolean (AST ast)
449 if (ast is Identifier)
451 else if (ast is Expression) {
452 Expression exp = ast as Expression;
453 int n = exp.exprs.Count - 1;
454 AST tmp = (AST) exp.exprs [n];
455 if (tmp is Equality || tmp is Relational || tmp is BooleanLiteral)
464 // Loads a current VsaEngine
466 internal static void load_engine (AST parent, ILGenerator ig)
469 // If we are in a function declaration at global level,
470 // we must load the engine associated to the current 'JScript N' instance,
471 // otherwise pick up the engine at second place in method's signature.
473 if (parent == null || parent.GetType () == typeof (ScriptBlock)) {
474 ig.Emit (OpCodes.Ldarg_0);
475 ig.Emit (OpCodes.Ldfld, typeof (ScriptObject).GetField ("engine"));
476 } else if (parent != null && parent.GetType () == typeof (FunctionDeclaration ))
477 ig.Emit (OpCodes.Ldarg_1);