PageRenderTime 84ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 1ms

/src/Boo.Lang.Compiler/Steps/EmitAssembly.cs

http://github.com/bamboo/boo
C# | 5680 lines | 4675 code | 807 blank | 198 comment | 887 complexity | af1838b67c0ca4a5b3a2b75e2abbb7b1 MD5 | raw file
Possible License(s): GPL-2.0
  1. #region license
  2. // Copyright (c) 2004, Rodrigo B. de Oliveira (rbo@acm.org)
  3. // All rights reserved.
  4. //
  5. // Redistribution and use in source and binary forms, with or without modification,
  6. // are permitted provided that the following conditions are met:
  7. //
  8. // * Redistributions of source code must retain the above copyright notice,
  9. // this list of conditions and the following disclaimer.
  10. // * Redistributions in binary form must reproduce the above copyright notice,
  11. // this list of conditions and the following disclaimer in the documentation
  12. // and/or other materials provided with the distribution.
  13. // * Neither the name of Rodrigo B. de Oliveira nor the names of its
  14. // contributors may be used to endorse or promote products derived from this
  15. // software without specific prior written permission.
  16. //
  17. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  18. // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  19. // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  20. // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
  21. // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22. // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  23. // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  24. // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  25. // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  26. // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27. #endregion
  28. using System;
  29. using System.Collections;
  30. using System.Diagnostics;
  31. using System.Diagnostics.SymbolStore;
  32. using System.IO;
  33. using System.Linq;
  34. using System.Reflection;
  35. using System.Reflection.Emit;
  36. using System.Resources;
  37. using System.Text;
  38. using System.Text.RegularExpressions;
  39. using System.Threading;
  40. using System.Security;
  41. using Boo.Lang.Compiler.Ast;
  42. using Boo.Lang.Compiler.TypeSystem.Services;
  43. using Boo.Lang.Compiler.Util;
  44. using Boo.Lang.Compiler.TypeSystem;
  45. using Boo.Lang.Compiler.TypeSystem.Generics;
  46. using Boo.Lang.Compiler.TypeSystem.Internal;
  47. using Boo.Lang.Compiler.TypeSystem.Reflection;
  48. using Boo.Lang.Runtime;
  49. using Attribute = Boo.Lang.Compiler.Ast.Attribute;
  50. using Module = Boo.Lang.Compiler.Ast.Module;
  51. using System.Collections.Generic;
  52. using Method = Boo.Lang.Compiler.Ast.Method;
  53. using ExceptionHandler = Boo.Lang.Compiler.Ast.ExceptionHandler;
  54. namespace Boo.Lang.Compiler.Steps
  55. {
  56. sealed class LoopInfo
  57. {
  58. public Label BreakLabel;
  59. public Label ContinueLabel;
  60. public int TryBlockDepth;
  61. public LoopInfo(Label breakLabel, Label continueLabel, int tryBlockDepth)
  62. {
  63. BreakLabel = breakLabel;
  64. ContinueLabel = continueLabel;
  65. TryBlockDepth = tryBlockDepth;
  66. }
  67. }
  68. public class EmitAssembly : AbstractFastVisitorCompilerStep
  69. {
  70. static ConstructorInfo DebuggableAttribute_Constructor = Methods.ConstructorOf(() => new DebuggableAttribute(DebuggableAttribute.DebuggingModes.Default));
  71. static ConstructorInfo RuntimeCompatibilityAttribute_Constructor = Methods.ConstructorOf(() => new System.Runtime.CompilerServices.RuntimeCompatibilityAttribute());
  72. static ConstructorInfo SerializableAttribute_Constructor = Methods.ConstructorOf(() => new SerializableAttribute());
  73. static PropertyInfo[] RuntimeCompatibilityAttribute_Property = new[] { Properties.Of<System.Runtime.CompilerServices.RuntimeCompatibilityAttribute, bool>(a => a.WrapNonExceptionThrows) };
  74. static ConstructorInfo DuckTypedAttribute_Constructor = Methods.ConstructorOf(() => new DuckTypedAttribute());
  75. static ConstructorInfo ParamArrayAttribute_Constructor = Methods.ConstructorOf(() => new ParamArrayAttribute());
  76. static MethodInfo RuntimeServices_NormalizeArrayIndex = Methods.Of<Array, int, int>(RuntimeServices.NormalizeArrayIndex);
  77. static MethodInfo RuntimeServices_ToBool_Object = Types.RuntimeServices.GetMethod("ToBool", new Type[] { Types.Object });
  78. static MethodInfo RuntimeServices_ToBool_Decimal = Types.RuntimeServices.GetMethod("ToBool", new Type[] { Types.Decimal });
  79. static MethodInfo Builtins_ArrayTypedConstructor = Types.Builtins.GetMethod("array", new Type[] { Types.Type, Types.Int });
  80. static MethodInfo Builtins_ArrayGenericConstructor = Types.Builtins.GetMethod("array", new Type[] { Types.Int });
  81. static MethodInfo Builtins_ArrayTypedCollectionConstructor = Types.Builtins.GetMethod("array", new Type[] { Types.Type, Types.ICollection });
  82. private static MethodInfo Array_get_Length = Methods.GetterOf<Array, int>(a => a.Length);
  83. static MethodInfo Math_Pow = Methods.Of<double, double, double>(Math.Pow);
  84. static ConstructorInfo List_EmptyConstructor = Types.List.GetConstructor(Type.EmptyTypes);
  85. static ConstructorInfo List_ArrayBoolConstructor = Types.List.GetConstructor(new Type[] { Types.ObjectArray, Types.Bool });
  86. static ConstructorInfo Hash_Constructor = Types.Hash.GetConstructor(Type.EmptyTypes);
  87. static ConstructorInfo Regex_Constructor = typeof(Regex).GetConstructor(new Type[] { Types.String });
  88. static ConstructorInfo Regex_Constructor_Options = typeof(Regex).GetConstructor(new Type[] { Types.String, typeof(RegexOptions) });
  89. static MethodInfo Hash_Add = Types.Hash.GetMethod("Add", new Type[] { typeof(object), typeof(object) });
  90. private static ConstructorInfo TimeSpan_LongConstructor = Methods.ConstructorOf(() => new TimeSpan(default(long)));
  91. private static MethodInfo Type_GetTypeFromHandle = Methods.Of<RuntimeTypeHandle, Type>(Type.GetTypeFromHandle);
  92. static MethodInfo String_IsNullOrEmpty = Methods.Of<string, bool>(string.IsNullOrEmpty);
  93. static MethodInfo RuntimeHelpers_InitializeArray = Methods.Of<Array, RuntimeFieldHandle>(System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray);
  94. AssemblyBuilder _asmBuilder;
  95. ModuleBuilder _moduleBuilder;
  96. Hashtable _symbolDocWriters = new Hashtable();
  97. // IL generation state
  98. ILGenerator _il;
  99. Method _method; //current method
  100. int _returnStatements;//number of return statements in current method
  101. bool _hasLeaveWithStoredValue;//has a explicit return inside a try block (a `leave')
  102. bool _returnImplicit; //method ends with an implicit return
  103. Label _returnLabel; //label for `ret'
  104. Label _implicitLabel; //label for implicit return (with default value)
  105. Label _leaveLabel; //label to load the stored return value (because of a `leave')
  106. IType _returnType;
  107. int _tryBlock; // are we in a try block?
  108. bool _checked = true;
  109. bool _rawArrayIndexing = false;
  110. bool _perModuleRawArrayIndexing = false;
  111. Dictionary<IType, Type> _typeCache = new Dictionary<IType, Type>();
  112. // keeps track of types on the IL stack
  113. readonly Stack<IType> _types = new Stack<IType>();
  114. readonly Stack<LoopInfo> _loopInfoStack = new Stack<LoopInfo>();
  115. readonly AttributeCollection _assemblyAttributes = new AttributeCollection();
  116. LoopInfo _currentLoopInfo;
  117. void EnterLoop(Label breakLabel, Label continueLabel)
  118. {
  119. _loopInfoStack.Push(_currentLoopInfo);
  120. _currentLoopInfo = new LoopInfo(breakLabel, continueLabel, _tryBlock);
  121. }
  122. bool InTryInLoop()
  123. {
  124. return _tryBlock > _currentLoopInfo.TryBlockDepth;
  125. }
  126. void LeaveLoop()
  127. {
  128. _currentLoopInfo = _loopInfoStack.Pop();
  129. }
  130. void PushType(IType type)
  131. {
  132. _types.Push(type);
  133. }
  134. void PushBool()
  135. {
  136. PushType(TypeSystemServices.BoolType);
  137. }
  138. void PushVoid()
  139. {
  140. PushType(TypeSystemServices.VoidType);
  141. }
  142. IType PopType()
  143. {
  144. return _types.Pop();
  145. }
  146. IType PeekTypeOnStack()
  147. {
  148. return (_types.Count != 0) ? _types.Peek() : null;
  149. }
  150. override public void Run()
  151. {
  152. if (Errors.Count > 0)
  153. return;
  154. GatherAssemblyAttributes();
  155. SetUpAssembly();
  156. DefineTypes();
  157. DefineResources();
  158. DefineAssemblyAttributes();
  159. DefineEntryPoint();
  160. // Define the unmanaged version information resource, which
  161. // contains the attribute informaion applied earlier
  162. _asmBuilder.DefineVersionInfoResource();
  163. _moduleBuilder.CreateGlobalFunctions(); //setup global .data
  164. }
  165. void GatherAssemblyAttributes()
  166. {
  167. foreach (var module in CompileUnit.Modules)
  168. foreach (var attribute in module.AssemblyAttributes)
  169. _assemblyAttributes.Add(attribute);
  170. }
  171. void DefineTypes()
  172. {
  173. if (CompileUnit.Modules.Count == 0)
  174. return;
  175. var types = CollectTypes();
  176. foreach (var type in types)
  177. DefineType(type);
  178. foreach (var type in types)
  179. {
  180. DefineGenericParameters(type);
  181. DefineTypeMembers(type);
  182. }
  183. foreach (var module in CompileUnit.Modules)
  184. OnModule(module);
  185. EmitAttributes();
  186. CreateTypes(types);
  187. }
  188. sealed class AttributeEmitVisitor : FastDepthFirstVisitor
  189. {
  190. EmitAssembly _emitter;
  191. public AttributeEmitVisitor(EmitAssembly emitter)
  192. {
  193. _emitter = emitter;
  194. }
  195. public override void OnField(Field node)
  196. {
  197. _emitter.EmitFieldAttributes(node);
  198. }
  199. public override void OnEnumMember(EnumMember node)
  200. {
  201. _emitter.EmitFieldAttributes(node);
  202. }
  203. public override void OnEvent(Event node)
  204. {
  205. _emitter.EmitEventAttributes(node);
  206. }
  207. public override void OnProperty(Property node)
  208. {
  209. Visit(node.Getter);
  210. Visit(node.Setter);
  211. _emitter.EmitPropertyAttributes(node);
  212. }
  213. public override void OnConstructor(Constructor node)
  214. {
  215. Visit(node.Parameters);
  216. _emitter.EmitConstructorAttributes(node);
  217. }
  218. public override void OnMethod(Method node)
  219. {
  220. Visit(node.Parameters);
  221. _emitter.EmitMethodAttributes(node);
  222. }
  223. public override void OnParameterDeclaration(ParameterDeclaration node)
  224. {
  225. _emitter.EmitParameterAttributes(node);
  226. }
  227. public override void OnClassDefinition(ClassDefinition node)
  228. {
  229. base.OnClassDefinition(node);
  230. _emitter.EmitTypeAttributes(node);
  231. }
  232. public override void OnInterfaceDefinition(InterfaceDefinition node)
  233. {
  234. base.OnInterfaceDefinition(node);
  235. _emitter.EmitTypeAttributes(node);
  236. }
  237. public override void OnEnumDefinition(EnumDefinition node)
  238. {
  239. base.OnEnumDefinition(node);
  240. _emitter.EmitTypeAttributes(node);
  241. }
  242. }
  243. delegate void CustomAttributeSetter(CustomAttributeBuilder attribute);
  244. void EmitAttributes(INodeWithAttributes node, CustomAttributeSetter setCustomAttribute)
  245. {
  246. foreach (Attribute attribute in node.Attributes)
  247. setCustomAttribute(GetCustomAttributeBuilder(attribute));
  248. }
  249. void EmitPropertyAttributes(Property node)
  250. {
  251. PropertyBuilder builder = GetPropertyBuilder(node);
  252. EmitAttributes(node, builder.SetCustomAttribute);
  253. }
  254. void EmitParameterAttributes(ParameterDeclaration node)
  255. {
  256. ParameterBuilder builder = (ParameterBuilder)GetBuilder(node);
  257. EmitAttributes(node, builder.SetCustomAttribute);
  258. }
  259. void EmitEventAttributes(Event node)
  260. {
  261. EventBuilder builder = (EventBuilder)GetBuilder(node);
  262. EmitAttributes(node, builder.SetCustomAttribute);
  263. }
  264. void EmitConstructorAttributes(Constructor node)
  265. {
  266. ConstructorBuilder builder = (ConstructorBuilder)GetBuilder(node);
  267. EmitAttributes(node, builder.SetCustomAttribute);
  268. }
  269. void EmitMethodAttributes(Method node)
  270. {
  271. MethodBuilder builder = GetMethodBuilder(node);
  272. EmitAttributes(node, builder.SetCustomAttribute);
  273. }
  274. void EmitTypeAttributes(TypeDefinition node)
  275. {
  276. TypeBuilder builder = GetTypeBuilder(node);
  277. EmitAttributes(node, builder.SetCustomAttribute);
  278. }
  279. void EmitFieldAttributes(TypeMember node)
  280. {
  281. FieldBuilder builder = GetFieldBuilder(node);
  282. EmitAttributes(node, builder.SetCustomAttribute);
  283. }
  284. void EmitAttributes()
  285. {
  286. AttributeEmitVisitor visitor = new AttributeEmitVisitor(this);
  287. foreach (Module module in CompileUnit.Modules)
  288. module.Accept(visitor);
  289. }
  290. void CreateTypes(List<TypeDefinition> types)
  291. {
  292. new TypeCreator(this, types).Run();
  293. }
  294. /// <summary>
  295. /// Ensures that all types are created in the correct order.
  296. /// </summary>
  297. sealed class TypeCreator
  298. {
  299. EmitAssembly _emitter;
  300. Set<TypeDefinition> _created;
  301. List<TypeDefinition> _types;
  302. TypeDefinition _current;
  303. public TypeCreator(EmitAssembly emitter, List<TypeDefinition> types)
  304. {
  305. _emitter = emitter;
  306. _types = types;
  307. _created = new Set<TypeDefinition>();
  308. }
  309. public void Run()
  310. {
  311. AppDomain domain = Thread.GetDomain();
  312. try
  313. {
  314. domain.TypeResolve += OnTypeResolve;
  315. CreateTypes();
  316. }
  317. finally
  318. {
  319. domain.TypeResolve -= OnTypeResolve;
  320. }
  321. }
  322. private Assembly OnTypeResolve(object sender, ResolveEventArgs args)
  323. {
  324. Trace("OnTypeResolve('{0}') during '{1}' creation.", args.Name, _current);
  325. EnsureInternalFieldDependencies(_current);
  326. return _emitter._asmBuilder;
  327. }
  328. private void CreateTypes()
  329. {
  330. foreach (var type in _types)
  331. CreateType(type);
  332. }
  333. void CreateType(TypeDefinition type)
  334. {
  335. if (_created.Contains(type))
  336. return;
  337. _created.Add(type);
  338. var saved = _current;
  339. _current = type;
  340. try
  341. {
  342. HandleTypeCreation(type);
  343. }
  344. catch (Exception e)
  345. {
  346. throw CompilerErrorFactory.InternalError(type, string.Format("Failed to create '{0}' type.", type), e);
  347. }
  348. _current = saved;
  349. }
  350. private void HandleTypeCreation(TypeDefinition type)
  351. {
  352. Trace("creating type '{0}'", type);
  353. if (IsNestedType(type))
  354. CreateOuterTypeOf(type);
  355. CreateRelatedTypes(type);
  356. var typeBuilder = (TypeBuilder)_emitter.GetBuilder(type);
  357. typeBuilder.CreateType();
  358. Trace("type '{0}' successfully created", type);
  359. }
  360. private void CreateOuterTypeOf(TypeMember type)
  361. {
  362. CreateType(type.DeclaringType);
  363. }
  364. private void CreateRelatedTypes(TypeDefinition typedef)
  365. {
  366. CreateRelatedTypes(typedef.BaseTypes);
  367. foreach (var gpd in typedef.GenericParameters)
  368. CreateRelatedTypes(gpd.BaseTypes);
  369. }
  370. private void EnsureInternalFieldDependencies(TypeDefinition typedef)
  371. {
  372. foreach (var field in typedef.Members.OfType<Field>())
  373. EnsureInternalDependencies((IType)field.Type.Entity);
  374. }
  375. private void CreateRelatedTypes(IEnumerable<TypeReference> typerefs)
  376. {
  377. foreach (var typeref in typerefs)
  378. {
  379. var type = _emitter.GetType(typeref);
  380. EnsureInternalDependencies(type);
  381. }
  382. }
  383. private void EnsureInternalDependencies(IType type)
  384. {
  385. var internalType = type as AbstractInternalType;
  386. if (null != internalType)
  387. {
  388. CreateType(internalType.TypeDefinition);
  389. return;
  390. }
  391. if (type.ConstructedInfo != null)
  392. {
  393. EnsureInternalDependencies(type.ConstructedInfo.GenericDefinition);
  394. foreach (var typeArg in type.ConstructedInfo.GenericArguments)
  395. EnsureInternalDependencies(typeArg);
  396. }
  397. }
  398. static bool IsNestedType(TypeMember type)
  399. {
  400. switch (type.ParentNode.NodeType)
  401. {
  402. case NodeType.ClassDefinition:
  403. case NodeType.InterfaceDefinition:
  404. return true;
  405. }
  406. return false;
  407. }
  408. void Trace(string format, params object[] args)
  409. {
  410. _emitter.Context.TraceVerbose(format, args);
  411. }
  412. }
  413. List<TypeDefinition> CollectTypes()
  414. {
  415. var types = new List<TypeDefinition>();
  416. foreach (Module module in CompileUnit.Modules)
  417. CollectTypes(types, module.Members);
  418. return types;
  419. }
  420. void CollectTypes(List<TypeDefinition> types, TypeMemberCollection members)
  421. {
  422. foreach (var member in members)
  423. {
  424. switch (member.NodeType)
  425. {
  426. case NodeType.InterfaceDefinition:
  427. case NodeType.ClassDefinition:
  428. {
  429. var typeDefinition = ((TypeDefinition)member);
  430. types.Add(typeDefinition);
  431. CollectTypes(types, typeDefinition.Members);
  432. break;
  433. }
  434. case NodeType.EnumDefinition:
  435. {
  436. types.Add((TypeDefinition) member);
  437. break;
  438. }
  439. }
  440. }
  441. }
  442. override public void Dispose()
  443. {
  444. base.Dispose();
  445. _asmBuilder = null;
  446. _moduleBuilder = null;
  447. _symbolDocWriters.Clear();
  448. _il = null;
  449. _returnStatements = 0;
  450. _hasLeaveWithStoredValue = false;
  451. _returnImplicit = false;
  452. _returnType = null;
  453. _tryBlock = 0;
  454. _checked = true;
  455. _rawArrayIndexing = false;
  456. _types.Clear();
  457. _typeCache.Clear();
  458. _builders.Clear();
  459. _assemblyAttributes.Clear();
  460. _defaultValueHolders.Clear();
  461. _packedArrays.Clear();
  462. }
  463. override public void OnAttribute(Attribute node)
  464. {
  465. }
  466. override public void OnModule(Module module)
  467. {
  468. _perModuleRawArrayIndexing = AstAnnotations.IsRawIndexing(module);
  469. _checked = AstAnnotations.IsChecked(module, Parameters.Checked);
  470. Visit(module.Members);
  471. }
  472. override public void OnEnumDefinition(EnumDefinition node)
  473. {
  474. var typeBuilder = GetTypeBuilder(node);
  475. foreach (EnumMember member in node.Members)
  476. {
  477. var field = typeBuilder.DefineField(member.Name, typeBuilder,
  478. FieldAttributes.Public |
  479. FieldAttributes.Static |
  480. FieldAttributes.Literal);
  481. field.SetConstant(InitializerValueOf(member, node));
  482. SetBuilder(member, field);
  483. }
  484. }
  485. private object InitializerValueOf(EnumMember enumMember, EnumDefinition enumType)
  486. {
  487. return Convert.ChangeType(((IntegerLiteralExpression) enumMember.Initializer).Value,
  488. GetEnumUnderlyingType(enumType));
  489. }
  490. override public void OnArrayTypeReference(ArrayTypeReference node)
  491. {
  492. }
  493. override public void OnClassDefinition(ClassDefinition node)
  494. {
  495. EmitTypeDefinition(node);
  496. }
  497. override public void OnField(Field node)
  498. {
  499. FieldBuilder builder = GetFieldBuilder(node);
  500. if (builder.IsLiteral)
  501. {
  502. builder.SetConstant(GetInternalFieldStaticValue((InternalField)node.Entity));
  503. }
  504. }
  505. override public void OnInterfaceDefinition(InterfaceDefinition node)
  506. {
  507. TypeBuilder builder = GetTypeBuilder(node);
  508. foreach (TypeReference baseType in node.BaseTypes)
  509. {
  510. builder.AddInterfaceImplementation(GetSystemType(baseType));
  511. }
  512. }
  513. override public void OnMacroStatement(MacroStatement node)
  514. {
  515. NotImplemented(node, "Unexpected macro: " + node.ToCodeString());
  516. }
  517. override public void OnCallableDefinition(CallableDefinition node)
  518. {
  519. NotImplemented(node, "Unexpected callable definition!");
  520. }
  521. void EmitTypeDefinition(TypeDefinition node)
  522. {
  523. TypeBuilder current = GetTypeBuilder(node);
  524. EmitBaseTypesAndAttributes(node, current);
  525. Visit(node.Members);
  526. }
  527. override public void OnMethod(Method method)
  528. {
  529. if (method.IsRuntime) return;
  530. if (IsPInvoke(method)) return;
  531. MethodBuilder methodBuilder = GetMethodBuilder(method);
  532. DefineExplicitImplementationInfo(method);
  533. EmitMethod(method, methodBuilder.GetILGenerator());
  534. }
  535. private void DefineExplicitImplementationInfo(Method method)
  536. {
  537. if (null == method.ExplicitInfo)
  538. return;
  539. IMethod ifaceMethod = (IMethod)method.ExplicitInfo.Entity;
  540. MethodInfo ifaceInfo = GetMethodInfo(ifaceMethod);
  541. MethodInfo implInfo = GetMethodInfo((IMethod)method.Entity);
  542. TypeBuilder typeBuilder = GetTypeBuilder(method.DeclaringType);
  543. typeBuilder.DefineMethodOverride(implInfo, ifaceInfo);
  544. }
  545. void EmitMethod(Method method, ILGenerator generator)
  546. {
  547. _il = generator;
  548. _method = method;
  549. DefineLabels(method);
  550. Visit(method.Locals);
  551. BeginMethodBody(GetEntity(method).ReturnType);
  552. Visit(method.Body);
  553. EndMethodBody(method);
  554. }
  555. void BeginMethodBody(IType returnType)
  556. {
  557. _defaultValueHolders.Clear();
  558. _returnType = returnType;
  559. _returnStatements = 0;
  560. _returnImplicit = IsVoid(returnType);
  561. _hasLeaveWithStoredValue = false;
  562. //we may not actually use (any/all of) them, but at least they're ready
  563. _returnLabel = _il.DefineLabel();
  564. _leaveLabel = _il.DefineLabel();
  565. _implicitLabel = _il.DefineLabel();
  566. }
  567. void EndMethodBody(Method method)
  568. {
  569. if (!_returnImplicit)
  570. _returnImplicit = !AstUtil.AllCodePathsReturnOrRaise(method.Body);
  571. //At most a method epilogue contains 3 independent load instructions:
  572. //1) load of the value of an actual return (emitted elsewhere and branched to _returnLabel)
  573. //2) load of a default value (implicit returns [e.g return without expression])
  574. //3) load of the `leave' stored value
  575. bool hasDefaultValueReturn = _returnImplicit && !IsVoid(_returnType);
  576. if (hasDefaultValueReturn)
  577. {
  578. if (_returnStatements == -1) //emit branch only if instructed to do so (-1)
  579. _il.Emit(OpCodes.Br_S, _returnLabel);
  580. //load default return value for implicit return
  581. _il.MarkLabel(_implicitLabel);
  582. EmitDefaultValue(_returnType);
  583. PopType();
  584. }
  585. if (_hasLeaveWithStoredValue)
  586. {
  587. if (hasDefaultValueReturn || _returnStatements == -1)
  588. _il.Emit(OpCodes.Br_S, _returnLabel);
  589. //load the stored return value and `ret'
  590. _il.MarkLabel(_leaveLabel);
  591. _il.Emit(OpCodes.Ldloc, GetDefaultValueHolder(_returnType));
  592. }
  593. if (_returnImplicit || _returnStatements != 0)
  594. {
  595. _il.MarkLabel(_returnLabel);
  596. _il.Emit(OpCodes.Ret);
  597. }
  598. }
  599. private bool IsPInvoke(Method method)
  600. {
  601. return GetEntity(method).IsPInvoke;
  602. }
  603. override public void OnBlock(Block block)
  604. {
  605. var currentChecked = _checked;
  606. _checked = AstAnnotations.IsChecked(block, currentChecked);
  607. var currentArrayIndexing = _rawArrayIndexing;
  608. _rawArrayIndexing = _perModuleRawArrayIndexing || AstAnnotations.IsRawIndexing(block);
  609. Visit(block.Statements);
  610. _rawArrayIndexing = currentArrayIndexing;
  611. _checked = currentChecked;
  612. }
  613. void DefineLabels(Method method)
  614. {
  615. foreach (var label in LabelsOn(method))
  616. label.Label = _il.DefineLabel();
  617. }
  618. private InternalLabel[] LabelsOn(Method method)
  619. {
  620. return ((InternalMethod) method.Entity).Labels;
  621. }
  622. override public void OnConstructor(Constructor constructor)
  623. {
  624. if (constructor.IsRuntime) return;
  625. ConstructorBuilder builder = GetConstructorBuilder(constructor);
  626. EmitMethod(constructor, builder.GetILGenerator());
  627. }
  628. override public void OnLocal(Local local)
  629. {
  630. InternalLocal info = GetInternalLocal(local);
  631. info.LocalBuilder = _il.DeclareLocal(GetSystemType(local), info.Type.IsPointer);
  632. if (Parameters.Debug)
  633. {
  634. info.LocalBuilder.SetLocalSymInfo(local.Name);
  635. }
  636. }
  637. override public void OnForStatement(ForStatement node)
  638. {
  639. NotImplemented("ForStatement");
  640. }
  641. override public void OnReturnStatement(ReturnStatement node)
  642. {
  643. EmitDebugInfo(node);
  644. var retOpCode = _tryBlock > 0 ? OpCodes.Leave : OpCodes.Br;
  645. var label = _returnLabel;
  646. var expression = node.Expression;
  647. if (expression != null)
  648. {
  649. ++_returnStatements;
  650. LoadExpressionWithType(_returnType, expression);
  651. if (retOpCode == OpCodes.Leave)
  652. {
  653. //`leave' clears the stack, so we have to store return value temporarily
  654. //we can use a default value holder for that since it won't be read afterwards
  655. //of course this is necessary only if return type is not void
  656. LocalBuilder temp = GetDefaultValueHolder(_returnType);
  657. _il.Emit(OpCodes.Stloc, temp);
  658. label = _leaveLabel;
  659. _hasLeaveWithStoredValue = true;
  660. }
  661. }
  662. else if (_returnType != TypeSystemServices.VoidType)
  663. {
  664. _returnImplicit = true;
  665. label = _implicitLabel;
  666. }
  667. if (_method.Body.LastStatement != node)
  668. _il.Emit(retOpCode, label);
  669. else if (null != expression)
  670. _returnStatements = -1; //instruct epilogue to branch last ret only if necessary
  671. }
  672. private void LoadExpressionWithType(IType expectedType, Expression expression)
  673. {
  674. Visit(expression);
  675. EmitCastIfNeeded(expectedType, PopType());
  676. }
  677. override public void OnRaiseStatement(RaiseStatement node)
  678. {
  679. EmitDebugInfo(node);
  680. if (node.Exception == null)
  681. {
  682. _il.Emit(OpCodes.Rethrow);
  683. }
  684. else
  685. {
  686. Visit(node.Exception); PopType();
  687. _il.Emit(OpCodes.Throw);
  688. }
  689. }
  690. override public void OnTryStatement(TryStatement node)
  691. {
  692. ++_tryBlock;
  693. Label end = _il.BeginExceptionBlock();
  694. // The fault handler isn't very well supported by the
  695. // the ILGenerator. Thus, when there is a failure block
  696. // in the same try as an except or ensure block, we
  697. // need to do some special brute forcing with the exception
  698. // block context in the ILGenerator.
  699. if(null != node.FailureBlock && null != node.EnsureBlock)
  700. {
  701. ++_tryBlock;
  702. _il.BeginExceptionBlock();
  703. }
  704. if(null != node.FailureBlock && node.ExceptionHandlers.Count > 0)
  705. {
  706. ++_tryBlock;
  707. _il.BeginExceptionBlock();
  708. }
  709. Visit(node.ProtectedBlock);
  710. Visit(node.ExceptionHandlers);
  711. if(null != node.FailureBlock)
  712. {
  713. // Logic to back out of the manually forced blocks
  714. if(node.ExceptionHandlers.Count > 0)
  715. {
  716. _il.EndExceptionBlock();
  717. --_tryBlock;
  718. }
  719. _il.BeginFaultBlock();
  720. Visit(node.FailureBlock);
  721. // Logic to back out of the manually forced blocks once more
  722. if(null != node.EnsureBlock)
  723. {
  724. _il.EndExceptionBlock();
  725. --_tryBlock;
  726. }
  727. }
  728. if (null != node.EnsureBlock)
  729. {
  730. _il.BeginFinallyBlock();
  731. Visit(node.EnsureBlock);
  732. }
  733. _il.EndExceptionBlock();
  734. --_tryBlock;
  735. }
  736. override public void OnExceptionHandler(ExceptionHandler node)
  737. {
  738. if((node.Flags & ExceptionHandlerFlags.Filter) == ExceptionHandlerFlags.Filter)
  739. {
  740. _il.BeginExceptFilterBlock();
  741. Label endLabel = _il.DefineLabel();
  742. // If the filter is not untyped, then test the exception type
  743. // before testing the filter condition
  744. if((node.Flags & ExceptionHandlerFlags.Untyped) == ExceptionHandlerFlags.None)
  745. {
  746. Label filterCondition = _il.DefineLabel();
  747. // Test the type of the exception.
  748. _il.Emit(OpCodes.Isinst, GetSystemType(node.Declaration.Type));
  749. // Duplicate it. If it is null, then it will be used to
  750. // skip the filter.
  751. Dup();
  752. // If the exception is of the right type, branch
  753. // to test the filter condition.
  754. _il.Emit(OpCodes.Brtrue_S, filterCondition);
  755. // Otherwise, clean up the stack and prepare the stack
  756. // to skip the filter.
  757. EmitStoreOrPopException(node);
  758. _il.Emit(OpCodes.Ldc_I4_0);
  759. _il.Emit(OpCodes.Br, endLabel);
  760. _il.MarkLabel(filterCondition);
  761. }
  762. else if((node.Flags & ExceptionHandlerFlags.Anonymous) == ExceptionHandlerFlags.None)
  763. {
  764. // Cast the exception to the default except type
  765. _il.Emit(OpCodes.Isinst, GetSystemType(node.Declaration.Type));
  766. }
  767. EmitStoreOrPopException(node);
  768. // Test the condition and convert to boolean if needed.
  769. node.FilterCondition.Accept(this);
  770. PopType();
  771. EmitToBoolIfNeeded(node.FilterCondition);
  772. // If the type is right and the condition is true,
  773. // proceed with the handler.
  774. _il.MarkLabel(endLabel);
  775. _il.Emit(OpCodes.Ldc_I4_0);
  776. _il.Emit(OpCodes.Cgt_Un);
  777. _il.BeginCatchBlock(null);
  778. }
  779. else
  780. {
  781. // Begin a normal catch block of the appropriate type.
  782. _il.BeginCatchBlock(GetSystemType(node.Declaration.Type));
  783. // Clean up the stack or store the exception if not anonymous.
  784. EmitStoreOrPopException(node);
  785. }
  786. Visit(node.Block);
  787. }
  788. private void EmitStoreOrPopException(ExceptionHandler node)
  789. {
  790. if((node.Flags & ExceptionHandlerFlags.Anonymous) == ExceptionHandlerFlags.None)
  791. {
  792. _il.Emit(OpCodes.Stloc, GetLocalBuilder(node.Declaration));
  793. }
  794. else
  795. {
  796. _il.Emit(OpCodes.Pop);
  797. }
  798. }
  799. override public void OnUnpackStatement(UnpackStatement node)
  800. {
  801. NotImplemented("Unpacking");
  802. }
  803. override public void OnExpressionStatement(ExpressionStatement node)
  804. {
  805. EmitDebugInfo(node);
  806. base.OnExpressionStatement(node);
  807. // if the type of the inner expression is not
  808. // void we need to pop its return value to leave
  809. // the stack sane
  810. DiscardValueOnStack();
  811. }
  812. void DiscardValueOnStack()
  813. {
  814. if (!IsVoid(PopType()))
  815. _il.Emit(OpCodes.Pop);
  816. }
  817. bool IsVoid(IType type)
  818. {
  819. return type == TypeSystemServices.VoidType;
  820. }
  821. override public void OnUnlessStatement(UnlessStatement node)
  822. {
  823. Label endLabel = _il.DefineLabel();
  824. EmitDebugInfo(node);
  825. EmitBranchTrue(node.Condition, endLabel);
  826. node.Block.Accept(this);
  827. _il.MarkLabel(endLabel);
  828. }
  829. void OnSwitch(MethodInvocationExpression node)
  830. {
  831. var args = node.Arguments;
  832. LoadExpressionWithType(TypeSystemServices.IntType, args[0]);
  833. _il.Emit(OpCodes.Switch, args.Skip(1).Select(e => LabelFor(e)).ToArray());
  834. PushVoid();
  835. }
  836. private static Label LabelFor(Expression expression)
  837. {
  838. return ((InternalLabel) expression.Entity).Label;
  839. }
  840. override public void OnGotoStatement(GotoStatement node)
  841. {
  842. EmitDebugInfo(node);
  843. InternalLabel label = (InternalLabel)GetEntity(node.Label);
  844. int gotoDepth = AstAnnotations.GetTryBlockDepth(node);
  845. int targetDepth = AstAnnotations.GetTryBlockDepth(label.LabelStatement);
  846. if (targetDepth == gotoDepth)
  847. {
  848. _il.Emit(OpCodes.Br, label.Label);
  849. }
  850. else
  851. {
  852. _il.Emit(OpCodes.Leave, label.Label);
  853. }
  854. }
  855. override public void OnLabelStatement(LabelStatement node)
  856. {
  857. EmitDebugInfo(node);
  858. _il.MarkLabel(((InternalLabel)node.Entity).Label);
  859. }
  860. override public void OnConditionalExpression(ConditionalExpression node)
  861. {
  862. var type = GetExpressionType(node);
  863. var endLabel = _il.DefineLabel();
  864. EmitBranchFalse(node.Condition, endLabel);
  865. LoadExpressionWithType(type, node.TrueValue);
  866. var elseEndLabel = _il.DefineLabel();
  867. _il.Emit(OpCodes.Br, elseEndLabel);
  868. _il.MarkLabel(endLabel);
  869. endLabel = elseEndLabel;
  870. LoadExpressionWithType(type, node.FalseValue);
  871. _il.MarkLabel(endLabel);
  872. PushType(type);
  873. }
  874. override public void OnIfStatement(IfStatement node)
  875. {
  876. Label endLabel = _il.DefineLabel();
  877. EmitDebugInfo(node);
  878. EmitBranchFalse(node.Condition, endLabel);
  879. node.TrueBlock.Accept(this);
  880. if (null != node.FalseBlock)
  881. {
  882. Label elseEndLabel = _il.DefineLabel();
  883. if (!node.TrueBlock.EndsWith<ReturnStatement>() && !node.TrueBlock.EndsWith<RaiseStatement>())
  884. _il.Emit(OpCodes.Br, elseEndLabel);
  885. _il.MarkLabel(endLabel);
  886. endLabel = elseEndLabel;
  887. node.FalseBlock.Accept(this);
  888. }
  889. _il.MarkLabel(endLabel);
  890. }
  891. void EmitBranchTrue(Expression expression, Label label)
  892. {
  893. EmitBranch(true, expression, label);
  894. }
  895. void EmitBranchFalse(Expression expression, Label label)
  896. {
  897. EmitBranch(false, expression, label);
  898. }
  899. void EmitBranch(bool branchOnTrue, BinaryExpression expression, Label label)
  900. {
  901. switch (expression.Operator)
  902. {
  903. case BinaryOperatorType.TypeTest:
  904. EmitTypeTest(expression);
  905. _il.Emit(branchOnTrue ? OpCodes.Brtrue : OpCodes.Brfalse, label);
  906. break;
  907. case BinaryOperatorType.Or:
  908. if (branchOnTrue)
  909. {
  910. EmitBranch(true, expression.Left, label);
  911. EmitBranch(true, expression.Right, label);
  912. }
  913. else
  914. {
  915. Label skipRhs = _il.DefineLabel();
  916. EmitBranch(true, expression.Left, skipRhs);
  917. EmitBranch(false, expression.Right, label);
  918. _il.MarkLabel(skipRhs);
  919. }
  920. break;
  921. case BinaryOperatorType.And:
  922. if (branchOnTrue)
  923. {
  924. Label skipRhs = _il.DefineLabel();
  925. EmitBranch(false, expression.Left, skipRhs);
  926. EmitBranch(true, expression.Right, label);
  927. _il.MarkLabel(skipRhs);
  928. }
  929. else
  930. {
  931. EmitBranch(false, expression.Left, label);
  932. EmitBranch(false, expression.Right, label);
  933. }
  934. break;
  935. case BinaryOperatorType.Equality:
  936. if (IsZeroEquivalent(expression.Left))
  937. EmitBranch(!branchOnTrue, expression.Right, label);
  938. else if (IsZeroEquivalent(expression.Right))
  939. EmitBranch(!branchOnTrue, expression.Left, label);
  940. else
  941. {
  942. LoadCmpOperands(expression);
  943. _il.Emit(branchOnTrue ? OpCodes.Beq : OpCodes.Bne_Un, label);
  944. }
  945. break;
  946. case BinaryOperatorType.Inequality:
  947. if (IsZeroEquivalent(expression.Left))
  948. {
  949. EmitBranch(branchOnTrue, expression.Right, label);
  950. }
  951. else if (IsZeroEquivalent(expression.Right))
  952. {
  953. EmitBranch(branchOnTrue, expression.Left, label);
  954. }
  955. else
  956. {
  957. LoadCmpOperands(expression);
  958. _il.Emit(branchOnTrue ? OpCodes.Bne_Un : OpCodes.Beq, label);
  959. }
  960. break;
  961. case BinaryOperatorType.ReferenceEquality:
  962. if (IsNull(expression.Left))
  963. {
  964. EmitRawBranch(!branchOnTrue, expression.Right, label);
  965. break;
  966. }
  967. if (IsNull(expression.Right))
  968. {
  969. EmitRawBranch(!branchOnTrue, expression.Left, label);
  970. break;
  971. }
  972. Visit(expression.Left); PopType();
  973. Visit(expression.Right); PopType();
  974. _il.Emit(branchOnTrue ? OpCodes.Beq : OpCodes.Bne_Un, label);
  975. break;
  976. case BinaryOperatorType.ReferenceInequality:
  977. if (IsNull(expression.Left))
  978. {
  979. EmitRawBranch(branchOnTrue, expression.Right, label);
  980. break;
  981. }
  982. if (IsNull(expression.Right))
  983. {
  984. EmitRawBranch(branchOnTrue, expression.Left, label);
  985. break;
  986. }
  987. Visit(expression.Left); PopType();
  988. Visit(expression.Right); PopType();
  989. _il.Emit(branchOnTrue ? OpCodes.Bne_Un : OpCodes.Beq, label);
  990. break;
  991. case BinaryOperatorType.GreaterThan:
  992. LoadCmpOperands(expression);
  993. _il.Emit(branchOnTrue ? OpCodes.Bgt : OpCodes.Ble, label);
  994. break;
  995. case BinaryOperatorType.GreaterThanOrEqual:
  996. LoadCmpOperands(expression);
  997. _il.Emit(branchOnTrue ? OpCodes.Bge : OpCodes.Blt, label);
  998. break;
  999. case BinaryOperatorType.LessThan:
  1000. LoadCmpOperands(expression);
  1001. _il.Emit(branchOnTrue ? OpCodes.Blt : OpCodes.Bge, label);
  1002. break;
  1003. case BinaryOperatorType.LessThanOrEqual:
  1004. LoadCmpOperands(expression);
  1005. _il.Emit(branchOnTrue ? OpCodes.Ble : OpCodes.Bgt, label);
  1006. break;
  1007. default:
  1008. EmitDefaultBranch(branchOnTrue, expression, label);
  1009. break;
  1010. }
  1011. }
  1012. void EmitBranch(bool branchOnTrue, UnaryExpression expression, Label label)
  1013. {
  1014. if (UnaryOperatorType.LogicalNot == expression.Operator)
  1015. {
  1016. EmitBranch(!branchOnTrue, expression.Operand, label);
  1017. }
  1018. else
  1019. {
  1020. EmitDefaultBranch(branchOnTrue, expression, label);
  1021. }
  1022. }
  1023. void EmitBranch(bool branchOnTrue, Expression expression, Label label)
  1024. {
  1025. switch (expression.NodeType)
  1026. {
  1027. case NodeType.BinaryExpression:
  1028. {
  1029. EmitBranch(branchOnTrue, (BinaryExpression)expression, label);
  1030. break;
  1031. }
  1032. case NodeType.UnaryExpression:
  1033. {
  1034. EmitBranch(branchOnTrue, (UnaryExpression)expression, label);
  1035. break;
  1036. }
  1037. default:
  1038. {
  1039. EmitDefaultBranch(branchOnTrue, expression, label);
  1040. break;
  1041. }
  1042. }
  1043. }
  1044. void EmitRawBranch(bool branch, Expression condition, Label label)
  1045. {
  1046. condition.Accept(this); PopType();
  1047. _il.Emit(branch ? OpCodes.Brtrue : OpCodes.Brfalse, label);
  1048. }
  1049. void EmitDefaultBranch(bool branch, Expression condition, Label label)
  1050. {
  1051. if (branch && IsOneEquivalent(condition))
  1052. {
  1053. _il.Emit(OpCodes.Br, label);
  1054. return;
  1055. }
  1056. if (!branch && IsZeroEquivalent(condition))
  1057. {
  1058. _il.Emit(OpCodes.Br, label);
  1059. return;
  1060. }
  1061. condition.Accept(this);
  1062. var type = PopType();
  1063. if (TypeSystemServices.IsFloatingPointNumber(type))
  1064. {
  1065. EmitDefaultValue(type);
  1066. _il.Emit(branch ? OpCodes.Bne_Un : OpCodes.Beq, label);
  1067. return;
  1068. }
  1069. EmitToBoolIfNeeded(condition);
  1070. _il.Emit(branch ? OpCodes.Brtrue : OpCodes.Brfalse, label);
  1071. }
  1072. private static bool IsZeroEquivalent(Expression expression)
  1073. {
  1074. return (IsNull(expression) || IsZero(expression) || IsFalse(expression));
  1075. }
  1076. private static bool IsOneEquivalent(Expression expression)
  1077. {
  1078. return IsBooleanLiteral(expression, true) || IsNumberLiteral(expression, 1);
  1079. }
  1080. private static bool IsNull(Expression expression)
  1081. {
  1082. return NodeType.NullLiteralExpression == expression.NodeType;
  1083. }
  1084. private static bool IsFalse(Expression expression)
  1085. {
  1086. return IsBooleanLiteral(expression, false);
  1087. }
  1088. private static bool IsBooleanLiteral(Expression expression, bool value)
  1089. {
  1090. return NodeType.BoolLiteralExpression == expression.NodeType
  1091. && (value == ((BoolLiteralExpression)expression).Value);
  1092. }
  1093. private static bool IsZero(Expression expression)
  1094. {
  1095. return IsNumberLiteral(expression, 0);
  1096. }
  1097. private static bool IsNumberLiteral(Expression expression, int value)
  1098. {
  1099. return (NodeType.IntegerLiteralExpression == expression.NodeType
  1100. && (value == ((IntegerLiteralExpression)expression).Value))
  1101. ||
  1102. (NodeType.DoubleLiteralExpression == expression.NodeType
  1103. && (value == ((DoubleLiteralExpression)expression).Value));
  1104. }
  1105. override public void OnBreakStatement(BreakStatement node)
  1106. {
  1107. EmitGoTo(_currentLoopInfo.BreakLabel, node);
  1108. }
  1109. private void EmitGoTo(Label label, Node debugInfo)
  1110. {
  1111. EmitDebugInfo(debugInfo);
  1112. _il.Emit(InTryInLoop() ? OpCodes.Leave : OpCodes.Br, label);
  1113. }
  1114. override public void OnContinueStatement(ContinueStatement node)
  1115. {
  1116. EmitGoTo(_currentLoopInfo.ContinueLabel, node);
  1117. }
  1118. override public void OnWhileStatement(WhileStatement node)
  1119. {
  1120. Label endLabel = _il.DefineLabel();
  1121. Label bodyLabel = _il.DefineLabel();
  1122. Label conditionLabel = _il.DefineLabel();
  1123. _il.Emit(OpCodes.Br, conditionLabel);
  1124. _il.MarkLabel(bodyLabel);
  1125. EnterLoop(endLabel, conditionLabel);
  1126. node.Block.Accept(this);
  1127. LeaveLoop();
  1128. _il.MarkLabel(conditionLabel);
  1129. EmitDebugInfo(node);
  1130. EmitBranchTrue(node.Condition, bodyLabel);
  1131. Visit(node.OrBlock);
  1132. Visit(node.ThenBlock);
  1133. _il.MarkLabel(endLabel);
  1134. }
  1135. void EmitIntNot()
  1136. {
  1137. _il.Emit(OpCodes.Ldc_I4_0);
  1138. _il.Emit(OpCodes.Ceq);
  1139. }
  1140. void EmitGenericNot()
  1141. {
  1142. // bool codification:
  1143. // value_on_stack ? 0 : 1
  1144. Label wasTrue = _il.DefineLabel();
  1145. Label wasFalse = _il.DefineLabel();
  1146. _il.Emit(OpCodes.Brfalse_S, wasFalse);
  1147. _il.Emit(OpCodes.Ldc_I4_0);
  1148. _il.Emit(OpCodes.Br_S, wasTrue);
  1149. _il.MarkLabel(wasFalse);
  1150. _il.Emit(OpCodes.Ldc_I4_1);
  1151. _il.MarkLabel(wasTrue);
  1152. }
  1153. override public void OnUnaryExpression(UnaryExpression node)
  1154. {
  1155. switch (node.Operator)
  1156. {
  1157. case UnaryOperatorType.LogicalNot:
  1158. {
  1159. EmitLogicalNot(node);
  1160. break;
  1161. }
  1162. case UnaryOperatorType.UnaryNegation:
  1163. {
  1164. EmitUnaryNegation(node);
  1165. break;
  1166. }
  1167. case UnaryOperatorType.OnesComplement:
  1168. {
  1169. EmitOnesComplement(node);
  1170. break;
  1171. }
  1172. case UnaryOperatorType.AddressOf:
  1173. {
  1174. EmitAddressOf(node);
  1175. break;
  1176. }
  1177. case UnaryOperatorType.Indirection:
  1178. {
  1179. EmitIndirection(node);
  1180. break;
  1181. }
  1182. default:
  1183. {
  1184. NotImplemented(node, "unary operator not supported");
  1185. break;
  1186. }
  1187. }
  1188. }
  1189. IType _byAddress = null;
  1190. bool IsByAddress(IType type)
  1191. {
  1192. return (_byAddress == type);
  1193. }
  1194. void EmitDefaultValue(IType type)
  1195. {
  1196. var isGenericParameter = GenericsServices.IsGenericParameter(type);
  1197. if (!type.IsValueType && !isGenericParameter)
  1198. _il.Emit(OpCodes.Ldnull);
  1199. else if (type == TypeSystemServices.BoolType)
  1200. _il.Emit(OpCodes.Ldc_I4_0);
  1201. else if (TypeSystemServices.IsFloatingPointNumber(type))
  1202. EmitLoadLiteral(type, 0.0);
  1203. else if (TypeSystemServices.IsPrimitiveNumber(type) || type == TypeSystemServices.CharType)
  1204. EmitLoadLiteral(type, 0);
  1205. else if (isGenericParameter && TypeSystemServices.IsReferenceType(type))
  1206. {
  1207. _il.Emit(OpCodes.Ldnull);
  1208. _il.Emit(OpCodes.Unbox_Any, GetSystemType(type));
  1209. }
  1210. else //valuetype or valuetype/unconstrained generic parameter
  1211. {
  1212. //TODO: if MethodBody.InitLocals is false
  1213. //_il.Emit(OpCodes.Ldloca, GetDefaultValueHolder(type));
  1214. //_il.Emit(OpCodes.Initobj, GetSystemType(type));
  1215. _il.Emit(OpCodes.Ldloc, GetDefaultValueHolder(type));
  1216. }
  1217. PushType(type);
  1218. }
  1219. Dictionary<IType, LocalBuilder> _defaultValueHolders = new Dictionary<IType, LocalBuilder>();
  1220. //get the default value holder (a local actually) for a given type
  1221. //default value holder pool is cleared before each method body processing
  1222. LocalBuilder GetDefaultValueHolder(IType type)
  1223. {
  1224. LocalBuilder holder;
  1225. if (_defaultValueHolders.TryGetValue(type, out holder))
  1226. return holder;
  1227. holder = _il.DeclareLocal(GetSystemType(type));
  1228. _defaultValueHolders.Add(type, holder);
  1229. return holder;
  1230. }
  1231. private void EmitOnesComplement(UnaryExpression node)
  1232. {
  1233. node.Operand.Accept(this);
  1234. _il.Emit(OpCodes.Not);
  1235. }
  1236. private void EmitLogicalNot(UnaryExpression node)
  1237. {
  1238. Expression operand = node.Operand;
  1239. operand.Accept(this);
  1240. IType typeOnStack = PopType();
  1241. bool notContext = true;
  1242. if (IsBoolOrInt(typeOnStack))
  1243. {
  1244. EmitIntNot();
  1245. }
  1246. else if (EmitToBoolIfNeeded(operand, ref notContext))
  1247. {
  1248. if (!notContext) //we are in a not context and emit to bool is also in a not context
  1249. EmitIntNot();//so we do not need any not (false && false => true)
  1250. }
  1251. else
  1252. {
  1253. EmitGenericNot();
  1254. }
  1255. PushBool();
  1256. }
  1257. private void EmitUnaryNegation(UnaryExpression node)
  1258. {
  1259. var operandType = GetExpressionType(node.Operand);
  1260. if (IsCheckedIntegerOperand(operandType))
  1261. {
  1262. _il.Emit(OpCodes.Ldc_I4_0);
  1263. if (IsLong(operandType) || operandType == TypeSystemServices.ULongType)
  1264. _il.Emit(OpCodes.Conv_I8);
  1265. node.Operand.Accept(this);
  1266. _il.Emit(TypeSystemServices.IsSignedNumber(operandType)
  1267. ? OpCodes.Sub_Ovf
  1268. : OpCodes.Sub_Ovf_Un);
  1269. if (!IsLong(operandType) && operandType != TypeSystemServices.ULongType)
  1270. EmitCastIfNeeded(operandType, TypeSystemServices.IntType);
  1271. }
  1272. else
  1273. {
  1274. //a single/double unary negation never overflow
  1275. node.Operand.Accept(this);
  1276. _il.Emit(OpCodes.Neg);
  1277. }
  1278. }
  1279. private bool IsCheckedIntegerOperand(IType operandType)
  1280. {
  1281. return _checked && IsInteger(operandType);
  1282. }
  1283. void EmitAddressOf(UnaryExpression node)
  1284. {
  1285. _byAddress = GetExpressionType(node.Operand);
  1286. node.Operand.Accept(this);
  1287. PushType(PopType().MakePointerType());
  1288. _byAddress = null;
  1289. }
  1290. void EmitIndirection(UnaryExpression node)
  1291. {
  1292. node.Operand.Accept(this);
  1293. if (node.Operand.NodeType != NodeType.ReferenceExpression
  1294. && node.ParentNode.NodeType != NodeType.MemberReferenceExpression)
  1295. {
  1296. //pointer arithmetic, need to load the address
  1297. IType et = PeekTypeOnStack().ElementType;
  1298. OpCode code = GetLoadRefParamCode(et);
  1299. if (code == OpCodes.Ldobj)
  1300. _il.Emit(code, GetSystemType(et));
  1301. else
  1302. _il.Emit(code);
  1303. PopType();
  1304. PushType(et);
  1305. }
  1306. }
  1307. static bool ShouldLeaveValueOnStack(Expression node)
  1308. {
  1309. return node.ParentNode.NodeType != NodeType.ExpressionStatement;
  1310. }
  1311. void OnReferenceComparison(BinaryExpression node)
  1312. {
  1313. node.Left.Accept(this); PopType();
  1314. node.Right.Accept(this); PopType();
  1315. _il.Emit(OpCodes.Ceq);
  1316. if (BinaryOperatorType.ReferenceInequality == node.Operator)
  1317. {
  1318. EmitIntNot();
  1319. }
  1320. PushBool();
  1321. }
  1322. void OnAssignmentToSlice(BinaryExpression node)
  1323. {
  1324. var slice = (SlicingExpression)node.Left;
  1325. Visit(slice.Target);
  1326. var arrayType = (IArrayType)PopType();
  1327. if (arrayType.Rank == 1)
  1328. EmitAssignmentToSingleDimensionalArrayElement(arrayType, slice, node);
  1329. else
  1330. EmitAssignmentToMultiDimensionalArrayElement(arrayType, slice, node);
  1331. }
  1332. private void EmitAssignmentToMultiDimensionalArrayElement(IArrayType arrayType, SlicingExpression slice, BinaryExpression node)
  1333. {
  1334. var elementType = arrayType.ElementType;
  1335. LoadArrayIndices(slice);
  1336. var temp = LoadAssignmentOperand(elementType, node);
  1337. CallArrayMethod(arrayType, "Set", typeof(void), ParameterTypesForArraySet(arrayType));
  1338. FlushAssignmentOperand(elementType, temp);
  1339. }
  1340. private void EmitAssignmentToSingleDimensionalArrayElement(IArrayType arrayType, SlicingExpression slice, BinaryExpression node)
  1341. {
  1342. var elementType = arrayType.ElementType;
  1343. var index = slice.Indices[0];
  1344. EmitNormalizedArrayIndex(slice, index.Begin);
  1345. var opcode = GetStoreEntityOpCode(elementType);
  1346. bool stobj = IsStobj(opcode);
  1347. if (stobj) _il.Emit(OpCodes.Ldelema, GetSystemType(elementType));
  1348. var temp = LoadAssignmentOperand(elementType, node);
  1349. if (stobj)
  1350. _il.Emit(opcode, GetSystemType(elementType));
  1351. else
  1352. _il.Emit(opcode);
  1353. FlushAssignmentOperand(elementType, temp);
  1354. }
  1355. private void FlushAssignmentOperand(IType elementType, LocalBuilder temp)
  1356. {
  1357. if (temp != null)
  1358. LoadLocal(temp, elementType);
  1359. else
  1360. PushVoid();
  1361. }
  1362. private LocalBuilder LoadAssignmentOperand(IType elementType, BinaryExpression node)
  1363. {
  1364. LoadExpressionWithType(elementType, node.Right);
  1365. var leaveValueOnStack = ShouldLeaveValueOnStack(node);
  1366. LocalBuilder temp = null;
  1367. if (leaveValueOnStack)
  1368. {
  1369. Dup();
  1370. temp = StoreTempLocal(elementType);
  1371. }
  1372. return temp;
  1373. }
  1374. LocalBuilder _currentLocal = null;
  1375. void LoadLocal(LocalBuilder local, IType localType)
  1376. {
  1377. _il.Emit(OpCodes.Ldloc, local);
  1378. PushType(localType);
  1379. _currentLocal = local;
  1380. }
  1381. void LoadLocal(InternalLocal local)
  1382. {
  1383. LoadLocal(local, false);
  1384. }
  1385. void LoadLocal(InternalLocal local, bool byAddress)
  1386. {
  1387. _il.Emit(IsByAddress(local.Type) ? OpCodes.Ldloca : OpCodes.Ldloc, local.LocalBuilder);
  1388. PushType(local.Type);
  1389. _currentLocal = local.LocalBuilder;
  1390. }
  1391. void LoadIndirectLocal(InternalLocal local)
  1392. {
  1393. LoadLocal(local);
  1394. IType et = local.Type.ElementType;
  1395. PopType();
  1396. PushType(et);
  1397. OpCode code = GetLoadRefParamCode(et);
  1398. if (code == OpCodes.Ldobj)
  1399. _il.Emit(code, GetSystemType(et));
  1400. else
  1401. _il.Emit(code);
  1402. }
  1403. private LocalBuilder StoreTempLocal(IType elementType)
  1404. {
  1405. LocalBuilder temp;
  1406. temp = _il.DeclareLocal(GetSystemType(elementType));
  1407. _il.Emit(OpCodes.Stloc, temp);
  1408. return temp;
  1409. }
  1410. void OnAssignment(BinaryExpression node)
  1411. {
  1412. if (NodeType.SlicingExpression == node.Left.NodeType)
  1413. {
  1414. OnAssignmentToSlice(node);
  1415. return;
  1416. }
  1417. // when the parent is not a statement we need to leave
  1418. // the value on the stack
  1419. bool leaveValueOnStack = ShouldLeaveValueOnStack(node);
  1420. IEntity tag = TypeSystemServices.GetEntity(node.Left);
  1421. switch (tag.EntityType)
  1422. {
  1423. case EntityType.Local:
  1424. {
  1425. SetLocal(node, (InternalLocal)tag, leaveValueOnStack);
  1426. break;
  1427. }
  1428. case EntityType.Parameter:
  1429. {
  1430. InternalParameter param = (InternalParameter)tag;
  1431. if (param.Parameter.IsByRef)
  1432. {
  1433. SetByRefParam(param, node.Right, leaveValueOnStack);
  1434. break;
  1435. }
  1436. LoadExpressionWithType(param.Type, node.Right);
  1437. if (leaveValueOnStack)
  1438. {
  1439. Dup();
  1440. PushType(param.Type);
  1441. }
  1442. _il.Emit(OpCodes.Starg, param.Index);
  1443. break;
  1444. }
  1445. case EntityType.Field:
  1446. {
  1447. IField field = (IField)tag;
  1448. SetField(node, field, node.Left, node.Right, leaveValueOnStack);
  1449. break;
  1450. }
  1451. case EntityType.Property:
  1452. {
  1453. SetProperty((IProperty)tag, node.Left, node.Right, leaveValueOnStack);
  1454. break;
  1455. }
  1456. case EntityType.Event: //event=null (always internal in this context)
  1457. {
  1458. InternalEvent e = (InternalEvent) tag;
  1459. OpCode opcode = e.IsStatic ? OpCodes.Stsfld : OpCodes.Stfld;
  1460. _il.Emit(OpCodes.Ldnull);
  1461. _il.Emit(opcode, GetFieldBuilder(e.BackingField.Field));
  1462. break;
  1463. }
  1464. default:
  1465. {
  1466. NotImplemented(node, tag.ToString());
  1467. break;
  1468. }
  1469. }
  1470. if (!leaveValueOnStack)
  1471. {
  1472. PushVoid();
  1473. }
  1474. }
  1475. private void SetByRefParam(InternalParameter param, Expression right, bool leaveValueOnStack)
  1476. {
  1477. LocalBuilder temp = null;
  1478. IType tempType = null;
  1479. if (leaveValueOnStack)
  1480. {
  1481. Visit(right);
  1482. tempType = PopType();
  1483. temp = StoreTempLocal(tempType);
  1484. }
  1485. LoadParam(param);
  1486. if (temp != null)
  1487. {
  1488. LoadLocal(temp, tempType);
  1489. PopType();
  1490. }
  1491. else
  1492. LoadExpressionWithType(param.Type, right);
  1493. var storecode = GetStoreRefParamCode(param.Type);
  1494. if (IsStobj(storecode)) //passing struct/decimal byref
  1495. _il.Emit(storecode, GetSystemType(param.Type));
  1496. else
  1497. _il.Emit(storecode);
  1498. if (null != temp)
  1499. LoadLocal(temp, tempType);
  1500. }
  1501. void EmitTypeTest(BinaryExpression node)
  1502. {
  1503. Visit(node.Left);
  1504. IType actualType = PopType();
  1505. EmitBoxIfNeeded(TypeSystemServices.ObjectType, actualType);
  1506. Type type = NodeType.TypeofExpression == node.Right.NodeType
  1507. ? GetSystemType(((TypeofExpression)node.Right).Type)
  1508. : GetSystemType(node.Right);
  1509. _il.Emit(OpCodes.Isinst, type);
  1510. }
  1511. void OnTypeTest(BinaryExpression node)
  1512. {
  1513. EmitTypeTest(node);
  1514. _il.Emit(OpCodes.Ldnull);
  1515. _il.Emit(OpCodes.Cgt_Un);
  1516. PushBool();
  1517. }
  1518. void LoadCmpOperands(BinaryExpression node)
  1519. {
  1520. var lhs = node.Left.ExpressionType;
  1521. var rhs = node.Right.ExpressionType;
  1522. if (lhs != rhs)
  1523. {
  1524. var type = TypeSystemServices.GetPromotedNumberType(lhs, rhs);
  1525. LoadExpressionWithType(type, node.Left);
  1526. LoadExpressionWithType(type, node.Right);
  1527. }
  1528. else //no need for conversion
  1529. {
  1530. Visit(node.Left);
  1531. PopType();
  1532. Visit(node.Right);
  1533. PopType();
  1534. }
  1535. }
  1536. void OnEquality(BinaryExpression node)
  1537. {
  1538. LoadCmpOperands(node);
  1539. _il.Emit(OpCodes.Ceq);
  1540. PushBool();
  1541. }
  1542. void OnInequality(BinaryExpression node)
  1543. {
  1544. LoadCmpOperands(node);
  1545. _il.Emit(OpCodes.Ceq);
  1546. EmitIntNot();
  1547. PushBool();
  1548. }
  1549. void OnGreaterThan(BinaryExpression node)
  1550. {
  1551. LoadCmpOperands(node);
  1552. _il.Emit(OpCodes.Cgt);
  1553. PushBool();
  1554. }
  1555. void OnGreaterThanOrEqual(BinaryExpression node)
  1556. {
  1557. OnLessThan(node);
  1558. EmitIntNot();
  1559. }
  1560. void OnLessThan(BinaryExpression node)
  1561. {
  1562. LoadCmpOperands(node);
  1563. _il.Emit(OpCodes.Clt);
  1564. PushBool();
  1565. }
  1566. void OnLessThanOrEqual(BinaryExpression node)
  1567. {
  1568. OnGreaterThan(node);
  1569. EmitIntNot();
  1570. }
  1571. void OnExponentiation(BinaryExpression node)
  1572. {
  1573. var doubleType = TypeSystemServices.DoubleType;
  1574. LoadOperandsWithType(doubleType, node);
  1575. Call(Math_Pow);
  1576. PushType(doubleType);
  1577. }
  1578. private void LoadOperandsWithType(IType type, BinaryExpression node)
  1579. {
  1580. LoadExpressionWithType(type, node.Left);
  1581. LoadExpressionWithType(type, node.Right);
  1582. }
  1583. void OnArithmeticOperator(BinaryExpression node)
  1584. {
  1585. var type = node.ExpressionType;
  1586. LoadOperandsWithType(type, node);
  1587. _il.Emit(GetArithmeticOpCode(type, node.Operator));
  1588. PushType(type);
  1589. }
  1590. bool EmitToBoolIfNeeded(Expression expression)
  1591. {
  1592. bool notContext = false;
  1593. return EmitToBoolIfNeeded(expression, ref notContext);
  1594. }
  1595. //mostly used for logical operators and ducky mode
  1596. //other cases of bool context are handled by PMB
  1597. bool EmitToBoolIfNeeded(Expression expression, ref bool notContext)
  1598. {
  1599. bool inNotContext = notContext;
  1600. notContext = false;
  1601. //use a builtin conversion operator just for the logical operator trueness test
  1602. IType type = GetExpressionType(expression);
  1603. if (TypeSystemServices.ObjectType == type || TypeSystemServices.DuckType == type)
  1604. {
  1605. Call(RuntimeServices_ToBool_Object);
  1606. return true;
  1607. }
  1608. else if (TypeSystemServices.IsNullable(type))
  1609. {
  1610. _il.Emit(OpCodes.Ldloca, _currentLocal);
  1611. Type sType = GetSystemType(TypeSystemServices.GetNullableUnderlyingType(type));
  1612. Call(GetNullableHasValue(sType));
  1613. LocalBuilder hasValue = StoreTempLocal(TypeSystemServices.BoolType);
  1614. _il.Emit(OpCodes.Pop); //pop nullable address (ldloca)
  1615. _il.Emit(OpCodes.Ldloc, hasValue);
  1616. return true;
  1617. }
  1618. else if (TypeSystemServices.StringType == type)
  1619. {
  1620. Call(String_IsNullOrEmpty);
  1621. if (!inNotContext)
  1622. EmitIntNot(); //reverse result (true for not empty)
  1623. else
  1624. notContext = true;
  1625. return true;
  1626. }
  1627. else if (IsInteger(type))
  1628. {
  1629. if (IsLong(type) || TypeSystemServices.ULongType == type)
  1630. _il.Emit(OpCodes.Conv_I4);
  1631. return true;
  1632. }
  1633. else if (TypeSystemServices.SingleType == type)
  1634. {
  1635. EmitDefaultValue(TypeSystemServices.SingleType);
  1636. _il.Emit(OpCodes.Ceq);
  1637. if (!inNotContext)
  1638. EmitIntNot();
  1639. else
  1640. notContext = true;
  1641. return true;
  1642. }
  1643. else if (TypeSystemServices.DoubleType == type)
  1644. {
  1645. EmitDefaultValue(TypeSystemServices.DoubleType);
  1646. _il.Emit(OpCodes.Ceq);
  1647. if (!inNotContext)
  1648. EmitIntNot();
  1649. else
  1650. notContext = true;
  1651. return true;
  1652. }
  1653. else if (TypeSystemServices.DecimalType == type)
  1654. {
  1655. Call(RuntimeServices_ToBool_Decimal);
  1656. return true;
  1657. }
  1658. else if (!type.IsValueType)
  1659. {
  1660. if (null == expression.GetAncestor<BinaryExpression>()
  1661. && null != expression.GetAncestor<IfStatement>())
  1662. return true; //use br(true|false) directly (most common case)
  1663. _il.Emit(OpCodes.Ldnull);
  1664. if (!inNotContext)
  1665. {
  1666. _il.Emit(OpCodes.Cgt_Un);
  1667. }
  1668. else
  1669. {
  1670. _il.Emit(OpCodes.Ceq);
  1671. notContext = true;
  1672. }
  1673. return true;
  1674. }
  1675. return false;
  1676. }
  1677. void EmitAnd(BinaryExpression node)
  1678. {
  1679. EmitLogicalOperator(node, OpCodes.Brtrue, OpCodes.Brfalse);
  1680. }
  1681. void EmitOr(BinaryExpression node)
  1682. {
  1683. EmitLogicalOperator(node, OpCodes.Brfalse, OpCodes.Brtrue);
  1684. }
  1685. void EmitLogicalOperator(BinaryExpression node, OpCode brForValueType, OpCode brForRefType)
  1686. {
  1687. var type = GetExpressionType(node);
  1688. Visit(node.Left);
  1689. var lhsType = PopType();
  1690. if (lhsType != null && lhsType.IsValueType && !type.IsValueType)
  1691. {
  1692. // if boxing, first evaluate the value
  1693. // as it is and then box it...
  1694. Label evalRhs = _il.DefineLabel();
  1695. Label end = _il.DefineLabel();
  1696. Dup();
  1697. EmitToBoolIfNeeded(node.Left); // may need to convert decimal to bool
  1698. _il.Emit(brForValueType, evalRhs);
  1699. EmitCastIfNeeded(type, lhsType);
  1700. _il.Emit(OpCodes.Br_S, end);
  1701. _il.MarkLabel(evalRhs);
  1702. _il.Emit(OpCodes.Pop);
  1703. LoadExpressionWithType(type, node.Right);
  1704. _il.MarkLabel(end);
  1705. }
  1706. else
  1707. {
  1708. Label end = _il.DefineLabel();
  1709. EmitCastIfNeeded(type, lhsType);
  1710. Dup();
  1711. EmitToBoolIfNeeded(node.Left);
  1712. _il.Emit(brForRefType, end);
  1713. _il.Emit(OpCodes.Pop);
  1714. LoadExpressionWithType(type, node.Right);
  1715. _il.MarkLabel(end);
  1716. }
  1717. PushType(type);
  1718. }
  1719. IType GetExpectedTypeForBitwiseRightOperand(BinaryExpression node)
  1720. {
  1721. switch (node.Operator)
  1722. {
  1723. case BinaryOperatorType.ShiftLeft:
  1724. case BinaryOperatorType.ShiftRight:
  1725. return TypeSystemServices.IntType;
  1726. }
  1727. return GetExpressionType(node);
  1728. }
  1729. void EmitBitwiseOperator(BinaryExpression node)
  1730. {
  1731. var type = node.ExpressionType;
  1732. LoadExpressionWithType(type, node.Left);
  1733. LoadExpressionWithType(GetExpectedTypeForBitwiseRightOperand(node), node.Right);
  1734. switch (node.Operator)
  1735. {
  1736. case BinaryOperatorType.BitwiseOr:
  1737. {
  1738. _il.Emit(OpCodes.Or);
  1739. break;
  1740. }
  1741. case BinaryOperatorType.BitwiseAnd:
  1742. {
  1743. _il.Emit(OpCodes.And);
  1744. break;
  1745. }
  1746. case BinaryOperatorType.ExclusiveOr:
  1747. {
  1748. _il.Emit(OpCodes.Xor);
  1749. break;
  1750. }
  1751. case BinaryOperatorType.ShiftLeft:
  1752. {
  1753. _il.Emit(OpCodes.Shl);
  1754. break;
  1755. }
  1756. case BinaryOperatorType.ShiftRight:
  1757. {
  1758. _il.Emit(TypeSystemServices.IsSignedNumber(type) ? OpCodes.Shr : OpCodes.Shr_Un);
  1759. break;
  1760. }
  1761. }
  1762. PushType(type);
  1763. }
  1764. override public void OnBinaryExpression(BinaryExpression node)
  1765. {
  1766. switch (node.Operator)
  1767. {
  1768. case BinaryOperatorType.ShiftLeft:
  1769. case BinaryOperatorType.ShiftRight:
  1770. case BinaryOperatorType.ExclusiveOr:
  1771. case BinaryOperatorType.BitwiseAnd:
  1772. case BinaryOperatorType.BitwiseOr:
  1773. {
  1774. EmitBitwiseOperator(node);
  1775. break;
  1776. }
  1777. case BinaryOperatorType.Or:
  1778. {
  1779. EmitOr(node);
  1780. break;
  1781. }
  1782. case BinaryOperatorType.And:
  1783. {
  1784. EmitAnd(node);
  1785. break;
  1786. }
  1787. case BinaryOperatorType.Addition:
  1788. case BinaryOperatorType.Subtraction:
  1789. case BinaryOperatorType.Multiply:
  1790. case BinaryOperatorType.Division:
  1791. case BinaryOperatorType.Modulus:
  1792. {
  1793. OnArithmeticOperator(node);
  1794. break;
  1795. }
  1796. case BinaryOperatorType.Exponentiation:
  1797. {
  1798. OnExponentiation(node);
  1799. break;
  1800. }
  1801. case BinaryOperatorType.Assign:
  1802. {
  1803. OnAssignment(node);
  1804. break;
  1805. }
  1806. case BinaryOperatorType.Equality:
  1807. {
  1808. OnEquality(node);
  1809. break;
  1810. }
  1811. case BinaryOperatorType.Inequality:
  1812. {
  1813. OnInequality(node);
  1814. break;
  1815. }
  1816. case BinaryOperatorType.GreaterThan:
  1817. {
  1818. OnGreaterThan(node);
  1819. break;
  1820. }
  1821. case BinaryOperatorType.LessThan:
  1822. {
  1823. OnLessThan(node);
  1824. break;
  1825. }
  1826. case BinaryOperatorType.GreaterThanOrEqual:
  1827. {
  1828. OnGreaterThanOrEqual(node);
  1829. break;
  1830. }
  1831. case BinaryOperatorType.LessThanOrEqual:
  1832. {
  1833. OnLessThanOrEqual(node);
  1834. break;
  1835. }
  1836. case BinaryOperatorType.ReferenceInequality:
  1837. {
  1838. OnReferenceComparison(node);
  1839. break;
  1840. }
  1841. case BinaryOperatorType.ReferenceEquality:
  1842. {
  1843. OnReferenceComparison(node);
  1844. break;
  1845. }
  1846. case BinaryOperatorType.TypeTest:
  1847. {
  1848. OnTypeTest(node);
  1849. break;
  1850. }
  1851. default:
  1852. {
  1853. OperatorNotImplemented(node);
  1854. break;
  1855. }
  1856. }
  1857. }
  1858. void OperatorNotImplemented(BinaryExpression node)
  1859. {
  1860. NotImplemented(node, node.Operator.ToString());
  1861. }
  1862. override public void OnTypeofExpression(TypeofExpression node)
  1863. {
  1864. EmitGetTypeFromHandle(GetSystemType(node.Type));
  1865. }
  1866. override public void OnCastExpression(CastExpression node)
  1867. {
  1868. var type = GetType(node.Type);
  1869. LoadExpressionWithType(type, node.Target);
  1870. PushType(type);
  1871. }
  1872. override public void OnTryCastExpression(TryCastExpression node)
  1873. {
  1874. var type = GetSystemType(node.Type);
  1875. node.Target.Accept(this); PopType();
  1876. Isinst(type);
  1877. PushType(node.ExpressionType);
  1878. }
  1879. private void Isinst(Type type)
  1880. {
  1881. _il.Emit(OpCodes.Isinst, type);
  1882. }
  1883. void InvokeMethod(IMethod method, MethodInvocationExpression node)
  1884. {
  1885. var mi = GetMethodInfo(method);
  1886. if (!InvokeOptimizedMethod(method, mi, node))
  1887. InvokeRegularMethod(method, mi, node);
  1888. }
  1889. bool InvokeOptimizedMethod(IMethod method, MethodInfo mi, MethodInvocationExpression node)
  1890. {
  1891. if (Array_get_Length == mi)
  1892. {
  1893. // don't use ldlen for System.Array
  1894. if (!GetType(node.Target).IsArray)
  1895. return false;
  1896. // optimize constructs such as:
  1897. // len(anArray)
  1898. // anArray.Length
  1899. Visit(node.Target);
  1900. PopType();
  1901. _il.Emit(OpCodes.Ldlen);
  1902. PushType(TypeSystemServices.IntType);
  1903. return true;
  1904. }
  1905. if (mi.DeclaringType != Builtins_ArrayTypedConstructor.DeclaringType)
  1906. return false;
  1907. if (mi.IsGenericMethod)
  1908. {
  1909. if (Builtins_ArrayGenericConstructor == mi.GetGenericMethodDefinition())
  1910. {
  1911. // optimize constructs such as:
  1912. // array[of int](2)
  1913. IType type = method.ConstructedInfo.GenericArguments[0];
  1914. EmitNewArray(type, node.Arguments[0]);
  1915. return true;
  1916. }
  1917. if (mi.Name == "matrix")
  1918. {
  1919. EmitNewMatrix(node);
  1920. return true;
  1921. }
  1922. return false;
  1923. }
  1924. if (Builtins_ArrayTypedConstructor == mi)
  1925. {
  1926. // optimize constructs such as:
  1927. // array(int, 2)
  1928. IType type = TypeSystemServices.GetReferencedType(node.Arguments[0]);
  1929. if (null != type)
  1930. {
  1931. EmitNewArray(type, node.Arguments[1]);
  1932. return true;
  1933. }
  1934. }
  1935. else if (Builtins_ArrayTypedCollectionConstructor == mi)
  1936. {
  1937. // optimize constructs such as:
  1938. // array(int, (1, 2, 3))
  1939. // array(byte, [1, 2, 3, 4])
  1940. IType type = TypeSystemServices.GetReferencedType(node.Arguments[0]);
  1941. if (null != type)
  1942. {
  1943. ListLiteralExpression items = node.Arguments[1] as ListLiteralExpression;
  1944. if (null != items)
  1945. {
  1946. EmitArray(type, items.Items);
  1947. PushType(type.MakeArrayType(1));
  1948. return true;
  1949. }
  1950. }
  1951. }
  1952. return false;
  1953. }
  1954. private void EmitNewMatrix(MethodInvocationExpression node)
  1955. {
  1956. var expressionType = GetExpressionType(node);
  1957. var matrixType = GetSystemType(expressionType);
  1958. // matrix of type(dimensions)
  1959. EmitGetTypeFromHandle(matrixType.GetElementType());
  1960. PopType();
  1961. EmitArray(TypeSystemServices.IntType, node.Arguments);
  1962. Call(Array_CreateInstance);
  1963. Castclass(matrixType);
  1964. PushType(expressionType);
  1965. }
  1966. MethodInfo Array_CreateInstance
  1967. {
  1968. get
  1969. {
  1970. if (_Builtins_TypedMatrixConstructor != null)
  1971. return _Builtins_TypedMatrixConstructor;
  1972. return (_Builtins_TypedMatrixConstructor = Types.Array.GetMethod("CreateInstance", new Type[] { Types.Type, typeof(int[]) }));
  1973. }
  1974. }
  1975. private MethodInfo _Builtins_TypedMatrixConstructor;
  1976. void EmitNewArray(IType type, Expression length)
  1977. {
  1978. LoadIntExpression(length);
  1979. _il.Emit(OpCodes.Newarr, GetSystemType(type));
  1980. PushType(type.MakeArrayType(1));
  1981. }
  1982. void InvokeRegularMethod(IMethod method, MethodInfo mi, MethodInvocationExpression node)
  1983. {
  1984. // Do not emit call if conditional attributes (if any) do not match defined symbols
  1985. if (!CheckConditionalAttributes(method))
  1986. {
  1987. EmitNop();
  1988. PushType(method.ReturnType); // keep a valid state
  1989. return;
  1990. }
  1991. IType targetType = null;
  1992. Expression target = null;
  1993. if (!mi.IsStatic)
  1994. {
  1995. target = GetTargetObject(node);
  1996. targetType = target.ExpressionType;
  1997. PushTargetObjectFor(mi, target, targetType);
  1998. }
  1999. PushArguments(method, node.Arguments);
  2000. // Emit a constrained call if target is a generic parameter
  2001. if (targetType != null && targetType is IGenericParameter)
  2002. _il.Emit(OpCodes.Constrained, GetSystemType(targetType));
  2003. _il.EmitCall(GetCallOpCode(target, method), mi, null);
  2004. PushType(method.ReturnType);
  2005. }
  2006. //returns true if no conditional attribute match the defined symbols
  2007. //else return false (which means the method won't get emitted)
  2008. private bool CheckConditionalAttributes(IMethod method)
  2009. {
  2010. foreach (string conditionalSymbol in GetConditionalSymbols(method))
  2011. if (!Parameters.Defines.ContainsKey(conditionalSymbol))
  2012. {
  2013. Context.TraceInfo("call to method '{0}' not emitted because the symbol '{1}' is not defined.", method, conditionalSymbol);
  2014. return false;
  2015. }
  2016. return true;
  2017. }
  2018. private IEnumerable<string> GetConditionalSymbols(IMethod method)
  2019. {
  2020. var mappedMethod = method as GenericMappedMethod;
  2021. if (mappedMethod != null)
  2022. return GetConditionalSymbols(mappedMethod.SourceMember);
  2023. var constructedMethod = method as GenericConstructedMethod;
  2024. if (constructedMethod != null)
  2025. return GetConditionalSymbols(constructedMethod.GenericDefinition);
  2026. var externalMethod = method as ExternalMethod;
  2027. if (externalMethod != null)
  2028. return GetConditionalSymbols(externalMethod);
  2029. var internalMethod = method as InternalMethod;
  2030. if (internalMethod != null)
  2031. return GetConditionalSymbols(internalMethod);
  2032. return NoSymbols;
  2033. }
  2034. private static readonly string[] NoSymbols = new string[0];
  2035. private IEnumerable<string> GetConditionalSymbols(ExternalMethod method)
  2036. {
  2037. foreach (ConditionalAttribute attr in method.MethodInfo.GetCustomAttributes(typeof(ConditionalAttribute), false))
  2038. yield return attr.ConditionString;
  2039. }
  2040. private IEnumerable<string> GetConditionalSymbols(InternalMethod method)
  2041. {
  2042. foreach (var attr in MetadataUtil.GetCustomAttributes(method.Method, TypeSystemServices.ConditionalAttribute))
  2043. {
  2044. if (1 != attr.Arguments.Count) continue;
  2045. var conditionString = attr.Arguments[0] as StringLiteralExpression;
  2046. if (conditionString == null) continue;
  2047. yield return conditionString.Value;
  2048. }
  2049. }
  2050. private void PushTargetObjectFor(MethodInfo methodToBeInvoked, Expression target, IType targetType)
  2051. {
  2052. if (targetType is IGenericParameter)
  2053. {
  2054. // If target is a generic parameter, its address must be loaded
  2055. // to allow a constrained method call
  2056. LoadAddress(target);
  2057. return;
  2058. }
  2059. if (targetType.IsValueType)
  2060. {
  2061. if (methodToBeInvoked.DeclaringType.IsValueType)
  2062. LoadAddress(target);
  2063. else
  2064. {
  2065. Visit(target);
  2066. EmitBox(PopType());
  2067. }
  2068. return;
  2069. }
  2070. // pushes target reference
  2071. Visit(target);
  2072. PopType();
  2073. }
  2074. private static Expression GetTargetObject(MethodInvocationExpression node)
  2075. {
  2076. var target = node.Target;
  2077. // Skip over generic reference expressions
  2078. var genericRef = target as GenericReferenceExpression;
  2079. if (genericRef != null)
  2080. target = genericRef.Target;
  2081. var memberRef = target as MemberReferenceExpression;
  2082. if (memberRef != null)
  2083. return memberRef.Target;
  2084. return null;
  2085. }
  2086. private OpCode GetCallOpCode(Expression target, IMethod method)
  2087. {
  2088. if (method.IsStatic) return OpCodes.Call;
  2089. if (NodeType.SuperLiteralExpression == target.NodeType) return OpCodes.Call;
  2090. if (IsValueTypeMethodCall(target, method)) return OpCodes.Call;
  2091. return OpCodes.Callvirt;
  2092. }
  2093. private bool IsValueTypeMethodCall(Expression target, IMethod method)
  2094. {
  2095. IType type = target.ExpressionType;
  2096. return type.IsValueType && method.DeclaringType == type;
  2097. }
  2098. void InvokeSuperMethod(IMethod method, MethodInvocationExpression node)
  2099. {
  2100. var super = (IMethod)GetEntity(node.Target);
  2101. var superMI = GetMethodInfo(super);
  2102. if (method.DeclaringType.IsValueType)
  2103. _il.Emit(OpCodes.Ldarga_S, 0);
  2104. else
  2105. _il.Emit(OpCodes.Ldarg_0); // this
  2106. PushArguments(super, node.Arguments);
  2107. Call(superMI);
  2108. PushType(super.ReturnType);
  2109. }
  2110. void EmitGetTypeFromHandle(Type type)
  2111. {
  2112. _il.Emit(OpCodes.Ldtoken, type);
  2113. Call(Type_GetTypeFromHandle);
  2114. PushType(TypeSystemServices.TypeType);
  2115. }
  2116. void OnEval(MethodInvocationExpression node)
  2117. {
  2118. int allButLast = node.Arguments.Count-1;
  2119. for (int i=0; i<allButLast; ++i)
  2120. {
  2121. Visit(node.Arguments[i]);
  2122. DiscardValueOnStack();
  2123. }
  2124. Visit(node.Arguments[-1]);
  2125. }
  2126. void OnAddressOf(MethodInvocationExpression node)
  2127. {
  2128. MemberReferenceExpression methodRef = (MemberReferenceExpression)node.Arguments[0];
  2129. MethodInfo method = GetMethodInfo((IMethod)GetEntity(methodRef));
  2130. if (method.IsVirtual)
  2131. {
  2132. Dup();
  2133. _il.Emit(OpCodes.Ldvirtftn, method);
  2134. }
  2135. else
  2136. {
  2137. _il.Emit(OpCodes.Ldftn, method);
  2138. }
  2139. PushType(TypeSystemServices.IntPtrType);
  2140. }
  2141. void OnBuiltinFunction(BuiltinFunction function, MethodInvocationExpression node)
  2142. {
  2143. switch (function.FunctionType)
  2144. {
  2145. case BuiltinFunctionType.Switch:
  2146. {
  2147. OnSwitch(node);
  2148. break;
  2149. }
  2150. case BuiltinFunctionType.AddressOf:
  2151. {
  2152. OnAddressOf(node);
  2153. break;
  2154. }
  2155. case BuiltinFunctionType.Eval:
  2156. {
  2157. OnEval(node);
  2158. break;
  2159. }
  2160. case BuiltinFunctionType.InitValueType:
  2161. {
  2162. OnInitValueType(node);
  2163. break;
  2164. }
  2165. default:
  2166. {
  2167. NotImplemented(node, "BuiltinFunction: " + function.FunctionType);
  2168. break;
  2169. }
  2170. }
  2171. }
  2172. private void OnInitValueType(MethodInvocationExpression node)
  2173. {
  2174. Debug.Assert(1 == node.Arguments.Count);
  2175. Expression argument = node.Arguments[0];
  2176. LoadAddressForInitObj(argument);
  2177. var expressionType = GetExpressionType(argument);
  2178. System.Type type = GetSystemType(expressionType);
  2179. Debug.Assert(type.IsValueType || (type.IsGenericParameter && expressionType.IsValueType));
  2180. _il.Emit(OpCodes.Initobj, type);
  2181. PushVoid();
  2182. }
  2183. private void LoadAddressForInitObj(Expression argument)
  2184. {
  2185. IEntity entity = argument.Entity;
  2186. switch (entity.EntityType)
  2187. {
  2188. case EntityType.Local:
  2189. {
  2190. InternalLocal local = (InternalLocal)entity;
  2191. LocalBuilder builder = local.LocalBuilder;
  2192. _il.Emit(OpCodes.Ldloca, builder);
  2193. break;
  2194. }
  2195. case EntityType.Field:
  2196. {
  2197. EmitLoadFieldAddress(argument, (IField)entity);
  2198. break;
  2199. }
  2200. default:
  2201. NotImplemented(argument, "__initobj__");
  2202. break;
  2203. }
  2204. }
  2205. override public void OnMethodInvocationExpression(MethodInvocationExpression node)
  2206. {
  2207. IEntity entity = TypeSystemServices.GetEntity(node.Target);
  2208. switch (entity.EntityType)
  2209. {
  2210. case EntityType.BuiltinFunction:
  2211. {
  2212. OnBuiltinFunction((BuiltinFunction)entity, node);
  2213. break;
  2214. }
  2215. case EntityType.Method:
  2216. {
  2217. var methodInfo = (IMethod)entity;
  2218. if (node.Target.NodeType == NodeType.SuperLiteralExpression)
  2219. InvokeSuperMethod(methodInfo, node);
  2220. else
  2221. InvokeMethod(methodInfo, node);
  2222. break;
  2223. }
  2224. case EntityType.Constructor:
  2225. {
  2226. IConstructor constructorInfo = (IConstructor)entity;
  2227. ConstructorInfo ci = GetConstructorInfo(constructorInfo);
  2228. if (NodeType.SuperLiteralExpression == node.Target.NodeType || node.Target.NodeType == NodeType.SelfLiteralExpression)
  2229. {
  2230. // super constructor call
  2231. _il.Emit(OpCodes.Ldarg_0);
  2232. PushArguments(constructorInfo, node.Arguments);
  2233. _il.Emit(OpCodes.Call, ci);
  2234. PushVoid();
  2235. }
  2236. else
  2237. {
  2238. PushArguments(constructorInfo, node.Arguments);
  2239. _il.Emit(OpCodes.Newobj, ci);
  2240. // constructor invocation resulting type is
  2241. PushType(constructorInfo.DeclaringType);
  2242. }
  2243. break;
  2244. }
  2245. default:
  2246. {
  2247. NotImplemented(node, entity.ToString());
  2248. break;
  2249. }
  2250. }
  2251. }
  2252. override public void OnTimeSpanLiteralExpression(TimeSpanLiteralExpression node)
  2253. {
  2254. EmitLoadLiteral(node.Value.Ticks);
  2255. _il.Emit(OpCodes.Newobj, TimeSpan_LongConstructor);
  2256. PushType(TypeSystemServices.TimeSpanType);
  2257. }
  2258. override public void OnIntegerLiteralExpression(IntegerLiteralExpression node)
  2259. {
  2260. IType type = node.ExpressionType ?? TypeSystemServices.IntType;
  2261. EmitLoadLiteral(type, node.Value);
  2262. PushType(type);
  2263. }
  2264. override public void OnDoubleLiteralExpression(DoubleLiteralExpression node)
  2265. {
  2266. IType type = node.ExpressionType ?? TypeSystemServices.DoubleType;
  2267. EmitLoadLiteral(type, node.Value);
  2268. PushType(type);
  2269. }
  2270. void EmitLoadLiteral(int i)
  2271. {
  2272. EmitLoadLiteral(TypeSystemServices.IntType, i);
  2273. }
  2274. void EmitLoadLiteral(long l)
  2275. {
  2276. EmitLoadLiteral(TypeSystemServices.LongType, l);
  2277. }
  2278. void EmitLoadLiteral(IType type, double d)
  2279. {
  2280. if (type == TypeSystemServices.SingleType)
  2281. {
  2282. if (d != 0)
  2283. _il.Emit(OpCodes.Ldc_R4, (float) d);
  2284. else
  2285. {
  2286. _il.Emit(OpCodes.Ldc_I4_0);
  2287. _il.Emit(OpCodes.Conv_R4);
  2288. }
  2289. return;
  2290. }
  2291. if (type == TypeSystemServices.DoubleType)
  2292. {
  2293. if (d != 0)
  2294. _il.Emit(OpCodes.Ldc_R8, d);
  2295. else
  2296. {
  2297. _il.Emit(OpCodes.Ldc_I4_0);
  2298. _il.Emit(OpCodes.Conv_R8);
  2299. }
  2300. return;
  2301. }
  2302. throw new InvalidOperationException(string.Format("`{0}' is not a literal", type));
  2303. }
  2304. void EmitLoadLiteral(IType type, long l)
  2305. {
  2306. if (type.IsEnum)
  2307. type = TypeSystemServices.Map(GetEnumUnderlyingType(type));
  2308. if (!(IsInteger(type) || type == TypeSystemServices.CharType))
  2309. throw new InvalidOperationException();
  2310. var needsLongConv = true;
  2311. switch (l)
  2312. {
  2313. case -1L:
  2314. {
  2315. if (IsLong(type) || type == TypeSystemServices.ULongType)
  2316. {
  2317. _il.Emit(OpCodes.Ldc_I8, -1L);
  2318. needsLongConv = false;
  2319. }
  2320. else
  2321. _il.Emit(OpCodes.Ldc_I4_M1);
  2322. }
  2323. break;
  2324. case 0L:
  2325. _il.Emit(OpCodes.Ldc_I4_0);
  2326. break;
  2327. case 1L:
  2328. _il.Emit(OpCodes.Ldc_I4_1);
  2329. break;
  2330. case 2L:
  2331. _il.Emit(OpCodes.Ldc_I4_2);
  2332. break;
  2333. case 3L:
  2334. _il.Emit(OpCodes.Ldc_I4_3);
  2335. break;
  2336. case 4L:
  2337. _il.Emit(OpCodes.Ldc_I4_4);
  2338. break;
  2339. case 5L:
  2340. _il.Emit(OpCodes.Ldc_I4_5);
  2341. break;
  2342. case 6L:
  2343. _il.Emit(OpCodes.Ldc_I4_6);
  2344. break;
  2345. case 7L:
  2346. _il.Emit(OpCodes.Ldc_I4_7);
  2347. break;
  2348. case 8L:
  2349. _il.Emit(OpCodes.Ldc_I4_8);
  2350. break;
  2351. default:
  2352. {
  2353. if (IsLong(type))
  2354. {
  2355. _il.Emit(OpCodes.Ldc_I8, l);
  2356. return;
  2357. }
  2358. if (l == (sbyte) l) //fits in an signed i1
  2359. {
  2360. _il.Emit(OpCodes.Ldc_I4_S, (sbyte) l);
  2361. }
  2362. else if (l == (int) l || l == (uint) l) //fits in an i4
  2363. {
  2364. if ((int) l == -1)
  2365. _il.Emit(OpCodes.Ldc_I4_M1);
  2366. else
  2367. _il.Emit(OpCodes.Ldc_I4, (int) l);
  2368. }
  2369. else
  2370. {
  2371. _il.Emit(OpCodes.Ldc_I8, l);
  2372. needsLongConv = false;
  2373. }
  2374. }
  2375. break;
  2376. }
  2377. if (needsLongConv && IsLong(type))
  2378. _il.Emit(OpCodes.Conv_I8);
  2379. else if (type == TypeSystemServices.ULongType)
  2380. _il.Emit(OpCodes.Conv_U8);
  2381. }
  2382. private bool IsLong(IType type)
  2383. {
  2384. return type == TypeSystemServices.LongType;
  2385. }
  2386. override public void OnBoolLiteralExpression(BoolLiteralExpression node)
  2387. {
  2388. if (node.Value)
  2389. {
  2390. _il.Emit(OpCodes.Ldc_I4_1);
  2391. }
  2392. else
  2393. {
  2394. _il.Emit(OpCodes.Ldc_I4_0);
  2395. }
  2396. PushBool();
  2397. }
  2398. override public void OnHashLiteralExpression(HashLiteralExpression node)
  2399. {
  2400. _il.Emit(OpCodes.Newobj, Hash_Constructor);
  2401. var objType = TypeSystemServices.ObjectType;
  2402. foreach (ExpressionPair pair in node.Items)
  2403. {
  2404. Dup();
  2405. LoadExpressionWithType(objType, pair.First);
  2406. LoadExpressionWithType(objType, pair.Second);
  2407. _il.EmitCall(OpCodes.Callvirt, Hash_Add, null);
  2408. }
  2409. PushType(TypeSystemServices.HashType);
  2410. }
  2411. override public void OnGeneratorExpression(GeneratorExpression node)
  2412. {
  2413. NotImplemented(node, node.ToString());
  2414. }
  2415. override public void OnListLiteralExpression(ListLiteralExpression node)
  2416. {
  2417. if (node.Items.Count > 0)
  2418. {
  2419. EmitObjectArray(node.Items);
  2420. _il.Emit(OpCodes.Ldc_I4_1);
  2421. _il.Emit(OpCodes.Newobj, List_ArrayBoolConstructor);
  2422. }
  2423. else
  2424. {
  2425. _il.Emit(OpCodes.Newobj, List_EmptyConstructor);
  2426. }
  2427. PushType(TypeSystemServices.ListType);
  2428. }
  2429. override public void OnArrayLiteralExpression(ArrayLiteralExpression node)
  2430. {
  2431. var type = (IArrayType)node.ExpressionType;
  2432. EmitArray(type.ElementType, node.Items);
  2433. PushType(type);
  2434. }
  2435. override public void OnRELiteralExpression(RELiteralExpression node)
  2436. {
  2437. RegexOptions options = AstUtil.GetRegexOptions(node);
  2438. _il.Emit(OpCodes.Ldstr, node.Pattern);
  2439. if (options == RegexOptions.None)
  2440. {
  2441. _il.Emit(OpCodes.Newobj, Regex_Constructor);
  2442. }
  2443. else
  2444. {
  2445. EmitLoadLiteral((int) options);
  2446. _il.Emit(OpCodes.Newobj, Regex_Constructor_Options);
  2447. }
  2448. PushType(node.ExpressionType);
  2449. }
  2450. override public void OnStringLiteralExpression(StringLiteralExpression node)
  2451. {
  2452. if (null == node.Value)
  2453. {
  2454. _il.Emit(OpCodes.Ldnull);
  2455. }
  2456. else if (0 != node.Value.Length)
  2457. {
  2458. _il.Emit(OpCodes.Ldstr, node.Value);
  2459. }
  2460. else /* force use of CLR-friendly string.Empty */
  2461. {
  2462. _il.Emit(OpCodes.Ldsfld, typeof(string).GetField("Empty"));
  2463. }
  2464. PushType(TypeSystemServices.StringType);
  2465. }
  2466. override public void OnCharLiteralExpression(CharLiteralExpression node)
  2467. {
  2468. EmitLoadLiteral(node.Value[0]);
  2469. PushType(TypeSystemServices.CharType);
  2470. }
  2471. override public void OnSlicingExpression(SlicingExpression node)
  2472. {
  2473. if (node.IsTargetOfAssignment())
  2474. return;
  2475. Visit(node.Target);
  2476. var type = (IArrayType)PopType();
  2477. if (type.Rank == 1)
  2478. LoadSingleDimensionalArrayElement(node, type);
  2479. else
  2480. LoadMultiDimensionalArrayElement(node, type);
  2481. PushType(type.ElementType);
  2482. }
  2483. private void LoadMultiDimensionalArrayElement(SlicingExpression node, IArrayType arrayType)
  2484. {
  2485. LoadArrayIndices(node);
  2486. CallArrayMethod(arrayType, "Get", GetSystemType(arrayType.ElementType), ParameterTypesForArrayGet(arrayType));
  2487. }
  2488. private static Type[] ParameterTypesForArrayGet(IArrayType arrayType)
  2489. {
  2490. return Enumerable.Range(0, arrayType.Rank).Select(_ => typeof(int)).ToArray();
  2491. }
  2492. private Type[] ParameterTypesForArraySet(IArrayType arrayType)
  2493. {
  2494. var types = new Type[arrayType.Rank + 1];
  2495. for (var i = 0; i < arrayType.Rank; ++i)
  2496. types[i] = typeof(int);
  2497. types[arrayType.Rank] = GetSystemType(arrayType.ElementType);
  2498. return types;
  2499. }
  2500. private void CallArrayMethod(IType arrayType, string methodName, Type returnType, Type[] parameterTypes)
  2501. {
  2502. var method = _moduleBuilder.GetArrayMethod(
  2503. GetSystemType(arrayType), methodName, CallingConventions.HasThis,returnType, parameterTypes);
  2504. Call(method);
  2505. //Call(GetSystemType(arrayType).GetMethod(methodName));
  2506. }
  2507. private void LoadArrayIndices(SlicingExpression node)
  2508. {
  2509. foreach (var index in node.Indices.Select(index => index.Begin))
  2510. LoadIntExpression(index);
  2511. }
  2512. private void LoadSingleDimensionalArrayElement(SlicingExpression node, IType arrayType)
  2513. {
  2514. EmitNormalizedArrayIndex(node, node.Indices[0].Begin);
  2515. var elementType = arrayType.ElementType;
  2516. var opcode = GetLoadEntityOpCode(elementType);
  2517. if (OpCodes.Ldelema.Value == opcode.Value)
  2518. {
  2519. var systemType = GetSystemType(elementType);
  2520. _il.Emit(opcode, systemType);
  2521. if (!IsByAddress(elementType))
  2522. _il.Emit(OpCodes.Ldobj, systemType);
  2523. }
  2524. else if (OpCodes.Ldelem.Value == opcode.Value)
  2525. _il.Emit(opcode, GetSystemType(elementType));
  2526. else
  2527. _il.Emit(opcode);
  2528. }
  2529. void EmitNormalizedArrayIndex(SlicingExpression sourceNode, Expression index)
  2530. {
  2531. bool isNegative = false;
  2532. if (CanBeNegative(index, ref isNegative)
  2533. && !_rawArrayIndexing
  2534. && !AstAnnotations.IsRawIndexing(sourceNode))
  2535. {
  2536. if (isNegative)
  2537. {
  2538. Dup();
  2539. _il.Emit(OpCodes.Ldlen);
  2540. LoadIntExpression(index);
  2541. _il.Emit(OpCodes.Add);
  2542. }
  2543. else
  2544. {
  2545. Dup();
  2546. LoadIntExpression(index);
  2547. Call(RuntimeServices_NormalizeArrayIndex);
  2548. }
  2549. }
  2550. else
  2551. LoadIntExpression(index);
  2552. }
  2553. bool CanBeNegative(Expression expression, ref bool isNegative)
  2554. {
  2555. var integer = expression as IntegerLiteralExpression;
  2556. if (integer != null)
  2557. {
  2558. if (integer.Value >= 0)
  2559. return false;
  2560. isNegative = true;
  2561. }
  2562. return true;
  2563. }
  2564. void LoadIntExpression(Expression expression)
  2565. {
  2566. LoadExpressionWithType(TypeSystemServices.IntType, expression);
  2567. }
  2568. override public void OnExpressionInterpolationExpression(ExpressionInterpolationExpression node)
  2569. {
  2570. Type stringBuilderType = typeof(StringBuilder);
  2571. ConstructorInfo constructor = stringBuilderType.GetConstructor(Type.EmptyTypes);
  2572. ConstructorInfo constructorString = stringBuilderType.GetConstructor(new Type[] { typeof(string) });
  2573. MethodInfo appendObject = Methods.InstanceFunctionOf<StringBuilder, object, StringBuilder>(sb => sb.Append);
  2574. MethodInfo appendString = Methods.InstanceFunctionOf<StringBuilder, string, StringBuilder>(sb => sb.Append);
  2575. Expression arg0 = node.Expressions[0];
  2576. IType argType = arg0.ExpressionType;
  2577. /* if arg0 is a string, let's call StringBuilder constructor
  2578. * directly with the string */
  2579. if ( ( typeof(StringLiteralExpression) == arg0.GetType()
  2580. && ((StringLiteralExpression) arg0).Value.Length > 0 )
  2581. || ( typeof(StringLiteralExpression) != arg0.GetType()
  2582. && TypeSystemServices.StringType == argType ) )
  2583. {
  2584. Visit(arg0);
  2585. PopType();
  2586. _il.Emit(OpCodes.Newobj, constructorString);
  2587. }
  2588. else
  2589. {
  2590. _il.Emit(OpCodes.Newobj, constructor);
  2591. arg0 = null; /* arg0 is not a string so we want it to be appended below */
  2592. }
  2593. string formatString;
  2594. foreach (Expression arg in node.Expressions)
  2595. {
  2596. /* we do not need to append literal string.Empty
  2597. * or arg0 if it has been handled by ctor */
  2598. if ( ( typeof(StringLiteralExpression) == arg.GetType()
  2599. && ((StringLiteralExpression) arg).Value.Length == 0 )
  2600. || arg == arg0 )
  2601. {
  2602. continue;
  2603. }
  2604. formatString = arg["formatString"] as string; //annotation
  2605. if (!string.IsNullOrEmpty(formatString))
  2606. _il.Emit(OpCodes.Ldstr, string.Format("{{0:{0}}}", formatString));
  2607. Visit(arg);
  2608. argType = PopType();
  2609. if (!string.IsNullOrEmpty(formatString))
  2610. {
  2611. EmitCastIfNeeded(TypeSystemServices.ObjectType, argType);
  2612. Call(StringFormat);
  2613. }
  2614. if (TypeSystemServices.StringType == argType || !string.IsNullOrEmpty(formatString))
  2615. {
  2616. Call(appendString);
  2617. }
  2618. else
  2619. {
  2620. EmitCastIfNeeded(TypeSystemServices.ObjectType, argType);
  2621. Call(appendObject);
  2622. }
  2623. }
  2624. Call(stringBuilderType.GetMethod("ToString", Type.EmptyTypes));
  2625. PushType(TypeSystemServices.StringType);
  2626. }
  2627. void LoadMemberTarget(Expression self, IMember member)
  2628. {
  2629. if (member.DeclaringType.IsValueType)
  2630. {
  2631. LoadAddress(self);
  2632. }
  2633. else
  2634. {
  2635. Visit(self);
  2636. PopType();
  2637. }
  2638. }
  2639. void EmitLoadFieldAddress(Expression expression, IField field)
  2640. {
  2641. if (field.IsStatic)
  2642. {
  2643. _il.Emit(OpCodes.Ldsflda, GetFieldInfo(field));
  2644. }
  2645. else
  2646. {
  2647. LoadMemberTarget(((MemberReferenceExpression)expression).Target, field);
  2648. _il.Emit(OpCodes.Ldflda, GetFieldInfo(field));
  2649. }
  2650. }
  2651. void EmitLoadField(Expression self, IField fieldInfo)
  2652. {
  2653. if (fieldInfo.IsStatic)
  2654. {
  2655. if (fieldInfo.IsLiteral)
  2656. {
  2657. EmitLoadLiteralField(self, fieldInfo);
  2658. }
  2659. else
  2660. {
  2661. if (fieldInfo.IsVolatile)
  2662. _il.Emit(OpCodes.Volatile);
  2663. _il.Emit(IsByAddress(fieldInfo.Type) ? OpCodes.Ldsflda : OpCodes.Ldsfld,
  2664. GetFieldInfo(fieldInfo));
  2665. }
  2666. }
  2667. else
  2668. {
  2669. LoadMemberTarget(self, fieldInfo);
  2670. if (fieldInfo.IsVolatile)
  2671. _il.Emit(OpCodes.Volatile);
  2672. _il.Emit(IsByAddress(fieldInfo.Type) ? OpCodes.Ldflda : OpCodes.Ldfld,
  2673. GetFieldInfo(fieldInfo));
  2674. }
  2675. PushType(fieldInfo.Type);
  2676. }
  2677. object GetStaticValue(IField field)
  2678. {
  2679. InternalField internalField = field as InternalField;
  2680. if (null != internalField)
  2681. {
  2682. return GetInternalFieldStaticValue(internalField);
  2683. }
  2684. return field.StaticValue;
  2685. }
  2686. object GetInternalFieldStaticValue(InternalField field)
  2687. {
  2688. return GetValue(field.Type, (Expression)field.StaticValue);
  2689. }
  2690. void EmitLoadLiteralField(Node node, IField fieldInfo)
  2691. {
  2692. object value = GetStaticValue(fieldInfo);
  2693. IType type = fieldInfo.Type;
  2694. if (type.IsEnum){
  2695. Type underlyingType = GetEnumUnderlyingType(type);
  2696. type = TypeSystemServices.Map(underlyingType);
  2697. value = Convert.ChangeType(value, underlyingType);
  2698. }
  2699. if (null == value)
  2700. {
  2701. _il.Emit(OpCodes.Ldnull);
  2702. }
  2703. else if (type == TypeSystemServices.BoolType)
  2704. {
  2705. _il.Emit(((bool) value) ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
  2706. }
  2707. else if (type == TypeSystemServices.StringType)
  2708. {
  2709. _il.Emit(OpCodes.Ldstr, (string) value);
  2710. }
  2711. else if (type == TypeSystemServices.CharType)
  2712. {
  2713. EmitLoadLiteral(type, (long)(char) value);
  2714. }
  2715. else if (type == TypeSystemServices.IntType)
  2716. {
  2717. EmitLoadLiteral(type, (long)(int) value);
  2718. }
  2719. else if (type == TypeSystemServices.UIntType)
  2720. {
  2721. EmitLoadLiteral(type, unchecked((long)(uint) value));
  2722. }
  2723. else if (IsLong(type))
  2724. {
  2725. EmitLoadLiteral(type, (long) value);
  2726. }
  2727. else if (type == TypeSystemServices.ULongType)
  2728. {
  2729. EmitLoadLiteral(type, unchecked((long)(ulong) value));
  2730. }
  2731. else if (type == TypeSystemServices.SingleType)
  2732. {
  2733. EmitLoadLiteral(type, (double)(float) value);
  2734. }
  2735. else if (type == TypeSystemServices.DoubleType)
  2736. {
  2737. EmitLoadLiteral(type, (double) value);
  2738. }
  2739. else if (type == TypeSystemServices.SByteType)
  2740. {
  2741. EmitLoadLiteral(type, (long)(sbyte) value);
  2742. }
  2743. else if (type == TypeSystemServices.ByteType)
  2744. {
  2745. EmitLoadLiteral(type, (long)(byte) value);
  2746. }
  2747. else if (type == TypeSystemServices.ShortType)
  2748. {
  2749. EmitLoadLiteral(type, (long)(short) value);
  2750. }
  2751. else if (type == TypeSystemServices.UShortType)
  2752. {
  2753. EmitLoadLiteral(type, (long)(ushort) value);
  2754. }
  2755. else
  2756. {
  2757. NotImplemented(node, "Literal field type: " + type.ToString());
  2758. }
  2759. }
  2760. override public void OnGenericReferenceExpression(GenericReferenceExpression node)
  2761. {
  2762. IEntity entity = TypeSystem.TypeSystemServices.GetEntity(node);
  2763. switch (entity.EntityType)
  2764. {
  2765. case EntityType.Type:
  2766. {
  2767. EmitGetTypeFromHandle(GetSystemType(node));
  2768. break;
  2769. }
  2770. case EntityType.Method:
  2771. {
  2772. node.Target.Accept(this);
  2773. break;
  2774. }
  2775. default:
  2776. {
  2777. NotImplemented(node, entity.ToString());
  2778. break;
  2779. }
  2780. }
  2781. }
  2782. override public void OnMemberReferenceExpression(MemberReferenceExpression node)
  2783. {
  2784. var tag = TypeSystemServices.GetEntity(node);
  2785. switch (tag.EntityType)
  2786. {
  2787. case EntityType.Ambiguous:
  2788. case EntityType.Method:
  2789. {
  2790. node.Target.Accept(this);
  2791. break;
  2792. }
  2793. case EntityType.Field:
  2794. {
  2795. EmitLoadField(node.Target, (IField)tag);
  2796. break;
  2797. }
  2798. case EntityType.Type:
  2799. {
  2800. EmitGetTypeFromHandle(GetSystemType(node));
  2801. break;
  2802. }
  2803. default:
  2804. {
  2805. NotImplemented(node, tag.ToString());
  2806. break;
  2807. }
  2808. }
  2809. }
  2810. void LoadAddress(Expression expression)
  2811. {
  2812. if (expression.NodeType == NodeType.SelfLiteralExpression && expression.ExpressionType.IsValueType)
  2813. {
  2814. _il.Emit(OpCodes.Ldarg_0);
  2815. return;
  2816. }
  2817. var entity = expression.Entity;
  2818. if (entity != null)
  2819. {
  2820. switch (entity.EntityType)
  2821. {
  2822. case EntityType.Local:
  2823. {
  2824. var local = ((InternalLocal) entity);
  2825. _il.Emit(!local.Type.IsPointer ? OpCodes.Ldloca : OpCodes.Ldloc, local.LocalBuilder);
  2826. return;
  2827. }
  2828. case EntityType.Parameter:
  2829. {
  2830. var param = (InternalParameter)entity;
  2831. if (param.Parameter.IsByRef)
  2832. LoadParam(param);
  2833. else
  2834. _il.Emit(OpCodes.Ldarga, param.Index);
  2835. return;
  2836. }
  2837. case EntityType.Field:
  2838. {
  2839. var field = (IField)entity;
  2840. if (!field.IsLiteral)
  2841. {
  2842. EmitLoadFieldAddress(expression, field);
  2843. return;
  2844. }
  2845. break;
  2846. }
  2847. }
  2848. }
  2849. if (IsValueTypeArraySlicing(expression))
  2850. {
  2851. LoadArrayElementAddress((SlicingExpression)expression);
  2852. return;
  2853. }
  2854. Visit(expression);
  2855. if (!AstUtil.IsIndirection(expression))
  2856. {
  2857. // declare local to hold value type
  2858. var temp = _il.DeclareLocal(GetSystemType(PopType()));
  2859. _il.Emit(OpCodes.Stloc, temp);
  2860. _il.Emit(OpCodes.Ldloca, temp);
  2861. }
  2862. }
  2863. private void LoadArrayElementAddress(SlicingExpression slicing)
  2864. {
  2865. Visit(slicing.Target);
  2866. var arrayType = (IArrayType)PopType();
  2867. if (arrayType.Rank == 1)
  2868. LoadSingleDimensionalArrayElementAddress(slicing, arrayType);
  2869. else
  2870. LoadMultiDimensionalArrayElementAddress(slicing, arrayType);
  2871. }
  2872. private void LoadMultiDimensionalArrayElementAddress(SlicingExpression slicing, IArrayType arrayType)
  2873. {
  2874. LoadArrayIndices(slicing);
  2875. CallArrayMethod(arrayType, "Address", GetSystemType(arrayType.ElementType).MakeByRefType(), ParameterTypesForArrayGet(arrayType));
  2876. }
  2877. private void LoadSingleDimensionalArrayElementAddress(SlicingExpression slicing, IArrayType arrayType)
  2878. {
  2879. EmitNormalizedArrayIndex(slicing, slicing.Indices[0].Begin);
  2880. _il.Emit(OpCodes.Ldelema, GetSystemType(arrayType.ElementType));
  2881. }
  2882. bool IsValueTypeArraySlicing(Expression expression)
  2883. {
  2884. var slicing = expression as SlicingExpression;
  2885. if (slicing != null)
  2886. {
  2887. var type = (IArrayType)slicing.Target.ExpressionType;
  2888. return type.ElementType.IsValueType;
  2889. }
  2890. return false;
  2891. }
  2892. override public void OnSelfLiteralExpression(SelfLiteralExpression node)
  2893. {
  2894. LoadSelf(node);
  2895. }
  2896. override public void OnSuperLiteralExpression(SuperLiteralExpression node)
  2897. {
  2898. LoadSelf(node);
  2899. }
  2900. private void LoadSelf(Expression node)
  2901. {
  2902. _il.Emit(OpCodes.Ldarg_0);
  2903. if (node.ExpressionType.IsValueType)
  2904. _il.Emit(OpCodes.Ldobj, GetSystemType(node.ExpressionType));
  2905. PushType(node.ExpressionType);
  2906. }
  2907. override public void OnNullLiteralExpression(NullLiteralExpression node)
  2908. {
  2909. _il.Emit(OpCodes.Ldnull);
  2910. PushType(null);
  2911. }
  2912. override public void OnReferenceExpression(ReferenceExpression node)
  2913. {
  2914. var entity = TypeSystemServices.GetEntity(node);
  2915. switch (entity.EntityType)
  2916. {
  2917. case EntityType.Local:
  2918. {
  2919. if (!AstUtil.IsIndirection(node.ParentNode))
  2920. LoadLocal((InternalLocal)entity);
  2921. else
  2922. LoadIndirectLocal((InternalLocal)entity);
  2923. break;
  2924. }
  2925. case EntityType.Parameter:
  2926. {
  2927. var param = (InternalParameter)entity;
  2928. LoadParam(param);
  2929. if (param.Parameter.IsByRef)
  2930. {
  2931. var code = GetLoadRefParamCode(param.Type);
  2932. if (code.Value == OpCodes.Ldobj.Value)
  2933. _il.Emit(code, GetSystemType(param.Type));
  2934. else
  2935. _il.Emit(code);
  2936. }
  2937. PushType(param.Type);
  2938. break;
  2939. }
  2940. case EntityType.Array:
  2941. case EntityType.Type:
  2942. {
  2943. EmitGetTypeFromHandle(GetSystemType(node));
  2944. break;
  2945. }
  2946. default:
  2947. {
  2948. NotImplemented(node, entity.ToString());
  2949. break;
  2950. }
  2951. }
  2952. }
  2953. void LoadParam(InternalParameter param)
  2954. {
  2955. int index = param.Index;
  2956. switch (index)
  2957. {
  2958. case 0:
  2959. {
  2960. _il.Emit(OpCodes.Ldarg_0);
  2961. break;
  2962. }
  2963. case 1:
  2964. {
  2965. _il.Emit(OpCodes.Ldarg_1);
  2966. break;
  2967. }
  2968. case 2:
  2969. {
  2970. _il.Emit(OpCodes.Ldarg_2);
  2971. break;
  2972. }
  2973. case 3:
  2974. {
  2975. _il.Emit(OpCodes.Ldarg_3);
  2976. break;
  2977. }
  2978. default:
  2979. {
  2980. if (index < 256)
  2981. {
  2982. _il.Emit(OpCodes.Ldarg_S, index);
  2983. }
  2984. else
  2985. {
  2986. _il.Emit(OpCodes.Ldarg, index);
  2987. }
  2988. break;
  2989. }
  2990. }
  2991. }
  2992. void SetLocal(BinaryExpression node, InternalLocal tag, bool leaveValueOnStack)
  2993. {
  2994. if (AstUtil.IsIndirection(node.Left))
  2995. _il.Emit(OpCodes.Ldloc, tag.LocalBuilder);
  2996. node.Right.Accept(this); // leaves type on stack
  2997. IType typeOnStack = null;
  2998. if (leaveValueOnStack)
  2999. {
  3000. typeOnStack = PeekTypeOnStack();
  3001. Dup();
  3002. }
  3003. else
  3004. {
  3005. typeOnStack = PopType();
  3006. }
  3007. if (!AstUtil.IsIndirection(node.Left))
  3008. EmitAssignment(tag, typeOnStack);
  3009. else
  3010. EmitIndirectAssignment(tag, typeOnStack);
  3011. }
  3012. void EmitAssignment(InternalLocal tag, IType typeOnStack)
  3013. {
  3014. // todo: assignment result must be type on the left in the
  3015. // case of casting
  3016. LocalBuilder local = tag.LocalBuilder;
  3017. EmitCastIfNeeded(tag.Type, typeOnStack);
  3018. _il.Emit(OpCodes.Stloc, local);
  3019. }
  3020. void EmitIndirectAssignment(InternalLocal local, IType typeOnStack)
  3021. {
  3022. var elementType = local.Type.ElementType;
  3023. EmitCastIfNeeded(elementType, typeOnStack);
  3024. var code = GetStoreRefParamCode(elementType);
  3025. if (code == OpCodes.Stobj)
  3026. _il.Emit(code, GetSystemType(elementType));
  3027. else
  3028. _il.Emit(code);
  3029. }
  3030. void SetField(Node sourceNode, IField field, Expression reference, Expression value, bool leaveValueOnStack)
  3031. {
  3032. OpCode opSetField = OpCodes.Stsfld;
  3033. if (!field.IsStatic)
  3034. {
  3035. opSetField = OpCodes.Stfld;
  3036. if (null != reference)
  3037. {
  3038. LoadMemberTarget(
  3039. ((MemberReferenceExpression)reference).Target,
  3040. field);
  3041. }
  3042. }
  3043. LoadExpressionWithType(field.Type, value);
  3044. LocalBuilder local = null;
  3045. if (leaveValueOnStack)
  3046. {
  3047. Dup();
  3048. local = _il.DeclareLocal(GetSystemType(field.Type));
  3049. _il.Emit(OpCodes.Stloc, local);
  3050. }
  3051. if (field.IsVolatile)
  3052. _il.Emit(OpCodes.Volatile);
  3053. _il.Emit(opSetField, GetFieldInfo(field));
  3054. if (leaveValueOnStack)
  3055. {
  3056. _il.Emit(OpCodes.Ldloc, local);
  3057. PushType(field.Type);
  3058. }
  3059. }
  3060. void SetProperty(IProperty property, Expression reference, Expression value, bool leaveValueOnStack)
  3061. {
  3062. OpCode callOpCode = OpCodes.Call;
  3063. MethodInfo setMethod = GetMethodInfo(property.GetSetMethod());
  3064. IType targetType = null;
  3065. if (null != reference)
  3066. {
  3067. if (!setMethod.IsStatic)
  3068. {
  3069. Expression target = ((MemberReferenceExpression)reference).Target;
  3070. targetType = target.ExpressionType;
  3071. if (setMethod.DeclaringType.IsValueType || targetType is IGenericParameter)
  3072. LoadAddress(target);
  3073. else
  3074. {
  3075. callOpCode = GetCallOpCode(target, property.GetSetMethod());
  3076. target.Accept(this);
  3077. PopType();
  3078. }
  3079. }
  3080. }
  3081. LoadExpressionWithType(property.Type, value);
  3082. LocalBuilder local = null;
  3083. if (leaveValueOnStack)
  3084. {
  3085. Dup();
  3086. local = _il.DeclareLocal(GetSystemType(property.Type));
  3087. _il.Emit(OpCodes.Stloc, local);
  3088. }
  3089. if (targetType is IGenericParameter)
  3090. {
  3091. _il.Emit(OpCodes.Constrained, GetSystemType(targetType));
  3092. callOpCode = OpCodes.Callvirt;
  3093. }
  3094. _il.EmitCall(callOpCode, setMethod, null);
  3095. if (leaveValueOnStack)
  3096. {
  3097. _il.Emit(OpCodes.Ldloc, local);
  3098. PushType(property.Type);
  3099. }
  3100. }
  3101. bool EmitDebugInfo(Node node)
  3102. {
  3103. if (!Parameters.Debug)
  3104. return false;
  3105. return EmitDebugInfo(node, node);
  3106. }
  3107. private const int _DBG_SYMBOLS_QUEUE_CAPACITY = 5;
  3108. private System.Collections.Generic.Queue<LexicalInfo> _dbgSymbols = new System.Collections.Generic.Queue<LexicalInfo>(_DBG_SYMBOLS_QUEUE_CAPACITY);
  3109. bool EmitDebugInfo(Node startNode, Node endNode)
  3110. {
  3111. LexicalInfo start = startNode.LexicalInfo;
  3112. if (!start.IsValid) return false;
  3113. ISymbolDocumentWriter writer = GetDocumentWriter(start.FullPath);
  3114. if (null == writer) return false;
  3115. // ensure there is no duplicate emitted
  3116. if (_dbgSymbols.Contains(start)) {
  3117. Context.TraceInfo("duplicate symbol emit attempt for '{0}' : '{1}'.", start, startNode);
  3118. return false;
  3119. }
  3120. if (_dbgSymbols.Count >= _DBG_SYMBOLS_QUEUE_CAPACITY) _dbgSymbols.Dequeue();
  3121. _dbgSymbols.Enqueue(start);
  3122. try
  3123. {
  3124. _il.MarkSequencePoint(writer, start.Line, 0, start.Line+1, 0);
  3125. }
  3126. catch (Exception x)
  3127. {
  3128. Error(CompilerErrorFactory.InternalError(startNode, x));
  3129. return false;
  3130. }
  3131. return true;
  3132. }
  3133. private void EmitNop()
  3134. {
  3135. _il.Emit(OpCodes.Nop);
  3136. }
  3137. private ISymbolDocumentWriter GetDocumentWriter(string fname)
  3138. {
  3139. ISymbolDocumentWriter writer = GetCachedDocumentWriter(fname);
  3140. if (null != writer) return writer;
  3141. writer = _moduleBuilder.DefineDocument(
  3142. fname,
  3143. Guid.Empty,
  3144. Guid.Empty,
  3145. SymDocumentType.Text);
  3146. _symbolDocWriters.Add(fname, writer);
  3147. return writer;
  3148. }
  3149. private ISymbolDocumentWriter GetCachedDocumentWriter(string fname)
  3150. {
  3151. return (ISymbolDocumentWriter) _symbolDocWriters[fname];
  3152. }
  3153. bool IsBoolOrInt(IType type)
  3154. {
  3155. return TypeSystemServices.BoolType == type ||
  3156. TypeSystemServices.IntType == type;
  3157. }
  3158. void PushArguments(IMethodBase entity, ExpressionCollection args)
  3159. {
  3160. var parameters = entity.GetParameters();
  3161. for (var i=0; i<args.Count; ++i)
  3162. {
  3163. var parameterType = parameters[i].Type;
  3164. var arg = args[i];
  3165. if (parameters[i].IsByRef)
  3166. LoadAddress(arg);
  3167. else
  3168. LoadExpressionWithType(parameterType, arg);
  3169. }
  3170. }
  3171. void EmitObjectArray(ExpressionCollection items)
  3172. {
  3173. EmitArray(TypeSystemServices.ObjectType, items);
  3174. }
  3175. const int InlineArrayItemCountLimit = 3;
  3176. void EmitArray(IType type, ExpressionCollection items)
  3177. {
  3178. EmitLoadLiteral(items.Count);
  3179. _il.Emit(OpCodes.Newarr, GetSystemType(type));
  3180. if (items.Count == 0)
  3181. return;
  3182. var inlineStores = 0;
  3183. if (items.Count > InlineArrayItemCountLimit && TypeSystemServices.IsPrimitiveNumber(type))
  3184. {
  3185. //packed array are only supported for a literal array of
  3186. //an unique primitive type. check that all items are literal
  3187. //and count number of actual stores in order to build/emit
  3188. //a packed array only if is is an advantage
  3189. foreach (Expression item in items)
  3190. {
  3191. if ((item.NodeType != NodeType.IntegerLiteralExpression
  3192. && item.NodeType != NodeType.DoubleLiteralExpression)
  3193. || type != item.ExpressionType)
  3194. {
  3195. inlineStores = 0;
  3196. break;
  3197. }
  3198. if (IsZeroEquivalent(item))
  3199. continue;
  3200. ++inlineStores;
  3201. }
  3202. }
  3203. if (inlineStores <= InlineArrayItemCountLimit)
  3204. EmitInlineArrayInit(type, items);
  3205. else
  3206. EmitPackedArrayInit(type, items);
  3207. }
  3208. void EmitInlineArrayInit(IType type, ExpressionCollection items)
  3209. {
  3210. OpCode opcode = GetStoreEntityOpCode(type);
  3211. for (int i=0; i<items.Count; ++i)
  3212. {
  3213. if (IsNull(items[i]))
  3214. continue; //do not emit even if types are not the same (null is any)
  3215. if (type == items[i].ExpressionType && IsZeroEquivalent(items[i]))
  3216. continue; //do not emit unnecessary init to zero
  3217. StoreEntity(opcode, i, items[i], type);
  3218. }
  3219. }
  3220. void EmitPackedArrayInit(IType type, ExpressionCollection items)
  3221. {
  3222. byte[] ba = CreateByteArrayFromLiteralCollection(type, items);
  3223. if (null == ba)
  3224. {
  3225. EmitInlineArrayInit(type, items);
  3226. return;
  3227. }
  3228. FieldBuilder fb;
  3229. if (!_packedArrays.TryGetValue(ba, out fb))
  3230. {
  3231. //there is no previously emitted bytearray to reuse, create it then
  3232. fb = _moduleBuilder.DefineInitializedData(Context.GetUniqueName("newarr"), ba, FieldAttributes.Private);
  3233. _packedArrays.Add(ba, fb);
  3234. }
  3235. Dup(); //dup (newarr)
  3236. _il.Emit(OpCodes.Ldtoken, fb);
  3237. Call(RuntimeHelpers_InitializeArray);
  3238. }
  3239. Dictionary<byte[], FieldBuilder> _packedArrays = new Dictionary<byte[], FieldBuilder>(ValueTypeArrayEqualityComparer<byte>.Default);
  3240. byte[] CreateByteArrayFromLiteralCollection(IType type, ExpressionCollection items)
  3241. {
  3242. using (MemoryStream ms = new MemoryStream(items.Count * TypeSystemServices.SizeOf(type)))
  3243. {
  3244. using (BinaryWriter writer = new BinaryWriter(ms))
  3245. {
  3246. foreach (Expression item in items)
  3247. {
  3248. //TODO: BOO-1222 NumericLiteralExpression.GetValueAs<T>()
  3249. if (item.NodeType == NodeType.IntegerLiteralExpression)
  3250. {
  3251. IntegerLiteralExpression literal = (IntegerLiteralExpression) item;
  3252. if (type == TypeSystemServices.IntType)
  3253. writer.Write(Convert.ToInt32(literal.Value));
  3254. else if (type == TypeSystemServices.UIntType)
  3255. writer.Write(Convert.ToUInt32(literal.Value));
  3256. else if (IsLong(type))
  3257. writer.Write(Convert.ToInt64(literal.Value));
  3258. else if (type == TypeSystemServices.ULongType)
  3259. writer.Write(Convert.ToUInt64(literal.Value));
  3260. else if (type == TypeSystemServices.ShortType)
  3261. writer.Write(Convert.ToInt16(literal.Value));
  3262. else if (type == TypeSystemServices.UShortType)
  3263. writer.Write(Convert.ToUInt16(literal.Value));
  3264. else if (type == TypeSystemServices.ByteType)
  3265. writer.Write(Convert.ToByte(literal.Value));
  3266. else if (type == TypeSystemServices.SByteType)
  3267. writer.Write(Convert.ToSByte(literal.Value));
  3268. else if (type == TypeSystemServices.SingleType)
  3269. writer.Write(Convert.ToSingle(literal.Value));
  3270. else if (type == TypeSystemServices.DoubleType)
  3271. writer.Write(Convert.ToDouble(literal.Value));
  3272. else
  3273. return null;
  3274. }
  3275. else if (item.NodeType == NodeType.DoubleLiteralExpression)
  3276. {
  3277. DoubleLiteralExpression literal = (DoubleLiteralExpression) item;
  3278. if (type == TypeSystemServices.SingleType)
  3279. writer.Write(Convert.ToSingle(literal.Value));
  3280. else if (type == TypeSystemServices.DoubleType)
  3281. writer.Write(Convert.ToDouble(literal.Value));
  3282. else if (type == TypeSystemServices.IntType)
  3283. writer.Write(Convert.ToInt32(literal.Value));
  3284. else if (type == TypeSystemServices.UIntType)
  3285. writer.Write(Convert.ToUInt32(literal.Value));
  3286. else if (IsLong(type))
  3287. writer.Write(Convert.ToInt64(literal.Value));
  3288. else if (type == TypeSystemServices.ULongType)
  3289. writer.Write(Convert.ToUInt64(literal.Value));
  3290. else if (type == TypeSystemServices.ShortType)
  3291. writer.Write(Convert.ToInt16(literal.Value));
  3292. else if (type == TypeSystemServices.UShortType)
  3293. writer.Write(Convert.ToUInt16(literal.Value));
  3294. else if (type == TypeSystemServices.ByteType)
  3295. writer.Write(Convert.ToByte(literal.Value));
  3296. else if (type == TypeSystemServices.SByteType)
  3297. writer.Write(Convert.ToSByte(literal.Value));
  3298. else
  3299. return null;
  3300. }
  3301. else
  3302. return null;
  3303. }
  3304. }
  3305. return ms.ToArray();
  3306. }
  3307. }
  3308. bool IsInteger(IType type)
  3309. {
  3310. return TypeSystemServices.IsIntegerNumber(type);
  3311. }
  3312. MethodInfo GetToDecimalConversionMethod(IType type)
  3313. {
  3314. MethodInfo method =
  3315. typeof(Decimal).GetMethod("op_Implicit", new Type[] { GetSystemType(type) });
  3316. if (method == null)
  3317. {
  3318. method =
  3319. typeof(Decimal).GetMethod("op_Explicit", new Type[] { GetSystemType(type) });
  3320. if (method == null)
  3321. {
  3322. NotImplemented(string.Format("Numeric promotion for {0} to decimal not implemented!", type));
  3323. }
  3324. }
  3325. return method;
  3326. }
  3327. MethodInfo GetFromDecimalConversionMethod(IType type)
  3328. {
  3329. string toType = "To" + type.Name;
  3330. MethodInfo method =
  3331. typeof(Decimal).GetMethod(toType, new Type[] { typeof(Decimal) });
  3332. if (method == null)
  3333. {
  3334. NotImplemented(string.Format("Numeric promotion for decimal to {0} not implemented!", type));
  3335. }
  3336. return method;
  3337. }
  3338. OpCode GetArithmeticOpCode(IType type, BinaryOperatorType op)
  3339. {
  3340. if (IsCheckedIntegerOperand(type))
  3341. {
  3342. switch (op)
  3343. {
  3344. case BinaryOperatorType.Addition: return OpCodes.Add_Ovf;
  3345. case BinaryOperatorType.Subtraction: return OpCodes.Sub_Ovf;
  3346. case BinaryOperatorType.Multiply: return OpCodes.Mul_Ovf;
  3347. case BinaryOperatorType.Division: return OpCodes.Div;
  3348. case BinaryOperatorType.Modulus: return OpCodes.Rem;
  3349. }
  3350. }
  3351. else
  3352. {
  3353. switch (op)
  3354. {
  3355. case BinaryOperatorType.Addition: return OpCodes.Add;
  3356. case BinaryOperatorType.Subtraction: return OpCodes.Sub;
  3357. case BinaryOperatorType.Multiply: return OpCodes.Mul;
  3358. case BinaryOperatorType.Division: return OpCodes.Div;
  3359. case BinaryOperatorType.Modulus: return OpCodes.Rem;
  3360. }
  3361. }
  3362. throw new ArgumentException("op");
  3363. }
  3364. OpCode GetLoadEntityOpCode(IType type)
  3365. {
  3366. if (IsByAddress(type))
  3367. return OpCodes.Ldelema;
  3368. if (!type.IsValueType)
  3369. {
  3370. return type is IGenericParameter
  3371. ? OpCodes.Ldelem
  3372. : OpCodes.Ldelem_Ref;
  3373. }
  3374. if (type.IsEnum)
  3375. {
  3376. type = TypeSystemServices.Map(GetEnumUnderlyingType(type));
  3377. }
  3378. if (TypeSystemServices.IntType == type)
  3379. {
  3380. return OpCodes.Ldelem_I4;
  3381. }
  3382. if (TypeSystemServices.UIntType == type)
  3383. {
  3384. return OpCodes.Ldelem_U4;
  3385. }
  3386. if (IsLong(type))
  3387. {
  3388. return OpCodes.Ldelem_I8;
  3389. }
  3390. if (TypeSystemServices.SByteType == type)
  3391. {
  3392. return OpCodes.Ldelem_I1;
  3393. }
  3394. if (TypeSystemServices.ByteType == type)
  3395. {
  3396. return OpCodes.Ldelem_U1;
  3397. }
  3398. if (TypeSystemServices.ShortType == type ||
  3399. TypeSystemServices.CharType == type)
  3400. {
  3401. return OpCodes.Ldelem_I2;
  3402. }
  3403. if (TypeSystemServices.UShortType == type)
  3404. {
  3405. return OpCodes.Ldelem_U2;
  3406. }
  3407. if (TypeSystemServices.SingleType == type)
  3408. {
  3409. return OpCodes.Ldelem_R4;
  3410. }
  3411. if (TypeSystemServices.DoubleType == type)
  3412. {
  3413. return OpCodes.Ldelem_R8;
  3414. }
  3415. //NotImplemented("LoadEntityOpCode(" + tag + ")");
  3416. return OpCodes.Ldelema;
  3417. }
  3418. OpCode GetStoreEntityOpCode(IType tag)
  3419. {
  3420. if (tag.IsValueType || tag is IGenericParameter)
  3421. {
  3422. if (tag.IsEnum)
  3423. {
  3424. tag = TypeSystemServices.Map(GetEnumUnderlyingType(tag));
  3425. }
  3426. if (TypeSystemServices.IntType == tag ||
  3427. TypeSystemServices.UIntType == tag)
  3428. {
  3429. return OpCodes.Stelem_I4;
  3430. }
  3431. else if (IsLong(tag) ||
  3432. TypeSystemServices.ULongType == tag)
  3433. {
  3434. return OpCodes.Stelem_I8;
  3435. }
  3436. else if (TypeSystemServices.ShortType == tag ||
  3437. TypeSystemServices.CharType == tag)
  3438. {
  3439. return OpCodes.Stelem_I2;
  3440. }
  3441. else if (TypeSystemServices.ByteType == tag ||
  3442. TypeSystemServices.SByteType == tag)
  3443. {
  3444. return OpCodes.Stelem_I1;
  3445. }
  3446. else if (TypeSystemServices.SingleType == tag)
  3447. {
  3448. return OpCodes.Stelem_R4;
  3449. }
  3450. else if (TypeSystemServices.DoubleType == tag)
  3451. {
  3452. return OpCodes.Stelem_R8;
  3453. }
  3454. return OpCodes.Stobj;
  3455. }
  3456. return OpCodes.Stelem_Ref;
  3457. }
  3458. OpCode GetLoadRefParamCode(IType tag)
  3459. {
  3460. if (tag.IsValueType)
  3461. {
  3462. if (tag.IsEnum)
  3463. {
  3464. tag = TypeSystemServices.Map(GetEnumUnderlyingType(tag));
  3465. }
  3466. if (TypeSystemServices.IntType == tag)
  3467. {
  3468. return OpCodes.Ldind_I4;
  3469. }
  3470. if (IsLong(tag) ||
  3471. TypeSystemServices.ULongType == tag)
  3472. {
  3473. return OpCodes.Ldind_I8;
  3474. }
  3475. if (TypeSystemServices.ByteType == tag)
  3476. {
  3477. return OpCodes.Ldind_U1;
  3478. }
  3479. if (TypeSystemServices.ShortType == tag ||
  3480. TypeSystemServices.CharType == tag)
  3481. {
  3482. return OpCodes.Ldind_I2;
  3483. }
  3484. if (TypeSystemServices.SingleType == tag)
  3485. {
  3486. return OpCodes.Ldind_R4;
  3487. }
  3488. if (TypeSystemServices.DoubleType == tag)
  3489. {
  3490. return OpCodes.Ldind_R8;
  3491. }
  3492. if (TypeSystemServices.UShortType == tag)
  3493. {
  3494. return OpCodes.Ldind_U2;
  3495. }
  3496. if (TypeSystemServices.UIntType == tag)
  3497. {
  3498. return OpCodes.Ldind_U4;
  3499. }
  3500. return OpCodes.Ldobj;
  3501. }
  3502. return OpCodes.Ldind_Ref;
  3503. }
  3504. OpCode GetStoreRefParamCode(IType tag)
  3505. {
  3506. if (tag.IsValueType)
  3507. {
  3508. if (tag.IsEnum)
  3509. {
  3510. tag = TypeSystemServices.Map(GetEnumUnderlyingType(tag));
  3511. }
  3512. if (TypeSystemServices.IntType == tag
  3513. || TypeSystemServices.UIntType == tag)
  3514. {
  3515. return OpCodes.Stind_I4;
  3516. }
  3517. if (IsLong(tag)
  3518. || TypeSystemServices.ULongType == tag)
  3519. {
  3520. return OpCodes.Stind_I8;
  3521. }
  3522. if (TypeSystemServices.ByteType == tag)
  3523. {
  3524. return OpCodes.Stind_I1;
  3525. }
  3526. if (TypeSystemServices.ShortType == tag ||
  3527. TypeSystemServices.CharType == tag)
  3528. {
  3529. return OpCodes.Stind_I2;
  3530. }
  3531. if (TypeSystemServices.SingleType == tag)
  3532. {
  3533. return OpCodes.Stind_R4;
  3534. }
  3535. if (TypeSystemServices.DoubleType == tag)
  3536. {
  3537. return OpCodes.Stind_R8;
  3538. }
  3539. return OpCodes.Stobj;
  3540. }
  3541. return OpCodes.Stind_Ref;
  3542. }
  3543. bool IsAssignableFrom(IType expectedType, IType actualType)
  3544. {
  3545. return (IsPtr(expectedType) && IsPtr(actualType))
  3546. || TypeCompatibilityRules.IsAssignableFrom(expectedType, actualType);
  3547. }
  3548. bool IsPtr(IType type)
  3549. {
  3550. return (type == TypeSystemServices.IntPtrType)
  3551. || (type == TypeSystemServices.UIntPtrType);
  3552. }
  3553. void EmitCastIfNeeded(IType expectedType, IType actualType)
  3554. {
  3555. if (actualType == null) // see NullLiteralExpression
  3556. return;
  3557. if (expectedType == actualType)
  3558. return;
  3559. if (expectedType.IsPointer || actualType.IsPointer) //no cast needed for addresses
  3560. return;
  3561. if (IsAssignableFrom(expectedType, actualType))
  3562. {
  3563. EmitBoxIfNeeded(expectedType, actualType);
  3564. return;
  3565. }
  3566. var method = TypeSystemServices.FindImplicitConversionOperator(actualType, expectedType)
  3567. ?? TypeSystemServices.FindExplicitConversionOperator(actualType, expectedType);
  3568. if (method != null)
  3569. {
  3570. EmitBoxIfNeeded(method.GetParameters()[0].Type, actualType);
  3571. Call(GetMethodInfo(method));
  3572. return;
  3573. }
  3574. if (expectedType is IGenericParameter)
  3575. {
  3576. // Since expected type is a generic parameter, we don't know whether to emit
  3577. // an unbox opcode or a castclass opcode; so we emit an unbox.any opcode which
  3578. // works as either of those at runtime
  3579. _il.Emit(OpCodes.Unbox_Any, GetSystemType(expectedType));
  3580. return;
  3581. }
  3582. if (expectedType.IsValueType)
  3583. {
  3584. if (!actualType.IsValueType)
  3585. {
  3586. // To get a value type out of a reference type we emit an unbox opcode
  3587. EmitUnbox(expectedType);
  3588. return;
  3589. }
  3590. // numeric promotion
  3591. if (TypeSystemServices.DecimalType == expectedType)
  3592. {
  3593. Call(GetToDecimalConversionMethod(actualType));
  3594. }
  3595. else if (TypeSystemServices.DecimalType == actualType)
  3596. {
  3597. Call(GetFromDecimalConversionMethod(expectedType));
  3598. }
  3599. else
  3600. {
  3601. //we need to get the real underlying type here and no earlier
  3602. //(because cause enum casting from int can occur [e.g enums-13])
  3603. if (actualType.IsEnum)
  3604. actualType = TypeSystemServices.Map(GetEnumUnderlyingType(actualType));
  3605. if (expectedType.IsEnum)
  3606. expectedType = TypeSystemServices.Map(GetEnumUnderlyingType(expectedType));
  3607. if (actualType != expectedType) //do we really need conv?
  3608. _il.Emit(GetNumericPromotionOpCode(expectedType));
  3609. }
  3610. return;
  3611. }
  3612. EmitRuntimeCoercionIfNeeded(expectedType, actualType);
  3613. }
  3614. private void EmitRuntimeCoercionIfNeeded(IType expectedType, IType actualType)
  3615. {
  3616. // In order to cast to a reference type we emit a castclass opcode
  3617. Context.TraceInfo("castclass: expected type='{0}', type on stack='{1}'", expectedType, actualType);
  3618. var expectedSystemType = GetSystemType(expectedType);
  3619. if (TypeSystemServices.IsSystemObject(actualType))
  3620. {
  3621. Dup();
  3622. Isinst(expectedSystemType);
  3623. var skipCoercion = _il.DefineLabel();
  3624. _il.Emit(OpCodes.Brtrue, skipCoercion);
  3625. EmitGetTypeFromHandle(expectedSystemType); PopType();
  3626. Call(RuntimeServices_Coerce);
  3627. _il.MarkLabel(skipCoercion);
  3628. }
  3629. Castclass(expectedSystemType);
  3630. }
  3631. private void Call(MethodInfo method)
  3632. {
  3633. _il.EmitCall(OpCodes.Call, method, null);
  3634. }
  3635. private void Castclass(Type expectedSystemType)
  3636. {
  3637. _il.Emit(OpCodes.Castclass, expectedSystemType);
  3638. }
  3639. private MethodInfo _RuntimeServices_Coerce;
  3640. private MethodInfo RuntimeServices_Coerce
  3641. {
  3642. get
  3643. {
  3644. if (_RuntimeServices_Coerce != null) return _RuntimeServices_Coerce;
  3645. return _RuntimeServices_Coerce = Types.RuntimeServices.GetMethod("Coerce", new Type[] { Types.Object, Types.Type });
  3646. }
  3647. }
  3648. private void EmitBoxIfNeeded(IType expectedType, IType actualType)
  3649. {
  3650. if ((actualType.IsValueType && !expectedType.IsValueType)
  3651. || (actualType is IGenericParameter && !(expectedType is IGenericParameter)))
  3652. EmitBox(actualType);
  3653. }
  3654. void EmitBox(IType type)
  3655. {
  3656. _il.Emit(OpCodes.Box, GetSystemType(type));
  3657. }
  3658. void EmitUnbox(IType expectedType)
  3659. {
  3660. var unboxMethod = UnboxMethodFor(expectedType);
  3661. if (null != unboxMethod)
  3662. {
  3663. Call(unboxMethod);
  3664. }
  3665. else
  3666. {
  3667. Type type = GetSystemType(expectedType);
  3668. _il.Emit(OpCodes.Unbox, type);
  3669. _il.Emit(OpCodes.Ldobj, type);
  3670. }
  3671. }
  3672. MethodInfo UnboxMethodFor(IType type)
  3673. {
  3674. if (type == TypeSystemServices.ByteType) return Methods.Of<object, byte>(RuntimeServices.UnboxByte);
  3675. if (type == TypeSystemServices.SByteType) return Methods.Of<object, sbyte>(RuntimeServices.UnboxSByte);
  3676. if (type == TypeSystemServices.ShortType) return Methods.Of<object, short>(RuntimeServices.UnboxInt16);
  3677. if (type == TypeSystemServices.UShortType) return Methods.Of<object, ushort>(RuntimeServices.UnboxUInt16);
  3678. if (type == TypeSystemServices.IntType) return Methods.Of<object, int>(RuntimeServices.UnboxInt32);
  3679. if (type == TypeSystemServices.UIntType) return Methods.Of<object, uint>(RuntimeServices.UnboxUInt32);
  3680. if (IsLong(type)) return Methods.Of<object, long>(RuntimeServices.UnboxInt64);
  3681. if (type == TypeSystemServices.ULongType) return Methods.Of<object, ulong>(RuntimeServices.UnboxUInt64);
  3682. if (type == TypeSystemServices.SingleType) return Methods.Of<object, float>(RuntimeServices.UnboxSingle);
  3683. if (type == TypeSystemServices.DoubleType) return Methods.Of<object, double>(RuntimeServices.UnboxDouble);
  3684. if (type == TypeSystemServices.DecimalType) return Methods.Of<object, decimal>(RuntimeServices.UnboxDecimal);
  3685. if (type == TypeSystemServices.BoolType) return Methods.Of<object, bool>(RuntimeServices.UnboxBoolean);
  3686. if (type == TypeSystemServices.CharType) return Methods.Of<object, char>(RuntimeServices.UnboxChar);
  3687. return null;
  3688. }
  3689. OpCode GetNumericPromotionOpCode(IType type)
  3690. {
  3691. return NumericPromotionOpcodeFor(TypeCodeFor(type), _checked);
  3692. }
  3693. private static OpCode NumericPromotionOpcodeFor(TypeCode typeCode, bool @checked)
  3694. {
  3695. switch (typeCode)
  3696. {
  3697. case TypeCode.SByte:
  3698. return @checked ? OpCodes.Conv_Ovf_I1 : OpCodes.Conv_I1;
  3699. case TypeCode.Byte:
  3700. return @checked ? OpCodes.Conv_Ovf_U1 : OpCodes.Conv_U1;
  3701. case TypeCode.Int16:
  3702. return @checked ? OpCodes.Conv_Ovf_I2 : OpCodes.Conv_I2;
  3703. case TypeCode.UInt16:
  3704. case TypeCode.Char:
  3705. return @checked ? OpCodes.Conv_Ovf_U2 : OpCodes.Conv_U2;
  3706. case TypeCode.Int32:
  3707. return @checked ? OpCodes.Conv_Ovf_I4 : OpCodes.Conv_I4;
  3708. case TypeCode.UInt32:
  3709. return @checked ? OpCodes.Conv_Ovf_U4 : OpCodes.Conv_U4;
  3710. case TypeCode.Int64:
  3711. return @checked ? OpCodes.Conv_Ovf_I8 : OpCodes.Conv_I8;
  3712. case TypeCode.UInt64:
  3713. return @checked ? OpCodes.Conv_Ovf_U8 : OpCodes.Conv_U8;
  3714. case TypeCode.Single:
  3715. return OpCodes.Conv_R4;
  3716. case TypeCode.Double:
  3717. return OpCodes.Conv_R8;
  3718. default:
  3719. throw new ArgumentException(typeCode.ToString());
  3720. }
  3721. }
  3722. private static TypeCode TypeCodeFor(IType type)
  3723. {
  3724. var externalType = type as ExternalType;
  3725. if (externalType != null)
  3726. return Type.GetTypeCode(externalType.ActualType);
  3727. throw new NotImplementedException(string.Format("TypeCodeFor({0}) not implemented!", type));
  3728. }
  3729. void StoreEntity(OpCode opcode, int index, Expression value, IType elementType)
  3730. {
  3731. // array reference
  3732. Dup();
  3733. EmitLoadLiteral(index); // element index
  3734. bool stobj = IsStobj(opcode); // value type sequence?
  3735. if (stobj)
  3736. {
  3737. Type systemType = GetSystemType(elementType);
  3738. _il.Emit(OpCodes.Ldelema, systemType);
  3739. LoadExpressionWithType(elementType, value); // might need to cast to decimal
  3740. _il.Emit(opcode, systemType);
  3741. }
  3742. else
  3743. {
  3744. LoadExpressionWithType(elementType, value);
  3745. _il.Emit(opcode);
  3746. }
  3747. }
  3748. private void Dup()
  3749. {
  3750. _il.Emit(OpCodes.Dup);
  3751. }
  3752. bool IsStobj(OpCode code)
  3753. {
  3754. return OpCodes.Stobj.Value == code.Value;
  3755. }
  3756. void DefineAssemblyAttributes()
  3757. {
  3758. foreach (Attribute attribute in _assemblyAttributes)
  3759. {
  3760. _asmBuilder.SetCustomAttribute(GetCustomAttributeBuilder(attribute));
  3761. }
  3762. }
  3763. CustomAttributeBuilder CreateDebuggableAttribute()
  3764. {
  3765. return new CustomAttributeBuilder(
  3766. DebuggableAttribute_Constructor,
  3767. new object[] { DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations });
  3768. }
  3769. CustomAttributeBuilder CreateRuntimeCompatibilityAttribute()
  3770. {
  3771. return new CustomAttributeBuilder(
  3772. RuntimeCompatibilityAttribute_Constructor, new object[0],
  3773. RuntimeCompatibilityAttribute_Property, new object[] { true });
  3774. }
  3775. CustomAttributeBuilder CreateUnverifiableCodeAttribute()
  3776. {
  3777. return new CustomAttributeBuilder(Methods.ConstructorOf(() => new UnverifiableCodeAttribute()), new object[0]);
  3778. }
  3779. void DefineEntryPoint()
  3780. {
  3781. if (Context.Parameters.GenerateInMemory)
  3782. {
  3783. Context.GeneratedAssembly = _asmBuilder;
  3784. }
  3785. if (CompilerOutputType.Library != Parameters.OutputType)
  3786. {
  3787. Method method = ContextAnnotations.GetEntryPoint(Context);
  3788. if (null != method)
  3789. {
  3790. MethodInfo entryPoint = Context.Parameters.GenerateInMemory
  3791. ? _asmBuilder.GetType(method.DeclaringType.FullName).GetMethod(method.Name, BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Static)
  3792. : GetMethodBuilder(method);
  3793. _asmBuilder.SetEntryPoint(entryPoint, (PEFileKinds)Parameters.OutputType);
  3794. }
  3795. else
  3796. {
  3797. Errors.Add(CompilerErrorFactory.NoEntryPoint());
  3798. }
  3799. }
  3800. }
  3801. Type[] GetParameterTypes(ParameterDeclarationCollection parameters)
  3802. {
  3803. Type[] types = new Type[parameters.Count];
  3804. for (int i=0; i<types.Length; ++i)
  3805. {
  3806. types[i] = GetSystemType(parameters[i].Type);
  3807. if (parameters[i].IsByRef && !types[i].IsByRef)
  3808. {
  3809. types[i] = types[i].MakeByRefType();
  3810. }
  3811. }
  3812. return types;
  3813. }
  3814. Hashtable _builders = new Hashtable();
  3815. void SetBuilder(Node node, object builder)
  3816. {
  3817. if (null == builder)
  3818. {
  3819. throw new ArgumentNullException("type");
  3820. }
  3821. _builders[node] = builder;
  3822. }
  3823. object GetBuilder(Node node)
  3824. {
  3825. return _builders[node];
  3826. }
  3827. internal TypeBuilder GetTypeBuilder(Node node)
  3828. {
  3829. return (TypeBuilder)_builders[node];
  3830. }
  3831. PropertyBuilder GetPropertyBuilder(Node node)
  3832. {
  3833. return (PropertyBuilder)_builders[node];
  3834. }
  3835. FieldBuilder GetFieldBuilder(Node node)
  3836. {
  3837. return (FieldBuilder)_builders[node];
  3838. }
  3839. MethodBuilder GetMethodBuilder(Method method)
  3840. {
  3841. return (MethodBuilder)_builders[method];
  3842. }
  3843. ConstructorBuilder GetConstructorBuilder(Method method)
  3844. {
  3845. return (ConstructorBuilder)_builders[method];
  3846. }
  3847. LocalBuilder GetLocalBuilder(Node local)
  3848. {
  3849. return GetInternalLocal(local).LocalBuilder;
  3850. }
  3851. PropertyInfo GetPropertyInfo(IEntity tag)
  3852. {
  3853. ExternalProperty external = tag as ExternalProperty;
  3854. if (null != external)
  3855. {
  3856. return external.PropertyInfo;
  3857. }
  3858. return GetPropertyBuilder(((InternalProperty)tag).Property);
  3859. }
  3860. FieldInfo GetFieldInfo(IField tag)
  3861. {
  3862. // If field is external, get its existing FieldInfo
  3863. ExternalField external = tag as ExternalField;
  3864. if (null != external)
  3865. {
  3866. return external.FieldInfo;
  3867. }
  3868. // If field is mapped from a generic type, get its mapped FieldInfo
  3869. // on the constructed type
  3870. GenericMappedField mapped = tag as GenericMappedField;
  3871. if (mapped != null)
  3872. {
  3873. return GetMappedFieldInfo(mapped.DeclaringType, mapped.SourceMember);
  3874. }
  3875. // If field is internal, get its FieldBuilder
  3876. return GetFieldBuilder(((InternalField)tag).Field);
  3877. }
  3878. MethodInfo GetMethodInfo(IMethod entity)
  3879. {
  3880. // If method is external, get its existing MethodInfo
  3881. var external = entity as ExternalMethod;
  3882. if (null != external)
  3883. return (MethodInfo)external.MethodInfo;
  3884. // If method is a constructed generic method, get its MethodInfo from its definition
  3885. if (entity is GenericConstructedMethod)
  3886. return GetConstructedMethodInfo(entity.ConstructedInfo);
  3887. // If method is mapped from a generic type, get its MethodInfo on the constructed type
  3888. var mapped = entity as GenericMappedMethod;
  3889. if (mapped != null)
  3890. return GetMappedMethodInfo(mapped.DeclaringType, mapped.SourceMember);
  3891. // If method is internal, get its MethodBuilder
  3892. return GetMethodBuilder(((InternalMethod)entity).Method);
  3893. }
  3894. ConstructorInfo GetConstructorInfo(IConstructor entity)
  3895. {
  3896. // If constructor is external, get its existing ConstructorInfo
  3897. var external = entity as ExternalConstructor;
  3898. if (null != external)
  3899. return external.ConstructorInfo;
  3900. // If constructor is mapped from a generic type, get its ConstructorInfo on the constructed type
  3901. var mapped = entity as GenericMappedConstructor;
  3902. if (mapped != null)
  3903. return TypeBuilder.GetConstructor(GetSystemType(mapped.DeclaringType), GetConstructorInfo((IConstructor)mapped.SourceMember));
  3904. // If constructor is internal, get its MethodBuilder
  3905. return GetConstructorBuilder(((InternalMethod)entity).Method);
  3906. }
  3907. /// <summary>
  3908. /// Retrieves the MethodInfo for a generic constructed method.
  3909. /// </summary>
  3910. private MethodInfo GetConstructedMethodInfo(IConstructedMethodInfo constructedInfo)
  3911. {
  3912. Type[] arguments = Array.ConvertAll<IType, Type>(constructedInfo.GenericArguments, GetSystemType);
  3913. return GetMethodInfo(constructedInfo.GenericDefinition).MakeGenericMethod(arguments);
  3914. }
  3915. /// <summary>
  3916. /// Retrieves the FieldInfo for a field as mapped on a generic type.
  3917. /// </summary>
  3918. private FieldInfo GetMappedFieldInfo(IType targetType, IField source)
  3919. {
  3920. FieldInfo fi = GetFieldInfo(source);
  3921. if (!fi.DeclaringType.IsGenericTypeDefinition)
  3922. {
  3923. // HACK: .NET Reflection doesn't allow calling TypeBuilder.GetField(Type, FieldInfo)
  3924. // on types that aren't generic definitions (like open constructed types), so we have
  3925. // to manually find the corresponding FieldInfo on the declaring type's definition
  3926. // before mapping it
  3927. Type definition = fi.DeclaringType.GetGenericTypeDefinition();
  3928. fi = definition.GetField(fi.Name);
  3929. }
  3930. return TypeBuilder.GetField(GetSystemType(targetType), fi);
  3931. }
  3932. /// <summary>
  3933. /// Retrieves the MethodInfo for a method as mapped on a generic type.
  3934. /// </summary>
  3935. private MethodInfo GetMappedMethodInfo(IType targetType, IMethod source)
  3936. {
  3937. var mi = GetMethodInfo(source);
  3938. if (mi.DeclaringType.IsGenericTypeDefinition)
  3939. return GetConstructedMethodInfo(targetType, mi);
  3940. // HACK: .NET Reflection doesn't allow calling TypeBuilder.GetMethod(Type, MethodInfo)
  3941. // on types that aren't generic definitions (like open constructed types), so we have to
  3942. // manually find the corresponding MethodInfo on the declaring type's definition before
  3943. // mapping it
  3944. var definition = mi.DeclaringType.GetGenericTypeDefinition();
  3945. var correspondingMethod = Array.Find(definition.GetMethods(), it => it.MetadataToken == mi.MetadataToken);
  3946. return GetConstructedMethodInfo(targetType, correspondingMethod);
  3947. }
  3948. MethodInfo GetConstructedMethodInfo(IType targetType, MethodInfo mi)
  3949. {
  3950. return TypeBuilder.GetMethod(GetSystemType(targetType), mi);
  3951. }
  3952. /// <summary>
  3953. /// Retrieves the ConstructorInfo for a constructor as mapped on a generic type.
  3954. /// </summary>
  3955. private ConstructorInfo GetMappedConstructorInfo(IType targetType, IConstructor source)
  3956. {
  3957. ConstructorInfo ci = GetConstructorInfo(source);
  3958. if (!ci.DeclaringType.IsGenericTypeDefinition)
  3959. {
  3960. // HACK: .NET Reflection doesn't allow calling
  3961. // TypeBuilder.GetConstructor(Type, ConstructorInfo) on types that aren't generic
  3962. // definitions, so we have to manually find the corresponding ConstructorInfo on the
  3963. // declaring type's definition before mapping it
  3964. Type definition = ci.DeclaringType.GetGenericTypeDefinition();
  3965. ci = Array.Find<ConstructorInfo>(
  3966. definition.GetConstructors(),
  3967. delegate(ConstructorInfo other) { return other.MetadataToken == ci.MetadataToken; });
  3968. }
  3969. return TypeBuilder.GetConstructor(GetSystemType(targetType), ci);
  3970. }
  3971. Type GetSystemType(Node node)
  3972. {
  3973. return GetSystemType(GetType(node));
  3974. }
  3975. Type GetSystemType(IType entity)
  3976. {
  3977. Type existingType;
  3978. if (_typeCache.TryGetValue(entity, out existingType))
  3979. return existingType;
  3980. Type type = SystemTypeFrom(entity);
  3981. if (type == null)
  3982. throw new InvalidOperationException(string.Format("Could not find a Type for {0}.", entity));
  3983. _typeCache.Add(entity, type);
  3984. return type;
  3985. }
  3986. private Type SystemTypeFrom(IType entity)
  3987. {
  3988. var external = entity as ExternalType;
  3989. if (null != external)
  3990. return external.ActualType;
  3991. if (entity.IsArray)
  3992. {
  3993. IArrayType arrayType = (IArrayType)entity;
  3994. Type systemType = GetSystemType(arrayType.ElementType);
  3995. int rank = arrayType.Rank;
  3996. if (rank == 1) return systemType.MakeArrayType();
  3997. return systemType.MakeArrayType(rank);
  3998. }
  3999. if (entity.ConstructedInfo != null)
  4000. {
  4001. // Type is a constructed generic type - create it using its definition's system type
  4002. Type[] arguments = Array.ConvertAll<IType, Type>(entity.ConstructedInfo.GenericArguments, GetSystemType);
  4003. return GetSystemType(entity.ConstructedInfo.GenericDefinition).MakeGenericType(arguments);
  4004. }
  4005. if (entity.IsNull())
  4006. return Types.Object;
  4007. if (entity is InternalGenericParameter)
  4008. return (Type)GetBuilder(((InternalGenericParameter)entity).Node);
  4009. if (entity is AbstractInternalType)
  4010. {
  4011. TypeDefinition typedef = ((AbstractInternalType) entity).TypeDefinition;
  4012. var type = (Type)GetBuilder(typedef);
  4013. if (null != entity.GenericInfo && !type.IsGenericType) //hu-oh, early-bound
  4014. DefineGenericParameters(typedef);
  4015. if (entity.IsPointer && null != type)
  4016. return type.MakePointerType();
  4017. return type;
  4018. }
  4019. return null;
  4020. }
  4021. TypeAttributes GetNestedTypeAttributes(TypeMember type)
  4022. {
  4023. return GetExtendedTypeAttributes(GetNestedTypeAccessibility(type), type);
  4024. }
  4025. TypeAttributes GetNestedTypeAccessibility(TypeMember type)
  4026. {
  4027. if (type.IsPublic) return TypeAttributes.NestedPublic;
  4028. if (type.IsInternal) return TypeAttributes.NestedAssembly;
  4029. return TypeAttributes.NestedPrivate;
  4030. }
  4031. TypeAttributes GetTypeAttributes(TypeMember type)
  4032. {
  4033. return GetExtendedTypeAttributes(GetTypeVisibilityAttributes(type), type);
  4034. }
  4035. private TypeAttributes GetTypeVisibilityAttributes(TypeMember type)
  4036. {
  4037. return type.IsPublic ? TypeAttributes.Public : TypeAttributes.NotPublic;
  4038. }
  4039. TypeAttributes GetExtendedTypeAttributes(TypeAttributes attributes, TypeMember type)
  4040. {
  4041. switch (type.NodeType)
  4042. {
  4043. case NodeType.ClassDefinition:
  4044. {
  4045. attributes |= (TypeAttributes.AnsiClass | TypeAttributes.AutoLayout);
  4046. attributes |= TypeAttributes.Class;
  4047. if (!((ClassDefinition) type).HasDeclaredStaticConstructor)
  4048. {
  4049. attributes |= TypeAttributes.BeforeFieldInit;
  4050. }
  4051. if (type.IsAbstract)
  4052. {
  4053. attributes |= TypeAttributes.Abstract;
  4054. }
  4055. if (type.IsFinal)
  4056. {
  4057. attributes |= TypeAttributes.Sealed;
  4058. }
  4059. if (type.IsStatic) //static type is Sealed+Abstract in SRE
  4060. attributes |= TypeAttributes.Sealed | TypeAttributes.Abstract;
  4061. else if (!type.IsTransient)
  4062. attributes |= TypeAttributes.Serializable;
  4063. if (((IType)type.Entity).IsValueType)
  4064. {
  4065. attributes |= TypeAttributes.SequentialLayout;
  4066. }
  4067. break;
  4068. }
  4069. case NodeType.EnumDefinition:
  4070. {
  4071. attributes |= TypeAttributes.Sealed;
  4072. attributes |= TypeAttributes.Serializable;
  4073. break;
  4074. }
  4075. case NodeType.InterfaceDefinition:
  4076. {
  4077. attributes |= (TypeAttributes.Interface | TypeAttributes.Abstract);
  4078. break;
  4079. }
  4080. case NodeType.Module:
  4081. {
  4082. attributes |= TypeAttributes.Sealed;
  4083. break;
  4084. }
  4085. }
  4086. return attributes;
  4087. }
  4088. PropertyAttributes PropertyAttributesFor(Property property)
  4089. {
  4090. return property.ExplicitInfo != null
  4091. ? PropertyAttributes.SpecialName | PropertyAttributes.RTSpecialName
  4092. : PropertyAttributes.None;
  4093. }
  4094. MethodAttributes MethodAttributesFor(TypeMember member)
  4095. {
  4096. var attributes = MethodVisibilityAttributesFor(member);
  4097. if (member.IsStatic)
  4098. {
  4099. attributes |= MethodAttributes.Static;
  4100. if (member.Name.StartsWith("op_"))
  4101. attributes |= MethodAttributes.SpecialName;
  4102. }
  4103. else if (member.IsAbstract)
  4104. attributes |= (MethodAttributes.Abstract | MethodAttributes.Virtual);
  4105. else if (member.IsVirtual || member.IsOverride)
  4106. {
  4107. attributes |= MethodAttributes.Virtual;
  4108. if (member.IsFinal)
  4109. attributes |= MethodAttributes.Final;
  4110. if (member.IsNew)
  4111. attributes |= MethodAttributes.NewSlot;
  4112. }
  4113. return attributes;
  4114. }
  4115. private static MethodAttributes MethodVisibilityAttributesFor(TypeMember member)
  4116. {
  4117. if (member.IsPublic)
  4118. return MethodAttributes.Public;
  4119. if (member.IsProtected)
  4120. return member.IsInternal ? MethodAttributes.FamORAssem : MethodAttributes.Family;
  4121. if (member.IsInternal)
  4122. return MethodAttributes.Assembly;
  4123. return MethodAttributes.Private;
  4124. }
  4125. MethodAttributes PropertyAccessorAttributesFor(TypeMember property)
  4126. {
  4127. const MethodAttributes defaultPropertyAccessorAttributes = MethodAttributes.SpecialName | MethodAttributes.HideBySig;
  4128. return defaultPropertyAccessorAttributes | MethodAttributesFor(property);
  4129. }
  4130. MethodAttributes GetMethodAttributes(Method method)
  4131. {
  4132. MethodAttributes attributes = MethodAttributes.HideBySig;
  4133. if (method.ExplicitInfo != null)
  4134. attributes |= MethodAttributes.NewSlot;
  4135. if (IsPInvoke(method))
  4136. {
  4137. Debug.Assert(method.IsStatic);
  4138. attributes |= MethodAttributes.PinvokeImpl;
  4139. }
  4140. attributes |= MethodAttributesFor(method);
  4141. return attributes;
  4142. }
  4143. static FieldAttributes FieldAttributesFor(Field field)
  4144. {
  4145. var attributes = FieldVisibilityAttributeFor(field);
  4146. if (field.IsStatic)
  4147. attributes |= FieldAttributes.Static;
  4148. if (field.IsTransient)
  4149. attributes |= FieldAttributes.NotSerialized;
  4150. if (field.IsFinal)
  4151. {
  4152. IField entity = (IField)field.Entity;
  4153. if (entity.IsLiteral)
  4154. attributes |= FieldAttributes.Literal;
  4155. else
  4156. attributes |= FieldAttributes.InitOnly;
  4157. }
  4158. return attributes;
  4159. }
  4160. private static FieldAttributes FieldVisibilityAttributeFor(Field field)
  4161. {
  4162. if (field.IsProtected)
  4163. return FieldAttributes.Family;
  4164. if (field.IsPublic)
  4165. return FieldAttributes.Public;
  4166. if (field.IsInternal)
  4167. return FieldAttributes.Assembly;
  4168. return FieldAttributes.Private;
  4169. }
  4170. static readonly Type IsVolatileType = typeof(System.Runtime.CompilerServices.IsVolatile);
  4171. static Type[] GetFieldRequiredCustomModifiers(Field field)
  4172. {
  4173. if (field.IsVolatile)
  4174. return new[] { IsVolatileType };
  4175. return Type.EmptyTypes;
  4176. }
  4177. ParameterAttributes GetParameterAttributes(ParameterDeclaration param)
  4178. {
  4179. return ParameterAttributes.None;
  4180. }
  4181. void DefineEvent(TypeBuilder typeBuilder, Event node)
  4182. {
  4183. var builder = typeBuilder.DefineEvent(node.Name, EventAttributes.None, GetSystemType(node.Type));
  4184. builder.SetAddOnMethod(DefineEventMethod(typeBuilder, node.Add));
  4185. builder.SetRemoveOnMethod(DefineEventMethod(typeBuilder, node.Remove));
  4186. if (node.Raise != null)
  4187. builder.SetRaiseMethod(DefineEventMethod(typeBuilder, node.Raise));
  4188. SetBuilder(node, builder);
  4189. }
  4190. private MethodBuilder DefineEventMethod(TypeBuilder typeBuilder, Method method)
  4191. {
  4192. return DefineMethod(typeBuilder, method, MethodAttributes.SpecialName | GetMethodAttributes(method));
  4193. }
  4194. void DefineProperty(TypeBuilder typeBuilder, Property property)
  4195. {
  4196. var name = property.ExplicitInfo != null
  4197. ? property.ExplicitInfo.InterfaceType.Name + "." + property.Name
  4198. : property.Name;
  4199. var builder = typeBuilder.DefineProperty(name,
  4200. PropertyAttributesFor(property),
  4201. GetSystemType(property.Type),
  4202. GetParameterTypes(property.Parameters));
  4203. var getter = property.Getter;
  4204. if (getter != null)
  4205. builder.SetGetMethod(DefinePropertyAccessor(typeBuilder, property, getter));
  4206. var setter = property.Setter;
  4207. if (setter != null)
  4208. builder.SetSetMethod(DefinePropertyAccessor(typeBuilder, property, setter));
  4209. if (GetEntity(property).IsDuckTyped)
  4210. builder.SetCustomAttribute(CreateDuckTypedCustomAttribute());
  4211. SetBuilder(property, builder);
  4212. }
  4213. private MethodBuilder DefinePropertyAccessor(TypeBuilder typeBuilder, Property property, Method accessor)
  4214. {
  4215. if (!accessor.IsVisibilitySet)
  4216. accessor.Visibility = property.Visibility;
  4217. return DefineMethod(typeBuilder, accessor, PropertyAccessorAttributesFor(accessor));
  4218. }
  4219. void DefineField(TypeBuilder typeBuilder, Field field)
  4220. {
  4221. var builder = typeBuilder.DefineField(field.Name,
  4222. GetSystemType(field),
  4223. GetFieldRequiredCustomModifiers(field),
  4224. Type.EmptyTypes,
  4225. FieldAttributesFor(field));
  4226. SetBuilder(field, builder);
  4227. }
  4228. delegate ParameterBuilder ParameterFactory(int index, ParameterAttributes attributes, string name);
  4229. void DefineParameters(ConstructorBuilder builder, ParameterDeclarationCollection parameters)
  4230. {
  4231. DefineParameters(parameters, builder.DefineParameter);
  4232. }
  4233. void DefineParameters(MethodBuilder builder, ParameterDeclarationCollection parameters)
  4234. {
  4235. DefineParameters(parameters, builder.DefineParameter);
  4236. }
  4237. void DefineParameters(ParameterDeclarationCollection parameters, ParameterFactory defineParameter)
  4238. {
  4239. for (int i=0; i<parameters.Count; ++i)
  4240. {
  4241. ParameterBuilder paramBuilder = defineParameter(i+1, GetParameterAttributes(parameters[i]), parameters[i].Name);
  4242. if (parameters[i].IsParamArray)
  4243. {
  4244. SetParamArrayAttribute(paramBuilder);
  4245. }
  4246. SetBuilder(parameters[i], paramBuilder);
  4247. }
  4248. }
  4249. void SetParamArrayAttribute(ParameterBuilder builder)
  4250. {
  4251. builder.SetCustomAttribute(
  4252. new CustomAttributeBuilder(
  4253. ParamArrayAttribute_Constructor,
  4254. new object[0]));
  4255. }
  4256. static MethodImplAttributes ImplementationFlagsFor(Method method)
  4257. {
  4258. return method.IsRuntime
  4259. ? MethodImplAttributes.Runtime
  4260. : MethodImplAttributes.Managed;
  4261. }
  4262. MethodBuilder DefineMethod(TypeBuilder typeBuilder, Method method, MethodAttributes attributes)
  4263. {
  4264. ParameterDeclarationCollection parameters = method.Parameters;
  4265. MethodAttributes methodAttributes = GetMethodAttributes(method) | attributes;
  4266. string name;
  4267. if (method.ExplicitInfo != null)
  4268. {
  4269. name = method.ExplicitInfo.InterfaceType.Name + "." + method.Name;
  4270. }
  4271. else
  4272. {
  4273. name = method.Name;
  4274. }
  4275. MethodBuilder builder = typeBuilder.DefineMethod(name,
  4276. methodAttributes);
  4277. if (method.GenericParameters.Count != 0)
  4278. {
  4279. DefineGenericParameters(builder, method.GenericParameters.ToArray());
  4280. }
  4281. builder.SetParameters(GetParameterTypes(parameters));
  4282. IType returnType = GetEntity(method).ReturnType;
  4283. if (IsPInvoke(method) && TypeSystemServices.IsUnknown(returnType))
  4284. {
  4285. returnType = TypeSystemServices.VoidType;
  4286. }
  4287. builder.SetReturnType(GetSystemType(returnType));
  4288. builder.SetImplementationFlags(ImplementationFlagsFor(method));
  4289. DefineParameters(builder, parameters);
  4290. SetBuilder(method, builder);
  4291. IMethod methodEntity = GetEntity(method);
  4292. if (methodEntity.IsDuckTyped)
  4293. {
  4294. builder.SetCustomAttribute(CreateDuckTypedCustomAttribute());
  4295. }
  4296. return builder;
  4297. }
  4298. void DefineGenericParameters(TypeDefinition typeDefinition)
  4299. {
  4300. if (typeDefinition is EnumDefinition)
  4301. return;
  4302. TypeBuilder type = GetTypeBuilder(typeDefinition);
  4303. if (type.IsGenericType)
  4304. return; //early-bound, do not redefine generic parameters again
  4305. if (typeDefinition.GenericParameters.Count > 0)
  4306. {
  4307. DefineGenericParameters(type, typeDefinition.GenericParameters.ToArray());
  4308. }
  4309. }
  4310. /// <summary>
  4311. /// Defines the generic parameters of an internal generic type.
  4312. /// </summary>
  4313. void DefineGenericParameters(TypeBuilder builder, GenericParameterDeclaration[] parameters)
  4314. {
  4315. string[] names = Array.ConvertAll<GenericParameterDeclaration, string>(
  4316. parameters,
  4317. delegate(GenericParameterDeclaration gpd) { return gpd.Name; });
  4318. GenericTypeParameterBuilder[] builders = builder.DefineGenericParameters(names);
  4319. DefineGenericParameters(builders, parameters);
  4320. }
  4321. /// <summary>
  4322. /// Defines the generic parameters of an internal generic method.
  4323. /// </summary>
  4324. void DefineGenericParameters(MethodBuilder builder, GenericParameterDeclaration[] parameters)
  4325. {
  4326. string[] names = Array.ConvertAll<GenericParameterDeclaration, string>(
  4327. parameters,
  4328. delegate(GenericParameterDeclaration gpd) { return gpd.Name; });
  4329. GenericTypeParameterBuilder[] builders = builder.DefineGenericParameters(names);
  4330. DefineGenericParameters(builders, parameters);
  4331. }
  4332. void DefineGenericParameters(GenericTypeParameterBuilder[] builders, GenericParameterDeclaration[] declarations)
  4333. {
  4334. for (int i = 0; i < builders.Length; i++)
  4335. {
  4336. SetBuilder(declarations[i], builders[i]);
  4337. DefineGenericParameter(((InternalGenericParameter)declarations[i].Entity), builders[i]);
  4338. }
  4339. }
  4340. private void DefineGenericParameter(InternalGenericParameter parameter, GenericTypeParameterBuilder builder)
  4341. {
  4342. // Set base type constraint
  4343. if (parameter.BaseType != TypeSystemServices.ObjectType)
  4344. {
  4345. builder.SetBaseTypeConstraint(GetSystemType(parameter.BaseType));
  4346. }
  4347. // Set interface constraints
  4348. Type[] interfaceTypes = Array.ConvertAll<IType, Type>(
  4349. parameter.GetInterfaces(), GetSystemType);
  4350. builder.SetInterfaceConstraints(interfaceTypes);
  4351. // Set special attributes
  4352. GenericParameterAttributes attributes = GenericParameterAttributes.None;
  4353. if (parameter.IsClass)
  4354. attributes |= GenericParameterAttributes.ReferenceTypeConstraint;
  4355. if (parameter.IsValueType)
  4356. attributes |= GenericParameterAttributes.NotNullableValueTypeConstraint;
  4357. if (parameter.MustHaveDefaultConstructor)
  4358. attributes |= GenericParameterAttributes.DefaultConstructorConstraint;
  4359. builder.SetGenericParameterAttributes(attributes);
  4360. }
  4361. private CustomAttributeBuilder CreateDuckTypedCustomAttribute()
  4362. {
  4363. return new CustomAttributeBuilder(DuckTypedAttribute_Constructor, new object[0]);
  4364. }
  4365. void DefineConstructor(TypeBuilder typeBuilder, Method constructor)
  4366. {
  4367. ConstructorBuilder builder = typeBuilder.DefineConstructor(GetMethodAttributes(constructor),
  4368. CallingConventions.Standard,
  4369. GetParameterTypes(constructor.Parameters));
  4370. builder.SetImplementationFlags(ImplementationFlagsFor(constructor));
  4371. DefineParameters(builder, constructor.Parameters);
  4372. SetBuilder(constructor, builder);
  4373. }
  4374. bool IsEnumDefinition(TypeMember type)
  4375. {
  4376. return NodeType.EnumDefinition == type.NodeType;
  4377. }
  4378. void DefineType(TypeDefinition typeDefinition)
  4379. {
  4380. SetBuilder(typeDefinition, CreateTypeBuilder(typeDefinition));
  4381. }
  4382. bool IsValueType(TypeMember type)
  4383. {
  4384. IType entity = type.Entity as IType;
  4385. return null != entity && entity.IsValueType;
  4386. }
  4387. InternalLocal GetInternalLocal(Node local)
  4388. {
  4389. return (InternalLocal)GetEntity(local);
  4390. }
  4391. object CreateTypeBuilder(TypeDefinition type)
  4392. {
  4393. Type baseType = null;
  4394. if (IsEnumDefinition(type))
  4395. {
  4396. baseType = typeof(Enum);
  4397. }
  4398. else if (IsValueType(type))
  4399. {
  4400. baseType = Types.ValueType;
  4401. }
  4402. TypeBuilder typeBuilder = null;
  4403. var enclosingType = type.ParentNode as ClassDefinition;
  4404. var enumDef = type as EnumDefinition;
  4405. if (null == enclosingType)
  4406. {
  4407. typeBuilder = _moduleBuilder.DefineType(
  4408. AnnotateGenericTypeName(type, type.QualifiedName),
  4409. GetTypeAttributes(type),
  4410. baseType);
  4411. }
  4412. else
  4413. {
  4414. typeBuilder = GetTypeBuilder(enclosingType).DefineNestedType(
  4415. AnnotateGenericTypeName(type, type.Name),
  4416. GetNestedTypeAttributes(type),
  4417. baseType);
  4418. }
  4419. if (IsEnumDefinition(type))
  4420. {
  4421. // Mono cant construct enum array types unless
  4422. // the fields is already defined
  4423. typeBuilder.DefineField("value__",
  4424. GetEnumUnderlyingType(enumDef),
  4425. FieldAttributes.Public |
  4426. FieldAttributes.SpecialName |
  4427. FieldAttributes.RTSpecialName);
  4428. }
  4429. return typeBuilder;
  4430. }
  4431. private string AnnotateGenericTypeName(TypeDefinition typeDef, string name)
  4432. {
  4433. if (typeDef.HasGenericParameters)
  4434. {
  4435. return name + "`" + typeDef.GenericParameters.Count;
  4436. }
  4437. return name;
  4438. }
  4439. void EmitBaseTypesAndAttributes(TypeDefinition typeDefinition, TypeBuilder typeBuilder)
  4440. {
  4441. foreach (TypeReference baseType in typeDefinition.BaseTypes)
  4442. {
  4443. Type type = GetSystemType(baseType);
  4444. // For some reason you can't call IsClass on constructed types created at compile time,
  4445. // so we'll ask the generic definition instead
  4446. if ((type.IsGenericType && type.GetGenericTypeDefinition().IsClass) || (type.IsClass))
  4447. {
  4448. typeBuilder.SetParent(type);
  4449. }
  4450. else
  4451. {
  4452. typeBuilder.AddInterfaceImplementation(type);
  4453. }
  4454. }
  4455. }
  4456. void NotImplemented(string feature)
  4457. {
  4458. throw new NotImplementedException(feature);
  4459. }
  4460. CustomAttributeBuilder GetCustomAttributeBuilder(Attribute node)
  4461. {
  4462. var constructor = (IConstructor)GetEntity(node);
  4463. var constructorInfo = GetConstructorInfo(constructor);
  4464. object[] constructorArgs = ArgumentsForAttributeConstructor(constructor, node.Arguments);
  4465. var namedArgs = node.NamedArguments;
  4466. if (namedArgs.Count > 0)
  4467. {
  4468. PropertyInfo[] namedProperties;
  4469. object[] propertyValues;
  4470. FieldInfo[] namedFields;
  4471. object[] fieldValues;
  4472. GetNamedValues(namedArgs,
  4473. out namedProperties,
  4474. out propertyValues,
  4475. out namedFields,
  4476. out fieldValues);
  4477. return new CustomAttributeBuilder(
  4478. constructorInfo, constructorArgs,
  4479. namedProperties, propertyValues,
  4480. namedFields, fieldValues);
  4481. }
  4482. return new CustomAttributeBuilder(constructorInfo, constructorArgs);
  4483. }
  4484. void GetNamedValues(ExpressionPairCollection values,
  4485. out PropertyInfo[] outNamedProperties,
  4486. out object[] outPropertyValues,
  4487. out FieldInfo[] outNamedFields,
  4488. out object[] outFieldValues)
  4489. {
  4490. List namedProperties = new List();
  4491. List propertyValues = new List();
  4492. List namedFields = new List();
  4493. List fieldValues = new List();
  4494. foreach (ExpressionPair pair in values)
  4495. {
  4496. ITypedEntity entity = (ITypedEntity)GetEntity(pair.First);
  4497. object value = GetValue(entity.Type, pair.Second);
  4498. if (EntityType.Property == entity.EntityType)
  4499. {
  4500. namedProperties.Add(GetPropertyInfo(entity));
  4501. propertyValues.Add(value);
  4502. }
  4503. else
  4504. {
  4505. namedFields.Add(GetFieldInfo((IField)entity));
  4506. fieldValues.Add(value);
  4507. }
  4508. }
  4509. outNamedProperties = (PropertyInfo[])namedProperties.ToArray(typeof(PropertyInfo));
  4510. outPropertyValues = propertyValues.ToArray();
  4511. outNamedFields = (FieldInfo[])namedFields.ToArray(typeof(FieldInfo));
  4512. outFieldValues = fieldValues.ToArray();
  4513. }
  4514. object[] ArgumentsForAttributeConstructor(IConstructor ctor, ExpressionCollection args)
  4515. {
  4516. var varargs = ctor.AcceptVarArgs;
  4517. var parameters = ctor.GetParameters();
  4518. var result = new object[parameters.Length];
  4519. var lastIndex = parameters.Length - 1;
  4520. var fixedParameters = (varargs ? parameters.Take(lastIndex) : parameters);
  4521. var i = 0;
  4522. foreach (var parameter in fixedParameters)
  4523. {
  4524. result[i] = GetValue(parameter.Type, args[i]);
  4525. ++i;
  4526. }
  4527. if (varargs)
  4528. {
  4529. var varArgType = parameters[lastIndex].Type.ElementType;
  4530. result[lastIndex] = args.Skip(lastIndex).Select(e => GetValue(varArgType, e)).ToArray();
  4531. }
  4532. return result;
  4533. }
  4534. object GetValue(IType expectedType, Expression expression)
  4535. {
  4536. switch (expression.NodeType)
  4537. {
  4538. case NodeType.NullLiteralExpression:
  4539. return null;
  4540. case NodeType.StringLiteralExpression:
  4541. return ((StringLiteralExpression)expression).Value;
  4542. case NodeType.CharLiteralExpression:
  4543. return ((CharLiteralExpression)expression).Value[0];
  4544. case NodeType.BoolLiteralExpression:
  4545. return ((BoolLiteralExpression)expression).Value;
  4546. case NodeType.IntegerLiteralExpression:
  4547. return ConvertValue(expectedType,
  4548. ((IntegerLiteralExpression)expression).Value);
  4549. case NodeType.DoubleLiteralExpression:
  4550. return ConvertValue(expectedType,
  4551. ((DoubleLiteralExpression)expression).Value);
  4552. case NodeType.TypeofExpression:
  4553. return GetSystemType(((TypeofExpression)expression).Type);
  4554. case NodeType.CastExpression:
  4555. return GetValue(expectedType, ((CastExpression)expression).Target);
  4556. default:
  4557. return GetComplexExpressionValue(expectedType, expression);
  4558. }
  4559. }
  4560. private object GetComplexExpressionValue(IType expectedType, Expression expression)
  4561. {
  4562. IEntity tag = GetEntity(expression);
  4563. if (EntityType.Type == tag.EntityType)
  4564. return GetSystemType(expression);
  4565. if (EntityType.Field == tag.EntityType)
  4566. {
  4567. IField field = (IField)tag;
  4568. if (field.IsLiteral)
  4569. {
  4570. //Scenario:
  4571. //IF:
  4572. //SomeType.StaticReference = "hamsandwich"
  4573. //[RandomAttribute(SomeType.StaticReferenece)]
  4574. //THEN:
  4575. //field.StaticValue != "hamsandwich"
  4576. //field.StaticValue == SomeType.StaticReference
  4577. //SO:
  4578. //If field.StaticValue is an AST Expression, call GetValue() on it
  4579. if (field.StaticValue is Expression)
  4580. return GetValue(expectedType, field.StaticValue as Expression);
  4581. return field.StaticValue;
  4582. }
  4583. }
  4584. NotImplemented(expression, "Expression value: " + expression);
  4585. return null;
  4586. }
  4587. object ConvertValue(IType expectedType, object value)
  4588. {
  4589. if (expectedType.IsEnum)
  4590. {
  4591. return Convert.ChangeType(value, GetEnumUnderlyingType(expectedType));
  4592. }
  4593. return Convert.ChangeType(value, GetSystemType(expectedType));
  4594. }
  4595. private Type GetEnumUnderlyingType(EnumDefinition node)
  4596. {
  4597. return ((InternalEnum) node.Entity).UnderlyingType;
  4598. }
  4599. private Type GetEnumUnderlyingType(IType enumType)
  4600. {
  4601. return enumType is IInternalEntity
  4602. ? ((InternalEnum) enumType).UnderlyingType
  4603. : Enum.GetUnderlyingType(GetSystemType(enumType));
  4604. }
  4605. void DefineTypeMembers(TypeDefinition typeDefinition)
  4606. {
  4607. if (IsEnumDefinition(typeDefinition))
  4608. {
  4609. return;
  4610. }
  4611. TypeBuilder typeBuilder = GetTypeBuilder(typeDefinition);
  4612. TypeMemberCollection members = typeDefinition.Members;
  4613. foreach (TypeMember member in members)
  4614. {
  4615. switch (member.NodeType)
  4616. {
  4617. case NodeType.Method:
  4618. {
  4619. DefineMethod(typeBuilder, (Method)member, 0);
  4620. break;
  4621. }
  4622. case NodeType.Constructor:
  4623. {
  4624. DefineConstructor(typeBuilder, (Constructor)member);
  4625. break;
  4626. }
  4627. case NodeType.Field:
  4628. {
  4629. DefineField(typeBuilder, (Field)member);
  4630. break;
  4631. }
  4632. case NodeType.Property:
  4633. {
  4634. DefineProperty(typeBuilder, (Property)member);
  4635. break;
  4636. }
  4637. case NodeType.Event:
  4638. {
  4639. DefineEvent(typeBuilder, (Event)member);
  4640. break;
  4641. }
  4642. }
  4643. }
  4644. }
  4645. string GetAssemblySimpleName(string fname)
  4646. {
  4647. return Path.GetFileNameWithoutExtension(fname);
  4648. }
  4649. string GetTargetDirectory(string fname)
  4650. {
  4651. return Permissions.WithDiscoveryPermission(() => Path.GetDirectoryName(Path.GetFullPath(fname)));
  4652. }
  4653. string BuildOutputAssemblyName()
  4654. {
  4655. string configuredOutputAssembly = Parameters.OutputAssembly;
  4656. if (!string.IsNullOrEmpty(configuredOutputAssembly))
  4657. return TryToGetFullPath(configuredOutputAssembly);
  4658. string outputAssembly = CompileUnit.Modules[0].Name;
  4659. if (!HasDllOrExeExtension(outputAssembly))
  4660. {
  4661. if (CompilerOutputType.Library == Parameters.OutputType)
  4662. outputAssembly += ".dll";
  4663. else
  4664. outputAssembly += ".exe";
  4665. }
  4666. return TryToGetFullPath(outputAssembly);
  4667. }
  4668. private string TryToGetFullPath(string path)
  4669. {
  4670. return Permissions.WithDiscoveryPermission(() => Path.GetFullPath(path)) ?? path;
  4671. }
  4672. private bool HasDllOrExeExtension(string fname)
  4673. {
  4674. var extension = Path.GetExtension(fname);
  4675. switch (extension.ToLower())
  4676. {
  4677. case ".dll":
  4678. case ".exe":
  4679. return true;
  4680. }
  4681. return false;
  4682. }
  4683. void DefineResources()
  4684. {
  4685. foreach (ICompilerResource resource in Parameters.Resources)
  4686. resource.WriteResource(_sreResourceService);
  4687. }
  4688. SREResourceService _sreResourceService;
  4689. sealed class SREResourceService : IResourceService
  4690. {
  4691. AssemblyBuilder _asmBuilder;
  4692. ModuleBuilder _moduleBuilder;
  4693. public SREResourceService (AssemblyBuilder asmBuilder, ModuleBuilder modBuilder)
  4694. {
  4695. _asmBuilder = asmBuilder;
  4696. _moduleBuilder = modBuilder;
  4697. }
  4698. public bool EmbedFile(string resourceName, string fname)
  4699. {
  4700. _moduleBuilder.DefineManifestResource(resourceName, File.OpenRead(fname), ResourceAttributes.Public);
  4701. return true;
  4702. }
  4703. public IResourceWriter DefineResource(string resourceName, string resourceDescription)
  4704. {
  4705. return _moduleBuilder.DefineResource(resourceName, resourceDescription);
  4706. }
  4707. }
  4708. void SetUpAssembly()
  4709. {
  4710. var outputFile = BuildOutputAssemblyName();
  4711. var asmName = CreateAssemblyName(outputFile);
  4712. var assemblyBuilderAccess = GetAssemblyBuilderAccess();
  4713. var targetDirectory = GetTargetDirectory(outputFile);
  4714. _asmBuilder = string.IsNullOrEmpty(targetDirectory)
  4715. ? AppDomain.CurrentDomain.DefineDynamicAssembly(asmName, assemblyBuilderAccess)
  4716. : AppDomain.CurrentDomain.DefineDynamicAssembly(asmName, assemblyBuilderAccess, targetDirectory);
  4717. if (Parameters.Debug)
  4718. {
  4719. // ikvm tip: Set DebuggableAttribute to assembly before
  4720. // creating the module, to make sure Visual Studio (Whidbey)
  4721. // picks up the attribute when debugging dynamically generated code.
  4722. _asmBuilder.SetCustomAttribute(CreateDebuggableAttribute());
  4723. }
  4724. _asmBuilder.SetCustomAttribute(CreateRuntimeCompatibilityAttribute());
  4725. _moduleBuilder = _asmBuilder.DefineDynamicModule(asmName.Name, Path.GetFileName(outputFile), Parameters.Debug);
  4726. if (Parameters.Unsafe)
  4727. _moduleBuilder.SetCustomAttribute(CreateUnverifiableCodeAttribute());
  4728. _sreResourceService = new SREResourceService (_asmBuilder, _moduleBuilder);
  4729. ContextAnnotations.SetAssemblyBuilder(Context, _asmBuilder);
  4730. Context.GeneratedAssemblyFileName = outputFile;
  4731. }
  4732. AssemblyBuilderAccess GetAssemblyBuilderAccess()
  4733. {
  4734. return Parameters.GenerateInMemory ? AssemblyBuilderAccess.RunAndSave : AssemblyBuilderAccess.Save;
  4735. }
  4736. AssemblyName CreateAssemblyName(string outputFile)
  4737. {
  4738. var assemblyName = new AssemblyName();
  4739. assemblyName.Name = GetAssemblySimpleName(outputFile);
  4740. assemblyName.Version = GetAssemblyVersion();
  4741. if (Parameters.DelaySign)
  4742. assemblyName.SetPublicKey(GetAssemblyKeyPair(outputFile).PublicKey);
  4743. else
  4744. assemblyName.KeyPair = GetAssemblyKeyPair(outputFile);
  4745. return assemblyName;
  4746. }
  4747. StrongNameKeyPair GetAssemblyKeyPair(string outputFile)
  4748. {
  4749. var attribute = GetAssemblyAttribute("System.Reflection.AssemblyKeyNameAttribute");
  4750. if (Parameters.KeyContainer != null)
  4751. {
  4752. if (attribute != null)
  4753. Warnings.Add(CompilerWarningFactory.HaveBothKeyNameAndAttribute(attribute));
  4754. if (Parameters.KeyContainer.Length != 0)
  4755. return new StrongNameKeyPair(Parameters.KeyContainer);
  4756. }
  4757. else if (attribute != null)
  4758. {
  4759. var asmName = ((StringLiteralExpression)attribute.Arguments[0]).Value;
  4760. if (asmName.Length != 0) //ignore empty AssemblyKeyName values, like C# does
  4761. return new StrongNameKeyPair(asmName);
  4762. }
  4763. string fname = null;
  4764. string srcFile = null;
  4765. attribute = GetAssemblyAttribute("System.Reflection.AssemblyKeyFileAttribute");
  4766. if (Parameters.KeyFile != null)
  4767. {
  4768. fname = Parameters.KeyFile;
  4769. if (attribute != null)
  4770. Warnings.Add(CompilerWarningFactory.HaveBothKeyFileAndAttribute(attribute));
  4771. }
  4772. else if (attribute != null)
  4773. {
  4774. fname = ((StringLiteralExpression)attribute.Arguments[0]).Value;
  4775. if (attribute.LexicalInfo != null)
  4776. srcFile = attribute.LexicalInfo.FileName;
  4777. }
  4778. if (!string.IsNullOrEmpty(fname))
  4779. {
  4780. if (!Path.IsPathRooted(fname))
  4781. fname = ResolveRelative(outputFile, srcFile, fname);
  4782. using (FileStream stream = File.OpenRead(fname))
  4783. {
  4784. //Parameters.DelaySign is ignored.
  4785. return new StrongNameKeyPair(stream);
  4786. }
  4787. }
  4788. return null;
  4789. }
  4790. string ResolveRelative(string targetFile, string srcFile, string relativeFile)
  4791. {
  4792. //relative to current directory:
  4793. var fname = Path.GetFullPath(relativeFile);
  4794. if (File.Exists(fname))
  4795. return fname;
  4796. //relative to source file:
  4797. if (srcFile != null)
  4798. {
  4799. fname = ResolveRelativePath(srcFile, relativeFile);
  4800. if (File.Exists(fname))
  4801. return fname;
  4802. }
  4803. //relative to output assembly:
  4804. if (targetFile != null)
  4805. return ResolveRelativePath(targetFile, relativeFile);
  4806. return fname;
  4807. }
  4808. private string ResolveRelativePath(string srcFile, string relativeFile)
  4809. {
  4810. return Path.GetFullPath(Path.Combine(Path.GetDirectoryName(srcFile), relativeFile));
  4811. }
  4812. Version GetAssemblyVersion()
  4813. {
  4814. var version = GetAssemblyAttributeValue("System.Reflection.AssemblyVersionAttribute");
  4815. if (version == null)
  4816. return new Version();
  4817. /* 1.0.* -- BUILD -- based on days since January 1, 2000
  4818. * 1.0.0.* -- REVISION -- based on seconds since midnight, January 1, 2000, divided by 2 *
  4819. */
  4820. string[] sliced = version.Split('.');
  4821. if (sliced.Length > 2)
  4822. {
  4823. var baseTime = new DateTime(2000, 1, 1);
  4824. var mark = DateTime.Now - baseTime;
  4825. if (sliced[2].StartsWith("*"))
  4826. sliced[2] = Math.Round(mark.TotalDays).ToString();
  4827. if (sliced.Length > 3)
  4828. if (sliced[3].StartsWith("*"))
  4829. sliced[3] = Math.Round(mark.TotalSeconds).ToString();
  4830. version = string.Join(".", sliced);
  4831. }
  4832. return new Version(version);
  4833. }
  4834. string GetAssemblyAttributeValue(string name)
  4835. {
  4836. Attribute attribute = GetAssemblyAttribute(name);
  4837. if (null != attribute)
  4838. return ((StringLiteralExpression)attribute.Arguments[0]).Value;
  4839. return null;
  4840. }
  4841. Attribute GetAssemblyAttribute(string name)
  4842. {
  4843. return _assemblyAttributes.Get(name).FirstOrDefault();
  4844. }
  4845. protected override IType GetExpressionType(Expression node)
  4846. {
  4847. IType type = base.GetExpressionType(node);
  4848. if (TypeSystemServices.IsUnknown(type)) throw CompilerErrorFactory.InvalidNode(node);
  4849. return type;
  4850. }
  4851. static private MethodInfo StringFormat
  4852. {
  4853. get
  4854. {
  4855. if (null != stringFormat)
  4856. return stringFormat;
  4857. stringFormat = Methods.Of<string, object, string>(string.Format);
  4858. return stringFormat;
  4859. }
  4860. }
  4861. static MethodInfo stringFormat;
  4862. static Dictionary<Type,MethodInfo> _Nullable_HasValue = new Dictionary<Type,MethodInfo>();
  4863. static MethodInfo GetNullableHasValue(Type type)
  4864. {
  4865. MethodInfo method;
  4866. if (_Nullable_HasValue.TryGetValue(type, out method))
  4867. return method;
  4868. method = Types.Nullable.MakeGenericType(new Type[] {type}).GetProperty("HasValue").GetGetMethod();
  4869. _Nullable_HasValue.Add(type, method);
  4870. return method;
  4871. }
  4872. }
  4873. }