this repo has no description
1/* Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com) */
2#pragma once
3
4#include "frame.h"
5#include "globals.h"
6#include "handles-decl.h"
7#include "objects.h"
8#include "os.h"
9#include "symbols.h"
10#include "vector.h"
11
12namespace py {
13
14class Frame;
15class FrameVisitor;
16class HandleScope;
17class PointerVisitor;
18class Runtime;
19
20class Handles {
21 public:
22 Handles() = default;
23
24 Object* head() const { return head_; }
25
26 Object* push(Object* new_head) {
27 Object* old_head = head_;
28 head_ = new_head;
29 return old_head;
30 }
31
32 void pop(Object* new_head) { head_ = new_head; }
33
34 void visitPointers(PointerVisitor* visitor);
35
36 DISALLOW_COPY_AND_ASSIGN(Handles);
37
38 private:
39 Object* head_ = nullptr;
40};
41
42RawObject uninitializedInterpreterFunc(Thread*);
43
44class Thread {
45 public:
46 static const int kDefaultStackSize = 1 * kMiB;
47
48 enum InterruptKind {
49 kSignal = 1 << 0,
50 kReinitInterpreter = 1 << 1,
51 kProfile = 1 << 2,
52 };
53
54 explicit Thread(Runtime* runtime, word size);
55 ~Thread();
56
57 void begin();
58
59 static Thread* current();
60 static void setCurrentThread(Thread* thread);
61
62 void linkFrame(Frame* frame);
63 // Private method. Call pushCallFrame() or pushNativeFrame() isntead.
64 Frame* pushCallFrame(RawFunction function);
65 Frame* pushNativeFrame(word nargs);
66 Frame* pushGeneratorFrame(const GeneratorFrame& generator_frame);
67
68 Frame* popFrame();
69 Frame* popFrameToGeneratorFrame(const GeneratorFrame& generator_frame);
70
71 RawObject* stackPointer() { return stack_pointer_; }
72 void setStackPointer(RawObject* stack_pointer) {
73 stack_pointer_ = stack_pointer;
74 }
75
76 // Begin of the value stack of the current frame.
77 RawObject* valueStackBase();
78
79 // Returns the number of items on the value stack of the current frame.
80 word valueStackSize();
81
82 // Pop n items off the stack.
83 void stackDrop(word count);
84
85 // Insert value at offset on the stack.
86 void stackInsertAt(word offset, RawObject value);
87
88 // Return the object at offset from the top of the value stack (e.g. peek(0)
89 // returns the top of the stack)
90 RawObject stackPeek(word offset);
91
92 // Pop the top value off the stack and return it.
93 RawObject stackPop();
94
95 // Push value on the stack.
96 void stackPush(RawObject value);
97
98 // Remove value at offset on the stack.
99 void stackRemoveAt(word offset);
100
101 // Set value at offset on the stack.
102 void stackSetAt(word offset, RawObject value);
103
104 // Set the top value of the stack.
105 void stackSetTop(RawObject value);
106
107 // Return the top value of the stack.
108 RawObject stackTop();
109
110 // Runs a code object on the current thread.
111 NODISCARD RawObject exec(const Code& code, const Module& module,
112 const Object& implicit_globals);
113
114 NODISCARD RawObject callFunctionWithImplicitGlobals(
115 const Function& function, const Object& implicit_globals);
116
117 Thread* next() { return next_; }
118 void setNext(Thread* next) { next_ = next; }
119
120 Thread* prev() { return prev_; }
121 void setPrev(Thread* prev) { prev_ = prev; }
122
123 Handles* handles() { return &handles_; }
124
125 Runtime* runtime() { return runtime_; }
126
127 Frame* currentFrame() { return current_frame_; }
128
129 RawObject heapFrameAtDepth(word depth);
130
131 using InterpreterFunc = RawObject (*)(Thread*);
132
133 InterpreterFunc interpreterFunc() { return interpreter_func_; }
134 void setInterpreterFunc(InterpreterFunc func) { interpreter_func_ = func; }
135
136 void* interpreterData() { return interpreter_data_; }
137 void setInterpreterData(void* data) { interpreter_data_ = data; }
138
139 void clearInterrupt(InterruptKind kind);
140 void interrupt(InterruptKind kind);
141
142 bool isMainThread();
143
144 void visitRoots(PointerVisitor* visitor);
145
146 void visitStackRoots(PointerVisitor* visitor);
147
148 // Calls out to the interpreter to lookup and call a method on the receiver
149 // with the given argument(s). Returns Error<NotFound> if the method can't be
150 // found, or the result of the call otheriwse (which may be Error<Exception>).
151 NODISCARD RawObject invokeMethod1(const Object& receiver, SymbolId selector);
152 NODISCARD RawObject invokeMethod2(const Object& receiver, SymbolId selector,
153 const Object& arg1);
154 NODISCARD RawObject invokeMethod3(const Object& receiver, SymbolId selector,
155 const Object& arg1, const Object& arg2);
156
157 // Looks up a method on a type and invokes it with the given receiver and
158 // argument(s). Returns Error<NotFound> if the method can't be found, or the
159 // result of the call otheriwse (which may be Error<Exception>).
160 // ex: str.foo(receiver, arg1, ...)
161 NODISCARD RawObject invokeMethodStatic1(LayoutId type, SymbolId method_name,
162 const Object& receiver);
163 NODISCARD RawObject invokeMethodStatic2(LayoutId type, SymbolId method_name,
164 const Object& receiver,
165 const Object& arg1);
166 NODISCARD RawObject invokeMethodStatic3(LayoutId type, SymbolId method_name,
167 const Object& receiver,
168 const Object& arg1,
169 const Object& arg2);
170 NODISCARD RawObject invokeMethodStatic4(LayoutId type, SymbolId method_name,
171 const Object& receiver,
172 const Object& arg1,
173 const Object& arg2,
174 const Object& arg3);
175
176 // Calls out to the interpreter to lookup and call a function with the given
177 // argument(s). Returns Error<NotFound> if the function can't be found, or the
178 // result of the call otherwise (which may be Error<Exception>).
179 NODISCARD RawObject invokeFunction0(SymbolId module, SymbolId name);
180 NODISCARD RawObject invokeFunction1(SymbolId module, SymbolId name,
181 const Object& arg1);
182 NODISCARD RawObject invokeFunction2(SymbolId module, SymbolId name,
183 const Object& arg1, const Object& arg2);
184 NODISCARD RawObject invokeFunction3(SymbolId module, SymbolId name,
185 const Object& arg1, const Object& arg2,
186 const Object& arg3);
187 NODISCARD RawObject invokeFunction4(SymbolId module, SymbolId name,
188 const Object& arg1, const Object& arg2,
189 const Object& arg3, const Object& arg4);
190 NODISCARD RawObject invokeFunction5(SymbolId module, SymbolId name,
191 const Object& arg1, const Object& arg2,
192 const Object& arg3, const Object& arg4,
193 const Object& arg5);
194 NODISCARD RawObject invokeFunction6(SymbolId module, SymbolId name,
195 const Object& arg1, const Object& arg2,
196 const Object& arg3, const Object& arg4,
197 const Object& arg5, const Object& arg6);
198
199 // Raises an exception with the given type and returns an Error that must be
200 // returned up the stack by the caller.
201 RawObject raise(LayoutId type, RawObject value);
202 RawObject raiseWithType(RawObject type, RawObject value);
203 RawObject raiseWithFmt(LayoutId type, const char* fmt, ...);
204
205 // Raises a new exception, attaching the pending exception (if any) to the
206 // new exception's __cause__ and __context__ attributes.
207 RawObject raiseWithFmtChainingPendingAsCause(LayoutId type, const char* fmt,
208 ...);
209
210 // Raises a TypeError exception for PyErr_BadArgument.
211 void raiseBadArgument();
212
213 // Raises a SystemError exception for PyErr_BadInternalCall.
214 RawObject raiseBadInternalCall();
215
216 // Raises a MemoryError exception and returns an Error that must be returned
217 // up the stack by the caller.
218 RawObject raiseMemoryError();
219
220 // Raises an OSError exception generated from the value of errno.
221 RawObject raiseOSErrorFromErrno(int errno_value);
222
223 RawObject raiseFromErrnoWithFilenames(const Object& type, int errno_value,
224 const Object& filename0,
225 const Object& filename1);
226
227 // Raises a TypeError exception of the form '<method> requires a <type(obj)>
228 // object but received a <expected_type>' and returns an Error object that
229 // must be returned up the stack by the caller.
230 RawObject raiseRequiresType(const Object& obj, SymbolId expected_type);
231
232 // Raise a StopAsyncIteration exception, indicating an asynchronous generator
233 // has returned. Note, unlike generators and coroutines, asynchoronous
234 // generators cannot have non-None return values.
235 RawObject raiseStopAsyncIteration();
236
237 // Raise a StopIteration exception with no value attribute set. This can
238 // indicate a a return value from a generator with value None, but can also
239 // mean the generator did not run, e.g. it is exhausted.
240 RawObject raiseStopIteration();
241
242 // Raise a StopIteration exception with the value attribute set. This is
243 // typically used to transport a return value from a generator or coroutine.
244 RawObject raiseStopIterationWithValue(const Object& value);
245
246 // Raises a TypeError exception and returns an Error object that must be
247 // returned up the stack by the caller.
248 RawObject raiseUnsupportedBinaryOperation(const Object& left,
249 const Object& right,
250 SymbolId op_name);
251
252 // Exception support
253 //
254 // We track two sets of exception state, a "pending" exception and a "caught"
255 // exception. Each one has a type, value, and traceback.
256 //
257 // An exception is pending from the moment it is raised until it is caught by
258 // a handler. It transitions from pending to caught right before execution of
259 // the handler. If the handler re-raises, the exception transitions back to
260 // pending to resume unwinding; otherwise, the caught exception is cleared
261 // when the handler block is popped.
262 //
263 // The pending exception is stored directly in the Thread, since there is at
264 // most one active at any given time. The caught exception is kept in a stack
265 // of ExceptionState objects, and the Thread holds a pointer to the top of
266 // the stack. When the runtime enters a generator or coroutine, it pushes the
267 // ExceptionState owned by that object onto this stack, allowing that state
268 // to be preserved if we yield in an except block. When there is no generator
269 // or coroutine running, the default ExceptionState created with this Thread
270 // holds the caught exception.
271
272 // Returns true if there is a pending exception.
273 bool hasPendingException();
274
275 // Returns true if there is a StopIteration exception pending.
276 bool hasPendingStopIteration();
277
278 // If there is a StopIteration exception pending, clear it and return
279 // true. Otherwise, return false.
280 bool clearPendingStopIteration();
281
282 // Assuming there is a StopIteration pending, returns its value, accounting
283 // for various potential states of normalization.
284 RawObject pendingStopIterationValue();
285
286 // If there's a pending exception, clears it.
287 void clearPendingException();
288
289 // If there's a pending exception, prints it and ignores it.
290 void ignorePendingException();
291
292 // Gets the type, value, or traceback of the pending exception. No pending
293 // exception is indicated with a type of None.
294 RawObject pendingExceptionType() { return pending_exc_type_; }
295 RawObject pendingExceptionValue() { return pending_exc_value_; }
296 RawObject pendingExceptionTraceback() { return pending_exc_traceback_; }
297
298 // Returns whether or not the pending exception type (which must be set) is a
299 // subtype of the given type.
300 bool pendingExceptionMatches(LayoutId type);
301
302 // Sets the type, value, or traceback of the pending exception.
303 void setPendingExceptionType(RawObject type) { pending_exc_type_ = type; }
304 void setPendingExceptionValue(RawObject value) { pending_exc_value_ = value; }
305 void setPendingExceptionTraceback(RawObject traceback) {
306 pending_exc_traceback_ = traceback;
307 }
308
309 // Sets the type, value, or traceback of the caught exception.
310 void setCaughtExceptionType(RawObject type);
311 void setCaughtExceptionValue(RawObject value);
312 void setCaughtExceptionTraceback(RawObject traceback);
313
314 // Gets or sets the current caught ExceptionState. See also
315 // topmostCaughtExceptionState().
316 RawObject caughtExceptionState();
317 void setCaughtExceptionState(RawObject state);
318
319 // Searches up the stack for the nearest caught exception. Returns None if
320 // there are no caught exceptions being handled, or an ExceptionState.
321 RawObject topmostCaughtExceptionState();
322
323 // If there is a current caught exception, attach it to the given exception's
324 // __context__ attribute.
325 //
326 // Returns the updated value, which may be the result of createException(type,
327 // value) if value is not an instance of BaseException.
328 RawObject chainExceptionContext(const Type& type, const Object& value);
329
330 // Returns true if and only if obj is not an Error and there is no pending
331 // exception, or obj is an Error<Exception> and there is a pending exception.
332 // Mostly used in assertions around call boundaries.
333 bool isErrorValueOk(RawObject obj);
334
335 // Walk all the frames on the stack starting with the top-most frame
336 void visitFrames(FrameVisitor* visitor);
337
338 int recursionDepth() { return recursion_depth_; }
339
340 int recursionEnter() {
341 DCHECK(recursion_depth_ <= recursion_limit_,
342 "recursion depth can't be more than the recursion limit");
343 return recursion_depth_++;
344 }
345
346 void recursionLeave() {
347 DCHECK(recursion_depth_ > 0, "recursion depth can't be less than 0");
348 recursion_depth_--;
349 }
350
351 int recursionLimit() { return recursion_limit_; }
352 // TODO(T62600497): Enforce the recursion limit
353 void setRecursionLimit(int limit) { recursion_limit_ = limit; }
354
355 RawObject reprEnter(const Object& obj);
356 void reprLeave(const Object& obj);
357
358 // Get/set the thread-global callbacks for asynchronous generators.
359 RawObject asyncgenHooksFirstIter() { return asyncgen_hooks_first_iter_; }
360 RawObject asyncgenHooksFinalizer() { return asyncgen_hooks_finalizer_; }
361
362 void setAsyncgenHooksFirstIter(RawObject first_iter) {
363 asyncgen_hooks_first_iter_ = first_iter;
364 }
365 void setAsyncgenHooksFinalizer(RawObject finalizer) {
366 asyncgen_hooks_finalizer_ = finalizer;
367 }
368
369 // Get/set the current thread-global _contextvars.Context
370 RawObject contextvarsContext() { return contextvars_context_; }
371 void setContextvarsContext(RawObject context) {
372 contextvars_context_ = context;
373 }
374
375 void countOpcodes(word count) { opcode_count_ += count; }
376 // Returns number of opcodes executed in this thread. This is only guaranteed
377 // to be accurate when `Runtime::supportProfiling()` is enabled.
378 word opcodeCount() { return opcode_count_; }
379
380 bool profilingEnabled();
381 void enableProfiling();
382 void disableProfiling();
383
384 RawObject profilingData() { return profiling_data_; }
385 void setProfilingData(RawObject data) { profiling_data_ = data; }
386
387 word strOffset(const Str& str, word index);
388
389 bool wouldStackOverflow(word size);
390 bool handleInterrupt(word size);
391
392 static int currentFrameOffset() { return offsetof(Thread, current_frame_); }
393
394 static int interpreterDataOffset() {
395 return offsetof(Thread, interpreter_data_);
396 }
397
398 static int opcodeCountOffset() { return offsetof(Thread, opcode_count_); }
399
400 static int runtimeOffset() { return offsetof(Thread, runtime_); }
401
402 static int limitOffset() { return offsetof(Thread, limit_); }
403
404 static int stackPointerOffset() { return offsetof(Thread, stack_pointer_); }
405
406 private:
407 Frame* pushInitialFrame();
408 Frame* openAndLinkFrame(word size, word locals_offset);
409
410 void handleInterruptWithFrame();
411 Frame* handleInterruptPushCallFrame(RawFunction function, word max_stack_size,
412 word initial_stack_size,
413 word locals_offset);
414 Frame* handleInterruptPushGeneratorFrame(
415 const GeneratorFrame& generator_frame, word size);
416 Frame* handleInterruptPushNativeFrame(word locals_offset);
417 Frame* pushCallFrameImpl(RawFunction function, word stack_size,
418 word locals_offset);
419 Frame* pushGeneratorFrameImpl(const GeneratorFrame& generator_frame,
420 word size);
421 Frame* pushNativeFrameImpl(word locals_offset);
422
423 Handles handles_;
424
425 byte* start_; // base address of the stack
426 byte* end_; // exclusive limit of the stack
427 byte* limit_; // current limit of the stack
428
429 RawObject* stack_pointer_;
430
431 // Has the runtime requested a thread interruption? (e.g. signals, GC)
432 uint8_t interrupt_flags_ = 0;
433
434 // Number of opcodes executed in the thread while opcode counting was enabled.
435 word opcode_count_ = 0;
436
437 // current_frame_ always points to the top-most frame on the stack.
438 Frame* current_frame_;
439 Thread* next_ = nullptr;
440 Thread* prev_ = nullptr;
441 Runtime* runtime_ = nullptr;
442 InterpreterFunc interpreter_func_ = uninitializedInterpreterFunc;
443 void* interpreter_data_ = nullptr;
444
445 // State of the pending exception.
446 RawObject pending_exc_type_ = RawNoneType::object();
447 RawObject pending_exc_value_ = RawNoneType::object();
448 RawObject pending_exc_traceback_ = RawNoneType::object();
449
450 // Stack of ExceptionStates for the current caught exception. Generators push
451 // their private state onto this stack before resuming, and pop it after
452 // suspending.
453 RawObject caught_exc_stack_ = RawNoneType::object();
454
455 RawObject api_repr_list_ = RawNoneType::object();
456
457 RawObject asyncgen_hooks_first_iter_ = RawNoneType::object();
458 RawObject asyncgen_hooks_finalizer_ = RawNoneType::object();
459 RawObject contextvars_context_ = RawNoneType::object();
460
461 RawObject profiling_data_ = RawNoneType::object();
462
463 RawObject str_offset_str_ = RawNoneType::object();
464 word str_offset_index_;
465 word str_offset_offset_;
466
467 // C-API current recursion depth used via _PyThreadState_GetRecursionDepth
468 int recursion_depth_ = 0;
469
470 // C-API recursion limit as set via Py_SetRecursionLimit.
471 int recursion_limit_ = 1000; // CPython's default: Py_DEFAULT_RECURSION_LIMIT
472
473 static thread_local Thread* current_thread_;
474
475 DISALLOW_COPY_AND_ASSIGN(Thread);
476};
477
478inline RawObject* Thread::valueStackBase() {
479 return reinterpret_cast<RawObject*>(current_frame_);
480}
481
482inline word Thread::valueStackSize() {
483 return valueStackBase() - stack_pointer_;
484}
485
486inline Frame* Thread::popFrame() {
487 Frame* frame = current_frame_;
488 DCHECK(!frame->isSentinel(), "cannot pop initial frame");
489 stack_pointer_ = frame->frameEnd();
490 current_frame_ = frame->previousFrame();
491 return current_frame_;
492}
493
494inline void Thread::stackDrop(word count) {
495 DCHECK(stack_pointer_ + count <= valueStackBase(), "stack underflow");
496 stack_pointer_ += count;
497}
498
499inline void Thread::stackInsertAt(word offset, RawObject value) {
500 RawObject* sp = stack_pointer_ - 1;
501 DCHECK(sp + offset < valueStackBase(), "stack underflow");
502 for (word i = 0; i < offset; i++) {
503 sp[i] = sp[i + 1];
504 }
505 sp[offset] = value;
506 stack_pointer_ = sp;
507}
508
509inline RawObject Thread::stackPeek(word offset) {
510 DCHECK(stack_pointer_ + offset < valueStackBase(), "stack underflow");
511 return *(stack_pointer_ + offset);
512}
513
514inline RawObject Thread::stackPop() {
515 DCHECK(stack_pointer_ + 1 <= valueStackBase(), "stack underflow");
516 return *(stack_pointer_++);
517}
518
519inline void Thread::stackPush(RawObject value) { *(--stack_pointer_) = value; }
520
521inline void Thread::stackRemoveAt(word offset) {
522 DCHECK(stack_pointer_ + offset < valueStackBase(), "stack underflow");
523 RawObject* sp = stack_pointer_;
524 for (word i = offset; i >= 1; i--) {
525 sp[i] = sp[i - 1];
526 }
527 stack_pointer_ = sp + 1;
528}
529
530inline void Thread::stackSetAt(word offset, RawObject value) {
531 DCHECK(stack_pointer_ + offset < valueStackBase(), "stack underflow");
532 *(stack_pointer_ + offset) = value;
533}
534
535inline void Thread::stackSetTop(RawObject value) {
536 DCHECK(stack_pointer_ < valueStackBase(), "stack underflow");
537 *stack_pointer_ = value;
538}
539
540inline RawObject Thread::stackTop() {
541 DCHECK(stack_pointer_ < valueStackBase(), "stack underflow");
542 return *stack_pointer_;
543}
544
545inline bool Thread::profilingEnabled() { return interrupt_flags_ & kProfile; }
546
547inline bool Thread::wouldStackOverflow(word size) {
548 // Check that there is sufficient space on the stack
549 return reinterpret_cast<byte*>(stack_pointer_) - size < limit_;
550}
551
552} // namespace py