diff --git a/aggregate.h b/aggregate.h
index d607b0a..59eaf2e 100644
--- a/aggregate.h
+++ b/aggregate.h
@@ -188,7 +188,12 @@ struct BaseClass
 #if DMDV2
 #define CLASSINFO_SIZE  (0x3C+16+4)     // value of ClassInfo.size
 #else
-#define CLASSINFO_SIZE  (0x3C+12+4)     // value of ClassInfo.size
+    // warning: if the user's object.d contains a ClassInfo.pointermap field,
+    //  CLASSINFO_SIZE grows by an additonal 2 words - this is handled
+    //  dynamically in ClassDeclaration::toObjFile
+    //now, the ONLY purpose of this is for the object.d incompatibility warning
+#define CLASSINFO_SIZE_1  (0x3C+12+4)     // value of ClassInfo.size
+#define CLASSINFO_SIZE_2  (0x3C+12+4+8)     // value of ClassInfo.size
 #endif
 
 struct ClassDeclaration : AggregateDeclaration
diff --git a/attrib.c b/attrib.c
index ab135f9..e0b7879 100644
--- a/attrib.c
+++ b/attrib.c
@@ -277,6 +277,20 @@ int AttribDeclaration::hasPointers()
     return 0;
 }
 
+void AttribDeclaration::fillPointerMap(PointerMap *pm, size_t offset)
+{
+    Array *d = include(NULL, NULL);
+
+    if (d)
+    {
+        for (size_t i = 0; i < d->dim; i++)
+        {
+            Dsymbol *s = (Dsymbol *)d->data[i];
+            s->fillPointerMap(pm, offset);
+        }
+    }
+}
+
 const char *AttribDeclaration::kind()
 {
     return "attribute";
diff --git a/attrib.h b/attrib.h
index f4a8498..a381a07 100644
--- a/attrib.h
+++ b/attrib.h
@@ -23,6 +23,7 @@ struct LabelDsymbol;
 struct Initializer;
 struct Module;
 struct Condition;
+struct PointerMap;
 #ifdef _DH
 struct HdrGenState;
 #endif
@@ -51,6 +52,7 @@ struct AttribDeclaration : Dsymbol
     const char *kind();
     int oneMember(Dsymbol **ps);
     int hasPointers();
+    void fillPointerMap(PointerMap *pm, size_t offset);
     void checkCtorConstInit();
     void addLocalClass(ClassDeclarations *);
     void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
diff --git a/declaration.c b/declaration.c
index 5c07c58..fb9698c 100644
--- a/declaration.c
+++ b/declaration.c
@@ -1372,6 +1372,13 @@ int VarDeclaration::hasPointers()
     return (!isDataseg() && type->hasPointers());
 }
 
