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.
32 using System.Reflection;
33 using System.Reflection.Emit;
34 using System.Threading;
35 using Microsoft.JScript.Vsa;
36 using System.Runtime.CompilerServices;
38 namespace Microsoft.JScript {
40 internal class EmitContext {
42 internal TypeBuilder type_builder;
43 internal ILGenerator ig;
44 internal ModuleBuilder mod_builder;
46 internal Label LoopBegin, LoopEnd;
48 internal EmitContext (TypeBuilder type)
52 if (type_builder != null) {
53 MethodBuilder global_code = type_builder.DefineMethod (
55 MethodAttributes.Public,
56 typeof (System.Object),
58 ig = global_code.GetILGenerator ();
62 internal EmitContext (TypeBuilder type_builder, ModuleBuilder mod_builder, ILGenerator ig)
64 this.type_builder = type_builder;
65 this.mod_builder = mod_builder;
70 public class CodeGenerator {
72 private static string MODULE = "JScript Module";
74 internal static string mod_name;
75 internal static AppDomain app_domain;
76 internal static AssemblyName assembly_name;
77 internal static AssemblyBuilder assembly_builder;
78 internal static ModuleBuilder module_builder;
80 internal static void Init (string file_name)
82 app_domain = Thread.GetDomain ();
84 assembly_name = new AssemblyName ();
85 assembly_name.Name = trim_extension (file_name);
89 assembly_builder = app_domain.DefineDynamicAssembly (
91 AssemblyBuilderAccess.RunAndSave);
93 ConstructorInfo ctr_info = typeof (Microsoft.JScript.ReferenceAttribute).GetConstructor (new Type [] { typeof (string) });
94 // FIXME: find out which is the blob.
95 byte [] blob = new byte [] {};
96 assembly_builder.SetCustomAttribute (ctr_info, blob);
98 module_builder = assembly_builder.DefineDynamicModule (
100 assembly_name.Name + ".exe",
104 internal static string trim_extension (string file_name)
106 int index = file_name.LastIndexOf ('.');
111 return file_name.Substring (0, index);
114 internal static void Save (string target_name)
116 assembly_builder.Save (target_name);
119 internal static void Emit (AST prog)
124 TypeBuilder type_builder;
125 type_builder = module_builder.DefineType ("JScript 0", TypeAttributes.Public);
127 type_builder.SetParent (typeof (GlobalScope));
128 type_builder.SetCustomAttribute (new CustomAttributeBuilder
129 (typeof (CompilerGlobalScopeAttribute).GetConstructor (new Type [] {}), new object [] {}));
131 EmitContext ec = new EmitContext (type_builder);
132 ec.mod_builder = module_builder;
133 ILGenerator global_code = ec.ig;
135 emit_default_script_constructor (ec);
136 emit_default_init_global_code (global_code);
138 emit_default_end_global_code (global_code);
139 ec.type_builder.CreateType ();
142 // Build the default 'JScript Main' class
144 ec.type_builder = module_builder.DefineType ("JScript Main");
145 emit_jscript_main (ec.type_builder);
146 ec.type_builder.CreateType ();
149 internal static void emit_default_init_global_code (ILGenerator ig)
151 ig.Emit (OpCodes.Ldarg_0);
152 ig.Emit (OpCodes.Ldfld, typeof (ScriptObject).GetField ("engine"));
153 ig.Emit (OpCodes.Ldarg_0);
154 ig.Emit (OpCodes.Call,
155 typeof (VsaEngine).GetMethod ("PushScriptObject",
156 new Type [] { typeof (ScriptObject)}));
159 internal static void emit_default_end_global_code (ILGenerator ig)
161 ig.Emit (OpCodes.Ldnull);
162 ig.Emit (OpCodes.Ldarg_0);
163 ig.Emit (OpCodes.Ldfld, typeof (ScriptObject).GetField ("engine"));
164 ig.Emit (OpCodes.Call, typeof (VsaEngine).GetMethod ("PopScriptObject"));
165 ig.Emit (OpCodes.Pop);
166 ig.Emit (OpCodes.Ret);
169 internal static void emit_default_script_constructor (EmitContext ec)
171 ConstructorBuilder cons_builder;
172 TypeBuilder tb = ec.type_builder;
173 cons_builder = tb.DefineConstructor (MethodAttributes.Public,
174 CallingConventions.Standard,
175 new Type [] { typeof (GlobalScope) });
177 ILGenerator ig = cons_builder.GetILGenerator ();
178 ig.Emit (OpCodes.Ldarg_0);
179 ig.Emit (OpCodes.Ldarg_1);
180 ig.Emit (OpCodes.Dup);
181 ig.Emit (OpCodes.Ldfld,
182 typeof (ScriptObject).GetField ("engine"));
184 ig.Emit (OpCodes.Call,
185 typeof (GlobalScope).GetConstructor (new Type [] {typeof (GlobalScope),
186 typeof (VsaEngine)}));
187 ig.Emit (OpCodes.Ret);
190 internal static void emit_jscript_main (TypeBuilder tb)
192 emit_jscript_main_constructor (tb);
193 emit_jscript_main_entry_point (tb);
196 internal static void emit_jscript_main_constructor (TypeBuilder tb)
198 ConstructorBuilder cons = tb.DefineConstructor (MethodAttributes.Public,
199 CallingConventions.Standard,
201 ILGenerator ig = cons.GetILGenerator ();
202 ig.Emit (OpCodes.Ldarg_0);
203 ig.Emit (OpCodes.Call, typeof (Object).GetConstructor (new Type [] {}));
204 ig.Emit (OpCodes.Ret);
207 internal static void emit_jscript_main_entry_point (TypeBuilder tb)
209 MethodBuilder method;
210 method = tb.DefineMethod ("Main",
211 MethodAttributes.Public | MethodAttributes.Static,
212 typeof (void), new Type [] {typeof (String [])});
214 method.SetCustomAttribute (new CustomAttributeBuilder
215 (typeof (STAThreadAttribute).GetConstructor (
219 ILGenerator ig = method.GetILGenerator ();
221 ig.DeclareLocal (typeof (GlobalScope));
223 ig.Emit (OpCodes.Ldc_I4_1);
224 ig.Emit (OpCodes.Ldc_I4_1);
225 ig.Emit (OpCodes.Newarr, typeof (string));
226 ig.Emit (OpCodes.Dup);
227 ig.Emit (OpCodes.Ldc_I4_0);
229 ig.Emit (OpCodes.Ldstr,
230 "mscorlib, Version=1.0.3300.0, Culture=neutral, Pub" +
231 "licKeyToken=b77a5c561934e089");
233 ig.Emit (OpCodes.Stelem_Ref);
235 ig.Emit (OpCodes.Call,
236 typeof (VsaEngine).GetMethod ("CreateEngineAndGetGlobalScope",
237 new Type [] {typeof (bool),
238 typeof (string [])}));
239 ig.Emit (OpCodes.Stloc_0);
240 ig.Emit (OpCodes.Ldloc_0);
242 ig.Emit (OpCodes.Newobj,
243 assembly_builder.GetType ("JScript 0").GetConstructor (
244 new Type [] {typeof (GlobalScope)}));
245 ig.Emit (OpCodes.Call,
246 assembly_builder.GetType ("JScript 0").GetMethod (
247 "Global Code", new Type [] {}));
248 ig.Emit (OpCodes.Pop);
249 ig.Emit (OpCodes.Ret);
251 assembly_builder.SetEntryPoint (method);
254 public static void Run (string file_name, AST prog)
256 CodeGenerator.Init (file_name);
257 CodeGenerator.Emit (prog);
258 CodeGenerator.Save (trim_extension (file_name) + ".exe");
261 static void emit_default_case (EmitContext ec, AST ast, OpCode op, Label lbl)
264 if (need_convert_to_boolean (ast))
265 emit_to_boolean (ast, ec.ig, 0);
266 ec.ig.Emit (op, lbl);
269 static void ft_binary_recursion (EmitContext ec, AST ast, Label lbl)
271 ILGenerator ig = ec.ig;
273 Binary b = ast as Binary;
275 case JSToken.LogicalOr:
276 Label ftLb = ig.DefineLabel ();
277 fall_false (ec, b.left, ftLb);
278 fall_true (ec, b.right, lbl);
281 case JSToken.LogicalAnd:
282 fall_true (ec, b.left, lbl);
283 fall_true (ec, b.right, lbl);
286 case JSToken.LessThan:
287 ig.Emit (OpCodes.Ldc_I4_0);
288 ig.Emit (OpCodes.Conv_R8);
289 ig.Emit (OpCodes.Blt, lbl);
295 static void ft_emit_equality (EmitContext ec, AST ast, Label lbl)
297 ILGenerator ig = ec.ig;
298 Equality eq = ast as Equality;
301 case JSToken.NotEqual:
302 ig.Emit (OpCodes.Brtrue, lbl);
305 ig.Emit (OpCodes.Brfalse, lbl);
310 internal static void fall_true (EmitContext ec, AST ast, Label lbl)
312 ILGenerator ig = ec.ig;
313 Type type = ast.GetType ();
315 if (type == typeof (Expression)) {
316 Expression exp = ast as Expression;
318 AST last_exp = (AST) exp.exprs [exp.exprs.Count - 1];
320 if (last_exp is Binary)
321 ft_binary_recursion (ec, last_exp, lbl);
322 else if (last_exp is Equality)
323 ft_emit_equality (ec, last_exp, lbl);
324 } else if (type == typeof (Binary))
325 ft_binary_recursion (ec, ast, lbl);
327 emit_default_case (ec, ast, OpCodes.Brfalse, lbl);
330 static void ff_emit_relational (ILGenerator ig, AST ast, Label lbl)
332 Relational r = ast as Relational;
335 case JSToken.LessThan:
336 ig.Emit (OpCodes.Ldc_I4_0);
337 ig.Emit (OpCodes.Conv_R8);
338 ig.Emit (OpCodes.Blt, lbl);
343 static void ff_binary_recursion (EmitContext ec, AST ast, Label lbl)
345 ILGenerator ig = ec.ig;
346 Binary b = ast as Binary;
349 case JSToken.LogicalOr:
350 fall_false (ec, b.left, lbl);
351 fall_false (ec, b.right, lbl);
354 case JSToken.LogicalAnd:
355 Label ftLb = ig.DefineLabel ();
356 fall_true (ec, b.left, ftLb);
357 fall_false (ec, b.right, lbl);
363 internal static void fall_false (EmitContext ec, AST ast, Label lbl)
365 ILGenerator ig = ec.ig;
366 Type type = ast.GetType ();
368 if (type == typeof (Expression)) {
369 Expression exp = ast as Expression;
371 AST last_exp = (AST) exp.exprs [exp.exprs.Count - 1];
373 if (last_exp is Relational)
374 ff_emit_relational (ec.ig, last_exp, lbl);
375 else if (last_exp is Binary)
376 ff_binary_recursion (ec, last_exp, lbl);
377 } else if (type == typeof (Binary))
378 ff_binary_recursion (ec, ast, lbl);
380 emit_default_case (ec, ast, OpCodes.Brtrue, lbl);
383 internal static void emit_to_boolean (AST ast, ILGenerator ig, int i)
385 ig.Emit (OpCodes.Ldc_I4, i);
386 ig.Emit (OpCodes.Call, typeof (Convert).GetMethod ("ToBoolean",
387 new Type [] { typeof (object), typeof (Boolean)}));
390 internal static bool need_convert_to_boolean (AST ast)
395 if (ast is Identifier)
397 else if (ast is Expression) {
398 Expression exp = ast as Expression;
399 int n = exp.exprs.Count - 1;
400 AST tmp = (AST) exp.exprs [n];
401 if (tmp is Equality || tmp is Relational || tmp is BooleanLiteral)