From 0a31e406334d34998650c550ed2337c7fb58a72d Mon Sep 17 00:00:00 2001 From: bsimmers Date: Thu, 11 Oct 2012 22:13:46 -0700 Subject: [PATCH] Support a register base for properties in the generic translator Most of this diff was pretty mechanical, just expanding tables of helper functions. The generic translator now supports getting properties off of a base object that's in a register, avoiding a bunch of unnecessary stores in the case. This also adds most of the infrastructure necessary to support keeping intermediate values in registers if we ever want to support that. --- src/runtime/vm/instance.h | 6 + src/runtime/vm/member_operations.cpp | 58 ++- src/runtime/vm/member_operations.h | 215 ++++++---- src/runtime/vm/translator/regalloc.cpp | 13 +- src/runtime/vm/translator/regalloc.h | 1 + .../vm/translator/translator-x64-internal.h | 17 + .../vm/translator/translator-x64-vector.cpp | 449 ++++++++++++++------- src/runtime/vm/translator/translator-x64.cpp | 11 +- src/runtime/vm/translator/translator-x64.h | 3 + 9 files changed, 504 insertions(+), 269 deletions(-) diff --git a/src/runtime/vm/instance.h b/src/runtime/vm/instance.h index 7c11fde09e4..d178628ef7a 100644 --- a/src/runtime/vm/instance.h +++ b/src/runtime/vm/instance.h @@ -265,6 +265,11 @@ class Instance : public ObjectData { void raiseUndefProp(const StringData* name); }; +inline Instance* instanceFromTv(TypedValue* tv) { + ASSERT(dynamic_cast(tv->m_data.pobj)); + return static_cast(tv->m_data.pobj); +} + } } // HPHP::VM namespace HPHP { @@ -297,6 +302,7 @@ template class ExtObjectDataFlags : public ExtObjectData { ObjectData::setAttributes(flags); } }; + } // HPHP #endif diff --git a/src/runtime/vm/member_operations.cpp b/src/runtime/vm/member_operations.cpp index e6191ae35c8..41562ce4971 100644 --- a/src/runtime/vm/member_operations.cpp +++ b/src/runtime/vm/member_operations.cpp @@ -20,53 +20,48 @@ namespace HPHP { namespace VM { -void objArrayAccess(TypedValue* base) { - ASSERT(base->m_type == KindOfObject); - ASSERT(!base->m_data.pobj->isCollection()); - if (!instanceOf(tvAsCVarRef(base), "ArrayAccess")) { +void objArrayAccess(Instance* base) { + ASSERT(!base->isCollection()); + if (!instanceOf(base, "ArrayAccess")) { raise_error("Object does not implement ArrayAccess"); } } -TypedValue* objOffsetGet(TypedValue& tvRef, TypedValue* base, +TypedValue* objOffsetGet(TypedValue& tvRef, Instance* base, CVarRef offset, bool validate /* = true */) { if (validate) { objArrayAccess(base); } TypedValue* result; - ObjectData* obj = base->m_data.pobj; - ASSERT(!obj->isCollection()); - Instance* instance = static_cast(obj); + ASSERT(!base->isCollection()); static StringData* sd__offsetGet = StringData::GetStaticString("offsetGet"); - const Func* method = instance->methodNamed(sd__offsetGet); + const Func* method = base->methodNamed(sd__offsetGet); ASSERT(method != NULL); - instance->invokeUserMethod(&tvRef, method, CREATE_VECTOR1(offset)); + base->invokeUserMethod(&tvRef, method, CREATE_VECTOR1(offset)); result = &tvRef; return result; } -static bool objOffsetExists(TypedValue* base, CVarRef offset) { +static bool objOffsetExists(Instance* base, CVarRef offset) { objArrayAccess(base); TypedValue tvResult; tvWriteUninit(&tvResult); static StringData* sd__offsetExists = StringData::GetStaticString("offsetExists"); - ObjectData* obj = base->m_data.pobj; - ASSERT(!obj->isCollection()); - Instance* instance = static_cast(obj); - const Func* method = instance->methodNamed(sd__offsetExists); + ASSERT(!base->isCollection()); + const Func* method = base->methodNamed(sd__offsetExists); ASSERT(method != NULL); - instance->invokeUserMethod(&tvResult, method, CREATE_VECTOR1(offset)); + base->invokeUserMethod(&tvResult, method, CREATE_VECTOR1(offset)); tvCastToBooleanInPlace(&tvResult); return bool(tvResult.m_data.num); } -bool objOffsetIsset(TypedValue& tvRef, TypedValue* base, CVarRef offset, +bool objOffsetIsset(TypedValue& tvRef, Instance* base, CVarRef offset, bool validate /* = true */) { return objOffsetExists(base, offset); } -bool objOffsetEmpty(TypedValue& tvRef, TypedValue* base, CVarRef offset, +bool objOffsetEmpty(TypedValue& tvRef, Instance* base, CVarRef offset, bool validate /* = true */) { if (!objOffsetExists(base, offset)) { return true; @@ -76,46 +71,41 @@ bool objOffsetEmpty(TypedValue& tvRef, TypedValue* base, CVarRef offset, return empty(tvAsCVarRef(result)); } -void objOffsetAppend(TypedValue* base, TypedValue* val, +void objOffsetAppend(Instance* base, TypedValue* val, bool validate /* = true */) { - ObjectData* obj UNUSED = base->m_data.pobj; - ASSERT(!obj->isCollection()); + ASSERT(!base->isCollection()); if (validate) { objArrayAccess(base); } objOffsetSet(base, init_null_variant, val, false); } -void objOffsetSet(TypedValue* base, CVarRef offset, TypedValue* val, +void objOffsetSet(Instance* base, CVarRef offset, TypedValue* val, bool validate /* = true */) { if (validate) { objArrayAccess(base); } static StringData* sd__offsetSet = StringData::GetStaticString("offsetSet"); - ObjectData* obj = base->m_data.pobj; - ASSERT(!obj->isCollection()); - Instance* instance = static_cast(obj); - const Func* method = instance->methodNamed(sd__offsetSet); + ASSERT(!base->isCollection()); + const Func* method = base->methodNamed(sd__offsetSet); ASSERT(method != NULL); TypedValue tvResult; tvWriteUninit(&tvResult); - instance->invokeUserMethod(&tvResult, method, - CREATE_VECTOR2(offset, tvAsCVarRef(val))); + base->invokeUserMethod(&tvResult, method, + CREATE_VECTOR2(offset, tvAsCVarRef(val))); tvRefcountedDecRef(&tvResult); } -void objOffsetUnset(TypedValue* base, CVarRef offset) { +void objOffsetUnset(Instance* base, CVarRef offset) { objArrayAccess(base); static StringData* sd__offsetUnset = StringData::GetStaticString("offsetUnset"); - ObjectData* obj = base->m_data.pobj; - ASSERT(!obj->isCollection()); - Instance* instance = static_cast(obj); - const Func* method = instance->methodNamed(sd__offsetUnset); + ASSERT(!base->isCollection()); + const Func* method = base->methodNamed(sd__offsetUnset); ASSERT(method != NULL); TypedValue tv; tvWriteUninit(&tv); - instance->invokeUserMethod(&tv, method, CREATE_VECTOR1(offset)); + base->invokeUserMethod(&tv, method, CREATE_VECTOR1(offset)); tvRefcountedDecRef(&tv); } diff --git a/src/runtime/vm/member_operations.h b/src/runtime/vm/member_operations.h index 208d1dc66e5..9db8a9fd529 100644 --- a/src/runtime/vm/member_operations.h +++ b/src/runtime/vm/member_operations.h @@ -39,17 +39,17 @@ const bool MoreWarnings = #endif ; -void objArrayAccess(TypedValue* base); -TypedValue* objOffsetGet(TypedValue& tvRef, TypedValue* base, +void objArrayAccess(Instance* base); +TypedValue* objOffsetGet(TypedValue& tvRef, Instance* base, CVarRef offset, bool validate=true); -bool objOffsetIsset(TypedValue& tvRef, TypedValue* base, CVarRef offset, +bool objOffsetIsset(TypedValue& tvRef, Instance* base, CVarRef offset, bool validate=true); -bool objOffsetEmpty(TypedValue& tvRef, TypedValue* base, CVarRef offset, +bool objOffsetEmpty(TypedValue& tvRef, Instance* base, CVarRef offset, bool validate=true); -void objOffsetSet(TypedValue* base, CVarRef offset, TypedValue* val, +void objOffsetSet(Instance* base, CVarRef offset, TypedValue* val, bool validate=true); -void objOffsetAppend(TypedValue* base, TypedValue* val, bool validate=true); -void objOffsetUnset(TypedValue* base, CVarRef offset); +void objOffsetAppend(Instance* base, TypedValue* val, bool validate=true); +void objOffsetUnset(Instance* base, CVarRef offset); static inline String prepareKey(TypedValue* tv) { String ret; @@ -171,7 +171,7 @@ static inline TypedValue* Elem(TypedValue& tvScratch, TypedValue& tvRef, if (LIKELY(base->m_data.pobj->isCollection())) { result = collectionGet(base->m_data.pobj, key); } else { - result = objOffsetGet(tvRef, base, tvCellAsCVarRef(key)); + result = objOffsetGet(tvRef, instanceFromTv(base), tvCellAsCVarRef(key)); } break; } @@ -280,7 +280,7 @@ static inline TypedValue* ElemD(TypedValue& tvScratch, TypedValue& tvRef, result = collectionGet(base->m_data.pobj, key); } } else { - result = objOffsetGet(tvRef, base, tvCellAsCVarRef(key)); + result = objOffsetGet(tvRef, instanceFromTv(base), tvCellAsCVarRef(key)); } break; } @@ -337,7 +337,7 @@ static inline TypedValue* ElemU(TypedValue& tvScratch, TypedValue& tvRef, if (LIKELY(base->m_data.pobj->isCollection())) { result = collectionGet(base->m_data.pobj, key); } else { - result = objOffsetGet(tvRef, base, tvCellAsCVarRef(key)); + result = objOffsetGet(tvRef, instanceFromTv(base), tvCellAsCVarRef(key)); } break; } @@ -397,7 +397,7 @@ static inline TypedValue* NewElem(TypedValue& tvScratch, TypedValue& tvRef, raise_error("Cannot use [] for reading"); result = NULL; } else { - result = objOffsetGet(tvRef, base, init_null_variant); + result = objOffsetGet(tvRef, instanceFromTv(base), init_null_variant); } break; } @@ -567,7 +567,7 @@ static inline void SetElem(TypedValue* base, TypedValue* key, Cell* value) { if (LIKELY(base->m_data.pobj->isCollection())) { collectionSet(base->m_data.pobj, key, (TypedValue*)value); } else { - objOffsetSet(base, tvAsCVarRef(key), (TypedValue*)value); + objOffsetSet(instanceFromTv(base), tvAsCVarRef(key), (TypedValue*)value); } break; } @@ -637,7 +637,7 @@ static inline void SetNewElem(TypedValue* base, Cell* value) { if (LIKELY(base->m_data.pobj->isCollection())) { collectionAppend(base->m_data.pobj, (TypedValue*)value); } else { - objOffsetAppend(base, (TypedValue*)value); + objOffsetAppend(instanceFromTv(base), (TypedValue*)value); } break; } @@ -705,9 +705,9 @@ static inline TypedValue* SetOpElem(TypedValue& tvScratch, TypedValue& tvRef, result = collectionGet(base->m_data.pobj, key); SETOP_BODY(result, op, rhs); } else { - result = objOffsetGet(tvRef, base, tvCellAsCVarRef(key)); + result = objOffsetGet(tvRef, instanceFromTv(base), tvCellAsCVarRef(key)); SETOP_BODY(result, op, rhs); - objOffsetSet(base, tvAsCVarRef(key), result, false); + objOffsetSet(instanceFromTv(base), tvAsCVarRef(key), result, false); } break; } @@ -775,9 +775,9 @@ static inline TypedValue* SetOpNewElem(TypedValue& tvScratch, TypedValue& tvRef, raise_error("Cannot use [] for reading"); result = NULL; } else { - result = objOffsetGet(tvRef, base, init_null_variant); + result = objOffsetGet(tvRef, instanceFromTv(base), init_null_variant); SETOP_BODY(result, op, rhs); - objOffsetAppend(base, result, false); + objOffsetAppend(instanceFromTv(base), result, false); } break; } @@ -933,7 +933,7 @@ static inline void IncDecElem(TypedValue& tvScratch, TypedValue& tvRef, if (LIKELY(base->m_data.pobj->isCollection())) { result = collectionGet(base->m_data.pobj, key); } else { - result = objOffsetGet(tvRef, base, tvCellAsCVarRef(key)); + result = objOffsetGet(tvRef, instanceFromTv(base), tvCellAsCVarRef(key)); } IncDecBody(op, result, &dest); break; @@ -1001,7 +1001,7 @@ static inline void IncDecNewElem(TypedValue& tvScratch, TypedValue& tvRef, raise_error("Cannot use [] for reading"); result = NULL; } else { - result = objOffsetGet(tvRef, base, init_null_variant); + result = objOffsetGet(tvRef, instanceFromTv(base), init_null_variant); IncDecBody(op, result, &dest); } break; @@ -1049,7 +1049,7 @@ static inline void UnsetElem(TypedValue* base, TypedValue* member) { if (LIKELY(base->m_data.pobj->isCollection())) { collectionUnset(base->m_data.pobj, member); } else { - objOffsetUnset(base, tvAsCVarRef(member)); + objOffsetUnset(instanceFromTv(base), tvAsCVarRef(member)); } break; } @@ -1119,7 +1119,6 @@ static inline DataType propPre(TypedValue& tvScratch, TypedValue*& result, return issetEmpty ? KindOfArray : propPreNull(tvScratch, result); } case KindOfObject: { - keySD = prepareKey(key).detach(); return KindOfObject; } default: { @@ -1140,20 +1139,26 @@ static inline void propPost(StringData* keySD) { // \____ ____/ // v // $result -template +template static inline TypedValue* Prop(TypedValue& tvScratch, TypedValue& tvRef, Class* ctx, TypedValue* base, TypedValue* key) { ASSERT(!warn || !unset); TypedValue* result = NULL; - StringData* keySD = 0; - DataType t = propPre(tvScratch, result, base, key, - keySD); - if (t == KindOfNull) { - return result; + StringData* keySD = NULL; + Instance* instance; + if (baseIsObj) { + instance = reinterpret_cast(base); + } else { + DataType t = propPre(tvScratch, result, base, key, + keySD); + if (t == KindOfNull) { + return result; + } + ASSERT(t == KindOfObject); + instance = static_cast(base->m_data.pobj); } - ASSERT(t == KindOfObject); + keySD = prepareKey(key).detach(); // Get property. - Instance* instance = static_cast(base->m_data.pobj); result = &tvScratch; #define ARGS result, tvRef, ctx, keySD if (!warn && !(define || unset)) instance->prop (ARGS); @@ -1165,10 +1170,33 @@ static inline TypedValue* Prop(TypedValue& tvScratch, TypedValue& tvRef, return result; } -template +template +static inline bool IssetEmptyElemObj(TypedValue& tvRef, Instance* instance, + bool baseStrOff, TypedValue* key) { + if (useEmpty) { + if (LIKELY(instance->isCollection())) { + return collectionEmpty(instance, key); + } else { + return objOffsetEmpty(tvRef, instance, tvCellAsCVarRef(key)); + } + } else { + if (LIKELY(instance->isCollection())) { + return collectionIsset(instance, key); + } else { + return objOffsetIsset(tvRef, instance, tvCellAsCVarRef(key)); + } + } +} + +template static inline bool IssetEmptyElem(TypedValue& tvScratch, TypedValue& tvRef, TypedValue* base, bool baseStrOff, TypedValue* key) { + if (isObj) { + return IssetEmptyElemObj( + tvRef, reinterpret_cast(base), baseStrOff, key); + } + TypedValue* result; DataType type; opPre(base, type); @@ -1197,19 +1225,8 @@ static inline bool IssetEmptyElem(TypedValue& tvScratch, TypedValue& tvRef, break; } case KindOfObject: { - if (useEmpty) { - if (LIKELY(base->m_data.pobj->isCollection())) { - return collectionEmpty(base->m_data.pobj, key); - } else { - return objOffsetEmpty(tvRef, base, tvCellAsCVarRef(key)); - } - } else { - if (LIKELY(base->m_data.pobj->isCollection())) { - return collectionIsset(base->m_data.pobj, key); - } else { - return objOffsetIsset(tvRef, base, tvCellAsCVarRef(key)); - } - } + return IssetEmptyElemObj( + tvRef, static_cast(base->m_data.pobj), baseStrOff, key); break; } default: { @@ -1225,8 +1242,26 @@ static inline bool IssetEmptyElem(TypedValue& tvScratch, TypedValue& tvRef, } template +static inline bool IssetEmptyPropObj(Class* ctx, Instance* instance, + TypedValue* key) { + StringData* keySD; + bool issetEmptyResult; + keySD = prepareKey(key).detach(); + issetEmptyResult = useEmpty ? + instance->propEmpty(ctx, keySD) : + instance->propIsset(ctx, keySD); + propPost(keySD); + return issetEmptyResult; +} + +template static inline bool IssetEmptyProp(Class* ctx, TypedValue* base, TypedValue* key) { + if (isObj) { + return IssetEmptyPropObj(ctx, reinterpret_cast(base), + key); + } + StringData* keySD; TypedValue tvScratch; TypedValue* result = NULL; @@ -1236,13 +1271,7 @@ static inline bool IssetEmptyProp(Class* ctx, TypedValue* base, return useEmpty; } if (t == KindOfObject) { - bool issetEmptyResult; - Instance* instance = static_cast(base->m_data.pobj); - issetEmptyResult = useEmpty ? - instance->propEmpty(ctx, keySD) : - instance->propIsset(ctx, keySD); - propPost(keySD); - return issetEmptyResult; + return IssetEmptyPropObj(ctx, instanceFromTv(base), key); } else { ASSERT(t == KindOfArray); return useEmpty; @@ -1271,10 +1300,24 @@ static inline void SetPropStdclass(TypedValue* base, TypedValue* key, /* dont set _count; base could be an inner variant */ base->m_data.pobj = obj; } + +static inline void SetPropObj(Class* ctx, Instance* instance, + TypedValue* key, Cell* val) { + StringData* keySD = prepareKey(key).detach(); + // Set property. + instance->setProp(ctx, keySD, val); + LITSTR_DECREF(keySD); +} + // $base->$key = $val -template +template static inline void SetProp(Class* ctx, TypedValue* base, TypedValue* key, Cell* val) { + if (isObj) { + SetPropObj(ctx, reinterpret_cast(base), key, val); + return; + } + DataType type; opPre(base, type); switch (type) { @@ -1301,11 +1344,7 @@ static inline void SetProp(Class* ctx, TypedValue* base, TypedValue* key, break; } case KindOfObject: { - StringData* keySD = prepareKey(key).detach(); - // Set property. - Instance* instance = static_cast(base->m_data.pobj); - instance->setProp(ctx, keySD, val); - LITSTR_DECREF(keySD); + SetPropObj(ctx, static_cast(base->m_data.pobj), key, val); break; } default: { @@ -1337,11 +1376,27 @@ static inline TypedValue* SetOpPropStdclass(TypedValue& tvRef, unsigned char op, LITSTR_DECREF(keySD); return &tvRef; } + +static inline TypedValue* SetOpPropObj(TypedValue& tvRef, Class* ctx, + unsigned char op, Instance* instance, + TypedValue* key, Cell* rhs) { + StringData* keySD = prepareKey(key).detach(); + TypedValue* result = instance->setOpProp(tvRef, ctx, op, keySD, rhs); + LITSTR_DECREF(keySD); + return result; +} + // $base->$key = $rhs +template static inline TypedValue* SetOpProp(TypedValue& tvScratch, TypedValue& tvRef, Class* ctx, unsigned char op, TypedValue* base, TypedValue* key, Cell* rhs) { + if (isObj) { + return SetOpPropObj(tvRef, ctx, op, reinterpret_cast(base), + key, rhs); + } + TypedValue* result; DataType type; opPre(base, type); @@ -1369,10 +1424,8 @@ static inline TypedValue* SetOpProp(TypedValue& tvScratch, TypedValue& tvRef, break; } case KindOfObject: { - StringData* keySD = prepareKey(key).detach(); - Instance* instance = static_cast(base->m_data.pobj); - result = instance->setOpProp(tvRef, ctx, op, keySD, rhs); - LITSTR_DECREF(keySD); + result = SetOpPropObj(tvRef, ctx, op, + static_cast(base->m_data.pobj), key, rhs); break; } default: { @@ -1418,11 +1471,27 @@ static inline void IncDecPropStdclass(unsigned char op, TypedValue* base, ASSERT(!IS_REFCOUNTED_TYPE(tv.m_type)); LITSTR_DECREF(keySD); } + template +static inline void IncDecPropObj(TypedValue& tvRef, Class* ctx, + unsigned char op, Instance* base, + TypedValue* key, TypedValue& dest) { + StringData* keySD = prepareKey(key).detach(); + base->incDecProp(tvRef, ctx, op, keySD, dest); + LITSTR_DECREF(keySD); +} + +template static inline void IncDecProp(TypedValue& tvScratch, TypedValue& tvRef, Class* ctx, unsigned char op, TypedValue* base, TypedValue* key, TypedValue& dest) { + if (isObj) { + IncDecPropObj(tvRef, ctx, op, reinterpret_cast(base), + key, dest); + return; + } + DataType type; opPre(base, type); switch (type) { @@ -1449,10 +1518,7 @@ static inline void IncDecProp(TypedValue& tvScratch, TypedValue& tvRef, break; } case KindOfObject: { - StringData* keySD = prepareKey(key).detach(); - Instance* instance = static_cast(base->m_data.pobj); - instance->incDecProp(tvRef, ctx, op, keySD, dest); - LITSTR_DECREF(keySD); + IncDecPropObj(tvRef, ctx, op, instanceFromTv(base), key, dest); break; } default: { @@ -1462,21 +1528,26 @@ static inline void IncDecProp(TypedValue& tvScratch, TypedValue& tvRef, } } +template static inline void UnsetProp(Class* ctx, TypedValue* base, TypedValue* key) { - DataType type; - opPre(base, type); - // Validate base. - if (UNLIKELY(type != KindOfObject)) { - // Do nothing. - return; + Instance* instance; + if (!isObj) { + DataType type; + opPre(base, type); + // Validate base. + if (UNLIKELY(type != KindOfObject)) { + // Do nothing. + return; + } + instance = instanceFromTv(base); + } else { + instance = reinterpret_cast(base); } // Prepare key. StringData* keySD = prepareKey(key).detach(); // Unset property. - Instance* instance = static_cast(base->m_data.pobj); instance->unsetProp(ctx, keySD); - LITSTR_DECREF(keySD); } diff --git a/src/runtime/vm/translator/regalloc.cpp b/src/runtime/vm/translator/regalloc.cpp index 3abc0b14b5e..8ab38ad8a09 100644 --- a/src/runtime/vm/translator/regalloc.cpp +++ b/src/runtime/vm/translator/regalloc.cpp @@ -164,9 +164,8 @@ RegAlloc::alloc(const Location& loc, DataType type, RegInfo::State state, } void -RegAlloc::allocInputReg(const NormalizedInstruction& ni, int index, - PhysReg target /* = InvalidReg */) { - RuntimeType& rtt = ni.inputs[index]->rtt; +RegAlloc::allocInputReg(const DynLocation& dl, PhysReg target) { + const RuntimeType& rtt = dl.rtt; if (rtt.isIter()) { // Note: if this changes to enregister iterators unwinding will // have to be updated. @@ -176,7 +175,7 @@ RegAlloc::allocInputReg(const NormalizedInstruction& ni, int index, DataType t = rtt.outerType(); if (t == KindOfInvalid) return; - Location& loc = ni.inputs[index]->location; + const Location& loc = dl.location; int64 litVal = 0; if (loc.isLiteral()) { @@ -187,6 +186,12 @@ RegAlloc::allocInputReg(const NormalizedInstruction& ni, int index, } void +RegAlloc::allocInputReg(const NormalizedInstruction& ni, int index, + PhysReg target /* = InvalidReg */) { + allocInputReg(*ni.inputs[index], target); +} + +void RegAlloc::allocInputRegs(const NormalizedInstruction& ni) { for (unsigned i = 0; i < ni.inputs.size(); i++) { allocInputReg(ni, i); diff --git a/src/runtime/vm/translator/regalloc.h b/src/runtime/vm/translator/regalloc.h index c1b4dc87547..cd06cc3f2d6 100644 --- a/src/runtime/vm/translator/regalloc.h +++ b/src/runtime/vm/translator/regalloc.h @@ -345,6 +345,7 @@ class RegAlloc { } // allocInputRegs: given an instruction, find/fill its inputs. + void allocInputReg(const DynLocation& dl, PhysReg target = InvalidReg); void allocInputReg(const NormalizedInstruction& ni, int index, PhysReg target = InvalidReg); void allocInputRegs(const NormalizedInstruction& ni); diff --git a/src/runtime/vm/translator/translator-x64-internal.h b/src/runtime/vm/translator/translator-x64-internal.h index 985420baf2c..f0437b0f570 100644 --- a/src/runtime/vm/translator/translator-x64-internal.h +++ b/src/runtime/vm/translator/translator-x64-internal.h @@ -792,6 +792,23 @@ static const char* getContextName() { return ctx ? ctx->name()->data() : ":anonymous:"; } +template +struct Nuller : private boost::noncopyable { + explicit Nuller(const T** p) : p(p) {} + ~Nuller() { *p = 0; } + T const** const p; +}; + +template +struct Deleter : private boost::noncopyable { + explicit Deleter(T** p) : p(p) {} + ~Deleter() { + delete *p; + *p = NULL; + } + T** p; +}; + }}} #endif diff --git a/src/runtime/vm/translator/translator-x64-vector.cpp b/src/runtime/vm/translator/translator-x64-vector.cpp index c7bb002caf4..05100567209 100644 --- a/src/runtime/vm/translator/translator-x64-vector.cpp +++ b/src/runtime/vm/translator/translator-x64-vector.cpp @@ -36,6 +36,23 @@ namespace Transl { * Translator for vector instructions. */ +struct MVecTransState { + MVecTransState() + : baseType(KindOfUninit) + {} + + bool isKnown() { return baseType != KindOfUninit; } + bool isObj() { return baseType == KindOfObject; } + void setObj() { baseType = KindOfObject; } + void resetBase() { baseType = KindOfUninit; } + + private: + /* This stores the type of the current value in rBase. If it's != + * KindOfUninit then the register will hold the value itself instead of a + * TypedValue* */ + DataType baseType; +}; + #define ML(loc, a, regMap, rMis) \ IE(loc.isLiteral(), \ _am.addLiteral(loc, a, regMap, rMis), \ @@ -70,6 +87,8 @@ namespace Transl { #define TRANSLATE_MINSTR_GENERIC(instr, t, ni) do { \ ASSERT(RuntimeOption::EvalJitMGeneric); \ SKTRACE(2, ni.source, "%s\n", __func__); \ + m_vecState = new MVecTransState(); \ + Deleter stateDeleter(&m_vecState); \ const MInstrInfo& mii = getMInstrInfo(Op##instr##M); \ bool ctxFixed; \ unsigned mInd, iInd; \ @@ -79,6 +98,15 @@ namespace Transl { emitMPost((t), (ni), mii); \ } while (0) +template +unsigned buildBitmask() { + return 0; +} +template +unsigned buildBitmask(bool condition, Args... args) { + static_assert(bit < (sizeof(unsigned) * CHAR_BIT), "Too many bits"); + return buildBitmask(args...) | (condition ? (1u << bit) : 0); +} int TranslatorX64::mResultStackOffset(const NormalizedInstruction& ni) const { int stackDest = 0 - int(sizeof(Cell)); @@ -210,11 +238,8 @@ void TranslatorX64::emitBaseLCR(const Tracelet& t, void TranslatorX64::emitBaseH(LazyScratchReg& rBase) { rBase.alloc(); - ScratchReg scratch(m_regMap); - a.load_reg64_disp_reg64(rVmFp, AROFF(m_this), *scratch); - a.lea_reg64_disp_reg64(rsp, offsetof(MInstrState, tvScratch), *rBase); - a.store_reg64_disp_reg64(*scratch, TVOFF(m_data), *rBase); - a.store_imm32_disp_reg(KindOfObject, TVOFF(m_type), *rBase); + a.load_reg64_disp_reg64(rVmFp, AROFF(m_this), *rBase); + m_vecState->setObj(); } template @@ -654,32 +679,43 @@ void TranslatorX64::emitElem(const Tracelet& t, unsigned iInd, LazyScratchReg& rBase); -template +template static inline TypedValue* propImpl(Class* ctx, TypedValue* base, TypedValue* key, TranslatorX64::MInstrState* mis) { key = unbox(key); - return Prop(mis->tvScratch, mis->tvRef, ctx, base, key); -} - -#define PROP_TABLE \ - /* name unboxKey warn define unset */ \ - PROP(CU, false, false, false, true) \ - PROP(CWD, false, true, true, false) \ - PROP(CW, false, true, false, false) \ - PROP(CD, false, false, true, false) \ - PROP(C, false, false, false, false) \ - PROP(LU, true, false, false, true) \ - PROP(LWD, true, true, true, false) \ - PROP(LW, true, true, false, false) \ - PROP(LD, true, false, true, false) \ - PROP(L, true, false, false, false) - -#define PROP(nm, unboxKey, warn, define, unset) \ + return Prop( + mis->tvScratch, mis->tvRef, ctx, base, key); +} + +#define PROP_TABLE \ + /* name unboxKey warn define unset isObj */ \ + PROP(CU, false, false, false, true, false) \ + PROP(CWD, false, true, true, false, false) \ + PROP(CW, false, true, false, false, false) \ + PROP(CD, false, false, true, false, false) \ + PROP(C, false, false, false, false, false) \ + PROP(CUO, false, false, false, true, true) \ + PROP(CWDO, false, true, true, false, true) \ + PROP(CWO, false, true, false, false, true) \ + PROP(CDO, false, false, true, false, true) \ + PROP(CO, false, false, false, false, true) \ + PROP(LU, true, false, false, true, false) \ + PROP(LWD, true, true, true, false, false) \ + PROP(LW, true, true, false, false, false) \ + PROP(LD, true, false, true, false, false) \ + PROP(L, true, false, false, false, false) \ + PROP(LUO, true, false, false, true, true) \ + PROP(LWDO, true, true, true, false, true) \ + PROP(LWO, true, true, false, false, true) \ + PROP(LDO, true, false, true, false, true) \ + PROP(LO, true, false, false, false, true) + +#define PROP(nm, unboxKey, warn, define, unset, isObj) \ HOT_FUNC_VM \ static TypedValue* prop ## nm(Class* ctx, TypedValue* base, TypedValue* key, \ TranslatorX64::MInstrState* mis) { \ - return propImpl(ctx, base, key, mis); \ + return propImpl(ctx, base, key, mis); \ } PROP_TABLE #undef PROP @@ -703,14 +739,18 @@ void TranslatorX64::emitPropGeneric(const Tracelet& t, const PropOp propX = nullptr; static const PropOp localPropOps[] = {propL, propLW, propLD, propLWD, propX, propX, propLD, propLWD, - propLU, propX, propX, propX, propX, propX, propX, propX}; + propLU, propX, propX, propX, propX, propX, propX, propX, + propLO, propLWO,propLDO,propLWDO,propX, propX, propLDO,propLWDO, + propLUO,propX, propX, propX, propX, propX, propX, propX}; static const PropOp cellPropOps[] = {propC, propCW, propCD, propCWD, propX, propX, propCD, propCWD, - propCU, propX, propX, propX, propX, propX, propX, propX}; + propCU, propX, propX, propX, propX, propX, propX, propX, + propCO, propCWO,propCDO,propCWDO,propX, propX, propCDO,propCWD, + propCUO,propX, propX, propX, propX, propX, propX, propX}; ASSERT((mia & MIA_intermediate) < array_size(localPropOps)); ASSERT((mia & MIA_intermediate) < array_size(cellPropOps)); - PropOp propOp = ((mCode == MPL) ? localPropOps : cellPropOps) - [mia & MIA_intermediate]; + unsigned idx = (mia & MIA_intermediate) | (m_vecState->isObj() ? 0x10 : 0x0); + PropOp propOp = ((mCode == MPL) ? localPropOps : cellPropOps)[idx]; ASSERT(propOp != propX); PREP_CTX(ctxFixed, argNumToRegName[0]); // Emit the appropriate helper call. @@ -720,6 +760,7 @@ void TranslatorX64::emitPropGeneric(const Tracelet& t, ML(memb.location, a, m_regMap, rsp), R(rsp)); rBase.realloc(rax); + m_vecState->resetBase(); } static int getPropertyOffset(const NormalizedInstruction& ni, @@ -813,7 +854,8 @@ void TranslatorX64::emitPropSpecialized(MInstrAttr const mia, * cases. */ std::unique_ptr nonObjectRet; - if (mInd != 0) { + bool isObj = m_vecState->isObj(); + if (!isObj) { emitTypeCheck(a, KindOfObject, *rBase, 0); { nonObjectRet.reset(new DiamondReturn()); @@ -854,7 +896,9 @@ void TranslatorX64::emitPropSpecialized(MInstrAttr const mia, ScratchReg rScratch(m_regMap); - emitDeref(a, *rBase, *rBase); + if (!isObj) { + emitDeref(a, *rBase, *rBase); + } a. lea_reg64_disp_reg64(*rBase, propOffset, *rScratch); if (doWarn || doDefine) { a. cmp_imm32_disp_reg32(KindOfUninit, TVOFF(m_type), *rScratch); @@ -880,6 +924,7 @@ void TranslatorX64::emitPropSpecialized(MInstrAttr const mia, auto usedScratch = *rScratch; rScratch.dealloc(); rBase.realloc(usedScratch); + m_vecState->resetBase(); // nonObjectRet returns here. } @@ -923,6 +968,7 @@ void TranslatorX64::emitIntermediateOp(const Tracelet& t, LazyScratchReg& rBase) { switch (ni.immVecM[mInd]) { case MEC: case MEL: case MET: case MEI: { + ASSERT(!m_vecState->isKnown()); DataType keyType = ni.inputs[iInd]->rtt.valueType(); auto emitter = IS_STRING_TYPE(keyType) ? &TranslatorX64::emitElem : @@ -937,6 +983,7 @@ void TranslatorX64::emitIntermediateOp(const Tracelet& t, ++iInd; break; case MW: + ASSERT(!m_vecState->isKnown()); ASSERT(mii.newElem()); emitNewElem(t, ni, mInd, rBase); break; @@ -1049,12 +1096,12 @@ void TranslatorX64::emitRatchetRefs(const Tracelet& t, a. lea_reg64_disp_reg64(rsp, offsetof(MInstrState, tvRef2), rBase); } } -template +template static inline void cGetPropImpl(Class* ctx, TypedValue* base, TypedValue* key, TypedValue* result, TranslatorX64::MInstrState* mis) { key = unbox(key); - base = Prop(*result, mis->tvRef, ctx, base, key); + base = Prop(*result, mis->tvRef, ctx, base, key); if (base != result) { // Save a copy of the result. tvDup(base, result); @@ -1064,17 +1111,23 @@ static inline void cGetPropImpl(Class* ctx, TypedValue* base, TypedValue* key, } } -HOT_FUNC_VM -static void cGetPropL(Class* ctx, TypedValue* base, TypedValue* key, - TypedValue* result, TranslatorX64::MInstrState* mis) { - cGetPropImpl(ctx, base, key, result, mis); -} +#define PROP_TABLE \ + /* name unboxKey isObj */ \ + PROP(L, true, false) \ + PROP(LO, true, true) \ + PROP(C, false, false) \ + PROP(CO, false, true) -HOT_FUNC_VM -static void cGetPropC(Class* ctx, TypedValue* base, TypedValue* key, - TypedValue* result, TranslatorX64::MInstrState* mis) { - cGetPropImpl(ctx, base, key, result, mis); +#define PROP(nm, unboxKey, isObj) \ +HOT_FUNC_VM \ +static void cGetProp##nm(Class* ctx, TypedValue* base, TypedValue* key, \ + TypedValue* result, \ + TranslatorX64::MInstrState* mis) { \ + cGetPropImpl(ctx, base, key, result, mis); \ } +PROP_TABLE +#undef PROP +#undef PROP_TABLE void TranslatorX64::emitCGetProp(const Tracelet& t, const NormalizedInstruction& ni, @@ -1114,7 +1167,12 @@ void TranslatorX64::emitCGetProp(const Tracelet& t, Stats::emitInc(a, Stats::PropAsm_GenFinal); const DynLocation& memb = *ni.inputs[iInd]; - auto* cGetPropOp = ni.immVecM[mInd] == MPL ? cGetPropL : cGetPropC; + typedef void (*PropOp)(Class*, TypedValue*, TypedValue*, TypedValue*, + MInstrState*); + static const PropOp propOps[] + = {cGetPropC, cGetPropL, cGetPropCO, cGetPropLO}; + unsigned idx = buildBitmask(ni.immVecM[mInd] == MPL, m_vecState->isObj()); + PropOp cGetPropOp = propOps[idx]; m_regMap.cleanSmashLoc(memb.location); const DynLocation& result = *ni.outStack; PREP_CTX(ctxFixed, argNumToRegName[0]); @@ -1178,12 +1236,13 @@ void TranslatorX64::emitVGetElem(const Tracelet& t, R(rsp)); } -template +template static inline void vGetPropImpl(Class* ctx, TypedValue* base, TypedValue* key, TypedValue* result, TranslatorX64::MInstrState* mis) { key = unbox(key); - base = Prop(mis->tvScratch, mis->tvRef, ctx, base, key); + base = Prop(mis->tvScratch, mis->tvRef, ctx, + base, key); if (base == &mis->tvScratch && base->m_type == KindOfUninit) { // Error (no result was set). tvWriteNull(result); @@ -1196,19 +1255,23 @@ static inline void vGetPropImpl(Class* ctx, TypedValue* base, TypedValue* key, } } -HOT_FUNC_VM -static inline void vGetPropL(Class* ctx, TypedValue* base, TypedValue* key, - TypedValue* result, - TranslatorX64::MInstrState* mis) { - vGetPropImpl(ctx, base, key, result, mis); -} +#define PROP_TABLE \ + /* name unboxKey isObj */ \ + PROP(L, true, false) \ + PROP(LO, true, true) \ + PROP(C, false, false) \ + PROP(CO, false, true) -HOT_FUNC_VM -static inline void vGetPropC(Class* ctx, TypedValue* base, TypedValue* key, - TypedValue* result, - TranslatorX64::MInstrState* mis) { - vGetPropImpl(ctx, base, key, result, mis); +#define PROP(nm, unboxKey, isObj) \ +HOT_FUNC_VM \ +static inline void vGetProp##nm(Class* ctx, TypedValue* base, TypedValue* key, \ + TypedValue* result, \ + TranslatorX64::MInstrState* mis) { \ + vGetPropImpl(ctx, base, key, result, mis); \ } +PROP_TABLE +#undef PROP +#undef PROP_TABLE void TranslatorX64::emitVGetProp(const Tracelet& t, const NormalizedInstruction& ni, @@ -1218,7 +1281,12 @@ void TranslatorX64::emitVGetProp(const Tracelet& t, SKTRACE(2, ni.source, "%s %#lx mInd=%u, iInd=%u\n", __func__, long(a.code.frontier), mInd, iInd); const DynLocation& memb = *ni.inputs[iInd]; - auto vGetPropOp = ni.immVecM[mInd] == MPL ? vGetPropL : vGetPropC; + typedef void (*PropOp)(Class*, TypedValue*, TypedValue*, TypedValue*, + MInstrState*); + static const PropOp propOps[] + = {vGetPropC, vGetPropL, vGetPropCO, vGetPropLO}; + unsigned idx = buildBitmask(ni.immVecM[mInd] == MPL, m_vecState->isObj()); + PropOp vGetPropOp = propOps[idx]; m_regMap.cleanSmashLoc(memb.location); const DynLocation& result = *ni.outStack; bool useTvR = useTvResult(t, ni, mii); @@ -1297,37 +1365,34 @@ void TranslatorX64::emitIssetElem(const Tracelet& t, emitIssetEmptyElem(t, ni, mii, mInd, iInd, rBase); } -template +template static inline bool issetEmptyPropImpl(Class* ctx, TypedValue* base, TypedValue* key, TranslatorX64::MInstrState* mis) { key = unbox(key); - return IssetEmptyProp(ctx, base, key); -} - -HOT_FUNC_VM -static bool issetPropL(Class* ctx, TypedValue* base, TypedValue* key, - TranslatorX64::MInstrState* mis) { - return issetEmptyPropImpl(ctx, base, key, mis); -} - -HOT_FUNC_VM -static bool issetPropC(Class* ctx, TypedValue* base, TypedValue* key, - TranslatorX64::MInstrState* mis) { - return issetEmptyPropImpl(ctx, base, key, mis); -} - -HOT_FUNC_VM -static bool emptyPropL(Class* ctx, TypedValue* base, TypedValue* key, - TranslatorX64::MInstrState* mis) { - return issetEmptyPropImpl(ctx, base, key, mis); -} - -HOT_FUNC_VM -static bool emptyPropC(Class* ctx, TypedValue* base, TypedValue* key, - TranslatorX64::MInstrState* mis) { - return issetEmptyPropImpl(ctx, base, key, mis); -} + return IssetEmptyProp(ctx, base, key); +} + +#define ISSET_TABLE \ + /* nm unboxKey useEmpty isObj */ \ + ISSET(C, false, false, false) \ + ISSET(L, true, false, false) \ + ISSET(CE, false, true, false) \ + ISSET(LE, true, true, false) \ + ISSET(CO, false, false, true) \ + ISSET(LO, true, false, true) \ + ISSET(CEO, false, true, true) \ + ISSET(LEO, true, true, true) + +#define ISSET(nm, unboxKey, useEmpty, isObj) \ +HOT_FUNC_VM \ +static bool issetProp##nm(Class* ctx, TypedValue* base, TypedValue* key, \ + TranslatorX64::MInstrState* mis) { \ + return issetEmptyPropImpl(ctx, base, key, mis); \ +} +ISSET_TABLE +#undef ISSET +#undef ISSET_TABLE template void TranslatorX64::emitIssetEmptyProp(const Tracelet& t, @@ -1336,9 +1401,13 @@ void TranslatorX64::emitIssetEmptyProp(const Tracelet& t, unsigned mInd, unsigned iInd, PhysReg rBase) { const DynLocation& memb = *ni.inputs[iInd]; - auto issetEmptyPropOp = - useEmpty ? (ni.immVecM[mInd] == MPL ? emptyPropL : emptyPropC) - : (ni.immVecM[mInd] == MPL ? issetPropL : issetPropC); + typedef bool (*IssetOp)(Class* ctx, TypedValue*, TypedValue*, MInstrState*); + static const IssetOp issetOps[] + = {issetPropC, issetPropL, issetPropCE, issetPropLE, + issetPropCO, issetPropLO, issetPropCEO, issetPropLEO}; + unsigned idx = buildBitmask(ni.immVecM[mInd] == MPL, useEmpty, + m_vecState->isObj()); + IssetOp issetEmptyPropOp = issetOps[idx]; m_regMap.cleanSmashLoc(memb.location); PREP_CTX(ctxFixed, argNumToRegName[0]); // Emit the appropriate helper call. @@ -1440,34 +1509,32 @@ void TranslatorX64::emitSetElem(const Tracelet& t, VAL(useRVal))); } -template +template static inline void setPropImpl(Class* ctx, TypedValue* base, TypedValue* key, Cell* val) { key = unbox(key); - SetProp(ctx, base, key, val); + SetProp(ctx, base, key, val); } -HOT_FUNC_VM -static void setPropLR(Class* ctx, TypedValue* base, TypedValue* key, - Cell* val) { - setPropImpl(ctx, base, key, val); -} - -HOT_FUNC_VM -static void setPropL(Class* ctx, TypedValue* base, TypedValue* key, Cell* val) { - setPropImpl(ctx, base, key, val); -} - -HOT_FUNC_VM -static void setPropCR(Class* ctx, TypedValue* base, TypedValue* key, - Cell* val) { - setPropImpl(ctx, base, key, val); -} - -HOT_FUNC_VM -static void setPropC(Class* ctx, TypedValue* base, TypedValue* key, Cell* val) { - setPropImpl(ctx, base, key, val); +#define PROP_TABLE \ + PROP(L, true, false, false) \ + PROP(LR, true, true, false) \ + PROP(LO, true, false, true) \ + PROP(LRO, true, true, true) \ + PROP(C, false, false, false) \ + PROP(CR, false, true, false) \ + PROP(CO, false, false, true) \ + PROP(CRO, false, true, true) + +#define PROP(nm, unboxKey, setResult, isObj) \ +HOT_FUNC_VM \ +static void setProp ## nm(Class* ctx, TypedValue* base, TypedValue* key, \ + Cell* val) { \ + setPropImpl(ctx, base, key, val); \ } +PROP_TABLE +#undef PROP +#undef PROP_TABLE void TranslatorX64::emitSetProp(const Tracelet& t, const NormalizedInstruction& ni, @@ -1509,9 +1576,14 @@ void TranslatorX64::emitSetProp(const Tracelet& t, SKTRACE(2, ni.source, "%s setResult=%s\n", __func__, setResult ? "true" : "false"); const DynLocation& key = *ni.inputs[iInd]; - auto const setPropOp = (ni.immVecM[mInd] == MPL) - ? (setResult ? setPropLR : setPropL) - : (setResult ? setPropCR : setPropC); + typedef void (*PropOp)(Class*, TypedValue*, TypedValue*, Cell*); + static const PropOp propOps[] + = {setPropC, setPropL, setPropCR, setPropLR, + setPropCO, setPropLO, setPropCRO, setPropLRO}; + unsigned idx = buildBitmask(ni.immVecM[mInd] == MPL, + setResult, + m_vecState->isObj()); + auto setPropOp = propOps[idx]; m_regMap.cleanSmashLoc(key.location); m_regMap.cleanSmashLoc(val.location); PREP_CTX(ctxFixed, argNumToRegName[0]); @@ -1629,13 +1701,13 @@ void TranslatorX64::emitSetOpElem(const Tracelet& t, } } -template +template static inline void setOpPropImpl(Class* ctx, TypedValue* base, TypedValue* key, Cell* val, TranslatorX64::MInstrState* mis, TypedValue* tvRes=NULL) { key = unbox(key); - TypedValue* result = SetOpProp(mis->tvScratch, mis->tvRef, ctx, op, base, key, - val); + TypedValue* result = SetOpProp(mis->tvScratch, mis->tvRef, ctx, op, + base, key, val); if (setResult) { if (result->m_type == KindOfRef) { tvUnbox(result); @@ -1649,23 +1721,45 @@ HOT_FUNC_VM \ static void setOp##op##PropLR(Class* ctx, TypedValue* base, TypedValue* key, \ Cell* val, TranslatorX64::MInstrState* mis, \ TypedValue* tvRes) { \ - setOpPropImpl(ctx, base, key, val, mis, tvRes); \ + setOpPropImpl(ctx, base, key, val, mis, tvRes); \ } \ HOT_FUNC_VM \ static void setOp##op##PropCR(Class* ctx, TypedValue* base, TypedValue* key, \ Cell* val, TranslatorX64::MInstrState* mis, \ TypedValue* tvRes) { \ - setOpPropImpl(ctx, base, key, val, mis, tvRes); \ + setOpPropImpl(ctx, base, key, val, mis, tvRes); \ } \ HOT_FUNC_VM \ static void setOp##op##PropL(Class* ctx, TypedValue* base, TypedValue* key, \ Cell* val, TranslatorX64::MInstrState* mis) { \ - setOpPropImpl(ctx, base, key, val, mis); \ + setOpPropImpl(ctx, base, key, val, mis); \ } \ HOT_FUNC_VM \ static void setOp##op##PropC(Class* ctx, TypedValue* base, TypedValue* key, \ Cell* val, TranslatorX64::MInstrState* mis) { \ - setOpPropImpl(ctx, base, key, val, mis); \ + setOpPropImpl(ctx, base, key, val, mis); \ +} \ +HOT_FUNC_VM \ +static void setOp##op##PropLRO(Class* ctx, TypedValue* base, TypedValue* key, \ + Cell* val, TranslatorX64::MInstrState* mis, \ + TypedValue* tvRes) { \ + setOpPropImpl(ctx, base, key, val, mis, tvRes); \ +} \ +HOT_FUNC_VM \ +static void setOp##op##PropCRO(Class* ctx, TypedValue* base, TypedValue* key, \ + Cell* val, TranslatorX64::MInstrState* mis, \ + TypedValue* tvRes) { \ + setOpPropImpl(ctx, base, key, val, mis, tvRes); \ +} \ +HOT_FUNC_VM \ +static void setOp##op##PropLO(Class* ctx, TypedValue* base, TypedValue* key, \ + Cell* val, TranslatorX64::MInstrState* mis) { \ + setOpPropImpl(ctx, base, key, val, mis); \ +} \ +HOT_FUNC_VM \ +static void setOp##op##PropCO(Class* ctx, TypedValue* base, TypedValue* key, \ + Cell* val, TranslatorX64::MInstrState* mis) { \ + setOpPropImpl(ctx, base, key, val, mis); \ } SETOP_OPS #undef SETOP_OP @@ -1687,6 +1781,7 @@ void TranslatorX64::emitSetOpProp(const Tracelet& t, m_regMap.cleanSmashLoc(val.location); PREP_CTX(ctxFixed, argNumToRegName[0]); bool useRVal = val.isVariant(); + bool isObj = m_vecState->isObj(); PREP_VAL(useRVal, argNumToRegName[3]); // Emit the appropriate helper call. if (setResult) { @@ -1696,7 +1791,8 @@ void TranslatorX64::emitSetOpProp(const Tracelet& t, #define SETOP_OP(op, bcOp) \ case SetOp##op: \ setOpPropOp = (ni.immVecM[mInd] == MEL) \ - ? setOp##op##PropLR : setOp##op##PropCR; \ + ? (isObj ? setOp##op##PropLRO : setOp##op##PropLR) \ + : (isObj ? setOp##op##PropCRO : setOp##op##PropCR); \ break; SETOP_OPS #undef SETOP_OP @@ -1718,7 +1814,8 @@ void TranslatorX64::emitSetOpProp(const Tracelet& t, #define SETOP_OP(op, bcOp) \ case SetOp##op: \ setOpPropOp = (ni.immVecM[mInd] == MEL) \ - ? setOp##op##PropL : setOp##op##PropC; \ + ? (isObj ? setOp##op##PropLO : setOp##op##PropL) \ + : (isObj ? setOp##op##PropCO : setOp##op##PropC); \ break; SETOP_OPS #undef SETOP_OP @@ -1819,12 +1916,13 @@ void TranslatorX64::emitIncDecElem(const Tracelet& t, } } -template +template static inline void incDecPropImpl(Class* ctx, TypedValue* base, TypedValue* key, TranslatorX64::MInstrState* mis, TypedValue* tvRes) { key = unbox(key); - IncDecProp(mis->tvScratch, mis->tvRef, ctx, op, base, key, *tvRes); + IncDecProp(mis->tvScratch, mis->tvRef, ctx, op, base, key, + *tvRes); } #define INCDEC_OP(op) \ @@ -1832,25 +1930,49 @@ HOT_FUNC_VM \ static void incDec##op##PropLR(Class* ctx, TypedValue* base, TypedValue* key, \ TranslatorX64::MInstrState* mis, \ TypedValue* tvRes) { \ - incDecPropImpl(ctx, base, key, mis, tvRes); \ + incDecPropImpl(ctx, base, key, mis, tvRes); \ } \ HOT_FUNC_VM \ static void incDec##op##PropCR(Class* ctx, TypedValue* base, TypedValue* key, \ TranslatorX64::MInstrState* mis, \ TypedValue* tvRes) { \ - incDecPropImpl(ctx, base, key, mis, tvRes); \ + incDecPropImpl(ctx, base, key, mis, tvRes); \ } \ HOT_FUNC_VM \ static void incDec##op##PropL(Class* ctx, TypedValue* base, TypedValue* key, \ TranslatorX64::MInstrState* mis) { \ TypedValue tvRes; /* Not used; no need to initialize. */ \ - incDecPropImpl(ctx, base, key, mis, &tvRes); \ + incDecPropImpl(ctx, base, key, mis, &tvRes); \ } \ HOT_FUNC_VM \ static void incDec##op##PropC(Class* ctx, TypedValue* base, TypedValue* key, \ TranslatorX64::MInstrState* mis) { \ TypedValue tvRes; /* Not used; no need to initialize. */ \ - incDecPropImpl(ctx, base, key, mis, &tvRes); \ + incDecPropImpl(ctx, base, key, mis, &tvRes); \ +} \ +HOT_FUNC_VM \ +static void incDec##op##PropLRO(Class* ctx, TypedValue* base, TypedValue* key, \ + TranslatorX64::MInstrState* mis, \ + TypedValue* tvRes) { \ + incDecPropImpl(ctx, base, key, mis, tvRes); \ +} \ +HOT_FUNC_VM \ +static void incDec##op##PropCRO(Class* ctx, TypedValue* base, TypedValue* key, \ + TranslatorX64::MInstrState* mis, \ + TypedValue* tvRes) { \ + incDecPropImpl(ctx, base, key, mis, tvRes); \ +} \ +HOT_FUNC_VM \ +static void incDec##op##PropLO(Class* ctx, TypedValue* base, TypedValue* key, \ + TranslatorX64::MInstrState* mis) { \ + TypedValue tvRes; /* Not used; no need to initialize. */ \ + incDecPropImpl(ctx, base, key, mis, &tvRes); \ +} \ +HOT_FUNC_VM \ +static void incDec##op##PropCO(Class* ctx, TypedValue* base, TypedValue* key, \ + TranslatorX64::MInstrState* mis) { \ + TypedValue tvRes; /* Not used; no need to initialize. */ \ + incDecPropImpl(ctx, base, key, mis, &tvRes); \ } INCDEC_OPS #undef INCDEC_OP @@ -1869,6 +1991,7 @@ void TranslatorX64::emitIncDecProp(const Tracelet& t, __func__, setResult ? "true" : "false"); m_regMap.cleanSmashLoc(key.location); PREP_CTX(ctxFixed, argNumToRegName[0]); + bool isObj = m_vecState->isObj(); // Emit the appropriate helper call. if (setResult) { void (*incDecPropOp)(Class*, TypedValue*, TypedValue*, MInstrState*, @@ -1877,7 +2000,8 @@ void TranslatorX64::emitIncDecProp(const Tracelet& t, #define INCDEC_OP(op) \ case op: \ incDecPropOp = (ni.immVecM[mInd] == MEL) \ - ? incDec##op##PropLR : incDec##op##PropCR; \ + ? (isObj ? incDec##op##PropLRO : incDec##op##PropLR) \ + : (isObj ? incDec##op##PropCRO : incDec##op##PropCR); \ break; INCDEC_OPS #undef INCDEC_OP @@ -1898,7 +2022,8 @@ void TranslatorX64::emitIncDecProp(const Tracelet& t, #define INCDEC_OP(op) \ case op: \ incDecPropOp = (ni.immVecM[mInd] == MEL) \ - ? incDec##op##PropL : incDec##op##PropC; \ + ? (isObj ? incDec##op##PropLO : incDec##op##PropL) \ + : (isObj ? incDec##op##PropCO : incDec##op##PropC); \ break; INCDEC_OPS #undef INCDEC_OP @@ -1952,27 +2077,34 @@ void TranslatorX64::emitBindElem(const Tracelet& t, A(val.location), R(rsp)); } -template +template static inline void bindPropImpl(Class* ctx, TypedValue* base, TypedValue* key, RefData* val, TranslatorX64::MInstrState* mis) { key = unbox(key); - base = Prop(mis->tvScratch, mis->tvRef, ctx, base, key); + base = Prop(mis->tvScratch, mis->tvRef, ctx, base, + key); if (!(base == &mis->tvScratch && base->m_type == KindOfUninit)) { tvBind(val->tv(), base); } } -HOT_FUNC_VM -static inline void bindPropL(Class* ctx, TypedValue* base, TypedValue* key, - RefData* val, TranslatorX64::MInstrState* mis) { - bindPropImpl(ctx, base, key, val, mis); -} +#define PROP_TABLE \ + /* name unboxKey isObj */ \ + PROP(L, true, false) \ + PROP(LO, true, true) \ + PROP(C, false, false) \ + PROP(CO, false, true) -HOT_FUNC_VM -static inline void bindPropC(Class* ctx, TypedValue* base, TypedValue* key, - RefData* val, TranslatorX64::MInstrState* mis) { - bindPropImpl(ctx, base, key, val, mis); +#define PROP(nm, unboxKey, isObj) \ +HOT_FUNC_VM \ +static inline void bindProp##nm(Class* ctx, TypedValue* base, TypedValue* key, \ + RefData* val, \ + TranslatorX64::MInstrState* mis) { \ + bindPropImpl(ctx, base, key, val, mis); \ } +PROP_TABLE +#undef PROP +#undef PROP_TABLE void TranslatorX64::emitBindProp(const Tracelet& t, const NormalizedInstruction& ni, @@ -1987,7 +2119,12 @@ void TranslatorX64::emitBindProp(const Tracelet& t, ASSERT(val.isVariant()); ASSERT(generateMVal(t, ni, mii)); const DynLocation& key = *ni.inputs[iInd]; - auto bindPropOp = (ni.immVecM[mInd] == MPL) ? bindPropL : bindPropC; + typedef void (*PropOp)(Class*, TypedValue*, TypedValue*, RefData*, + MInstrState*); + static const PropOp propOps[] + = {bindPropC, bindPropL, bindPropCO, bindPropLO}; + unsigned idx = buildBitmask(ni.immVecM[mInd] == MPL, m_vecState->isObj()); + PropOp bindPropOp = propOps[idx]; m_regMap.cleanSmashLoc(key.location); PREP_CTX(ctxFixed, argNumToRegName[0]); // Emit the appropriate helper call. @@ -2030,22 +2167,28 @@ void TranslatorX64::emitUnsetElem(const Tracelet& t, EMIT_RCALL(a, ni, unsetElemOp, R(rBase), ML(key.location, a, m_regMap, rsp)); } -template +template static inline void unsetPropImpl(Class* ctx, TypedValue* base, TypedValue* key) { key = unbox(key); - UnsetProp(ctx, base, key); + UnsetProp(ctx, base, key); } -HOT_FUNC_VM -static void unsetPropL(Class* ctx, TypedValue* base, TypedValue* key) { - unsetPropImpl(ctx, base, key); -} +#define PROP_TABLE \ + /* name unboxKey isObj */ \ + PROP(L, true, false) \ + PROP(LO, true, true) \ + PROP(C, false, false) \ + PROP(CO, false, true) -HOT_FUNC_VM -static void unsetPropC(Class* ctx, TypedValue* base, TypedValue* key) { - unsetPropImpl(ctx, base, key); +#define PROP(nm, unboxKey, isObj) \ +HOT_FUNC_VM \ +static void unsetProp##nm(Class* ctx, TypedValue* base, TypedValue* key) { \ + unsetPropImpl(ctx, base, key); \ } +PROP_TABLE +#undef PROP +#undef PROP_TABLE void TranslatorX64::emitUnsetProp(const Tracelet& t, const NormalizedInstruction& ni, @@ -2056,7 +2199,11 @@ void TranslatorX64::emitUnsetProp(const Tracelet& t, __func__, long(a.code.frontier), mInd, iInd); const DynLocation& key = *ni.inputs[iInd]; const DynLocation& val = *ni.inputs[0]; - auto unsetPropOp = ni.immVecM[mInd] == MPL ? unsetPropL : unsetPropC; + typedef void (*PropOp)(Class*, TypedValue*, TypedValue*); + static const PropOp propOps[] + = {unsetPropC, unsetPropL, unsetPropCO, unsetPropLO}; + unsigned idx = buildBitmask(ni.immVecM[mInd] == MPL, m_vecState->isObj()); + PropOp unsetPropOp = propOps[idx]; m_regMap.cleanSmashLoc(key.location); m_regMap.cleanSmashLoc(val.location); PREP_CTX(ctxFixed, argNumToRegName[0]); @@ -2309,12 +2456,14 @@ void TranslatorX64::emitFinal##instr##MOp(const Tracelet& t, \ LazyScratchReg& rBase) { \ switch (ni.immVecM[mInd]) { \ case MEC: case MEL: case MET: case MEI: \ + ASSERT(!m_vecState->isKnown()); \ emit##instr##Elem(t, ni, mii, mInd, iInd, *rBase); \ break; \ case MPC: case MPL: case MPT: \ emit##instr##Prop(t, ni, mii, ctxFixed, mInd, iInd, rBase); \ break; \ case MW: \ + ASSERT(!m_vecState->isKnown()); \ ASSERT((attrs) & MIA_final); \ emit##fN(t, ni, mii, mInd, iInd, *rBase); \ break; \ diff --git a/src/runtime/vm/translator/translator-x64.cpp b/src/runtime/vm/translator/translator-x64.cpp index 30ef2085dec..eb82c4f6a75 100644 --- a/src/runtime/vm/translator/translator-x64.cpp +++ b/src/runtime/vm/translator/translator-x64.cpp @@ -9504,14 +9504,6 @@ void dumpTranslationInfo(const Tracelet& t, TCA postGuards) { } } -namespace { -template struct Nuller : private boost::noncopyable { - explicit Nuller(const T** p) : p(p) {} - ~Nuller() { *p = 0; } - T const** const p; -}; -} - void TranslatorX64::translateTracelet(const Tracelet& t) { const SrcKey &sk = t.m_sk; @@ -9646,7 +9638,8 @@ TranslatorX64::TranslatorX64() m_interceptsEnabled(false), m_unwindRegMap(128), m_curTrace(0), - m_curNI(0) + m_curNI(0), + m_vecState(NULL) { TRACE(1, "TranslatorX64@%p startup\n", this); tx64 = this; diff --git a/src/runtime/vm/translator/translator-x64.h b/src/runtime/vm/translator/translator-x64.h index e11edf3201c..c01899eca7a 100644 --- a/src/runtime/vm/translator/translator-x64.h +++ b/src/runtime/vm/translator/translator-x64.h @@ -39,6 +39,7 @@ namespace VM { namespace Transl { class IRTranslator; +class MVecTransState; struct TraceletCounters { uint64_t m_numEntered, m_numExecuted; @@ -320,6 +321,8 @@ class TranslatorX64 : public Translator Class* ctx; } __attribute__((aligned(16))); private: + + MVecTransState* m_vecState; int mResultStackOffset(const NormalizedInstruction& ni) const; bool generateMVal(const Tracelet& t, const NormalizedInstruction& ni, const MInstrInfo& mii) const; -- 2.11.4.GIT