1 
2 //
3 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining
6 // a copy of this software and associated documentation files (the
7 // "Software"), to deal in the Software without restriction, including
8 // without limitation the rights to use, copy, modify, merge, publish,
9 // distribute, sublicense, and/or sell copies of the Software, and to
10 // permit persons to whom the Software is furnished to do so, subject to
11 // the following conditions:
12 //
13 // The above copyright notice and this permission notice shall be
14 // included in all copies or substantial portions of the Software.
15 //
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 //
24 
25 //
26 // System.Reflection.Emit/ILGenerator.cs
27 //
28 // Author:
29 //   Paolo Molaro (lupus@ximian.com)
30 //
31 // (C) 2001 Ximian, Inc.  http://www.ximian.com
32 //
33 
34 #if !FULL_AOT_RUNTIME
35 using System;
36 using System.Collections;
37 using System.Collections.Generic;
38 using System.Diagnostics.SymbolStore;
39 using System.Runtime.InteropServices;
40 
41 namespace System.Reflection.Emit {
42 
43 	internal struct ILExceptionBlock {
44 		public const int CATCH = 0;
45 		public const int FILTER = 1;
46 		public const int FINALLY = 2;
47 		public const int FAULT = 4;
48 		public const int FILTER_START = -1;
49 
50 		internal Type extype;
51 		internal int type;
52 		internal int start;
53 		internal int len;
54 		internal int filter_offset;
55 
DebugSystem.Reflection.Emit.ILExceptionBlock56 		internal void Debug () {
57 #if NO
58 			System.Console.Write ("\ttype="+type.ToString()+" start="+start.ToString()+" len="+len.ToString());
59 			if (extype != null)
60 				System.Console.WriteLine (" extype="+extype.ToString());
61 			else
62 				System.Console.WriteLine (String.Empty);
63 #endif
64 		}
65 	}
66 	internal struct ILExceptionInfo {
67 #pragma warning disable 169
68 #pragma warning disable 414
69 		internal ILExceptionBlock[] handlers;
70 		internal int start;
71 		internal int len;
72 		internal Label end;
73 #pragma warning restore 169
74 #pragma warning restore 414
75 
NumHandlersSystem.Reflection.Emit.ILExceptionInfo76 		internal int NumHandlers ()
77 		{
78 			return handlers.Length;
79 		}
80 
AddCatchSystem.Reflection.Emit.ILExceptionInfo81 		internal void AddCatch (Type extype, int offset)
82 		{
83 			int i;
84 			End (offset);
85 			add_block (offset);
86 			i = handlers.Length - 1;
87 			handlers [i].type = ILExceptionBlock.CATCH;
88 			handlers [i].start = offset;
89 			handlers [i].extype = extype;
90 		}
91 
AddFinallySystem.Reflection.Emit.ILExceptionInfo92 		internal void AddFinally (int offset)
93 		{
94 			int i;
95 			End (offset);
96 			add_block (offset);
97 			i = handlers.Length - 1;
98 			handlers [i].type = ILExceptionBlock.FINALLY;
99 			handlers [i].start = offset;
100 			handlers [i].extype = null;
101 		}
102 
AddFaultSystem.Reflection.Emit.ILExceptionInfo103 		internal void AddFault (int offset)
104 		{
105 			int i;
106 			End (offset);
107 			add_block (offset);
108 			i = handlers.Length - 1;
109 			handlers [i].type = ILExceptionBlock.FAULT;
110 			handlers [i].start = offset;
111 			handlers [i].extype = null;
112 		}
113 
AddFilterSystem.Reflection.Emit.ILExceptionInfo114 		internal void AddFilter (int offset)
115 		{
116 			int i;
117 			End (offset);
118 			add_block (offset);
119 			i = handlers.Length - 1;
120 			handlers [i].type = ILExceptionBlock.FILTER_START;
121 			handlers [i].extype = null;
122 			handlers [i].filter_offset = offset;
123 		}
124 
EndSystem.Reflection.Emit.ILExceptionInfo125 		internal void End (int offset)
126 		{
127 			if (handlers == null)
128 				return;
129 			int i = handlers.Length - 1;
130 			if (i >= 0)
131 				handlers [i].len = offset - handlers [i].start;
132 		}
133 
LastClauseTypeSystem.Reflection.Emit.ILExceptionInfo134 		internal int LastClauseType ()
135 		{
136 			if (handlers != null)
137 				return handlers [handlers.Length-1].type;
138 			else
139 				return ILExceptionBlock.CATCH;
140 		}
141 
PatchFilterClauseSystem.Reflection.Emit.ILExceptionInfo142 		internal void PatchFilterClause (int start)
143 		{
144 			if (handlers != null && handlers.Length > 0) {
145 				handlers [handlers.Length - 1].start = start;
146 				handlers [handlers.Length - 1].type = ILExceptionBlock.FILTER;
147 			}
148 		}
149 
DebugSystem.Reflection.Emit.ILExceptionInfo150 		internal void Debug (int b)
151 		{
152 #if NO
153 			System.Console.WriteLine ("Handler {0} at {1}, len: {2}", b, start, len);
154 			for (int i = 0; i < handlers.Length; ++i)
155 				handlers [i].Debug ();
156 #endif
157 		}
158 
add_blockSystem.Reflection.Emit.ILExceptionInfo159 		void add_block (int offset)
160 		{
161 			if (handlers != null) {
162 				int i = handlers.Length;
163 				ILExceptionBlock[] new_b = new ILExceptionBlock [i + 1];
164 				System.Array.Copy (handlers, new_b, i);
165 				handlers = new_b;
166 				handlers [i].len = offset - handlers [i].start;
167 			} else {
168 				handlers = new ILExceptionBlock [1];
169 				len = offset - start;
170 			}
171 		}
172 	}
173 
174 	internal struct ILTokenInfo {
175 		public MemberInfo member;
176 		public int code_pos;
177 	}
178 
179 	internal interface TokenGenerator {
GetToken(string str)180 		int GetToken (string str);
181 
GetToken(MemberInfo member, bool create_open_instance)182 		int GetToken (MemberInfo member, bool create_open_instance);
183 
GetToken(MethodBase method, Type[] opt_param_types)184 		int GetToken (MethodBase method, Type[] opt_param_types);
185 
GetToken(SignatureHelper helper)186 		int GetToken (SignatureHelper helper);
187 	}
188 
189 	[ComVisible (true)]
190 	[ComDefaultInterface (typeof (_ILGenerator))]
191 	[ClassInterface (ClassInterfaceType.None)]
192 	[StructLayout (LayoutKind.Sequential)]
193 	public class ILGenerator: _ILGenerator {
194 		private struct LabelFixup {
195 			public int offset;    // The number of bytes between pos and the
196 							      // offset of the jump
197 			public int pos;	      // Where offset of the label is placed
198 			public int label_idx; // The label to jump to
199 		};
200 
201 		struct LabelData {
LabelDataSystem.Reflection.Emit.ILGenerator.LabelData202 			public LabelData (int addr, int maxStack)
203 			{
204 				this.addr = addr;
205 				this.maxStack = maxStack;
206 			}
207 
208 			public int addr;
209 			public int maxStack;
210 		}
211 
212 		#region Sync with reflection.h
213 		private byte[] code;
214 		private int code_len;
215 		private int max_stack;
216 		private int cur_stack;
217 		private LocalBuilder[] locals;
218 		private ILExceptionInfo[] ex_handlers;
219 		private int num_token_fixups;
220 		private ILTokenInfo[] token_fixups;
221 		#endregion
222 
223 		private LabelData [] labels;
224 		private int num_labels;
225 		private LabelFixup[] fixups;
226 		private int num_fixups;
227 		internal Module module;
228 		private int cur_block;
229 		private Stack open_blocks;
230 		private TokenGenerator token_gen;
231 
232 		const int defaultFixupSize = 4;
233 		const int defaultLabelsSize = 4;
234 		const int defaultExceptionStackSize = 2;
235 
236 		ArrayList sequencePointLists;
237 		SequencePointList currentSequence;
238 
ILGenerator(Module m, TokenGenerator token_gen, int size)239 		internal ILGenerator (Module m, TokenGenerator token_gen, int size)
240 		{
241 			if (size < 0)
242 				size = 128;
243 			code = new byte [size];
244 			token_fixups = new ILTokenInfo [8];
245 			module = m;
246 			this.token_gen = token_gen;
247 		}
248 
add_token_fixup(MemberInfo mi)249 		private void add_token_fixup (MemberInfo mi)
250 		{
251 			if (num_token_fixups == token_fixups.Length) {
252 				ILTokenInfo[] ntf = new ILTokenInfo [num_token_fixups * 2];
253 				token_fixups.CopyTo (ntf, 0);
254 				token_fixups = ntf;
255 			}
256 			token_fixups [num_token_fixups].member = mi;
257 			token_fixups [num_token_fixups++].code_pos = code_len;
258 		}
259 
make_room(int nbytes)260 		private void make_room (int nbytes)
261 		{
262 			if (code_len + nbytes < code.Length)
263 				return;
264 			byte[] new_code = new byte [(code_len + nbytes) * 2 + 128];
265 			System.Array.Copy (code, 0, new_code, 0, code.Length);
266 			code = new_code;
267 		}
268 
emit_int(int val)269 		private void emit_int (int val)
270 		{
271 			code [code_len++] = (byte) (val & 0xFF);
272 			code [code_len++] = (byte) ((val >> 8) & 0xFF);
273 			code [code_len++] = (byte) ((val >> 16) & 0xFF);
274 			code [code_len++] = (byte) ((val >> 24) & 0xFF);
275 		}
276 
277 		/* change to pass by ref to avoid copy */
ll_emit(OpCode opcode)278 		private void ll_emit (OpCode opcode)
279 		{
280 			/*
281 			 * there is already enough room allocated in code.
282 			 */
283 			// access op1 and op2 directly since the Value property is useless
284 			if (opcode.Size == 2)
285 				code [code_len++] = opcode.op1;
286 			code [code_len++] = opcode.op2;
287 			/*
288 			 * We should probably keep track of stack needs here.
289 			 * Or we may want to run the verifier on the code before saving it
290 			 * (this may be needed anyway when the ILGenerator is not used...).
291 			 */
292 			switch (opcode.StackBehaviourPush) {
293 			case StackBehaviour.Push1:
294 			case StackBehaviour.Pushi:
295 			case StackBehaviour.Pushi8:
296 			case StackBehaviour.Pushr4:
297 			case StackBehaviour.Pushr8:
298 			case StackBehaviour.Pushref:
299 			case StackBehaviour.Varpush: /* again we are conservative and assume it pushes 1 */
300 				cur_stack ++;
301 				break;
302 			case StackBehaviour.Push1_push1:
303 				cur_stack += 2;
304 				break;
305 			}
306 			if (max_stack < cur_stack)
307 				max_stack = cur_stack;
308 
309 			/*
310 			 * Note that we adjust for the pop behaviour _after_ setting max_stack.
311 			 */
312 			switch (opcode.StackBehaviourPop) {
313 			case StackBehaviour.Varpop:
314 				break; /* we are conservative and assume it doesn't decrease the stack needs */
315 			case StackBehaviour.Pop1:
316 			case StackBehaviour.Popi:
317 			case StackBehaviour.Popref:
318 				cur_stack --;
319 				break;
320 			case StackBehaviour.Pop1_pop1:
321 			case StackBehaviour.Popi_pop1:
322 			case StackBehaviour.Popi_popi:
323 			case StackBehaviour.Popi_popi8:
324 			case StackBehaviour.Popi_popr4:
325 			case StackBehaviour.Popi_popr8:
326 			case StackBehaviour.Popref_pop1:
327 			case StackBehaviour.Popref_popi:
328 				cur_stack -= 2;
329 				break;
330 			case StackBehaviour.Popi_popi_popi:
331 			case StackBehaviour.Popref_popi_popi:
332 			case StackBehaviour.Popref_popi_popi8:
333 			case StackBehaviour.Popref_popi_popr4:
334 			case StackBehaviour.Popref_popi_popr8:
335 			case StackBehaviour.Popref_popi_popref:
336 				cur_stack -= 3;
337 				break;
338 			}
339 		}
340 
target_len(OpCode opcode)341 		private static int target_len (OpCode opcode)
342 		{
343 			if (opcode.OperandType == OperandType.InlineBrTarget)
344 				return 4;
345 			return 1;
346 		}
347 
InternalEndClause()348 		private void InternalEndClause ()
349 		{
350 			switch (ex_handlers [cur_block].LastClauseType ()) {
351 			case ILExceptionBlock.CATCH:
352 			case ILExceptionBlock.FILTER:
353 			case ILExceptionBlock.FILTER_START:
354 				// how could we optimize code size here?
355 				Emit (OpCodes.Leave, ex_handlers [cur_block].end);
356 				break;
357 			case ILExceptionBlock.FAULT:
358 			case ILExceptionBlock.FINALLY:
359 				Emit (OpCodes.Endfinally);
360 				break;
361 			}
362 		}
363 
BeginCatchBlock(Type exceptionType)364 		public virtual void BeginCatchBlock (Type exceptionType)
365 		{
366 			if (open_blocks == null)
367 				open_blocks = new Stack (defaultExceptionStackSize);
368 
369 			if (open_blocks.Count <= 0)
370 				throw new NotSupportedException ("Not in an exception block");
371 			if (exceptionType != null && exceptionType.IsUserType)
372 				throw new NotSupportedException ("User defined subclasses of System.Type are not yet supported.");
373 			if (ex_handlers [cur_block].LastClauseType () == ILExceptionBlock.FILTER_START) {
374 				if (exceptionType != null)
375 					throw new ArgumentException ("Do not supply an exception type for filter clause");
376 				Emit (OpCodes.Endfilter);
377 				ex_handlers [cur_block].PatchFilterClause (code_len);
378 			} else {
379 				InternalEndClause ();
380 				ex_handlers [cur_block].AddCatch (exceptionType, code_len);
381 			}
382 
383 			cur_stack = 1; // the exception object is on the stack by default
384 			if (max_stack < cur_stack)
385 				max_stack = cur_stack;
386 
387 			//System.Console.WriteLine ("Begin catch Block: {0} {1}",exceptionType.ToString(), max_stack);
388 		}
389 
BeginExceptFilterBlock()390 		public virtual void BeginExceptFilterBlock ()
391 		{
392 			if (open_blocks == null)
393 				open_blocks = new Stack (defaultExceptionStackSize);
394 
395 			if (open_blocks.Count <= 0)
396 				throw new NotSupportedException ("Not in an exception block");
397 			InternalEndClause ();
398 
399 			ex_handlers [cur_block].AddFilter (code_len);
400 		}
401 
BeginExceptionBlock()402 		public virtual Label BeginExceptionBlock ()
403 		{
404 			//System.Console.WriteLine ("Begin Block");
405 			if (open_blocks == null)
406 				open_blocks = new Stack (defaultExceptionStackSize);
407 
408 			if (ex_handlers != null) {
409 				cur_block = ex_handlers.Length;
410 				ILExceptionInfo[] new_ex = new ILExceptionInfo [cur_block + 1];
411 				System.Array.Copy (ex_handlers, new_ex, cur_block);
412 				ex_handlers = new_ex;
413 			} else {
414 				ex_handlers = new ILExceptionInfo [1];
415 				cur_block = 0;
416 			}
417 			open_blocks.Push (cur_block);
418 			ex_handlers [cur_block].start = code_len;
419 			return ex_handlers [cur_block].end = DefineLabel ();
420 		}
421 
BeginFaultBlock()422 		public virtual void BeginFaultBlock()
423 		{
424 			if (open_blocks == null)
425 				open_blocks = new Stack (defaultExceptionStackSize);
426 
427 			if (open_blocks.Count <= 0)
428 				throw new NotSupportedException ("Not in an exception block");
429 
430 			if (ex_handlers [cur_block].LastClauseType () == ILExceptionBlock.FILTER_START) {
431 				Emit (OpCodes.Leave, ex_handlers [cur_block].end);
432 				ex_handlers [cur_block].PatchFilterClause (code_len);
433 			}
434 
435 			InternalEndClause ();
436 			//System.Console.WriteLine ("Begin fault Block");
437 			ex_handlers [cur_block].AddFault (code_len);
438 		}
439 
BeginFinallyBlock()440 		public virtual void BeginFinallyBlock()
441 		{
442 			if (open_blocks == null)
443 				open_blocks = new Stack (defaultExceptionStackSize);
444 
445 			if (open_blocks.Count <= 0)
446 				throw new NotSupportedException ("Not in an exception block");
447 
448 			InternalEndClause ();
449 
450 			if (ex_handlers [cur_block].LastClauseType () == ILExceptionBlock.FILTER_START) {
451 				Emit (OpCodes.Leave, ex_handlers [cur_block].end);
452 				ex_handlers [cur_block].PatchFilterClause (code_len);
453 			}
454 
455 			//System.Console.WriteLine ("Begin finally Block");
456 			ex_handlers [cur_block].AddFinally (code_len);
457 		}
458 
BeginScope()459 		public virtual void BeginScope ()
460 		{ }
461 
DeclareLocal(Type localType)462 		public virtual LocalBuilder DeclareLocal (Type localType)
463 		{
464 			return DeclareLocal (localType, false);
465 		}
466 
467 
DeclareLocal(Type localType, bool pinned)468 		public virtual LocalBuilder DeclareLocal (Type localType, bool pinned)
469 		{
470 			if (localType == null)
471 				throw new ArgumentNullException ("localType");
472 			if (localType.IsUserType)
473 				throw new NotSupportedException ("User defined subclasses of System.Type are not yet supported.");
474 			LocalBuilder res = new LocalBuilder (localType, this);
475 			res.is_pinned = pinned;
476 
477 			if (locals != null) {
478 				LocalBuilder[] new_l = new LocalBuilder [locals.Length + 1];
479 				System.Array.Copy (locals, new_l, locals.Length);
480 				new_l [locals.Length] = res;
481 				locals = new_l;
482 			} else {
483 				locals = new LocalBuilder [1];
484 				locals [0] = res;
485 			}
486 			res.position = (ushort)(locals.Length - 1);
487 			return res;
488 		}
489 
DefineLabel()490 		public virtual Label DefineLabel ()
491 		{
492 			if (labels == null)
493 				labels = new LabelData [defaultLabelsSize];
494 			else if (num_labels >= labels.Length) {
495 				LabelData [] t = new LabelData [labels.Length * 2];
496 				Array.Copy (labels, t, labels.Length);
497 				labels = t;
498 			}
499 
500 			labels [num_labels] = new LabelData (-1, 0);
501 
502 			return new Label (num_labels++);
503 		}
504 
Emit(OpCode opcode)505 		public virtual void Emit (OpCode opcode)
506 		{
507 			make_room (2);
508 			ll_emit (opcode);
509 		}
510 
Emit(OpCode opcode, Byte arg)511 		public virtual void Emit (OpCode opcode, Byte arg)
512 		{
513 			make_room (3);
514 			ll_emit (opcode);
515 			code [code_len++] = arg;
516 		}
517 
518 		[ComVisible (true)]
Emit(OpCode opcode, ConstructorInfo con)519 		public virtual void Emit (OpCode opcode, ConstructorInfo con)
520 		{
521 			int token = token_gen.GetToken (con, true);
522 			make_room (6);
523 			ll_emit (opcode);
524 			if (con.DeclaringType.Module == module || (con is ConstructorOnTypeBuilderInst) || (con is ConstructorBuilder))
525 				add_token_fixup (con);
526 			emit_int (token);
527 
528 			if (opcode.StackBehaviourPop == StackBehaviour.Varpop)
529 				cur_stack -= con.GetParametersCount ();
530 		}
531 
Emit(OpCode opcode, double arg)532 		public virtual void Emit (OpCode opcode, double arg)
533 		{
534 			byte[] s = System.BitConverter.GetBytes (arg);
535 			make_room (10);
536 			ll_emit (opcode);
537 			if (BitConverter.IsLittleEndian){
538 				System.Array.Copy (s, 0, code, code_len, 8);
539 				code_len += 8;
540 			} else {
541 				code [code_len++] = s [7];
542 				code [code_len++] = s [6];
543 				code [code_len++] = s [5];
544 				code [code_len++] = s [4];
545 				code [code_len++] = s [3];
546 				code [code_len++] = s [2];
547 				code [code_len++] = s [1];
548 				code [code_len++] = s [0];
549 			}
550 		}
551 
Emit(OpCode opcode, FieldInfo field)552 		public virtual void Emit (OpCode opcode, FieldInfo field)
553 		{
554 			int token = token_gen.GetToken (field, true);
555 			make_room (6);
556 			ll_emit (opcode);
557 			if (field.DeclaringType.Module == module || (field is FieldOnTypeBuilderInst) || (field is FieldBuilder))
558 				add_token_fixup (field);
559 			emit_int (token);
560 		}
561 
Emit(OpCode opcode, Int16 arg)562 		public virtual void Emit (OpCode opcode, Int16 arg)
563 		{
564 			make_room (4);
565 			ll_emit (opcode);
566 			code [code_len++] = (byte) (arg & 0xFF);
567 			code [code_len++] = (byte) ((arg >> 8) & 0xFF);
568 		}
569 
Emit(OpCode opcode, int arg)570 		public virtual void Emit (OpCode opcode, int arg)
571 		{
572 			make_room (6);
573 			ll_emit (opcode);
574 			emit_int (arg);
575 		}
576 
Emit(OpCode opcode, long arg)577 		public virtual void Emit (OpCode opcode, long arg)
578 		{
579 			make_room (10);
580 			ll_emit (opcode);
581 			code [code_len++] = (byte) (arg & 0xFF);
582 			code [code_len++] = (byte) ((arg >> 8) & 0xFF);
583 			code [code_len++] = (byte) ((arg >> 16) & 0xFF);
584 			code [code_len++] = (byte) ((arg >> 24) & 0xFF);
585 			code [code_len++] = (byte) ((arg >> 32) & 0xFF);
586 			code [code_len++] = (byte) ((arg >> 40) & 0xFF);
587 			code [code_len++] = (byte) ((arg >> 48) & 0xFF);
588 			code [code_len++] = (byte) ((arg >> 56) & 0xFF);
589 		}
590 
Emit(OpCode opcode, Label label)591 		public virtual void Emit (OpCode opcode, Label label)
592 		{
593 			int tlen = target_len (opcode);
594 			make_room (6);
595 			ll_emit (opcode);
596 			if (cur_stack > labels [label.label].maxStack)
597 				labels [label.label].maxStack = cur_stack;
598 
599 			if (fixups == null)
600 				fixups = new LabelFixup [defaultFixupSize];
601 			else if (num_fixups >= fixups.Length) {
602 				LabelFixup[] newf = new LabelFixup [fixups.Length * 2];
603 				System.Array.Copy (fixups, newf, fixups.Length);
604 				fixups = newf;
605 			}
606 			fixups [num_fixups].offset = tlen;
607 			fixups [num_fixups].pos = code_len;
608 			fixups [num_fixups].label_idx = label.label;
609 			num_fixups++;
610 			code_len += tlen;
611 
612 		}
613 
Emit(OpCode opcode, Label[] labels)614 		public virtual void Emit (OpCode opcode, Label[] labels)
615 		{
616 			if (labels == null)
617 				throw new ArgumentNullException ("labels");
618 
619 			/* opcode needs to be switch. */
620 			int count = labels.Length;
621 			make_room (6 + count * 4);
622 			ll_emit (opcode);
623 
624 			for (int i = 0; i < count; ++i)
625 				if (cur_stack > this.labels [labels [i].label].maxStack)
626 					this.labels [labels [i].label].maxStack = cur_stack;
627 
628 			emit_int (count);
629 			if (fixups == null)
630 				fixups = new LabelFixup [defaultFixupSize + count];
631 			else if (num_fixups + count >= fixups.Length) {
632 				LabelFixup[] newf = new LabelFixup [count + fixups.Length * 2];
633 				System.Array.Copy (fixups, newf, fixups.Length);
634 				fixups = newf;
635 			}
636 
637 			// ECMA 335, Partition III, p94 (7-10)
638 			//
639 			// The switch instruction implements a jump table. The format of
640 			// the instruction is an unsigned int32 representing the number of targets N,
641 			// followed by N int32 values specifying jump targets: these targets are
642 			// represented as offsets (positive or negative) from the beginning of the
643 			// instruction following this switch instruction.
644 			//
645 			// We must make sure it gets an offset from the *end* of the last label
646 			// (eg, the beginning of the instruction following this).
647 			//
648 			// remaining is the number of bytes from the current instruction to the
649 			// instruction that will be emitted.
650 
651 			for (int i = 0, remaining = count * 4; i < count; ++i, remaining -= 4) {
652 				fixups [num_fixups].offset = remaining;
653 				fixups [num_fixups].pos = code_len;
654 				fixups [num_fixups].label_idx = labels [i].label;
655 				num_fixups++;
656 				code_len += 4;
657 			}
658 		}
659 
Emit(OpCode opcode, LocalBuilder local)660 		public virtual void Emit (OpCode opcode, LocalBuilder local)
661 		{
662 			if (local == null)
663 				throw new ArgumentNullException ("local");
664 			if (local.ilgen != this)
665 				throw new ArgumentException ("Trying to emit a local from a different ILGenerator.");
666 
667 			uint pos = local.position;
668 			bool load_addr = false;
669 			bool is_store = false;
670 			bool is_load = false;
671 			make_room (6);
672 
673 			/* inline the code from ll_emit () to optimize il code size */
674 			if (opcode.StackBehaviourPop == StackBehaviour.Pop1) {
675 				cur_stack --;
676 				is_store = true;
677 			} else if (opcode.StackBehaviourPush == StackBehaviour.Push1 || opcode.StackBehaviourPush == StackBehaviour.Pushi) {
678 				cur_stack++;
679 				is_load = true;
680 				if (cur_stack > max_stack)
681 					max_stack = cur_stack;
682 				load_addr = opcode.StackBehaviourPush == StackBehaviour.Pushi;
683 			}
684 			if (load_addr) {
685 				if (pos < 256) {
686 					code [code_len++] = (byte)0x12;
687 					code [code_len++] = (byte)pos;
688 				} else {
689 					code [code_len++] = (byte)0xfe;
690 					code [code_len++] = (byte)0x0d;
691 					code [code_len++] = (byte)(pos & 0xff);
692 					code [code_len++] = (byte)((pos >> 8) & 0xff);
693 				}
694 			} else {
695 				if (is_store) {
696 					if (pos < 4) {
697 						code [code_len++] = (byte)(0x0a + pos);
698 					} else if (pos < 256) {
699 						code [code_len++] = (byte)0x13;
700 						code [code_len++] = (byte)pos;
701 					} else {
702 						code [code_len++] = (byte)0xfe;
703 						code [code_len++] = (byte)0x0e;
704 						code [code_len++] = (byte)(pos & 0xff);
705 						code [code_len++] = (byte)((pos >> 8) & 0xff);
706 					}
707 				} else if (is_load) {
708 					if (pos < 4) {
709 						code [code_len++] = (byte)(0x06 + pos);
710 					} else if (pos < 256) {
711 						code [code_len++] = (byte)0x11;
712 						code [code_len++] = (byte)pos;
713 					} else {
714 						code [code_len++] = (byte)0xfe;
715 						code [code_len++] = (byte)0x0c;
716 						code [code_len++] = (byte)(pos & 0xff);
717 						code [code_len++] = (byte)((pos >> 8) & 0xff);
718 					}
719 				} else {
720 					ll_emit (opcode);
721 				}
722 			}
723 		}
724 
Emit(OpCode opcode, MethodInfo meth)725 		public virtual void Emit (OpCode opcode, MethodInfo meth)
726 		{
727 			if (meth == null)
728 				throw new ArgumentNullException ("meth");
729 
730 			// For compatibility with MS
731 			if ((meth is DynamicMethod) && ((opcode == OpCodes.Ldftn) || (opcode == OpCodes.Ldvirtftn) || (opcode == OpCodes.Ldtoken)))
732 				throw new ArgumentException ("Ldtoken, Ldftn and Ldvirtftn OpCodes cannot target DynamicMethods.");
733 
734 			int token = token_gen.GetToken (meth, true);
735 			make_room (6);
736 			ll_emit (opcode);
737 			Type declaringType = meth.DeclaringType;
738 			// Might be a DynamicMethod with no declaring type
739 			if (declaringType != null) {
740 				if (declaringType.Module == module || meth is MethodOnTypeBuilderInst || meth is MethodBuilder)
741 					add_token_fixup (meth);
742 			}
743 			emit_int (token);
744 			if (meth.ReturnType != typeof (void))
745 				cur_stack ++;
746 
747 			if (opcode.StackBehaviourPop == StackBehaviour.Varpop)
748 				cur_stack -= meth.GetParametersCount ();
749 		}
750 
Emit(OpCode opcode, MethodInfo method, int token)751 		private void Emit (OpCode opcode, MethodInfo method, int token)
752 		{
753 			make_room (6);
754 			ll_emit (opcode);
755 			// Might be a DynamicMethod with no declaring type
756 			Type declaringType = method.DeclaringType;
757 			if (declaringType != null) {
758 				if (declaringType.Module == module || method is MethodBuilder)
759 					add_token_fixup (method);
760 			}
761 			emit_int (token);
762 			if (method.ReturnType != typeof (void))
763 				cur_stack ++;
764 
765 			if (opcode.StackBehaviourPop == StackBehaviour.Varpop)
766 				cur_stack -= method.GetParametersCount ();
767 		}
768 
769 		[CLSCompliant(false)]
Emit(OpCode opcode, sbyte arg)770 		public void Emit (OpCode opcode, sbyte arg)
771 		{
772 			make_room (3);
773 			ll_emit (opcode);
774 			code [code_len++] = (byte)arg;
775 		}
776 
Emit(OpCode opcode, SignatureHelper signature)777 		public virtual void Emit (OpCode opcode, SignatureHelper signature)
778 		{
779 			int token = token_gen.GetToken (signature);
780 			make_room (6);
781 			ll_emit (opcode);
782 			emit_int (token);
783 		}
784 
Emit(OpCode opcode, float arg)785 		public virtual void Emit (OpCode opcode, float arg)
786 		{
787 			byte[] s = System.BitConverter.GetBytes (arg);
788 			make_room (6);
789 			ll_emit (opcode);
790 			if (BitConverter.IsLittleEndian){
791 				System.Array.Copy (s, 0, code, code_len, 4);
792 				code_len += 4;
793 			} else {
794 				code [code_len++] = s [3];
795 				code [code_len++] = s [2];
796 				code [code_len++] = s [1];
797 				code [code_len++] = s [0];
798 			}
799 		}
800 
Emit(OpCode opcode, string str)801 		public virtual void Emit (OpCode opcode, string str)
802 		{
803 			int token = token_gen.GetToken (str);
804 			make_room (6);
805 			ll_emit (opcode);
806 			emit_int (token);
807 		}
808 
Emit(OpCode opcode, Type cls)809 		public virtual void Emit (OpCode opcode, Type cls)
810 		{
811 			if (cls != null && cls.IsByRef)
812 				throw new ArgumentException ("Cannot get TypeToken for a ByRef type.");
813 
814 			make_room (6);
815 			ll_emit (opcode);
816 			int token = token_gen.GetToken (cls, opcode != OpCodes.Ldtoken);
817 			if (cls is TypeBuilderInstantiation || cls is SymbolType || cls is TypeBuilder || cls is GenericTypeParameterBuilder || cls is EnumBuilder)
818 				add_token_fixup (cls);
819 			emit_int (token);
820 		}
821 
822 		[MonoLimitation ("vararg methods are not supported")]
EmitCall(OpCode opcode, MethodInfo methodInfo, Type[] optionalParameterTypes)823 		public virtual void EmitCall (OpCode opcode, MethodInfo methodInfo, Type[] optionalParameterTypes)
824 		{
825 			if (methodInfo == null)
826 				throw new ArgumentNullException ("methodInfo");
827 			short value = opcode.Value;
828 			if (!(value == OpCodes.Call.Value || value == OpCodes.Callvirt.Value))
829 				throw new NotSupportedException ("Only Call and CallVirt are allowed");
830 			if ((methodInfo.CallingConvention & CallingConventions.VarArgs)  == 0)
831 				optionalParameterTypes = null;
832 			if (optionalParameterTypes != null){
833 				if ((methodInfo.CallingConvention & CallingConventions.VarArgs)  == 0){
834 					throw new InvalidOperationException ("Method is not VarArgs method and optional types were passed");
835 				}
836 
837 				int token = token_gen.GetToken (methodInfo, optionalParameterTypes);
838 				Emit (opcode, methodInfo, token);
839 				return;
840 			}
841 			Emit (opcode, methodInfo);
842 		}
843 
EmitCalli(OpCode opcode, CallingConvention unmanagedCallConv, Type returnType, Type[] parameterTypes)844 		public virtual void EmitCalli (OpCode opcode, CallingConvention unmanagedCallConv, Type returnType, Type[] parameterTypes)
845 		{
846 			// GetMethodSigHelper expects a ModuleBuilder or null, and module might be
847 			// a normal module when using dynamic methods.
848 			SignatureHelper helper = SignatureHelper.GetMethodSigHelper (module as ModuleBuilder, 0, unmanagedCallConv, returnType, parameterTypes);
849 			Emit (opcode, helper);
850 		}
851 
EmitCalli(OpCode opcode, CallingConventions callingConvention, Type returnType, Type[] parameterTypes, Type[] optionalParameterTypes)852 		public virtual void EmitCalli (OpCode opcode, CallingConventions callingConvention, Type returnType, Type[] parameterTypes, Type[] optionalParameterTypes)
853 		{
854 			if (optionalParameterTypes != null)
855 				throw new NotImplementedException ();
856 
857 			SignatureHelper helper = SignatureHelper.GetMethodSigHelper (module as ModuleBuilder, callingConvention, 0, returnType, parameterTypes);
858 			Emit (opcode, helper);
859 		}
860 
EmitWriteLine(FieldInfo fld)861 		public virtual void EmitWriteLine (FieldInfo fld)
862 		{
863 			if (fld == null)
864 				throw new ArgumentNullException ("fld");
865 
866 			// The MS implementation does not check for valuetypes here but it
867 			// should. Also, it should check that if the field is not static,
868 			// then it is a member of this type.
869 			if (fld.IsStatic)
870 				Emit (OpCodes.Ldsfld, fld);
871 			else {
872 				Emit (OpCodes.Ldarg_0);
873 				Emit (OpCodes.Ldfld, fld);
874 			}
875 			Emit (OpCodes.Call, typeof (Console).GetMethod ("WriteLine", new Type[1] { fld.FieldType }));
876 		}
877 
EmitWriteLine(LocalBuilder localBuilder)878 		public virtual void EmitWriteLine (LocalBuilder localBuilder)
879 		{
880 			if (localBuilder == null)
881 				throw new ArgumentNullException ("localBuilder");
882 			if (localBuilder.LocalType is TypeBuilder)
883 				throw new  ArgumentException ("Output streams do not support TypeBuilders.");
884 			// The MS implementation does not check for valuetypes here but it
885 			// should.
886 			Emit (OpCodes.Ldloc, localBuilder);
887 			Emit (OpCodes.Call, typeof (Console).GetMethod ("WriteLine", new Type[1] { localBuilder.LocalType }));
888 		}
889 
EmitWriteLine(string value)890 		public virtual void EmitWriteLine (string value)
891 		{
892 			Emit (OpCodes.Ldstr, value);
893 			Emit (OpCodes.Call, typeof (Console).GetMethod ("WriteLine", new Type[1] { typeof(string)}));
894 		}
895 
EndExceptionBlock()896 		public virtual void EndExceptionBlock ()
897 		{
898 			if (open_blocks == null)
899 				open_blocks = new Stack (defaultExceptionStackSize);
900 
901 			if (open_blocks.Count <= 0)
902 				throw new NotSupportedException ("Not in an exception block");
903 
904 			if (ex_handlers [cur_block].LastClauseType () == ILExceptionBlock.FILTER_START)
905 				throw new InvalidOperationException ("Incorrect code generation for exception block.");
906 
907 			InternalEndClause ();
908 			MarkLabel (ex_handlers [cur_block].end);
909 			ex_handlers [cur_block].End (code_len);
910 			ex_handlers [cur_block].Debug (cur_block);
911 			//System.Console.WriteLine ("End Block {0} (handlers: {1})", cur_block, ex_handlers [cur_block].NumHandlers ());
912 			open_blocks.Pop ();
913 			if (open_blocks.Count > 0)
914 				cur_block = (int)open_blocks.Peek ();
915 			//Console.WriteLine ("curblock restored to {0}", cur_block);
916 			//throw new NotImplementedException ();
917 		}
918 
EndScope()919 		public virtual void EndScope ()
920 		{ }
921 
MarkLabel(Label loc)922 		public virtual void MarkLabel (Label loc)
923 		{
924 			if (loc.label < 0 || loc.label >= num_labels)
925 				throw new System.ArgumentException ("The label is not valid");
926 			if (labels [loc.label].addr >= 0)
927 				throw new System.ArgumentException ("The label was already defined");
928 			labels [loc.label].addr = code_len;
929 			if (labels [loc.label].maxStack > cur_stack)
930 				cur_stack = labels [loc.label].maxStack;
931 		}
932 
MarkSequencePoint(ISymbolDocumentWriter document, int startLine, int startColumn, int endLine, int endColumn)933 		public virtual void MarkSequencePoint (ISymbolDocumentWriter document, int startLine,
934 						       int startColumn, int endLine, int endColumn)
935 		{
936 			if (currentSequence == null || currentSequence.Document != document) {
937 				if (sequencePointLists == null)
938 					sequencePointLists = new ArrayList ();
939 				currentSequence = new SequencePointList (document);
940 				sequencePointLists.Add (currentSequence);
941 			}
942 
943 			currentSequence.AddSequencePoint (code_len, startLine, startColumn, endLine, endColumn);
944 		}
945 
GenerateDebugInfo(ISymbolWriter symbolWriter)946 		internal void GenerateDebugInfo (ISymbolWriter symbolWriter)
947 		{
948 			if (sequencePointLists != null) {
949 				SequencePointList first = (SequencePointList) sequencePointLists [0];
950 				SequencePointList last = (SequencePointList) sequencePointLists [sequencePointLists.Count - 1];
951 				symbolWriter.SetMethodSourceRange (first.Document, first.StartLine, first.StartColumn, last.Document, last.EndLine, last.EndColumn);
952 
953 				foreach (SequencePointList list in sequencePointLists)
954 					symbolWriter.DefineSequencePoints (list.Document, list.GetOffsets(), list.GetLines(), list.GetColumns(), list.GetEndLines(), list.GetEndColumns());
955 
956 				if (locals != null) {
957 					foreach (LocalBuilder local in locals) {
958 						if (local.Name != null && local.Name.Length > 0) {
959 							SignatureHelper sighelper = SignatureHelper.GetLocalVarSigHelper (module as ModuleBuilder);
960 							sighelper.AddArgument (local.LocalType);
961 							byte[] signature = sighelper.GetSignature ();
962 							symbolWriter.DefineLocalVariable (local.Name, FieldAttributes.Public, signature, SymAddressKind.ILOffset, local.position, 0, 0, local.StartOffset, local.EndOffset);
963 						}
964 					}
965 				}
966 				sequencePointLists = null;
967 			}
968 		}
969 
970 		internal bool HasDebugInfo
971 		{
972 			get { return sequencePointLists != null; }
973 		}
974 
ThrowException(Type excType)975 		public virtual void ThrowException (Type excType)
976 		{
977 			if (excType == null)
978 				throw new ArgumentNullException ("excType");
979 			if (! ((excType == typeof (Exception)) ||
980 				   excType.IsSubclassOf (typeof (Exception))))
981 				throw new ArgumentException ("Type should be an exception type", "excType");
982 			ConstructorInfo ctor = excType.GetConstructor (Type.EmptyTypes);
983 			if (ctor == null)
984 				throw new ArgumentException ("Type should have a default constructor", "excType");
985 			Emit (OpCodes.Newobj, ctor);
986 			Emit (OpCodes.Throw);
987 		}
988 
989 		[MonoTODO("Not implemented")]
UsingNamespace(String usingNamespace)990 		public virtual void UsingNamespace (String usingNamespace)
991 		{
992 			throw new NotImplementedException ();
993 		}
994 
label_fixup(MethodBase mb)995 		internal void label_fixup (MethodBase mb)
996 		{
997 			for (int i = 0; i < num_fixups; ++i) {
998 				if (labels [fixups [i].label_idx].addr < 0)
999 					throw new ArgumentException (string.Format ("Label #{0} is not marked in method `{1}'", fixups [i].label_idx + 1, mb.Name));
1000 				// Diff is the offset from the end of the jump instruction to the address of the label
1001 				int diff = labels [fixups [i].label_idx].addr - (fixups [i].pos + fixups [i].offset);
1002 				if (fixups [i].offset == 1) {
1003 					code [fixups [i].pos] = (byte)((sbyte) diff);
1004 				} else {
1005 					int old_cl = code_len;
1006 					code_len = fixups [i].pos;
1007 					emit_int (diff);
1008 					code_len = old_cl;
1009 				}
1010 			}
1011 		}
1012 
FixupTokens(Dictionary<int, int> token_map, Dictionary<int, MemberInfo> member_map)1013 		internal void FixupTokens (Dictionary<int, int> token_map, Dictionary<int, MemberInfo> member_map) {
1014 			for (int i = 0; i < num_token_fixups; ++i) {
1015 				int pos = token_fixups [i].code_pos;
1016 				int old_token = code [pos] | (code [pos + 1] << 8) | (code [pos + 2] << 16) | (code [pos + 3] << 24);
1017 				int new_token;
1018 				if (token_map.TryGetValue (old_token, out new_token)) {
1019 					token_fixups [i].member = member_map [old_token];
1020 					int old_cl = code_len;
1021 					code_len = pos;
1022 					emit_int (new_token);
1023 					code_len = old_cl;
1024 				}
1025 			}
1026 		}
1027 
1028 		// Used by MethodBuilder.SetMethodBody
SetExceptionHandlers(ILExceptionInfo[] exHandlers)1029 		internal void SetExceptionHandlers (ILExceptionInfo[] exHandlers) {
1030 			this.ex_handlers = exHandlers;
1031 		}
1032 
1033 		// Used by MethodBuilder.SetMethodBody
SetTokenFixups(ILTokenInfo[] tokenFixups)1034 		internal void SetTokenFixups (ILTokenInfo[] tokenFixups) {
1035 			this.token_fixups = tokenFixups;
1036 		}
1037 
1038 		// Used by DynamicILGenerator and MethodBuilder.SetMethodBody
SetCode(byte[] code, int max_stack)1039 		internal void SetCode (byte[] code, int max_stack) {
1040 			// Make a copy to avoid possible security problems
1041 			this.code = (byte[])code.Clone ();
1042 			this.code_len = code.Length;
1043 			this.max_stack = max_stack;
1044 			this.cur_stack = 0;
1045 		}
1046 
SetCode(byte *code, int code_size, int max_stack)1047 		internal unsafe void SetCode (byte *code, int code_size, int max_stack) {
1048 			// Make a copy to avoid possible security problems
1049 			this.code = new byte [code_size];
1050 			for (int i = 0; i < code_size; ++i)
1051 				this.code [i] = code [i];
1052 			this.code_len = code_size;
1053 			this.max_stack = max_stack;
1054 			this.cur_stack = 0;
1055 		}
1056 
Init(byte[] il, int maxStack, byte[] localSignature, IEnumerable<ExceptionHandler> exceptionHandlers, IEnumerable<int> tokenFixups)1057 		internal void Init (byte[] il, int maxStack, byte[] localSignature,
1058 			IEnumerable<ExceptionHandler> exceptionHandlers, IEnumerable<int> tokenFixups)
1059 		{
1060 			SetCode (il, maxStack);
1061 
1062 			// FIXME: Process local signature
1063 
1064 			// Process exception handlers
1065 			if (exceptionHandlers != null) {
1066 				// Group exception handlers by try blocks
1067 				var tryBlocks = new Dictionary <Tuple<int, int>, List<ExceptionHandler>> ();
1068 				foreach (var h in exceptionHandlers) {
1069 					List<ExceptionHandler> list;
1070 					var key = new Tuple <int, int> (h.TryOffset, h.TryLength);
1071 					if (!tryBlocks.TryGetValue (key, out list)) {
1072 						list = new List<ExceptionHandler> ();
1073 						tryBlocks.Add (key, list);
1074 					}
1075 					list.Add (h);
1076 				}
1077 
1078 				// Generate ILExceptionInfo from tryBlocks
1079 				var infos = new List<ILExceptionInfo> ();
1080 				foreach (var kv in tryBlocks) {
1081 					var info = new ILExceptionInfo () {
1082 						start = kv.Key.Item1,
1083 						len = kv.Key.Item2,
1084 						handlers = new ILExceptionBlock [kv.Value.Count],
1085 					};
1086 					infos.Add (info);
1087 					var i = 0;
1088 					foreach (var b in kv.Value) {
1089 						info.handlers [i++] = new ILExceptionBlock () {
1090 							start = b.HandlerOffset,
1091 							len = b.HandlerLength,
1092 							filter_offset = b.FilterOffset,
1093 							type = (int) b.Kind,
1094 							extype = module.ResolveType (b.ExceptionTypeToken),
1095 						};
1096 					}
1097 				}
1098 
1099 				SetExceptionHandlers (infos.ToArray ());
1100 			}
1101 
1102 			// Process token fixups
1103 			if (tokenFixups != null) {
1104 				var tokenInfos = new List<ILTokenInfo> ();
1105 				foreach (var pos in tokenFixups) {
1106 					var token = (int) BitConverter.ToUInt32 (il, pos);
1107 					var tokenInfo = new ILTokenInfo () {
1108 						code_pos = pos,
1109 						member = ((ModuleBuilder) module).ResolveOrGetRegisteredToken (token, null, null)
1110 					};
1111 					tokenInfos.Add (tokenInfo);
1112 				}
1113 
1114 				SetTokenFixups (tokenInfos.ToArray ());
1115 			}
1116 		}
1117 
1118 
1119 		internal TokenGenerator TokenGenerator {
1120 			get {
1121 				return token_gen;
1122 			}
1123 		}
1124 
1125 		// Still used by symbolwriter
1126 		[Obsolete ("Use ILOffset", true)]
Mono_GetCurrentOffset(ILGenerator ig)1127 		internal static int Mono_GetCurrentOffset (ILGenerator ig)
1128 		{
1129 			return ig.code_len;
1130 		}
1131 
1132 		public
1133 		virtual int ILOffset {
1134 			get { return code_len; }
1135 		}
1136 
_ILGenerator.GetIDsOfNames([In] ref Guid riid, IntPtr rgszNames, uint cNames, uint lcid, IntPtr rgDispId)1137 		void _ILGenerator.GetIDsOfNames ([In] ref Guid riid, IntPtr rgszNames, uint cNames, uint lcid, IntPtr rgDispId)
1138 		{
1139 			throw new NotImplementedException ();
1140 		}
1141 
_ILGenerator.GetTypeInfo(uint iTInfo, uint lcid, IntPtr ppTInfo)1142 		void _ILGenerator.GetTypeInfo (uint iTInfo, uint lcid, IntPtr ppTInfo)
1143 		{
1144 			throw new NotImplementedException ();
1145 		}
1146 
_ILGenerator.GetTypeInfoCount(out uint pcTInfo)1147 		void _ILGenerator.GetTypeInfoCount (out uint pcTInfo)
1148 		{
1149 			throw new NotImplementedException ();
1150 		}
1151 
_ILGenerator.Invoke(uint dispIdMember, [In] ref Guid riid, uint lcid, short wFlags, IntPtr pDispParams, IntPtr pVarResult, IntPtr pExcepInfo, IntPtr puArgErr)1152 		void _ILGenerator.Invoke (uint dispIdMember, [In] ref Guid riid, uint lcid, short wFlags, IntPtr pDispParams, IntPtr pVarResult, IntPtr pExcepInfo, IntPtr puArgErr)
1153 		{
1154 			throw new NotImplementedException ();
1155 		}
1156 	}
1157 
1158 	internal class SequencePointList
1159 	{
1160 		ISymbolDocumentWriter doc;
1161 		SequencePoint[] points;
1162 		int count;
1163 		const int arrayGrow = 10;
1164 
SequencePointList(ISymbolDocumentWriter doc)1165 		public SequencePointList (ISymbolDocumentWriter doc)
1166 		{
1167 			this.doc = doc;
1168 		}
1169 
1170 		public ISymbolDocumentWriter Document {
1171 			get { return doc; }
1172 		}
1173 
GetOffsets()1174 		public int[] GetOffsets()
1175 		{
1176 			int[] data = new int [count];
1177 			for (int n=0; n<count; n++) data [n] = points[n].Offset;
1178 			return data;
1179 		}
GetLines()1180 		public int[] GetLines()
1181 		{
1182 			int[] data = new int [count];
1183 			for (int n=0; n<count; n++) data [n] = points[n].Line;
1184 			return data;
1185 		}
GetColumns()1186 		public int[] GetColumns()
1187 		{
1188 			int[] data = new int [count];
1189 			for (int n=0; n<count; n++) data [n] = points[n].Col;
1190 			return data;
1191 		}
GetEndLines()1192 		public int[] GetEndLines()
1193 		{
1194 			int[] data = new int [count];
1195 			for (int n=0; n<count; n++) data [n] = points[n].EndLine;
1196 			return data;
1197 		}
GetEndColumns()1198 		public int[] GetEndColumns()
1199 		{
1200 			int[] data = new int [count];
1201 			for (int n=0; n<count; n++) data [n] = points[n].EndCol;
1202 			return data;
1203 		}
1204 		public int StartLine {
1205 			get { return points[0].Line; }
1206 		}
1207 		public int EndLine {
1208 			get { return points[count - 1].Line; }
1209 		}
1210 		public int StartColumn {
1211 			get { return points[0].Col; }
1212 		}
1213 		public int EndColumn {
1214 			get { return points[count - 1].Col; }
1215 		}
1216 
AddSequencePoint(int offset, int line, int col, int endLine, int endCol)1217 		public void AddSequencePoint (int offset, int line, int col, int endLine, int endCol)
1218 		{
1219 			SequencePoint s = new SequencePoint ();
1220 			s.Offset = offset;
1221 			s.Line = line;
1222 			s.Col = col;
1223 			s.EndLine = endLine;
1224 			s.EndCol = endCol;
1225 
1226 			if (points == null) {
1227 				points = new SequencePoint [arrayGrow];
1228 			} else if (count >= points.Length) {
1229 				SequencePoint[] temp = new SequencePoint [count + arrayGrow];
1230 				Array.Copy (points, temp, points.Length);
1231 				points = temp;
1232 			}
1233 
1234 			points [count] = s;
1235 			count++;
1236 		}
1237 	}
1238 
1239 	struct SequencePoint {
1240 		public int Offset;
1241 		public int Line;
1242 		public int Col;
1243 		public int EndLine;
1244 		public int EndCol;
1245 	}
1246 }
1247 #endif
1248