+void VarDeclaration::fillPointerMap(PointerMap *pm, size_t a_offset)
+{
+    //printf("VarDeclaration::fillPointerMap() %s, ty = %d, offs=%d\n", toChars(), type->ty, (int)offset);
+    if (!isDataseg())
+        type->fillPointerMap(pm, offset + a_offset);
+}
+
 /******************************************
  * If a variable has an auto destructor call, return call for it.
  * Otherwise, return NULL.
diff --git a/declaration.h b/declaration.h
index f9f5707..de5f8d7 100644
--- a/declaration.h
+++ b/declaration.h
@@ -271,6 +271,7 @@ struct VarDeclaration : Declaration
     int isThreadlocal();
     int isCTFE();
     int hasPointers();
+    void fillPointerMap(PointerMap *pm, size_t offset);
 #if DMDV2
     int canTakeAddressOf();
     int needsAutoDtor();
diff --git a/dsymbol.c b/dsymbol.c
index 5b38d7f..784b491 100644
--- a/dsymbol.c
+++ b/dsymbol.c
@@ -148,6 +148,10 @@ int Dsymbol::hasPointers()
     return 0;
 }
 
+void Dsymbol::fillPointerMap(PointerMap *pm, size_t offset)
+{
+}
+
 char *Dsymbol::toChars()
 {
     return ident ? ident->toChars() : (char *)"__anonymous";
diff --git a/dsymbol.h b/dsymbol.h
index 5c0dbb1..3568d2a 100644
--- a/dsymbol.h
+++ b/dsymbol.h
@@ -70,6 +70,7 @@ struct DeleteDeclaration;
 struct HdrGenState;
 struct OverloadSet;
 struct AA;
+struct PointerMap;
 #if TARGET_NET
 struct PragmaScope;
 #endif
@@ -179,6 +180,7 @@ struct Dsymbol : Object
     virtual int oneMember(Dsymbol **ps);
     static int oneMembers(Array *members, Dsymbol **ps);
     virtual int hasPointers();
+    virtual void fillPointerMap(PointerMap *pm, size_t offset);
     virtual void addLocalClass(ClassDeclarations *) { }
     virtual void checkCtorConstInit() { }
 
diff --git a/idgen.c b/idgen.c
index 8e3bf4c..60de3a6 100644
--- a/idgen.c
+++ b/idgen.c
@@ -91,6 +91,10 @@ Msgtable msgtable[] =
     { "_argptr" },
     { "_match" },
 
+    // check for PointerMap-aware runtime
+    { "pointermap" }, //ClassInfo.pointermap
+    { "m_pointermap" }, //TypeInfo_Struct.m_pointermap
+
     { "LINE", "__LINE__" },
     { "FILE", "__FILE__" },
     { "DATE", "__DATE__" },
diff --git a/mars.c b/mars.c
index d6fc98c..1e84903 100644
--- a/mars.c
+++ b/mars.c
@@ -382,6 +382,8 @@ int main(int argc, char *argv[])
 #error "fix this"
 #endif
 
+    VersionCondition::addPredefinedGlobalIdent("D_HavePointerMap");
+
     VersionCondition::addPredefinedGlobalIdent("LittleEndian");
     //VersionCondition::addPredefinedGlobalIdent("D_Bits");
 #if DMDV2
diff --git a/mtype.c b/mtype.c
index f984275..fa2a47d 100644
--- a/mtype.c
+++ b/mtype.c
@@ -832,6 +832,20 @@ int Type::hasPointers()
     return FALSE;
 }
 
+void Type::fillPointerMap(PointerMap *pm, size_t offset)
+{
+    // special case: static void arrays inside structs/classes
+    // justification: union { void[8] a; void[] b; } (often used for variants)
+    //  should just be fully scanned, instead of only b.ptr
+    // [dynamic void[] arrays are handled by TypeInfo_v.flags() (that's why
+    //  hasPointers() is not special cased for Tvoid?)]
+    if (ty == Tvoid)
+    {
+        if (offset + sizeof(size_t) <= pm->size())
+            pm->pointer(offset);
+    }
+}
+
 /* ============================= TypeError =========================== */
 
 TypeError::TypeError()
@@ -2056,6 +2070,18 @@ int TypeSArray::hasPointers()
     return next->hasPointers();
 }
 
+void TypeSArray::fillPointerMap(PointerMap *pm, size_t offset)
+{
+    // for all array items
+    // static arrays of size 0 produce nothing
+    size_t d = dim->toInteger();
+    size_t s = next->size();
+    for (size_t n = 0; n < d; n++)
+    {
+        next->fillPointerMap(pm, offset + n * s);
+    }
+}
+
 /***************************** TypeDArray *****************************/
 
 TypeDArray::TypeDArray(Type *t)
@@ -2205,6 +2231,12 @@ int TypeDArray::hasPointers()
     return TRUE;
 }
 
+void TypeDArray::fillPointerMap(PointerMap *pm, size_t offset)
+{
+    // like struct Array { size_t length; byte* data; }
+    pm->pointer(offset + sizeof(size_t));
+}
+
 /***************************** TypeAArray *****************************/
 
 TypeAArray::TypeAArray(Type *t, Type *index)
