this repo has no description
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com)
2#include "thread.h"
3
4#include <signal.h>
5
6#include <cerrno>
7#include <cstdarg>
8#include <cstdio>
9#include <cstring>
10
11#include "builtins-module.h"
12#include "exception-builtins.h"
13#include "file.h"
14#include "frame.h"
15#include "globals.h"
16#include "handles.h"
17#include "interpreter.h"
18#include "module-builtins.h"
19#include "objects.h"
20#include "profiling.h"
21#include "runtime.h"
22#include "tuple-builtins.h"
23#include "type-builtins.h"
24#include "visitor.h"
25
26namespace py {
27
28void Handles::visitPointers(PointerVisitor* visitor) {
29 for (Object* handle = head_; handle != nullptr;
30 handle = handle->nextHandle()) {
31 visitor->visitPointer(handle, PointerKind::kHandle);
32 }
33}
34
35RawObject uninitializedInterpreterFunc(Thread*) {
36 UNREACHABLE("interpreter main loop not initialized on this thread");
37}
38
39thread_local Thread* Thread::current_thread_ = nullptr;
40
41Thread::Thread(Runtime* runtime, word size) : runtime_(runtime) {
42 CHECK(size % kPointerSize == 0, "size must be a multiple of kPointerSize");
43 start_ = new byte[size](); // Zero-initialize the stack
44 // Stack growns down in order to match machine convention
45 end_ = start_ + size;
46 limit_ = start_;
47 stack_pointer_ = reinterpret_cast<RawObject*>(end_);
48 current_frame_ = pushInitialFrame();
49 setCaughtExceptionState(runtime_->newExceptionState());
50}
51
52Thread::~Thread() { delete[] start_; }
53
54void Thread::begin() {
55 Thread::setCurrentThread(this);
56 runtime_->interpreter()->setupThread(this);
57}
58
59void Thread::visitRoots(PointerVisitor* visitor) {
60 visitStackRoots(visitor);
61 handles()->visitPointers(visitor);
62 visitor->visitPointer(&api_repr_list_, PointerKind::kThread);
63 visitor->visitPointer(&asyncgen_hooks_finalizer_, PointerKind::kThread);
64 visitor->visitPointer(&asyncgen_hooks_first_iter_, PointerKind::kThread);
65 visitor->visitPointer(&caught_exc_stack_, PointerKind::kThread);
66 visitor->visitPointer(&contextvars_context_, PointerKind::kThread);
67 visitor->visitPointer(&pending_exc_traceback_, PointerKind::kThread);
68 visitor->visitPointer(&pending_exc_type_, PointerKind::kThread);
69 visitor->visitPointer(&pending_exc_value_, PointerKind::kThread);
70 visitor->visitPointer(&profiling_data_, PointerKind::kThread);
71 visitor->visitPointer(&str_offset_str_, PointerKind::kThread);
72}
73
74void Thread::visitStackRoots(PointerVisitor* visitor) {
75 auto address = reinterpret_cast<uword>(stackPointer());
76 auto end = reinterpret_cast<uword>(end_);
77 std::memset(start_, 0, reinterpret_cast<byte*>(address) - start_);
78 for (; address < end; address += kPointerSize) {
79 visitor->visitPointer(reinterpret_cast<RawObject*>(address),
80 PointerKind::kStack);
81 }
82}
83
84Thread* Thread::current() { return Thread::current_thread_; }
85
86bool Thread::isMainThread() { return this == runtime_->mainThread(); }
87
88namespace {
89
90class UserVisibleFrameVisitor : public FrameVisitor {
91 public:
92 UserVisibleFrameVisitor(Thread* thread, word depth)
93 : thread_(thread),
94 scope_(thread),
95 result_(&scope_, NoneType::object()),
96 heap_frame_(&scope_, NoneType::object()),
97 next_heap_frame_(&scope_, NoneType::object()),
98 depth_(depth) {}
99
100 bool visit(Frame* frame) {
101 if (isHiddenFrame(frame)) {
102 return true;
103 }
104 if (call_ < depth_) {
105 call_++;
106 return true;
107 }
108 // Once visitor reaches the target depth, start creating a linked list of
109 // FrameProxys objects.
110 // TOOD(T63960421): Cache an already created object in the stack frame.
111 Function function(&scope_, frame->function());
112 Object lasti(&scope_, NoneType::object());
113 if (!frame->isNative()) {
114 lasti = SmallInt::fromWord(frame->virtualPC());
115 }
116 heap_frame_ = thread_->runtime()->newFrameProxy(thread_, function, lasti);
117 // TODO(T89882231) unconditionally add frameLocals. We cannot currently do
118 // this because uninitialized variables are not cleared and will read
119 // arbitrary values.
120 if (function.hasOptimizedOrNewlocals()) {
121 FrameProxy::cast(*heap_frame_).setLocals(thread_->runtime()->newDict());
122 } else {
123 FrameProxy::cast(*heap_frame_).setLocals(frameLocals(thread_, frame));
124 }
125 if (result_.isNoneType()) {
126 // The head of the linked list is returned as the result.
127 result_ = *heap_frame_;
128 } else {
129 FrameProxy::cast(*next_heap_frame_).setBack(*heap_frame_);
130 }
131 next_heap_frame_ = *heap_frame_;
132 return true;
133 }
134
135 RawObject result() { return *result_; }
136
137 private:
138 bool isHiddenFrame(Frame* frame) {
139 if (frame == nullptr || frame->isSentinel()) {
140 return true;
141 }
142 RawFunction function = Function::cast(frame->function());
143 word builtins_module_id = thread_->runtime()->builtinsModuleId();
144 // PyCFunction do not generate a frame in cpython and therefore do
145 // not show up in sys._getframe(). Our builtin functions do create a
146 // frame so we hide frames of functions in builtins from the user.
147 // TODO(T64005113): This logic should be applied to each function.
148 if (function.moduleObject().isModule() &&
149 Module::cast(function.moduleObject()).id() == builtins_module_id) {
150 return true;
151 }
152 return false;
153 }
154
155 Thread* thread_;
156 HandleScope scope_;
157 Object result_;
158 Object heap_frame_;
159 Object next_heap_frame_;
160
161 word call_ = 0;
162 word depth_;
163
164 DISALLOW_HEAP_ALLOCATION();
165 DISALLOW_IMPLICIT_CONSTRUCTORS(UserVisibleFrameVisitor);
166};
167
168} // namespace
169
170RawObject Thread::heapFrameAtDepth(word depth) {
171 UserVisibleFrameVisitor visitor(this, depth);
172 visitFrames(&visitor);
173 return visitor.result();
174}
175
176void Thread::setCurrentThread(Thread* thread) {
177 Thread::current_thread_ = thread;
178}
179
180void Thread::clearInterrupt(InterruptKind kind) {
181 interrupt_flags_ &= ~kind;
182 if (interrupt_flags_ == 0) {
183 limit_ = start_;
184 }
185}
186
187void Thread::interrupt(InterruptKind kind) {
188 interrupt_flags_ |= kind;
189 limit_ = end_;
190}
191
192bool Thread::handleInterrupt(word size) {
193 // Is it a real stack overflow?
194 if (reinterpret_cast<byte*>(stackPointer()) - size < start_) {
195 raiseWithFmt(LayoutId::kRecursionError, "maximum recursion depth exceeded");
196 return true;
197 }
198 uint8_t interrupt_flags = interrupt_flags_;
199 if ((interrupt_flags & kSignal) != 0 &&
200 !runtime_->handlePendingSignals(this).isNoneType()) {
201 return true;
202 }
203 if (interrupt_flags & kReinitInterpreter) {
204 clearInterrupt(kReinitInterpreter);
205 runtime_->interpreter()->setupThread(this);
206 }
207 return false;
208}
209
210void Thread::handleInterruptWithFrame() {
211 if ((interrupt_flags_ & kProfile) != 0) {
212 profiling_call(this);
213 }
214}
215
216void Thread::linkFrame(Frame* frame) {
217 frame->setPreviousFrame(current_frame_);
218 current_frame_ = frame;
219}
220
221inline Frame* Thread::openAndLinkFrame(word size, word locals_offset) {
222 // Initialize the frame.
223 byte* new_sp = reinterpret_cast<byte*>(stack_pointer_) - size;
224 stack_pointer_ = reinterpret_cast<RawObject*>(new_sp);
225 Frame* frame = reinterpret_cast<Frame*>(new_sp);
226 frame->setLocalsOffset(locals_offset);
227
228 // return a pointer to the base of the frame
229 linkFrame(frame);
230 DCHECK(frame->isInvalid() == nullptr, "invalid frame");
231 return frame;
232}
233
234ALWAYS_INLINE Frame* Thread::pushNativeFrameImpl(word locals_offset) {
235 return openAndLinkFrame(Frame::kSize, locals_offset);
236}
237
238NEVER_INLINE Frame* Thread::handleInterruptPushNativeFrame(word locals_offset) {
239 if (handleInterrupt(Frame::kSize)) {
240 return nullptr;
241 }
242 Frame* result = pushNativeFrameImpl(locals_offset);
243 handleInterruptWithFrame();
244 return result;
245}
246
247Frame* Thread::pushNativeFrame(word nargs) {
248 word locals_offset = Frame::kSize + nargs * kPointerSize;
249 if (UNLIKELY(wouldStackOverflow(Frame::kSize))) {
250 return handleInterruptPushNativeFrame(locals_offset);
251 }
252 return pushNativeFrameImpl(locals_offset);
253}
254
255ALWAYS_INLINE Frame* Thread::pushCallFrameImpl(RawFunction function,
256 word stack_size,
257 word locals_offset) {
258 Frame* result = openAndLinkFrame(stack_size, locals_offset);
259 result->setBytecode(MutableBytes::cast(function.rewrittenBytecode()));
260 result->setCaches(function.caches());
261 result->setVirtualPC(0);
262 result->setBlockStackDepthReturnMode(0);
263 return result;
264}
265
266NEVER_INLINE Frame* Thread::handleInterruptPushCallFrame(
267 RawFunction function, word max_stack_size, word initial_stack_size,
268 word locals_offset) {
269 if (handleInterrupt(max_stack_size)) {
270 return nullptr;
271 }
272 Frame* result =
273 pushCallFrameImpl(function, initial_stack_size, locals_offset);
274 handleInterruptWithFrame();
275 return result;
276}
277
278Frame* Thread::pushCallFrame(RawFunction function) {
279 word initial_stack_size = Frame::kSize + function.totalVars() * kPointerSize;
280 word stack_size = SmallInt::cast(function.stacksizeOrBuiltin()).value();
281 word max_stack_size = initial_stack_size + stack_size * kPointerSize;
282 word locals_offset = initial_stack_size + function.totalArgs() * kPointerSize;
283 if (UNLIKELY(wouldStackOverflow(max_stack_size))) {
284 return handleInterruptPushCallFrame(function, max_stack_size,
285 initial_stack_size, locals_offset);
286 }
287 return pushCallFrameImpl(function, initial_stack_size, locals_offset);
288}
289
290ALWAYS_INLINE Frame* Thread::pushGeneratorFrameImpl(
291 const GeneratorFrame& generator_frame, word size) {
292 word max_stack_size = generator_frame.maxStackSize();
293 word stack_size = generator_frame.stackSize();
294 word unused_stack = max_stack_size - stack_size;
295 size -= unused_stack * kPointerSize;
296 byte* src = reinterpret_cast<byte*>(generator_frame.address() +
297 RawGeneratorFrame::kFrameOffset +
298 unused_stack * kPointerSize);
299 byte* dest = reinterpret_cast<byte*>(stack_pointer_) - size;
300 std::memcpy(dest, src, size);
301 Frame* result = reinterpret_cast<Frame*>(dest + stack_size * kPointerSize);
302 setStackPointer(reinterpret_cast<RawObject*>(dest));
303 linkFrame(result);
304 DCHECK(result->isInvalid() == nullptr, "invalid frame");
305 return result;
306}
307
308NEVER_INLINE Frame* Thread::handleInterruptPushGeneratorFrame(
309 const GeneratorFrame& generator_frame, word size) {
310 if (handleInterrupt(size)) {
311 return nullptr;
312 }
313 Frame* result = pushGeneratorFrameImpl(generator_frame, size);
314 handleInterruptWithFrame();
315 return result;
316}
317
318Frame* Thread::pushGeneratorFrame(const GeneratorFrame& generator_frame) {
319 word num_frame_words = generator_frame.numFrameWords();
320 word size = num_frame_words * kPointerSize;
321 if (UNLIKELY(wouldStackOverflow(size))) {
322 return handleInterruptPushGeneratorFrame(generator_frame, size);
323 }
324 return pushGeneratorFrameImpl(generator_frame, size);
325}
326
327Frame* Thread::pushInitialFrame() {
328 byte* sp = end_ - Frame::kSize;
329 CHECK(sp > start_, "no space for initial frame");
330 Frame* frame = reinterpret_cast<Frame*>(sp);
331 frame->setLocalsOffset(Frame::kSize);
332 stack_pointer_ = reinterpret_cast<RawObject*>(sp);
333 frame->setPreviousFrame(nullptr);
334 return frame;
335}
336
337Frame* Thread::popFrameToGeneratorFrame(const GeneratorFrame& generator_frame) {
338 word max_stack_size = generator_frame.maxStackSize();
339 word stack_size = valueStackSize();
340 word unused_stack = max_stack_size - stack_size;
341 DCHECK(stack_size <= max_stack_size,
342 "not enough space in RawGeneratorBase to save live stack");
343 byte* dest = reinterpret_cast<byte*>(generator_frame.address() +
344 RawGeneratorFrame::kFrameOffset +
345 unused_stack * kPointerSize);
346 byte* src = reinterpret_cast<byte*>(valueStackBase() - stack_size);
347 word copy_size =
348 (generator_frame.numFrameWords() - unused_stack) * kPointerSize;
349 std::memcpy(dest, src, copy_size);
350 generator_frame.setStackSize(stack_size);
351 return popFrame();
352}
353
354RawObject Thread::exec(const Code& code, const Module& module,
355 const Object& implicit_globals) {
356 HandleScope scope(this);
357 Object qualname(&scope, code.name());
358
359 if (code.hasOptimizedOrNewlocals()) {
360 UNIMPLEMENTED("exec() on code with CO_OPTIMIZED / CO_NEWLOCALS");
361 }
362
363 Runtime* runtime = this->runtime();
364 Object builtins_module_obj(&scope,
365 moduleAtById(this, module, ID(__builtins__)));
366 if (builtins_module_obj.isErrorNotFound()) {
367 Module builtins(&scope, runtime->findModuleById(ID(builtins)));
368 DCHECK(!builtins.isErrorNotFound(), "invalid builtins module");
369 Object proxy(&scope, builtins.moduleProxy());
370 moduleAtPutById(this, module, ID(__builtins__), proxy);
371 }
372 Function function(&scope,
373 runtime->newFunctionWithCode(this, qualname, code, module));
374 return callFunctionWithImplicitGlobals(function, implicit_globals);
375}
376
377RawObject Thread::callFunctionWithImplicitGlobals(
378 const Function& function, const Object& implicit_globals) {
379 CHECK(!function.hasOptimizedOrNewlocals(),
380 "function must not have CO_OPTIMIZED or CO_NEWLOCALS");
381
382 // Push implicit globals and function.
383 stackPush(*implicit_globals);
384 stackPush(*function);
385 Frame* frame = pushCallFrame(*function);
386 if (frame == nullptr) {
387 return Error::exception();
388 }
389 if (function.hasFreevarsOrCellvars()) {
390 processFreevarsAndCellvars(this, frame);
391 }
392 RawObject result = Interpreter::execute(this);
393 DCHECK(stackTop() == *implicit_globals, "stack mismatch");
394 stackDrop(1);
395 return result;
396}
397
398RawObject Thread::invokeMethod1(const Object& receiver, SymbolId selector) {
399 HandleScope scope(this);
400 Object method(&scope, Interpreter::lookupMethod(this, receiver, selector));
401 if (method.isError()) return *method;
402 return Interpreter::callMethod1(this, method, receiver);
403}
404
405RawObject Thread::invokeMethod2(const Object& receiver, SymbolId selector,
406 const Object& arg1) {
407 HandleScope scope(this);
408 Object method(&scope, Interpreter::lookupMethod(this, receiver, selector));
409 if (method.isError()) return *method;
410 return Interpreter::callMethod2(this, method, receiver, arg1);
411}
412
413RawObject Thread::invokeMethod3(const Object& receiver, SymbolId selector,
414 const Object& arg1, const Object& arg2) {
415 HandleScope scope(this);
416 Object method(&scope, Interpreter::lookupMethod(this, receiver, selector));
417 if (method.isError()) return *method;
418 return Interpreter::callMethod3(this, method, receiver, arg1, arg2);
419}
420
421RawObject Thread::invokeMethodStatic1(LayoutId type, SymbolId method_name,
422 const Object& receiver) {
423 HandleScope scope(this);
424 Object type_obj(&scope, runtime()->typeAt(type));
425 if (type_obj.isError()) return *type_obj;
426 Type type_handle(&scope, *type_obj);
427 Object method(&scope, typeLookupInMroById(this, *type_handle, method_name));
428 if (method.isError()) return *method;
429 return Interpreter::callMethod1(this, method, receiver);
430}
431
432RawObject Thread::invokeMethodStatic2(LayoutId type, SymbolId method_name,
433 const Object& receiver,
434 const Object& arg1) {
435 HandleScope scope(this);
436 Object type_obj(&scope, runtime()->typeAt(type));
437 if (type_obj.isError()) return *type_obj;
438 Type type_handle(&scope, *type_obj);
439 Object method(&scope, typeLookupInMroById(this, *type_handle, method_name));
440 if (method.isError()) return *method;
441 return Interpreter::callMethod2(this, method, receiver, arg1);
442}
443
444RawObject Thread::invokeMethodStatic3(LayoutId type, SymbolId method_name,
445 const Object& receiver,
446 const Object& arg1, const Object& arg2) {
447 HandleScope scope(this);
448 Object type_obj(&scope, runtime()->typeAt(type));
449 if (type_obj.isError()) return *type_obj;
450 Type type_handle(&scope, *type_obj);
451 Object method(&scope, typeLookupInMroById(this, *type_handle, method_name));
452 if (method.isError()) return *method;
453 return Interpreter::callMethod3(this, method, receiver, arg1, arg2);
454}
455
456RawObject Thread::invokeMethodStatic4(LayoutId type, SymbolId method_name,
457 const Object& receiver,
458 const Object& arg1, const Object& arg2,
459 const Object& arg3) {
460 HandleScope scope(this);
461 Object type_obj(&scope, runtime()->typeAt(type));
462 if (type_obj.isError()) return *type_obj;
463 Type type_handle(&scope, *type_obj);
464 Object method(&scope, typeLookupInMroById(this, *type_handle, method_name));
465 if (method.isError()) return *method;
466 return Interpreter::callMethod4(this, method, receiver, arg1, arg2, arg3);
467}
468
469RawObject Thread::invokeFunction0(SymbolId module, SymbolId name) {
470 HandleScope scope(this);
471 Object func(&scope, runtime()->lookupNameInModule(this, module, name));
472 if (func.isError()) return *func;
473 return Interpreter::call0(this, func);
474}
475
476RawObject Thread::invokeFunction1(SymbolId module, SymbolId name,
477 const Object& arg1) {
478 HandleScope scope(this);
479 Object func(&scope, runtime()->lookupNameInModule(this, module, name));
480 if (func.isError()) return *func;
481 return Interpreter::call1(this, func, arg1);
482}
483
484RawObject Thread::invokeFunction2(SymbolId module, SymbolId name,
485 const Object& arg1, const Object& arg2) {
486 HandleScope scope(this);
487 Object func(&scope, runtime()->lookupNameInModule(this, module, name));
488 if (func.isError()) return *func;
489 return Interpreter::call2(this, func, arg1, arg2);
490}
491
492RawObject Thread::invokeFunction3(SymbolId module, SymbolId name,
493 const Object& arg1, const Object& arg2,
494 const Object& arg3) {
495 HandleScope scope(this);
496 Object func(&scope, runtime()->lookupNameInModule(this, module, name));
497 if (func.isError()) return *func;
498 return Interpreter::call3(this, func, arg1, arg2, arg3);
499}
500
501RawObject Thread::invokeFunction4(SymbolId module, SymbolId name,
502 const Object& arg1, const Object& arg2,
503 const Object& arg3, const Object& arg4) {
504 HandleScope scope(this);
505 Object func(&scope, runtime()->lookupNameInModule(this, module, name));
506 if (func.isError()) return *func;
507 return Interpreter::call4(this, func, arg1, arg2, arg3, arg4);
508}
509
510RawObject Thread::invokeFunction5(SymbolId module, SymbolId name,
511 const Object& arg1, const Object& arg2,
512 const Object& arg3, const Object& arg4,
513 const Object& arg5) {
514 HandleScope scope(this);
515 Object func(&scope, runtime()->lookupNameInModule(this, module, name));
516 if (func.isError()) return *func;
517 return Interpreter::call5(this, func, arg1, arg2, arg3, arg4, arg5);
518}
519
520RawObject Thread::invokeFunction6(SymbolId module, SymbolId name,
521 const Object& arg1, const Object& arg2,
522 const Object& arg3, const Object& arg4,
523 const Object& arg5, const Object& arg6) {
524 HandleScope scope(this);
525 Object func(&scope, runtime()->lookupNameInModule(this, module, name));
526 if (func.isError()) return *func;
527 return Interpreter::call6(this, func, arg1, arg2, arg3, arg4, arg5, arg6);
528}
529
530RawObject Thread::raise(LayoutId type, RawObject value) {
531 return raiseWithType(runtime()->typeAt(type), value);
532}
533
534RawObject Thread::raiseWithType(RawObject type, RawObject value) {
535 DCHECK(!hasPendingException(), "unhandled exception lingering");
536 HandleScope scope(this);
537 Type type_obj(&scope, type);
538 Object value_obj(&scope, value);
539 Object traceback_obj(&scope, NoneType::object());
540 // If raise is called with an exception instance use the original traceback
541 if (runtime()->isInstanceOfBaseException(*value_obj)) {
542 traceback_obj = value_obj.rawCast<RawBaseException>().traceback();
543 }
544
545 value_obj = chainExceptionContext(type_obj, value_obj);
546 if (value_obj.isErrorException()) return Error::exception();
547
548 setPendingExceptionType(*type_obj);
549 setPendingExceptionValue(*value_obj);
550 setPendingExceptionTraceback(*traceback_obj);
551 return Error::exception();
552}
553
554RawObject Thread::chainExceptionContext(const Type& type, const Object& value) {
555 HandleScope scope(this);
556 Object caught_exc_state_obj(&scope, topmostCaughtExceptionState());
557 if (caught_exc_state_obj.isNoneType()) {
558 return *value;
559 }
560 ExceptionState caught_exc_state(&scope, *caught_exc_state_obj);
561
562 Object fixed_value(&scope, *value);
563 if (!runtime()->isInstanceOfBaseException(*value)) {
564 // Perform partial normalization before attempting to set __context__.
565 fixed_value = createException(this, type, value);
566 if (fixed_value.isError()) return *fixed_value;
567 }
568
569 // Avoid creating cycles by breaking any link from caught_value to value
570 // before setting value's __context__.
571 BaseException caught_value(&scope, caught_exc_state.value());
572 if (*fixed_value == *caught_value) return *fixed_value;
573 BaseException exc(&scope, *caught_value);
574 Object context(&scope, NoneType::object());
575 while (!(context = exc.context()).isNoneType()) {
576 if (*context == *fixed_value) {
577 exc.setContext(Unbound::object());
578 break;
579 }
580 exc = *context;
581 }
582
583 BaseException(&scope, *fixed_value).setContext(*caught_value);
584 return *fixed_value;
585}
586
587RawObject Thread::raiseWithFmt(LayoutId type, const char* fmt, ...) {
588 va_list args;
589 va_start(args, fmt);
590 HandleScope scope(this);
591 Object message(&scope, runtime()->newStrFromFmtV(this, fmt, args));
592 va_end(args);
593 return raise(type, *message);
594}
595
596RawObject Thread::raiseWithFmtChainingPendingAsCause(LayoutId type,
597 const char* fmt, ...) {
598 HandleScope scope(this);
599
600 va_list args;
601 va_start(args, fmt);
602 Object message(&scope, runtime()->newStrFromFmtV(this, fmt, args));
603 va_end(args);
604
605 Object pending_type(&scope, pendingExceptionType());
606 Object pending_value(&scope, pendingExceptionValue());
607 Object pending_traceback(&scope, pendingExceptionTraceback());
608 clearPendingException();
609 normalizeException(this, &pending_type, &pending_value, &pending_traceback);
610
611 Type new_exc_type(&scope, runtime()->typeAt(type));
612 BaseException new_exc(&scope, createException(this, new_exc_type, message));
613 new_exc.setCause(*pending_value);
614 new_exc.setContext(*pending_value);
615 setPendingExceptionType(*new_exc_type);
616 setPendingExceptionValue(*new_exc);
617 setPendingExceptionTraceback(NoneType::object());
618 return Error::exception();
619}
620
621// Convenience method for throwing a binary-operation-specific TypeError
622// exception with an error message.
623RawObject Thread::raiseUnsupportedBinaryOperation(
624 const Handle<RawObject>& left, const Handle<RawObject>& right,
625 SymbolId op_name) {
626 return raiseWithFmt(LayoutId::kTypeError, "%T.%Y(%T) is not supported", &left,
627 op_name, &right);
628}
629
630void Thread::raiseBadArgument() {
631 raiseWithFmt(LayoutId::kTypeError,
632 "bad argument type for built-in operation");
633}
634
635RawObject Thread::raiseBadInternalCall() {
636 return raiseWithFmt(LayoutId::kSystemError,
637 "bad argument to internal function");
638}
639
640RawObject Thread::raiseMemoryError() {
641 return raise(LayoutId::kMemoryError, NoneType::object());
642}
643
644RawObject Thread::raiseOSErrorFromErrno(int errno_value) {
645 HandleScope scope(this);
646 Object type(&scope, runtime()->typeAt(LayoutId::kOSError));
647 NoneType none(&scope, NoneType::object());
648 return raiseFromErrnoWithFilenames(type, errno_value, none, none);
649}
650
651RawObject Thread::raiseFromErrnoWithFilenames(const Object& type,
652 int errno_value,
653 const Object& filename0,
654 const Object& filename1) {
655 HandleScope scope(this);
656 if (errno_value == EINTR) {
657 Object result(&scope, runtime_->handlePendingSignals(this));
658 if (result.isErrorException()) return *result;
659 }
660
661 stackPush(*type);
662 stackPush(SmallInt::fromWord(errno_value));
663 stackPush(errno_value == 0
664 ? runtime_->symbols()->at(ID(Error))
665 : Runtime::internStrFromCStr(this, std::strerror(errno_value)));
666 word nargs = 2;
667 if (!filename0.isNoneType()) {
668 stackPush(*filename0);
669 ++nargs;
670 if (!filename1.isNoneType()) {
671 stackPush(SmallInt::fromWord(0));
672 stackPush(*filename1);
673 nargs += 2;
674 }
675 } else {
676 DCHECK(filename1.isNoneType(), "expected filename1 to be None");
677 }
678 Object exception(&scope, Interpreter::call(this, nargs));
679 if (exception.isErrorException()) return *exception;
680 return raiseWithType(runtime_->typeOf(*exception), *exception);
681}
682
683RawObject Thread::raiseRequiresType(const Object& obj, SymbolId expected_type) {
684 HandleScope scope(this);
685 Function function(&scope, currentFrame()->function());
686 Str function_name(&scope, function.name());
687 return raiseWithFmt(LayoutId::kTypeError,
688 "'%S' for '%Y' objects doesn't apply to a '%T' object",
689 &function_name, expected_type, &obj);
690}
691
692RawObject Thread::raiseStopAsyncIteration() {
693 return raise(LayoutId::kStopAsyncIteration, NoneType::object());
694}
695
696RawObject Thread::raiseStopIteration() {
697 return raise(LayoutId::kStopIteration, NoneType::object());
698}
699
700RawObject Thread::raiseStopIterationWithValue(const Object& value) {
701 if (runtime()->isInstanceOfTuple(*value) ||
702 runtime()->isInstanceOfBaseException(*value)) {
703 // TODO(T67598788): Remove this special case. For now this works around
704 // the behavior of normalizeException() when it's called in
705 // Interpreter::unwind() as part of returning values from generators. Our
706 // desired end-state is StopIterations will be treated as a special
707 // optimized path which, among other properties, are not processed by
708 // normalization.
709 HandleScope scope(this);
710 Layout layout(&scope, runtime()->layoutAt(LayoutId::kStopIteration));
711 StopIteration stop_iteration(&scope, runtime()->newInstance(layout));
712 stop_iteration.setArgs(runtime()->newTupleWith1(value));
713 stop_iteration.setValue(*value);
714 stop_iteration.setCause(Unbound::object());
715 stop_iteration.setContext(Unbound::object());
716 stop_iteration.setTraceback(Unbound::object());
717 stop_iteration.setSuppressContext(RawBool::falseObj());
718 return raise(LayoutId::kStopIteration, *stop_iteration);
719 }
720 return raise(LayoutId::kStopIteration, *value);
721}
722
723bool Thread::hasPendingException() { return !pending_exc_type_.isNoneType(); }
724
725bool Thread::hasPendingStopIteration() {
726 if (pending_exc_type_.isType()) {
727 return Type::cast(pending_exc_type_).builtinBase() ==
728 LayoutId::kStopIteration;
729 }
730 if (runtime()->isInstanceOfType(pending_exc_type_)) {
731 HandleScope scope(this);
732 Type type(&scope, pending_exc_type_);
733 return type.builtinBase() == LayoutId::kStopIteration;
734 }
735 return false;
736}
737
738bool Thread::clearPendingStopIteration() {
739 if (hasPendingStopIteration()) {
740 clearPendingException();
741 return true;
742 }
743 return false;
744}
745
746RawObject Thread::pendingStopIterationValue() {
747 DCHECK(hasPendingStopIteration(),
748 "Shouldn't be called without a pending StopIteration");
749
750 HandleScope scope(this);
751 Object exc_value(&scope, pendingExceptionValue());
752 if (runtime()->isInstanceOfStopIteration(*exc_value)) {
753 StopIteration si(&scope, *exc_value);
754 return si.value();
755 }
756 if (runtime()->isInstanceOfTuple(*exc_value)) {
757 return tupleUnderlying(*exc_value).at(0);
758 }
759 return *exc_value;
760}
761
762void Thread::ignorePendingException() {
763 if (!hasPendingException()) {
764 return;
765 }
766 fprintf(stderr, "ignore pending exception");
767 if (pendingExceptionValue().isStr()) {
768 RawStr message = Str::cast(pendingExceptionValue());
769 word len = message.length();
770 byte* buffer = new byte[len + 1];
771 message.copyTo(buffer, len);
772 buffer[len] = 0;
773 fprintf(stderr, ": %s", buffer);
774 delete[] buffer;
775 }
776 fprintf(stderr, "\n");
777 clearPendingException();
778 runtime_->printTraceback(this, File::kStderr);
779}
780
781void Thread::clearPendingException() {
782 setPendingExceptionType(NoneType::object());
783 setPendingExceptionValue(NoneType::object());
784 setPendingExceptionTraceback(NoneType::object());
785}
786
787bool Thread::pendingExceptionMatches(LayoutId type) {
788 return typeIsSubclass(pendingExceptionType(), runtime()->typeAt(type));
789}
790
791void Thread::setCaughtExceptionType(RawObject type) {
792 ExceptionState::cast(caught_exc_stack_).setType(type);
793}
794
795void Thread::setCaughtExceptionValue(RawObject value) {
796 ExceptionState::cast(caught_exc_stack_).setValue(value);
797}
798
799void Thread::setCaughtExceptionTraceback(RawObject traceback) {
800 ExceptionState::cast(caught_exc_stack_).setTraceback(traceback);
801}
802
803RawObject Thread::caughtExceptionState() { return caught_exc_stack_; }
804
805void Thread::setCaughtExceptionState(RawObject state) {
806 caught_exc_stack_ = state;
807}
808
809RawObject Thread::topmostCaughtExceptionState() {
810 HandleScope scope(this);
811 Object exc_state(&scope, caught_exc_stack_);
812 while (!exc_state.isNoneType() &&
813 ExceptionState::cast(*exc_state).type().isNoneType()) {
814 exc_state = ExceptionState::cast(*exc_state).previous();
815 }
816 return *exc_state;
817}
818
819bool Thread::isErrorValueOk(RawObject obj) {
820 return (!obj.isError() && !hasPendingException()) ||
821 (obj.isErrorException() && hasPendingException());
822}
823
824void Thread::visitFrames(FrameVisitor* visitor) {
825 Frame* frame = currentFrame();
826 while (!frame->isSentinel()) {
827 if (!visitor->visit(frame)) {
828 break;
829 }
830 frame = frame->previousFrame();
831 }
832}
833
834void Thread::enableProfiling() { interrupt(kProfile); }
835
836void Thread::disableProfiling() { clearInterrupt(kProfile); }
837
838RawObject Thread::reprEnter(const Object& obj) {
839 HandleScope scope(this);
840 if (api_repr_list_.isNoneType()) {
841 api_repr_list_ = runtime_->newList();
842 }
843 List list(&scope, api_repr_list_);
844 for (word i = list.numItems() - 1; i >= 0; i--) {
845 if (list.at(i) == *obj) {
846 return RawBool::trueObj();
847 }
848 }
849 // TODO(emacs): When there is better error handling, raise an exception.
850 runtime_->listAdd(this, list, obj);
851 return RawBool::falseObj();
852}
853
854void Thread::reprLeave(const Object& obj) {
855 HandleScope scope(this);
856 List list(&scope, api_repr_list_);
857 for (word i = list.numItems() - 1; i >= 0; i--) {
858 if (list.at(i) == *obj) {
859 list.atPut(i, Unbound::object());
860 break;
861 }
862 }
863}
864
865word Thread::strOffset(const Str& str, word index) {
866 if (str != str_offset_str_) {
867 str_offset_str_ = *str;
868 str_offset_index_ = index;
869 str_offset_offset_ = str.offsetByCodePoints(0, index);
870 return str_offset_offset_;
871 }
872 word index_diff = index - str_offset_index_;
873 word offset = str.offsetByCodePoints(str_offset_offset_, index_diff);
874 if (0 <= offset && offset < str.length()) {
875 str_offset_index_ = index;
876 str_offset_offset_ = offset;
877 }
878 return offset;
879}
880
881} // namespace py