runtime/runtime.h (598 lines of code) (raw):
/* Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com) */
#pragma once
#include "bytecode.h"
#include "capi.h"
#include "handles.h"
#include "heap.h"
#include "interpreter-gen.h"
#include "interpreter.h"
#include "layout.h"
#include "modules.h"
#include "mutex.h"
#include "symbols.h"
#include "view.h"
namespace py {
class AttributeInfo;
class Heap;
class RawObject;
class RawTuple;
class PointerVisitor;
class Thread;
enum LayoutTypeTransition {
kFrom = 0,
kTo = 1,
kResult = 2,
kTransitionSize,
};
using AtExitFn = void (*)(void*);
using DictEq = RawObject (*)(Thread*, RawObject, RawObject);
enum class ReadOnly : bool {
ReadWrite,
ReadOnly,
};
struct RandomState {
uint64_t state[2];
uint64_t siphash24_secret;
uint64_t extra_secret[3];
};
RandomState randomState();
RandomState randomStateFromSeed(uint64_t seed);
class Runtime {
public:
Runtime(word heap_size, Interpreter* interpreter, RandomState random_seed);
~Runtime();
// Completes the runtime initialization. Should be called after
// `initializeSys`.
RawObject initialize(Thread* thread);
bool initialized() { return initialized_; }
// TODO(T75349221): Make createXXX functions private or remove them
RawObject createLargeInt(word num_digits);
RawObject createLargeStr(word length);
// Allocate memory for JITed code.
bool allocateForMachineCode(word size, uword* address_out);
RawObject newBoundMethod(const Object& function, const Object& self);
RawObject newBytearray();
RawObject newBytearrayIterator(Thread* thread, const Bytearray& bytearray);
RawObject newBytes(word length, byte fill);
RawObject newBytesWithAll(View<byte> array);
RawObject newBytesIterator(Thread* thread, const Bytes& bytes);
RawObject newTraceback();
RawObject newType();
RawObject newTypeWithMetaclass(LayoutId metaclass_id);
RawObject newTypeProxy(const Type& type);
RawObject newCell();
RawObject newClassMethod();
// TODO(T55871582): Remove code paths that can raise from the Runtime
RawObject newCode(word argcount, word posonlyargcount, word kwonlyargcount,
word nlocals, word stacksize, word flags,
const Object& code, const Object& consts,
const Object& names, const Object& varnames,
const Object& freevars, const Object& cellvars,
const Object& filename, const Object& name,
word firstlineno, const Object& lnotab);
RawObject newBuiltinCode(word argcount, word posonlyargcount,
word kwonlyargcount, word flags,
BuiltinFunction function,
const Object& parameter_names,
const Object& name_str);
RawObject newComplex(double real, double imag);
RawObject newCoroutine();
RawObject newDeque();
RawObject newDequeIterator(const Deque& deque, word index);
RawObject newDequeReverseIterator(const Deque& deque, word index);
RawObject newDict();
RawObject newDictWithSize(word initial_size);
RawObject newDictItemIterator(Thread* thread, const Dict& dict);
RawObject newDictItems(Thread* thread, const Dict& dict);
RawObject newDictKeyIterator(Thread* thread, const Dict& dict);
RawObject newDictKeys(Thread* thread, const Dict& dict);
RawObject newDictValueIterator(Thread* thread, const Dict& dict);
RawObject newDictValues(Thread* thread, const Dict& dict);
RawObject newFloat(double value);
RawObject newSet();
RawObject emptyFrozenSet();
RawObject newFrozenSet();
RawObject newFunction(Thread* thread, const Object& name, const Object& code,
word flags, word argcount, word total_args,
word total_vars, const Object& stacksize_or_builtin,
Function::Entry entry, Function::Entry entry_kw,
Function::Entry entry_ex);
RawObject newFunctionWithCode(Thread* thread, const Object& qualname,
const Code& code, const Object& module_obj);
RawObject newExceptionState();
RawObject newFrameProxy(Thread* thread, const Object& function,
const Object& lasti);
RawObject newGenerator();
RawObject newGeneratorFrame(const Function& function);
RawObject newInstance(const Layout& layout);
RawObject newInstanceWithSize(LayoutId layout_id, word object_size);
// Create a new Int from a signed value.
RawObject newInt(word value);
// Create a new Int from an unsigned value.
RawObject newIntFromUnsigned(uword value);
RawObject newLargeIntFromWord(word value);
// Create a new LargeInt from a sequence of digits, which will be interpreted
// as a signed, two's-complement number. The digits must satisfy the
// invariants listed on the LargeInt class.
RawObject newLargeIntWithDigits(View<uword> digits);
RawObject newLayout(LayoutId id);
RawObject newList();
RawObject newListIterator(const Object& list);
RawObject newSeqIterator(const Object& sequence);
RawObject newSlotDescriptor(const Type& type, const Object& name);
// Create a new MemoryView object. Initializes the view format to "B".
RawObject newMemoryView(Thread* thread, const Object& obj,
const Object& buffer, word length,
ReadOnly read_only);
// Create a new MemoryView object from a C pointer. Initializes the view
// format to "B".
RawObject newMemoryViewFromCPtr(Thread* thread, const Object& obj, void* ptr,
word length, ReadOnly read_only);
// Create a new Mmap object.
RawObject newMmap();
RawObject newModule(const Object& name);
RawObject newModuleProxy(const Module& module);
RawObject newMutableBytesUninitialized(word size);
RawObject newMutableBytesZeroed(word size);
// Returns an Int that stores the numerical address of the pointer.
RawObject newIntFromCPtr(void* ptr);
// Returns the singleton empty mutablebytes. Guaranteed to not allocate.
RawObject emptyMutableBytes();
// Returns the singleton empty slice. Guaranteed to not allocate.
RawObject emptySlice();
// Returns the singleton empty tuple. Guaranteed to not allocate.
RawObject emptyTuple();
// Return a new, zero-initialized, mutable tuple of the given length.
RawObject newMutableTuple(word length);
// Return a new tuple containing the specified arguments.
RawObject newTupleWith1(const Object& item1);
RawObject newTupleWith2(const Object& item1, const Object& item2);
RawObject newTupleWith3(const Object& item1, const Object& item2,
const Object& item3);
RawObject newTupleWith4(const Object& item1, const Object& item2,
const Object& item3, const Object& item4);
RawObject newTupleWithN(word num_items, const Object* item1, ...);
RawObject newPointer(void* cptr, word length);
RawObject newProperty(const Object& getter, const Object& setter,
const Object& deleter);
RawObject newRange(const Object& start, const Object& stop,
const Object& step);
RawObject newLongRangeIterator(const Int& start, const Int& stop,
const Int& step);
RawObject newRangeIterator(word start, word step, word length);
RawObject newSetIterator(const Object& set);
RawObject newSlice(const Object& start, const Object& stop,
const Object& step);
RawObject newStaticMethod();
RawObject newStrArray();
RawObject newStrFromCStr(const char* c_str);
RawObject strFromStrArray(const StrArray& array);
// Creates a new string constructed from a format and a list of arguments,
// similar to sprintf.
// %c formats an ASCII character
// %w formats a word
// %C formats a unicode code point
// %S formats a Str object
// %T gets the type name of an object and formats that
// %Y formats a SymbolId
RawObject newStrFromFmt(const char* fmt, ...);
RawObject newStrFromFmtV(Thread* thread, const char* fmt, va_list args);
RawObject newStrFromUTF32(View<int32_t> code_units);
RawObject newStrWithAll(View<byte> code_units);
RawObject newStrIterator(const Object& str);
RawObject newSuper();
RawObject newTupleIterator(const Tuple& tuple, word length);
// Constructors from _contextvars
RawObject newContext(const Dict& data);
RawObject newContextVar(const Str& name, const Object& default_value);
RawObject newToken(const Context& ctx, const ContextVar& ctx_var,
const Object& old_value);
void processCallbacks();
void processFinalizers();
RawObject strConcat(Thread* thread, const Str& left, const Str& right);
RawObject strJoin(Thread* thread, const Str& sep, const Tuple& items,
word allocated);
// Creates a new Str containing `str` repeated `count` times.
RawObject strRepeat(Thread* thread, const Str& str, word count);
RawObject strSlice(Thread* thread, const Str& str, word start, word stop,
word step);
RawObject newValueCell();
RawObject newWeakLink(Thread* thread, const Object& referent,
const Object& prev, const Object& next);
RawObject newWeakRef(Thread* thread, const Object& referent);
RawObject ellipsis() { return ellipsis_; }
word builtinsModuleId() { return builtins_module_id_; }
void setBuiltinsModuleId(word builtins_module_id) {
builtins_module_id_ = builtins_module_id;
}
RawObject moduleDunderGetattribute() { return module_dunder_getattribute_; }
RawObject objectDunderClass() { return object_dunder_class_; }
RawObject objectDunderEq() { return object_dunder_eq_; }
RawObject objectDunderGetattribute() { return object_dunder_getattribute_; }
RawObject objectDunderHash() { return object_dunder_hash_; }
RawObject objectDunderInit() { return object_dunder_init_; }
RawObject objectDunderNew() { return object_dunder_new_; }
RawObject objectDunderSetattr() { return object_dunder_setattr_; }
RawObject strDunderEq() { return str_dunder_eq_; }
RawObject strDunderHash() { return str_dunder_hash_; }
RawValueCell sysStderr() { return ValueCell::cast(sys_stderr_); }
RawValueCell sysStdin() { return ValueCell::cast(sys_stdin_); }
RawValueCell sysStdout() { return ValueCell::cast(sys_stdout_); }
RawObject typeDunderGetattribute() { return type_dunder_getattribute_; }
RawObject profilingNewThread() { return profiling_new_thread_; }
RawObject profilingCall() { return profiling_call_; }
RawObject profilingReturn() { return profiling_return_; }
void setProfiling(const Object& new_thread_func, const Object& call_func,
const Object& return_func);
void reinitInterpreter();
void builtinTypeCreated(Thread* thread, const Type& type);
void cacheBuildClass(Thread* thread, const Module& builtins);
void cacheSysInstances(Thread* thread, const Module& sys);
static RawObject internStr(Thread* thread, const Object& str);
static RawObject internStrFromAll(Thread* thread, View<byte> bytes);
static RawObject internStrFromCStr(Thread* thread, const char* c_str);
static RawObject internLargeStr(Thread* thread, const Object& str);
// This function should only be used for `CHECK()`/`DCHECK()`. It is as slow
// as the whole `internStr()` operation and will always return true for small
// strings, even when the user did not explicitly intern them.
static bool isInternedStr(Thread* thread, const Object& str);
enum class CompactionDestination { kImmortalPartition, kNewPartition };
void collectGarbage() {
collectGarbageInto(CompactionDestination::kNewPartition);
}
void immortalizeCurrentHeapObjects() {
collectGarbageInto(CompactionDestination::kImmortalPartition);
}
void collectGarbageInto(CompactionDestination destination);
// Creates a new thread and adds it to the runtime.
Thread* newThread();
// Removes the specified thread from the runtime and deletes it.
void deleteThread(Thread* thread);
// Compute hash value suitable for `RawObject::operator==` (aka `a is b`)
// equality tests.
word hash(RawObject object);
// Compute hash value for objects with byte payload. This is a helper to
// implement `xxxHash()` functions.
word valueHash(RawObject object);
word identityHash(RawObject object);
word bytesHash(View<byte> array);
uword random();
Heap* heap() { return &heap_; }
Interpreter* interpreter() { return interpreter_.get(); }
RawObject* finalizableReferences();
void visitRootsWithoutApiHandles(PointerVisitor* visitor);
RawObject findModule(const Object& name);
RawObject findModuleById(SymbolId name);
RawObject lookupNameInModule(Thread* thread, SymbolId module_name,
SymbolId name);
// Write the traceback to the given file object. If success, return None.
// Else, return Error.
RawObject printTraceback(Thread* thread, word fd);
// Returns the implicit bases -- (object,) -- for a new class.
RawObject implicitBases();
// Gets the internal notion of type, rather than the user-visible type.
RawObject concreteTypeAt(LayoutId layout_id);
inline RawObject concreteTypeOf(RawObject object) {
return concreteTypeAt(object.layoutId());
}
// Sets the internal type for layouts with a different describedType.
void setLargeBytesType(const Type& type);
void setLargeIntType(const Type& type);
void setLargeStrType(const Type& type);
void setSmallBytesType(const Type& type);
void setSmallIntType(const Type& type);
void setSmallStrType(const Type& type);
RawType typeOf(RawObject object) {
return Layout::cast(layoutOf(object)).describedType().rawCast<RawType>();
}
RawObject typeAt(LayoutId layout_id);
RawObject layoutAt(LayoutId layout_id) {
DCHECK(layout_id != LayoutId::kError, "Error has no Layout");
return Tuple::cast(layouts_).at(static_cast<word>(layout_id));
}
void layoutAtPut(LayoutId layout_id, RawObject object);
// Get layout for `layout_id` and attempt not to crash for invalid ids. This
// is for debug dumpers. Do not use for other purposes!
RawObject layoutAtSafe(LayoutId layout_id);
RawObject layoutOf(RawObject obj) {
if (obj.isHeapObject()) {
return layoutAt(RawHeapObject::cast(obj).header().layoutId());
}
return layoutAt(
static_cast<LayoutId>(obj.raw() & Object::kImmediateTagMask));
}
// Raw access to the MutableTuple of Layouts. Intended only for use by the GC.
RawObject layouts() { return layouts_; }
void setLayouts(RawObject layouts) { layouts_ = layouts; }
// Raw access to the Tuple of layout transitions while setting __class__.
// Intended only for use by the GC.
RawObject layoutTypeTransitions() { return layout_type_transitions_; }
void setLayoutTypeTransitions(RawObject value) {
layout_type_transitions_ = value;
}
void layoutSetTupleOverflow(RawLayout layout);
LayoutId reserveLayoutId(Thread* thread);
word reserveModuleId();
RawObject buildClass() { return build_class_; }
RawObject displayHook() { return display_hook_; }
// Returns modules mapping (aka `sys.modules`).
RawObject modules() { return modules_; }
char* capiStateData() { return capi_state_; }
void setAtExit(AtExitFn func, void* ctx) {
DCHECK(at_exit_ == nullptr,
"setAtExit should not override existing at_exit function");
at_exit_ = func;
at_exit_context_ = ctx;
}
void callAtExit() {
if (at_exit_ == nullptr) return;
at_exit_(at_exit_context_);
at_exit_ = nullptr;
at_exit_context_ = nullptr;
}
Symbols* symbols() { return symbols_; }
// Provides a growth strategy for mutable sequences. Grows by a factor of 1.5,
// scaling up to the requested capacity if the initial factor is insufficient.
// Always grows the sequence.
static word newCapacity(word curr_capacity, word min_capacity);
// Ensures that the byte array has at least the desired capacity.
// Allocates if the existing capacity is insufficient.
void bytearrayEnsureCapacity(Thread* thread, const Bytearray& array,
word min_capacity);
// Appends multiple bytes to the end of the array.
void bytearrayExtend(Thread* thread, const Bytearray& array, View<byte> view);
void bytearrayIadd(Thread* thread, const Bytearray& array, const Bytes& bytes,
word length);
// Returns a new Bytes containing the elements of `left` and `right`.
RawObject bytesConcat(Thread* thread, const Bytes& left, const Bytes& right);
// Returns a copy of a bytes object
RawObject bytesCopy(Thread* thread, const Bytes& src);
// Makes a new copy of the `original` bytes with the specified `size`.
// If the new length is less than the old length, truncate the bytes to fit.
// If the new length is greater than the old length, pad with trailing zeros.
RawObject bytesCopyWithSize(Thread* thread, const Bytes& original,
word new_length);
// Checks whether the specified range of `bytes` ends with the given `suffix`.
// Returns `Bool::trueObj()` if the suffix matches, else `Bool::falseObj()`.
RawObject bytesEndsWith(const Bytes& bytes, word bytes_len,
const Bytes& suffix, word suffix_len, word start,
word end);
// Returns a new Bytes from the first `length` int-like elements in the tuple.
RawObject bytesFromTuple(Thread* thread, const Tuple& items, word length);
// Creates a new Bytes or MutableBytes (depending on `source`'s type)
// containing the first `length` bytes of the `source` repeated `count` times.
// Specifies `length` explicitly to allow for Bytearrays with extra allocated
// space.
RawObject bytesRepeat(Thread* thread, const Bytes& source, word length,
word count);
// Replace the occurances of old_bytes with new_bytes in src up to max_count.
// If no instances of old_bytes exist, old_bytes == new_bytes, or max_count is
// zero, return src unmodified.
// NOTE: a negative max_count value is used to signify that all instaces of
// old_bytes should be replaced
RawObject bytesReplace(Thread* thread, const Bytes& src,
const Bytes& old_bytes, word old_len,
const Bytes& new_bytes, word new_len, word max_count);
// Returns a new Bytes that contains the specified slice of bytes.
RawObject bytesSlice(Thread* thread, const Bytes& bytes, word start,
word stop, word step);
// Checks whether the specified range of bytes starts with the given prefix.
// Returns Bool::trueObj() if the suffix matches, else Bool::falseObj().
RawObject bytesStartsWith(const Bytes& bytes, word bytes_len,
const Bytes& prefix, word prefix_len, word start,
word end);
// Returns a new Bytes or MutableBytes copy of `bytes` with all of
// the bytes in `del` removed, where the remaining bytes are mapped using
// `table`.
RawObject bytesTranslate(Thread* thread, const Bytes& bytes, word length,
const Bytes& table, word table_len, const Bytes& del,
word del_len);
// Returns the repr-string for a byteslike object. The caller must provide the
// size of the resulting string, accounting for escaping, and the correct
// delimiter character, which is either a single- or double-quote.
RawObject byteslikeRepr(Thread* thread, const Byteslike& byteslike,
word result_length, byte delimiter);
// Ensures that the list has at least the desired capacity.
// Allocates if the existing capacity is insufficient.
void listEnsureCapacity(Thread* thread, const List& list, word min_capacity);
// Appends an element to the end of the list.
void listAdd(Thread* thread, const List& list, const Object& value);
// Create a MutableBytes object from a given Bytes
RawObject mutableBytesFromBytes(Thread* thread, const Bytes& bytes);
RawObject mutableBytesWith(word length, byte value);
RawObject tupleSubseq(Thread* thread, const Tuple& tuple, word start,
word length);
// Creates a layout that is a subclass of a built-in class and zero or more
// additional built-in attributes.
RawObject layoutCreateSubclassWithBuiltins(Thread* thread,
LayoutId subclass_id,
LayoutId superclass_id,
View<BuiltinAttribute> attributes,
word size);
RawObject layoutNewAttribute(const Object& name, AttributeInfo info);
// Performs a simple scan of the bytecode and collects all attributes that
// are set via `self.<attribute> =` into attributes.
void collectAttributes(const Code& code, const Dict& attributes);
// Returns type's __init__ method, or None
RawObject classConstructor(const Type& type);
// Implements `receiver.name`
NODISCARD RawObject attributeAt(Thread* thread, const Object& receiver,
const Object& name);
NODISCARD RawObject attributeAtSetLocation(Thread* thread,
const Object& receiver,
const Object& name,
LoadAttrKind* kind,
Object* location_out);
NODISCARD RawObject attributeAtById(Thread* thread, const Object& receiver,
SymbolId id);
NODISCARD RawObject attributeAtByCStr(Thread* thread, const Object& receiver,
const char* name);
// Implements `del receiver.name`
NODISCARD RawObject attributeDel(Thread* thread, const Object& receiver,
const Object& name);
// Looks up the named attribute in the layout.
//
// If the attribute is found this returns true and sets info.
// Returns false otherwise.
static bool layoutFindAttribute(RawLayout layout, const Object& name,
AttributeInfo* info);
// Creates a copy of a layout with a new layout id.
//
// The new layout shares the in-object and overflow attributes and contains
// no outgoing edges.
RawObject layoutCreateCopy(Thread* thread, const Layout& layout);
// Add the attribute to the overflow array.
//
// This returns a new layout by either following a pre-existing edge or
// adding one.
RawObject layoutAddAttribute(Thread* thread, const Layout& layout,
const Object& name, word flags,
AttributeInfo* info);
// Create a new tuple for the name, info pair and return a new tuple
// containing entries + entry.
RawObject layoutAddAttributeEntry(Thread* thread, const Tuple& entries,
const Object& name, AttributeInfo info);
// Change the described type of a layout. Follow an edge if it exists, or
// create a new layout otherwise.
// This is used when assigning to __class__ on an instance.
RawObject layoutSetDescribedType(Thread* thread, const Layout& from,
const Type& to);
// Delete the named attribute from the layout.
//
// If the attribute exists, this returns a new layout by either following
// a pre-existing edge or adding one.
//
// If the attribute doesn't exist, Error::object() is returned.
RawObject layoutDeleteAttribute(Thread* thread, const Layout& layout,
const Object& name, AttributeInfo info);
// Return the dict overflow-only layout derived from `type`, for instances
// having `num_in_object_attr` in-object attributes.
RawObject typeDictOnlyLayout(Thread* thread, const Type& type,
word num_in_object_attr);
// For commonly-subclassed builtin types, define isInstanceOfFoo(RawObject)
// that does a check including subclasses (unlike RawObject::isFoo(), which
// only gets exact types).
#define DEFINE_IS_INSTANCE(ty) \
bool isInstanceOf##ty(RawObject obj) { \
if (obj.is##ty()) return true; \
return typeOf(obj).rawCast<RawType>().builtinBase() == LayoutId::k##ty; \
}
DEFINE_IS_INSTANCE(Array)
DEFINE_IS_INSTANCE(BufferedReader)
DEFINE_IS_INSTANCE(BufferedWriter)
DEFINE_IS_INSTANCE(Bytearray)
DEFINE_IS_INSTANCE(Bytes)
DEFINE_IS_INSTANCE(BytesIO)
DEFINE_IS_INSTANCE(ClassMethod)
DEFINE_IS_INSTANCE(Complex)
DEFINE_IS_INSTANCE(Deque)
DEFINE_IS_INSTANCE(Dict)
DEFINE_IS_INSTANCE(FileIO)
DEFINE_IS_INSTANCE(Float)
DEFINE_IS_INSTANCE(FrozenSet)
DEFINE_IS_INSTANCE(ImportError)
DEFINE_IS_INSTANCE(Int)
DEFINE_IS_INSTANCE(List)
DEFINE_IS_INSTANCE(Mmap)
DEFINE_IS_INSTANCE(Module)
DEFINE_IS_INSTANCE(Property)
DEFINE_IS_INSTANCE(Set)
DEFINE_IS_INSTANCE(StaticMethod)
DEFINE_IS_INSTANCE(StopIteration)
DEFINE_IS_INSTANCE(Str)
DEFINE_IS_INSTANCE(StringIO)
DEFINE_IS_INSTANCE(SystemExit)
DEFINE_IS_INSTANCE(TextIOWrapper)
DEFINE_IS_INSTANCE(Tuple)
DEFINE_IS_INSTANCE(Type)
DEFINE_IS_INSTANCE(UnicodeDecodeError)
DEFINE_IS_INSTANCE(UnicodeEncodeError)
DEFINE_IS_INSTANCE(UnicodeError)
DEFINE_IS_INSTANCE(UnicodeTranslateError)
DEFINE_IS_INSTANCE(WeakRef)
#undef DEFINE_IS_INSTANCE
// User-defined subclasses of immediate types have no corresponding LayoutId,
// so we detect them by looking for an object that is a subclass of a
// particular immediate type but not exactly that type.
#define DEFINE_IS_USER_INSTANCE(ty) \
bool isInstanceOfUser##ty##Base(RawObject obj) { \
return !obj.is##ty() && \
typeOf(obj).rawCast<RawType>().builtinBase() == LayoutId::k##ty; \
}
DEFINE_IS_USER_INSTANCE(Bytes)
DEFINE_IS_USER_INSTANCE(Complex)
DEFINE_IS_USER_INSTANCE(Float)
DEFINE_IS_USER_INSTANCE(Int)
DEFINE_IS_USER_INSTANCE(Str)
DEFINE_IS_USER_INSTANCE(Tuple)
DEFINE_IS_USER_INSTANCE(WeakRef)
#undef DEFINE_IS_USER_INSTANCE
bool isInstanceOfNativeProxy(RawObject obj) {
// Note that this reports true when the object can be used safely via
// `RawNativeProxy` or assigned to a `NativeProxy` handle. The function
// name is required for `Hanlde<>` to work. It is misleading in that we
// consider native proxy to be more of a property of the type than is
// orthogonal to the subtyping relationships.
return typeOf(obj).rawCast<RawType>().hasNativeData();
}
// BaseException must be handled specially because it has builtin subclasses
// that are visible to managed code.
bool isInstanceOfBaseException(RawObject obj) {
return typeOf(obj).rawCast<RawType>().isBaseExceptionSubclass();
}
// SetBase must also be handled specially because many builtin functions
// accept set or frozenset, despite them not having a common ancestor.
bool isInstanceOfSetBase(RawObject instance) {
if (instance.isSetBase()) {
return true;
}
LayoutId builtin_base = typeOf(instance).rawCast<RawType>().builtinBase();
return builtin_base == LayoutId::kSet ||
builtin_base == LayoutId::kFrozenSet;
}
bool isInstanceOfUnicodeErrorBase(RawObject instance) {
return isInstanceOfUnicodeDecodeError(instance) ||
isInstanceOfUnicodeEncodeError(instance) ||
isInstanceOfUnicodeTranslateError(instance);
}
inline bool isByteslike(RawObject obj) {
return isInstanceOfBytes(obj) || isInstanceOfBytearray(obj) ||
obj.isMemoryView() || obj.isArray();
}
// Clear the allocated memory from all extension related objects
void deallocExtensions();
// Initial data of the set.
static const int kSetGrowthFactor = 2;
static const int kInitialSetCapacity = 8;
static const word kInitialInternSetCapacity = 8192;
static const word kInitialLayoutTupleCapacity = 1024;
void setRandomState(RandomState random_state) {
random_state_ = random_state;
}
// Returns whether object's class provides a __call__ method
//
// If its type defines a __call__, it is also callable (even if __call__ is
// not actually callable).
// Note that this does not include __call__ defined on the particular
// instance, only __call__ defined on the type.
bool isCallable(Thread* thread, const Object& obj);
// Returns whether object's class provides a __delete__ method
bool isDeleteDescriptor(Thread* thread, const Object& object);
// Returns whether object's class provides a __next__ method
bool isIterator(Thread* thread, const Object& obj);
// Return whether object's class supports the sequence protocol
bool isSequence(Thread* thread, const Object& obj);
// Return whether object's class provides a __getitem__ method
bool isMapping(Thread* thread, const Object& obj);
// Converts bytes object into an int object. The conversion is performed
// with the specified endianness. `is_signed` specifies whether the highest
// bit is considered a sign.
RawObject bytesToInt(Thread* thread, const Bytes& bytes, endian endianness,
bool is_signed);
static uint64_t hashWithKey(const Bytes& bytes, uint64_t key);
// Returns the sum of `left` and `right`.
RawObject intAdd(Thread* thread, const Int& left, const Int& right);
// Returns the result of bitwise AND of the arguments
RawObject intBinaryAnd(Thread* thread, const Int& left, const Int& right);
// Returns the result of bitwise left shift of the arguments
RawObject intBinaryLshift(Thread* thread, const Int& num, const Int& amount);
// Returns the result of bitwise logical OR of the arguments
RawObject intBinaryOr(Thread* thread, const Int& left, const Int& right);
// Returns the result of bitwise right shift of `num` by `shift`.
RawObject intBinaryRshift(Thread* thread, const Int& num, const Int& amount);
// Returns the result of bitwise XOR of the arguments
RawObject intBinaryXor(Thread* thread, const Int& left, const Int& right);
// Computes the floor of the quotient of dividing `left` by `right` and
// `left` modulo `right` so that `left = quotient * right + modulo`.
// Note that this is different from C++ division (which truncates).
// Writes the results to the handles pointed to by `quotient` or `modulo`.
// It is allowed to specify a nullptr for any of them.
// Returns true on success, false on division by zero.
bool intDivideModulo(Thread* thread, const Int& dividend, const Int& divisor,
Object* quotient, Object* modulo);
// Returns a copy of `value` with all bits flipped.
RawObject intInvert(Thread* thread, const Int& value);
// Returns the product of `left` and `right`.
RawObject intMultiply(Thread* thread, const Int& left, const Int& right);
// Returns `0 - value`.
RawObject intNegate(Thread* thread, const Int& value);
// Returns the result of subtracting `right` from `left`.
RawObject intSubtract(Thread* thread, const Int& left, const Int& right);
// Converts `num` into a bytes object with the given length. This function
// expects the length to be big enough to hold the number and does not check
// for overflow.
RawObject intToBytes(Thread* thread, const Int& num, word length,
endian endianness);
// Given a possibly invalid LargeInt remove redundant sign- and
// zero-extension and convert to a SmallInt when possible.
RawObject normalizeLargeInt(Thread* thread, const LargeInt& large_int);
// Replace the occurences of oldstr get replaced for newstr in src up
// to maxcount. If no replacement happens, returns src itself, unmodified.
RawObject strReplace(Thread* thread, const Str& src, const Str& oldstr,
const Str& newstr, word count);
void strArrayAddASCII(Thread* thread, const StrArray& array, byte code_point);
void strArrayAddCodePoint(Thread* thread, const StrArray& array,
int32_t code_point);
void strArrayAddStr(Thread* thread, const StrArray& array, const Str& str);
void strArrayAddStrArray(Thread* thread, const StrArray& array,
const StrArray& str);
// Ensures that the str array has at least the desired capacity.
// Allocates if the existing capacity is insufficient.
void strArrayEnsureCapacity(Thread* thread, const StrArray& array,
word min_capacity);
static word nextModuleIndex();
static int heapOffset() { return OFFSETOF(Runtime, heap_); }
static int layoutsOffset() { return OFFSETOF(Runtime, layouts_); }
// Equivalent to `o0 is o1 or o0 == o1` optimized for LargeStr, SmallStr and
// SmallInt objects.
static RawObject objectEquals(Thread* thread, RawObject o0, RawObject o1);
// The exec_prefix is a directory prefix where platform-dependent Python files
// are installed (e.g. compiled .so files)
static wchar_t* execPrefix() { return exec_prefix_; }
static void setExecPrefix(const wchar_t* exec_prefix);
// Getter/setter for the module search path.
static wchar_t* moduleSearchPath() { return module_search_path_; }
static void setModuleSearchPath(const wchar_t* module_search_path);
// The prefix is a directory prefix where platform-independent Python files
// are installed (e.g. .py library files)
static wchar_t* prefix() { return prefix_; }
static void setPrefix(const wchar_t* prefix);
static wchar_t* programName();
static void setProgramName(const wchar_t* program_name);
const byte* hashSecret(size_t size);
// Sets up the signal handlers.
void initializeSignals(Thread* thread, const Module& under_signal);
void finalizeSignals(Thread* thread);
RawObject handlePendingSignals(Thread* thread);
void setPendingSignal(Thread* thread, int signum);
RawObject signalCallback(word signum);
RawObject setSignalCallback(word signum, const Object& callback);
bool isFinalizing() { return is_finalizing_; }
Thread* mainThread() { return main_thread_; }
void populateEntryAsm(const Function& function);
private:
Runtime(word heap_size);
void initializeHeapTypes(Thread* thread);
void initializeInterned(Thread* thread);
void initializeJITState();
void initializeLayouts();
void initializeModules(Thread* thread);
void initializePrimitiveInstances();
void initializeSymbols(Thread* thread);
void initializeTypes(Thread* thread);
void internSetGrow(Thread* thread);
void visitRuntimeRoots(PointerVisitor* visitor);
void visitThreadRoots(PointerVisitor* visitor);
word siphash24(View<byte> array);
RawObject createLargeBytes(word length);
RawObject createMutableBytes(word length);
// Appends attribute entries for fixed attributes to an array of in-object
// attribute entries starting at a specific index. Useful for constructing
// the in-object attributes array for built-in classes with fixed attributes.
void appendBuiltinAttributes(Thread* thread,
View<BuiltinAttribute> attributes,
const MutableTuple& dst, word start_index);
// Joins the type's name and attribute's name to produce a qualname
RawObject newQualname(Thread* thread, const Type& type, SymbolId name);
static word immediateHash(RawObject object);
// Clear all active handle scopes
void clearHandleScopes();
// Clear the allocated memory from all extension related objects
void freeApiHandles();
bool is_finalizing_ = false;
// The size newCapacity grows to if array is empty. Must be large enough to
// guarantee a LargeBytes/LargeStr for Bytearray/StrArray.
static const int kInitialEnsuredCapacity = kWordSize * 2;
static_assert(kInitialEnsuredCapacity > SmallStr::kMaxLength,
"array must be backed by a heap type");
Heap heap_;
std::unique_ptr<Interpreter> interpreter_;
// List of native instances which can be finalizable through tp_dealloc
RawObject finalizable_references_ = NoneType::object();
// A MutableTuple of Layout objects, indexed by layout id.
RawObject layouts_ = NoneType::object();
// The number of layout objects in layouts_.
word num_layouts_ = 0;
// A Tuple of (A, B, C) triples representing transitions from a layout A to a
// class B, resulting in final cached layout C.
RawObject layout_type_transitions_ = NoneType::object();
// The last module ID given out.
word max_module_id_ = 0;
// The ID of builtins module.
// TODO(T64005113): Remove this once we mark individual functions.
word builtins_module_id_ = -1;
// Internal-only types, for which the Layout has a different described type
RawObject large_bytes_ = NoneType::object();
RawObject large_int_ = NoneType::object();
RawObject large_str_ = NoneType::object();
RawObject small_bytes_ = NoneType::object();
RawObject small_int_ = NoneType::object();
RawObject small_str_ = NoneType::object();
// Cached instances
RawObject build_class_ = NoneType::object();
RawObject display_hook_ = NoneType::object();
RawObject ellipsis_ = NoneType::object();
RawObject empty_frozen_set_ = NoneType::object();
RawObject empty_mutable_bytes_ = NoneType::object();
RawObject empty_slice_ = NoneType::object();
RawObject empty_tuple_ = NoneType::object();
RawObject module_dunder_getattribute_ = NoneType::object();
RawObject object_dunder_class_ = NoneType::object();
RawObject object_dunder_eq_ = NoneType::object();
RawObject object_dunder_getattribute_ = NoneType::object();
RawObject object_dunder_hash_ = NoneType::object();
RawObject object_dunder_init_ = NoneType::object();
RawObject object_dunder_new_ = NoneType::object();
RawObject object_dunder_setattr_ = NoneType::object();
RawObject str_dunder_eq_ = NoneType::object();
RawObject str_dunder_hash_ = NoneType::object();
RawObject sys_stderr_ = NoneType::object();
RawObject sys_stdin_ = NoneType::object();
RawObject sys_stdout_ = NoneType::object();
RawObject type_dunder_getattribute_ = NoneType::object();
RawObject profiling_new_thread_ = NoneType::object();
RawObject profiling_call_ = NoneType::object();
RawObject profiling_return_ = NoneType::object();
// Interned strings
RawObject interned_ = NoneType::object();
word interned_remaining_ = 0;
// Modules
RawObject modules_ = NoneType::object();
// C-API State
char capi_state_[kCAPIStateSize];
// Weak reference callback list
RawObject callbacks_ = NoneType::object();
// Quick check if any signals have been tripped.
volatile bool is_signal_pending_ = false;
// Tuple mapping each signal to either SIG_DFL, SIG_IGN, None,
// or a Python object to be called when handling the signal.
RawObject signal_callbacks_ = NoneType::object();
void* signal_stack_ = nullptr;
// File descriptor for writing when a signal is received.
int wakeup_fd_ = -1;
Thread* main_thread_ = nullptr;
Mutex threads_mutex_;
RandomState random_state_;
Symbols* symbols_;
// atexit thunk (to be passed into pylifecycle and called with atexit module)
AtExitFn at_exit_ = nullptr;
void* at_exit_context_ = nullptr;
bool initialized_ = false;
// Non-moving memory for JIT compiled functions.
Space* machine_code_ = nullptr;
static word next_module_index_;
static wchar_t exec_prefix_[];
static wchar_t module_search_path_[];
static wchar_t prefix_[];
static wchar_t program_name_[];
DISALLOW_COPY_AND_ASSIGN(Runtime);
};
inline RawObject Runtime::emptyMutableBytes() { return empty_mutable_bytes_; }
inline RawObject Runtime::emptySlice() { return empty_slice_; }
inline RawObject Runtime::emptyTuple() { return empty_tuple_; }
inline RawObject Runtime::internStr(Thread* thread, const Object& str) {
if (str.isSmallStr()) {
return *str;
}
return internLargeStr(thread, str);
}
inline RawObject Runtime::newInt(word value) {
if (SmallInt::isValid(value)) {
return SmallInt::fromWord(value);
}
return newLargeIntFromWord(value);
}
inline RawObject Runtime::newMutableBytesUninitialized(word size) {
return newMutableBytesZeroed(size);
}
} // namespace py