@@ -2447,6 +2479,12 @@ int TypeAArray::hasPointers()
     return TRUE;
 }
 
+void TypeAArray::fillPointerMap(PointerMap *pm, size_t offset)
+{
+    // a pointer to the internal AA struct
+    pm->pointer(offset);
+}
+
 /***************************** TypePointer *****************************/
 
 TypePointer::TypePointer(Type *t)
@@ -2555,6 +2593,11 @@ int TypePointer::hasPointers()
     return TRUE;
 }
 
+void TypePointer::fillPointerMap(PointerMap *pm, size_t offset)
+{
+    pm->pointer(offset);
+}
+
 
 /***************************** TypeReference *****************************/
 
@@ -3183,6 +3226,14 @@ int TypeDelegate::hasPointers()
     return TRUE;
 }
 
+void TypeDelegate::fillPointerMap(PointerMap *pm, size_t offset)
+{
+    // ABI: .ptr followed by .funcptr
+    // assume .funcptr always points to static data (code)
+    // thus, only .ptr needs to be scanned
+    pm->pointer(offset);
+}
+
 
 
 /***************************** TypeQualified *****************************/
@@ -4094,6 +4145,11 @@ int TypeEnum::hasPointers()
     return toBasetype()->hasPointers();
 }
 
+void TypeEnum::fillPointerMap(PointerMap *pm, size_t offset)
+{
+    toBasetype()->fillPointerMap(pm, offset);
+}
+
 /***************************** TypeTypedef *****************************/
 
 TypeTypedef::TypeTypedef(TypedefDeclaration *sym)
@@ -4302,6 +4358,11 @@ int TypeTypedef::hasPointers()
     return toBasetype()->hasPointers();
 }
 
+void TypeTypedef::fillPointerMap(PointerMap *pm, size_t offset)
+{
+    toBasetype()->fillPointerMap(pm, offset);
+}
+
 /***************************** TypeStruct *****************************/
 
 TypeStruct::TypeStruct(StructDeclaration *sym)
@@ -4645,6 +4706,20 @@ int TypeStruct::hasPointers()
     return FALSE;
 }
 
+void TypeStruct::fillPointerMap(PointerMap *pm, size_t offset)
+{
+    StructDeclaration *s = sym;
+
+    sym->size(0);               // give error for forward references
+    if (s->members)
+    {
+        for (size_t i = 0; i < s->members->dim; i++)
+        {
+            Dsymbol *sm = (Dsymbol *)s->members->data[i];
+            sm->fillPointerMap(pm, offset);
+        }
+    }
+}
 
 /***************************** TypeClass *****************************/
 
@@ -5057,6 +5132,11 @@ int TypeClass::hasPointers()
     return TRUE;
 }
 
+void TypeClass::fillPointerMap(PointerMap *pm, size_t offset)
+{
+    pm->pointer(offset);
+}
+
 /***************************** TypeTuple *****************************/
 
 TypeTuple::TypeTuple(Parameters *arguments)
@@ -5561,3 +5641,54 @@ Parameter *Parameter::getNth(Parameters *args, size_t nth, size_t *pn)
         *pn += n;
     return NULL;
 }
+
+
+PointerMap::PointerMap()
+{
+    m_data = 0;
+    m_dlen = 0;
+    m_size = 0;
+}
+
+PointerMap::~PointerMap()
+{
+    mem.free(m_data);
+}
+
+/***
+ * Set size in bytes and reinit all bits to 0.
+ */
+void PointerMap::setSize(size_t bytes)
+{
+    mem.free(m_data);
+    m_size = bytes;
+    size_t nelem = bytes / sizeof(size_t);
+    m_dlen = 1 + (nelem + BITS - 1) / BITS;
+    m_data = (size_t*)mem.calloc(m_dlen, sizeof(size_t));
+    assert(m_data);
+    m_data[0] = nelem;
+}
+
+size_t PointerMap::size()
+{
+    return m_size;
+}
+
+/***
+ * Mark position at offset as pointer.
+ * Actually does nothing if the offset isn't aligned.
+ */
+void PointerMap::pointer(size_t offset)
+{
+    assert(m_data);
+    assert(offset < m_size);
+    //reject unaligned pointers
+    if ((offset & (sizeof(size_t) - 1)) != 0)
+        return;
+    size_t elem = offset / sizeof(size_t);
+    assert(elem < m_data[0]);
+    size_t bitpos = elem % BITS;
+    size_t npos = 1 + elem / BITS;
+    assert(npos < m_dlen);
+    m_data[npos] |= 1 << bitpos;
+}
diff --git a/mtype.h b/mtype.h
index 5147992..142fe40 100644
--- a/mtype.h
+++ b/mtype.h
@@ -38,6 +38,7 @@ enum LINK;
 struct TypeBasic;
 struct HdrGenState;
 struct Parameter;
