PageRenderTime 55ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/Microsoft.Scripting.Core/Compiler/ILGen.cs

https://bitbucket.org/stefanrusek/xronos
C# | 1059 lines | 863 code | 127 blank | 69 comment | 199 complexity | 1ce3bfd5e8911226a3eb99a4180dc6d8 MD5 | raw file
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Microsoft Public License. A
  6. * copy of the license can be found in the License.html file at the root of this distribution. If
  7. * you cannot locate the Microsoft Public License, please send an email to
  8. * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  9. * by the terms of the Microsoft Public License.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. *
  14. * ***************************************************************************/
  15. using System; using Microsoft;
  16. #if CODEPLEX_40
  17. using ILGenerator = System.Linq.Expressions.Compiler.OffsetTrackingILGenerator;
  18. #else
  19. using ILGenerator = Microsoft.Linq.Expressions.Compiler.OffsetTrackingILGenerator;
  20. #endif
  21. using System.Collections.Generic;
  22. using System.Diagnostics;
  23. #if CODEPLEX_40
  24. using System.Dynamic.Utils;
  25. #else
  26. using Microsoft.Scripting.Utils;
  27. #endif
  28. using System.Reflection;
  29. using System.Reflection.Emit;
  30. using System.Runtime.CompilerServices;
  31. #if !CODEPLEX_40
  32. using Microsoft.Runtime.CompilerServices;
  33. #endif
  34. #if CODEPLEX_40
  35. namespace System.Linq.Expressions.Compiler {
  36. #else
  37. namespace Microsoft.Linq.Expressions.Compiler {
  38. #endif
  39. internal static class ILGen {
  40. internal static void Emit(this ILGenerator il, OpCode opcode, MethodBase methodBase) {
  41. Debug.Assert(methodBase is MethodInfo || methodBase is ConstructorInfo);
  42. if (methodBase.MemberType == MemberTypes.Constructor) {
  43. il.Emit(opcode, (ConstructorInfo)methodBase);
  44. } else {
  45. il.Emit(opcode, (MethodInfo)methodBase);
  46. }
  47. }
  48. #region Instruction helpers
  49. internal static void EmitLoadArg(this ILGenerator il, int index) {
  50. Debug.Assert(index >= 0);
  51. switch (index) {
  52. case 0:
  53. il.Emit(OpCodes.Ldarg_0);
  54. break;
  55. case 1:
  56. il.Emit(OpCodes.Ldarg_1);
  57. break;
  58. case 2:
  59. il.Emit(OpCodes.Ldarg_2);
  60. break;
  61. case 3:
  62. il.Emit(OpCodes.Ldarg_3);
  63. break;
  64. default:
  65. if (index <= Byte.MaxValue) {
  66. il.Emit(OpCodes.Ldarg_S, (byte)index);
  67. } else {
  68. il.Emit(OpCodes.Ldarg, index);
  69. }
  70. break;
  71. }
  72. }
  73. internal static void EmitLoadArgAddress(this ILGenerator il, int index) {
  74. Debug.Assert(index >= 0);
  75. if (index <= Byte.MaxValue) {
  76. il.Emit(OpCodes.Ldarga_S, (byte)index);
  77. } else {
  78. il.Emit(OpCodes.Ldarga, index);
  79. }
  80. }
  81. internal static void EmitStoreArg(this ILGenerator il, int index) {
  82. Debug.Assert(index >= 0);
  83. if (index <= Byte.MaxValue) {
  84. il.Emit(OpCodes.Starg_S, (byte)index);
  85. } else {
  86. il.Emit(OpCodes.Starg, index);
  87. }
  88. }
  89. /// <summary>
  90. /// Emits a Ldind* instruction for the appropriate type
  91. /// </summary>
  92. internal static void EmitLoadValueIndirect(this ILGenerator il, Type type) {
  93. ContractUtils.RequiresNotNull(type, "type");
  94. if (type.IsValueType) {
  95. if (type == typeof(int)) {
  96. il.Emit(OpCodes.Ldind_I4);
  97. } else if (type == typeof(uint)) {
  98. il.Emit(OpCodes.Ldind_U4);
  99. } else if (type == typeof(short)) {
  100. il.Emit(OpCodes.Ldind_I2);
  101. } else if (type == typeof(ushort)) {
  102. il.Emit(OpCodes.Ldind_U2);
  103. } else if (type == typeof(long) || type == typeof(ulong)) {
  104. il.Emit(OpCodes.Ldind_I8);
  105. } else if (type == typeof(char)) {
  106. il.Emit(OpCodes.Ldind_I2);
  107. } else if (type == typeof(bool)) {
  108. il.Emit(OpCodes.Ldind_I1);
  109. } else if (type == typeof(float)) {
  110. il.Emit(OpCodes.Ldind_R4);
  111. } else if (type == typeof(double)) {
  112. il.Emit(OpCodes.Ldind_R8);
  113. } else {
  114. il.Emit(OpCodes.Ldobj, type);
  115. }
  116. } else {
  117. il.Emit(OpCodes.Ldind_Ref);
  118. }
  119. }
  120. /// <summary>
  121. /// Emits a Stind* instruction for the appropriate type.
  122. /// </summary>
  123. internal static void EmitStoreValueIndirect(this ILGenerator il, Type type) {
  124. ContractUtils.RequiresNotNull(type, "type");
  125. if (type.IsValueType) {
  126. if (type == typeof(int)) {
  127. il.Emit(OpCodes.Stind_I4);
  128. } else if (type == typeof(short)) {
  129. il.Emit(OpCodes.Stind_I2);
  130. } else if (type == typeof(long) || type == typeof(ulong)) {
  131. il.Emit(OpCodes.Stind_I8);
  132. } else if (type == typeof(char)) {
  133. il.Emit(OpCodes.Stind_I2);
  134. } else if (type == typeof(bool)) {
  135. il.Emit(OpCodes.Stind_I1);
  136. } else if (type == typeof(float)) {
  137. il.Emit(OpCodes.Stind_R4);
  138. } else if (type == typeof(double)) {
  139. il.Emit(OpCodes.Stind_R8);
  140. } else {
  141. il.Emit(OpCodes.Stobj, type);
  142. }
  143. } else {
  144. il.Emit(OpCodes.Stind_Ref);
  145. }
  146. }
  147. // Emits the Ldelem* instruction for the appropriate type
  148. internal static void EmitLoadElement(this ILGenerator il, Type type) {
  149. ContractUtils.RequiresNotNull(type, "type");
  150. if (!type.IsValueType) {
  151. il.Emit(OpCodes.Ldelem_Ref);
  152. } else if (type.IsEnum) {
  153. il.Emit(OpCodes.Ldelem, type);
  154. } else {
  155. switch (Type.GetTypeCode(type)) {
  156. case TypeCode.Boolean:
  157. case TypeCode.SByte:
  158. il.Emit(OpCodes.Ldelem_I1);
  159. break;
  160. case TypeCode.Byte:
  161. il.Emit(OpCodes.Ldelem_U1);
  162. break;
  163. case TypeCode.Int16:
  164. il.Emit(OpCodes.Ldelem_I2);
  165. break;
  166. case TypeCode.Char:
  167. case TypeCode.UInt16:
  168. il.Emit(OpCodes.Ldelem_U2);
  169. break;
  170. case TypeCode.Int32:
  171. il.Emit(OpCodes.Ldelem_I4);
  172. break;
  173. case TypeCode.UInt32:
  174. il.Emit(OpCodes.Ldelem_U4);
  175. break;
  176. case TypeCode.Int64:
  177. case TypeCode.UInt64:
  178. il.Emit(OpCodes.Ldelem_I8);
  179. break;
  180. case TypeCode.Single:
  181. il.Emit(OpCodes.Ldelem_R4);
  182. break;
  183. case TypeCode.Double:
  184. il.Emit(OpCodes.Ldelem_R8);
  185. break;
  186. default:
  187. il.Emit(OpCodes.Ldelem, type);
  188. break;
  189. }
  190. }
  191. }
  192. /// <summary>
  193. /// Emits a Stelem* instruction for the appropriate type.
  194. /// </summary>
  195. internal static void EmitStoreElement(this ILGenerator il, Type type) {
  196. ContractUtils.RequiresNotNull(type, "type");
  197. if (type.IsEnum) {
  198. il.Emit(OpCodes.Stelem, type);
  199. return;
  200. }
  201. switch (Type.GetTypeCode(type)) {
  202. case TypeCode.Boolean:
  203. case TypeCode.SByte:
  204. case TypeCode.Byte:
  205. il.Emit(OpCodes.Stelem_I1);
  206. break;
  207. case TypeCode.Char:
  208. case TypeCode.Int16:
  209. case TypeCode.UInt16:
  210. il.Emit(OpCodes.Stelem_I2);
  211. break;
  212. case TypeCode.Int32:
  213. case TypeCode.UInt32:
  214. il.Emit(OpCodes.Stelem_I4);
  215. break;
  216. case TypeCode.Int64:
  217. case TypeCode.UInt64:
  218. il.Emit(OpCodes.Stelem_I8);
  219. break;
  220. case TypeCode.Single:
  221. il.Emit(OpCodes.Stelem_R4);
  222. break;
  223. case TypeCode.Double:
  224. il.Emit(OpCodes.Stelem_R8);
  225. break;
  226. default:
  227. if (type.IsValueType) {
  228. il.Emit(OpCodes.Stelem, type);
  229. } else {
  230. il.Emit(OpCodes.Stelem_Ref);
  231. }
  232. break;
  233. }
  234. }
  235. internal static void EmitType(this ILGenerator il, Type type) {
  236. ContractUtils.RequiresNotNull(type, "type");
  237. il.Emit(OpCodes.Ldtoken, type);
  238. il.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle"));
  239. }
  240. #endregion
  241. #region Fields, properties and methods
  242. internal static void EmitFieldAddress(this ILGenerator il, FieldInfo fi) {
  243. ContractUtils.RequiresNotNull(fi, "fi");
  244. if (fi.IsStatic) {
  245. il.Emit(OpCodes.Ldsflda, fi);
  246. } else {
  247. il.Emit(OpCodes.Ldflda, fi);
  248. }
  249. }
  250. internal static void EmitFieldGet(this ILGenerator il, FieldInfo fi) {
  251. ContractUtils.RequiresNotNull(fi, "fi");
  252. if (fi.IsStatic) {
  253. il.Emit(OpCodes.Ldsfld, fi);
  254. } else {
  255. il.Emit(OpCodes.Ldfld, fi);
  256. }
  257. }
  258. internal static void EmitFieldSet(this ILGenerator il, FieldInfo fi) {
  259. ContractUtils.RequiresNotNull(fi, "fi");
  260. if (fi.IsStatic) {
  261. il.Emit(OpCodes.Stsfld, fi);
  262. } else {
  263. il.Emit(OpCodes.Stfld, fi);
  264. }
  265. }
  266. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1711:IdentifiersShouldNotHaveIncorrectSuffix")]
  267. internal static void EmitNew(this ILGenerator il, ConstructorInfo ci) {
  268. ContractUtils.RequiresNotNull(ci, "ci");
  269. if (ci.DeclaringType.ContainsGenericParameters) {
  270. throw Error.IllegalNewGenericParams(ci.DeclaringType);
  271. }
  272. il.Emit(OpCodes.Newobj, ci);
  273. }
  274. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1711:IdentifiersShouldNotHaveIncorrectSuffix")]
  275. internal static void EmitNew(this ILGenerator il, Type type, Type[] paramTypes) {
  276. ContractUtils.RequiresNotNull(type, "type");
  277. ContractUtils.RequiresNotNull(paramTypes, "paramTypes");
  278. ConstructorInfo ci = type.GetConstructor(paramTypes);
  279. ContractUtils.Requires(ci != null, "type", Strings.TypeDoesNotHaveConstructorForTheSignature);
  280. il.EmitNew(ci);
  281. }
  282. #endregion
  283. #region Constants
  284. internal static void EmitNull(this ILGenerator il) {
  285. il.Emit(OpCodes.Ldnull);
  286. }
  287. internal static void EmitString(this ILGenerator il, string value) {
  288. ContractUtils.RequiresNotNull(value, "value");
  289. il.Emit(OpCodes.Ldstr, value);
  290. }
  291. internal static void EmitBoolean(this ILGenerator il, bool value) {
  292. if (value) {
  293. il.Emit(OpCodes.Ldc_I4_1);
  294. } else {
  295. il.Emit(OpCodes.Ldc_I4_0);
  296. }
  297. }
  298. internal static void EmitChar(this ILGenerator il, char value) {
  299. il.EmitInt(value);
  300. il.Emit(OpCodes.Conv_U2);
  301. }
  302. internal static void EmitByte(this ILGenerator il, byte value) {
  303. il.EmitInt(value);
  304. il.Emit(OpCodes.Conv_U1);
  305. }
  306. internal static void EmitSByte(this ILGenerator il, sbyte value) {
  307. il.EmitInt(value);
  308. il.Emit(OpCodes.Conv_I1);
  309. }
  310. internal static void EmitShort(this ILGenerator il, short value) {
  311. il.EmitInt(value);
  312. il.Emit(OpCodes.Conv_I2);
  313. }
  314. internal static void EmitUShort(this ILGenerator il, ushort value) {
  315. il.EmitInt(value);
  316. il.Emit(OpCodes.Conv_U2);
  317. }
  318. internal static void EmitInt(this ILGenerator il, int value) {
  319. OpCode c;
  320. switch (value) {
  321. case -1:
  322. c = OpCodes.Ldc_I4_M1;
  323. break;
  324. case 0:
  325. c = OpCodes.Ldc_I4_0;
  326. break;
  327. case 1:
  328. c = OpCodes.Ldc_I4_1;
  329. break;
  330. case 2:
  331. c = OpCodes.Ldc_I4_2;
  332. break;
  333. case 3:
  334. c = OpCodes.Ldc_I4_3;
  335. break;
  336. case 4:
  337. c = OpCodes.Ldc_I4_4;
  338. break;
  339. case 5:
  340. c = OpCodes.Ldc_I4_5;
  341. break;
  342. case 6:
  343. c = OpCodes.Ldc_I4_6;
  344. break;
  345. case 7:
  346. c = OpCodes.Ldc_I4_7;
  347. break;
  348. case 8:
  349. c = OpCodes.Ldc_I4_8;
  350. break;
  351. default:
  352. if (value >= -128 && value <= 127) {
  353. il.Emit(OpCodes.Ldc_I4_S, (sbyte)value);
  354. } else {
  355. il.Emit(OpCodes.Ldc_I4, value);
  356. }
  357. return;
  358. }
  359. il.Emit(c);
  360. }
  361. internal static void EmitUInt(this ILGenerator il, uint value) {
  362. il.EmitInt((int)value);
  363. il.Emit(OpCodes.Conv_U4);
  364. }
  365. internal static void EmitLong(this ILGenerator il, long value) {
  366. il.Emit(OpCodes.Ldc_I8, value);
  367. //
  368. // Now, emit convert to give the constant type information.
  369. //
  370. // Otherwise, it is treated as unsigned and overflow is not
  371. // detected if it's used in checked ops.
  372. //
  373. il.Emit(OpCodes.Conv_I8);
  374. }
  375. internal static void EmitULong(this ILGenerator il, ulong value) {
  376. il.Emit(OpCodes.Ldc_I8, (long)value);
  377. il.Emit(OpCodes.Conv_U8);
  378. }
  379. internal static void EmitDouble(this ILGenerator il, double value) {
  380. il.Emit(OpCodes.Ldc_R8, value);
  381. }
  382. internal static void EmitSingle(this ILGenerator il, float value) {
  383. il.Emit(OpCodes.Ldc_R4, value);
  384. }
  385. // matches TryEmitConstant
  386. internal static bool CanEmitConstant(object value, Type type) {
  387. if (value == null || CanEmitILConstant(type)) {
  388. return true;
  389. }
  390. Type t = value as Type;
  391. if (t != null && ShouldLdtoken(t)) {
  392. return true;
  393. }
  394. MethodBase mb = value as MethodBase;
  395. if (mb != null && ShouldLdtoken(mb)) {
  396. return true;
  397. }
  398. return false;
  399. }
  400. // matches TryEmitILConstant
  401. private static bool CanEmitILConstant(Type type) {
  402. switch (Type.GetTypeCode(type)) {
  403. case TypeCode.Boolean:
  404. case TypeCode.SByte:
  405. case TypeCode.Int16:
  406. case TypeCode.Int32:
  407. case TypeCode.Int64:
  408. case TypeCode.Single:
  409. case TypeCode.Double:
  410. case TypeCode.Char:
  411. case TypeCode.Byte:
  412. case TypeCode.UInt16:
  413. case TypeCode.UInt32:
  414. case TypeCode.UInt64:
  415. case TypeCode.Decimal:
  416. case TypeCode.String:
  417. return true;
  418. }
  419. return false;
  420. }
  421. internal static void EmitConstant(this ILGenerator il, object value) {
  422. Debug.Assert(value != null);
  423. EmitConstant(il, value, value.GetType());
  424. }
  425. //
  426. // Note: we support emitting more things as IL constants than
  427. // Linq does
  428. internal static void EmitConstant(this ILGenerator il, object value, Type type) {
  429. if (value == null) {
  430. // Smarter than the Linq implementation which uses the initobj
  431. // pattern for all value types (works, but requires a local and
  432. // more IL)
  433. il.EmitDefault(type);
  434. return;
  435. }
  436. // Handle the easy cases
  437. if (il.TryEmitILConstant(value, type)) {
  438. return;
  439. }
  440. // Check for a few more types that we support emitting as constants
  441. Type t = value as Type;
  442. if (t != null && ShouldLdtoken(t)) {
  443. il.EmitType(t);
  444. return;
  445. }
  446. MethodBase mb = value as MethodBase;
  447. if (mb != null && ShouldLdtoken(mb)) {
  448. il.Emit(OpCodes.Ldtoken, mb);
  449. Type dt = mb.DeclaringType;
  450. if (dt != null && dt.IsGenericType) {
  451. il.Emit(OpCodes.Ldtoken, dt);
  452. il.Emit(OpCodes.Call, typeof(MethodBase).GetMethod("GetMethodFromHandle", new Type[] { typeof(RuntimeMethodHandle), typeof(RuntimeTypeHandle) }));
  453. } else {
  454. il.Emit(OpCodes.Call, typeof(MethodBase).GetMethod("GetMethodFromHandle", new Type[] { typeof(RuntimeMethodHandle) }));
  455. }
  456. type = TypeUtils.GetConstantType(type);
  457. if (type != typeof(MethodBase)) {
  458. il.Emit(OpCodes.Castclass, type);
  459. }
  460. return;
  461. }
  462. throw ContractUtils.Unreachable;
  463. }
  464. internal static bool ShouldLdtoken(Type t) {
  465. return t is TypeBuilder || t.IsGenericParameter || t.IsVisible;
  466. }
  467. internal static bool ShouldLdtoken(MethodBase mb) {
  468. // Can't ldtoken on a DynamicMethod
  469. if (mb is DynamicMethod) {
  470. return false;
  471. }
  472. Type dt = mb.DeclaringType;
  473. return dt == null || ShouldLdtoken(dt);
  474. }
  475. private static bool TryEmitILConstant(this ILGenerator il, object value, Type type) {
  476. switch (Type.GetTypeCode(type)) {
  477. case TypeCode.Boolean:
  478. il.EmitBoolean((bool)value);
  479. return true;
  480. case TypeCode.SByte:
  481. il.EmitSByte((sbyte)value);
  482. return true;
  483. case TypeCode.Int16:
  484. il.EmitShort((short)value);
  485. return true;
  486. case TypeCode.Int32:
  487. il.EmitInt((int)value);
  488. return true;
  489. case TypeCode.Int64:
  490. il.EmitLong((long)value);
  491. return true;
  492. case TypeCode.Single:
  493. il.EmitSingle((float)value);
  494. return true;
  495. case TypeCode.Double:
  496. il.EmitDouble((double)value);
  497. return true;
  498. case TypeCode.Char:
  499. il.EmitChar((char)value);
  500. return true;
  501. case TypeCode.Byte:
  502. il.EmitByte((byte)value);
  503. return true;
  504. case TypeCode.UInt16:
  505. il.EmitUShort((ushort)value);
  506. return true;
  507. case TypeCode.UInt32:
  508. il.EmitUInt((uint)value);
  509. return true;
  510. case TypeCode.UInt64:
  511. il.EmitULong((ulong)value);
  512. return true;
  513. case TypeCode.Decimal:
  514. il.EmitDecimal((decimal)value);
  515. return true;
  516. case TypeCode.String:
  517. il.EmitString((string)value);
  518. return true;
  519. default:
  520. return false;
  521. }
  522. }
  523. #endregion
  524. #region Linq Conversions
  525. internal static void EmitConvertToType(this ILGenerator il, Type typeFrom, Type typeTo, bool isChecked) {
  526. if (typeFrom == typeTo) {
  527. return;
  528. }
  529. if (typeFrom == typeof(void) || typeTo == typeof(void)) {
  530. throw ContractUtils.Unreachable;
  531. }
  532. bool isTypeFromNullable = TypeUtils.IsNullableType(typeFrom);
  533. bool isTypeToNullable = TypeUtils.IsNullableType(typeTo);
  534. Type nnExprType = TypeUtils.GetNonNullableType(typeFrom);
  535. Type nnType = TypeUtils.GetNonNullableType(typeTo);
  536. if (typeFrom.IsInterface || // interface cast
  537. typeTo.IsInterface ||
  538. typeFrom == typeof(object) || // boxing cast
  539. typeTo == typeof(object)) {
  540. il.EmitCastToType(typeFrom, typeTo);
  541. } else if (isTypeFromNullable || isTypeToNullable) {
  542. il.EmitNullableConversion(typeFrom, typeTo, isChecked);
  543. } else if (!(TypeUtils.IsConvertible(typeFrom) && TypeUtils.IsConvertible(typeTo)) // primitive runtime conversion
  544. &&
  545. (nnExprType.IsAssignableFrom(nnType) || // down cast
  546. nnType.IsAssignableFrom(nnExprType))) // up cast
  547. {
  548. il.EmitCastToType(typeFrom, typeTo);
  549. } else if (typeFrom.IsArray && typeTo.IsArray) {
  550. // See DevDiv Bugs #94657.
  551. il.EmitCastToType(typeFrom, typeTo);
  552. } else {
  553. il.EmitNumericConversion(typeFrom, typeTo, isChecked);
  554. }
  555. }
  556. private static void EmitCastToType(this ILGenerator il, Type typeFrom, Type typeTo) {
  557. if (!typeFrom.IsValueType && typeTo.IsValueType) {
  558. il.Emit(OpCodes.Unbox_Any, typeTo);
  559. } else if (typeFrom.IsValueType && !typeTo.IsValueType) {
  560. il.Emit(OpCodes.Box, typeFrom);
  561. if (typeTo != typeof(object)) {
  562. il.Emit(OpCodes.Castclass, typeTo);
  563. }
  564. } else if (!typeFrom.IsValueType && !typeTo.IsValueType) {
  565. il.Emit(OpCodes.Castclass, typeTo);
  566. } else {
  567. throw Error.InvalidCast(typeFrom, typeTo);
  568. }
  569. }
  570. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
  571. private static void EmitNumericConversion(this ILGenerator il, Type typeFrom, Type typeTo, bool isChecked) {
  572. bool isFromUnsigned = TypeUtils.IsUnsigned(typeFrom);
  573. bool isFromFloatingPoint = TypeUtils.IsFloatingPoint(typeFrom);
  574. if (typeTo == typeof(Single)) {
  575. if (isFromUnsigned)
  576. il.Emit(OpCodes.Conv_R_Un);
  577. il.Emit(OpCodes.Conv_R4);
  578. } else if (typeTo == typeof(Double)) {
  579. if (isFromUnsigned)
  580. il.Emit(OpCodes.Conv_R_Un);
  581. il.Emit(OpCodes.Conv_R8);
  582. } else {
  583. TypeCode tc = Type.GetTypeCode(typeTo);
  584. if (isChecked) {
  585. if (isFromUnsigned) {
  586. switch (tc) {
  587. case TypeCode.SByte:
  588. il.Emit(OpCodes.Conv_Ovf_I1_Un);
  589. break;
  590. case TypeCode.Int16:
  591. il.Emit(OpCodes.Conv_Ovf_I2_Un);
  592. break;
  593. case TypeCode.Int32:
  594. il.Emit(OpCodes.Conv_Ovf_I4_Un);
  595. break;
  596. case TypeCode.Int64:
  597. il.Emit(OpCodes.Conv_Ovf_I8_Un);
  598. break;
  599. case TypeCode.Byte:
  600. il.Emit(OpCodes.Conv_Ovf_U1_Un);
  601. break;
  602. case TypeCode.UInt16:
  603. case TypeCode.Char:
  604. il.Emit(OpCodes.Conv_Ovf_U2_Un);
  605. break;
  606. case TypeCode.UInt32:
  607. il.Emit(OpCodes.Conv_Ovf_U4_Un);
  608. break;
  609. case TypeCode.UInt64:
  610. il.Emit(OpCodes.Conv_Ovf_U8_Un);
  611. break;
  612. default:
  613. throw Error.UnhandledConvert(typeTo);
  614. }
  615. } else {
  616. switch (tc) {
  617. case TypeCode.SByte:
  618. il.Emit(OpCodes.Conv_Ovf_I1);
  619. break;
  620. case TypeCode.Int16:
  621. il.Emit(OpCodes.Conv_Ovf_I2);
  622. break;
  623. case TypeCode.Int32:
  624. il.Emit(OpCodes.Conv_Ovf_I4);
  625. break;
  626. case TypeCode.Int64:
  627. il.Emit(OpCodes.Conv_Ovf_I8);
  628. break;
  629. case TypeCode.Byte:
  630. il.Emit(OpCodes.Conv_Ovf_U1);
  631. break;
  632. case TypeCode.UInt16:
  633. case TypeCode.Char:
  634. il.Emit(OpCodes.Conv_Ovf_U2);
  635. break;
  636. case TypeCode.UInt32:
  637. il.Emit(OpCodes.Conv_Ovf_U4);
  638. break;
  639. case TypeCode.UInt64:
  640. il.Emit(OpCodes.Conv_Ovf_U8);
  641. break;
  642. default:
  643. throw Error.UnhandledConvert(typeTo);
  644. }
  645. }
  646. } else {
  647. if (isFromUnsigned) {
  648. switch (tc) {
  649. case TypeCode.SByte:
  650. case TypeCode.Byte:
  651. il.Emit(OpCodes.Conv_U1);
  652. break;
  653. case TypeCode.Int16:
  654. case TypeCode.UInt16:
  655. case TypeCode.Char:
  656. il.Emit(OpCodes.Conv_U2);
  657. break;
  658. case TypeCode.Int32:
  659. case TypeCode.UInt32:
  660. il.Emit(OpCodes.Conv_U4);
  661. break;
  662. case TypeCode.Int64:
  663. case TypeCode.UInt64:
  664. il.Emit(OpCodes.Conv_U8);
  665. break;
  666. default:
  667. throw Error.UnhandledConvert(typeTo);
  668. }
  669. } else {
  670. switch (tc) {
  671. case TypeCode.SByte:
  672. case TypeCode.Byte:
  673. il.Emit(OpCodes.Conv_I1);
  674. break;
  675. case TypeCode.Int16:
  676. case TypeCode.UInt16:
  677. case TypeCode.Char:
  678. il.Emit(OpCodes.Conv_I2);
  679. break;
  680. case TypeCode.Int32:
  681. case TypeCode.UInt32:
  682. il.Emit(OpCodes.Conv_I4);
  683. break;
  684. case TypeCode.Int64:
  685. case TypeCode.UInt64:
  686. il.Emit(OpCodes.Conv_I8);
  687. break;
  688. default:
  689. throw Error.UnhandledConvert(typeTo);
  690. }
  691. }
  692. }
  693. }
  694. }
  695. private static void EmitNullableToNullableConversion(this ILGenerator il, Type typeFrom, Type typeTo, bool isChecked) {
  696. Debug.Assert(TypeUtils.IsNullableType(typeFrom));
  697. Debug.Assert(TypeUtils.IsNullableType(typeTo));
  698. Label labIfNull = default(Label);
  699. Label labEnd = default(Label);
  700. LocalBuilder locFrom = null;
  701. LocalBuilder locTo = null;
  702. locFrom = il.DeclareLocal(typeFrom);
  703. il.Emit(OpCodes.Stloc, locFrom);
  704. locTo = il.DeclareLocal(typeTo);
  705. // test for null
  706. il.Emit(OpCodes.Ldloca, locFrom);
  707. il.EmitHasValue(typeFrom);
  708. labIfNull = il.DefineLabel();
  709. il.Emit(OpCodes.Brfalse_S, labIfNull);
  710. il.Emit(OpCodes.Ldloca, locFrom);
  711. il.EmitGetValueOrDefault(typeFrom);
  712. Type nnTypeFrom = TypeUtils.GetNonNullableType(typeFrom);
  713. Type nnTypeTo = TypeUtils.GetNonNullableType(typeTo);
  714. il.EmitConvertToType(nnTypeFrom, nnTypeTo, isChecked);
  715. // construct result type
  716. ConstructorInfo ci = typeTo.GetConstructor(new Type[] { nnTypeTo });
  717. il.Emit(OpCodes.Newobj, ci);
  718. il.Emit(OpCodes.Stloc, locTo);
  719. labEnd = il.DefineLabel();
  720. il.Emit(OpCodes.Br_S, labEnd);
  721. // if null then create a default one
  722. il.MarkLabel(labIfNull);
  723. il.Emit(OpCodes.Ldloca, locTo);
  724. il.Emit(OpCodes.Initobj, typeTo);
  725. il.MarkLabel(labEnd);
  726. il.Emit(OpCodes.Ldloc, locTo);
  727. }
  728. private static void EmitNonNullableToNullableConversion(this ILGenerator il, Type typeFrom, Type typeTo, bool isChecked) {
  729. Debug.Assert(!TypeUtils.IsNullableType(typeFrom));
  730. Debug.Assert(TypeUtils.IsNullableType(typeTo));
  731. LocalBuilder locTo = null;
  732. locTo = il.DeclareLocal(typeTo);
  733. Type nnTypeTo = TypeUtils.GetNonNullableType(typeTo);
  734. il.EmitConvertToType(typeFrom, nnTypeTo, isChecked);
  735. ConstructorInfo ci = typeTo.GetConstructor(new Type[] { nnTypeTo });
  736. il.Emit(OpCodes.Newobj, ci);
  737. il.Emit(OpCodes.Stloc, locTo);
  738. il.Emit(OpCodes.Ldloc, locTo);
  739. }
  740. private static void EmitNullableToNonNullableConversion(this ILGenerator il, Type typeFrom, Type typeTo, bool isChecked) {
  741. Debug.Assert(TypeUtils.IsNullableType(typeFrom));
  742. Debug.Assert(!TypeUtils.IsNullableType(typeTo));
  743. if (typeTo.IsValueType)
  744. il.EmitNullableToNonNullableStructConversion(typeFrom, typeTo, isChecked);
  745. else
  746. il.EmitNullableToReferenceConversion(typeFrom);
  747. }
  748. private static void EmitNullableToNonNullableStructConversion(this ILGenerator il, Type typeFrom, Type typeTo, bool isChecked) {
  749. Debug.Assert(TypeUtils.IsNullableType(typeFrom));
  750. Debug.Assert(!TypeUtils.IsNullableType(typeTo));
  751. Debug.Assert(typeTo.IsValueType);
  752. LocalBuilder locFrom = null;
  753. locFrom = il.DeclareLocal(typeFrom);
  754. il.Emit(OpCodes.Stloc, locFrom);
  755. il.Emit(OpCodes.Ldloca, locFrom);
  756. il.EmitGetValue(typeFrom);
  757. Type nnTypeFrom = TypeUtils.GetNonNullableType(typeFrom);
  758. il.EmitConvertToType(nnTypeFrom, typeTo, isChecked);
  759. }
  760. private static void EmitNullableToReferenceConversion(this ILGenerator il, Type typeFrom) {
  761. Debug.Assert(TypeUtils.IsNullableType(typeFrom));
  762. // We've got a conversion from nullable to Object, ValueType, Enum, etc. Just box it so that
  763. // we get the nullable semantics.
  764. il.Emit(OpCodes.Box, typeFrom);
  765. }
  766. private static void EmitNullableConversion(this ILGenerator il, Type typeFrom, Type typeTo, bool isChecked) {
  767. bool isTypeFromNullable = TypeUtils.IsNullableType(typeFrom);
  768. bool isTypeToNullable = TypeUtils.IsNullableType(typeTo);
  769. Debug.Assert(isTypeFromNullable || isTypeToNullable);
  770. if (isTypeFromNullable && isTypeToNullable)
  771. il.EmitNullableToNullableConversion(typeFrom, typeTo, isChecked);
  772. else if (isTypeFromNullable)
  773. il.EmitNullableToNonNullableConversion(typeFrom, typeTo, isChecked);
  774. else
  775. il.EmitNonNullableToNullableConversion(typeFrom, typeTo, isChecked);
  776. }
  777. internal static void EmitHasValue(this ILGenerator il, Type nullableType) {
  778. MethodInfo mi = nullableType.GetMethod("get_HasValue", BindingFlags.Instance | BindingFlags.Public);
  779. Debug.Assert(nullableType.IsValueType);
  780. il.Emit(OpCodes.Call, mi);
  781. }
  782. internal static void EmitGetValue(this ILGenerator il, Type nullableType) {
  783. MethodInfo mi = nullableType.GetMethod("get_Value", BindingFlags.Instance | BindingFlags.Public);
  784. Debug.Assert(nullableType.IsValueType);
  785. il.Emit(OpCodes.Call, mi);
  786. }
  787. internal static void EmitGetValueOrDefault(this ILGenerator il, Type nullableType) {
  788. MethodInfo mi = nullableType.GetMethod("GetValueOrDefault", System.Type.EmptyTypes);
  789. Debug.Assert(nullableType.IsValueType);
  790. il.Emit(OpCodes.Call, mi);
  791. }
  792. #endregion
  793. #region Arrays
  794. /// <summary>
  795. /// Emits an array of constant values provided in the given list.
  796. /// The array is strongly typed.
  797. /// </summary>
  798. internal static void EmitArray<T>(this ILGenerator il, IList<T> items) {
  799. ContractUtils.RequiresNotNull(items, "items");
  800. il.EmitInt(items.Count);
  801. il.Emit(OpCodes.Newarr, typeof(T));
  802. for (int i = 0; i < items.Count; i++) {
  803. il.Emit(OpCodes.Dup);
  804. il.EmitInt(i);
  805. il.EmitConstant(items[i], typeof(T));
  806. il.EmitStoreElement(typeof(T));
  807. }
  808. }
  809. /// <summary>
  810. /// Emits an array of values of count size. The items are emitted via the callback
  811. /// which is provided with the current item index to emit.
  812. /// </summary>
  813. internal static void EmitArray(this ILGenerator il, Type elementType, int count, Action<int> emit) {
  814. ContractUtils.RequiresNotNull(elementType, "elementType");
  815. ContractUtils.RequiresNotNull(emit, "emit");
  816. ContractUtils.Requires(count >= 0, "count", Strings.CountCannotBeNegative);
  817. il.EmitInt(count);
  818. il.Emit(OpCodes.Newarr, elementType);
  819. for (int i = 0; i < count; i++) {
  820. il.Emit(OpCodes.Dup);
  821. il.EmitInt(i);
  822. emit(i);
  823. il.EmitStoreElement(elementType);
  824. }
  825. }
  826. /// <summary>
  827. /// Emits an array construction code.
  828. /// The code assumes that bounds for all dimensions
  829. /// are already emitted.
  830. /// </summary>
  831. internal static void EmitArray(this ILGenerator il, Type arrayType) {
  832. ContractUtils.RequiresNotNull(arrayType, "arrayType");
  833. ContractUtils.Requires(arrayType.IsArray, "arrayType", Strings.ArrayTypeMustBeArray);
  834. int rank = arrayType.GetArrayRank();
  835. if (rank == 1) {
  836. il.Emit(OpCodes.Newarr, arrayType.GetElementType());
  837. } else {
  838. Type[] types = new Type[rank];
  839. for (int i = 0; i < rank; i++) {
  840. types[i] = typeof(int);
  841. }
  842. il. EmitNew(arrayType, types);
  843. }
  844. }
  845. #endregion
  846. #region Support for emitting constants
  847. internal static void EmitDecimal(this ILGenerator il, decimal value) {
  848. if (Decimal.Truncate(value) == value) {
  849. if (Int32.MinValue <= value && value <= Int32.MaxValue) {
  850. int intValue = Decimal.ToInt32(value);
  851. il.EmitInt(intValue);
  852. il.EmitNew(typeof(Decimal).GetConstructor(new Type[] { typeof(int) }));
  853. } else if (Int64.MinValue <= value && value <= Int64.MaxValue) {
  854. long longValue = Decimal.ToInt64(value);
  855. il.EmitLong(longValue);
  856. il.EmitNew(typeof(Decimal).GetConstructor(new Type[] { typeof(long) }));
  857. } else {
  858. il.EmitDecimalBits(value);
  859. }
  860. } else {
  861. il.EmitDecimalBits(value);
  862. }
  863. }
  864. private static void EmitDecimalBits(this ILGenerator il, decimal value) {
  865. int[] bits = Decimal.GetBits(value);
  866. il.EmitInt(bits[0]);
  867. il.EmitInt(bits[1]);
  868. il.EmitInt(bits[2]);
  869. il.EmitBoolean((bits[3] & 0x80000000) != 0);
  870. il.EmitByte((byte)(bits[3] >> 16));
  871. il.EmitNew(typeof(decimal).GetConstructor(new Type[] { typeof(int), typeof(int), typeof(int), typeof(bool), typeof(byte) }));
  872. }
  873. /// <summary>
  874. /// Emits default(T)
  875. /// Semantics match C# compiler behavior
  876. /// </summary>
  877. internal static void EmitDefault(this ILGenerator il, Type type) {
  878. switch (Type.GetTypeCode(type)) {
  879. case TypeCode.Object:
  880. case TypeCode.DateTime:
  881. if (type.IsValueType) {
  882. // Type.GetTypeCode on an enum returns the underlying
  883. // integer TypeCode, so we won't get here.
  884. Debug.Assert(!type.IsEnum);
  885. // This is the IL for default(T) if T is a generic type
  886. // parameter, so it should work for any type. It's also
  887. // the standard pattern for structs.
  888. LocalBuilder lb = il.DeclareLocal(type);
  889. il.Emit(OpCodes.Ldloca, lb);
  890. il.Emit(OpCodes.Initobj, type);
  891. il.Emit(OpCodes.Ldloc, lb);
  892. } else {
  893. il.Emit(OpCodes.Ldnull);
  894. }
  895. break;
  896. case TypeCode.Empty:
  897. case TypeCode.String:
  898. case TypeCode.DBNull:
  899. il.Emit(OpCodes.Ldnull);
  900. break;
  901. case TypeCode.Boolean:
  902. case TypeCode.Char:
  903. case TypeCode.SByte:
  904. case TypeCode.Byte:
  905. case TypeCode.Int16:
  906. case TypeCode.UInt16:
  907. case TypeCode.Int32:
  908. case TypeCode.UInt32:
  909. il.Emit(OpCodes.Ldc_I4_0);
  910. break;
  911. case TypeCode.Int64:
  912. case TypeCode.UInt64:
  913. il.Emit(OpCodes.Ldc_I4_0);
  914. il.Emit(OpCodes.Conv_I8);
  915. break;
  916. case TypeCode.Single:
  917. il.Emit(OpCodes.Ldc_R4, default(Single));
  918. break;
  919. case TypeCode.Double:
  920. il.Emit(OpCodes.Ldc_R8, default(Double));
  921. break;
  922. case TypeCode.Decimal:
  923. il.Emit(OpCodes.Ldc_I4_0);
  924. il.Emit(OpCodes.Newobj, typeof(Decimal).GetConstructor(new Type[] { typeof(int) }));
  925. break;
  926. default:
  927. throw ContractUtils.Unreachable;
  928. }
  929. }
  930. #endregion
  931. }
  932. }