Commit c5b1d41e authored by Kevin Modzelewski's avatar Kevin Modzelewski

Change attributes from strings to BoxedStrings

The real benefit is that we intern the strings that
end up getting used as attribute names, so we can compare
them using pointer comparisons.  It should also reduce
the size overhead of hidden classes, since we no longer
have to copy the string data into the hidden class.
parent db4bc778
......@@ -222,7 +222,7 @@ private:
// TODO this isn't the exact behavior
BoxedString* name = getInplaceOpName(node->op_type);
CompilerType* attr_type = left->getattrType(name->s(), true);
CompilerType* attr_type = left->getattrType(name, true);
if (attr_type == UNDEF)
attr_type = UNKNOWN;
......@@ -251,7 +251,7 @@ private:
// TODO this isn't the exact behavior
BoxedString* name = getOpName(node->op_type);
CompilerType* attr_type = left->getattrType(name->s(), true);
CompilerType* attr_type = left->getattrType(name, true);
if (attr_type == UNDEF)
attr_type = UNKNOWN;
......@@ -336,7 +336,7 @@ private:
}
BoxedString* name = getOpName(node->ops[0]);
CompilerType* attr_type = left->getattrType(name->s(), true);
CompilerType* attr_type = left->getattrType(name, true);
if (attr_type == UNDEF)
attr_type = UNKNOWN;
......@@ -474,7 +474,7 @@ private:
void* visit_subscript(AST_Subscript* node) override {
CompilerType* val = getType(node->value);
CompilerType* slice = getType(node->slice);
static std::string name("__getitem__");
static BoxedString* name = internStringImmortal("__getitem__");
CompilerType* getitem_type = val->getattrType(name, true);
std::vector<CompilerType*> args;
args.push_back(slice);
......@@ -494,7 +494,7 @@ private:
// TODO this isn't the exact behavior
BoxedString* name = getOpName(node->op_type);
CompilerType* attr_type = operand->getattrType(name->s(), true);
CompilerType* attr_type = operand->getattrType(name, true);
std::vector<CompilerType*> arg_types;
return attr_type->callType(ArgPassSpec(0), arg_types, NULL);
}
......
......@@ -444,7 +444,7 @@ extern "C" int PyModule_AddObject(PyObject* _m, const char* name, PyObject* valu
BoxedModule* m = static_cast<BoxedModule*>(_m);
assert(m->cls == module_cls);
m->setattr(name, value, NULL);
m->setattr(internStringMortal(name), value, NULL);
return 0;
}
......
......@@ -419,11 +419,13 @@ extern "C" PyObject* PyObject_SelfIter(PyObject* obj) noexcept {
extern "C" int PyObject_GenericSetAttr(PyObject* obj, PyObject* name, PyObject* value) noexcept {
RELEASE_ASSERT(PyString_Check(name), "");
BoxedString* str = static_cast<BoxedString*>(name);
internStringMortalInplace(str);
try {
if (value == NULL)
delattrGeneric(obj, static_cast<BoxedString*>(name), NULL);
delattrGeneric(obj, str, NULL);
else
setattrGeneric(obj, static_cast<BoxedString*>(name), value, NULL);
setattrGeneric(obj, str, value, NULL);
} catch (ExcInfo e) {
setCAPIException(e);
return -1;
......@@ -458,7 +460,7 @@ extern "C" int PyObject_SetAttr(PyObject* obj, PyObject* name, PyObject* value)
extern "C" int PyObject_SetAttrString(PyObject* v, const char* name, PyObject* w) noexcept {
try {
setattr(v, boxString(name), w);
setattr(v, internStringMortal(name), w);
} catch (ExcInfo e) {
setCAPIException(e);
return -1;
......@@ -468,7 +470,7 @@ extern "C" int PyObject_SetAttrString(PyObject* v, const char* name, PyObject* w
extern "C" PyObject* PyObject_GetAttrString(PyObject* o, const char* attr) noexcept {
try {
return getattr(o, boxString(attr));
return getattr(o, internStringMortal(attr));
} catch (ExcInfo e) {
setCAPIException(e);
return NULL;
......
......@@ -22,10 +22,6 @@
namespace pyston {
// FIXME duplicated with objmodel.cpp
static const std::string _new_str("__new__");
static const std::string _getattr_str("__getattr__");
static const std::string _getattribute_str("__getattribute__");
typedef int (*update_callback)(PyTypeObject*, void*);
static PyObject* tp_new_wrapper(PyTypeObject* self, BoxedTuple* args, Box* kwds) noexcept;
......@@ -529,10 +525,13 @@ static PyObject* wrap_init(PyObject* self, PyObject* args, void* wrapped, PyObje
static PyObject* lookup_maybe(PyObject* self, const char* attrstr, PyObject** attrobj) noexcept {
PyObject* res;
// TODO: CPython uses the attrobj as a cache. If we want to use it, we'd have to make sure that
// they get registered as GC roots since they are usually placed into static variables.
if (*attrobj == NULL) {
*attrobj = PyString_InternFromString(attrstr);
if (*attrobj == NULL)
return NULL;
}
Box* obj = typeLookup(self->cls, attrstr, NULL);
Box* obj = typeLookup(self->cls, (BoxedString*)*attrobj, NULL);
if (obj)
return processDescriptor(obj, self, self->cls);
return obj;
......@@ -850,7 +849,8 @@ static PyObject* slot_tp_descr_get(PyObject* self, PyObject* obj, PyObject* type
PyTypeObject* tp = Py_TYPE(self);
PyObject* get;
get = typeLookup(tp, "__get__", NULL);
static BoxedString* get_str = internStringImmortal("__get__");
get = typeLookup(tp, get_str, NULL);
if (get == NULL) {
/* Avoid further slowdowns */
if (tp->tp_descr_get == slot_tp_descr_get)
......@@ -932,6 +932,7 @@ static PyObject* slot_tp_getattr_hook(PyObject* self, PyObject* name) noexcept {
__getattr__, even when the attribute is present. So we use
_PyType_Lookup and create the method only when needed, with
call_attribute. */
static BoxedString* _getattr_str = internStringImmortal("__getattr__");
getattr = typeLookup(self->cls, _getattr_str, NULL);
if (getattr == NULL) {
/* No __getattr__ hook: use a simpler dispatcher */
......@@ -943,6 +944,7 @@ static PyObject* slot_tp_getattr_hook(PyObject* self, PyObject* name) noexcept {
__getattr__, even when self has the default __getattribute__
method. So we use _PyType_Lookup and create the method only when
needed, with call_attribute. */
static BoxedString* _getattribute_str = internStringImmortal("__getattribute__");
getattribute = typeLookup(self->cls, _getattribute_str, NULL);
if (getattribute == NULL
|| (Py_TYPE(getattribute) == wrapperdescr_cls
......@@ -963,6 +965,7 @@ static PyObject* slot_tp_getattr_hook(PyObject* self, PyObject* name) noexcept {
try {
// TODO: runtime ICs?
static BoxedString* _new_str = internStringImmortal("__new__");
Box* new_attr = typeLookup(self, _new_str, NULL);
assert(new_attr);
new_attr = processDescriptor(new_attr, None, self);
......@@ -1406,13 +1409,13 @@ static void** slotptr(BoxedClass* type, int offset) noexcept {
// Copied from CPython:
#define TPSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \
{ NAME, offsetof(PyTypeObject, SLOT), (void*)(FUNCTION), WRAPPER, PyDoc_STR(DOC), 0 }
{ NAME, offsetof(PyTypeObject, SLOT), (void*)(FUNCTION), WRAPPER, PyDoc_STR(DOC), 0, NULL }
#define TPPSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \
{ NAME, offsetof(PyTypeObject, SLOT), (void*)(FUNCTION), WRAPPER, PyDoc_STR(DOC), PyWrapperFlag_PYSTON }
{ NAME, offsetof(PyTypeObject, SLOT), (void*)(FUNCTION), WRAPPER, PyDoc_STR(DOC), PyWrapperFlag_PYSTON, NULL }
#define FLSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC, FLAGS) \
{ NAME, offsetof(PyTypeObject, SLOT), (void*)(FUNCTION), WRAPPER, PyDoc_STR(DOC), FLAGS }
{ NAME, offsetof(PyTypeObject, SLOT), (void*)(FUNCTION), WRAPPER, PyDoc_STR(DOC), FLAGS, NULL }
#define ETSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \
{ NAME, offsetof(PyHeapTypeObject, SLOT), (void*)(FUNCTION), WRAPPER, PyDoc_STR(DOC), 0 }
{ NAME, offsetof(PyHeapTypeObject, SLOT), (void*)(FUNCTION), WRAPPER, PyDoc_STR(DOC), 0, NULL }
#define SQSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) ETSLOT(NAME, as_sequence.SLOT, FUNCTION, WRAPPER, DOC)
#define MPSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) ETSLOT(NAME, as_mapping.SLOT, FUNCTION, WRAPPER, DOC)
#define NBSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) ETSLOT(NAME, as_number.SLOT, FUNCTION, WRAPPER, DOC)
......@@ -1551,7 +1554,7 @@ static slotdef slotdefs[]
SQSLOT("__contains__", sq_contains, slot_sq_contains, wrap_objobjproc, "x.__contains__(y) <==> y in x"),
SQSLOT("__iadd__", sq_inplace_concat, NULL, wrap_binaryfunc, "x.__iadd__(y) <==> x+=y"),
SQSLOT("__imul__", sq_inplace_repeat, NULL, wrap_indexargfunc, "x.__imul__(y) <==> x*=y"),
{ "", 0, NULL, NULL, "", 0 } };
{ "", 0, NULL, NULL, "", 0, NULL } };
static void init_slotdefs() noexcept {
static bool initialized = false;
......@@ -1559,6 +1562,8 @@ static void init_slotdefs() noexcept {
return;
for (int i = 0; i < sizeof(slotdefs) / sizeof(slotdefs[0]); i++) {
slotdefs[i].name_strobj = internStringImmortal(slotdefs[i].name.data());
if (i > 0) {
if (!slotdefs[i].name.size())
continue;
......@@ -1575,7 +1580,6 @@ static void init_slotdefs() noexcept {
}
#endif
ASSERT(slotdefs[i].offset >= slotdefs[i - 1].offset, "%d %s", i, slotdefs[i - 1].name.data());
// CPython interns the name here
}
}
......@@ -1642,7 +1646,7 @@ static const slotdef* update_one_slot(BoxedClass* type, const slotdef* p) noexce
}
do {
descr = typeLookup(type, p->name, NULL);
descr = typeLookup(type, p->name_strobj, NULL);
if (descr == NULL) {
if (ptr == (void**)&type->tp_iternext) {
specific = (void*)_PyObject_NextNotImplemented;
......@@ -1819,10 +1823,11 @@ static struct PyMethodDef tp_new_methoddef[] = { { "__new__", (PyCFunction)tp_ne
{ 0, 0, 0, 0 } };
static void add_tp_new_wrapper(BoxedClass* type) noexcept {
if (type->getattr("__new__"))
static BoxedString* new_str = internStringImmortal("__new__");
if (type->getattr(new_str))
return;
type->giveAttr("__new__", new BoxedCApiFunction(tp_new_methoddef, type));
type->giveAttr(new_str, new BoxedCApiFunction(tp_new_methoddef, type));
}
void add_operators(BoxedClass* cls) noexcept {
......@@ -1836,13 +1841,13 @@ void add_operators(BoxedClass* cls) noexcept {
if (!ptr || !*ptr)
continue;
if (cls->getattr(p.name))
if (cls->getattr(p.name_strobj))
continue;
if (*ptr == PyObject_HashNotImplemented) {
cls->giveAttr(p.name, None);
cls->giveAttr(p.name_strobj, None);
} else {
cls->giveAttr(p.name, new BoxedWrapperDescriptor(&p, cls, *ptr));
cls->giveAttr(p.name_strobj, new BoxedWrapperDescriptor(&p, cls, *ptr));
}
}
......@@ -3097,17 +3102,18 @@ extern "C" int PyType_Ready(PyTypeObject* cls) noexcept {
}
for (PyMethodDef* method = cls->tp_methods; method && method->ml_name; ++method) {
cls->setattr(method->ml_name, new BoxedMethodDescriptor(method, cls), NULL);
cls->setattr(internStringMortal(method->ml_name), new BoxedMethodDescriptor(method, cls), NULL);
}
for (PyMemberDef* member = cls->tp_members; member && member->name; ++member) {
cls->giveAttr(member->name, new BoxedMemberDescriptor(member));
cls->giveAttr(internStringMortal(member->name), new BoxedMemberDescriptor(member));
}
for (PyGetSetDef* getset = cls->tp_getset; getset && getset->name; ++getset) {
// TODO do something with __doc__
cls->giveAttr(getset->name, new (capi_getset_cls) BoxedGetsetDescriptor(
getset->get, (void (*)(Box*, Box*, void*))getset->set, getset->closure));
cls->giveAttr(internStringMortal(getset->name),
new (capi_getset_cls) BoxedGetsetDescriptor(getset->get, (void (*)(Box*, Box*, void*))getset->set,
getset->closure));
}
try {
......@@ -3117,11 +3123,12 @@ extern "C" int PyType_Ready(PyTypeObject* cls) noexcept {
return -1;
}
if (!cls->hasattr("__doc__")) {
static BoxedString* doc_str = internStringImmortal("__doc__");
if (!cls->hasattr(doc_str)) {
if (cls->tp_doc) {
cls->giveAttr("__doc__", boxString(cls->tp_doc));
cls->giveAttr(doc_str, boxString(cls->tp_doc));
} else {
cls->giveAttr("__doc__", None);
cls->giveAttr(doc_str, None);
}
}
......
......@@ -849,7 +849,7 @@ Value ASTInterpreter::visit_langPrimitive(AST_LangPrimitive* node) {
const std::string& name = ast_str->str_data;
assert(name.size());
// TODO: shouldn't have to rebox here
v.o = importFrom(module.o, boxString(name));
v.o = importFrom(module.o, internStringMortal(name));
} else if (node->opcode == AST_LangPrimitive::IMPORT_NAME) {
abortJITing();
assert(node->args.size() == 3);
......
......@@ -34,10 +34,9 @@
namespace pyston {
static const std::string iter_str = "__iter__";
static const std::string hasnext_str = "__hasnext__";
CompilerType* CompilerType::getPystonIterType() {
static BoxedString* iter_str = internStringImmortal("__iter__");
static BoxedString* hasnext_str = internStringImmortal("__hasnext__");
if (hasattr(iter_str) == Yes) {
CompilerType* iter_type = getattrType(iter_str, true)->callType(ArgPassSpec(0), {}, NULL);
if (iter_type->hasattr(hasnext_str) == Yes)
......@@ -48,7 +47,7 @@ CompilerType* CompilerType::getPystonIterType() {
return UNKNOWN;
}
CompilerType::Result CompilerType::hasattr(llvm::StringRef attr) {
CompilerType::Result CompilerType::hasattr(BoxedString* attr) {
CompilerType* type = getattrType(attr, true);
if (type == UNKNOWN)
return Result::Maybe;
......@@ -299,7 +298,7 @@ public:
return rtn;
}
CompilerType* getattrType(llvm::StringRef attr, bool cls_only) override { return UNKNOWN; }
CompilerType* getattrType(BoxedString* attr, bool cls_only) override { return UNKNOWN; }
CompilerType* callType(ArgPassSpec argspec, const std::vector<CompilerType*>& arg_types,
const std::vector<llvm::StringRef>* keyword_names) override {
return UNKNOWN;
......@@ -780,7 +779,7 @@ public:
bool canConvertTo(ConcreteCompilerType* other_type) override { return other_type == UNKNOWN; }
CompilerType* getattrType(llvm::StringRef attr, bool cls_only) override { return UNDEF; }
CompilerType* getattrType(BoxedString* attr, bool cls_only) override { return UNDEF; }
CompilerType* callType(ArgPassSpec argspec, const std::vector<CompilerType*>& arg_types,
const std::vector<llvm::StringRef>* keyword_names) override {
......@@ -861,7 +860,7 @@ public:
// pass
}
CompilerType* getattrType(llvm::StringRef attr, bool cls_only) override {
CompilerType* getattrType(BoxedString* attr, bool cls_only) override {
/*
static std::vector<AbstractFunctionType::Sig*> sigs;
if (sigs.size() == 0) {
......@@ -903,8 +902,9 @@ public:
}
// we can handle those operations when the rhs is a float
if (attr == "__add__" || attr == "__sub__" || attr == "__mul__" || attr == "__div__" || attr == "__pow__"
|| attr == "__floordiv__" || attr == "__mod__" || attr == "__pow__") {
if (attr->s() == "__add__" || attr->s() == "__sub__" || attr->s() == "__mul__" || attr->s() == "__div__"
|| attr->s() == "__pow__" || attr->s() == "__floordiv__" || attr->s() == "__mod__"
|| attr->s() == "__pow__") {
return AbstractFunctionType::get(sigs);
}
return BOXED_INT->getattrType(attr, cls_only);
......@@ -1118,7 +1118,7 @@ public:
// pass
}
CompilerType* getattrType(llvm::StringRef attr, bool cls_only) override {
CompilerType* getattrType(BoxedString* attr, bool cls_only) override {
static std::vector<AbstractFunctionType::Sig*> sigs;
if (sigs.size() == 0) {
AbstractFunctionType::Sig* float_sig = new AbstractFunctionType::Sig();
......@@ -1137,13 +1137,15 @@ public:
sigs.push_back(unknown_sig);
}
if (attr == "__add__" || attr == "__sub__" || attr == "__mul__" || attr == "__div__" || attr == "__pow__"
|| attr == "__floordiv__" || attr == "__mod__" || attr == "__pow__") {
if (attr->s() == "__add__" || attr->s() == "__sub__" || attr->s() == "__mul__" || attr->s() == "__div__"
|| attr->s() == "__pow__" || attr->s() == "__floordiv__" || attr->s() == "__mod__"
|| attr->s() == "__pow__") {
return AbstractFunctionType::get(sigs);
}
if (attr == "__iadd__" || attr == "__isub__" || attr == "__imul__" || attr == "__idiv__" || attr == "__ipow__"
|| attr == "__ifloordiv__" || attr == "__imod__" || attr == "__ipow__") {
if (attr->s() == "__iadd__" || attr->s() == "__isub__" || attr->s() == "__imul__" || attr->s() == "__idiv__"
|| attr->s() == "__ipow__" || attr->s() == "__ifloordiv__" || attr->s() == "__imod__"
|| attr->s() == "__ipow__") {
return AbstractFunctionType::get(sigs);
}
......@@ -1446,7 +1448,7 @@ public:
&& cls->hasGenericGetattr());
}
CompilerType* getattrType(llvm::StringRef attr, bool cls_only) override {
CompilerType* getattrType(BoxedString* attr, bool cls_only) override {
// Any changes here need to be mirrored in getattr()
if (canStaticallyResolveGetattrs()) {
Box* rtattr = typeLookup(cls, attr, nullptr);
......@@ -1474,7 +1476,7 @@ public:
bool cls_only) override {
// Any changes here need to be mirrored in getattrType()
if (canStaticallyResolveGetattrs()) {
Box* rtattr = typeLookup(cls, attr->s(), nullptr);
Box* rtattr = typeLookup(cls, attr, nullptr);
if (rtattr == NULL) {
llvm::CallSite call = emitter.createCall3(
info.unw_info, g.funcs.raiseAttributeErrorStr, embedRelocatablePtr(cls->tp_name, g.i8_ptr),
......@@ -1524,7 +1526,7 @@ public:
if (!canStaticallyResolveGetattrs())
return NULL;
Box* rtattr = cls->getattr(attr->s());
Box* rtattr = cls->getattr(attr);
if (rtattr == NULL) {
if (no_attribute) {
*no_attribute = true;
......@@ -2027,7 +2029,7 @@ public:
return new ConcreteCompilerVariable(other_type, boxed, true);
}
CompilerType* getattrType(llvm::StringRef attr, bool cls_only) override {
CompilerType* getattrType(BoxedString* attr, bool cls_only) override {
return BOXED_BOOL->getattrType(attr, cls_only);
}
......@@ -2228,7 +2230,7 @@ public:
return new ConcreteCompilerVariable(INT, getConstantInt(var->getValue()->size(), g.i64), true);
}
CompilerType* getattrType(llvm::StringRef attr, bool cls_only) override {
CompilerType* getattrType(BoxedString* attr, bool cls_only) override {
return BOXED_TUPLE->getattrType(attr, cls_only);
}
......@@ -2429,7 +2431,7 @@ public:
ConcreteCompilerType* getConcreteType() override { return this; }
CompilerType* getattrType(llvm::StringRef attr, bool cls_only) override { return UNDEF; }
CompilerType* getattrType(BoxedString* attr, bool cls_only) override { return UNDEF; }
bool canConvertTo(ConcreteCompilerType* other_type) override { return true; }
......
......@@ -35,6 +35,7 @@ class IREmitter;
class BoxedInt;
class BoxedFloat;
class BoxedLong;
class BoxedString;
typedef llvm::SmallVector<uint64_t, 1> FrameVals;
......@@ -47,9 +48,9 @@ public:
virtual ConcreteCompilerType* getConcreteType() = 0;
virtual ConcreteCompilerType* getBoxType() = 0;
virtual bool canConvertTo(ConcreteCompilerType* other_type) = 0;
virtual CompilerType* getattrType(llvm::StringRef attr, bool cls_only) = 0;
virtual CompilerType* getattrType(BoxedString* attr, bool cls_only) = 0;
virtual CompilerType* getPystonIterType();
virtual Result hasattr(llvm::StringRef attr);
virtual Result hasattr(BoxedString* attr);
virtual CompilerType* callType(ArgPassSpec argspec, const std::vector<CompilerType*>& arg_types,
const std::vector<llvm::StringRef>* keyword_names) = 0;
......@@ -157,7 +158,7 @@ public:
printf("makeClassCheck not defined for %s\n", debugName().c_str());
abort();
}
CompilerType* getattrType(llvm::StringRef attr, bool cls_only) override {
CompilerType* getattrType(BoxedString* attr, bool cls_only) override {
printf("getattrType not defined for %s\n", debugName().c_str());
abort();
}
......
......@@ -283,9 +283,13 @@ void compileAndRunModule(AST_Module* m, BoxedModule* bm) {
ScopingAnalysis* scoping = new ScopingAnalysis(m, true);
std::unique_ptr<SourceInfo> si(new SourceInfo(bm, scoping, future_flags, m, m->body, fn));
bm->setattr("__doc__", si->getDocString(), NULL);
if (!bm->hasattr("__builtins__"))
bm->giveAttr("__builtins__", PyModule_GetDict(builtins_module));
static BoxedString* doc_str = internStringImmortal("__doc__");
bm->setattr(doc_str, si->getDocString(), NULL);
static BoxedString* builtins_str = internStringImmortal("__builtins__");
if (!bm->hasattr(builtins_str))
bm->giveAttr(builtins_str, PyModule_GetDict(builtins_module));
clfunc = new CLFunction(0, 0, false, false, std::move(si));
}
......
......@@ -642,8 +642,9 @@ private:
const std::string& name = ast_str->str_data;
assert(name.size());
llvm::Value* name_arg = embedRelocatablePtr(
irstate->getSourceInfo()->parent_module->getStringConstant(name), g.llvm_boxedstring_type_ptr);
llvm::Value* name_arg
= embedRelocatablePtr(irstate->getSourceInfo()->parent_module->getStringConstant(name, true),
g.llvm_boxedstring_type_ptr);
llvm::Value* r
= emitter.createCall2(unw_info, g.funcs.importFrom, converted_module->getValue(), name_arg);
......
......@@ -2489,7 +2489,8 @@ CFG* computeCFG(SourceInfo* source, std::vector<AST_stmt*> body) {
new AST_Name(source->getInternedStrings().get("__module__"), AST_TYPE::Store, source->ast->lineno));
if (source->scoping->areGlobalsFromModule()) {
Box* module_name = source->parent_module->getattr("__name__", NULL);
static BoxedString* name_str = internStringImmortal("__name__");
Box* module_name = source->parent_module->getattr(name_str, NULL);
assert(module_name->cls == str_cls);
module_assign->value = new AST_Str(static_cast<BoxedString*>(module_name)->s());
} else {
......
......@@ -80,6 +80,7 @@ public:
llvm::StringRef s() const;
operator llvm::StringRef() const { return s(); }
operator BoxedString*() const { return getBox(); }
friend class InternedStringPool;
friend struct std::hash<InternedString>;
......
......@@ -457,10 +457,23 @@ struct GetattrRewriteArgs;
struct DelattrRewriteArgs;
// Helper function around PyString_InternFromString:
inline BoxedString* internStringImmortal(const char* s) {
BoxedString* r = (BoxedString*)PyString_InternFromString(s);
assert(r);
return r;
BoxedString* internStringImmortal(llvm::StringRef s);
// Callers should use this function if they can accept mortal string objects.
// FIXME For now it just returns immortal strings, but at least we can use it
// to start documenting the places that can take mortal strings.
inline BoxedString* internStringMortal(const char* s) {
return internStringImmortal(s);
}
inline BoxedString* internStringMortal(llvm::StringRef s) {
assert(s.data()[s.size()] == '\0');
return internStringMortal(s.data());
}
// TODO this is an immortal intern for now
inline void internStringMortalInplace(BoxedString*& s) {
PyString_InternInPlace((PyObject**)&s);
}
struct HCAttrs {
......@@ -503,18 +516,19 @@ public:
BoxedDict* getDict();
void setattr(llvm::StringRef attr, Box* val, SetattrRewriteArgs* rewrite_args);
void giveAttr(llvm::StringRef attr, Box* val) {
void setattr(BoxedString* attr, Box* val, SetattrRewriteArgs* rewrite_args);
void giveAttr(const char* attr, Box* val) { giveAttr(internStringMortal(attr), val); }
void giveAttr(BoxedString* attr, Box* val) {
assert(!this->hasattr(attr));
this->setattr(attr, val, NULL);
}
// getattr() does the equivalent of PyDict_GetItem(obj->dict, attr): it looks up the attribute's value on the
// object's attribute storage. it doesn't look at other objects or do any descriptor logic.
Box* getattr(llvm::StringRef attr, GetattrRewriteArgs* rewrite_args);
Box* getattr(llvm::StringRef attr) { return getattr(attr, NULL); }
bool hasattr(llvm::StringRef attr) { return getattr(attr) != NULL; }
void delattr(llvm::StringRef attr, DelattrRewriteArgs* rewrite_args);
Box* getattr(BoxedString* attr, GetattrRewriteArgs* rewrite_args);
Box* getattr(BoxedString* attr) { return getattr(attr, NULL); }
bool hasattr(BoxedString* attr) { return getattr(attr) != NULL; }
void delattr(BoxedString* attr, DelattrRewriteArgs* rewrite_args);
// Only valid for hc-backed instances:
Box* getAttrWrapper();
......
......@@ -412,6 +412,8 @@ Box* delattrFunc(Box* obj, Box* _str) {
if (_str->cls != str_cls)
raiseExcHelper(TypeError, "attribute name must be string, not '%s'", getTypeName(_str));
BoxedString* str = static_cast<BoxedString*>(_str);
internStringMortalInplace(str);
delattr(obj, str);
return None;
}
......@@ -424,6 +426,7 @@ Box* getattrFunc(Box* obj, Box* _str, Box* default_value) {
}
BoxedString* str = static_cast<BoxedString*>(_str);
internStringMortalInplace(str);
Box* rtn = NULL;
try {
......@@ -451,6 +454,8 @@ Box* setattrFunc(Box* obj, Box* _str, Box* value) {
}
BoxedString* str = static_cast<BoxedString*>(_str);
internStringMortalInplace(str);
setattr(obj, str, value);
return None;
}
......@@ -463,6 +468,8 @@ Box* hasattr(Box* obj, Box* _str) {
}
BoxedString* str = static_cast<BoxedString*>(_str);
internStringMortalInplace(str);
Box* attr;
try {
attr = getattrInternal(obj, str, NULL);
......@@ -656,7 +663,8 @@ Box* exceptionNew(BoxedClass* cls, BoxedTuple* args) {
Box* exceptionStr(Box* b) {
// TODO In CPython __str__ and __repr__ pull from an internalized message field, but for now do this:
Box* message = b->getattr("message");
static BoxedString* message_str = internStringImmortal("message");
Box* message = b->getattr(message_str);
assert(message);
message = str(message);
assert(message->cls == str_cls);
......@@ -666,7 +674,8 @@ Box* exceptionStr(Box* b) {
Box* exceptionRepr(Box* b) {
// TODO In CPython __str__ and __repr__ pull from an internalized message field, but for now do this:
Box* message = b->getattr("message");
static BoxedString* message_str = internStringImmortal("message");
Box* message = b->getattr(message_str);
assert(message);
message = repr(message);
assert(message->cls == str_cls);
......@@ -916,7 +925,8 @@ Box* getreversed(Box* o) {
if (r)
return r;
if (!typeLookup(o->cls, "__getitem__", NULL)) {
static BoxedString* getitem_str = internStringImmortal("__getitem__");
if (!typeLookup(o->cls, getitem_str, NULL)) {
raiseExcHelper(TypeError, "'%s' object is not iterable", getTypeName(o));
}
int64_t len = unboxedLen(o); // this will throw an exception if __len__ isn't there
......
......@@ -84,7 +84,7 @@ BoxedDict* getSysModulesDict() {
BoxedList* getSysPath() {
// Unlike sys.modules, CPython handles sys.path by fetching it each time:
Box* _sys_path = sys_module->getattr("path");
Box* _sys_path = sys_module->getattr(internStringMortal("path"));
assert(_sys_path);
if (_sys_path->cls != list_cls) {
......@@ -97,7 +97,7 @@ BoxedList* getSysPath() {
}
Box* getSysStdout() {
Box* sys_stdout = sys_module->getattr("stdout");
Box* sys_stdout = sys_module->getattr(internStringMortal("stdout"));
RELEASE_ASSERT(sys_stdout, "lost sys.stdout??");
return sys_stdout;
}
......@@ -135,10 +135,10 @@ Box* sysGetRecursionLimit() {
extern "C" int PySys_SetObject(const char* name, PyObject* v) noexcept {
try {
if (!v) {
if (sys_module->getattr(name))
sys_module->delattr(name, NULL);
if (sys_module->getattr(internStringMortal(name)))
sys_module->delattr(internStringMortal(name), NULL);
} else
sys_module->setattr(name, v, NULL);
sys_module->setattr(internStringMortal(name), v, NULL);
} catch (ExcInfo e) {
abort();
}
......@@ -146,7 +146,7 @@ extern "C" int PySys_SetObject(const char* name, PyObject* v) noexcept {
}
extern "C" PyObject* PySys_GetObject(const char* name) noexcept {
return sys_module->getattr(name);
return sys_module->getattr(internStringMortal(name));
}
static void mywrite(const char* name, FILE* fp, const char* format, va_list va) noexcept {
......@@ -192,7 +192,7 @@ extern "C" void PySys_WriteStderr(const char* format, ...) noexcept {
}
void addToSysArgv(const char* str) {
Box* sys_argv = sys_module->getattr("argv");
Box* sys_argv = sys_module->getattr(internStringMortal("argv"));
assert(sys_argv);
assert(sys_argv->cls == list_cls);
listAppendInternal(sys_argv, boxString(str));
......@@ -422,9 +422,9 @@ void setupSys() {
sys_module->giveAttr("stdout", new BoxedFile(stdout, "<stdout>", "w"));
sys_module->giveAttr("stdin", new BoxedFile(stdin, "<stdin>", "r"));
sys_module->giveAttr("stderr", new BoxedFile(stderr, "<stderr>", "w"));
sys_module->giveAttr("__stdout__", sys_module->getattr("stdout"));
sys_module->giveAttr("__stdin__", sys_module->getattr("stdin"));
sys_module->giveAttr("__stderr__", sys_module->getattr("stderr"));
sys_module->giveAttr("__stdout__", sys_module->getattr(internStringMortal("stdout")));
sys_module->giveAttr("__stdin__", sys_module->getattr(internStringMortal("stdin")));
sys_module->giveAttr("__stderr__", sys_module->getattr(internStringMortal("stderr")));
sys_module->giveAttr(
"exc_info", new BoxedBuiltinFunctionOrMethod(boxRTFunction((void*)sysExcInfo, BOXED_TUPLE, 0), "exc_info"));
......
......@@ -201,9 +201,9 @@ void setupThread() {
"acquire", new BoxedFunction(boxRTFunction((void*)BoxedThreadLock::acquire, BOXED_BOOL, 2, 1, false, false),
{ boxInt(1) }));
thread_lock_cls->giveAttr("release", new BoxedFunction(boxRTFunction((void*)BoxedThreadLock::release, NONE, 1)));
thread_lock_cls->giveAttr("acquire_lock", thread_lock_cls->getattr("acquire"));
thread_lock_cls->giveAttr("release_lock", thread_lock_cls->getattr("release"));
thread_lock_cls->giveAttr("__enter__", thread_lock_cls->getattr("acquire"));
thread_lock_cls->giveAttr("acquire_lock", thread_lock_cls->getattr(internStringMortal("acquire")));
thread_lock_cls->giveAttr("release_lock", thread_lock_cls->getattr(internStringMortal("release")));
thread_lock_cls->giveAttr("__enter__", thread_lock_cls->getattr(internStringMortal("acquire")));
thread_lock_cls->giveAttr("__exit__", new BoxedFunction(boxRTFunction((void*)BoxedThreadLock::exit, NONE, 4)));
thread_lock_cls->freeze();
......
......@@ -215,7 +215,9 @@ extern "C" PyObject* PyObject_GetAttr(PyObject* o, PyObject* attr_name) noexcept
extern "C" PyObject* PyObject_GenericGetAttr(PyObject* o, PyObject* name) noexcept {
try {
Box* r = getattrInternalGeneric(o, static_cast<BoxedString*>(name)->data(), NULL, false, false, NULL, NULL);
BoxedString* s = static_cast<BoxedString*>(name);
internStringMortalInplace(s);
Box* r = getattrInternalGeneric(o, s, NULL, false, false, NULL, NULL);
if (!r)
PyErr_Format(PyExc_AttributeError, "'%.50s' object has no attribute '%.400s'", o->cls->tp_name,
PyString_AS_STRING(name));
......@@ -637,7 +639,7 @@ extern "C" int PyCallable_Check(PyObject* x) noexcept {
if (x == NULL)
return 0;
static const std::string call_attr("__call__");
static BoxedString* call_attr = internStringImmortal("__call__");
return typeLookup(x->cls, call_attr, NULL) != NULL;
}
......@@ -1417,7 +1419,8 @@ extern "C" char* PyModule_GetName(PyObject* m) noexcept {
PyErr_BadArgument();
return NULL;
}
if ((nameobj = m->getattr("__name__")) == NULL || !PyString_Check(nameobj)) {
static BoxedString* name_str = internStringImmortal("__name__");
if ((nameobj = m->getattr(name_str)) == NULL || !PyString_Check(nameobj)) {
PyErr_SetString(PyExc_SystemError, "nameless module");
return NULL;
}
......@@ -1431,7 +1434,8 @@ extern "C" char* PyModule_GetFilename(PyObject* m) noexcept {
PyErr_BadArgument();
return NULL;
}
if ((fileobj = m->getattr("__file__")) == NULL || !PyString_Check(fileobj)) {
static BoxedString* file_str = internStringImmortal("__file__");
if ((fileobj = m->getattr(file_str)) == NULL || !PyString_Check(fileobj)) {
PyErr_SetString(PyExc_SystemError, "module filename missing");
return NULL;
}
......
......@@ -28,7 +28,7 @@ extern "C" {
BoxedClass* classobj_cls, *instance_cls;
}
static Box* classLookup(BoxedClassobj* cls, llvm::StringRef attr) {
static Box* classLookup(BoxedClassobj* cls, BoxedString* attr) {
Box* r = cls->getattr(attr);
if (r)
return r;
......@@ -104,12 +104,14 @@ Box* classobjNew(Box* _cls, Box* _name, Box* _bases, Box** _args) {
for (auto& p : dict->d) {
RELEASE_ASSERT(p.first->cls == str_cls, "");
made->setattr(std::string(static_cast<BoxedString*>(p.first)->s()), p.second, NULL);
BoxedString* s = (BoxedString*)p.first;
internStringMortalInplace(s);
made->setattr(s, p.second, NULL);
}
// Note: make sure to do this after assigning the attrs, since it will overwrite any defined __name__
made->setattr("__name__", name, NULL);
made->setattr("__bases__", bases, NULL);
made->setattr(internStringMortal("__name__"), name, NULL);
made->setattr(internStringMortal("__bases__"), bases, NULL);
return made;
}
......@@ -126,7 +128,7 @@ Box* classobjCall(Box* _cls, Box* _args, Box* _kwargs) {
BoxedInstance* made = new BoxedInstance(cls);
static const std::string init_str("__init__");
static BoxedString* init_str = internStringImmortal("__init__");
Box* init_func = classLookup(cls, init_str);
if (init_func) {
......@@ -162,7 +164,7 @@ static Box* classobjGetattribute(Box* _cls, Box* _attr) {
}
}
Box* r = classLookup(cls, attr->s());
Box* r = classLookup(cls, attr);
if (!r)
raiseExcHelper(AttributeError, "class %s has no attribute '%s'", cls->name->data(), attr->data());
......@@ -210,7 +212,8 @@ static void classobjSetattr(Box* _cls, Box* _attr, Box* _value) {
const char* error_str = set_bases((PyClassObject*)cls, _value);
if (error_str && error_str[0] != '\0')
raiseExcHelper(TypeError, "%s", error_str);
cls->setattr("__bases__", _value, NULL);
static BoxedString* bases_str = internStringImmortal("__bases__");
cls->setattr(bases_str, _value, NULL);
return;
}
PyObject_GenericSetAttr(cls, _attr, _value);
......@@ -239,7 +242,8 @@ Box* classobjStr(Box* _obj) {
BoxedClassobj* cls = static_cast<BoxedClassobj*>(_obj);
Box* _mod = cls->getattr("__module__");
static BoxedString* module_str = internStringImmortal("__module__");
Box* _mod = cls->getattr(module_str);
RELEASE_ASSERT(_mod, "");
RELEASE_ASSERT(_mod->cls == str_cls, "");
return boxStringTwine(llvm::Twine(static_cast<BoxedString*>(_mod)->s()) + "." + cls->name->s());
......@@ -263,17 +267,17 @@ static Box* _instanceGetattribute(Box* _inst, Box* _attr, bool raise_on_missing)
return inst->inst_cls;
}
Box* r = inst->getattr(attr->s());
Box* r = inst->getattr(attr);
if (r)
return r;
r = classLookup(inst->inst_cls, attr->s());
r = classLookup(inst->inst_cls, attr);
if (r) {
return processDescriptor(r, inst, inst->inst_cls);
}
RELEASE_ASSERT(!r, "");
static const std::string getattr_str("__getattr__");
static BoxedString* getattr_str = internStringImmortal("__getattr__");
Box* getattr = classLookup(inst->inst_cls, getattr_str);
if (getattr) {
......@@ -323,7 +327,7 @@ Box* instanceSetattr(Box* _inst, Box* _attr, Box* value) {
}
}
static const std::string setattr_str("__setattr__");
static BoxedString* setattr_str = internStringImmortal("__setattr__");
Box* setattr = classLookup(inst->inst_cls, setattr_str);
if (setattr) {
......@@ -331,7 +335,7 @@ Box* instanceSetattr(Box* _inst, Box* _attr, Box* value) {
return runtimeCall(setattr, ArgPassSpec(2), _attr, value, NULL, NULL, NULL);
}
_inst->setattr(attr->s(), value, NULL);
_inst->setattr(attr, value, NULL);
return None;
}
......@@ -351,7 +355,7 @@ Box* instanceDelattr(Box* _inst, Box* _attr) {
raiseExcHelper(TypeError, "__class__ must be set to a class");
}
static const std::string delattr_str("__delattr__");
static BoxedString* delattr_str = internStringImmortal("__delattr__");
Box* delattr = classLookup(inst->inst_cls, delattr_str);
if (delattr) {
......@@ -359,7 +363,7 @@ Box* instanceDelattr(Box* _inst, Box* _attr) {
return runtimeCall(delattr, ArgPassSpec(1), _attr, NULL, NULL, NULL, NULL);
}
_inst->delattr(attr->s(), NULL);
_inst->delattr(attr, NULL);
return None;
}
......@@ -731,38 +735,44 @@ static PyObject* instance_index(PyObject* self) noexcept {
return res;
}
Box* _instanceBinary(Box* _inst, Box* other, const char* attr) {
static Box* _instanceBinary(Box* _inst, Box* other, BoxedString* attr) {
RELEASE_ASSERT(_inst->cls == instance_cls, "");
BoxedInstance* inst = static_cast<BoxedInstance*>(_inst);
Box* func = _instanceGetattribute(inst, boxString(attr), false);
Box* func = _instanceGetattribute(inst, attr, false);
if (!func)
return NotImplemented;
return runtimeCall(func, ArgPassSpec(1), other, NULL, NULL, NULL, NULL);
}
Box* instanceGt(Box* _inst, Box* other) {
return _instanceBinary(_inst, other, "__gt__");
static BoxedString* attr_str = internStringImmortal("__gt__");
return _instanceBinary(_inst, other, attr_str);
}
Box* instanceGe(Box* _inst, Box* other) {
return _instanceBinary(_inst, other, "__ge__");
static BoxedString* attr_str = internStringImmortal("__ge__");
return _instanceBinary(_inst, other, attr_str);
}
Box* instanceLt(Box* _inst, Box* other) {
return _instanceBinary(_inst, other, "__lt__");
static BoxedString* attr_str = internStringImmortal("__lt__");
return _instanceBinary(_inst, other, attr_str);
}
Box* instanceLe(Box* _inst, Box* other) {
return _instanceBinary(_inst, other, "__le__");
static BoxedString* attr_str = internStringImmortal("__le__");
return _instanceBinary(_inst, other, attr_str);
}
Box* instanceEq(Box* _inst, Box* other) {
return _instanceBinary(_inst, other, "__eq__");
static BoxedString* attr_str = internStringImmortal("__eq__");
return _instanceBinary(_inst, other, attr_str);
}
Box* instanceNe(Box* _inst, Box* other) {
return _instanceBinary(_inst, other, "__ne__");
static BoxedString* attr_str = internStringImmortal("__ne__");
return _instanceBinary(_inst, other, attr_str);
}
Box* instanceCall(Box* _inst, Box* _args, Box* _kwargs) {
......
......@@ -308,7 +308,7 @@ extern "C" int PyDict_Next(PyObject* op, Py_ssize_t* ppos, PyObject** pkey, PyOb
extern "C" PyObject* PyDict_GetItemString(PyObject* dict, const char* key) noexcept {
if (dict->cls == attrwrapper_cls)
return unwrapAttrWrapper(dict)->getattr(key);
return unwrapAttrWrapper(dict)->getattr(internStringMortal(key));
Box* key_s;
try {
......@@ -697,7 +697,7 @@ void setupDict() {
new BoxedFunction(boxRTFunction((void*)dictIterValues, typeFromClass(dict_iterator_cls), 1)));
dict_cls->giveAttr("keys", new BoxedFunction(boxRTFunction((void*)dictKeys, LIST, 1)));
dict_cls->giveAttr("iterkeys", dict_cls->getattr("__iter__"));
dict_cls->giveAttr("iterkeys", dict_cls->getattr(internStringMortal("__iter__")));
dict_cls->giveAttr("pop", new BoxedFunction(boxRTFunction((void*)dictPop, UNKNOWN, 3, 1, false, false), { NULL }));
dict_cls->giveAttr("popitem", new BoxedFunction(boxRTFunction((void*)dictPopitem, BOXED_TUPLE, 1)));
......
......@@ -1776,7 +1776,7 @@ void setupFile() {
file_cls->giveAttr("__enter__", new BoxedFunction(boxRTFunction((void*)fileEnter, typeFromClass(file_cls), 1)));
file_cls->giveAttr("__exit__", new BoxedFunction(boxRTFunction((void*)fileExit, UNKNOWN, 4)));
file_cls->giveAttr("__iter__", file_cls->getattr("__enter__"));
file_cls->giveAttr("__iter__", file_cls->getattr(internStringMortal("__enter__")));
file_cls->giveAttr("__hasnext__", new BoxedFunction(boxRTFunction((void*)fileIterHasNext, BOXED_BOOL, 1)));
file_cls->giveAttr("next", new BoxedFunction(boxRTFunction((void*)fileIterNext, STR, 1)));
......
......@@ -1447,7 +1447,7 @@ static PyMethodDef float_methods[] = { { "hex", (PyCFunction)float_hex, METH_NOA
void setupFloat() {
_addFunc("__add__", BOXED_FLOAT, (void*)floatAddFloat, (void*)floatAddInt, (void*)floatAdd);
float_cls->giveAttr("__radd__", float_cls->getattr("__add__"));
float_cls->giveAttr("__radd__", float_cls->getattr(internStringMortal("__add__")));
_addFunc("__div__", BOXED_FLOAT, (void*)floatDivFloat, (void*)floatDivInt, (void*)floatDiv);
_addFunc("__rdiv__", BOXED_FLOAT, (void*)floatRDivFloat, (void*)floatRDivInt, (void*)floatRDiv);
......@@ -1464,7 +1464,7 @@ void setupFloat() {
_addFunc("__mod__", BOXED_FLOAT, (void*)floatModFloat, (void*)floatModInt, (void*)floatMod);
_addFunc("__rmod__", BOXED_FLOAT, (void*)floatRModFloat, (void*)floatRModInt, (void*)floatRMod);
_addFunc("__mul__", BOXED_FLOAT, (void*)floatMulFloat, (void*)floatMulInt, (void*)floatMul);
float_cls->giveAttr("__rmul__", float_cls->getattr("__mul__"));
float_cls->giveAttr("__rmul__", float_cls->getattr(internStringMortal("__mul__")));
_addFuncPow("__pow__", BOXED_FLOAT, (void*)floatPowFloat, (void*)floatPowInt, (void*)floatPow);
_addFunc("__sub__", BOXED_FLOAT, (void*)floatSubFloat, (void*)floatSubInt, (void*)floatSub);
......
......@@ -32,7 +32,6 @@ namespace pyston {
static const std::string all_str("__all__");
static const std::string name_str("__name__");
static const std::string package_str("__package__");
static const std::string path_str("__path__");
static BoxedClass* null_importer_cls;
static void removeModule(const std::string& name) {
......@@ -67,6 +66,7 @@ static Box* createAndRunModule(const std::string& name, const std::string& fn, c
BoxedList* path_list = new BoxedList();
listAppendInternal(path_list, b_path);
static BoxedString* path_str = internStringImmortal("__path__");
module->setattr(path_str, path_list, NULL);
AST_Module* ast = caching_parse_file(fn.c_str());
......@@ -184,7 +184,7 @@ struct SearchResult {
};
SearchResult findModule(const std::string& name, const std::string& full_name, BoxedList* path_list) {
BoxedList* meta_path = static_cast<BoxedList*>(sys_module->getattr("meta_path"));
BoxedList* meta_path = static_cast<BoxedList*>(sys_module->getattr(internStringMortal("meta_path")));
if (!meta_path || meta_path->cls != list_cls)
raiseExcHelper(RuntimeError, "sys.meta_path must be a list of import hooks");
......@@ -208,11 +208,12 @@ SearchResult findModule(const std::string& name, const std::string& full_name, B
raiseExcHelper(RuntimeError, "sys.path must be a list of directory names");
}
BoxedList* path_hooks = static_cast<BoxedList*>(sys_module->getattr("path_hooks"));
BoxedList* path_hooks = static_cast<BoxedList*>(sys_module->getattr(internStringMortal("path_hooks")));
if (!path_hooks || path_hooks->cls != list_cls)
raiseExcHelper(RuntimeError, "sys.path_hooks must be a list of import hooks");
BoxedDict* path_importer_cache = static_cast<BoxedDict*>(sys_module->getattr("path_importer_cache"));
BoxedDict* path_importer_cache
= static_cast<BoxedDict*>(sys_module->getattr(internStringMortal("path_importer_cache")));
if (!path_importer_cache || path_importer_cache->cls != dict_cls)
raiseExcHelper(RuntimeError, "sys.path_importer_cache must be a dict");
......@@ -412,7 +413,7 @@ static Box* importSub(const std::string& name, const std::string& full_name, Box
}
if (parent_module && parent_module != None)
parent_module->setattr(name, module, NULL);
parent_module->setattr(internStringMortal(name), module, NULL);
return module;
}
......@@ -573,6 +574,7 @@ static void ensureFromlist(Box* module, Box* fromlist, std::string& buf, bool re
for (Box* _s : fromlist->pyElements()) {
RELEASE_ASSERT(PyString_Check(_s), "");
BoxedString* s = static_cast<BoxedString*>(_s);
internStringMortalInplace(s);
if (s->s()[0] == '*') {
// If __all__ contains a '*', just skip it:
......@@ -641,7 +643,8 @@ extern "C" PyObject* PyImport_ExecCodeModuleEx(char* name, PyObject* co, char* p
if (module == NULL)
return NULL;
module->setattr("__file__", boxString(pathname), NULL);
static BoxedString* file_str = internStringImmortal("__file__");
module->setattr(file_str, boxString(pathname), NULL);
AST_Module* ast = parse_string(code->data());
compileAndRunModule(ast, module);
return module;
......@@ -825,7 +828,8 @@ BoxedModule* importCExtension(const std::string& full_name, const std::string& l
assert(_m->cls == module_cls);
BoxedModule* m = static_cast<BoxedModule*>(_m);
m->setattr("__file__", boxString(path), NULL);
static BoxedString* file_str = internStringImmortal("__file__");
m->setattr(file_str, boxString(path), NULL);
return m;
}
......@@ -861,7 +865,7 @@ Box* impIsBuiltin(Box* _name) {
if (!PyString_Check(_name))
raiseExcHelper(TypeError, "must be string, not %s", getTypeName(_name));
BoxedTuple* builtin_modules = (BoxedTuple*)sys_module->getattr("builtin_module_names");
BoxedTuple* builtin_modules = (BoxedTuple*)sys_module->getattr(internStringMortal("builtin_module_names"));
RELEASE_ASSERT(PyTuple_Check(builtin_modules), "");
for (Box* m : builtin_modules->pyElements()) {
if (compare(m, _name, AST_TYPE::Eq) == True)
......
......@@ -1373,7 +1373,7 @@ void setupLong() {
"__new__", new BoxedFunction(boxRTFunction((void*)longNew, UNKNOWN, 3, 2, false, false), { boxInt(0), NULL }));
long_cls->giveAttr("__mul__", new BoxedFunction(boxRTFunction((void*)longMul, UNKNOWN, 2)));
long_cls->giveAttr("__rmul__", long_cls->getattr("__mul__"));
long_cls->giveAttr("__rmul__", long_cls->getattr(internStringMortal("__mul__")));
long_cls->giveAttr("__div__", new BoxedFunction(boxRTFunction((void*)longDiv, UNKNOWN, 2)));
long_cls->giveAttr("__rdiv__", new BoxedFunction(boxRTFunction((void*)longRdiv, UNKNOWN, 2)));
......@@ -1390,17 +1390,17 @@ void setupLong() {
long_cls->giveAttr("__rsub__", new BoxedFunction(boxRTFunction((void*)longRsub, UNKNOWN, 2)));
long_cls->giveAttr("__add__", new BoxedFunction(boxRTFunction((void*)longAdd, UNKNOWN, 2)));
long_cls->giveAttr("__radd__", long_cls->getattr("__add__"));
long_cls->giveAttr("__radd__", long_cls->getattr(internStringMortal("__add__")));
long_cls->giveAttr("__pow__",
new BoxedFunction(boxRTFunction((void*)longPow, UNKNOWN, 3, 1, false, false), { None }));
long_cls->giveAttr("__and__", new BoxedFunction(boxRTFunction((void*)longAnd, UNKNOWN, 2)));
long_cls->giveAttr("__rand__", long_cls->getattr("__and__"));
long_cls->giveAttr("__rand__", long_cls->getattr(internStringMortal("__and__")));
long_cls->giveAttr("__or__", new BoxedFunction(boxRTFunction((void*)longOr, UNKNOWN, 2)));
long_cls->giveAttr("__ror__", long_cls->getattr("__or__"));
long_cls->giveAttr("__ror__", long_cls->getattr(internStringMortal("__or__")));
long_cls->giveAttr("__xor__", new BoxedFunction(boxRTFunction((void*)longXor, UNKNOWN, 2)));
long_cls->giveAttr("__rxor__", long_cls->getattr("__xor__"));
long_cls->giveAttr("__rxor__", long_cls->getattr(internStringMortal("__xor__")));
// Note: CPython implements long comparisons using tp_compare
long_cls->tp_richcompare = long_richcompare;
......
This diff is collapsed.
......@@ -128,7 +128,7 @@ enum LookupScope {
extern "C" Box* callattrInternal(Box* obj, BoxedString* attr, LookupScope, CallRewriteArgs* rewrite_args,
ArgPassSpec argspec, Box* arg1, Box* arg2, Box* arg3, Box** args,
const std::vector<BoxedString*>* keyword_names);
extern "C" void delattr_internal(Box* obj, llvm::StringRef attr, bool allow_custom, DelattrRewriteArgs* rewrite_args);
extern "C" void delattr_internal(Box* obj, BoxedString* attr, bool allow_custom, DelattrRewriteArgs* rewrite_args);
struct CompareRewriteArgs;
Box* compareInternal(Box* lhs, Box* rhs, int op_type, CompareRewriteArgs* rewrite_args);
......@@ -139,12 +139,12 @@ Box* getattrInternal(Box* obj, BoxedString* attr, GetattrRewriteArgs* rewrite_ar
// This is the equivalent of PyObject_GenericGetAttr, which performs the default lookup rules for getattr() (check for
// data descriptor, check for instance attribute, check for non-data descriptor). It does not check for __getattr__ or
// __getattribute__.
Box* getattrInternalGeneric(Box* obj, llvm::StringRef attr, GetattrRewriteArgs* rewrite_args, bool cls_only,
bool for_call, Box** bind_obj_out, RewriterVar** r_bind_obj_out);
Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rewrite_args, bool cls_only, bool for_call,
Box** bind_obj_out, RewriterVar** r_bind_obj_out);
// This is the equivalent of _PyType_Lookup(), which calls Box::getattr() on each item in the object's MRO in the
// appropriate order. It does not do any descriptor logic.
Box* typeLookup(BoxedClass* cls, llvm::StringRef attr, GetattrRewriteArgs* rewrite_args);
Box* typeLookup(BoxedClass* cls, BoxedString* attr, GetattrRewriteArgs* rewrite_args);
extern "C" void raiseAttributeErrorStr(const char* typeName, llvm::StringRef attr) __attribute__((__noreturn__));
extern "C" void raiseAttributeError(Box* obj, llvm::StringRef attr) __attribute__((__noreturn__));
......
......@@ -490,7 +490,7 @@ void setupSet() {
set_cls->giveAttr("__new__",
new BoxedFunction(boxRTFunction((void*)setNew, UNKNOWN, 2, 1, false, false), { None }));
frozenset_cls->giveAttr("__new__", set_cls->getattr("__new__"));
frozenset_cls->giveAttr("__new__", set_cls->getattr(internStringMortal("__new__")));
Box* set_repr = new BoxedFunction(boxRTFunction((void*)setRepr, STR, 1));
set_cls->giveAttr("__repr__", set_repr);
......@@ -515,14 +515,14 @@ void setupSet() {
v_fu.push_back(FROZENSET);
v_fu.push_back(UNKNOWN);
auto add = [&](llvm::StringRef name, void* func) {
auto add = [&](const char* name, void* func) {
CLFunction* func_obj = createRTFunction(2, 0, false, false);
addRTFunction(func_obj, (void*)func, SET, v_ss);
addRTFunction(func_obj, (void*)func, SET, v_sf);
addRTFunction(func_obj, (void*)func, FROZENSET, v_fs);
addRTFunction(func_obj, (void*)func, FROZENSET, v_ff);
set_cls->giveAttr(name, new BoxedFunction(func_obj));
frozenset_cls->giveAttr(name, set_cls->getattr(name));
frozenset_cls->giveAttr(name, set_cls->getattr(internStringMortal(name)));
};
add("__or__", (void*)setOrSet);
......@@ -531,21 +531,21 @@ void setupSet() {
add("__and__", (void*)setAndSet);
set_cls->giveAttr("__iter__", new BoxedFunction(boxRTFunction((void*)setIter, typeFromClass(set_iterator_cls), 1)));
frozenset_cls->giveAttr("__iter__", set_cls->getattr("__iter__"));
frozenset_cls->giveAttr("__iter__", set_cls->getattr(internStringMortal("__iter__")));
set_cls->giveAttr("__len__", new BoxedFunction(boxRTFunction((void*)setLen, BOXED_INT, 1)));
frozenset_cls->giveAttr("__len__", set_cls->getattr("__len__"));
frozenset_cls->giveAttr("__len__", set_cls->getattr(internStringMortal("__len__")));
set_cls->giveAttr("__contains__", new BoxedFunction(boxRTFunction((void*)setContains, BOXED_BOOL, 2)));
frozenset_cls->giveAttr("__contains__", set_cls->getattr("__contains__"));
frozenset_cls->giveAttr("__contains__", set_cls->getattr(internStringMortal("__contains__")));
set_cls->giveAttr("__eq__", new BoxedFunction(boxRTFunction((void*)setEq, UNKNOWN, 2)));
frozenset_cls->giveAttr("__eq__", set_cls->getattr("__eq__"));
frozenset_cls->giveAttr("__eq__", set_cls->getattr(internStringMortal("__eq__")));
set_cls->giveAttr("__ne__", new BoxedFunction(boxRTFunction((void*)setNe, UNKNOWN, 2)));
frozenset_cls->giveAttr("__ne__", set_cls->getattr("__ne__"));
frozenset_cls->giveAttr("__ne__", set_cls->getattr(internStringMortal("__ne__")));
set_cls->giveAttr("__nonzero__", new BoxedFunction(boxRTFunction((void*)setNonzero, BOXED_BOOL, 1)));
frozenset_cls->giveAttr("__nonzero__", set_cls->getattr("__nonzero__"));
frozenset_cls->giveAttr("__nonzero__", set_cls->getattr(internStringMortal("__nonzero__")));
frozenset_cls->giveAttr("__hash__", new BoxedFunction(boxRTFunction((void*)setHash, BOXED_INT, 1)));
......@@ -556,12 +556,12 @@ void setupSet() {
set_cls->giveAttr("clear", new BoxedFunction(boxRTFunction((void*)setClear, NONE, 1)));
set_cls->giveAttr("update", new BoxedFunction(boxRTFunction((void*)setUpdate, NONE, 1, 0, true, false)));
set_cls->giveAttr("union", new BoxedFunction(boxRTFunction((void*)setUnion, UNKNOWN, 1, 0, true, false)));
frozenset_cls->giveAttr("union", set_cls->getattr("union"));
frozenset_cls->giveAttr("union", set_cls->getattr(internStringMortal("union")));
set_cls->giveAttr("intersection",
new BoxedFunction(boxRTFunction((void*)setIntersection, UNKNOWN, 1, 0, true, false)));
frozenset_cls->giveAttr("intersection", set_cls->getattr("intersection"));
frozenset_cls->giveAttr("intersection", set_cls->getattr(internStringMortal("intersection")));
set_cls->giveAttr("difference", new BoxedFunction(boxRTFunction((void*)setDifference, UNKNOWN, 1, 0, true, false)));
frozenset_cls->giveAttr("difference", set_cls->getattr("difference"));
frozenset_cls->giveAttr("difference", set_cls->getattr(internStringMortal("difference")));
set_cls->giveAttr("difference_update",
new BoxedFunction(boxRTFunction((void*)setDifferenceUpdate, UNKNOWN, 1, 0, true, false)));
set_cls->giveAttr("issubset", new BoxedFunction(boxRTFunction((void*)setIssubset, UNKNOWN, 2)));
......
......@@ -352,16 +352,20 @@ extern "C" Box* strAdd(BoxedString* lhs, Box* _rhs) {
return new (lhs->size() + rhs->size()) BoxedString(lhs->s(), rhs->s());
}
static llvm::StringMap<Box*> interned_strings;
static llvm::StringMap<BoxedString*> interned_strings;
static StatCounter num_interned_strings("num_interned_string");
extern "C" PyObject* PyString_InternFromString(const char* s) noexcept {
RELEASE_ASSERT(s, "");
return internStringImmortal(s);
}
BoxedString* internStringImmortal(llvm::StringRef s) {
auto& entry = interned_strings[s];
if (!entry) {
num_interned_strings.log();
entry = PyGC_AddRoot(boxString(s));
entry = (BoxedString*)PyGC_AddRoot(boxString(s));
// CPython returns mortal but in our current implementation they are inmortal
((BoxedString*)entry)->interned_state = SSTATE_INTERNED_IMMORTAL;
entry->interned_state = SSTATE_INTERNED_IMMORTAL;
}
return entry;
}
......@@ -383,7 +387,7 @@ extern "C" void PyString_InternInPlace(PyObject** p) noexcept {
*p = entry;
else {
num_interned_strings.log();
entry = PyGC_AddRoot(s);
entry = (BoxedString*)PyGC_AddRoot(s);
// CPython returns mortal but in our current implementation they are inmortal
s->interned_state = SSTATE_INTERNED_IMMORTAL;
......
......@@ -101,7 +101,7 @@ Box* superGetattribute(Box* _s, Box* _attr) {
continue;
res = PyDict_GetItem(dict, name);
#endif
res = tmp->getattr(std::string(attr->s()));
res = tmp->getattr(attr);
if (res != NULL) {
// Pyston change:
......@@ -128,7 +128,7 @@ Box* superGetattribute(Box* _s, Box* _attr) {
}
}
Box* r = typeLookup(s->cls, attr->s(), NULL);
Box* r = typeLookup(s->cls, attr, NULL);
// TODO implement this
RELEASE_ASSERT(r, "should call the equivalent of objectGetattr here");
return processDescriptor(r, s, s->cls);
......@@ -166,6 +166,7 @@ BoxedClass* supercheck(BoxedClass* type, Box* obj) {
return obj->cls;
}
static BoxedString* class_str = internStringImmortal("__class__");
Box* class_attr = obj->getattr(class_str);
if (class_attr && isSubclass(class_attr->cls, type_cls) && class_attr != obj->cls) {
Py_FatalError("warning: this path never tested"); // blindly copied from CPython
......
This diff is collapsed.
......@@ -329,17 +329,17 @@ private:
HiddenClass(HiddenClass* parent) : type(NORMAL), attr_offsets(), attrwrapper_offset(parent->attrwrapper_offset) {
assert(parent->type == NORMAL);
for (auto& p : parent->attr_offsets) {
this->attr_offsets.insert(&p);
this->attr_offsets.insert(p);
}
}
// These fields only make sense for NORMAL or SINGLETON hidden classes:
llvm::StringMap<int> attr_offsets;
llvm::DenseMap<BoxedString*, int> attr_offsets;
// If >= 0, is the offset where we stored an attrwrapper object
int attrwrapper_offset = -1;
// These are only for NORMAL hidden classes:
ContiguousMap<llvm::StringRef, HiddenClass*, llvm::StringMap<int>> children;
ContiguousMap<BoxedString*, HiddenClass*, llvm::DenseMap<BoxedString*, int>> children;
HiddenClass* attrwrapper_child = NULL;
// Only for SINGLETON hidden classes:
......@@ -370,6 +370,10 @@ public:
visitor->visitRange((void* const*)&children.vector()[0], (void* const*)&children.vector()[children.size()]);
if (attrwrapper_child)
visitor->visit(attrwrapper_child);
for (auto p : children)
visitor->visit(p.first);
for (auto p : attr_offsets)
visitor->visit(p.first);
}
// The total size of the attribute array. The slots in the attribute array may not correspond 1:1 to Python
......@@ -388,16 +392,16 @@ public:
// The mapping from string attribute names to attribute offsets. There may be other objects in the attributes
// array.
// Only valid for NORMAL or SINGLETON hidden classes
const llvm::StringMap<int>& getStrAttrOffsets() {
const llvm::DenseMap<BoxedString*, int>& getStrAttrOffsets() {
assert(type == NORMAL || type == SINGLETON);
return attr_offsets;
}
// Only valid for NORMAL hidden classes:
HiddenClass* getOrMakeChild(llvm::StringRef attr);
HiddenClass* getOrMakeChild(BoxedString* attr);
// Only valid for NORMAL or SINGLETON hidden classes:
int getOffset(llvm::StringRef attr) {
int getOffset(BoxedString* attr) {
assert(type == NORMAL || type == SINGLETON);
auto it = attr_offsets.find(attr);
if (it == attr_offsets.end())
......@@ -411,16 +415,16 @@ public:
}
// Only valid for SINGLETON hidden classes:
void appendAttribute(llvm::StringRef attr);
void appendAttribute(BoxedString* attr);
void appendAttrwrapper();
void delAttribute(llvm::StringRef attr);
void delAttribute(BoxedString* attr);
void addDependence(Rewriter* rewriter);
// Only valid for NORMAL hidden classes:
HiddenClass* getAttrwrapperChild();
// Only valid for NORMAL hidden classes:
HiddenClass* delAttrToMakeHC(llvm::StringRef attr);
HiddenClass* delAttrToMakeHC(BoxedString* attr);
};
class BoxedInt : public Box {
......@@ -829,7 +833,7 @@ public:
BoxedModule() {} // noop constructor to disable zero-initialization of cls
std::string name();
BoxedString* getStringConstant(llvm::StringRef ast_str);
BoxedString* getStringConstant(llvm::StringRef ast_str, bool intern = false);
Box* getUnicodeConstant(llvm::StringRef ast_str);
BoxedInt* getIntConstant(int64_t n);
BoxedFloat* getFloatConstant(double d);
......@@ -1002,7 +1006,7 @@ struct wrapper_def {
wrapperfunc wrapper; // "wrapper" that ends up getting called by the Python-visible WrapperDescr
const llvm::StringRef doc;
int flags;
// exists in CPython: PyObject *name_strobj
BoxedString* name_strobj;
};
class BoxedWrapperDescriptor : public Box {
......
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