+struct PointerMap;
 
 // Back end
 #if IN_GCC
@@ -246,6 +247,7 @@ struct Type : Object
     virtual Type *reliesOnTident();
     virtual Expression *toExpression();
     virtual int hasPointers();
+    virtual void fillPointerMap(PointerMap *pm, size_t offset);
     Type *next;
     Type *nextOf() { return next; }
 
@@ -362,6 +364,7 @@ struct TypeSArray : TypeArray
     TypeInfoDeclaration *getTypeInfoDeclaration();
     Expression *toExpression();
     int hasPointers();
+    void fillPointerMap(PointerMap *pm, size_t offset);
 
     type *toCtype();
     type *toCParamtype();
@@ -386,6 +389,7 @@ struct TypeDArray : TypeArray
     int builtinTypeInfo();
     TypeInfoDeclaration *getTypeInfoDeclaration();
     int hasPointers();
+    void fillPointerMap(PointerMap *pm, size_t offset);
 
     type *toCtype();
 };
@@ -409,6 +413,7 @@ struct TypeAArray : TypeArray
     int checkBoolean();
     TypeInfoDeclaration *getTypeInfoDeclaration();
     int hasPointers();
+    void fillPointerMap(PointerMap *pm, size_t offset);
 
     // Back end
     Symbol *aaGetSymbol(const char *func, int flags);
@@ -429,6 +434,7 @@ struct TypePointer : Type
     int isZeroInit(Loc loc);
     TypeInfoDeclaration *getTypeInfoDeclaration();
     int hasPointers();
+    void fillPointerMap(PointerMap *pm, size_t offset);
 
     type *toCtype();
 };
@@ -489,6 +495,7 @@ struct TypeDelegate : Type
     TypeInfoDeclaration *getTypeInfoDeclaration();
     Expression *dotExp(Scope *sc, Expression *e, Identifier *ident);
     int hasPointers();
+    void fillPointerMap(PointerMap *pm, size_t offset);
 
     type *toCtype();
 };
@@ -577,6 +584,7 @@ struct TypeStruct : Type
     MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes);
     TypeInfoDeclaration *getTypeInfoDeclaration();
     int hasPointers();
+    void fillPointerMap(PointerMap *pm, size_t offset);
 
     type *toCtype();
 };
@@ -607,6 +615,7 @@ struct TypeEnum : Type
     MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes);
     TypeInfoDeclaration *getTypeInfoDeclaration();
     int hasPointers();
+    void fillPointerMap(PointerMap *pm, size_t offset);
 #if CPP_MANGLE
     void toCppMangle(OutBuffer *buf, CppMangleState *cms);
 #endif
@@ -646,6 +655,7 @@ struct TypeTypedef : Type
     MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes);
     TypeInfoDeclaration *getTypeInfoDeclaration();
     int hasPointers();
+    void fillPointerMap(PointerMap *pm, size_t offset);
 
     type *toCtype();
     type *toCParamtype();
@@ -674,6 +684,7 @@ struct TypeClass : Type
     int checkBoolean();
     TypeInfoDeclaration *getTypeInfoDeclaration();
     int hasPointers();
