Commit 50eb5bed authored by Chris Ramstad's avatar Chris Ramstad

Merge remote-tracking branch 'upstream/master'

parents d0863da3 e185374c
......@@ -477,7 +477,6 @@ void Assembler::cmp(Register reg1, Register reg2) {
reg1_idx -= 8;
}
if (reg2_idx >= 8) {
trap();
rex |= REX_B;
reg2_idx -= 8;
}
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
// Copyright (c) 2014 Dropbox, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef PYSTON_ASMWRITING_REWRITER2_H
#define PYSTON_ASMWRITING_REWRITER2_H
#include <memory>
#include "asm_writing/assembler.h"
#include "asm_writing/icinfo.h"
namespace pyston {
class TypeRecorder;
class ICInfo;
class ICSlotInfo;
class ICSlotRewrite;
class ICInvalidator;
class RewriterVar2;
struct Location {
public:
enum LocationType : uint8_t {
Register,
XMMRegister,
// Stack,
Scratch, // stack location, relative to the scratch start
// For representing constants that fit in 32-bits, that can be encoded as immediates
Constant,
AnyReg, // special type for use when specifying a location as a destination
None, // special type that represents the lack of a location, ex where a "ret void" gets returned
Uninitialized, // special type for an uninitialized (and invalid) location
};
public:
LocationType type;
union {
// only valid if type==Register; uses X86 numbering, not dwarf numbering.
// also valid if type==XMMRegister
int32_t regnum;
// only valid if type==Stack; this is the offset from bottom of the original frame.
// ie argument #6 will have a stack_offset of 0, #7 will have a stack offset of 8, etc
int32_t stack_offset;
// only valid if type == Scratch; offset from the beginning of the scratch area
int32_t scratch_offset;
// only valid if type==Constant
int32_t constant_val;
int32_t _data;
};
constexpr Location() : type(Uninitialized), _data(-1) {}
constexpr Location(const Location& r) : type(r.type), _data(r._data) {}
Location operator=(const Location& r) {
type = r.type;
_data = r._data;
return *this;
}
constexpr Location(LocationType type, int32_t data) : type(type), _data(data) {}
constexpr Location(assembler::Register reg) : type(Register), regnum(reg.regnum) {}
constexpr Location(assembler::XMMRegister reg) : type(XMMRegister), regnum(reg.regnum) {}
constexpr Location(assembler::GenericRegister reg)
: type(reg.type == assembler::GenericRegister::GP ? Register : reg.type == assembler::GenericRegister::XMM
? XMMRegister
: None),
regnum(reg.type == assembler::GenericRegister::GP ? reg.gp.regnum : reg.xmm.regnum) {}
assembler::Register asRegister() const;
assembler::XMMRegister asXMMRegister() const;
bool isClobberedByCall() const;
static constexpr Location any() { return Location(AnyReg, 0); }
static constexpr Location none() { return Location(None, 0); }
static Location forArg(int argnum);
bool operator==(const Location rhs) const { return this->asInt() == rhs.asInt(); }
bool operator!=(const Location rhs) const { return !(*this == rhs); }
uint64_t asInt() const { return (int)type + ((uint64_t)_data << 4); }
void dump() const;
};
static_assert(sizeof(Location) <= 8, "");
}
namespace std {
template <> struct hash<pyston::Location> {
size_t operator()(const pyston::Location p) const { return p.asInt(); }
};
}
namespace pyston {
class RewriterVarUsage2 {
public:
enum KillFlag {
NoKill,
Kill,
};
private:
RewriterVar2* var;
bool done_using;
RewriterVarUsage2();
RewriterVarUsage2(const RewriterVarUsage2&) = delete;
RewriterVarUsage2& operator=(const RewriterVarUsage2&) = delete;
void assertValid() {
assert(var);
assert(!done_using);
}
public:
// Creates a new Usage object of this var; ownership of
// one use of the var gets passed to this new object.
RewriterVarUsage2(RewriterVar2* var);
// Move constructor; don't need it for performance reasons, but because
// semantically we have to pass the ownership of the use.
RewriterVarUsage2(RewriterVarUsage2&& usage);
RewriterVarUsage2& operator=(RewriterVarUsage2&& usage);
static RewriterVarUsage2 empty();
#ifndef NDEBUG
~RewriterVarUsage2() {
if (!std::uncaught_exception())
assert(done_using);
}
#endif
void setDoneUsing();
// RewriterVarUsage2 addUse() { return var->addUse(); }
RewriterVarUsage2 addUse();
void addAttrGuard(int offset, uint64_t val);
RewriterVarUsage2 getAttr(int offset, KillFlag kill, Location loc = Location::any());
void setAttr(int offset, RewriterVarUsage2 other);
friend class Rewriter2;
};
class Rewriter2;
// This might make more sense as an inner class of Rewriter2, but
// you can't forward-declare that :/
class RewriterVar2 {
private:
Rewriter2* rewriter;
int num_uses;
std::unordered_set<Location> locations;
bool isInLocation(Location l);
// Gets a copy of this variable in a register, spilling/reloading if necessary.
// TODO have to be careful with the result since the interface doesn't guarantee
// that the register will still contain your value when you go to use it
assembler::Register getInReg(Location l = Location::any());
assembler::XMMRegister getInXMMReg(Location l = Location::any());
// If this is an immediate, try getting it as one
assembler::Immediate tryGetAsImmediate(bool* is_immediate);
void dump();
public:
void incUse();
void decUse();
RewriterVar2(Rewriter2* rewriter, Location location) : rewriter(rewriter), num_uses(1) {
assert(rewriter);
locations.insert(location);
}
friend class RewriterVarUsage2;
friend class Rewriter2;
};
class Rewriter2 : public ICSlotRewrite::CommitHook {
private:
std::unique_ptr<ICSlotRewrite> rewrite;
assembler::Assembler* assembler;
const Location return_location;
bool done_guarding;
std::vector<int> live_out_regs;
std::unordered_map<Location, RewriterVar2*> vars_by_location;
std::vector<RewriterVar2*> args;
std::vector<RewriterVar2*> live_outs;
Rewriter2(ICSlotRewrite* rewrite, int num_args, const std::vector<int>& live_outs);
void assertChangesOk() { assert(done_guarding); }
void kill(RewriterVar2* var);
// Allocates a register. dest must be of type Register or AnyReg
assembler::Register allocReg(Location dest);
// Allocates an 8-byte region in the scratch space
Location allocScratch();
assembler::Indirect indirectFor(Location l);
// Spills a specified register.
// If there are open callee-save registers, takes one of those, otherwise goes on the stack
void spillRegister(assembler::Register reg);
// Similar, but for XMM registers (always go on the stack)
void spillRegister(assembler::XMMRegister reg);
// Given an empty location, do the internal bookkeeping to create a new var out of that location.
RewriterVarUsage2 createNewVar(Location dest);
// Do the bookkeeping to say that var is now also in location l
void addLocationToVar(RewriterVar2* var, Location l);
// Do the bookkeeping to say that var is no longer in location l
void removeLocationFromVar(RewriterVar2* var, Location l);
void finishAssembly(int continue_offset) override;
public:
// This should be called exactly once for each argument
RewriterVarUsage2 getArg(int argnum);
Location getReturnDestination();
bool isDoneGuarding() { return done_guarding; }
void setDoneGuarding();
TypeRecorder* getTypeRecorder();
void trap();
RewriterVarUsage2 loadConst(int64_t val, Location loc = Location::any());
RewriterVarUsage2 call(bool can_call_into_python, void* func_addr, std::vector<RewriterVarUsage2> args);
RewriterVarUsage2 call(bool can_call_into_python, void* func_addr, RewriterVarUsage2 arg0);
RewriterVarUsage2 call(bool can_call_into_python, void* func_addr, RewriterVarUsage2 arg0, RewriterVarUsage2 arg1);
void commit();
void commitReturning(RewriterVarUsage2 rtn);
void addDependenceOn(ICInvalidator&);
static Rewriter2* createRewriter(void* rtn_addr, int num_args, const char* debug_name);
friend class RewriterVar2;
friend class RewriterVarUsage2;
};
}
#endif
......@@ -1812,7 +1812,7 @@ CFG* computeCFG(SourceInfo* source, std::vector<AST_stmt*> body) {
if (source->ast->type == AST_TYPE::ClassDef) {
// A classdef always starts with "__module__ = __name__"
Box* module_name = source->parent_module->getattr("__name__", NULL, NULL);
Box* module_name = source->parent_module->getattr("__name__", NULL);
assert(module_name->cls == str_cls);
AST_Assign* module_assign = new AST_Assign();
module_assign->targets.push_back(makeName("__module__", AST_TYPE::Store));
......
......@@ -54,6 +54,11 @@ struct ArgPassSpec {
int totalPassed() { return num_args + num_keywords + (has_starargs ? 1 : 0) + (has_kwargs ? 1 : 0); }
uintptr_t asInt() const { return *reinterpret_cast<const uintptr_t*>(this); }
void dump() {
printf("(has_starargs=%s, has_kwargs=%s, num_keywords=%d, num_args=%d)\n", has_starargs ? "true" : "false",
has_kwargs ? "true" : "false", num_keywords, num_args);
}
};
static_assert(sizeof(ArgPassSpec) <= sizeof(void*), "ArgPassSpec doesn't fit in register!");
......@@ -371,10 +376,9 @@ private:
};
class SetattrRewriteArgs2;
class SetattrRewriteArgs;
class GetattrRewriteArgs;
class GetattrRewriteArgs2;
class DelattrRewriteArgs2;
class DelattrRewriteArgs;
struct HCAttrs {
public:
......@@ -398,15 +402,15 @@ public:
HCAttrs* getAttrsPtr();
void setattr(const std::string& attr, Box* val, SetattrRewriteArgs2* rewrite_args2);
void setattr(const std::string& attr, Box* val, SetattrRewriteArgs* rewrite_args);
void giveAttr(const std::string& attr, Box* val) {
assert(this->getattr(attr) == NULL);
this->setattr(attr, val, NULL);
}
Box* getattr(const std::string& attr, GetattrRewriteArgs* rewrite_args, GetattrRewriteArgs2* rewrite_args2);
Box* getattr(const std::string& attr) { return getattr(attr, NULL, NULL); }
void delattr(const std::string& attr, DelattrRewriteArgs2* rewrite_args);
Box* getattr(const std::string& attr, GetattrRewriteArgs* rewrite_args);
Box* getattr(const std::string& attr) { return getattr(attr, NULL); }
void delattr(const std::string& attr, DelattrRewriteArgs* rewrite_args);
};
......
......@@ -56,7 +56,7 @@ extern "C" Box* dir(Box* obj) {
}
// If __dict__ is present use its keys and add the reset below
Box* obj_dict = getattr_internal(obj, "__dict__", false, true, nullptr, nullptr);
Box* obj_dict = getattr_internal(obj, "__dict__", false, true, nullptr);
if (obj_dict && obj_dict->cls == dict_cls) {
result = new BoxedList();
for (auto& kv : static_cast<BoxedDict*>(obj_dict)->d) {
......@@ -332,7 +332,7 @@ Box* getattrFunc(Box* obj, Box* _str, Box* default_value) {
}
BoxedString* str = static_cast<BoxedString*>(_str);
Box* rtn = getattr_internal(obj, str->s, true, true, NULL, NULL);
Box* rtn = getattr_internal(obj, str->s, true, true, NULL);
if (!rtn) {
if (default_value)
......@@ -351,7 +351,7 @@ Box* hasattr(Box* obj, Box* _str) {
}
BoxedString* str = static_cast<BoxedString*>(_str);
Box* attr = getattr_internal(obj, str->s, true, true, NULL, NULL);
Box* attr = getattr_internal(obj, str->s, true, true, NULL);
Box* rtn = attr ? True : False;
return rtn;
......
This diff is collapsed.
......@@ -84,10 +84,10 @@ extern "C" BoxedClosure* createClosure(BoxedClosure* parent_closure);
class BinopRewriteArgs;
extern "C" Box* binopInternal(Box* lhs, Box* rhs, int op_type, bool inplace, BinopRewriteArgs* rewrite_args);
class CallRewriteArgs;
Box* typeCallInternal(BoxedFunction* f, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2,
Box* arg3, Box** args, const std::vector<const std::string*>* keyword_names);
class CallRewriteArgs;
enum LookupScope {
CLASS_ONLY = 1,
INST_ONLY = 2,
......@@ -97,14 +97,13 @@ extern "C" Box* callattrInternal(Box* obj, const std::string* attr, LookupScope,
ArgPassSpec argspec, Box* arg1, Box* arg2, Box* arg3, Box** args,
const std::vector<const std::string*>* keyword_names);
extern "C" void delattr_internal(Box* obj, const std::string& attr, bool allow_custom,
DelattrRewriteArgs2* rewrite_args);
DelattrRewriteArgs* rewrite_args);
struct CompareRewriteArgs;
Box* compareInternal(Box* lhs, Box* rhs, int op_type, CompareRewriteArgs* rewrite_args);
Box* getattr_internal(Box* obj, const std::string& attr, bool check_cls, bool allow_custom,
GetattrRewriteArgs* rewrite_args, GetattrRewriteArgs2* rewrite_args2);
GetattrRewriteArgs* rewrite_args);
Box* typeLookup(BoxedClass* cls, const std::string& attr, GetattrRewriteArgs* rewrite_args,
GetattrRewriteArgs2* rewrite_args2);
Box* typeLookup(BoxedClass* cls, const std::string& attr, GetattrRewriteArgs* rewrite_args);
extern "C" void raiseAttributeErrorStr(const char* typeName, const char* attr) __attribute__((__noreturn__));
extern "C" void raiseAttributeError(Box* obj, const char* attr) __attribute__((__noreturn__));
......
......@@ -84,7 +84,7 @@ extern "C" BoxedFunction::BoxedFunction(CLFunction* f)
// this->giveAttr("__name__", boxString(&f->source->ast->name));
this->giveAttr("__name__", boxString(f->source->getName()));
Box* modname = f->source->parent_module->getattr("__name__", NULL, NULL);
Box* modname = f->source->parent_module->getattr("__name__", NULL);
this->giveAttr("__module__", modname);
}
......@@ -110,7 +110,7 @@ extern "C" BoxedFunction::BoxedFunction(CLFunction* f, std::initializer_list<Box
// this->giveAttr("__name__", boxString(&f->source->ast->name));
this->giveAttr("__name__", boxString(f->source->getName()));
Box* modname = f->source->parent_module->getattr("__name__", NULL, NULL);
Box* modname = f->source->parent_module->getattr("__name__", NULL);
this->giveAttr("__module__", modname);
}
......@@ -516,7 +516,7 @@ Box* objectNew(BoxedClass* cls, BoxedTuple* args) {
if (args->elts.size() != 0) {
// TODO slow
if (typeLookup(cls, "__init__", NULL, NULL) == typeLookup(object_cls, "__init__", NULL, NULL))
if (typeLookup(cls, "__init__", NULL) == typeLookup(object_cls, "__init__", NULL))
raiseExcHelper(TypeError, "object.__new__() takes no parameters");
}
......
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