1 //===-- NSArray.cpp ---------------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "Cocoa.h"
11 
12 #include "lldb/Core/DataBufferHeap.h"
13 #include "lldb/Core/Error.h"
14 #include "lldb/Core/Stream.h"
15 #include "lldb/Core/ValueObject.h"
16 #include "lldb/Core/ValueObjectConstResult.h"
17 #include "lldb/DataFormatters/FormattersHelpers.h"
18 #include "lldb/Host/Endian.h"
19 #include "lldb/Symbol/ClangASTContext.h"
20 #include "lldb/Target/ObjCLanguageRuntime.h"
21 #include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h"
22 #include "lldb/Target/Target.h"
23 
24 #include "clang/AST/ASTContext.h"
25 
26 using namespace lldb;
27 using namespace lldb_private;
28 using namespace lldb_private::formatters;
29 
30 namespace  lldb_private {
31     namespace formatters {
32         class NSArrayMSyntheticFrontEnd : public SyntheticChildrenFrontEnd
33         {
34         public:
35             NSArrayMSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);
36 
37             virtual size_t
38             CalculateNumChildren ();
39 
40             virtual lldb::ValueObjectSP
41             GetChildAtIndex (size_t idx);
42 
43             virtual bool
44             Update() = 0;
45 
46             virtual bool
47             MightHaveChildren ();
48 
49             virtual size_t
50             GetIndexOfChildWithName (const ConstString &name);
51 
52             virtual
53             ~NSArrayMSyntheticFrontEnd () {}
54 
55         protected:
56             virtual lldb::addr_t
57             GetDataAddress () = 0;
58 
59             virtual uint64_t
60             GetUsedCount () = 0;
61 
62             virtual uint64_t
63             GetOffset () = 0;
64 
65             virtual uint64_t
66             GetSize () = 0;
67 
68             ExecutionContextRef m_exe_ctx_ref;
69             uint8_t m_ptr_size;
70             CompilerType m_id_type;
71             std::vector<lldb::ValueObjectSP> m_children;
72         };
73 
74         class NSArrayMSyntheticFrontEnd_109 : public NSArrayMSyntheticFrontEnd
75         {
76         private:
77             struct DataDescriptor_32
78             {
79                 uint32_t _used;
80                 uint32_t _priv1 : 2 ;
81                 uint32_t _size : 30;
82                 uint32_t _priv2 : 2;
83                 uint32_t _offset : 30;
84                 uint32_t _priv3;
85                 uint32_t _data;
86             };
87             struct DataDescriptor_64
88             {
89                 uint64_t _used;
90                 uint64_t _priv1 : 2 ;
91                 uint64_t _size : 62;
92                 uint64_t _priv2 : 2;
93                 uint64_t _offset : 62;
94                 uint32_t _priv3;
95                 uint64_t _data;
96             };
97         public:
98             NSArrayMSyntheticFrontEnd_109 (lldb::ValueObjectSP valobj_sp);
99 
100             virtual bool
101             Update();
102 
103             virtual
104             ~NSArrayMSyntheticFrontEnd_109 ();
105 
106         protected:
107             virtual lldb::addr_t
108             GetDataAddress ();
109 
110             virtual uint64_t
111             GetUsedCount ();
112 
113             virtual uint64_t
114             GetOffset ();
115 
116             virtual uint64_t
117             GetSize ();
118 
119         private:
120             DataDescriptor_32 *m_data_32;
121             DataDescriptor_64 *m_data_64;
122         };
123 
124         class NSArrayMSyntheticFrontEnd_1010 : public NSArrayMSyntheticFrontEnd
125         {
126         private:
127             struct DataDescriptor_32
128             {
129                 uint32_t _used;
130                 uint32_t _offset;
131                 uint32_t _size : 28;
132                 uint64_t _priv1 : 4;
133                 uint32_t _priv2;
134                 uint32_t _data;
135             };
136             struct DataDescriptor_64
137             {
138                 uint64_t _used;
139                 uint64_t _offset;
140                 uint64_t _size : 60;
141                 uint64_t _priv1 : 4;
142                 uint32_t _priv2;
143                 uint64_t _data;
144             };
145         public:
146             NSArrayMSyntheticFrontEnd_1010 (lldb::ValueObjectSP valobj_sp);
147 
148             virtual bool
149             Update();
150 
151             virtual
152             ~NSArrayMSyntheticFrontEnd_1010 ();
153 
154         protected:
155             virtual lldb::addr_t
156             GetDataAddress ();
157 
158             virtual uint64_t
159             GetUsedCount ();
160 
161             virtual uint64_t
162             GetOffset ();
163 
164             virtual uint64_t
165             GetSize ();
166 
167         private:
168             DataDescriptor_32 *m_data_32;
169             DataDescriptor_64 *m_data_64;
170         };
171 
172         class NSArrayISyntheticFrontEnd : public SyntheticChildrenFrontEnd
173         {
174         public:
175             NSArrayISyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);
176 
177             virtual size_t
178             CalculateNumChildren ();
179 
180             virtual lldb::ValueObjectSP
181             GetChildAtIndex (size_t idx);
182 
183             virtual bool
184             Update();
185 
186             virtual bool
187             MightHaveChildren ();
188 
189             virtual size_t
190             GetIndexOfChildWithName (const ConstString &name);
191 
192             virtual
193             ~NSArrayISyntheticFrontEnd ();
194         private:
195             ExecutionContextRef m_exe_ctx_ref;
196             uint8_t m_ptr_size;
197             uint64_t m_items;
198             lldb::addr_t m_data_ptr;
199             CompilerType m_id_type;
200             std::vector<lldb::ValueObjectSP> m_children;
201         };
202 
203         class NSArrayCodeRunningSyntheticFrontEnd : public SyntheticChildrenFrontEnd
204         {
205         public:
206             NSArrayCodeRunningSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);
207 
208             virtual size_t
209             CalculateNumChildren ();
210 
211             virtual lldb::ValueObjectSP
212             GetChildAtIndex (size_t idx);
213 
214             virtual bool
215             Update();
216 
217             virtual bool
218             MightHaveChildren ();
219 
220             virtual size_t
221             GetIndexOfChildWithName (const ConstString &name);
222 
223             virtual
224             ~NSArrayCodeRunningSyntheticFrontEnd ();
225         };
226     }
227 }
228 
229 bool
230 lldb_private::formatters::NSArraySummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
231 {
232     ProcessSP process_sp = valobj.GetProcessSP();
233     if (!process_sp)
234         return false;
235 
236     ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
237 
238     if (!runtime)
239         return false;
240 
241     ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
242 
243     if (!descriptor.get() || !descriptor->IsValid())
244         return false;
245 
246     uint32_t ptr_size = process_sp->GetAddressByteSize();
247 
248     lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
249 
250     if (!valobj_addr)
251         return false;
252 
253     uint64_t value = 0;
254 
255     const char* class_name = descriptor->GetClassName().GetCString();
256 
257     if (!class_name || !*class_name)
258         return false;
259 
260     if (!strcmp(class_name,"__NSArrayI"))
261     {
262         Error error;
263         value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error);
264         if (error.Fail())
265             return false;
266     }
267     else if (!strcmp(class_name,"__NSArrayM"))
268     {
269         Error error;
270         value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error);
271         if (error.Fail())
272             return false;
273     }
274     else if (!strcmp(class_name,"__NSCFArray"))
275     {
276         Error error;
277         value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + 2 * ptr_size, ptr_size, 0, error);
278         if (error.Fail())
279             return false;
280     }
281     else
282     {
283         if (!ExtractValueFromObjCExpression(valobj, "int", "count", value))
284             return false;
285     }
286 
287     stream.Printf("@\"%" PRIu64 " object%s\"",
288                   value,
289                   value == 1 ? "" : "s");
290     return true;
291 }
292 
293 lldb_private::formatters::NSArrayMSyntheticFrontEnd::NSArrayMSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
294 SyntheticChildrenFrontEnd(*valobj_sp),
295     m_exe_ctx_ref(),
296     m_ptr_size(8),
297 m_id_type(),
298 m_children()
299 {
300     if (valobj_sp)
301     {
302         clang::ASTContext *ast = valobj_sp->GetExecutionContextRef().GetTargetSP()->GetScratchClangASTContext()->getASTContext();
303         if (ast)
304             m_id_type = CompilerType(ast, ast->ObjCBuiltinIdTy);
305         if (valobj_sp->GetProcessSP())
306             m_ptr_size = valobj_sp->GetProcessSP()->GetAddressByteSize();
307     }
308 }
309 
310 lldb_private::formatters::NSArrayMSyntheticFrontEnd_109::NSArrayMSyntheticFrontEnd_109 (lldb::ValueObjectSP valobj_sp) :
311 NSArrayMSyntheticFrontEnd(valobj_sp),
312 m_data_32(NULL),
313 m_data_64(NULL)
314 {
315 }
316 
317 lldb_private::formatters::NSArrayMSyntheticFrontEnd_1010::NSArrayMSyntheticFrontEnd_1010 (lldb::ValueObjectSP valobj_sp) :
318 NSArrayMSyntheticFrontEnd(valobj_sp),
319 m_data_32(NULL),
320 m_data_64(NULL)
321 {
322 }
323 
324 size_t
325 lldb_private::formatters::NSArrayMSyntheticFrontEnd::CalculateNumChildren ()
326 {
327     return GetUsedCount();
328 }
329 
330 lldb::ValueObjectSP
331 lldb_private::formatters::NSArrayMSyntheticFrontEnd::GetChildAtIndex (size_t idx)
332 {
333     if (idx >= CalculateNumChildren())
334         return lldb::ValueObjectSP();
335     lldb::addr_t object_at_idx = GetDataAddress();
336     size_t pyhs_idx = idx;
337     pyhs_idx += GetOffset();
338     if (GetSize() <= pyhs_idx)
339         pyhs_idx -= GetSize();
340     object_at_idx += (pyhs_idx * m_ptr_size);
341     StreamString idx_name;
342     idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
343     lldb::ValueObjectSP retval_sp = CreateValueObjectFromAddress(idx_name.GetData(),
344                                                                  object_at_idx,
345                                                                  m_exe_ctx_ref,
346                                                                  m_id_type);
347     m_children.push_back(retval_sp);
348     return retval_sp;
349 }
350 
351 bool
352 lldb_private::formatters::NSArrayMSyntheticFrontEnd_109::Update()
353 {
354     m_children.clear();
355     ValueObjectSP valobj_sp = m_backend.GetSP();
356     m_ptr_size = 0;
357     delete m_data_32;
358     m_data_32 = NULL;
359     delete m_data_64;
360     m_data_64 = NULL;
361     if (!valobj_sp)
362         return false;
363     m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
364     Error error;
365     error.Clear();
366     lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
367     if (!process_sp)
368         return false;
369     m_ptr_size = process_sp->GetAddressByteSize();
370     uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
371     if (m_ptr_size == 4)
372     {
373         m_data_32 = new DataDescriptor_32();
374         process_sp->ReadMemory (data_location, m_data_32, sizeof(DataDescriptor_32), error);
375     }
376     else
377     {
378         m_data_64 = new DataDescriptor_64();
379         process_sp->ReadMemory (data_location, m_data_64, sizeof(DataDescriptor_64), error);
380     }
381     if (error.Fail())
382         return false;
383     return false;
384 }
385 
386 bool
387 lldb_private::formatters::NSArrayMSyntheticFrontEnd_1010::Update()
388 {
389     m_children.clear();
390     ValueObjectSP valobj_sp = m_backend.GetSP();
391     m_ptr_size = 0;
392     delete m_data_32;
393     m_data_32 = NULL;
394     delete m_data_64;
395     m_data_64 = NULL;
396     if (!valobj_sp)
397         return false;
398     m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
399     Error error;
400     error.Clear();
401     lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
402     if (!process_sp)
403         return false;
404     m_ptr_size = process_sp->GetAddressByteSize();
405     uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
406     if (m_ptr_size == 4)
407     {
408         m_data_32 = new DataDescriptor_32();
409         process_sp->ReadMemory (data_location, m_data_32, sizeof(DataDescriptor_32), error);
410     }
411     else
412     {
413         m_data_64 = new DataDescriptor_64();
414         process_sp->ReadMemory (data_location, m_data_64, sizeof(DataDescriptor_64), error);
415     }
416     if (error.Fail())
417         return false;
418     return false;
419 }
420 
421 bool
422 lldb_private::formatters::NSArrayMSyntheticFrontEnd::MightHaveChildren ()
423 {
424     return true;
425 }
426 
427 size_t
428 lldb_private::formatters::NSArrayMSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
429 {
430     const char* item_name = name.GetCString();
431     uint32_t idx = ExtractIndexFromString(item_name);
432     if (idx < UINT32_MAX && idx >= CalculateNumChildren())
433         return UINT32_MAX;
434     return idx;
435 }
436 
437 lldb::addr_t
438 lldb_private::formatters::NSArrayMSyntheticFrontEnd_109::GetDataAddress ()
439 {
440     if (!m_data_32 && !m_data_64)
441         return LLDB_INVALID_ADDRESS;
442     return m_data_32 ? m_data_32->_data :
443     m_data_64->_data;
444 }
445 
446 uint64_t
447 lldb_private::formatters::NSArrayMSyntheticFrontEnd_109::GetUsedCount ()
448 {
449     if (!m_data_32 && !m_data_64)
450         return 0;
451     return m_data_32 ? m_data_32->_used :
452     m_data_64->_used;
453 }
454 
455 uint64_t
456 lldb_private::formatters::NSArrayMSyntheticFrontEnd_109::GetOffset ()
457 {
458     if (!m_data_32 && !m_data_64)
459         return 0;
460     return m_data_32 ? m_data_32->_offset :
461     m_data_64->_offset;
462 }
463 
464 uint64_t
465 lldb_private::formatters::NSArrayMSyntheticFrontEnd_109::GetSize ()
466 {
467     if (!m_data_32 && !m_data_64)
468         return 0;
469     return m_data_32 ? m_data_32->_size :
470     m_data_64->_size;
471 }
472 
473 lldb_private::formatters::NSArrayMSyntheticFrontEnd_109::~NSArrayMSyntheticFrontEnd_109 ()
474 {
475     delete m_data_32;
476     m_data_32 = NULL;
477     delete m_data_64;
478     m_data_64 = NULL;
479 }
480 
481 lldb::addr_t
482 lldb_private::formatters::NSArrayMSyntheticFrontEnd_1010::GetDataAddress ()
483 {
484     if (!m_data_32 && !m_data_64)
485         return LLDB_INVALID_ADDRESS;
486     return m_data_32 ? m_data_32->_data :
487     m_data_64->_data;
488 }
489 
490 uint64_t
491 lldb_private::formatters::NSArrayMSyntheticFrontEnd_1010::GetUsedCount ()
492 {
493     if (!m_data_32 && !m_data_64)
494         return 0;
495     return m_data_32 ? m_data_32->_used :
496     m_data_64->_used;
497 }
498 
499 uint64_t
500 lldb_private::formatters::NSArrayMSyntheticFrontEnd_1010::GetOffset ()
501 {
502     if (!m_data_32 && !m_data_64)
503         return 0;
504     return m_data_32 ? m_data_32->_offset :
505     m_data_64->_offset;
506 }
507 
508 uint64_t
509 lldb_private::formatters::NSArrayMSyntheticFrontEnd_1010::GetSize ()
510 {
511     if (!m_data_32 && !m_data_64)
512         return 0;
513     return m_data_32 ? m_data_32->_size :
514     m_data_64->_size;
515 }
516 
517 lldb_private::formatters::NSArrayMSyntheticFrontEnd_1010::~NSArrayMSyntheticFrontEnd_1010 ()
518 {
519     delete m_data_32;
520     m_data_32 = NULL;
521     delete m_data_64;
522     m_data_64 = NULL;
523 }
524 
525 lldb_private::formatters::NSArrayISyntheticFrontEnd::NSArrayISyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
526     SyntheticChildrenFrontEnd (*valobj_sp.get()),
527     m_exe_ctx_ref (),
528     m_ptr_size (8),
529     m_items (0),
530     m_data_ptr (0)
531 {
532     if (valobj_sp)
533     {
534         CompilerType type = valobj_sp->GetCompilerType();
535         if (type)
536         {
537             ClangASTContext *ast = valobj_sp->GetExecutionContextRef().GetTargetSP()->GetScratchClangASTContext();
538             if (ast)
539                 m_id_type = CompilerType(ast->getASTContext(), ast->getASTContext()->ObjCBuiltinIdTy);
540         }
541     }
542 }
543 
544 lldb_private::formatters::NSArrayISyntheticFrontEnd::~NSArrayISyntheticFrontEnd ()
545 {
546 }
547 
548 size_t
549 lldb_private::formatters::NSArrayISyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
550 {
551     const char* item_name = name.GetCString();
552     uint32_t idx = ExtractIndexFromString(item_name);
553     if (idx < UINT32_MAX && idx >= CalculateNumChildren())
554         return UINT32_MAX;
555     return idx;
556 }
557 
558 size_t
559 lldb_private::formatters::NSArrayISyntheticFrontEnd::CalculateNumChildren ()
560 {
561     return m_items;
562 }
563 
564 bool
565 lldb_private::formatters::NSArrayISyntheticFrontEnd::Update()
566 {
567     m_ptr_size = 0;
568     m_items = 0;
569     m_data_ptr = 0;
570     m_children.clear();
571     ValueObjectSP valobj_sp = m_backend.GetSP();
572     if (!valobj_sp)
573         return false;
574     m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
575     Error error;
576     error.Clear();
577     lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
578     if (!process_sp)
579         return false;
580     m_ptr_size = process_sp->GetAddressByteSize();
581     uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
582     m_items = process_sp->ReadPointerFromMemory(data_location, error);
583     if (error.Fail())
584         return false;
585     m_data_ptr = data_location+m_ptr_size;
586     return false;
587 }
588 
589 bool
590 lldb_private::formatters::NSArrayISyntheticFrontEnd::MightHaveChildren ()
591 {
592     return true;
593 }
594 
595 lldb::ValueObjectSP
596 lldb_private::formatters::NSArrayISyntheticFrontEnd::GetChildAtIndex (size_t idx)
597 {
598     if (idx >= CalculateNumChildren())
599         return lldb::ValueObjectSP();
600     lldb::addr_t object_at_idx = m_data_ptr;
601     object_at_idx += (idx * m_ptr_size);
602     ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
603     if (!process_sp)
604         return lldb::ValueObjectSP();
605     Error error;
606     if (error.Fail())
607         return lldb::ValueObjectSP();
608     StreamString idx_name;
609     idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
610     lldb::ValueObjectSP retval_sp = CreateValueObjectFromAddress(idx_name.GetData(),
611                                                                  object_at_idx,
612                                                                  m_exe_ctx_ref,
613                                                                  m_id_type);
614     m_children.push_back(retval_sp);
615     return retval_sp;
616 }
617 
618 SyntheticChildrenFrontEnd* lldb_private::formatters::NSArraySyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
619 {
620     if (!valobj_sp)
621         return nullptr;
622 
623     lldb::ProcessSP process_sp (valobj_sp->GetProcessSP());
624     if (!process_sp)
625         return NULL;
626     AppleObjCRuntime *runtime = (AppleObjCRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
627     if (!runtime)
628         return NULL;
629 
630     CompilerType valobj_type(valobj_sp->GetCompilerType());
631     Flags flags(valobj_type.GetTypeInfo());
632 
633     if (flags.IsClear(eTypeIsPointer))
634     {
635         Error error;
636         valobj_sp = valobj_sp->AddressOf(error);
637         if (error.Fail() || !valobj_sp)
638             return NULL;
639     }
640 
641     ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(*valobj_sp.get()));
642 
643     if (!descriptor.get() || !descriptor->IsValid())
644         return NULL;
645 
646     const char* class_name = descriptor->GetClassName().GetCString();
647 
648     if (!class_name || !*class_name)
649         return NULL;
650 
651     if (!strcmp(class_name,"__NSArrayI"))
652     {
653         return (new NSArrayISyntheticFrontEnd(valobj_sp));
654     }
655     else if (!strcmp(class_name,"__NSArrayM"))
656     {
657         if (runtime->GetFoundationVersion() >= 1100)
658             return (new NSArrayMSyntheticFrontEnd_1010(valobj_sp));
659         else
660             return (new NSArrayMSyntheticFrontEnd_109(valobj_sp));
661     }
662     else
663     {
664         return (new NSArrayCodeRunningSyntheticFrontEnd(valobj_sp));
665     }
666 }
667 
668 lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::NSArrayCodeRunningSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
669 SyntheticChildrenFrontEnd(*valobj_sp.get())
670 {}
671 
672 size_t
673 lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::CalculateNumChildren ()
674 {
675     uint64_t count = 0;
676     if (ExtractValueFromObjCExpression(m_backend, "int", "count", count))
677         return count;
678     return 0;
679 }
680 
681 lldb::ValueObjectSP
682 lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::GetChildAtIndex (size_t idx)
683 {
684     StreamString idx_name;
685     idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
686     lldb::ValueObjectSP valobj_sp = CallSelectorOnObject(m_backend,"id","objectAtIndex:",idx);
687     if (valobj_sp)
688         valobj_sp->SetName(ConstString(idx_name.GetData()));
689     return valobj_sp;
690 }
691 
692 bool
693 lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::Update()
694 {
695     return false;
696 }
697 
698 bool
699 lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::MightHaveChildren ()
700 {
701     return true;
702 }
703 
704 size_t
705 lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
706 {
707     return 0;
708 }
709 
710 lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::~NSArrayCodeRunningSyntheticFrontEnd ()
711 {}
712