+    void fillPointerMap(PointerMap *pm, size_t offset);
     int builtinTypeInfo();
 #if DMDV2
     Type *toHeadMutable();
@@ -750,4 +761,26 @@ extern int Tptrdiff_t;
 
 int arrayTypeCompatible(Loc loc, Type *t1, Type *t2);
 
+//"abstracted" because we might want to support other representations
+//e.g. a list of offsets
+struct PointerMap
+{
+    static const size_t BITS = sizeof(size_t) * 8;
+
+    size_t* m_data; //data in same format as D's PointerMap.bits.ptr
+    size_t m_dlen; //length of m_data
+    size_t m_size; //size of the type
+
+    PointerMap();
+    ~PointerMap();
+
+    void setSize(size_t bytes);
+    size_t size();
+    void pointer(size_t offset);
+    void toDt(dt_t **pdt);
+
+    //write an "invalid" PointerMap instance
+    static void toDtInvalid(dt_t **pdt);
+};
+
 #endif /* DMD_MTYPE_H */
diff --git a/template.c b/template.c
index d7455df..0f43114 100644
--- a/template.c
+++ b/template.c
@@ -4812,6 +4812,16 @@ int TemplateMixin::hasPointers()
     return 0;
 }
 
+void TemplateMixin::fillPointerMap(PointerMap *pm, size_t offset)
+{
+    for (size_t i = 0; i < members->dim; i++)
+    {
+        Dsymbol *s = (Dsymbol *)members->data[i];
+        //printf(" s = %s %s\n", s->kind(), s->toChars());
+        s->fillPointerMap(pm, offset);
+    }
+}
+
 char *TemplateMixin::toChars()
 {
     OutBuffer buf;
diff --git a/template.h b/template.h
index 9e19af8..86f4091 100644
--- a/template.h
+++ b/template.h
@@ -36,6 +36,7 @@ struct Expression;
 struct AliasDeclaration;
 struct FuncDeclaration;
 struct HdrGenState;
+struct PointerMap;
 enum MATCH;
 
 struct Tuple : Object
@@ -337,6 +338,7 @@ struct TemplateMixin : TemplateInstance
     const char *kind();
     int oneMember(Dsymbol **ps);
     int hasPointers();
+    void fillPointerMap(PointerMap *pm, size_t offset);
     char *toChars();
     void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
 
diff --git a/toobj.c b/toobj.c
index 73097cd..0930cb1 100644
--- a/toobj.c
+++ b/toobj.c
@@ -351,10 +351,14 @@ void ClassDeclaration::toObjFile(int multiobj)
        }
      */
     dt_t *dt = NULL;
