TypeSerializer.cs 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746
  1. #if !NO_RUNTIME
  2. using System;
  3. using ProtoBuf.Meta;
  4. #if FEAT_COMPILER
  5. #endif
  6. #if FEAT_IKVM
  7. using Type = IKVM.Reflection.Type;
  8. using IKVM.Reflection;
  9. #else
  10. using System.Reflection;
  11. #endif
  12. namespace ProtoBuf.Serializers
  13. {
  14. sealed class TypeSerializer : IProtoTypeSerializer
  15. {
  16. public bool HasCallbacks(TypeModel.CallbackType callbackType) {
  17. if(callbacks != null && callbacks[callbackType] != null) return true;
  18. for (int i = 0; i < serializers.Length; i++)
  19. {
  20. if (serializers[i].ExpectedType != forType && ((IProtoTypeSerializer)serializers[i]).HasCallbacks(callbackType)) return true;
  21. }
  22. return false;
  23. }
  24. private readonly Type forType, constructType;
  25. #if WINRT || COREFX
  26. private readonly TypeInfo typeInfo;
  27. #endif
  28. public Type ExpectedType { get { return forType; } }
  29. private readonly IProtoSerializer[] serializers;
  30. private readonly int[] fieldNumbers;
  31. private readonly bool isRootType, useConstructor, isExtensible, hasConstructor;
  32. private readonly CallbackSet callbacks;
  33. private readonly MethodInfo[] baseCtorCallbacks;
  34. private readonly MethodInfo factory;
  35. public TypeSerializer(TypeModel model, Type forType, int[] fieldNumbers, IProtoSerializer[] serializers, MethodInfo[] baseCtorCallbacks, bool isRootType, bool useConstructor, CallbackSet callbacks, Type constructType, MethodInfo factory)
  36. {
  37. Helpers.DebugAssert(forType != null);
  38. Helpers.DebugAssert(fieldNumbers != null);
  39. Helpers.DebugAssert(serializers != null);
  40. Helpers.DebugAssert(fieldNumbers.Length == serializers.Length);
  41. Helpers.Sort(fieldNumbers, serializers);
  42. bool hasSubTypes = false;
  43. for (int i = 1; i < fieldNumbers.Length; i++)
  44. {
  45. if (fieldNumbers[i] == fieldNumbers[i - 1]) throw new InvalidOperationException("Duplicate field-number detected; " +
  46. fieldNumbers[i].ToString() + " on: " + forType.FullName);
  47. if(!hasSubTypes && serializers[i].ExpectedType != forType)
  48. {
  49. hasSubTypes = true;
  50. }
  51. }
  52. this.forType = forType;
  53. this.factory = factory;
  54. #if WINRT || COREFX
  55. this.typeInfo = forType.GetTypeInfo();
  56. #endif
  57. if (constructType == null)
  58. {
  59. constructType = forType;
  60. }
  61. else
  62. {
  63. #if WINRT || COREFX
  64. if (!typeInfo.IsAssignableFrom(constructType.GetTypeInfo()))
  65. #else
  66. if (!forType.IsAssignableFrom(constructType))
  67. #endif
  68. {
  69. throw new InvalidOperationException(forType.FullName + " cannot be assigned from "+ constructType.FullName);
  70. }
  71. }
  72. this.constructType = constructType;
  73. this.serializers = serializers;
  74. this.fieldNumbers = fieldNumbers;
  75. this.callbacks = callbacks;
  76. this.isRootType = isRootType;
  77. this.useConstructor = useConstructor;
  78. if (baseCtorCallbacks != null && baseCtorCallbacks.Length == 0) baseCtorCallbacks = null;
  79. this.baseCtorCallbacks = baseCtorCallbacks;
  80. #if !NO_GENERICS
  81. if (Helpers.GetUnderlyingType(forType) != null)
  82. {
  83. throw new ArgumentException("Cannot create a TypeSerializer for nullable types", "forType");
  84. }
  85. #endif
  86. #if WINRT || COREFX
  87. if (iextensible.IsAssignableFrom(typeInfo))
  88. {
  89. if (typeInfo.IsValueType || !isRootType || hasSubTypes)
  90. #else
  91. if (model.MapType(iextensible).IsAssignableFrom(forType))
  92. {
  93. if (forType.IsValueType || !isRootType || hasSubTypes)
  94. #endif
  95. {
  96. throw new NotSupportedException("IExtensible is not supported in structs or classes with inheritance");
  97. }
  98. isExtensible = true;
  99. }
  100. #if WINRT || COREFX
  101. TypeInfo constructTypeInfo = constructType.GetTypeInfo();
  102. hasConstructor = !constructTypeInfo.IsAbstract && Helpers.GetConstructor(constructTypeInfo, Helpers.EmptyTypes, true) != null;
  103. #else
  104. hasConstructor = !constructType.IsAbstract && Helpers.GetConstructor(constructType, Helpers.EmptyTypes, true) != null;
  105. #endif
  106. if (constructType != forType && useConstructor && !hasConstructor)
  107. {
  108. throw new ArgumentException("The supplied default implementation cannot be created: " + constructType.FullName, "constructType");
  109. }
  110. }
  111. #if WINRT || COREFX
  112. private static readonly TypeInfo iextensible = typeof(IExtensible).GetTypeInfo();
  113. #else
  114. private static readonly System.Type iextensible = typeof(IExtensible);
  115. #endif
  116. private bool CanHaveInheritance
  117. {
  118. get {
  119. #if WINRT || COREFX
  120. return (typeInfo.IsClass || typeInfo.IsInterface) && !typeInfo.IsSealed;
  121. #else
  122. return (forType.IsClass || forType.IsInterface) && !forType.IsSealed;
  123. #endif
  124. }
  125. }
  126. bool IProtoTypeSerializer.CanCreateInstance() { return true; }
  127. #if !FEAT_IKVM
  128. object IProtoTypeSerializer.CreateInstance(ProtoReader source)
  129. {
  130. return CreateInstance(source, false);
  131. }
  132. public void Callback(object value, TypeModel.CallbackType callbackType, SerializationContext context)
  133. {
  134. if (callbacks != null) InvokeCallback(callbacks[callbackType], value, context);
  135. IProtoTypeSerializer ser = (IProtoTypeSerializer)GetMoreSpecificSerializer(value);
  136. if (ser != null) ser.Callback(value, callbackType, context);
  137. }
  138. private IProtoSerializer GetMoreSpecificSerializer(object value)
  139. {
  140. if (!CanHaveInheritance) return null;
  141. Type actualType = value.GetType();
  142. if (actualType == forType) return null;
  143. for (int i = 0; i < serializers.Length; i++)
  144. {
  145. IProtoSerializer ser = serializers[i];
  146. if (ser.ExpectedType != forType && Helpers.IsAssignableFrom(ser.ExpectedType, actualType))
  147. {
  148. return ser;
  149. }
  150. }
  151. if (actualType == constructType) return null; // needs to be last in case the default concrete type is also a known sub-type
  152. TypeModel.ThrowUnexpectedSubtype(forType, actualType); // might throw (if not a proxy)
  153. return null;
  154. }
  155. public void Write(object value, ProtoWriter dest)
  156. {
  157. if (isRootType) Callback(value, TypeModel.CallbackType.BeforeSerialize, dest.Context);
  158. // write inheritance first
  159. IProtoSerializer next = GetMoreSpecificSerializer(value);
  160. if (next != null) next.Write(value, dest);
  161. // write all actual fields
  162. //Helpers.DebugWriteLine(">> Writing fields for " + forType.FullName);
  163. for (int i = 0; i < serializers.Length; i++)
  164. {
  165. IProtoSerializer ser = serializers[i];
  166. if (ser.ExpectedType == forType)
  167. {
  168. //Helpers.DebugWriteLine(": " + ser.ToString());
  169. ser.Write(value, dest);
  170. }
  171. }
  172. //Helpers.DebugWriteLine("<< Writing fields for " + forType.FullName);
  173. if (isExtensible) ProtoWriter.AppendExtensionData((IExtensible)value, dest);
  174. if (isRootType) Callback(value, TypeModel.CallbackType.AfterSerialize, dest.Context);
  175. }
  176. public object Read(object value, ProtoReader source)
  177. {
  178. if (isRootType && value != null) { Callback(value, TypeModel.CallbackType.BeforeDeserialize, source.Context); }
  179. int fieldNumber, lastFieldNumber = 0, lastFieldIndex = 0;
  180. bool fieldHandled;
  181. //Helpers.DebugWriteLine(">> Reading fields for " + forType.FullName);
  182. while ((fieldNumber = source.ReadFieldHeader()) > 0)
  183. {
  184. fieldHandled = false;
  185. if (fieldNumber < lastFieldNumber)
  186. {
  187. lastFieldNumber = lastFieldIndex = 0;
  188. }
  189. for (int i = lastFieldIndex; i < fieldNumbers.Length; i++)
  190. {
  191. if (fieldNumbers[i] == fieldNumber)
  192. {
  193. IProtoSerializer ser = serializers[i];
  194. //Helpers.DebugWriteLine(": " + ser.ToString());
  195. Type serType = ser.ExpectedType;
  196. if (value == null)
  197. {
  198. if (serType == forType) value = CreateInstance(source, true);
  199. }
  200. else
  201. {
  202. if (serType != forType && ((IProtoTypeSerializer)ser).CanCreateInstance()
  203. && serType
  204. #if WINRT || COREFX
  205. .GetTypeInfo()
  206. #endif
  207. .IsSubclassOf(value.GetType()))
  208. {
  209. value = ProtoReader.Merge(source, value, ((IProtoTypeSerializer)ser).CreateInstance(source));
  210. }
  211. }
  212. if (ser.ReturnsValue) {
  213. value = ser.Read(value, source);
  214. } else { // pop
  215. ser.Read(value, source);
  216. }
  217. lastFieldIndex = i;
  218. lastFieldNumber = fieldNumber;
  219. fieldHandled = true;
  220. break;
  221. }
  222. }
  223. if (!fieldHandled)
  224. {
  225. //Helpers.DebugWriteLine(": [" + fieldNumber + "] (unknown)");
  226. if (value == null) value = CreateInstance(source, true);
  227. if (isExtensible) {
  228. source.AppendExtensionData((IExtensible)value);
  229. } else {
  230. source.SkipField();
  231. }
  232. }
  233. }
  234. //Helpers.DebugWriteLine("<< Reading fields for " + forType.FullName);
  235. if(value == null) value = CreateInstance(source, true);
  236. if (isRootType) { Callback(value, TypeModel.CallbackType.AfterDeserialize, source.Context); }
  237. return value;
  238. }
  239. private object InvokeCallback(MethodInfo method, object obj, SerializationContext context)
  240. {
  241. object result = null;
  242. object[] args;
  243. if (method != null)
  244. { // pass in a streaming context if one is needed, else null
  245. bool handled;
  246. ParameterInfo[] parameters = method.GetParameters();
  247. switch (parameters.Length)
  248. {
  249. case 0:
  250. args = null;
  251. handled = true;
  252. break;
  253. default:
  254. args = new object[parameters.Length];
  255. handled = true;
  256. for (int i = 0; i < args.Length; i++)
  257. {
  258. object val;
  259. Type paramType = parameters[i].ParameterType;
  260. if (paramType == typeof(SerializationContext)) val = context;
  261. else if (paramType == typeof(System.Type)) val = constructType;
  262. #if PLAT_BINARYFORMATTER || (SILVERLIGHT && NET_4_0)
  263. else if (paramType == typeof(System.Runtime.Serialization.StreamingContext)) val = (System.Runtime.Serialization.StreamingContext)context;
  264. #endif
  265. else
  266. {
  267. val = null;
  268. handled = false;
  269. }
  270. args[i] = val;
  271. }
  272. break;
  273. }
  274. if(handled)
  275. {
  276. result = method.Invoke(obj, args);
  277. }
  278. else
  279. {
  280. throw Meta.CallbackSet.CreateInvalidCallbackSignature(method);
  281. }
  282. }
  283. return result;
  284. }
  285. object CreateInstance(ProtoReader source, bool includeLocalCallback)
  286. {
  287. //Helpers.DebugWriteLine("* creating : " + forType.FullName);
  288. object obj;
  289. if (factory != null)
  290. {
  291. obj = InvokeCallback(factory, null, source.Context);
  292. }
  293. else if (useConstructor)
  294. {
  295. if (!hasConstructor) TypeModel.ThrowCannotCreateInstance(constructType);
  296. obj = Activator.CreateInstance(constructType
  297. #if !(CF || SILVERLIGHT || WINRT || PORTABLE || NETSTANDARD1_3 || NETSTANDARD1_4)
  298. , nonPublic: true
  299. #endif
  300. );
  301. }
  302. else
  303. {
  304. obj = BclHelpers.GetUninitializedObject(constructType);
  305. }
  306. ProtoReader.NoteObject(obj, source);
  307. if (baseCtorCallbacks != null) {
  308. for (int i = 0; i < baseCtorCallbacks.Length; i++) {
  309. InvokeCallback(baseCtorCallbacks[i], obj, source.Context);
  310. }
  311. }
  312. if (includeLocalCallback && callbacks != null) InvokeCallback(callbacks.BeforeDeserialize, obj, source.Context);
  313. return obj;
  314. }
  315. #endif
  316. bool IProtoSerializer.RequiresOldValue { get { return true; } }
  317. bool IProtoSerializer.ReturnsValue { get { return false; } } // updates field directly
  318. #if FEAT_COMPILER
  319. void IProtoSerializer.EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom)
  320. {
  321. Type expected = ExpectedType;
  322. using (Compiler.Local loc = ctx.GetLocalWithValue(expected, valueFrom))
  323. {
  324. // pre-callbacks
  325. EmitCallbackIfNeeded(ctx, loc, TypeModel.CallbackType.BeforeSerialize);
  326. Compiler.CodeLabel startFields = ctx.DefineLabel();
  327. // inheritance
  328. if (CanHaveInheritance)
  329. {
  330. for (int i = 0; i < serializers.Length; i++)
  331. {
  332. IProtoSerializer ser = serializers[i];
  333. Type serType = ser.ExpectedType;
  334. if (serType != forType)
  335. {
  336. Compiler.CodeLabel ifMatch = ctx.DefineLabel(), nextTest = ctx.DefineLabel();
  337. ctx.LoadValue(loc);
  338. ctx.TryCast(serType);
  339. ctx.CopyValue();
  340. ctx.BranchIfTrue(ifMatch, true);
  341. ctx.DiscardValue();
  342. ctx.Branch(nextTest, true);
  343. ctx.MarkLabel(ifMatch);
  344. ser.EmitWrite(ctx, null);
  345. ctx.Branch(startFields, false);
  346. ctx.MarkLabel(nextTest);
  347. }
  348. }
  349. if (constructType != null && constructType != forType)
  350. {
  351. using(Compiler.Local actualType = new Compiler.Local(ctx, ctx.MapType(typeof(System.Type))))
  352. {
  353. // would have jumped to "fields" if an expected sub-type, so two options:
  354. // a: *exactly* that type, b: an *unexpected* type
  355. ctx.LoadValue(loc);
  356. ctx.EmitCall(ctx.MapType(typeof(object)).GetMethod("GetType"));
  357. ctx.CopyValue();
  358. ctx.StoreValue(actualType);
  359. ctx.LoadValue(forType);
  360. ctx.BranchIfEqual(startFields, true);
  361. ctx.LoadValue(actualType);
  362. ctx.LoadValue(constructType);
  363. ctx.BranchIfEqual(startFields, true);
  364. }
  365. }
  366. else
  367. {
  368. // would have jumped to "fields" if an expected sub-type, so two options:
  369. // a: *exactly* that type, b: an *unexpected* type
  370. ctx.LoadValue(loc);
  371. ctx.EmitCall(ctx.MapType(typeof(object)).GetMethod("GetType"));
  372. ctx.LoadValue(forType);
  373. ctx.BranchIfEqual(startFields, true);
  374. }
  375. // unexpected, then... note that this *might* be a proxy, which
  376. // is handled by ThrowUnexpectedSubtype
  377. ctx.LoadValue(forType);
  378. ctx.LoadValue(loc);
  379. ctx.EmitCall(ctx.MapType(typeof(object)).GetMethod("GetType"));
  380. ctx.EmitCall(ctx.MapType(typeof(TypeModel)).GetMethod("ThrowUnexpectedSubtype",
  381. BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static));
  382. }
  383. // fields
  384. ctx.MarkLabel(startFields);
  385. for (int i = 0; i < serializers.Length; i++)
  386. {
  387. IProtoSerializer ser = serializers[i];
  388. if (ser.ExpectedType == forType) ser.EmitWrite(ctx, loc);
  389. }
  390. // extension data
  391. if (isExtensible)
  392. {
  393. ctx.LoadValue(loc);
  394. ctx.LoadReaderWriter();
  395. ctx.EmitCall(ctx.MapType(typeof(ProtoWriter)).GetMethod("AppendExtensionData"));
  396. }
  397. // post-callbacks
  398. EmitCallbackIfNeeded(ctx, loc, TypeModel.CallbackType.AfterSerialize);
  399. }
  400. }
  401. static void EmitInvokeCallback(Compiler.CompilerContext ctx, MethodInfo method, bool copyValue, Type constructType, Type type)
  402. {
  403. if (method != null)
  404. {
  405. if(copyValue) ctx.CopyValue(); // assumes the target is on the stack, and that we want to *retain* it on the stack
  406. ParameterInfo[] parameters = method.GetParameters();
  407. bool handled = true;
  408. for (int i = 0; i < parameters.Length; i++)
  409. {
  410. Type parameterType = parameters[0].ParameterType;
  411. if (parameterType == ctx.MapType(typeof(SerializationContext)))
  412. {
  413. ctx.LoadSerializationContext();
  414. }
  415. else if (parameterType == ctx.MapType(typeof(System.Type)))
  416. {
  417. Type tmp = constructType;
  418. if (tmp == null) tmp = type; // no ?? in some C# profiles
  419. ctx.LoadValue(tmp);
  420. }
  421. #if PLAT_BINARYFORMATTER
  422. else if (parameterType == ctx.MapType(typeof(System.Runtime.Serialization.StreamingContext)))
  423. {
  424. ctx.LoadSerializationContext();
  425. MethodInfo op = ctx.MapType(typeof(SerializationContext)).GetMethod("op_Implicit", new Type[] { ctx.MapType(typeof(SerializationContext)) });
  426. if (op != null)
  427. { // it isn't always! (framework versions, etc)
  428. ctx.EmitCall(op);
  429. handled = true;
  430. }
  431. }
  432. #endif
  433. else
  434. {
  435. handled = false;
  436. }
  437. }
  438. if (handled)
  439. {
  440. ctx.EmitCall(method);
  441. if (constructType != null)
  442. {
  443. if (method.ReturnType == ctx.MapType(typeof(object)))
  444. {
  445. ctx.CastFromObject(type);
  446. }
  447. }
  448. }
  449. else
  450. {
  451. throw Meta.CallbackSet.CreateInvalidCallbackSignature(method);
  452. }
  453. }
  454. }
  455. private void EmitCallbackIfNeeded(Compiler.CompilerContext ctx, Compiler.Local valueFrom, TypeModel.CallbackType callbackType) {
  456. Helpers.DebugAssert(valueFrom != null);
  457. if (isRootType && ((IProtoTypeSerializer)this).HasCallbacks(callbackType))
  458. {
  459. ((IProtoTypeSerializer)this).EmitCallback(ctx, valueFrom, callbackType);
  460. }
  461. }
  462. void IProtoTypeSerializer.EmitCallback(Compiler.CompilerContext ctx, Compiler.Local valueFrom, TypeModel.CallbackType callbackType)
  463. {
  464. bool actuallyHasInheritance = false;
  465. if (CanHaveInheritance)
  466. {
  467. for (int i = 0; i < serializers.Length; i++)
  468. {
  469. IProtoSerializer ser = serializers[i];
  470. if (ser.ExpectedType != forType && ((IProtoTypeSerializer)ser).HasCallbacks(callbackType))
  471. {
  472. actuallyHasInheritance = true;
  473. }
  474. }
  475. }
  476. Helpers.DebugAssert(((IProtoTypeSerializer)this).HasCallbacks(callbackType), "Shouldn't be calling this if there is nothing to do");
  477. MethodInfo method = callbacks == null ? null : callbacks[callbackType];
  478. if(method == null && !actuallyHasInheritance)
  479. {
  480. return;
  481. }
  482. ctx.LoadAddress(valueFrom, ExpectedType);
  483. EmitInvokeCallback(ctx, method, actuallyHasInheritance, null, forType);
  484. if (actuallyHasInheritance)
  485. {
  486. Compiler.CodeLabel @break = ctx.DefineLabel();
  487. for (int i = 0; i < serializers.Length; i++)
  488. {
  489. IProtoSerializer ser = serializers[i];
  490. IProtoTypeSerializer typeser;
  491. Type serType = ser.ExpectedType;
  492. if (serType != forType &&
  493. (typeser = (IProtoTypeSerializer) ser).HasCallbacks(callbackType))
  494. {
  495. Compiler.CodeLabel ifMatch = ctx.DefineLabel(), nextTest = ctx.DefineLabel();
  496. ctx.CopyValue();
  497. ctx.TryCast(serType);
  498. ctx.CopyValue();
  499. ctx.BranchIfTrue(ifMatch, true);
  500. ctx.DiscardValue();
  501. ctx.Branch(nextTest, false);
  502. ctx.MarkLabel(ifMatch);
  503. typeser.EmitCallback(ctx, null, callbackType);
  504. ctx.Branch(@break, false);
  505. ctx.MarkLabel(nextTest);
  506. }
  507. }
  508. ctx.MarkLabel(@break);
  509. ctx.DiscardValue();
  510. }
  511. }
  512. void IProtoSerializer.EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom)
  513. {
  514. Type expected = ExpectedType;
  515. Helpers.DebugAssert(valueFrom != null);
  516. using (Compiler.Local loc = ctx.GetLocalWithValue(expected, valueFrom))
  517. using (Compiler.Local fieldNumber = new Compiler.Local(ctx, ctx.MapType(typeof(int))))
  518. {
  519. // pre-callbacks
  520. if (HasCallbacks(TypeModel.CallbackType.BeforeDeserialize))
  521. {
  522. if(Helpers.IsValueType(ExpectedType))
  523. {
  524. EmitCallbackIfNeeded(ctx, loc, TypeModel.CallbackType.BeforeDeserialize);
  525. }
  526. else
  527. { // could be null
  528. Compiler.CodeLabel callbacksDone = ctx.DefineLabel();
  529. ctx.LoadValue(loc);
  530. ctx.BranchIfFalse(callbacksDone, false);
  531. EmitCallbackIfNeeded(ctx, loc, TypeModel.CallbackType.BeforeDeserialize);
  532. ctx.MarkLabel(callbacksDone);
  533. }
  534. }
  535. Compiler.CodeLabel @continue = ctx.DefineLabel(), processField = ctx.DefineLabel();
  536. ctx.Branch(@continue, false);
  537. ctx.MarkLabel(processField);
  538. foreach (BasicList.Group group in BasicList.GetContiguousGroups(fieldNumbers, serializers))
  539. {
  540. Compiler.CodeLabel tryNextField = ctx.DefineLabel();
  541. int groupItemCount = group.Items.Count;
  542. if (groupItemCount == 1)
  543. {
  544. // discreet group; use an equality test
  545. ctx.LoadValue(fieldNumber);
  546. ctx.LoadValue(group.First);
  547. Compiler.CodeLabel processThisField = ctx.DefineLabel();
  548. ctx.BranchIfEqual(processThisField, true);
  549. ctx.Branch(tryNextField, false);
  550. WriteFieldHandler(ctx, expected, loc, processThisField, @continue, (IProtoSerializer)group.Items[0]);
  551. }
  552. else
  553. { // implement as a jump-table-based switch
  554. ctx.LoadValue(fieldNumber);
  555. ctx.LoadValue(group.First);
  556. ctx.Subtract(); // jump-tables are zero-based
  557. Compiler.CodeLabel[] jmp = new Compiler.CodeLabel[groupItemCount];
  558. for (int i = 0; i < groupItemCount; i++) {
  559. jmp[i] = ctx.DefineLabel();
  560. }
  561. ctx.Switch(jmp);
  562. // write the default...
  563. ctx.Branch(tryNextField, false);
  564. for (int i = 0; i < groupItemCount; i++)
  565. {
  566. WriteFieldHandler(ctx, expected, loc, jmp[i], @continue, (IProtoSerializer)group.Items[i]);
  567. }
  568. }
  569. ctx.MarkLabel(tryNextField);
  570. }
  571. EmitCreateIfNull(ctx, loc);
  572. ctx.LoadReaderWriter();
  573. if (isExtensible)
  574. {
  575. ctx.LoadValue(loc);
  576. ctx.EmitCall(ctx.MapType(typeof(ProtoReader)).GetMethod("AppendExtensionData"));
  577. }
  578. else
  579. {
  580. ctx.EmitCall(ctx.MapType(typeof(ProtoReader)).GetMethod("SkipField"));
  581. }
  582. ctx.MarkLabel(@continue);
  583. ctx.EmitBasicRead("ReadFieldHeader", ctx.MapType(typeof(int)));
  584. ctx.CopyValue();
  585. ctx.StoreValue(fieldNumber);
  586. ctx.LoadValue(0);
  587. ctx.BranchIfGreater(processField, false);
  588. EmitCreateIfNull(ctx, loc);
  589. // post-callbacks
  590. EmitCallbackIfNeeded(ctx, loc, TypeModel.CallbackType.AfterDeserialize);
  591. if (valueFrom != null && !loc.IsSame(valueFrom))
  592. {
  593. ctx.LoadValue(loc);
  594. ctx.Cast(valueFrom.Type);
  595. ctx.StoreValue(valueFrom);
  596. }
  597. }
  598. }
  599. private void WriteFieldHandler(
  600. Compiler.CompilerContext ctx, Type expected, Compiler.Local loc,
  601. Compiler.CodeLabel handler, Compiler.CodeLabel @continue, IProtoSerializer serializer)
  602. {
  603. ctx.MarkLabel(handler);
  604. Type serType = serializer.ExpectedType;
  605. if (serType == forType) {
  606. EmitCreateIfNull(ctx, loc);
  607. serializer.EmitRead(ctx, loc);
  608. }
  609. else {
  610. //RuntimeTypeModel rtm = (RuntimeTypeModel)ctx.Model;
  611. if (((IProtoTypeSerializer)serializer).CanCreateInstance())
  612. {
  613. Compiler.CodeLabel allDone = ctx.DefineLabel();
  614. ctx.LoadValue(loc);
  615. ctx.BranchIfFalse(allDone, false); // null is always ok
  616. ctx.LoadValue(loc);
  617. ctx.TryCast(serType);
  618. ctx.BranchIfTrue(allDone, false); // not null, but of the correct type
  619. // otherwise, need to convert it
  620. ctx.LoadReaderWriter();
  621. ctx.LoadValue(loc);
  622. ((IProtoTypeSerializer)serializer).EmitCreateInstance(ctx);
  623. ctx.EmitCall(ctx.MapType(typeof(ProtoReader)).GetMethod("Merge"));
  624. ctx.Cast(expected);
  625. ctx.StoreValue(loc); // Merge always returns a value
  626. // nothing needs doing
  627. ctx.MarkLabel(allDone);
  628. }
  629. ctx.LoadValue(loc);
  630. ctx.Cast(serType);
  631. serializer.EmitRead(ctx, null);
  632. }
  633. if (serializer.ReturnsValue)
  634. { // update the variable
  635. ctx.StoreValue(loc);
  636. }
  637. ctx.Branch(@continue, false); // "continue"
  638. }
  639. void IProtoTypeSerializer.EmitCreateInstance(Compiler.CompilerContext ctx)
  640. {
  641. // different ways of creating a new instance
  642. bool callNoteObject = true;
  643. if (factory != null)
  644. {
  645. EmitInvokeCallback(ctx, factory, false, constructType, forType);
  646. }
  647. else if (!useConstructor)
  648. { // DataContractSerializer style
  649. ctx.LoadValue(constructType);
  650. ctx.EmitCall(ctx.MapType(typeof(BclHelpers)).GetMethod("GetUninitializedObject"));
  651. ctx.Cast(forType);
  652. }
  653. else if (Helpers.IsClass(constructType) && hasConstructor)
  654. { // XmlSerializer style
  655. ctx.EmitCtor(constructType);
  656. }
  657. else
  658. {
  659. ctx.LoadValue(ExpectedType);
  660. ctx.EmitCall(ctx.MapType(typeof(TypeModel)).GetMethod("ThrowCannotCreateInstance",
  661. BindingFlags.Static | BindingFlags.Public));
  662. ctx.LoadNullRef();
  663. callNoteObject = false;
  664. }
  665. if (callNoteObject)
  666. {
  667. // track root object creation
  668. ctx.CopyValue();
  669. ctx.LoadReaderWriter();
  670. ctx.EmitCall(ctx.MapType(typeof(ProtoReader)).GetMethod("NoteObject",
  671. BindingFlags.Static | BindingFlags.Public));
  672. }
  673. if (baseCtorCallbacks != null)
  674. {
  675. for (int i = 0; i < baseCtorCallbacks.Length; i++)
  676. {
  677. EmitInvokeCallback(ctx, baseCtorCallbacks[i], true, null, forType);
  678. }
  679. }
  680. }
  681. private void EmitCreateIfNull(Compiler.CompilerContext ctx, Compiler.Local storage)
  682. {
  683. Helpers.DebugAssert(storage != null);
  684. if (!Helpers.IsValueType(ExpectedType))
  685. {
  686. Compiler.CodeLabel afterNullCheck = ctx.DefineLabel();
  687. ctx.LoadValue(storage);
  688. ctx.BranchIfTrue(afterNullCheck, false);
  689. ((IProtoTypeSerializer)this).EmitCreateInstance(ctx);
  690. if (callbacks != null) EmitInvokeCallback(ctx, callbacks.BeforeDeserialize, true, null, forType);
  691. ctx.StoreValue(storage);
  692. ctx.MarkLabel(afterNullCheck);
  693. }
  694. }
  695. #endif
  696. }
  697. }
  698. #endif