#define OBJC_IMAGE_REQUIRES_GC (1<<2)
#define OBJC_IMAGE_OPTIMIZED_BY_DYLD (1<<3)
#define OBJC_IMAGE_SUPPORTS_COMPACTION (1<<4)
+#define OBJC_IMAGE_IS_SIMULATED (1<<5)
class ObjCImageInfoAtom : public ld::Atom {
public:
ObjCImageInfoAtom(ld::File::ObjcConstraint objcConstraint,
- bool compaction, bool abi2);
+ bool compaction, bool abi2, uint8_t swiftVersion);
virtual const ld::File* file() const { return NULL; }
- virtual bool translationUnitSource(const char** dir, const char**) const
- { return false; }
virtual const char* name() const { return "objc image info"; }
virtual uint64_t size() const { return sizeof(objc_image_info); }
virtual uint64_t objectAddress() const { return 0; }
template <typename A>
ObjCImageInfoAtom<A>::ObjCImageInfoAtom(ld::File::ObjcConstraint objcConstraint, bool compaction,
- bool abi2)
+ bool abi2, uint8_t swiftVersion)
: ld::Atom(abi2 ? _s_sectionABI2 : _s_sectionABI1, ld::Atom::definitionRegular, ld::Atom::combineNever,
ld::Atom::scopeLinkageUnit, ld::Atom::typeUnclassified,
symbolTableNotIn, false, false, false, ld::Atom::Alignment(2))
if ( compaction )
value |= OBJC_IMAGE_SUPPORTS_COMPACTION;
break;
+ case ld::File::objcConstraintRetainReleaseForSimulator:
+ value |= OBJC_IMAGE_IS_SIMULATED;
+ break;
}
+ // provide swift language version in final binary for runtime to inspect
+ value |= (swiftVersion << 8);
+
_content.version = 0;
A::P::E::set32(_content.flags, value);
}
std::set<const ld::Atom*>& deadAtoms);
virtual const ld::File* file() const { return _file; }
- virtual bool translationUnitSource(const char** dir, const char**) const
- { return false; }
virtual const char* name() const { return "objc merged method list"; }
virtual uint64_t size() const { return _methodCount*3*sizeof(pint_t) + 8; }
virtual uint64_t objectAddress() const { return 0; }
std::set<const ld::Atom*>& deadAtoms);
virtual const ld::File* file() const { return _file; }
- virtual bool translationUnitSource(const char** dir, const char**) const
- { return false; }
virtual const char* name() const { return "objc merged protocol list"; }
virtual uint64_t size() const { return (_protocolCount+1)*sizeof(pint_t); }
virtual uint64_t objectAddress() const { return 0; }
std::set<const ld::Atom*>& deadAtoms);
virtual const ld::File* file() const { return _file; }
- virtual bool translationUnitSource(const char** dir, const char**) const
- { return false; }
virtual const char* name() const { return "objc merged property list"; }
virtual uint64_t size() const { return _propertyCount*2*sizeof(pint_t) + 8; }
virtual uint64_t objectAddress() const { return 0; }
// overrides of ld::Atom
virtual const ld::File* file() const { return _atom->file(); }
- virtual bool translationUnitSource(const char** dir, const char** nm) const
- { return _atom->translationUnitSource(dir, nm); }
virtual const char* name() const { return _atom->name(); }
virtual uint64_t size() const { return _atom->size(); }
virtual uint64_t objectAddress() const { return _atom->objectAddress(); }
template <typename A>
class Category : public ObjCData<A> {
public:
- static const ld::Atom* getClass(ld::Internal& state, const ld::Atom* contentAtom);
+ static const ld::Atom* getClass(ld::Internal& state, const ld::Atom* contentAtom, bool& hasAddend);
static const ld::Atom* getInstanceMethods(ld::Internal& state, const ld::Atom* contentAtom);
static const ld::Atom* getClassMethods(ld::Internal& state, const ld::Atom* contentAtom);
static const ld::Atom* getProtocols(ld::Internal& state, const ld::Atom* contentAtom);
template <typename A>
-const ld::Atom* Category<A>::getClass(ld::Internal& state, const ld::Atom* contentAtom)
+const ld::Atom* Category<A>::getClass(ld::Internal& state, const ld::Atom* contentAtom, bool& hasAddend)
{
- return ObjCData<A>::getPointerInContent(state, contentAtom, sizeof(pint_t)); // category_t.cls
+ return ObjCData<A>::getPointerInContent(state, contentAtom, sizeof(pint_t), &hasAddend); // category_t.cls
}
template <typename A>
std::set<const ld::Atom*> nlcatListAtoms;
for (std::vector<ld::Internal::FinalSection*>::iterator sit=state.sections.begin(); sit != state.sections.end(); ++sit) {
ld::Internal::FinalSection* sect = *sit;
- if ( (strcmp(sect->sectionName(), "__objc_nlcatlist") == 0) && (strcmp(sect->segmentName(), "__DATA") == 0) ) {
+ if ( (strcmp(sect->sectionName(), "__objc_nlcatlist") == 0) && (strncmp(sect->segmentName(), "__DATA", 6) == 0) ) {
for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
const ld::Atom* categoryListElementAtom = *ait;
for (unsigned int offset=0; offset < categoryListElementAtom->size(); offset += sizeof(pint_t)) {
// ignore categories also in __objc_nlcatlist
if ( nlcatListAtoms.count(categoryAtom) != 0 )
continue;
- const ld::Atom* categoryOnClassAtom = Category<A>::getClass(state, categoryAtom);
+ const ld::Atom* categoryOnClassAtom = Category<A>::getClass(state, categoryAtom, hasAddend);
assert(categoryOnClassAtom != NULL);
+ // only look at classes defined in this image
if ( categoryOnClassAtom->definition() != ld::Atom::definitionProxy ) {
- // only look at classes defined in this image
+ // <rdar://problem/16107696> for now, back off optimization on new style classes
+ if ( hasAddend != 0 )
+ continue;
+ // <rdar://problem/17249777> don't apply categories to swift classes
+ if ( categoryOnClassAtom->hasFixupsOfKind(ld::Fixup::kindNoneGroupSubordinate) )
+ continue;
+
CatMap::iterator pos = classToCategories.find(categoryOnClassAtom);
if ( pos == classToCategories.end() ) {
classToCategories[categoryOnClassAtom] = new std::vector<const ld::Atom*>();
}
}
// record method list section
- if ( (strcmp(sect->sectionName(), "__objc_const") == 0) && (strcmp(sect->segmentName(), "__DATA") == 0) )
+ if ( (strcmp(sect->sectionName(), "__objc_const") == 0) && (strncmp(sect->segmentName(), "__DATA", 6) == 0) )
methodListSection = sect;
}
const ld::Atom* newClassRO = Class<A>::setInstanceMethodList(state, classAtom, newInstanceMethodListAtom, deadAtoms);
// add new method list to final sections
methodListSection->atoms.push_back(newInstanceMethodListAtom);
+ state.atomToSection[newInstanceMethodListAtom] = methodListSection;
if ( newClassRO != NULL ) {
assert(strcmp(newClassRO->section().sectionName(), "__objc_const") == 0);
methodListSection->atoms.push_back(newClassRO);
+ state.atomToSection[newClassRO] = methodListSection;
}
}
// if any category adds class methods, generate new merged method list, and replace
const ld::Atom* newClassRO = Class<A>::setClassMethodList(state, classAtom, newClassMethodListAtom, deadAtoms);
// add new method list to final sections
methodListSection->atoms.push_back(newClassMethodListAtom);
+ state.atomToSection[newClassMethodListAtom] = methodListSection;
if ( newClassRO != NULL ) {
assert(strcmp(newClassRO->section().sectionName(), "__objc_const") == 0);
methodListSection->atoms.push_back(newClassRO);
+ state.atomToSection[newClassRO] = methodListSection;
}
}
// if any category adds protocols, generate new merged protocol list, and replace
const ld::Atom* newMetaClassRO = Class<A>::setClassProtocolList(state, classAtom, newProtocolListAtom, deadAtoms);
// add new protocol list to final sections
methodListSection->atoms.push_back(newProtocolListAtom);
+ state.atomToSection[newProtocolListAtom] = methodListSection;
if ( newClassRO != NULL ) {
assert(strcmp(newClassRO->section().sectionName(), "__objc_const") == 0);
methodListSection->atoms.push_back(newClassRO);
+ state.atomToSection[newClassRO] = methodListSection;
}
if ( newMetaClassRO != NULL ) {
assert(strcmp(newMetaClassRO->section().sectionName(), "__objc_const") == 0);
methodListSection->atoms.push_back(newMetaClassRO);
+ state.atomToSection[newMetaClassRO] = methodListSection;
}
}
// if any category adds properties, generate new merged property list, and replace
const ld::Atom* newClassRO = Class<A>::setInstancePropertyList(state, classAtom, newPropertyListAtom, deadAtoms);
// add new property list to final sections
methodListSection->atoms.push_back(newPropertyListAtom);
+ state.atomToSection[newPropertyListAtom] = methodListSection;
if ( newClassRO != NULL ) {
assert(strcmp(newClassRO->section().sectionName(), "__objc_const") == 0);
methodListSection->atoms.push_back(newClassRO);
+ state.atomToSection[newClassRO] = methodListSection;
}
}
#if SUPPORT_ARCH_x86_64
case CPU_TYPE_X86_64:
state.addAtom(*new ObjCImageInfoAtom<x86_64>(state.objcObjectConstraint, compaction,
- true));
+ true, state.swiftVersion));
break;
#endif
#if SUPPORT_ARCH_i386
case CPU_TYPE_I386:
state.addAtom(*new ObjCImageInfoAtom<x86>(state.objcObjectConstraint, compaction,
- opts.objCABIVersion2POverride() ? true : false));
+ opts.objCABIVersion2POverride() ? true : false, state.swiftVersion));
break;
#endif
+#if SUPPORT_ARCH_arm_any
case CPU_TYPE_ARM:
state.addAtom(*new ObjCImageInfoAtom<arm>(state.objcObjectConstraint, compaction,
- true));
+ true, state.swiftVersion));
break;
+#endif
+#if SUPPORT_ARCH_arm64
+ case CPU_TYPE_ARM64:
+ state.addAtom(*new ObjCImageInfoAtom<arm64>(state.objcObjectConstraint, compaction,
+ true, state.swiftVersion));
+ break;
+#endif
default:
assert(0 && "unknown objc arch");
}
#endif
#if SUPPORT_ARCH_i386
case CPU_TYPE_I386:
- // disable optimization until fully tested
if ( opts.objCABIVersion2POverride() )
OptimizeCategories<x86>::doit(opts, state);
break;
#endif
#if SUPPORT_ARCH_arm_any
case CPU_TYPE_ARM:
- // disable optimization until fully tested
OptimizeCategories<arm>::doit(opts, state);
break;
+#endif
+#if SUPPORT_ARCH_arm64
+ case CPU_TYPE_ARM64:
+ // disabled until tested
+ break;
#endif
default:
assert(0 && "unknown objc arch");