this repo has no description
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com)
2#include "descriptor-builtins.h"
3
4#include "builtins.h"
5#include "frame.h"
6#include "globals.h"
7#include "object-builtins.h"
8#include "objects.h"
9#include "runtime.h"
10#include "thread.h"
11#include "type-builtins.h"
12
13namespace py {
14
15static const BuiltinAttribute kClassMethodAttributes[] = {
16 {ID(__func__), RawClassMethod::kFunctionOffset, AttributeFlags::kReadOnly},
17};
18
19static const BuiltinAttribute kPropertyAttributes[] = {
20 {ID(fget), RawProperty::kGetterOffset, AttributeFlags::kReadOnly},
21 {ID(fset), RawProperty::kSetterOffset, AttributeFlags::kReadOnly},
22 {ID(fdel), RawProperty::kDeleterOffset, AttributeFlags::kReadOnly},
23 {ID(__doc__), RawProperty::kDocOffset},
24};
25
26static const BuiltinAttribute kSlotDescriptorAttributes[] = {
27 {ID(__objclass__), RawSlotDescriptor::kTypeOffset,
28 AttributeFlags::kReadOnly},
29 {ID(__name__), RawSlotDescriptor::kNameOffset, AttributeFlags::kReadOnly},
30 {ID(_slot_descriptor__offset), RawSlotDescriptor::kOffsetOffset,
31 AttributeFlags::kHidden},
32};
33
34static const BuiltinAttribute kStaticMethodAttributes[] = {
35 {ID(__func__), RawStaticMethod::kFunctionOffset, AttributeFlags::kReadOnly},
36};
37
38void initializeDescriptorTypes(Thread* thread) {
39 addBuiltinType(thread, ID(classmethod), LayoutId::kClassMethod,
40 /*superclass_id=*/LayoutId::kObject, kClassMethodAttributes,
41 ClassMethod::kSize, /*basetype=*/true);
42
43 addBuiltinType(thread, ID(property), LayoutId::kProperty,
44 /*superclass_id=*/LayoutId::kObject, kPropertyAttributes,
45 Property::kSize, /*basetype=*/true);
46
47 addBuiltinType(thread, ID(slot_descriptor), LayoutId::kSlotDescriptor,
48 /*superclass_id=*/LayoutId::kObject, kSlotDescriptorAttributes,
49 SlotDescriptor::kSize, /*basetype=*/false);
50
51 addBuiltinType(thread, ID(staticmethod), LayoutId::kStaticMethod,
52 /*superclass_id=*/LayoutId::kObject, kStaticMethodAttributes,
53 StaticMethod::kSize, /*basetype=*/true);
54}
55
56// classmethod
57
58RawObject METH(classmethod, __new__)(Thread* thread, Arguments args) {
59 HandleScope scope(thread);
60 Object type_obj(&scope, args.get(0));
61 Runtime* runtime = thread->runtime();
62 if (!runtime->isInstanceOfType(*type_obj)) {
63 return thread->raiseWithFmt(LayoutId::kTypeError, "not a type object");
64 }
65 Type type(&scope, *type_obj);
66 if (type.builtinBase() != LayoutId::kClassMethod) {
67 return thread->raiseWithFmt(LayoutId::kTypeError,
68 "not a subtype of classmethod");
69 }
70 Layout layout(&scope, type.instanceLayout());
71 ClassMethod result(&scope, runtime->newInstance(layout));
72 return *result;
73}
74
75RawObject METH(classmethod, __init__)(Thread* thread, Arguments args) {
76 HandleScope scope(thread);
77 Object self(&scope, args.get(0));
78 if (!thread->runtime()->isInstanceOfClassMethod(*self)) {
79 return thread->raiseRequiresType(self, ID(classmethod));
80 }
81 ClassMethod classmethod(&scope, *self);
82 Object arg(&scope, args.get(1));
83 classmethod.setFunction(*arg);
84 return NoneType::object();
85}
86
87RawObject METH(classmethod, __get__)(Thread* thread, Arguments args) {
88 HandleScope scope(thread);
89 Runtime* runtime = thread->runtime();
90 Object self(&scope, args.get(0));
91 if (!runtime->isInstanceOfClassMethod(*self)) {
92 return thread->raiseRequiresType(self, ID(classmethod));
93 }
94 Object owner(&scope, args.get(2));
95
96 ClassMethod classmethod(&scope, *self);
97 Object method(&scope, classmethod.function());
98 return runtime->newBoundMethod(method, owner);
99}
100
101// slot_descriptor
102
103static RawObject slotDescriptorRaiseTypeError(
104 Thread* thread, const SlotDescriptor& slot_descriptor,
105 const Object& instance_obj) {
106 HandleScope scope(thread);
107 Str slot_descriptor_name(&scope, slot_descriptor.name());
108 Type slot_descriptor_type(&scope, slot_descriptor.type());
109 Str slot_descriptor_type_name(&scope, slot_descriptor_type.name());
110 return thread->raiseWithFmt(LayoutId::kTypeError,
111 "descriptor '%S' for '%S' objects "
112 "doesn't apply to a '%T' object",
113 &slot_descriptor_name, &slot_descriptor_type_name,
114 &instance_obj);
115}
116
117RawObject slotDescriptorGet(Thread* thread,
118 const SlotDescriptor& slot_descriptor,
119 const Object& instance_obj,
120 const Object& owner_obj) {
121 if (instance_obj.isNoneType()) {
122 if (owner_obj.isNoneType()) {
123 return thread->raiseWithFmt(LayoutId::kTypeError,
124 "__get__(None, None) is invalid");
125 }
126 return *slot_descriptor;
127 }
128 HandleScope scope(thread);
129 Type instance_type(&scope,
130 thread->runtime()->typeAt(instance_obj.layoutId()));
131 if (!typeIsSubclass(*instance_type, slot_descriptor.type())) {
132 return slotDescriptorRaiseTypeError(thread, slot_descriptor, instance_obj);
133 }
134 DCHECK(instance_type.hasFlag(Type::Flag::kHasSlots),
135 "instance type is expected to set kHasSlots");
136 Instance instance(&scope, *instance_obj);
137 word offset = slot_descriptor.offset();
138 DCHECK_BOUND(offset, instance.size() - kPointerSize);
139 Object attribute_value(&scope, instance.instanceVariableAt(offset));
140 if (attribute_value.isUnbound()) {
141 Object attribute_name(&scope, slot_descriptor.name());
142 return objectRaiseAttributeError(thread, instance, attribute_name);
143 }
144 return *attribute_value;
145}
146
147RawObject METH(slot_descriptor, __delete__)(Thread* thread, Arguments args) {
148 HandleScope scope(thread);
149 SlotDescriptor slot_descriptor(&scope, args.get(0));
150 Object instance_obj(&scope, args.get(1));
151 Type instance_type(&scope,
152 thread->runtime()->typeAt(instance_obj.layoutId()));
153 if (!typeIsSubclass(*instance_type, slot_descriptor.type())) {
154 return slotDescriptorRaiseTypeError(thread, slot_descriptor, instance_obj);
155 }
156 Object owner_obj(&scope, NoneType::object());
157 Object existing_value(&scope, slotDescriptorGet(thread, slot_descriptor,
158 instance_obj, owner_obj));
159 if (existing_value.isErrorException()) {
160 return *existing_value;
161 }
162 Instance instance(&scope, *instance_obj);
163 instance.instanceVariableAtPut(slot_descriptor.offset(), Unbound::object());
164 return NoneType::object();
165}
166
167RawObject METH(slot_descriptor, __get__)(Thread* thread, Arguments args) {
168 HandleScope scope(thread);
169 SlotDescriptor slot_descriptor(&scope, args.get(0));
170 Object instance(&scope, args.get(1));
171 Object owner(&scope, args.get(2));
172 return slotDescriptorGet(thread, slot_descriptor, instance, owner);
173}
174
175RawObject slotDescriptorSet(Thread* thread,
176 const SlotDescriptor& slot_descriptor,
177 const Object& instance_obj, const Object& value) {
178 HandleScope scope(thread);
179 Type instance_type(&scope,
180 thread->runtime()->typeAt(instance_obj.layoutId()));
181 if (!typeIsSubclass(*instance_type, slot_descriptor.type())) {
182 return slotDescriptorRaiseTypeError(thread, slot_descriptor, instance_obj);
183 }
184 DCHECK(instance_type.hasFlag(Type::Flag::kHasSlots),
185 "instance type is expected to set kHasSlots");
186 Instance instance(&scope, *instance_obj);
187 word offset = slot_descriptor.offset();
188 DCHECK_BOUND(offset, instance.size() - kPointerSize);
189 instance.instanceVariableAtPut(offset, *value);
190 return NoneType::object();
191}
192
193RawObject METH(slot_descriptor, __set__)(Thread* thread, Arguments args) {
194 HandleScope scope(thread);
195 SlotDescriptor slot_descriptor(&scope, args.get(0));
196 Object instance(&scope, args.get(1));
197 Object value(&scope, args.get(2));
198 return slotDescriptorSet(thread, slot_descriptor, instance, value);
199}
200
201// staticmethod
202
203RawObject METH(staticmethod, __get__)(Thread* thread, Arguments args) {
204 HandleScope scope(thread);
205 Object self(&scope, args.get(0));
206 if (!thread->runtime()->isInstanceOfStaticMethod(*self)) {
207 return thread->raiseRequiresType(self, ID(staticmethod));
208 }
209 StaticMethod staticmethod(&scope, *self);
210 return staticmethod.function();
211}
212
213RawObject METH(staticmethod, __new__)(Thread* thread, Arguments args) {
214 HandleScope scope(thread);
215 Runtime* runtime = thread->runtime();
216 Object type_obj(&scope, args.get(0));
217 if (!runtime->isInstanceOfType(*type_obj)) {
218 return thread->raiseWithFmt(LayoutId::kTypeError, "not a type object");
219 }
220 Type type(&scope, *type_obj);
221 if (type.builtinBase() != LayoutId::kStaticMethod) {
222 return thread->raiseWithFmt(LayoutId::kTypeError,
223 "not a subtype of staticmethod");
224 }
225 Layout layout(&scope, type.instanceLayout());
226 StaticMethod result(&scope, runtime->newInstance(layout));
227 return *result;
228}
229
230RawObject METH(staticmethod, __init__)(Thread* thread, Arguments args) {
231 HandleScope scope(thread);
232 StaticMethod staticmethod(&scope, args.get(0));
233 Object arg(&scope, args.get(1));
234 staticmethod.setFunction(*arg);
235 return NoneType::object();
236}
237
238// property
239
240RawObject METH(property, __delete__)(Thread* thread, Arguments args) {
241 HandleScope scope(thread);
242 Object self_obj(&scope, args.get(0));
243 if (!thread->runtime()->isInstanceOfProperty(*self_obj)) {
244 return thread->raiseRequiresType(self_obj, ID(property));
245 }
246 Property self(&scope, *self_obj);
247 Object deleter(&scope, self.deleter());
248 if (deleter.isNoneType()) {
249 return thread->raiseWithFmt(LayoutId::kAttributeError,
250 "can't delete attribute");
251 }
252 Object instance(&scope, args.get(1));
253 return Interpreter::call1(thread, deleter, instance);
254}
255
256RawObject METH(property, __get__)(Thread* thread, Arguments args) {
257 HandleScope scope(thread);
258 Object self_obj(&scope, args.get(0));
259 if (!thread->runtime()->isInstanceOfProperty(*self_obj)) {
260 return thread->raiseRequiresType(self_obj, ID(property));
261 }
262 Property self(&scope, *self_obj);
263 Object getter(&scope, self.getter());
264 if (getter.isNoneType()) {
265 return thread->raiseWithFmt(LayoutId::kAttributeError,
266 "unreadable attribute");
267 }
268 Object instance(&scope, args.get(1));
269 if (instance.isNoneType()) {
270 return *self;
271 }
272 return Interpreter::call1(thread, getter, instance);
273}
274
275RawObject METH(property, __init__)(Thread* thread, Arguments args) {
276 HandleScope scope(thread);
277 Object self_obj(&scope, args.get(0));
278 if (!thread->runtime()->isInstanceOfProperty(*self_obj)) {
279 return thread->raiseRequiresType(self_obj, ID(property));
280 }
281 Property self(&scope, *self_obj);
282 self.setGetter(args.get(1));
283 self.setSetter(args.get(2));
284 self.setDeleter(args.get(3));
285 // TODO(T42363565) Do something with the doc argument.
286 return NoneType::object();
287}
288
289RawObject METH(property, __new__)(Thread* thread, Arguments args) {
290 HandleScope scope(thread);
291 Object type_obj(&scope, args.get(0));
292 Runtime* runtime = thread->runtime();
293 if (!runtime->isInstanceOfType(*type_obj)) {
294 return thread->raiseWithFmt(LayoutId::kTypeError, "not a type object");
295 }
296 Type type(&scope, *type_obj);
297 if (type.builtinBase() != LayoutId::kProperty) {
298 return thread->raiseWithFmt(LayoutId::kTypeError,
299 "not a subtype of property");
300 }
301 Layout layout(&scope, type.instanceLayout());
302 Property result(&scope, runtime->newInstance(layout));
303 return *result;
304}
305
306RawObject METH(property, __set__)(Thread* thread, Arguments args) {
307 HandleScope scope(thread);
308 Object self_obj(&scope, args.get(0));
309 if (!thread->runtime()->isInstanceOfProperty(*self_obj)) {
310 return thread->raiseRequiresType(self_obj, ID(property));
311 }
312 Property self(&scope, *self_obj);
313 Object setter(&scope, self.setter());
314 if (setter.isNoneType()) {
315 return thread->raiseWithFmt(LayoutId::kAttributeError,
316 "can't set attribute");
317 }
318 Object obj(&scope, args.get(1));
319 Object value(&scope, args.get(2));
320 return Interpreter::call2(thread, setter, obj, value);
321}
322
323RawObject METH(property, deleter)(Thread* thread, Arguments args) {
324 HandleScope scope(thread);
325 Runtime* runtime = thread->runtime();
326 Object self_obj(&scope, args.get(0));
327 if (!runtime->isInstanceOfProperty(*self_obj)) {
328 return thread->raiseRequiresType(self_obj, ID(property));
329 }
330 Property self(&scope, *self_obj);
331 Object getter(&scope, self.getter());
332 Object setter(&scope, self.setter());
333 Object deleter(&scope, args.get(1));
334 return runtime->newProperty(getter, setter, deleter);
335}
336
337RawObject METH(property, getter)(Thread* thread, Arguments args) {
338 HandleScope scope(thread);
339 Runtime* runtime = thread->runtime();
340 Object self_obj(&scope, args.get(0));
341 if (!runtime->isInstanceOfProperty(*self_obj)) {
342 return thread->raiseRequiresType(self_obj, ID(property));
343 }
344 Property self(&scope, *self_obj);
345 Object getter(&scope, args.get(1));
346 Object setter(&scope, self.setter());
347 Object deleter(&scope, self.deleter());
348 return runtime->newProperty(getter, setter, deleter);
349}
350
351RawObject METH(property, setter)(Thread* thread, Arguments args) {
352 HandleScope scope(thread);
353 Runtime* runtime = thread->runtime();
354 Object self_obj(&scope, args.get(0));
355 if (!runtime->isInstanceOfProperty(*self_obj)) {
356 return thread->raiseRequiresType(self_obj, ID(property));
357 }
358 Property self(&scope, *self_obj);
359 Object getter(&scope, self.getter());
360 Object setter(&scope, args.get(1));
361 Object deleter(&scope, self.deleter());
362 return runtime->newProperty(getter, setter, deleter);
363}
364
365} // namespace py