ext/Internal/type-utils.cpp (106 lines of code) (raw):
// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com)
#include "type-utils.h"
#include "api-handle.h"
#include "globals.h"
#include "handles.h"
#include "runtime.h"
#include "symbols.h"
#include "thread.h"
namespace py {
static const SymbolId kParamsSelfValue[] = {ID(self), ID(value)};
static const SymbolId kParamsSelf[] = {ID(self)};
RawObject newExtCode(Thread* thread, const Object& name,
View<SymbolId> parameters, word flags,
BuiltinFunction function, void* slot_value) {
HandleScope scope(thread);
Runtime* runtime = thread->runtime();
Object code_code(&scope,
SmallInt::fromAlignedCPtr(bit_cast<void*>(function)));
Tuple empty_tuple(&scope, runtime->emptyTuple());
Object varnames_obj(&scope, *empty_tuple);
word num_parameters = parameters.length();
if (num_parameters > 0) {
MutableTuple varnames(&scope, runtime->newMutableTuple(num_parameters));
for (word i = 0; i < num_parameters; i++) {
varnames.atPut(i, runtime->symbols()->at(parameters.get(i)));
}
varnames_obj = varnames.becomeImmutable();
}
word argcount = num_parameters - ((flags & Code::Flags::kVarargs) != 0) -
((flags & Code::Flags::kVarkeyargs) != 0);
flags |= Code::Flags::kOptimized | Code::Flags::kNewlocals;
Object filename(&scope, Str::empty());
Object lnotab(&scope, Bytes::empty());
Object ptr(&scope, runtime->newIntFromCPtr(slot_value));
Tuple consts(&scope, runtime->newTupleWith1(ptr));
return runtime->newCode(argcount, /*posonlyargcount=*/num_parameters,
/*kwonlyargcount=*/0,
/*nlocals=*/num_parameters,
/*stacksize=*/0, flags, code_code, consts,
/*names=*/empty_tuple, varnames_obj,
/*freevars=*/empty_tuple, /*cellvars=*/empty_tuple,
filename, name, /*firstlineno=*/0, lnotab);
}
static ALIGN_16 RawObject getterWrapper(Thread* thread, Arguments args) {
PyGetSetDef* getset = reinterpret_cast<PyGetSetDef*>(getNativeFunc(thread));
getter func = getset->get;
void* closure = getset->closure;
PyObject* self = ApiHandle::newReference(thread->runtime(), args.get(0));
PyObject* result = (*func)(self, closure);
ApiHandle::fromPyObject(self)->decref();
return ApiHandle::checkFunctionResult(thread, result);
}
static RawObject getSetGetter(Thread* thread, const Object& name,
PyGetSetDef* def) {
if (def->get == nullptr) return NoneType::object();
HandleScope scope(thread);
Runtime* runtime = thread->runtime();
Code code(&scope, newExtCode(thread, name, kParamsSelf,
/*flags=*/0, getterWrapper,
reinterpret_cast<void*>(def)));
Object globals(&scope, NoneType::object());
Function function(&scope,
runtime->newFunctionWithCode(thread, name, code, globals));
if (def->doc != nullptr) {
Object doc(&scope, runtime->newStrFromCStr(def->doc));
function.setDoc(*doc);
}
return *function;
}
static ALIGN_16 RawObject setterWrapper(Thread* thread, Arguments args) {
PyGetSetDef* getset = reinterpret_cast<PyGetSetDef*>(getNativeFunc(thread));
setter func = getset->set;
void* closure = getset->closure;
Runtime* runtime = thread->runtime();
PyObject* self = ApiHandle::newReference(runtime, args.get(0));
PyObject* value = ApiHandle::newReference(runtime, args.get(1));
int result = func(self, value, closure);
ApiHandle::fromPyObject(self)->decref();
ApiHandle::fromPyObject(value)->decref();
if (result < 0) return Error::exception();
return NoneType::object();
}
static RawObject getSetSetter(Thread* thread, const Object& name,
PyGetSetDef* def) {
if (def->set == nullptr) return NoneType::object();
HandleScope scope(thread);
Runtime* runtime = thread->runtime();
Code code(&scope, newExtCode(thread, name, kParamsSelfValue,
/*flags=*/0, setterWrapper,
reinterpret_cast<void*>(def)));
Object globals(&scope, NoneType::object());
Function function(&scope,
runtime->newFunctionWithCode(thread, name, code, globals));
if (def->doc != nullptr) {
Object doc(&scope, runtime->newStrFromCStr(def->doc));
function.setDoc(*doc);
}
return *function;
}
RawObject newGetSet(Thread* thread, const Object& name, PyGetSetDef* def) {
HandleScope scope(thread);
Object getter(&scope, getSetGetter(thread, name, def));
Object setter(&scope, getSetSetter(thread, name, def));
Object none(&scope, NoneType::object());
return thread->runtime()->newProperty(getter, setter, none);
}
} // namespace py