+    assert(classinfo != NULL);
+    size_t CLASSINFO_SIZE = classinfo->structsize;
+    bool have_pointer_map = classinfo->search(NULL, Id::pointermap, 0);
     offset = CLASSINFO_SIZE;                    // must be ClassInfo.size
     if (classinfo)
     {
-        if (classinfo->structsize != CLASSINFO_SIZE)
+        if ((!have_pointer_map && (classinfo->structsize != CLASSINFO_SIZE_1))
+            || (have_pointer_map && (classinfo->structsize != CLASSINFO_SIZE_2)))
         {
             error("mismatch between dmd and object.d or object.di found. Check installation and import paths with -v compiler switch.");
             fatal();
@@ -464,6 +468,26 @@ void ClassDeclaration::toObjFile(int multiobj)
     dtxoff(&dt, type->vtinfo->toSymbol(), 0, TYnptr);   // typeinfo
     //dtdword(&dt, 0);
 
+    // pointermap - only with pointermap-aware runtime
+    if (have_pointer_map)
+    {
+        PointerMap pm;
+        pm.setSize(structsize);
+        for (ClassDeclaration *cd = this; cd; cd = cd->baseClass)
+        {
+            if (cd->members)
+            {
+                for (size_t i = 0; i < cd->members->dim; i++)
+                {
+                    Dsymbol *sm = (Dsymbol *)cd->members->data[i];
+                    //printf("sm = %s %s\n", sm->kind(), sm->toChars());
+                    sm->fillPointerMap(&pm, 0);
+                }
+            }
+        }
+        pm.toDt(&dt);
+    }
+
     //////////////////////////////////////////////
 
     // Put out vtblInterfaces->data[]. Must immediately follow csym, because
@@ -717,7 +741,8 @@ unsigned ClassDeclaration::baseVtblOffset(BaseClass *bc)
     int i;
 
     //printf("ClassDeclaration::baseVtblOffset('%s', bc = %p)\n", toChars(), bc);
-    csymoffset = CLASSINFO_SIZE;
+    assert(classinfo != NULL);
+    csymoffset = classinfo->structsize;
     csymoffset += vtblInterfaces->dim * (4 * PTRSIZE);
 
     for (i = 0; i < vtblInterfaces->dim; i++)
@@ -841,6 +866,7 @@ void InterfaceDeclaration::toObjFile(int multiobj)
             const(MemberInfo[]) function(string) xgetMembers;   // module getMembers() function
 #endif
             TypeInfo typeinfo;
+            PointerMap pointermap; //optional!
        }
      */
     dt_t *dt = NULL;
@@ -869,15 +895,8 @@ void InterfaceDeclaration::toObjFile(int multiobj)
     dtdword(&dt, vtblInterfaces->dim);
     if (vtblInterfaces->dim)
     {
-        if (classinfo)
-        {
-            if (classinfo->structsize != CLASSINFO_SIZE)
-            {
-                error("mismatch between dmd and object.d or object.di found. Check installation and import paths with -v compiler switch.");
-                fatal();
-            }
-        }
-        offset = CLASSINFO_SIZE;
+        assert(classinfo != NULL);
+        offset = classinfo->structsize;
         dtxoff(&dt, csym, offset, TYnptr);      // (*)
     }
     else
@@ -913,6 +932,10 @@ void InterfaceDeclaration::toObjFile(int multiobj)
 
     dtxoff(&dt, type->vtinfo->toSymbol(), 0, TYnptr);   // typeinfo
 
+    bool have_pointer_map = classinfo->search(NULL, Id::pointermap, 0);
+    if (have_pointer_map)
+        PointerMap::toDtInvalid(&dt);
+
     //////////////////////////////////////////////
 
     // Put out vtblInterfaces->data[]. Must immediately follow csym, because
diff --git a/typinf.c b/typinf.c
index 8ebf8eb..850ca70 100644
--- a/typinf.c
+++ b/typinf.c
@@ -573,6 +573,15 @@ void TypeInfoStructDeclaration::toDt(dt_t **pdt)
     // uint m_flags;
     dtdword(pdt, tc->hasPointers());
 
+    // m_pointermap - only with pointermap-aware runtime
+    if (Type::typeinfostruct->search(NULL, Id::m_pointermap, 0))
+    {
+        PointerMap pm;
+        pm.setSize(sd->structsize);
+        tc->fillPointerMap(&pm, 0);
+        pm.toDt(pdt);
+    }
+
 #if DMDV2
     // xgetMembers
     FuncDeclaration *sgetmembers = sd->findGetMembers();
@@ -599,6 +608,19 @@ void TypeInfoStructDeclaration::toDt(dt_t **pdt)
     dtnbytes(pdt, namelen + 1, name);
 }
 
+void PointerMap::toDt(dt_t **pdt)
+{
+    //length (inline size field + bits)
+    dtdword(pdt, m_dlen);
+    //data
+    dtabytes(pdt, TYnptr, 0, m_dlen * sizeof(size_t), (char*)m_data);
+}
+
+void PointerMap::toDtInvalid(dt_t **pdt) {
+    dtdword(pdt, 0);
+    dtdword(pdt, 0);
+}
+
 void TypeInfoClassDeclaration::toDt(dt_t **pdt)
 {
     //printf("TypeInfoClassDeclaration::toDt() %s\n", tinfo->toChars());
