**** Merged from MCS ****
[mono-project.git] / mcs / class / Microsoft.JScript / Microsoft.JScript / CodeGenerator.cs
blobe9feb263514e14f39ab74fcbbf2b93c29c63627d
1 //
2 // CodeGenerator.cs
3 //
4 // Author:
5 // Cesar Lopez Nataren (cesar@ciencias.unam.mx)
6 //
7 // (C) 2003, 2004 Cesar Lopez Nataren
8 //
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:
18 //
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 //
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.
31 using System;
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)
50 type_builder = type;
52 if (type_builder != null) {
53 MethodBuilder global_code = type_builder.DefineMethod (
54 "Global Code",
55 MethodAttributes.Public,
56 typeof (System.Object),
57 new Type [] {});
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;
66 this.ig = ig;
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);
87 mod_name = MODULE;
89 assembly_builder = app_domain.DefineDynamicAssembly (
90 assembly_name,
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 (
99 mod_name,
100 assembly_name.Name + ".exe",
101 false);
104 internal static string trim_extension (string file_name)
106 int index = file_name.LastIndexOf ('.');
108 if (index < 0)
109 return file_name;
110 else
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)
121 if (prog == null)
122 return;
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);
137 prog.Emit (ec);
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,
200 new Type [] {});
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 (
216 new Type [] {}),
217 new object [] {}));
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 internal static void fall_true (EmitContext ec, AST ast, Label lbl)
263 ILGenerator ig = ec.ig;
265 if (ast.GetType () == typeof (Expression)) {
266 Expression exp = ast as Expression;
267 exp.Emit (ec);
268 AST last_exp = (AST) exp.exprs [exp.exprs.Count - 1];
270 if (last_exp is Binary) {
271 Binary b = last_exp as Binary;
272 switch (b.op) {
273 case JSToken.LogicalOr:
274 Label ftLb = ig.DefineLabel ();
275 fall_false (ec, b.left, ftLb);
276 fall_true (ec, b.right, lbl);
277 ig.MarkLabel (ftLb);
278 break;
279 case JSToken.LogicalAnd:
280 fall_true (ec, b.left, lbl);
281 fall_true (ec, b.right, lbl);
282 break;
284 case JSToken.LessThan:
285 ig.Emit (OpCodes.Ldc_I4_0);
286 ig.Emit (OpCodes.Conv_R8);
287 ig.Emit (OpCodes.Blt, lbl);
288 break;
290 } else if (last_exp is Equality) {
291 Equality eq = last_exp as Equality;
292 switch (eq.op) {
293 case JSToken.NotEqual:
294 ig.Emit (OpCodes.Brtrue, lbl);
295 break;
296 case JSToken.Equal:
297 ig.Emit (OpCodes.Brfalse, lbl);
298 break;
299 default:
300 if (need_convert_to_boolean (ast))
301 emit_to_boolean (ast, ig, 0);
302 ig.Emit (OpCodes.Brtrue, lbl);
303 break;
306 } else {
307 ast.Emit (ec);
308 if (need_convert_to_boolean (ast))
309 emit_to_boolean (ast, ig, 0);
310 ig.Emit (OpCodes.Brfalse, lbl);
314 internal static void fall_false (EmitContext ec, AST ast, Label lbl)
316 ILGenerator ig = ec.ig;
318 if (ast.GetType () == typeof (Expression)) {
319 Expression exp = ast as Expression;
320 exp.Emit (ec);
321 AST last_exp = (AST) exp.exprs [exp.exprs.Count - 1];
323 if (last_exp is Relational) {
324 Relational r = last_exp as Relational;
325 switch (r.op) {
326 case JSToken.LessThan:
327 ig.Emit (OpCodes.Ldc_I4_0);
328 ig.Emit (OpCodes.Conv_R8);
329 ig.Emit (OpCodes.Blt, lbl);
330 break;
332 } else if (last_exp is Binary) {
333 Binary b = last_exp as Binary;
334 switch (b.op) {
335 case JSToken.LogicalOr:
336 fall_false (ec, b.left, lbl);
337 fall_false (ec, b.right, lbl);
338 break;
340 case JSToken.LogicalAnd:
341 Label ftLb = ig.DefineLabel ();
342 fall_true (ec, b.left, ftLb);
343 fall_false (ec, b.right, lbl);
344 ig.MarkLabel (ftLb);
345 break;
347 default:
348 if (need_convert_to_boolean (ast))
349 emit_to_boolean (ast, ig, 0);
350 ig.Emit (OpCodes.Brtrue, lbl);
351 break;
353 } else {
354 ast.Emit (ec);
355 if (need_convert_to_boolean (ast))
356 emit_to_boolean (ast, ig, 0);
357 ig.Emit (OpCodes.Brtrue, lbl);
362 internal static void emit_to_boolean (AST ast, ILGenerator ig, int i)
364 ig.Emit (OpCodes.Ldc_I4, i);
365 ig.Emit (OpCodes.Call, typeof (Convert).GetMethod ("ToBoolean",
366 new Type [] { typeof (object), typeof (Boolean)}));
369 internal static bool need_convert_to_boolean (AST ast)
371 if (ast == null)
372 return false;
374 if (ast is Identifier)
375 return true;
376 else if (ast is Expression) {
377 Expression exp = ast as Expression;
378 int n = exp.exprs.Count - 1;
379 AST tmp = (AST) exp.exprs [n];
380 if (tmp is Equality || tmp is Relational || tmp is BooleanLiteral)
381 return false;
382 else
383 return true;
384 } else
385 return false;