blob: 87dfc79289c32463ac4f24a0a2432ff98cc07b3b [file] [log] [blame]
Greg Clayton9b8ff512012-02-01 01:46:19 +00001//===-- ObjCLanguageRuntime.cpp ---------------------------------*- C++ -*-===//
Jim Ingham642036f2010-09-23 02:01:19 +00002//
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//===----------------------------------------------------------------------===//
Jim Ingham324067b2010-09-30 00:54:27 +00009#include "clang/AST/Type.h"
Jim Ingham642036f2010-09-23 02:01:19 +000010
Jim Inghamb66cd072010-09-28 01:25:32 +000011#include "lldb/Core/Log.h"
Greg Claytonce490e32013-02-13 22:56:14 +000012#include "lldb/Core/MappedHash.h"
Greg Clayton49ce8962012-08-29 21:13:06 +000013#include "lldb/Core/Module.h"
Jim Ingham642036f2010-09-23 02:01:19 +000014#include "lldb/Core/PluginManager.h"
Greg Claytonf892c422013-01-30 00:18:29 +000015#include "lldb/Core/Timer.h"
Jim Ingham324067b2010-09-30 00:54:27 +000016#include "lldb/Core/ValueObject.h"
17#include "lldb/Symbol/ClangASTContext.h"
Jim Inghamef80aab2011-05-02 18:13:59 +000018#include "lldb/Symbol/Type.h"
Greg Clayton49ce8962012-08-29 21:13:06 +000019#include "lldb/Symbol/TypeList.h"
Jim Inghamb66cd072010-09-28 01:25:32 +000020#include "lldb/Target/ObjCLanguageRuntime.h"
Sean Callanan931acec2012-02-22 23:57:45 +000021#include "lldb/Target/Target.h"
Jim Ingham642036f2010-09-23 02:01:19 +000022
Greg Claytonf892c422013-01-30 00:18:29 +000023#include "llvm/ADT/StringRef.h"
24
Jim Ingham642036f2010-09-23 02:01:19 +000025using namespace lldb;
26using namespace lldb_private;
27
28//----------------------------------------------------------------------
29// Destructor
30//----------------------------------------------------------------------
31ObjCLanguageRuntime::~ObjCLanguageRuntime()
32{
33}
34
35ObjCLanguageRuntime::ObjCLanguageRuntime (Process *process) :
Sean Callanan6e12c7a2012-03-08 02:39:03 +000036 LanguageRuntime (process),
Sean Callanan6fe8d362012-09-15 01:05:12 +000037 m_has_new_literals_and_indexing (eLazyBoolCalculate),
Greg Claytonce490e32013-02-13 22:56:14 +000038 m_isa_to_descriptor(),
39 m_isa_to_descriptor_stop_id (UINT32_MAX)
Jim Ingham642036f2010-09-23 02:01:19 +000040{
41
Jim Inghamb66cd072010-09-28 01:25:32 +000042}
43
Greg Claytonce490e32013-02-13 22:56:14 +000044bool
45ObjCLanguageRuntime::AddClass (ObjCISA isa, const ClassDescriptorSP &descriptor_sp, const char *class_name)
46{
47 if (isa != 0)
48 {
49 m_isa_to_descriptor[isa] = descriptor_sp;
50 // class_name is assumed to be valid
51 m_hash_to_isa_map.insert(std::make_pair(MappedHash::HashStringUsingDJB(class_name), isa));
52 return true;
53 }
54 return false;
55}
56
Jim Inghamb66cd072010-09-28 01:25:32 +000057void
58ObjCLanguageRuntime::AddToMethodCache (lldb::addr_t class_addr, lldb::addr_t selector, lldb::addr_t impl_addr)
59{
Greg Clayton952e9dc2013-03-27 23:08:40 +000060 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
Jim Inghamb66cd072010-09-28 01:25:32 +000061 if (log)
62 {
Daniel Malea5f35a4b2012-11-29 21:49:15 +000063 log->Printf ("Caching: class 0x%" PRIx64 " selector 0x%" PRIx64 " implementation 0x%" PRIx64 ".", class_addr, selector, impl_addr);
Jim Inghamb66cd072010-09-28 01:25:32 +000064 }
65 m_impl_cache.insert (std::pair<ClassAndSel,lldb::addr_t> (ClassAndSel(class_addr, selector), impl_addr));
66}
67
68lldb::addr_t
69ObjCLanguageRuntime::LookupInMethodCache (lldb::addr_t class_addr, lldb::addr_t selector)
70{
71 MsgImplMap::iterator pos, end = m_impl_cache.end();
72 pos = m_impl_cache.find (ClassAndSel(class_addr, selector));
73 if (pos != end)
74 return (*pos).second;
75 return LLDB_INVALID_ADDRESS;
76}
Jim Inghamef80aab2011-05-02 18:13:59 +000077
Jim Ingham58513662011-06-24 22:03:24 +000078
Sean Callanan931acec2012-02-22 23:57:45 +000079lldb::TypeSP
80ObjCLanguageRuntime::LookupInCompleteClassCache (ConstString &name)
81{
82 CompleteClassMap::iterator complete_class_iter = m_complete_class_cache.find(name);
83
84 if (complete_class_iter != m_complete_class_cache.end())
85 {
Greg Claytonef22b902012-10-23 22:41:19 +000086 // Check the weak pointer to make sure the type hasn't been unloaded
87 TypeSP complete_type_sp (complete_class_iter->second.lock());
Sean Callanan931acec2012-02-22 23:57:45 +000088
Greg Claytonef22b902012-10-23 22:41:19 +000089 if (complete_type_sp)
90 return complete_type_sp;
Sean Callanan931acec2012-02-22 23:57:45 +000091 else
Greg Claytonef22b902012-10-23 22:41:19 +000092 m_complete_class_cache.erase(name);
Sean Callanan931acec2012-02-22 23:57:45 +000093 }
94
Enrico Granata146d9522012-11-08 02:22:02 +000095 const ModuleList &modules = m_process->GetTarget().GetImages();
Greg Claytonef22b902012-10-23 22:41:19 +000096
Sean Callanan931acec2012-02-22 23:57:45 +000097 SymbolContextList sc_list;
Greg Claytonef22b902012-10-23 22:41:19 +000098 const size_t matching_symbols = modules.FindSymbolsWithNameAndType (name,
99 eSymbolTypeObjCClass,
100 sc_list);
Sean Callanan931acec2012-02-22 23:57:45 +0000101
Greg Claytonef22b902012-10-23 22:41:19 +0000102 if (matching_symbols)
Sean Callanan931acec2012-02-22 23:57:45 +0000103 {
Greg Claytonef22b902012-10-23 22:41:19 +0000104 SymbolContext sc;
Sean Callanan931acec2012-02-22 23:57:45 +0000105
Greg Claytonef22b902012-10-23 22:41:19 +0000106 sc_list.GetContextAtIndex(0, sc);
107
108 ModuleSP module_sp(sc.module_sp);
109
110 if (!module_sp)
Sean Callanan931acec2012-02-22 23:57:45 +0000111 return TypeSP();
Sean Callanan931acec2012-02-22 23:57:45 +0000112
Greg Claytonef22b902012-10-23 22:41:19 +0000113 const SymbolContext null_sc;
114 const bool exact_match = true;
115 const uint32_t max_matches = UINT32_MAX;
116 TypeList types;
117
118 const uint32_t num_types = module_sp->FindTypes (null_sc,
119 name,
120 exact_match,
121 max_matches,
122 types);
123
124 if (num_types)
Sean Callanan282c22c2012-12-19 23:05:01 +0000125 {
Greg Claytonef22b902012-10-23 22:41:19 +0000126 uint32_t i;
127 for (i = 0; i < num_types; ++i)
128 {
129 TypeSP type_sp (types.GetTypeAtIndex(i));
130
131 if (ClangASTContext::IsObjCClassType(type_sp->GetClangForwardType()))
132 {
133 if (type_sp->IsCompleteObjCClass())
134 {
135 m_complete_class_cache[name] = type_sp;
136 return type_sp;
137 }
Greg Claytonef22b902012-10-23 22:41:19 +0000138 }
139 }
Sean Callanan931acec2012-02-22 23:57:45 +0000140 }
141 }
Sean Callanan931acec2012-02-22 23:57:45 +0000142 return TypeSP();
143}
144
Jim Ingham58513662011-06-24 22:03:24 +0000145size_t
146ObjCLanguageRuntime::GetByteOffsetForIvar (ClangASTType &parent_qual_type, const char *ivar_name)
147{
148 return LLDB_INVALID_IVAR_OFFSET;
149}
150
Greg Claytonf892c422013-01-30 00:18:29 +0000151void
152ObjCLanguageRuntime::MethodName::Clear()
Jim Ingham3ad4da02011-08-15 01:32:22 +0000153{
Greg Claytonf892c422013-01-30 00:18:29 +0000154 m_full.Clear();
155 m_class.Clear();
156 m_category.Clear();
157 m_selector.Clear();
158 m_type = eTypeUnspecified;
159 m_category_is_valid = false;
160}
Greg Clayton662e5672012-01-19 03:24:53 +0000161
Greg Claytonf892c422013-01-30 00:18:29 +0000162//bool
163//ObjCLanguageRuntime::MethodName::SetName (const char *name, bool strict)
164//{
165// Clear();
166// if (name && name[0])
167// {
168// // If "strict" is true. then the method must be specified with a
169// // '+' or '-' at the beginning. If "strict" is false, then the '+'
170// // or '-' can be omitted
171// bool valid_prefix = false;
172//
173// if (name[0] == '+' || name[0] == '-')
174// {
175// valid_prefix = name[1] == '[';
176// }
177// else if (!strict)
178// {
179// // "strict" is false, the name just needs to start with '['
180// valid_prefix = name[0] == '[';
181// }
182//
183// if (valid_prefix)
184// {
185// static RegularExpression g_regex("^([-+]?)\\[([A-Za-z_][A-Za-z_0-9]*)(\\([A-Za-z_][A-Za-z_0-9]*\\))? ([A-Za-z_][A-Za-z_0-9:]*)\\]$");
186// llvm::StringRef matches[4];
187// // Since we are using a global regular expression, we must use the threadsafe version of execute
188// if (g_regex.ExecuteThreadSafe(name, matches, 4))
189// {
190// m_full.SetCString(name);
191// if (matches[0].empty())
192// m_type = eTypeUnspecified;
193// else if (matches[0][0] == '+')
194// m_type = eTypeClassMethod;
195// else
196// m_type = eTypeInstanceMethod;
197// m_class.SetString(matches[1]);
198// m_selector.SetString(matches[3]);
199// if (!matches[2].empty())
200// m_category.SetString(matches[2]);
201// }
202// }
203// }
204// return IsValid(strict);
205//}
206
207bool
208ObjCLanguageRuntime::MethodName::SetName (const char *name, bool strict)
209{
210 Clear();
211 if (name && name[0])
Jim Ingham3ad4da02011-08-15 01:32:22 +0000212 {
Greg Claytonf892c422013-01-30 00:18:29 +0000213 // If "strict" is true. then the method must be specified with a
214 // '+' or '-' at the beginning. If "strict" is false, then the '+'
215 // or '-' can be omitted
216 bool valid_prefix = false;
217
218 if (name[0] == '+' || name[0] == '-')
Jim Ingham3ad4da02011-08-15 01:32:22 +0000219 {
Greg Claytonf892c422013-01-30 00:18:29 +0000220 valid_prefix = name[1] == '[';
221 if (name[0] == '+')
222 m_type = eTypeClassMethod;
223 else
224 m_type = eTypeInstanceMethod;
225 }
226 else if (!strict)
227 {
228 // "strict" is false, the name just needs to start with '['
229 valid_prefix = name[0] == '[';
230 }
231
232 if (valid_prefix)
233 {
234 int name_len = strlen (name);
235 // Objective C methods must have at least:
236 // "-[" or "+[" prefix
237 // One character for a class name
238 // One character for the space between the class name
239 // One character for the method name
240 // "]" suffix
241 if (name_len >= (5 + (strict ? 1 : 0)) && name[name_len - 1] == ']')
Jim Ingham3ad4da02011-08-15 01:32:22 +0000242 {
Greg Claytonf892c422013-01-30 00:18:29 +0000243 m_full.SetCStringWithLength(name, name_len);
244 }
245 }
246 }
247 return IsValid(strict);
248}
249
250const ConstString &
251ObjCLanguageRuntime::MethodName::GetClassName ()
252{
253 if (!m_class)
254 {
255 if (IsValid(false))
256 {
257 const char *full = m_full.GetCString();
258 const char *class_start = (full[0] == '[' ? full + 1 : full + 2);
259 const char *paren_pos = strchr (class_start, '(');
260 if (paren_pos)
261 {
262 m_class.SetCStringWithLength (class_start, paren_pos - class_start);
263 }
264 else
265 {
266 // No '(' was found in the full name, we can definitively say
267 // that our category was valid (and empty).
268 m_category_is_valid = true;
269 const char *space_pos = strchr (full, ' ');
270 if (space_pos)
Greg Clayton662e5672012-01-19 03:24:53 +0000271 {
Greg Claytonf892c422013-01-30 00:18:29 +0000272 m_class.SetCStringWithLength (class_start, space_pos - class_start);
273 if (!m_class_category)
Jim Ingham3ad4da02011-08-15 01:32:22 +0000274 {
Greg Claytonf892c422013-01-30 00:18:29 +0000275 // No category in name, so we can also fill in the m_class_category
276 m_class_category = m_class;
Jim Ingham3ad4da02011-08-15 01:32:22 +0000277 }
278 }
279 }
Jim Ingham3ad4da02011-08-15 01:32:22 +0000280 }
Jim Ingham3ad4da02011-08-15 01:32:22 +0000281 }
Greg Claytonf892c422013-01-30 00:18:29 +0000282 return m_class;
Jim Ingham3ad4da02011-08-15 01:32:22 +0000283}
Enrico Granataae2ae942012-09-04 18:47:54 +0000284
Greg Claytonf892c422013-01-30 00:18:29 +0000285const ConstString &
286ObjCLanguageRuntime::MethodName::GetClassNameWithCategory ()
287{
288 if (!m_class_category)
289 {
290 if (IsValid(false))
291 {
292 const char *full = m_full.GetCString();
293 const char *class_start = (full[0] == '[' ? full + 1 : full + 2);
294 const char *space_pos = strchr (full, ' ');
295 if (space_pos)
296 {
297 m_class_category.SetCStringWithLength (class_start, space_pos - class_start);
298 // If m_class hasn't been filled in and the class with category doesn't
299 // contain a '(', then we can also fill in the m_class
300 if (!m_class && strchr (m_class_category.GetCString(), '(') == NULL)
301 {
302 m_class = m_class_category;
303 // No '(' was found in the full name, we can definitively say
304 // that our category was valid (and empty).
305 m_category_is_valid = true;
306
307 }
308 }
309 }
310 }
311 return m_class_category;
312}
313
314const ConstString &
315ObjCLanguageRuntime::MethodName::GetSelector ()
316{
317 if (!m_selector)
318 {
319 if (IsValid(false))
320 {
321 const char *full = m_full.GetCString();
322 const char *space_pos = strchr (full, ' ');
323 if (space_pos)
324 {
325 ++space_pos; // skip the space
326 m_selector.SetCStringWithLength (space_pos, m_full.GetLength() - (space_pos - full) - 1);
327 }
328 }
329 }
330 return m_selector;
331}
332
333const ConstString &
334ObjCLanguageRuntime::MethodName::GetCategory ()
335{
336 if (!m_category_is_valid && !m_category)
337 {
338 if (IsValid(false))
339 {
340 m_category_is_valid = true;
341 const char *full = m_full.GetCString();
342 const char *class_start = (full[0] == '[' ? full + 1 : full + 2);
343 const char *open_paren_pos = strchr (class_start, '(');
344 if (open_paren_pos)
345 {
346 ++open_paren_pos; // Skip the open paren
347 const char *close_paren_pos = strchr (open_paren_pos, ')');
348 if (close_paren_pos)
349 m_category.SetCStringWithLength (open_paren_pos, close_paren_pos - open_paren_pos);
350 }
351 }
352 }
353 return m_category;
354}
355
356ConstString
357ObjCLanguageRuntime::MethodName::GetFullNameWithoutCategory (bool empty_if_no_category)
358{
359 if (IsValid(false))
360 {
361 if (HasCategory())
362 {
363 StreamString strm;
364 if (m_type == eTypeClassMethod)
365 strm.PutChar('+');
366 else if (m_type == eTypeInstanceMethod)
367 strm.PutChar('-');
368 strm.Printf("[%s %s]", GetClassName().GetCString(), GetSelector().GetCString());
369 return ConstString(strm.GetString().c_str());
370 }
371
372 if (!empty_if_no_category)
373 {
374 // Just return the full name since it doesn't have a category
375 return GetFullName();
376 }
377 }
378 return ConstString();
379}
380
381size_t
382ObjCLanguageRuntime::MethodName::GetFullNames (std::vector<ConstString> &names, bool append)
383{
384 if (!append)
385 names.clear();
386 if (IsValid(false))
387 {
388 StreamString strm;
389 const bool is_class_method = m_type == eTypeClassMethod;
390 const bool is_instance_method = m_type == eTypeInstanceMethod;
391 const ConstString &category = GetCategory();
392 if (is_class_method || is_instance_method)
393 {
394 names.push_back (m_full);
395 if (category)
396 {
397 strm.Printf("%c[%s %s]",
398 is_class_method ? '+' : '-',
399 GetClassName().GetCString(),
400 GetSelector().GetCString());
401 names.push_back(ConstString(strm.GetString().c_str()));
402 }
403 }
404 else
405 {
406 const ConstString &class_name = GetClassName();
407 const ConstString &selector = GetSelector();
408 strm.Printf("+[%s %s]", class_name.GetCString(), selector.GetCString());
409 names.push_back(ConstString(strm.GetString().c_str()));
410 strm.Clear();
411 strm.Printf("-[%s %s]", class_name.GetCString(), selector.GetCString());
412 names.push_back(ConstString(strm.GetString().c_str()));
413 strm.Clear();
414 if (category)
415 {
416 strm.Printf("+[%s(%s) %s]", class_name.GetCString(), category.GetCString(), selector.GetCString());
417 names.push_back(ConstString(strm.GetString().c_str()));
418 strm.Clear();
419 strm.Printf("-[%s(%s) %s]", class_name.GetCString(), category.GetCString(), selector.GetCString());
420 names.push_back(ConstString(strm.GetString().c_str()));
421 }
422 }
423 }
424 return names.size();
425}
426
427
Enrico Granataae2ae942012-09-04 18:47:54 +0000428bool
429ObjCLanguageRuntime::ClassDescriptor::IsPointerValid (lldb::addr_t value,
430 uint32_t ptr_size,
431 bool allow_NULLs,
432 bool allow_tagged,
Greg Claytonbe2f3aa2012-10-09 17:51:53 +0000433 bool check_version_specific) const
Enrico Granataae2ae942012-09-04 18:47:54 +0000434{
435 if (!value)
436 return allow_NULLs;
437 if ( (value % 2) == 1 && allow_tagged)
438 return true;
439 if ((value % ptr_size) == 0)
440 return (check_version_specific ? CheckPointer(value,ptr_size) : true);
441 else
442 return false;
443}
444
445ObjCLanguageRuntime::ObjCISA
Sean Callananc718b962012-09-11 21:44:01 +0000446ObjCLanguageRuntime::GetISA(const ConstString &name)
447{
Greg Claytonce490e32013-02-13 22:56:14 +0000448 ISAToDescriptorIterator pos = GetDescriptorIterator (name);
449 if (pos != m_isa_to_descriptor.end())
450 return pos->first;
Sean Callananc718b962012-09-11 21:44:01 +0000451 return 0;
452}
453
Greg Claytonce490e32013-02-13 22:56:14 +0000454ObjCLanguageRuntime::ISAToDescriptorIterator
455ObjCLanguageRuntime::GetDescriptorIterator (const ConstString &name)
456{
457 ISAToDescriptorIterator end = m_isa_to_descriptor.end();
458
459 if (name)
460 {
461 UpdateISAToDescriptorMap();
462 if (m_hash_to_isa_map.empty())
463 {
464 // No name hashes were provided, we need to just linearly power through the
465 // names and find a match
466 for (ISAToDescriptorIterator pos = m_isa_to_descriptor.begin(); pos != end; ++pos)
467 {
468 if (pos->second->GetClassName() == name)
469 return pos;
470 }
471 }
472 else
473 {
474 // Name hashes were provided, so use them to efficiently lookup name to isa/descriptor
475 const uint32_t name_hash = MappedHash::HashStringUsingDJB (name.GetCString());
476 std::pair <HashToISAIterator, HashToISAIterator> range = m_hash_to_isa_map.equal_range(name_hash);
477 for (HashToISAIterator range_pos = range.first; range_pos != range.second; ++range_pos)
478 {
479 ISAToDescriptorIterator pos = m_isa_to_descriptor.find (range_pos->second);
480 if (pos != m_isa_to_descriptor.end())
481 {
482 if (pos->second->GetClassName() == name)
483 return pos;
484 }
485 }
486 }
487 }
488 return end;
489}
490
491
Sean Callananc718b962012-09-11 21:44:01 +0000492ObjCLanguageRuntime::ObjCISA
Enrico Granataae2ae942012-09-04 18:47:54 +0000493ObjCLanguageRuntime::GetParentClass(ObjCLanguageRuntime::ObjCISA isa)
494{
Greg Claytonbe2f3aa2012-10-09 17:51:53 +0000495 ClassDescriptorSP objc_class_sp (GetClassDescriptor(isa));
496 if (objc_class_sp)
Enrico Granataae2ae942012-09-04 18:47:54 +0000497 {
Greg Claytonbe2f3aa2012-10-09 17:51:53 +0000498 ClassDescriptorSP objc_super_class_sp (objc_class_sp->GetSuperclass());
499 if (objc_super_class_sp)
500 return objc_super_class_sp->GetISA();
Enrico Granataae2ae942012-09-04 18:47:54 +0000501 }
Greg Claytonbe2f3aa2012-10-09 17:51:53 +0000502 return 0;
Enrico Granataae2ae942012-09-04 18:47:54 +0000503}
504
Enrico Granataae2ae942012-09-04 18:47:54 +0000505ConstString
506ObjCLanguageRuntime::GetActualTypeName(ObjCLanguageRuntime::ObjCISA isa)
507{
Greg Claytonbe2f3aa2012-10-09 17:51:53 +0000508 ClassDescriptorSP objc_class_sp (GetNonKVOClassDescriptor(isa));
509 if (objc_class_sp)
510 return objc_class_sp->GetClassName();
511 return ConstString();
Enrico Granataae2ae942012-09-04 18:47:54 +0000512}
Greg Claytonbe2f3aa2012-10-09 17:51:53 +0000513
514ObjCLanguageRuntime::ClassDescriptorSP
Greg Claytona5104372012-10-11 18:07:21 +0000515ObjCLanguageRuntime::GetClassDescriptor (const ConstString &class_name)
Greg Claytonbe2f3aa2012-10-09 17:51:53 +0000516{
Greg Claytonce490e32013-02-13 22:56:14 +0000517 ISAToDescriptorIterator pos = GetDescriptorIterator (class_name);
518 if (pos != m_isa_to_descriptor.end())
519 return pos->second;
Greg Claytona5104372012-10-11 18:07:21 +0000520 return ClassDescriptorSP();
521
522}
523
524ObjCLanguageRuntime::ClassDescriptorSP
525ObjCLanguageRuntime::GetClassDescriptor (ValueObject& valobj)
526{
527 ClassDescriptorSP objc_class_sp;
528 // if we get an invalid VO (which might still happen when playing around
529 // with pointers returned by the expression parser, don't consider this
530 // a valid ObjC object)
531 if (valobj.GetValue().GetContextType() != Value::eContextTypeInvalid)
532 {
533 addr_t isa_pointer = valobj.GetPointerValue();
534 if (isa_pointer != LLDB_INVALID_ADDRESS)
535 {
536 ExecutionContext exe_ctx (valobj.GetExecutionContextRef());
537
538 Process *process = exe_ctx.GetProcessPtr();
539 if (process)
540 {
541 Error error;
542 ObjCISA isa = process->ReadPointerFromMemory(isa_pointer, error);
543 if (isa != LLDB_INVALID_ADDRESS)
544 objc_class_sp = GetClassDescriptor (isa);
545 }
546 }
547 }
548 return objc_class_sp;
549}
550
551ObjCLanguageRuntime::ClassDescriptorSP
552ObjCLanguageRuntime::GetNonKVOClassDescriptor (ValueObject& valobj)
553{
554 ObjCLanguageRuntime::ClassDescriptorSP objc_class_sp (GetClassDescriptor (valobj));
555 if (objc_class_sp)
556 {
557 if (!objc_class_sp->IsKVO())
558 return objc_class_sp;
559
560 ClassDescriptorSP non_kvo_objc_class_sp(objc_class_sp->GetSuperclass());
561 if (non_kvo_objc_class_sp && non_kvo_objc_class_sp->IsValid())
562 return non_kvo_objc_class_sp;
563 }
Greg Claytonbe2f3aa2012-10-09 17:51:53 +0000564 return ClassDescriptorSP();
565}
566
Greg Claytona5104372012-10-11 18:07:21 +0000567
Greg Claytonbe2f3aa2012-10-09 17:51:53 +0000568ObjCLanguageRuntime::ClassDescriptorSP
569ObjCLanguageRuntime::GetClassDescriptor (ObjCISA isa)
570{
Greg Claytonbe2f3aa2012-10-09 17:51:53 +0000571 if (isa)
572 {
Greg Claytona5104372012-10-11 18:07:21 +0000573 UpdateISAToDescriptorMap();
Greg Claytonce490e32013-02-13 22:56:14 +0000574 ObjCLanguageRuntime::ISAToDescriptorIterator pos = m_isa_to_descriptor.find(isa);
575 if (pos != m_isa_to_descriptor.end())
Greg Claytona5104372012-10-11 18:07:21 +0000576 return pos->second;
Greg Claytonbe2f3aa2012-10-09 17:51:53 +0000577 }
Greg Claytona5104372012-10-11 18:07:21 +0000578 return ClassDescriptorSP();
Greg Claytonbe2f3aa2012-10-09 17:51:53 +0000579}
580
581ObjCLanguageRuntime::ClassDescriptorSP
582ObjCLanguageRuntime::GetNonKVOClassDescriptor (ObjCISA isa)
583{
584 if (isa)
585 {
586 ClassDescriptorSP objc_class_sp = GetClassDescriptor (isa);
587 if (objc_class_sp && objc_class_sp->IsValid())
588 {
Greg Claytona5104372012-10-11 18:07:21 +0000589 if (!objc_class_sp->IsKVO())
Greg Claytonbe2f3aa2012-10-09 17:51:53 +0000590 return objc_class_sp;
Greg Claytona5104372012-10-11 18:07:21 +0000591
592 ClassDescriptorSP non_kvo_objc_class_sp(objc_class_sp->GetSuperclass());
593 if (non_kvo_objc_class_sp && non_kvo_objc_class_sp->IsValid())
594 return non_kvo_objc_class_sp;
Greg Claytonbe2f3aa2012-10-09 17:51:53 +0000595 }
596 }
597 return ClassDescriptorSP();
598}
599
600
601