this repo has no description
at trunk 552 lines 21 kB view raw
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