Commit a9118c1d authored by Marius Wachtler's avatar Marius Wachtler

Merge pull request #966 from undingen/method_cache2

typeLookup: guard on tp_version_tag instead of mro
parents 758a9b32 3ca2326d
...@@ -430,7 +430,9 @@ typedef PyObject *(*allocfunc)(PyTypeObject *, Py_ssize_t); ...@@ -430,7 +430,9 @@ typedef PyObject *(*allocfunc)(PyTypeObject *, Py_ssize_t);
destructor tp_del;\ destructor tp_del;\
\ \
/* Type attribute cache version tag. Added in version 2.6 */\ /* Type attribute cache version tag. Added in version 2.6 */\
unsigned int tp_version_tag; \ /* Pyston change: change uint to 64bit uint
unsigned int tp_version_tag; */ \
PY_UINT64_T tp_version_tag; \
\ \
/* Pyston changes: added these fields */ \ /* Pyston changes: added these fields */ \
......
...@@ -127,6 +127,17 @@ void Assembler::emitInt(int64_t n, int bytes) { ...@@ -127,6 +127,17 @@ void Assembler::emitInt(int64_t n, int bytes) {
ASSERT(n == 0 || n == -1, "%ld", n); ASSERT(n == 0 || n == -1, "%ld", n);
} }
void Assembler::emitUInt(uint64_t n, int bytes) {
assert(bytes > 0 && bytes <= 8);
if (bytes < 8)
assert(n < ((1UL << (8 * bytes))));
for (int i = 0; i < bytes; i++) {
emitByte(n & 0xff);
n >>= 8;
}
ASSERT(n == 0, "%lu", n);
}
void Assembler::emitRex(uint8_t rex) { void Assembler::emitRex(uint8_t rex) {
emitByte(rex | 0x40); emitByte(rex | 0x40);
} }
...@@ -167,7 +178,7 @@ void Assembler::mov(Immediate val, Register dest, bool force_64bit_load) { ...@@ -167,7 +178,7 @@ void Assembler::mov(Immediate val, Register dest, bool force_64bit_load) {
if (rex) if (rex)
emitRex(rex); emitRex(rex);
emitByte(0xb8 + dest_idx); emitByte(0xb8 + dest_idx);
emitInt(val.val, force_64bit_load ? 8 : 4); emitUInt(val.val, force_64bit_load ? 8 : 4);
} }
void Assembler::movq(Immediate src, Indirect dest) { void Assembler::movq(Immediate src, Indirect dest) {
......
...@@ -83,6 +83,7 @@ private: ...@@ -83,6 +83,7 @@ private:
private: private:
void emitByte(uint8_t b); void emitByte(uint8_t b);
void emitInt(int64_t n, int bytes); void emitInt(int64_t n, int bytes);
void emitUInt(uint64_t n, int bytes);
void emitRex(uint8_t rex); void emitRex(uint8_t rex);
void emitModRM(uint8_t mod, uint8_t reg, uint8_t rm); void emitModRM(uint8_t mod, uint8_t reg, uint8_t rm);
void emitSIB(uint8_t scalebits, uint8_t index, uint8_t base); void emitSIB(uint8_t scalebits, uint8_t index, uint8_t base);
......
...@@ -270,6 +270,11 @@ void Rewriter::assertArgsInPlace() { ...@@ -270,6 +270,11 @@ void Rewriter::assertArgsInPlace() {
void RewriterVar::addGuard(uint64_t val) { void RewriterVar::addGuard(uint64_t val) {
STAT_TIMER(t0, "us_timer_rewriter", 10); STAT_TIMER(t0, "us_timer_rewriter", 10);
if (isConstant()) {
RELEASE_ASSERT(constant_value == val, "added guard which is always false");
return;
}
RewriterVar* val_var = rewriter->loadConst(val); RewriterVar* val_var = rewriter->loadConst(val);
rewriter->addAction([=]() { rewriter->_addGuard(this, val_var); }, { this, val_var }, ActionType::GUARD); rewriter->addAction([=]() { rewriter->_addGuard(this, val_var); }, { this, val_var }, ActionType::GUARD);
} }
......
...@@ -957,7 +957,9 @@ extern "C" PyObject* _PyType_Lookup(PyTypeObject* type, PyObject* name) noexcept ...@@ -957,7 +957,9 @@ extern "C" PyObject* _PyType_Lookup(PyTypeObject* type, PyObject* name) noexcept
#define MCACHE_CACHEABLE_NAME(name) PyString_CheckExact(name) && PyString_GET_SIZE(name) <= MCACHE_MAX_ATTR_SIZE #define MCACHE_CACHEABLE_NAME(name) PyString_CheckExact(name) && PyString_GET_SIZE(name) <= MCACHE_MAX_ATTR_SIZE
struct method_cache_entry { struct method_cache_entry {
unsigned int version; // Pyston change:
// unsigned int version;
PY_UINT64_T version;
PyObject* name; /* reference to exactly a str or None */ PyObject* name; /* reference to exactly a str or None */
PyObject* value; /* borrowed */ PyObject* value; /* borrowed */
}; };
...@@ -984,7 +986,13 @@ int assign_version_tag(PyTypeObject* type) noexcept { ...@@ -984,7 +986,13 @@ int assign_version_tag(PyTypeObject* type) noexcept {
type->tp_version_tag = next_version_tag++; type->tp_version_tag = next_version_tag++;
/* for stress-testing: next_version_tag &= 0xFF; */ /* for stress-testing: next_version_tag &= 0xFF; */
if (type->tp_version_tag == 0) { if (unlikely(type->tp_version_tag == 0)) {
// Pyston change: check for a wrap around because they are not allowed to happen with our 64bit version tag
static bool is_wrap_around = false;
if (is_wrap_around)
abort();
is_wrap_around = true;
/* wrap-around or just starting Python - clear the whole /* wrap-around or just starting Python - clear the whole
cache by filling names with references to Py_None. cache by filling names with references to Py_None.
Values are also set to NULL for added protection, as they Values are also set to NULL for added protection, as they
...@@ -1019,7 +1027,9 @@ template <Rewritable rewritable> Box* typeLookup(BoxedClass* cls, BoxedString* a ...@@ -1019,7 +1027,9 @@ template <Rewritable rewritable> Box* typeLookup(BoxedClass* cls, BoxedString* a
Box* val = NULL; Box* val = NULL;
if (rewrite_args) { // CAPI types defined inside external extension normally don't have this flag set while all types inside pyston set
// it.
if (rewrite_args && !PyType_HasFeature(cls, Py_TPFLAGS_HAVE_VERSION_TAG)) {
assert(!rewrite_args->isSuccessful()); assert(!rewrite_args->isSuccessful());
RewriterVar* obj_saved = rewrite_args->obj; RewriterVar* obj_saved = rewrite_args->obj;
...@@ -1073,16 +1083,20 @@ template <Rewritable rewritable> Box* typeLookup(BoxedClass* cls, BoxedString* a ...@@ -1073,16 +1083,20 @@ template <Rewritable rewritable> Box* typeLookup(BoxedClass* cls, BoxedString* a
assert(cls->tp_mro); assert(cls->tp_mro);
assert(cls->tp_mro->cls == tuple_cls); assert(cls->tp_mro->cls == tuple_cls);
bool found_cached_entry = false;
if (MCACHE_CACHEABLE_NAME(attr) && PyType_HasFeature(cls, Py_TPFLAGS_VALID_VERSION_TAG)) { if (MCACHE_CACHEABLE_NAME(attr) && PyType_HasFeature(cls, Py_TPFLAGS_VALID_VERSION_TAG)) {
if (attr->hash == -1) if (attr->hash == -1)
strHashUnboxed(attr); strHashUnboxed(attr);
/* fast path */ /* fast path */
unsigned int h = MCACHE_HASH_METHOD(cls, attr); auto h = MCACHE_HASH_METHOD(cls, attr);
if (method_cache[h].version == cls->tp_version_tag && method_cache[h].name == attr) if (method_cache[h].version == cls->tp_version_tag && method_cache[h].name == attr) {
return method_cache[h].value; val = method_cache[h].value;
found_cached_entry = true;
}
} }
if (!found_cached_entry) {
for (auto b : *static_cast<BoxedTuple*>(cls->tp_mro)) { for (auto b : *static_cast<BoxedTuple*>(cls->tp_mro)) {
// object_cls will get checked very often, but it only // object_cls will get checked very often, but it only
// has attributes that start with an underscore. // has attributes that start with an underscore.
...@@ -1099,13 +1113,25 @@ template <Rewritable rewritable> Box* typeLookup(BoxedClass* cls, BoxedString* a ...@@ -1099,13 +1113,25 @@ template <Rewritable rewritable> Box* typeLookup(BoxedClass* cls, BoxedString* a
} }
if (MCACHE_CACHEABLE_NAME(attr) && assign_version_tag(cls)) { if (MCACHE_CACHEABLE_NAME(attr) && assign_version_tag(cls)) {
unsigned int h = MCACHE_HASH_METHOD(cls, attr); auto h = MCACHE_HASH_METHOD(cls, attr);
method_cache[h].version = cls->tp_version_tag; method_cache[h].version = cls->tp_version_tag;
method_cache[h].value = val; /* borrowed */ method_cache[h].value = val; /* borrowed */
Py_INCREF(attr); Py_INCREF(attr);
Py_DECREF(method_cache[h].name); Py_DECREF(method_cache[h].name);
method_cache[h].name = attr; method_cache[h].name = attr;
} }
}
if (rewrite_args) {
RewriterVar* obj_saved = rewrite_args->obj;
static_assert(sizeof(BoxedClass::tp_flags) == 8, "addAttrGuard only supports 64bit values");
static_assert(sizeof(BoxedClass::tp_version_tag) == 8, "addAttrGuard only supports 64bit values");
obj_saved->addAttrGuard(offsetof(BoxedClass, tp_flags), (intptr_t)cls->tp_flags);
obj_saved->addAttrGuard(offsetof(BoxedClass, tp_version_tag), (intptr_t)cls->tp_version_tag);
if (!val)
rewrite_args->setReturn(NULL, ReturnConvention::NO_RETURN);
else
rewrite_args->setReturn(rewrite_args->rewriter->loadConst((int64_t)val), ReturnConvention::HAS_RETURN);
}
return val; return val;
} }
} }
...@@ -2367,7 +2393,7 @@ void setattrGeneric(Box* obj, BoxedString* attr, Box* val, SetattrRewriteArgs* r ...@@ -2367,7 +2393,7 @@ void setattrGeneric(Box* obj, BoxedString* attr, Box* val, SetattrRewriteArgs* r
} }
// update_slot() calls PyType_Modified() internally so we only have to explicitly call it inside the IC // update_slot() calls PyType_Modified() internally so we only have to explicitly call it inside the IC
if (rewrite_args) if (rewrite_args && PyType_HasFeature(self, Py_TPFLAGS_HAVE_VERSION_TAG))
rewrite_args->rewriter->call(true, (void*)PyType_Modified, rewrite_args->obj); rewrite_args->rewriter->call(true, (void*)PyType_Modified, rewrite_args->obj);
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment