this repo has no description
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com)
2#include "module-builtins.h"
3
4#include "attributedict.h"
5#include "builtins.h"
6#include "capi.h"
7#include "dict-builtins.h"
8#include "frame.h"
9#include "globals.h"
10#include "ic.h"
11#include "object-builtins.h"
12#include "objects.h"
13#include "runtime.h"
14#include "thread.h"
15#include "type-builtins.h"
16
17namespace py {
18
19RawObject moduleAt(const Module& module, const Object& name) {
20 RawObject result = NoneType::object();
21 if (!attributeAt(*module, *name, &result)) return Error::notFound();
22 return result;
23}
24
25RawObject moduleAtById(Thread* thread, const Module& module, SymbolId id) {
26 RawObject name = thread->runtime()->symbols()->at(id);
27 RawObject result = NoneType::object();
28 if (!attributeAt(*module, name, &result)) return Error::notFound();
29 return result;
30}
31
32RawObject moduleDeleteAttribute(Thread* thread, const Module& module,
33 const Object& name) {
34 // Check for a descriptor with __delete__
35 HandleScope scope(thread);
36 Runtime* runtime = thread->runtime();
37 Type type(&scope, runtime->typeOf(*module));
38 Object type_attr(&scope, typeLookupInMro(thread, *type, *name));
39 if (!type_attr.isErrorNotFound() &&
40 runtime->isDeleteDescriptor(thread, type_attr)) {
41 return Interpreter::callDescriptorDelete(thread, type_attr, module);
42 }
43
44 // No delete descriptor found, attempt to delete from the module dict
45 if (moduleRemove(thread, module, name).isError()) {
46 Str module_name(&scope, module.name());
47 return thread->raiseWithFmt(LayoutId::kAttributeError,
48 "module '%S' has no attribute '%S'",
49 &module_name, &name);
50 }
51
52 return NoneType::object();
53}
54
55RawObject moduleValueCellAtById(Thread* thread, const Module& module,
56 SymbolId id) {
57 RawObject name = thread->runtime()->symbols()->at(id);
58 RawObject result = NoneType::object();
59 if (!attributeValueCellAt(*module, name, &result) ||
60 ValueCell::cast(result).isPlaceholder()) {
61 return Error::notFound();
62 }
63 return result;
64}
65
66RawObject moduleValueCellAt(Thread*, const Module& module, const Object& name) {
67 RawObject result = NoneType::object();
68 if (!attributeValueCellAt(*module, *name, &result) ||
69 ValueCell::cast(result).isPlaceholder()) {
70 return Error::notFound();
71 }
72 return result;
73}
74
75static RawObject moduleValueCellAtPut(Thread* thread, const Module& module,
76 const Object& name, const Object& value) {
77 RawObject module_result = NoneType::object();
78 if (attributeValueCellAt(*module, *name, &module_result) &&
79 ValueCell::cast(module_result).isPlaceholder()) {
80 // A builtin entry is cached under the same name, so invalidate its caches.
81 HandleScope scope(thread);
82 Object builtins(&scope, moduleAtById(thread, module, ID(__builtins__)));
83 Module builtins_module(&scope, *module);
84 if (builtins.isModuleProxy()) {
85 builtins = ModuleProxy::cast(*builtins).module();
86 }
87 if (thread->runtime()->isInstanceOfModule(*builtins)) {
88 builtins_module = *builtins;
89 RawObject builtins_result = NoneType::object();
90 if (attributeValueCellAt(*builtins_module, *name, &builtins_result)) {
91 ValueCell builtins_value_cell(&scope, builtins_result);
92 if (!builtins_value_cell.isPlaceholder()) {
93 DCHECK(!builtins_value_cell.dependencyLink().isNoneType(),
94 "the builtin valuecell must have a dependent");
95 icInvalidateGlobalVar(thread, builtins_value_cell);
96 }
97 }
98 }
99 }
100 return attributeAtPut(thread, module, name, value);
101}
102
103RawObject moduleAtPut(Thread* thread, const Module& module, const Object& name,
104 const Object& value) {
105 return moduleValueCellAtPut(thread, module, name, value);
106}
107
108RawObject moduleAtPutById(Thread* thread, const Module& module, SymbolId id,
109 const Object& value) {
110 HandleScope scope(thread);
111 Object name(&scope, thread->runtime()->symbols()->at(id));
112 return moduleValueCellAtPut(thread, module, name, value);
113}
114
115RawObject moduleAtPutByCStr(Thread* thread, const Module& module,
116 const char* name_cstr, const Object& value) {
117 HandleScope scope(thread);
118 Object name(&scope, Runtime::internStrFromCStr(thread, name_cstr));
119 return moduleValueCellAtPut(thread, module, name, value);
120}
121
122RawObject moduleKeys(Thread* thread, const Module& module) {
123 return attributeKeys(thread, module);
124}
125
126word moduleLen(Thread* thread, const Module& module) {
127 return attributeLen(thread, module);
128}
129
130RawObject moduleRaiseAttributeError(Thread* thread, const Module& module,
131 const Object& name) {
132 HandleScope scope(thread);
133 Object module_name(&scope, module.name());
134 if (!thread->runtime()->isInstanceOfStr(*module_name)) {
135 return thread->raiseWithFmt(LayoutId::kAttributeError,
136 "module has no attribute '%S'", &name);
137 }
138 return thread->raiseWithFmt(LayoutId::kAttributeError,
139 "module '%S' has no attribute '%S'", &module_name,
140 &name);
141}
142
143RawObject moduleRemove(Thread* thread, const Module& module,
144 const Object& name) {
145 DCHECK(Runtime::isInternedStr(thread, name), "expected interned str");
146 HandleScope scope(thread);
147 word index;
148 Object value_cell_obj(&scope, NoneType::object());
149 if (!attributeFindForRemoval(module, name, &value_cell_obj, &index)) {
150 return Error::notFound();
151 }
152 attributeRemove(module, index);
153 ValueCell value_cell(&scope, *value_cell_obj);
154 icInvalidateGlobalVar(thread, value_cell);
155 if (value_cell.isPlaceholder()) return Error::notFound();
156 Object previous_value(&scope, value_cell.value());
157 value_cell.makePlaceholder();
158 return *previous_value;
159}
160
161RawObject moduleValues(Thread* thread, const Module& module) {
162 return attributeValues(thread, module);
163}
164
165RawObject moduleGetAttribute(Thread* thread, const Module& module,
166 const Object& name) {
167 return moduleGetAttributeSetLocation(thread, module, name, nullptr);
168}
169
170RawObject moduleGetAttributeSetLocation(Thread* thread, const Module& module,
171 const Object& name,
172 Object* location_out) {
173 HandleScope scope(thread);
174 Runtime* runtime = thread->runtime();
175 Type module_type(&scope, runtime->typeOf(*module));
176 // TODO(T66579052): Skip type lookups for `module` type when `name` doesn't
177 // start with "__".
178 Object attr(&scope, typeLookupInMro(thread, *module_type, *name));
179 if (!attr.isError()) {
180 Type attr_type(&scope, runtime->typeOf(*attr));
181 if (typeIsDataDescriptor(*attr_type)) {
182 return Interpreter::callDescriptorGet(thread, attr, module, module_type);
183 }
184 }
185
186 Object result(&scope, moduleValueCellAt(thread, module, name));
187 DCHECK(result.isValueCell() || result.isErrorNotFound(),
188 "result must be a value cell or not found");
189 if (!result.isErrorNotFound() && !ValueCell::cast(*result).isPlaceholder()) {
190 if (location_out != nullptr) {
191 *location_out = *result;
192 }
193 return ValueCell::cast(*result).value();
194 }
195
196 if (!attr.isError()) {
197 Type attr_type(&scope, runtime->typeOf(*attr));
198 if (typeIsNonDataDescriptor(*attr_type)) {
199 return Interpreter::callDescriptorGet(thread, attr, module, module_type);
200 }
201 return *attr;
202 }
203
204 Object dunder_getattr(&scope, moduleAtById(thread, module, ID(__getattr__)));
205 if (!dunder_getattr.isErrorNotFound()) {
206 return Interpreter::call1(thread, dunder_getattr, name);
207 }
208
209 return Error::notFound();
210}
211
212RawObject moduleSetAttr(Thread* thread, const Module& module,
213 const Object& name, const Object& value) {
214 moduleAtPut(thread, module, name, value);
215 return NoneType::object();
216}
217
218RawObject moduleInit(Thread* thread, const Module& module, const Object& name) {
219 HandleScope scope(thread);
220 Runtime* runtime = thread->runtime();
221 module.setModuleProxy(runtime->newModuleProxy(module));
222 if (name.isStr()) {
223 module.setName(*name);
224 }
225 module.setDef(runtime->newIntFromCPtr(nullptr));
226 module.setState(runtime->newIntFromCPtr(nullptr));
227 moduleAtPutById(thread, module, ID(__name__), name);
228
229 Object none(&scope, NoneType::object());
230 moduleAtPutById(thread, module, ID(__doc__), none);
231 moduleAtPutById(thread, module, ID(__package__), none);
232 moduleAtPutById(thread, module, ID(__loader__), none);
233 moduleAtPutById(thread, module, ID(__spec__), none);
234 return NoneType::object();
235}
236
237static const BuiltinAttribute kModuleAttributes[] = {
238 {ID(_module__attributes), RawModule::kAttributesOffset,
239 AttributeFlags::kHidden},
240 {ID(_module__attributes_remaining), RawModule::kAttributesRemainingOffset,
241 AttributeFlags::kHidden},
242 {ID(_module__name), RawModule::kNameOffset, AttributeFlags::kHidden},
243 {ID(_module__def), RawModule::kDefOffset, AttributeFlags::kHidden},
244 {ID(_module__state), RawModule::kStateOffset, AttributeFlags::kHidden},
245 {ID(_module__proxy), RawModule::kModuleProxyOffset,
246 AttributeFlags::kHidden},
247};
248
249void initializeModuleType(Thread* thread) {
250 HandleScope scope(thread);
251 Type type(&scope, addBuiltinType(thread, ID(module), LayoutId::kModule,
252 /*superclass_id=*/LayoutId::kObject,
253 kModuleAttributes, Module::kSize,
254 /*basetype=*/true));
255 word flags = static_cast<word>(type.flags());
256 flags |= RawType::Flag::kHasCustomDict;
257 type.setFlags(static_cast<Type::Flag>(flags));
258 Runtime* runtime = thread->runtime();
259 Object object_type(&scope, runtime->typeAt(LayoutId::kObject));
260 type.setMro(runtime->newTupleWith2(type, object_type));
261}
262
263RawObject METH(module, __delattr__)(Thread* thread, Arguments args) {
264 HandleScope scope(thread);
265 Object self_obj(&scope, args.get(0));
266 if (!thread->runtime()->isInstanceOfModule(*self_obj)) {
267 return thread->raiseRequiresType(self_obj, ID(module));
268 }
269 Module self(&scope, *self_obj);
270 Object name(&scope, args.get(1));
271 name = attributeName(thread, name);
272 if (name.isErrorException()) return *name;
273 return moduleDeleteAttribute(thread, self, name);
274}
275
276RawObject METH(module, __getattribute__)(Thread* thread, Arguments args) {
277 HandleScope scope(thread);
278 Object self_obj(&scope, args.get(0));
279 Runtime* runtime = thread->runtime();
280 if (!runtime->isInstanceOfModule(*self_obj)) {
281 return thread->raiseRequiresType(self_obj, ID(module));
282 }
283 Module self(&scope, *self_obj);
284 Object name(&scope, args.get(1));
285 name = attributeName(thread, name);
286 if (name.isErrorException()) return *name;
287 Object result(&scope, moduleGetAttribute(thread, self, name));
288 if (result.isErrorNotFound()) {
289 return moduleRaiseAttributeError(thread, self, name);
290 }
291 return *result;
292}
293
294RawObject METH(module, __new__)(Thread* thread, Arguments args) {
295 HandleScope scope(thread);
296 Object cls_obj(&scope, args.get(0));
297 Runtime* runtime = thread->runtime();
298 if (!runtime->isInstanceOfType(*cls_obj)) {
299 return thread->raiseWithFmt(
300 LayoutId::kTypeError, "module.__new__(X): X is not a type object (%T)",
301 &cls_obj);
302 }
303 Type cls(&scope, *cls_obj);
304 if (cls.builtinBase() != LayoutId::kModule) {
305 Object cls_name(&scope, cls.name());
306 return thread->raiseWithFmt(
307 LayoutId::kTypeError,
308 "module.__new__(%S): %S is not a subtype of module", &cls_name,
309 &cls_name);
310 }
311 Layout layout(&scope, cls.instanceLayout());
312 Module result(&scope, runtime->newInstance(layout));
313 attributeDictInit(thread, result);
314 result.setDef(runtime->newIntFromCPtr(nullptr));
315 result.setId(runtime->reserveModuleId());
316 return *result;
317}
318
319RawObject METH(module, __init__)(Thread* thread, Arguments args) {
320 HandleScope scope(thread);
321 Object self_obj(&scope, args.get(0));
322 Runtime* runtime = thread->runtime();
323 if (!runtime->isInstanceOfModule(*self_obj)) {
324 return thread->raiseRequiresType(self_obj, ID(module));
325 }
326 Module self(&scope, *self_obj);
327 Object name(&scope, args.get(1));
328 if (!runtime->isInstanceOfStr(*name)) {
329 return thread->raiseWithFmt(
330 LayoutId::kTypeError,
331 "module.__init__() argument 1 must be str, not %T", &name);
332 }
333 return moduleInit(thread, self, name);
334}
335
336RawObject METH(module, __setattr__)(Thread* thread, Arguments args) {
337 HandleScope scope(thread);
338 Object self_obj(&scope, args.get(0));
339 Runtime* runtime = thread->runtime();
340 if (!runtime->isInstanceOfModule(*self_obj)) {
341 return thread->raiseRequiresType(self_obj, ID(module));
342 }
343 Module self(&scope, *self_obj);
344 Object name(&scope, args.get(1));
345 name = attributeName(thread, name);
346 if (name.isErrorException()) return *name;
347 Object value(&scope, args.get(2));
348 return moduleSetAttr(thread, self, name, value);
349}
350
351} // namespace py