this repo has no description
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com)
2#include "runtime.h"
3
4#include <unistd.h>
5
6#include <cinttypes>
7#include <climits>
8#include <csignal>
9#include <cstdarg>
10#include <cstdio>
11#include <cstdlib>
12#include <cstring>
13#include <cwchar>
14#include <fstream>
15#include <memory>
16
17#include "array-module.h"
18#include "attributedict.h"
19#include "builtins-module.h"
20#include "bytearray-builtins.h"
21#include "bytecode.h"
22#include "bytes-builtins.h"
23#include "byteslike.h"
24#include "capi.h"
25#include "code-builtins.h"
26#include "complex-builtins.h"
27#include "descriptor-builtins.h"
28#include "dict-builtins.h"
29#include "event.h"
30#include "exception-builtins.h"
31#include "file.h"
32#include "float-builtins.h"
33#include "formatter-utils.h"
34#include "frame-proxy-builtins.h"
35#include "frame.h"
36#include "function-builtins.h"
37#include "generator-builtins.h"
38#include "globals.h"
39#include "handles.h"
40#include "heap.h"
41#include "int-builtins.h"
42#include "interpreter.h"
43#include "iterator-builtins.h"
44#include "layout-builtins.h"
45#include "layout.h"
46#include "list-builtins.h"
47#include "mappingproxy-builtins.h"
48#include "memoryview-builtins.h"
49#include "mmap-module.h"
50#include "module-builtins.h"
51#include "module-proxy-builtins.h"
52#include "modules.h"
53#include "mutex.h"
54#include "object-builtins.h"
55#include "os.h"
56#include "range-builtins.h"
57#include "ref-builtins.h"
58#include "scavenger.h"
59#include "set-builtins.h"
60#include "siphash.h"
61#include "slice-builtins.h"
62#include "str-builtins.h"
63#include "str-intern.h"
64#include "strarray-builtins.h"
65#include "super-builtins.h"
66#include "sys-module.h"
67#include "thread.h"
68#include "traceback-builtins.h"
69#include "tuple-builtins.h"
70#include "type-builtins.h"
71#include "under-collections-module.h"
72#include "under-contextvars-module.h"
73#include "under-io-module.h"
74#include "under-signal-module.h"
75#include "unicode.h"
76#include "utils.h"
77#include "valuecell-builtins.h"
78#include "visitor.h"
79
80namespace py {
81
82static const SymbolId kRequiredModules[] = {
83 ID(_builtins), ID(builtins), ID(operator),
84 ID(_codecs), ID(_signal), ID(_frozen_importlib_external)};
85
86word Runtime::next_module_index_ = 0;
87
88wchar_t Runtime::exec_prefix_[PATH_MAX + 1] = L"";
89wchar_t Runtime::module_search_path_[PATH_MAX + 1] = L"";
90wchar_t Runtime::prefix_[PATH_MAX + 1] = L"";
91wchar_t Runtime::program_name_[NAME_MAX + 1] = L"python3";
92
93wchar_t* Runtime::programName() { return program_name_; }
94
95void Runtime::setExecPrefix(const wchar_t* exec_prefix) {
96 DCHECK(wcslen(exec_prefix) < ARRAYSIZE(exec_prefix_),
97 "exec_prefix is too long");
98 std::wcsncpy(exec_prefix_, exec_prefix, ARRAYSIZE(exec_prefix_));
99 exec_prefix_[ARRAYSIZE(exec_prefix_) - 1] = L'\0';
100}
101
102void Runtime::setModuleSearchPath(const wchar_t* module_search_path) {
103 DCHECK(wcslen(module_search_path) < ARRAYSIZE(module_search_path_),
104 "module_search_path is too long");
105 std::wcsncpy(module_search_path_, module_search_path,
106 ARRAYSIZE(module_search_path_));
107 module_search_path_[ARRAYSIZE(module_search_path_) - 1] = L'\0';
108}
109
110void Runtime::setPrefix(const wchar_t* prefix) {
111 DCHECK(wcslen(prefix) < ARRAYSIZE(module_search_path_), "prefix is too long");
112 std::wcsncpy(prefix_, prefix, ARRAYSIZE(prefix_));
113 prefix_[ARRAYSIZE(prefix_) - 1] = L'\0';
114}
115
116void Runtime::setProgramName(const wchar_t* program_name) {
117 DCHECK(wcslen(program_name) < ARRAYSIZE(program_name_),
118 "program_name is too long");
119 std::wcsncpy(program_name_, program_name, ARRAYSIZE(program_name_));
120 prefix_[ARRAYSIZE(program_name_) - 1] = L'\0';
121}
122
123RandomState randomState() {
124 RandomState result;
125 OS::secureRandom(reinterpret_cast<byte*>(&result), sizeof(result));
126 return result;
127}
128
129RandomState randomStateFromSeed(uint64_t seed) {
130 // Splitmix64 as suggested by http://xoshiro.di.unimi.it.
131 auto next = [&seed]() {
132 uint64_t z = (seed += 0x9e3779b97f4a7c15);
133 z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9;
134 z = (z ^ (z >> 27)) * 0x94d049bb133111eb;
135 return z ^ (z >> 31);
136 };
137 RandomState result;
138 for (size_t i = 0; i < ARRAYSIZE(result.state); i++) {
139 result.state[i] = next();
140 }
141 result.siphash24_secret = next();
142 for (size_t i = 0; i < ARRAYSIZE(result.extra_secret); i++) {
143 result.extra_secret[i] = next();
144 }
145 return result;
146}
147
148Runtime::Runtime(word heap_size, Interpreter* interpreter,
149 RandomState random_seed, StdioState stdio_state)
150 : heap_(heap_size),
151 interpreter_(interpreter),
152 random_state_(random_seed),
153 stdio_state_(stdio_state) {
154 Thread* thread = newThread();
155 thread->begin();
156 // This must be called before initializeTypes is called. Methods in
157 // initializeTypes rely on instances that are created in this method.
158 initializePrimitiveInstances();
159 initializeInterned(thread);
160 initializeSymbols(thread);
161 initializeLayouts();
162 initializeTypes(thread);
163 initializeCAPIState(this);
164 initializeModules(thread);
165 initializeCAPIModules();
166 initializeJITState();
167
168 // This creates a reference that prevents the linker from garbage collecting
169 // all of the symbols in debugging.cpp. This is a temporary workaround until
170 // we can fix the build to prevent symbols in debugging.cpp from being GCed.
171 extern void initializeDebugging();
172 initializeDebugging();
173}
174
175Runtime::~Runtime() {
176 is_finalizing_ = true;
177 // TODO(T30392425): This is an ugly and fragile workaround for having multiple
178 // runtimes created and destroyed by a single thread.
179 if (Thread::current() == nullptr) {
180 CHECK(main_thread_ != nullptr, "the runtime does not have any threads");
181 Thread::setCurrentThread(main_thread_);
182 }
183 callAtExit();
184 flushStdFiles();
185 finalizeSignals(Thread::current());
186 clearHandleScopes();
187 finalizeCAPIModules();
188 freeApiHandles();
189 finalizeCAPIState(this);
190 {
191 MutexGuard lock(&threads_mutex_);
192 Thread* thread = main_thread_;
193 Thread::setCurrentThread(nullptr);
194 main_thread_ = nullptr;
195 for (Thread* next; thread != nullptr; thread = next) {
196 next = thread->next();
197 delete thread;
198 }
199 }
200 delete symbols_;
201 delete machine_code_;
202}
203
204bool Runtime::allocateForMachineCode(word size, uword* address_out) {
205 DCHECK(Utils::isAligned(size, kPointerSize), "request %ld not aligned", size);
206 if (UNLIKELY(!machine_code_->allocate(size, address_out))) {
207 UNIMPLEMENTED("out of fixed memory");
208 }
209 return true;
210}
211
212RawObject Runtime::newBoundMethod(const Object& function, const Object& self) {
213 HandleScope scope(Thread::current());
214 BoundMethod bound_method(
215 &scope, newInstanceWithSize(LayoutId::kBoundMethod, BoundMethod::kSize));
216 bound_method.setFunction(*function);
217 bound_method.setSelf(*self);
218 return *bound_method;
219}
220
221RawObject Runtime::newLayout(LayoutId id) {
222 HandleScope scope(Thread::current());
223 Layout layout(&scope, newInstanceWithSize(LayoutId::kLayout, Layout::kSize));
224 layout.setId(id);
225 layout.setInObjectAttributes(empty_tuple_);
226 layout.setAdditions(newList());
227 layout.setDeletions(newList());
228 layout.setNumInObjectAttributes(0);
229 return *layout;
230}
231
232RawObject Runtime::layoutAtSafe(LayoutId layout_id) {
233 word id = static_cast<word>(layout_id);
234 if (id < 0 || id >= num_layouts_) {
235 return Error::notFound();
236 }
237 RawObject result = Tuple::cast(layouts_).at(id);
238 if (result == SmallInt::fromWord(0)) return Error::notFound();
239 return result;
240}
241
242// Sanity check that a subclass that has fixed attributes does inherit from a
243// superclass with attributes that are fixed.
244static void checkInObjectAttributesWithFixedOffset(const Tuple& attributes) {
245 for (word i = 0; i < attributes.length(); i++) {
246 AttributeInfo info(Tuple::cast(attributes.at(i)).at(1));
247 CHECK(info.isInObject() && info.isFixedOffset(),
248 "all superclass attributes must be in-object and fixed");
249 }
250}
251
252RawObject Runtime::layoutCreateSubclassWithBuiltins(
253 Thread* thread, LayoutId subclass_id, LayoutId superclass_id,
254 View<BuiltinAttribute> attributes, word size) {
255 HandleScope scope(thread);
256
257 // A builtin class is special since it contains attributes that must be
258 // located at fixed offsets from the start of an instance. These attributes
259 // are packed at the beginning of the layout starting at offset 0.
260 Layout super_layout(&scope, layoutAt(superclass_id));
261 Tuple super_attributes(&scope, super_layout.inObjectAttributes());
262 checkInObjectAttributesWithFixedOffset(super_attributes);
263
264 word super_attributes_len = super_attributes.length();
265 word attributes_length = attributes.length();
266 CHECK((attributes_length + super_attributes_len) * kPointerSize == size,
267 "Object size does not match attribute count");
268 for (word i = 0; i < attributes_length; i++) {
269 CHECK(attributes.get(i).offset == (i + super_attributes_len) * kPointerSize,
270 "unexpected attribute offset (not sorted or duplicated?)");
271 }
272
273 // Create an empty layout for the subclass
274 Layout result(&scope, newLayout(subclass_id));
275
276 // Copy down all of the superclass attributes into the subclass layout
277 result.setOverflowAttributes(super_layout.overflowAttributes());
278 word in_object_len = super_attributes_len + attributes_length;
279 if (in_object_len == 0) {
280 result.setInObjectAttributes(emptyTuple());
281 result.setNumInObjectAttributes(0);
282 } else {
283 MutableTuple in_object(&scope, newMutableTuple(in_object_len));
284 in_object.replaceFromWith(0, *super_attributes, super_attributes_len);
285 appendBuiltinAttributes(thread, attributes, in_object,
286 super_attributes_len);
287
288 // Install the in-object attributes
289 result.setInObjectAttributes(in_object.becomeImmutable());
290 result.setNumInObjectAttributes(in_object_len);
291 }
292
293 return *result;
294}
295
296void Runtime::appendBuiltinAttributes(Thread* thread,
297 View<BuiltinAttribute> attributes,
298 const MutableTuple& dst,
299 word start_index) {
300 if (attributes.length() == 0) {
301 return;
302 }
303 HandleScope scope(thread);
304 Object name(&scope, NoneType::object());
305 for (word i = 0; i < attributes.length(); i++) {
306 DCHECK((attributes.get(i).flags &
307 (AttributeFlags::kInObject | AttributeFlags::kDeleted |
308 AttributeFlags::kFixedOffset)) == 0,
309 "flag not allowed");
310 AttributeInfo info(attributes.get(i).offset,
311 attributes.get(i).flags | AttributeFlags::kInObject |
312 AttributeFlags::kFixedOffset);
313 SymbolId symbol_id = attributes.get(i).name;
314 name = symbol_id == SymbolId::kInvalid
315 ? NoneType::object()
316 : static_cast<RawObject>(symbols()->at(symbol_id));
317 dst.atPut(start_index + i, layoutNewAttribute(name, info));
318 }
319}
320
321RawObject Runtime::newBytearray() {
322 HandleScope scope(Thread::current());
323 Bytearray result(&scope,
324 newInstanceWithSize(LayoutId::kBytearray, Bytearray::kSize));
325 result.setItems(empty_mutable_bytes_);
326 result.setNumItems(0);
327 return *result;
328}
329
330RawObject Runtime::newBytearrayIterator(Thread* thread,
331 const Bytearray& bytearray) {
332 HandleScope scope(thread);
333 BytearrayIterator result(&scope,
334 newInstanceWithSize(LayoutId::kBytearrayIterator,
335 BytearrayIterator::kSize));
336 result.setIterable(*bytearray);
337 result.setIndex(0);
338 return *result;
339}
340
341RawObject Runtime::createLargeBytes(word length) {
342 DCHECK(length > SmallBytes::kMaxLength, "fits into a SmallBytes");
343 word size = LargeBytes::allocationSize(length);
344 uword address;
345 CHECK(heap()->allocate(size, &address), "out of memory");
346 return LargeBytes::cast(
347 DataArray::initialize(address, length, LayoutId::kLargeBytes));
348}
349
350RawObject Runtime::createLargeInt(word num_digits) {
351 DCHECK(num_digits > 0, "num_digits must be positive");
352 word size = LargeInt::allocationSize(num_digits);
353 uword address;
354 CHECK(heap()->allocate(size, &address), "out of memory");
355 return LargeInt::cast(LargeInt::initialize(address, num_digits));
356}
357
358RawObject Runtime::createLargeStr(word length) {
359 DCHECK(length > RawSmallStr::kMaxLength,
360 "string len %ld is too small to be a large string", length);
361 word size = LargeStr::allocationSize(length);
362 uword address;
363 CHECK(heap()->allocate(size, &address), "out of memory");
364 return LargeStr::cast(
365 DataArray::initialize(address, length, LayoutId::kLargeStr));
366}
367
368RawObject Runtime::createMutableBytes(word length) {
369 DCHECK(length >= 0, "cannot allocate negative size");
370 word size = MutableBytes::allocationSize(length);
371 uword address;
372 CHECK(heap()->allocate(size, &address), "out of memory");
373 return MutableBytes::cast(
374 DataArray::initialize(address, length, LayoutId::kMutableBytes));
375}
376
377RawObject Runtime::newBytes(word length, byte fill) {
378 DCHECK(length >= 0, "invalid length %ld", length);
379 if (length <= SmallBytes::kMaxLength) {
380 byte buffer[SmallBytes::kMaxLength];
381 for (word i = 0; i < SmallBytes::kMaxLength; i++) {
382 buffer[i] = fill;
383 }
384 return SmallBytes::fromBytes({buffer, length});
385 }
386 HandleScope scope(Thread::current());
387 LargeBytes result(&scope, createLargeBytes(length));
388 std::memset(reinterpret_cast<byte*>(result.address()), fill, length);
389 return *result;
390}
391
392RawObject Runtime::newBytesWithAll(View<byte> array) {
393 word length = array.length();
394 if (length <= SmallBytes::kMaxLength) {
395 return SmallBytes::fromBytes(array);
396 }
397 HandleScope scope(Thread::current());
398 LargeBytes result(&scope, createLargeBytes(length));
399 std::memcpy(reinterpret_cast<byte*>(result.address()), array.data(), length);
400 return *result;
401}
402
403RawObject Runtime::newBytesIterator(Thread* thread, const Bytes& bytes) {
404 HandleScope scope(thread);
405 BytesIterator result(&scope, newInstanceWithSize(LayoutId::kBytesIterator,
406 BytesIterator::kSize));
407 result.setIndex(0);
408 result.setIterable(*bytes);
409 return *result;
410}
411
412RawObject Runtime::newTraceback() {
413 return newInstanceWithSize(LayoutId::kTraceback, Traceback::kSize);
414}
415
416RawObject Runtime::newType() { return newTypeWithMetaclass(LayoutId::kType); }
417
418RawObject Runtime::newTypeWithMetaclass(LayoutId metaclass_id) {
419 Thread* thread = Thread::current();
420 HandleScope scope(thread);
421 Type result(&scope, newInstanceWithSize(metaclass_id, Type::kSize));
422 attributeDictInit(thread, result);
423 result.setFlagsAndBuiltinBase(Type::Flag::kNone, LayoutId::kObject);
424 result.setDoc(NoneType::object());
425 result.setAbstractMethods(Unbound::object());
426 return *result;
427}
428
429RawObject Runtime::newTypeProxy(const Type& type) {
430 Thread* thread = Thread::current();
431 HandleScope scope(thread);
432 TypeProxy result(&scope,
433 newInstanceWithSize(LayoutId::kTypeProxy, TypeProxy::kSize));
434 result.setType(*type);
435 return *result;
436}
437
438bool Runtime::isCallable(Thread* thread, const Object& obj) {
439 HandleScope scope(thread);
440 if (obj.isFunction() || obj.isBoundMethod() || obj.isType()) {
441 return true;
442 }
443 Type type(&scope, typeOf(*obj));
444 return !typeLookupInMroById(thread, *type, ID(__call__)).isError();
445}
446
447bool Runtime::isDeleteDescriptor(Thread* thread, const Object& object) {
448 HandleScope scope(thread);
449 Type type(&scope, typeOf(*object));
450 return type.hasFlag(Type::Flag::kHasDunderDelete);
451}
452
453bool Runtime::isIterator(Thread* thread, const Object& obj) {
454 HandleScope scope(thread);
455 Type type(&scope, typeOf(*obj));
456 return !typeLookupInMroById(thread, *type, ID(__next__)).isError();
457}
458
459bool Runtime::isMapping(Thread* thread, const Object& obj) {
460 if (obj.isDict()) return true;
461 HandleScope scope(thread);
462 Type type(&scope, typeOf(*obj));
463 return !typeLookupInMroById(thread, *type, ID(__getitem__)).isError();
464}
465
466bool Runtime::isSequence(Thread* thread, const Object& obj) {
467 if (isInstanceOfDict(*obj)) {
468 return false;
469 }
470 HandleScope scope(thread);
471 Type type(&scope, typeOf(*obj));
472 return !typeLookupInMroById(thread, *type, ID(__getitem__)).isError();
473}
474
475RawObject Runtime::newCode(word argcount, word posonlyargcount,
476 word kwonlyargcount, word nlocals, word stacksize,
477 word flags, const Object& code, const Object& consts,
478 const Object& names, const Object& varnames,
479 const Object& freevars, const Object& cellvars,
480 const Object& filename, const Object& name,
481 word firstlineno, const Object& lnotab) {
482 DCHECK(code.isInt() || isInstanceOfBytes(*code), "code must be bytes or int");
483 DCHECK(isInstanceOfTuple(*consts), "expected tuple");
484 DCHECK(isInstanceOfTuple(*names), "expected tuple");
485 DCHECK(isInstanceOfTuple(*varnames), "expected tuple");
486 DCHECK(isInstanceOfTuple(*freevars), "expected tuple");
487 DCHECK(isInstanceOfTuple(*cellvars), "expected tuple");
488 DCHECK(isInstanceOfStr(*filename), "expected str");
489 DCHECK(isInstanceOfStr(*name), "expected str");
490 DCHECK(isInstanceOfBytes(*lnotab), "expected bytes");
491 DCHECK(argcount >= 0, "argcount must not be negative");
492 DCHECK(posonlyargcount >= 0, "posonlyargcount must not be negative");
493 DCHECK(kwonlyargcount >= 0, "kwonlyargcount must not be negative");
494 DCHECK(nlocals >= 0, "nlocals must not be negative");
495
496 Thread* thread = Thread::current();
497 HandleScope scope(thread);
498
499 Tuple cellvars_tuple(&scope, tupleUnderlying(*cellvars));
500 Tuple freevars_tuple(&scope, tupleUnderlying(*freevars));
501 if (cellvars_tuple.length() == 0 && freevars_tuple.length() == 0) {
502 flags |= Code::Flags::kNofree;
503 } else {
504 flags &= ~Code::Flags::kNofree;
505 }
506
507 if (!code.isInt()) {
508 Bytes code_bytes(&scope, bytesUnderlying(*code));
509 CHECK(code_bytes.length() <= kMaxUint32, "code objects must fit in 4GB");
510 }
511
512 Code result(&scope, newInstanceWithSize(LayoutId::kCode, Code::kSize));
513 result.setArgcount(argcount);
514 result.setPosonlyargcount(posonlyargcount);
515 result.setKwonlyargcount(kwonlyargcount);
516 result.setNlocals(nlocals);
517 result.setStacksize(stacksize);
518 result.setFlags(flags);
519 result.setCode(*code);
520 result.setConsts(*consts);
521 result.setNames(*names);
522 result.setVarnames(*varnames);
523 result.setFreevars(*freevars);
524 result.setCellvars(*cellvars);
525 result.setFilename(*filename);
526 result.setName(*name);
527 result.setFirstlineno(firstlineno);
528 result.setLnotab(*lnotab);
529 result.setIntrinsic(nullptr);
530
531 Tuple varnames_tuple(&scope, tupleUnderlying(*varnames));
532 if (argcount > varnames_tuple.length() ||
533 kwonlyargcount > varnames_tuple.length() ||
534 result.totalArgs() > varnames_tuple.length()) {
535 return thread->raiseWithFmt(LayoutId::kValueError,
536 "code: varnames is too small");
537 }
538
539 strInternInTuple(thread, names);
540 strInternInTuple(thread, varnames);
541 strInternInTuple(thread, freevars);
542 strInternInTuple(thread, cellvars);
543 strInternConstants(thread, consts);
544
545 // Create mapping between cells and arguments if needed
546 if (result.numCellvars() > 0) {
547 MutableTuple cell2arg(&scope, newMutableTuple(result.numCellvars()));
548 cell2arg.fill(NoneType::object());
549 bool value_set = false;
550 for (word i = 0; i < result.numCellvars(); i++) {
551 for (word j = 0; j < result.totalArgs(); j++) {
552 if (Tuple::cast(*cellvars).at(i) == Tuple::cast(*varnames).at(j)) {
553 cell2arg.atPut(i, newInt(j));
554 value_set = true;
555 }
556 }
557 }
558 if (value_set) result.setCell2arg(cell2arg.becomeImmutable());
559 }
560
561 DCHECK(result.totalArgs() <= result.nlocals(), "invalid nlocals count");
562 return *result;
563}
564
565RawObject Runtime::newBuiltinCode(word argcount, word posonlyargcount,
566 word kwonlyargcount, word flags,
567 BuiltinFunction function,
568 const Object& parameter_names,
569 const Object& name_str) {
570 void* function_ptr = bit_cast<void*>(function);
571 DCHECK((reinterpret_cast<uword>(function_ptr) &
572 (1 << Object::kSmallIntTagBits)) == 0,
573 "function must be aligned");
574 Thread* thread = Thread::current();
575 HandleScope scope(thread);
576 Tuple empty_tuple(&scope, emptyTuple());
577 Object empty_string(&scope, Str::empty());
578 Object lnotab(&scope, Bytes::empty());
579 word nlocals = argcount + kwonlyargcount +
580 ((flags & Code::Flags::kVarargs) != 0) +
581 ((flags & Code::Flags::kVarkeyargs) != 0);
582 flags |= Code::Flags::kOptimized | Code::Flags::kNewlocals;
583 Object function_int(&scope, SmallInt::fromAlignedCPtr(function_ptr));
584 return newCode(argcount, posonlyargcount, kwonlyargcount, nlocals,
585 /*stacksize=*/0, flags, /*code=*/function_int,
586 /*consts=*/empty_tuple, /*names=*/empty_tuple,
587 /*varnames=*/parameter_names, /*freevars=*/empty_tuple,
588 /*cellvars=*/empty_tuple, /*filename=*/empty_string, name_str,
589 /*firstlineno=*/0, lnotab);
590}
591
592RawObject Runtime::newFunction(Thread* thread, const Object& name,
593 const Object& code, word flags, word argcount,
594 word total_args, word total_vars,
595 const Object& stacksize_or_builtin,
596 Function::Entry entry, Function::Entry entry_kw,
597 Function::Entry entry_ex) {
598 DCHECK(isInstanceOfStr(*name), "expected str");
599
600 HandleScope scope(thread);
601 Function function(&scope,
602 newInstanceWithSize(LayoutId::kFunction, Function::kSize));
603 function.setCode(*code);
604 function.setFlags(flags);
605 function.setArgcount(argcount);
606 function.setTotalArgs(total_args);
607 function.setTotalVars(total_vars);
608 function.setStacksizeOrBuiltin(*stacksize_or_builtin);
609 function.setName(*name);
610 function.setQualname(*name);
611 function.setEntry(entry);
612 function.setEntryKw(entry_kw);
613 function.setEntryEx(entry_ex);
614 function.setIntrinsic(nullptr);
615 populateEntryAsm(function);
616 return *function;
617}
618
619RawObject Runtime::newFunctionWithCode(Thread* thread, const Object& qualname,
620 const Code& code,
621 const Object& module_obj) {
622 DCHECK(module_obj.isNoneType() ||
623 thread->runtime()->isInstanceOfModule(*module_obj),
624 "module_obj should be either None or a Module");
625 HandleScope scope(thread);
626
627 Function::Entry entry;
628 Function::Entry entry_kw;
629 Function::Entry entry_ex;
630 word flags = code.flags();
631 if (code.kwonlyargcount() == 0 && (flags & Code::Flags::kNofree) &&
632 !(flags & (Code::Flags::kVarargs | Code::Flags::kVarkeyargs))) {
633 flags |= Function::Flags::kSimpleCall;
634 }
635 word stacksize = code.stacksize();
636 Object stacksize_or_builtin(&scope, NoneType::object());
637 if (!code.hasOptimizedAndNewlocals()) {
638 // We do not support calling non-optimized functions directly. We only allow
639 // them in Thread::exec() and Thread::runClassFunction().
640 entry = unimplementedTrampoline;
641 entry_kw = unimplementedTrampoline;
642 entry_ex = unimplementedTrampoline;
643 stacksize_or_builtin = SmallInt::fromWord(stacksize);
644 } else if (code.isNative()) {
645 entry = builtinTrampoline;
646 entry_kw = builtinTrampolineKw;
647 entry_ex = builtinTrampolineEx;
648 stacksize_or_builtin = code.code();
649 DCHECK(stacksize == 0, "expected zero stacksize");
650 } else if (code.isGeneratorLike()) {
651 entry = generatorTrampoline;
652 entry_kw = generatorTrampolineKw;
653 entry_ex = generatorTrampolineEx;
654 // HACK: Reserve one extra stack slot for the case where we need to unwrap a
655 // bound method.
656 stacksize++;
657 stacksize_or_builtin = SmallInt::fromWord(stacksize);
658 } else {
659 entry = interpreterTrampoline;
660 entry_kw = interpreterTrampolineKw;
661 entry_ex = interpreterTrampolineEx;
662 flags |= Function::Flags::kInterpreted;
663 // HACK: Reserve one extra stack slot for the case where we need to unwrap a
664 // bound method.
665 stacksize++;
666 stacksize_or_builtin = SmallInt::fromWord(stacksize);
667 }
668 Object name(&scope, code.name());
669 word total_args = code.totalArgs();
670 word total_vars =
671 code.nlocals() - total_args + code.numCellvars() + code.numFreevars();
672
673 Function function(
674 &scope,
675 newFunction(thread, name, code, flags, code.argcount(), total_args,
676 total_vars, stacksize_or_builtin, entry, entry_kw, entry_ex));
677 function.setIntrinsic(code.intrinsic());
678 populateEntryAsm(function);
679
680 if (isInstanceOfStr(*qualname)) {
681 function.setQualname(*qualname);
682 } else {
683 DCHECK(qualname.isNoneType(), "expected str or none type");
684 }
685
686 if (!module_obj.isNoneType()) {
687 Module module(&scope, *module_obj);
688 function.setModuleObject(*module_obj);
689 Object module_name(&scope, moduleAtById(thread, module, ID(__name__)));
690 if (!module_name.isErrorNotFound() && isInstanceOfStr(*module_name)) {
691 function.setModuleName(*module_name);
692 }
693 } else {
694 DCHECK(code.isNative(), "Only native code may have no globals");
695 }
696
697 Object consts_obj(&scope, code.consts());
698 if (consts_obj.isTuple()) {
699 Tuple consts(&scope, *consts_obj);
700 if (consts.length() >= 1 && consts.at(0).isStr()) {
701 function.setDoc(consts.at(0));
702 }
703 }
704
705 if (!code.isNative()) {
706 Bytes bytecode(&scope, code.code());
707 function.setRewrittenBytecode(expandBytecode(thread, bytecode));
708 // TODO(T45382423): Move this into a separate function to be called by a
709 // relevant opcode during opcode execution.
710 rewriteBytecode(thread, function);
711 }
712 return *function;
713}
714
715RawObject Runtime::newExceptionState() {
716 return newInstanceWithSize(LayoutId::kExceptionState, ExceptionState::kSize);
717}
718
719RawObject Runtime::newCoroutine() {
720 return newInstanceWithSize(LayoutId::kCoroutine, Coroutine::kSize);
721}
722
723RawObject Runtime::newFrameProxy(Thread* thread, const Object& function,
724 const Object& lasti) {
725 HandleScope scope(thread);
726 FrameProxy result(
727 &scope, newInstanceWithSize(LayoutId::kFrameProxy, FrameProxy::kSize));
728 result.setFunction(*function);
729 result.setLasti(*lasti);
730 return *result;
731}
732
733RawObject Runtime::newGenerator() {
734 return newInstanceWithSize(LayoutId::kGenerator, Generator::kSize);
735}
736
737RawObject Runtime::newGeneratorFrame(const Function& function) {
738 DCHECK(function.isGeneratorLike(), "expected a generator-like code object");
739
740 HandleScope scope(Thread::current());
741 word num_args = function.totalArgs();
742 word num_vars = function.totalVars();
743 word stacksize = SmallInt::cast(function.stacksizeOrBuiltin()).value();
744 // +1 for the function pointer.
745 word extra_words = num_args + num_vars + stacksize + 1;
746 GeneratorFrame frame(
747 &scope, newInstanceWithSize(
748 LayoutId::kGeneratorFrame,
749 GeneratorFrame::numAttributes(extra_words) * kPointerSize));
750 frame.setMaxStackSize(stacksize);
751 return *frame;
752}
753
754RawObject Runtime::newInstance(const Layout& layout) {
755 // This takes into account the potential overflow pointer.
756 RawInstance instance =
757 Instance::cast(newInstanceWithSize(layout.id(), layout.instanceSize()));
758 // Set the overflow array
759 if (layout.hasTupleOverflow()) {
760 instance.instanceVariableAtPut(layout.overflowOffset(), empty_tuple_);
761 }
762 return instance;
763}
764
765ALWAYS_INLINE USED RawObject Runtime::newInstanceWithSize(LayoutId layout_id,
766 word object_size) {
767 word num_attributes = object_size / kPointerSize;
768 word allocation_size = Instance::allocationSize(num_attributes);
769 uword address;
770 CHECK(heap()->allocate(allocation_size, &address), "out of memory");
771 return Instance::initializeWithNone(address, num_attributes, layout_id);
772}
773
774RawObject Runtime::newQualname(Thread* thread, const Type& type,
775 SymbolId name) {
776 HandleScope scope(thread);
777 Str type_name(&scope, type.name());
778 return newStrFromFmt("%S.%Y", &type_name, name);
779}
780
781RawObject Runtime::newDeque() {
782 HandleScope scope(Thread::current());
783 Deque deque(&scope, newInstanceWithSize(LayoutId::kDeque, Deque::kSize));
784 deque.setItems(SmallInt::fromWord(0));
785 deque.setLeft(0);
786 deque.setNumItems(0);
787 deque.setState(0);
788 return *deque;
789}
790
791RawObject Runtime::newDequeIterator(const Deque& deque, word index) {
792 HandleScope scope(Thread::current());
793 DequeIterator iter(&scope, newInstanceWithSize(LayoutId::kDequeIterator,
794 DequeIterator::kSize));
795 iter.setIndex(index);
796 iter.setIterable(*deque);
797 iter.setState(deque.state());
798 return *iter;
799}
800
801RawObject Runtime::newDequeReverseIterator(const Deque& deque, word index) {
802 HandleScope scope(Thread::current());
803 DequeReverseIterator iter(&scope,
804 newInstanceWithSize(LayoutId::kDequeReverseIterator,
805 DequeReverseIterator::kSize));
806 iter.setIndex(index);
807 iter.setIterable(*deque);
808 iter.setState(deque.state());
809 return *iter;
810}
811
812RawObject Runtime::newList() {
813 HandleScope scope(Thread::current());
814 List result(&scope, newInstanceWithSize(LayoutId::kList, List::kSize));
815 result.setNumItems(0);
816 result.setItems(empty_tuple_);
817 return *result;
818}
819
820RawObject Runtime::newListIterator(const Object& list) {
821 HandleScope scope(Thread::current());
822 ListIterator list_iterator(
823 &scope,
824 newInstanceWithSize(LayoutId::kListIterator, ListIterator::kSize));
825 list_iterator.setIndex(0);
826 list_iterator.setIterable(*list);
827 return *list_iterator;
828}
829
830RawObject Runtime::newSeqIterator(const Object& sequence) {
831 HandleScope scope(Thread::current());
832 SeqIterator iter(
833 &scope, newInstanceWithSize(LayoutId::kSeqIterator, SeqIterator::kSize));
834 iter.setIndex(0);
835 iter.setIterable(*sequence);
836 return *iter;
837}
838
839RawObject Runtime::newModule(const Object& name) {
840 Thread* thread = Thread::current();
841 HandleScope scope(thread);
842 Module result(&scope, newInstanceWithSize(LayoutId::kModule, Module::kSize));
843 attributeDictInit(thread, result);
844 result.setDef(newIntFromCPtr(nullptr));
845 result.setId(reserveModuleId());
846 Object init_result(&scope, moduleInit(thread, result, name));
847 if (init_result.isErrorException()) return *init_result;
848 return *result;
849}
850
851RawObject Runtime::newModuleProxy(const Module& module) {
852 Thread* thread = Thread::current();
853 HandleScope scope(thread);
854 ModuleProxy result(
855 &scope, newInstanceWithSize(LayoutId::kModuleProxy, ModuleProxy::kSize));
856 result.setModule(*module);
857 return *result;
858}
859
860RawObject Runtime::newSlotDescriptor(const Type& type, const Object& name) {
861 Thread* thread = Thread::current();
862 HandleScope scope(thread);
863 SlotDescriptor result(&scope, newInstanceWithSize(LayoutId::kSlotDescriptor,
864 SlotDescriptor::kSize));
865 result.setType(*type);
866 result.setName(*name);
867 return *result;
868}
869
870RawObject Runtime::newMemoryView(Thread* thread, const Object& obj,
871 const Object& buffer, word length,
872 ReadOnly read_only) {
873 HandleScope scope(thread);
874 MemoryView result(
875 &scope, newInstanceWithSize(LayoutId::kMemoryView, MemoryView::kSize));
876 result.setBuffer(*buffer);
877 result.setObject(*obj);
878 result.setLength(length);
879 result.setFormat(RawSmallStr::fromCodePoint('B'));
880 result.setReadOnly(read_only == ReadOnly::ReadOnly);
881 result.setStart(0);
882 Object length_obj(&scope, SmallInt::fromWord(length));
883 result.setShape(newTupleWith1(length_obj));
884 Object one(&scope, SmallInt::fromWord(1));
885 result.setNdim(*one);
886 result.setStrides(newTupleWith1(one));
887 return *result;
888}
889
890RawObject Runtime::newMemoryViewFromCPtr(Thread* thread, const Object& obj,
891 void* ptr, word length,
892 ReadOnly read_only) {
893 HandleScope scope(thread);
894 Object pointer(&scope, newPointer(ptr, length));
895 return newMemoryView(thread, obj, pointer, length, read_only);
896}
897
898RawObject Runtime::newMmap() {
899 HandleScope scope(Thread::current());
900 Mmap result(&scope, newInstanceWithSize(LayoutId::kMmap, Mmap::kSize));
901 result.setAccess(0);
902 result.setData(NoneType::object());
903 result.setFd(NoneType::object());
904 return *result;
905}
906
907RawObject Runtime::newMutableBytesZeroed(word size) {
908 if (size == 0) {
909 return empty_mutable_bytes_;
910 }
911 return createMutableBytes(size);
912}
913
914RawObject Runtime::mutableBytesFromBytes(Thread* thread, const Bytes& bytes) {
915 HandleScope scope(thread);
916 word len = bytes.length();
917 MutableBytes mb(&scope, createMutableBytes(len));
918 bytes.copyTo(reinterpret_cast<byte*>(mb.address()), len);
919 return *mb;
920}
921
922RawObject Runtime::mutableBytesWith(word length, byte value) {
923 if (length == 0) return empty_mutable_bytes_;
924 DCHECK(length > 0, "invalid length %ld", length);
925 HandleScope scope(Thread::current());
926 MutableBytes result(&scope, createMutableBytes(length));
927 std::memset(reinterpret_cast<byte*>(result.address()), value, length);
928 return *result;
929}
930
931RawObject Runtime::newIntFromCPtr(void* ptr) {
932 return newInt(reinterpret_cast<word>(ptr));
933}
934
935RawObject Runtime::newMutableTuple(word length) {
936 DCHECK(length > 0, "use emptyTuple() for MutableTuple with length 0");
937 word size = MutableTuple::allocationSize(length);
938 uword address;
939 CHECK(heap()->allocate(size, &address), "out of memory");
940 return MutableTuple::cast(MutableTuple::initialize(address, length));
941}
942
943RawObject Runtime::newTupleWith1(const Object& item1) {
944 RawMutableTuple result = MutableTuple::cast(newMutableTuple(1));
945 result.atPut(0, *item1);
946 return result.becomeImmutable();
947}
948
949RawObject Runtime::newTupleWith2(const Object& item1, const Object& item2) {
950 RawMutableTuple result = MutableTuple::cast(newMutableTuple(2));
951 result.atPut(0, *item1);
952 result.atPut(1, *item2);
953 return result.becomeImmutable();
954}
955
956RawObject Runtime::newTupleWith3(const Object& item1, const Object& item2,
957 const Object& item3) {
958 RawMutableTuple result = MutableTuple::cast(newMutableTuple(3));
959 result.atPut(0, *item1);
960 result.atPut(1, *item2);
961 result.atPut(2, *item3);
962 return result.becomeImmutable();
963}
964
965RawObject Runtime::newTupleWith4(const Object& item1, const Object& item2,
966 const Object& item3, const Object& item4) {
967 RawMutableTuple result = MutableTuple::cast(newMutableTuple(4));
968 result.atPut(0, *item1);
969 result.atPut(1, *item2);
970 result.atPut(2, *item3);
971 result.atPut(3, *item4);
972 return result.becomeImmutable();
973}
974
975RawObject Runtime::newTupleWithN(word num_items, const Object* item1, ...) {
976 RawMutableTuple result = MutableTuple::cast(newMutableTuple(num_items));
977 result.atPut(0, **item1);
978
979 va_list args;
980 va_start(args, item1);
981 for (word i = 1; i < num_items; i++) {
982 const Object* item = va_arg(args, const Object*);
983 result.atPut(i, **item);
984 }
985 va_end(args);
986
987 return result.becomeImmutable();
988}
989
990NEVER_INLINE
991RawObject Runtime::newLargeIntFromWord(word value) {
992 DCHECK(!SmallInt::isValid(value), "value must not fit into SmallInt");
993 uword digit[1] = {static_cast<uword>(value)};
994 return newLargeIntWithDigits(digit);
995}
996
997RawObject Runtime::newIntFromUnsigned(uword value) {
998 if (static_cast<word>(value) >= 0 && SmallInt::isValid(value)) {
999 return SmallInt::fromWord(value);
1000 }
1001 uword digits[] = {value, 0};
1002 View<uword> view(digits, digits[0] >> (kBitsPerWord - 1) ? 2 : 1);
1003 return newLargeIntWithDigits(view);
1004}
1005
1006RawObject Runtime::newFloat(double value) {
1007 uword address;
1008 CHECK(heap()->allocate(Float::allocationSize(), &address), "out of memory");
1009 return Float::cast(Float::initialize(address, value));
1010}
1011
1012RawObject Runtime::newComplex(double real, double imag) {
1013 uword address;
1014 CHECK(heap()->allocate(Complex::allocationSize(), &address), "out of memory");
1015 return Complex::cast(Complex::initialize(address, real, imag));
1016}
1017
1018RawObject Runtime::newLargeIntWithDigits(View<uword> digits) {
1019 word length = digits.length();
1020 DCHECK(length > 0, "must have at least 1 digit");
1021 DCHECK(length > 1 || !SmallInt::isValid(digits.get(0)),
1022 "must not fit into a SmallInt");
1023 HandleScope scope(Thread::current());
1024 LargeInt result(&scope, createLargeInt(digits.length()));
1025 for (word i = 0; i < digits.length(); i++) {
1026 result.digitAtPut(i, digits.get(i));
1027 }
1028 DCHECK(result.isValid(), "Invalid digits");
1029 return *result;
1030}
1031
1032RawObject Runtime::newPointer(void* cptr, word length) {
1033 uword address;
1034 CHECK(heap()->allocate(Pointer::allocationSize(), &address), "out of memory");
1035 return Pointer::cast(Pointer::initialize(address, cptr, length));
1036}
1037
1038RawObject Runtime::newProperty(const Object& getter, const Object& setter,
1039 const Object& deleter) {
1040 HandleScope scope(Thread::current());
1041 Property new_prop(&scope,
1042 newInstanceWithSize(LayoutId::kProperty, Property::kSize));
1043 new_prop.setGetter(*getter);
1044 new_prop.setSetter(*setter);
1045 new_prop.setDeleter(*deleter);
1046 return *new_prop;
1047}
1048
1049RawObject Runtime::newRange(const Object& start, const Object& stop,
1050 const Object& step) {
1051 HandleScope scope(Thread::current());
1052 Range result(&scope, newInstanceWithSize(LayoutId::kRange, Range::kSize));
1053 result.setStart(*start);
1054 result.setStop(*stop);
1055 result.setStep(*step);
1056 return *result;
1057}
1058
1059RawObject Runtime::newLongRangeIterator(const Int& start, const Int& stop,
1060 const Int& step) {
1061 HandleScope scope(Thread::current());
1062 LongRangeIterator result(&scope,
1063 newInstanceWithSize(LayoutId::kLongRangeIterator,
1064 LongRangeIterator::kSize));
1065 result.setNext(*start);
1066 result.setStop(*stop);
1067 result.setStep(*step);
1068 return *result;
1069}
1070
1071RawObject Runtime::newRangeIterator(word start, word step, word length) {
1072 HandleScope scope(Thread::current());
1073 RangeIterator result(&scope, newInstanceWithSize(LayoutId::kRangeIterator,
1074 RangeIterator::kSize));
1075 result.setNext(start);
1076 result.setStep(step);
1077 result.setLength(length);
1078 return *result;
1079}
1080
1081RawObject Runtime::newSetIterator(const Object& set) {
1082 HandleScope scope(Thread::current());
1083 SetIterator result(
1084 &scope, newInstanceWithSize(LayoutId::kSetIterator, SetIterator::kSize));
1085 result.setIterable(*set);
1086 result.setIndex(0);
1087 result.setConsumedCount(0);
1088 return *result;
1089}
1090
1091RawObject Runtime::newSlice(const Object& start, const Object& stop,
1092 const Object& step) {
1093 if (start.isNoneType() && stop.isNoneType() && step.isNoneType()) {
1094 return emptySlice();
1095 }
1096 HandleScope scope(Thread::current());
1097 Slice slice(&scope, newInstanceWithSize(LayoutId::kSlice, Slice::kSize));
1098 slice.setStart(*start);
1099 slice.setStop(*stop);
1100 slice.setStep(*step);
1101 return *slice;
1102}
1103
1104RawObject Runtime::newStaticMethod() {
1105 return newInstanceWithSize(LayoutId::kStaticMethod, StaticMethod::kSize);
1106}
1107
1108RawObject Runtime::newStrArray() {
1109 HandleScope scope(Thread::current());
1110 StrArray result(&scope,
1111 newInstanceWithSize(LayoutId::kStrArray, StrArray::kSize));
1112 result.setItems(empty_mutable_bytes_);
1113 result.setNumItems(0);
1114 return *result;
1115}
1116
1117RawObject Runtime::newStrFromCStr(const char* c_str) {
1118 word length = std::strlen(c_str);
1119 auto data = reinterpret_cast<const byte*>(c_str);
1120 return newStrWithAll(View<byte>(data, length));
1121}
1122
1123RawObject Runtime::strFromStrArray(const StrArray& array) {
1124 word length = array.numItems();
1125 if (length <= SmallStr::kMaxLength) {
1126 byte buffer[SmallStr::kMaxLength];
1127 array.copyTo(buffer, length);
1128 return SmallStr::fromBytes({buffer, length});
1129 }
1130 HandleScope scope(Thread::current());
1131 LargeStr result(&scope, createLargeStr(length));
1132 array.copyTo(reinterpret_cast<byte*>(result.address()), length);
1133 return *result;
1134}
1135
1136static word strFormat(Thread* thread, const MutableBytes& dst,
1137 bool determine_size, const char* fmt, va_list args) {
1138 HandleScope scope(thread);
1139 word fragment_begin = 0;
1140 word fmt_index = 0;
1141 word dst_index = 0;
1142 word size = determine_size ? -1 : dst.length();
1143 for (; fmt[fmt_index] != '\0'; fmt_index++) {
1144 if (fmt[fmt_index] != '%') {
1145 continue;
1146 }
1147 word fragment_length = fmt_index - fragment_begin;
1148 if (!determine_size) {
1149 std::memcpy(reinterpret_cast<void*>(dst.address() + dst_index),
1150 fmt + fragment_begin, fragment_length);
1151 }
1152 dst_index += fragment_length;
1153 fmt_index++;
1154 fragment_begin = fmt_index + 1;
1155 switch (fmt[fmt_index]) {
1156 case 'c': {
1157 int value_int = va_arg(args, int); // Note that C promotes char to int.
1158 if (value_int < 0 || value_int > kMaxASCII) {
1159 // Replace non-ASCII characters.
1160 RawSmallStr value = SmallStr::fromCodePoint(kReplacementCharacter);
1161 word length = value.length();
1162 if (!determine_size) {
1163 dst.replaceFromWithStr(dst_index, Str::cast(value), length);
1164 }
1165 dst_index += length;
1166 break;
1167 }
1168 if (!determine_size) {
1169 dst.byteAtPut(dst_index, static_cast<char>(value_int));
1170 }
1171 dst_index++;
1172 } break;
1173 case 'd': {
1174 int value = va_arg(args, int);
1175 char* print_dst =
1176 determine_size ? nullptr
1177 : reinterpret_cast<char*>(dst.address() + dst_index);
1178 size_t print_len = determine_size ? 0 : size - dst_index + 1;
1179 dst_index += std::snprintf(print_dst, print_len, "%d", value);
1180 } break;
1181 case 'g': {
1182 double value = va_arg(args, double);
1183 char* print_dst =
1184 determine_size ? nullptr
1185 : reinterpret_cast<char*>(dst.address() + dst_index);
1186 size_t print_len = determine_size ? 0 : size - dst_index + 1;
1187 dst_index += std::snprintf(print_dst, print_len, "%g", value);
1188 } break;
1189 case 's': {
1190 const char* value = va_arg(args, char*);
1191 word length = std::strlen(value);
1192 if (!determine_size) {
1193 std::memcpy(reinterpret_cast<byte*>(dst.address() + dst_index), value,
1194 length);
1195 }
1196 dst_index += length;
1197 } break;
1198 case 'w': {
1199 word value = va_arg(args, word);
1200 char* print_dst =
1201 determine_size ? nullptr
1202 : reinterpret_cast<char*>(dst.address() + dst_index);
1203 size_t print_len = determine_size ? 0 : size - dst_index + 1;
1204 dst_index += std::snprintf(print_dst, print_len, "%" PRIdPTR, value);
1205 } break;
1206 case 'x': {
1207 unsigned value = va_arg(args, unsigned);
1208 char* print_dst =
1209 determine_size ? nullptr
1210 : reinterpret_cast<char*>(dst.address() + dst_index);
1211 size_t print_len = determine_size ? 0 : size - dst_index + 1;
1212 dst_index += std::snprintf(print_dst, print_len, "%x", value);
1213 } break;
1214 case 'C': {
1215 int32_t value_int = va_arg(args, int32_t);
1216 if (value_int < 0 || value_int > kMaxUnicode) {
1217 value_int = kReplacementCharacter;
1218 }
1219 RawSmallStr value = SmallStr::fromCodePoint(value_int);
1220 word length = value.length();
1221 if (!determine_size) {
1222 dst.replaceFromWithStr(dst_index, Str::cast(value), length);
1223 }
1224 dst_index += length;
1225 } break;
1226 case 'S': {
1227 Object value_obj(&scope, **va_arg(args, Object*));
1228 Str value(&scope, strUnderlying(*value_obj));
1229 word length = value.length();
1230 if (!determine_size) {
1231 dst.replaceFromWithStr(dst_index, *value, length);
1232 }
1233 dst_index += length;
1234 } break;
1235 case 'F': {
1236 Object obj(&scope, **va_arg(args, Object*));
1237 Function function(&scope, *obj);
1238 Str value(&scope, function.qualname());
1239 word length = value.length();
1240 if (!determine_size) {
1241 dst.replaceFromWithStr(dst_index, *value, length);
1242 }
1243 dst_index += length;
1244 } break;
1245 case 'T': {
1246 Object obj(&scope, **va_arg(args, Object*));
1247 Type type(&scope, thread->runtime()->typeOf(*obj));
1248 Str value(&scope, type.name());
1249 word length = value.length();
1250 if (!determine_size) {
1251 dst.replaceFromWithStr(dst_index, *value, length);
1252 }
1253 dst_index += length;
1254 } break;
1255 case 'Y': {
1256 SymbolId symbol = va_arg(args, SymbolId);
1257 RawStr value = Str::cast(thread->runtime()->symbols()->at(symbol));
1258 word length = value.length();
1259 if (!determine_size) {
1260 dst.replaceFromWithStr(dst_index, value, length);
1261 }
1262 dst_index += length;
1263 } break;
1264 case '%':
1265 if (!determine_size) {
1266 dst.byteAtPut(dst_index, '%');
1267 }
1268 dst_index++;
1269 break;
1270 default:
1271 UNIMPLEMENTED("Unsupported format specifier");
1272 }
1273 DCHECK(determine_size || dst_index <= size, "dst buffer overflow");
1274 }
1275
1276 word fragment_length = fmt_index - fragment_begin;
1277 if (!determine_size) {
1278 std::memcpy(reinterpret_cast<void*>(dst.address() + dst_index),
1279 fmt + fragment_begin, fragment_length);
1280 }
1281 dst_index += fragment_length;
1282 DCHECK(determine_size || dst_index == size, "dst buffer underflow");
1283 return dst_index;
1284}
1285
1286RawObject Runtime::newStrFromFmtV(Thread* thread, const char* fmt,
1287 va_list args) {
1288 va_list args_copy;
1289 va_copy(args_copy, args);
1290 HandleScope scope(thread);
1291 MutableBytes result(&scope, emptyMutableBytes());
1292 word length = strFormat(thread, result, /*determine_size=*/true, fmt, args);
1293 result = newMutableBytesUninitialized(length);
1294 strFormat(thread, result, /*determine_size=*/false, fmt, args_copy);
1295 va_end(args_copy);
1296 return result.becomeStr();
1297}
1298
1299RawObject Runtime::newStrFromFmt(const char* fmt, ...) {
1300 va_list args;
1301 va_start(args, fmt);
1302 Thread* thread = Thread::current();
1303 HandleScope scope(thread);
1304 Object result(&scope, newStrFromFmtV(thread, fmt, args));
1305 va_end(args);
1306 return *result;
1307}
1308
1309RawObject Runtime::newStrFromUTF32(View<int32_t> code_units) {
1310 word size = 0;
1311 for (word i = 0; i < code_units.length(); ++i) {
1312 int32_t cp = code_units.get(i);
1313 if (cp <= kMaxASCII) {
1314 size += 1;
1315 } else if (cp < 0x0800) {
1316 size += 2;
1317 } else if (cp < 0x010000) {
1318 size += 3;
1319 } else {
1320 DCHECK(cp <= kMaxUnicode, "invalid codepoint");
1321 size += 4;
1322 }
1323 }
1324 if (size <= RawSmallStr::kMaxLength) {
1325 byte dst[SmallStr::kMaxLength];
1326 for (word i = 0, j = 0; i < code_units.length(); ++i) {
1327 RawSmallStr src = SmallStr::fromCodePoint(code_units.get(i));
1328 word num_bytes = src.length();
1329 src.copyTo(&dst[j], num_bytes);
1330 j += num_bytes;
1331 }
1332 return SmallStr::fromBytes(View<byte>(dst, size));
1333 }
1334 RawObject result = createLargeStr(size);
1335 DCHECK(!result.isError(), "failed to create large string");
1336 byte* dst = reinterpret_cast<byte*>(LargeStr::cast(result).address());
1337 if (code_units.length() == size) {
1338 // ASCII fastpath
1339 for (word i = 0; i < size; ++i) {
1340 dst[i] = code_units.get(i);
1341 }
1342 return result;
1343 }
1344 for (word i = 0, j = 0; i < code_units.length(); ++i) {
1345 RawSmallStr src = SmallStr::fromCodePoint(code_units.get(i));
1346 word num_bytes = src.length();
1347 src.copyTo(&dst[j], num_bytes);
1348 j += num_bytes;
1349 }
1350 return result;
1351}
1352
1353RawObject Runtime::newStrWithAll(View<byte> code_units) {
1354 word length = code_units.length();
1355 if (length <= RawSmallStr::kMaxLength) {
1356 return SmallStr::fromBytes(code_units);
1357 }
1358 RawObject result = createLargeStr(length);
1359 DCHECK(!result.isError(), "failed to create large string");
1360 byte* dst = reinterpret_cast<byte*>(LargeStr::cast(result).address());
1361 const byte* src = code_units.data();
1362 memcpy(dst, src, length);
1363 return result;
1364}
1365
1366void NEVER_INLINE Runtime::internSetGrow(Thread* thread) {
1367 interned_ = py::internSetGrow(thread, MutableTuple::cast(interned_),
1368 &interned_remaining_);
1369}
1370
1371RawObject Runtime::internLargeStr(Thread* thread, const Object& str) {
1372 Runtime* runtime = thread->runtime();
1373 RawObject result = NoneType::object();
1374 if (internSetAdd(thread, MutableTuple::cast(runtime->interned_), str,
1375 &result)) {
1376 DCHECK(result == str, "expected str");
1377 if (--runtime->interned_remaining_ == 0) {
1378 runtime->internSetGrow(thread);
1379 return *str;
1380 }
1381 }
1382 return result;
1383}
1384
1385RawObject Runtime::internStrFromAll(Thread* thread, View<byte> bytes) {
1386 if (bytes.length() <= SmallStr::kMaxLength) {
1387 return SmallStr::fromBytes(bytes);
1388 }
1389
1390 Runtime* runtime = thread->runtime();
1391 RawObject result = NoneType::object();
1392 if (internSetAddFromAll(thread, MutableTuple::cast(runtime->interned_), bytes,
1393 &result)) {
1394 if (--runtime->interned_remaining_ == 0) {
1395 HandleScope scope(thread);
1396 Object result_obj(&scope, result);
1397 runtime->internSetGrow(thread);
1398 return *result_obj;
1399 }
1400 }
1401 return result;
1402}
1403
1404RawObject Runtime::internStrFromCStr(Thread* thread, const char* c_str) {
1405 View<byte> bytes(reinterpret_cast<const byte*>(c_str), std::strlen(c_str));
1406 return internStrFromAll(thread, bytes);
1407}
1408
1409bool Runtime::isInternedStr(Thread* thread, const Object& str) {
1410 DCHECK(str.isStr(), "expected str");
1411 if (str.isSmallStr()) {
1412 return true;
1413 }
1414 return internSetContains(MutableTuple::cast(thread->runtime()->interned_),
1415 LargeStr::cast(*str));
1416}
1417
1418word Runtime::hash(RawObject object) {
1419 if (!object.isHeapObject()) {
1420 return immediateHash(object);
1421 }
1422 if (object.isLargeBytes() || object.isLargeStr()) {
1423 return valueHash(object);
1424 }
1425 return identityHash(object);
1426}
1427
1428word Runtime::immediateHash(RawObject object) {
1429 if (object.isSmallStr()) {
1430 return SmallStr::cast(object).hash();
1431 }
1432 if (object.isSmallInt()) {
1433 return SmallInt::cast(object).hash();
1434 }
1435 if (object.isBool()) {
1436 return Bool::cast(object).hash();
1437 }
1438 if (object.isSmallBytes()) {
1439 return SmallBytes::cast(object).hash();
1440 }
1441 return static_cast<word>(object.raw());
1442}
1443
1444// Xoroshiro128+
1445// http://xoroshiro.di.unimi.it/
1446uword Runtime::random() {
1447 const uint64_t s0 = random_state_.state[0];
1448 uint64_t s1 = random_state_.state[1];
1449 const uint64_t result = s0 + s1;
1450 s1 ^= s0;
1451 random_state_.state[0] = Utils::rotateLeft(s0, 55) ^ s1 ^ (s1 << 14);
1452 random_state_.state[1] = Utils::rotateLeft(s1, 36);
1453 return result;
1454}
1455
1456RawObject* Runtime::finalizableReferences() { return &finalizable_references_; }
1457
1458word Runtime::identityHash(RawObject object) {
1459 RawHeapObject src = HeapObject::cast(object);
1460 word code = src.header().hashCode();
1461 if (code == RawHeader::kUninitializedHash) {
1462 code = random() & RawHeader::kHashCodeMask;
1463 code = (code == RawHeader::kUninitializedHash) ? code + 1 : code;
1464 src.setHeader(src.header().withHashCode(code));
1465 }
1466 return code;
1467}
1468
1469word Runtime::siphash24(View<byte> array) {
1470 word result = 0;
1471 ::halfsiphash(
1472 array.data(), array.length(),
1473 reinterpret_cast<const uint8_t*>(&random_state_.siphash24_secret),
1474 reinterpret_cast<uint8_t*>(&result), sizeof(result));
1475 return result;
1476}
1477
1478uint64_t Runtime::hashWithKey(const Bytes& bytes, uint64_t key) {
1479 uint64_t result = 0;
1480 word length = bytes.length();
1481 byte small_buffer[SmallBytes::kMaxLength];
1482 byte* data;
1483 if (bytes.isSmallBytes()) {
1484 bytes.copyTo(small_buffer, length);
1485 data = small_buffer;
1486 } else {
1487 data = reinterpret_cast<byte*>(LargeBytes::cast(*bytes).address());
1488 }
1489 ::halfsiphash(data, length, reinterpret_cast<const uint8_t*>(&key),
1490 reinterpret_cast<uint8_t*>(&result), sizeof(result));
1491 return result;
1492}
1493
1494word Runtime::bytesHash(View<byte> array) {
1495 word result = siphash24(array);
1496 result &= RawHeader::kHashCodeMask;
1497 return (result == RawHeader::kUninitializedHash) ? result + 1 : result;
1498}
1499
1500word Runtime::valueHash(RawObject object) {
1501 RawHeapObject src = HeapObject::cast(object);
1502 RawHeader header = src.header();
1503 word code = header.hashCode();
1504 if (code == RawHeader::kUninitializedHash) {
1505 word size = src.headerCountOrOverflow();
1506 code = bytesHash(View<byte>(reinterpret_cast<byte*>(src.address()), size));
1507 src.setHeader(header.withHashCode(code));
1508 DCHECK(code == src.header().hashCode(), "hash failure");
1509 }
1510 return code;
1511}
1512
1513const byte* Runtime::hashSecret(size_t size) {
1514 CHECK(size <= sizeof(random_state_.extra_secret),
1515 "hash secret request too big");
1516 return reinterpret_cast<const byte*>(&random_state_.extra_secret);
1517}
1518
1519RawObject Runtime::handlePendingSignals(Thread* thread) {
1520 thread->clearInterrupt(Thread::kSignal);
1521 if (!is_signal_pending_ || !thread->isMainThread()) {
1522 return NoneType::object();
1523 }
1524
1525 is_signal_pending_ = false;
1526 HandleScope scope(thread);
1527 for (word i = 1; i < OS::kNumSignals; i++) {
1528 if (OS::pending_signals_[i]) {
1529 OS::pending_signals_[i] = false;
1530
1531 // NOTE: we do not expose frame objects to the user
1532 Object callback(&scope, signalCallback(i));
1533 Object signum(&scope, SmallInt::fromWord(i));
1534 Object frame(&scope, NoneType::object());
1535 Object result(&scope,
1536 Interpreter::call2(thread, callback, signum, frame));
1537
1538 if (result.isErrorException()) {
1539 is_signal_pending_ = true;
1540 return *result;
1541 }
1542 }
1543 }
1544
1545 return NoneType::object();
1546}
1547
1548void Runtime::initializeSignals(Thread* thread, const Module& under_signal) {
1549 if (!signal_callbacks_.isNoneType()) {
1550 return; // already initialized
1551 }
1552
1553 signal_stack_ = std::malloc(SIGSTKSZ);
1554 CHECK(signal_stack_ != nullptr, "out of memory");
1555
1556 stack_t altstack;
1557 altstack.ss_sp = signal_stack_;
1558 altstack.ss_size = SIGSTKSZ;
1559 altstack.ss_flags = 0;
1560 CHECK(::sigaltstack(&altstack, nullptr) == 0,
1561 "unable to create signal-handling stack");
1562
1563 HandleScope scope(thread);
1564 MutableTuple callbacks(&scope, newMutableTuple(OS::kNumSignals));
1565
1566 is_signal_pending_ = false;
1567 signal_callbacks_ = *callbacks;
1568
1569 OS::pending_signals_[0] = false;
1570 for (int i = 1; i < OS::kNumSignals; i++) {
1571 OS::pending_signals_[i] = false;
1572 SignalHandler handler = OS::signalHandler(i);
1573 if (handler == SIG_DFL) {
1574 callbacks.atPut(i, kDefaultHandler);
1575 } else if (handler == SIG_IGN) {
1576 callbacks.atPut(i, kIgnoreHandler);
1577 }
1578 }
1579
1580 if (callbacks.at(SIGINT) == kDefaultHandler) {
1581 callbacks.atPut(
1582 SIGINT, moduleAtById(thread, under_signal, ID(default_int_handler)));
1583 OS::setSignalHandler(SIGINT, handleSignal);
1584 }
1585}
1586
1587void Runtime::finalizeSignals(Thread* thread) {
1588 if (signal_callbacks_.isNoneType()) return;
1589
1590 stack_t altstack = {};
1591 altstack.ss_size = SIGSTKSZ;
1592 altstack.ss_flags = SS_DISABLE;
1593 CHECK(::sigaltstack(&altstack, nullptr) == 0,
1594 "unable to disable signal-handling stack");
1595 std::free(signal_stack_);
1596
1597 HandleScope scope(thread);
1598 MutableTuple callbacks(&scope, signal_callbacks_);
1599 Object callback(&scope, NoneType::object());
1600 for (int i = 1; i < OS::kNumSignals; i++) {
1601 callback = callbacks.at(i);
1602 if (callback != kDefaultHandler && callback != kIgnoreHandler) {
1603 OS::setSignalHandler(i, SIG_DFL);
1604 }
1605 }
1606}
1607
1608void Runtime::setPendingSignal(Thread* thread, int signum) {
1609 if (thread != main_thread_) return;
1610
1611 OS::pending_signals_[signum] = true;
1612 is_signal_pending_ = true;
1613 thread->interrupt(Thread::kSignal);
1614
1615 if (wakeup_fd_ < 0) return;
1616
1617 byte b = signum;
1618 File::write(wakeup_fd_, &b, 1);
1619 // TODO(wmeehan): add pending call to report wakeup error
1620}
1621
1622RawObject Runtime::setSignalCallback(word signum, const Object& callback) {
1623 RawMutableTuple callbacks = MutableTuple::cast(signal_callbacks_);
1624 RawObject result = callbacks.at(signum);
1625 callbacks.atPut(signum, *callback);
1626 return result;
1627}
1628
1629RawObject Runtime::signalCallback(word signum) {
1630 return Tuple::cast(signal_callbacks_).at(signum);
1631}
1632
1633void Runtime::populateEntryAsm(const Function& function) {
1634 function.setEntryAsm(interpreter_->entryAsm(function));
1635}
1636
1637static const word kFixedSpaceSize = 1 * kGiB;
1638
1639void Runtime::initializeJITState() {
1640 machine_code_ = new Space(kFixedSpaceSize);
1641 // TODO(T89276586): Only set X bit per-page after code is written and
1642 // finalized.
1643 OS::protectMemory(reinterpret_cast<byte*>(machine_code_->start()),
1644 machine_code_->size(), OS::kReadWriteExecute);
1645}
1646
1647void Runtime::initializeLayouts() {
1648 layouts_ = newMutableTuple(kInitialLayoutTupleCapacity);
1649 static_assert(
1650 static_cast<word>(LayoutId::kLastBuiltinId) < kInitialLayoutTupleCapacity,
1651 "initial layout tuple size too small");
1652 num_layouts_ = static_cast<word>(LayoutId::kLastBuiltinId) + 1;
1653 layout_type_transitions_ =
1654 newMutableTuple(LayoutTypeTransition::kTransitionSize);
1655}
1656
1657static const BuiltinAttribute kExceptionStateAttributes[] = {
1658 {ID(_exception_state__type), ExceptionState::kTypeOffset,
1659 AttributeFlags::kHidden},
1660 {ID(_exception_state__value), ExceptionState::kValueOffset,
1661 AttributeFlags::kHidden},
1662 {ID(_exception_state__traceback), ExceptionState::kTracebackOffset,
1663 AttributeFlags::kHidden},
1664 {ID(_exception_state__previous), ExceptionState::kPreviousOffset,
1665 AttributeFlags::kHidden},
1666};
1667
1668static const BuiltinAttribute kPointerAttributes[] = {
1669 {ID(_pointer__cptr), Pointer::kCPtrOffset, AttributeFlags::kHidden},
1670 {ID(_pointer__length), Pointer::kLengthOffset, AttributeFlags::kHidden},
1671};
1672
1673void Runtime::initializeTypes(Thread* thread) {
1674 initializeObjectTypes(thread);
1675
1676 initializeArrayType(thread);
1677 initializeBytearrayTypes(thread);
1678 initializeBytesTypes(thread);
1679 initializeCodeType(thread);
1680 initializeComplexType(thread);
1681 initializeDescriptorTypes(thread);
1682 initializeDictTypes(thread);
1683 initializeExceptionTypes(thread);
1684 initializeFloatType(thread);
1685 initializeFrameProxyType(thread);
1686 initializeFunctionTypes(thread);
1687 initializeGeneratorTypes(thread);
1688 initializeIntTypes(thread);
1689 initializeIteratorType(thread);
1690 initializeLayoutType(thread);
1691 initializeListTypes(thread);
1692 initializeMappingProxyType(thread);
1693 initializeMemoryViewType(thread);
1694 initializeMmapType(thread);
1695 initializeModuleProxyType(thread);
1696 initializeModuleType(thread);
1697 initializeRangeTypes(thread);
1698 initializeRefTypes(thread);
1699 initializeSetTypes(thread);
1700 initializeSliceType(thread);
1701 initializeStrArrayType(thread);
1702 initializeStrTypes(thread);
1703 initializeSuperType(thread);
1704 initializeTracebackType(thread);
1705 initializeTupleTypes(thread);
1706 initializeTypeTypes(thread);
1707 initializeUnderCollectionsTypes(thread);
1708 initializeUnderContextvarsTypes(thread);
1709 initializeUnderIOTypes(thread);
1710 initializeValueCellTypes(thread);
1711
1712 addBuiltinType(thread, ID(ExceptionState), LayoutId::kExceptionState,
1713 LayoutId::kObject, kExceptionStateAttributes,
1714 ExceptionState::kSize, /*basetype=*/false);
1715 addBuiltinType(thread, ID(_mutablebytes), LayoutId::kMutableBytes,
1716 LayoutId::kObject, kNoAttributes, MutableBytes::kSize,
1717 /*basetype=*/false);
1718 addBuiltinType(thread, ID(_mutabletuple), LayoutId::kMutableTuple,
1719 LayoutId::kObject, kNoAttributes, MutableTuple::kSize,
1720 /*basetype=*/false);
1721 addBuiltinType(thread, ID(_pointer), LayoutId::kPointer, LayoutId::kObject,
1722 kPointerAttributes, Pointer::kSize, /*basetype=*/false);
1723 addBuiltinType(thread, ID(ellipsis), LayoutId::kEllipsis, LayoutId::kObject,
1724 kNoAttributes, Ellipsis::kSize, /*basetype=*/false);
1725}
1726
1727void Runtime::collectGarbageInto(CompactionDestination destination) {
1728 EVENT(CollectGarbage);
1729 bool run_callback = callbacks_ == NoneType::object();
1730 RawObject cb = (destination == CompactionDestination::kImmortalPartition)
1731 ? scavengeImmortalize(this)
1732 : scavenge(this);
1733 callbacks_ = WeakRef::spliceQueue(callbacks_, cb);
1734 if (run_callback) {
1735 processCallbacks();
1736 }
1737 if (finalizable_references_ != NoneType::object()) {
1738 processFinalizers();
1739 }
1740}
1741
1742Thread* Runtime::newThread() {
1743 Thread* thread = new Thread(this, Thread::kDefaultStackSize);
1744 {
1745 MutexGuard lock(&threads_mutex_);
1746 if (main_thread_ == nullptr) {
1747 main_thread_ = thread;
1748 } else {
1749 Thread* next = main_thread_->next();
1750 main_thread_->setNext(thread);
1751 thread->setNext(next);
1752 thread->setPrev(main_thread_);
1753 if (next != nullptr) {
1754 next->setPrev(thread);
1755 }
1756 }
1757 }
1758 return thread;
1759}
1760
1761void Runtime::deleteThread(Thread* thread) {
1762 CHECK(thread != main_thread_, "cannot delete main thread");
1763 MutexGuard lock(&threads_mutex_);
1764 Thread* prev = thread->prev();
1765 Thread* next = thread->next();
1766 prev->setNext(next);
1767 if (next != nullptr) {
1768 next->setPrev(prev);
1769 }
1770 delete thread;
1771}
1772
1773void Runtime::processCallbacks() {
1774 Thread* thread = Thread::current();
1775 HandleScope scope(thread);
1776 Object saved_type(&scope, thread->pendingExceptionType());
1777 Object saved_value(&scope, thread->pendingExceptionValue());
1778 Object saved_traceback(&scope, thread->pendingExceptionTraceback());
1779 thread->clearPendingException();
1780
1781 while (callbacks_ != NoneType::object()) {
1782 Object weak(&scope, WeakRef::dequeue(&callbacks_));
1783 BoundMethod callback(&scope, WeakRef::cast(*weak).callback());
1784 Interpreter::call0(thread, callback);
1785 thread->ignorePendingException();
1786 WeakRef::cast(*weak).setCallback(NoneType::object());
1787 }
1788
1789 thread->setPendingExceptionType(*saved_type);
1790 thread->setPendingExceptionValue(*saved_value);
1791 thread->setPendingExceptionTraceback(*saved_traceback);
1792}
1793
1794void Runtime::processFinalizers() {
1795 Thread* thread = Thread::current();
1796 HandleScope scope(thread);
1797 Object saved_type(&scope, thread->pendingExceptionType());
1798 Object saved_value(&scope, thread->pendingExceptionValue());
1799 Object saved_traceback(&scope, thread->pendingExceptionTraceback());
1800 thread->clearPendingException();
1801
1802 while (finalizable_references_ != NoneType::object()) {
1803 finalizeExtensionObject(thread,
1804 RawNativeProxy::dequeue(&finalizable_references_));
1805 }
1806
1807 thread->setPendingExceptionType(*saved_type);
1808 thread->setPendingExceptionValue(*saved_value);
1809 thread->setPendingExceptionTraceback(*saved_traceback);
1810}
1811
1812static void writeCStr(word fd, const char* str) {
1813 File::write(fd, str, std::strlen(str));
1814}
1815
1816static void writeStr(word fd, RawStr str) {
1817 static const word buffer_length = 128;
1818 byte buffer[buffer_length];
1819
1820 word start = 0;
1821 word length = str.length();
1822 while (length > buffer_length) {
1823 LargeStr::cast(str).copyToStartAt(buffer, buffer_length, start);
1824 File::write(fd, buffer, buffer_length);
1825 start += buffer_length;
1826 length -= buffer_length;
1827 }
1828 str.copyToStartAt(buffer, length, start);
1829 File::write(fd, buffer, length);
1830}
1831
1832RawObject Runtime::printTraceback(Thread* thread, word fd) {
1833 // NOTE: all operations in this function must be async-signal-safe.
1834 // See http://man7.org/linux/man-pages/man7/signal-safety.7.html for details.
1835 static const char* in = " in ";
1836 static const char* line = ", line ";
1837 static const char* unknown = "???";
1838 writeCStr(fd, "Stack (most recent call first):\n");
1839
1840 Frame* frame = thread->currentFrame();
1841 while (!frame->isSentinel()) {
1842 writeCStr(fd, " File ");
1843 RawFunction function = frame->function();
1844 RawObject code_obj = function.code();
1845 if (code_obj.isCode()) {
1846 RawCode code = Code::cast(code_obj);
1847 RawObject filename = code.filename();
1848 if (filename.isStr()) {
1849 writeCStr(fd, "\"");
1850 writeStr(fd, RawStr::cast(filename));
1851 writeCStr(fd, "\"");
1852 } else {
1853 writeCStr(fd, unknown);
1854 }
1855
1856 writeCStr(fd, line);
1857 if (!code.isNative() && code.lnotab().isBytes()) {
1858 byte buf[kUwordDigits10];
1859 byte* end = buf + kUwordDigits10;
1860 byte* start = end;
1861 word pc = Utils::maximum(frame->virtualPC() - kCodeUnitSize, word{0});
1862 word linenum = code.offsetToLineNum(pc);
1863 DCHECK(linenum > 0, "expected non-negative line number");
1864 start = uwordToDecimal(static_cast<uword>(linenum), start);
1865 File::write(fd, start, end - start);
1866 } else {
1867 writeCStr(fd, unknown);
1868 }
1869
1870 writeCStr(fd, in);
1871 RawObject name = function.name();
1872 if (name.isStr()) {
1873 writeStr(fd, RawStr::cast(name));
1874 } else {
1875 writeCStr(fd, unknown);
1876 }
1877 } else {
1878 writeCStr(fd, unknown);
1879 writeCStr(fd, line);
1880 writeCStr(fd, unknown);
1881 writeCStr(fd, in);
1882 writeCStr(fd, unknown);
1883 }
1884
1885 writeCStr(fd, "\n");
1886 frame = frame->previousFrame();
1887 }
1888
1889 return NoneType::object();
1890}
1891
1892static RawTuple newEmptyTuple(Heap* heap) {
1893 word size = MutableTuple::allocationSize(0);
1894 uword address;
1895 CHECK(heap->allocate(size, &address), "out of memory");
1896 return Tuple::cast(MutableTuple::cast(MutableTuple::initialize(address, 0))
1897 .becomeImmutable());
1898}
1899
1900void Runtime::initializePrimitiveInstances() {
1901 empty_tuple_ = newEmptyTuple(heap());
1902 empty_frozen_set_ = newFrozenSet();
1903 empty_mutable_bytes_ = createMutableBytes(0);
1904 empty_slice_ = newInstanceWithSize(LayoutId::kSlice, Slice::kSize);
1905 {
1906 uword address;
1907 CHECK(heap()->allocate(Ellipsis::allocationSize(), &address),
1908 "out of memory");
1909 ellipsis_ = Ellipsis::cast(Ellipsis::initialize(address));
1910 }
1911}
1912
1913void Runtime::initializeInterned(Thread*) {
1914 interned_ = newMutableTuple(kInitialInternSetCapacity);
1915 interned_remaining_ = internSetComputeRemaining(kInitialInternSetCapacity);
1916}
1917
1918void Runtime::initializeSymbols(Thread* thread) {
1919 HandleScope scope(thread);
1920 symbols_ = new Symbols(this);
1921 for (int i = 0; i < static_cast<int>(SymbolId::kMaxId); i++) {
1922 SymbolId id = static_cast<SymbolId>(i);
1923 Object symbol(&scope, symbols()->at(id));
1924 internStr(thread, symbol);
1925 }
1926}
1927
1928RawObject Runtime::implicitBases() {
1929 return Type::cast(typeAt(LayoutId::kObject)).mro();
1930}
1931
1932void Runtime::cacheBuildClass(Thread* thread, const Module& builtins) {
1933 HandleScope scope(thread);
1934 Object none(&scope, NoneType::object());
1935 moduleAtPutById(thread, builtins, ID(__build_class__), none);
1936 build_class_ = moduleValueCellAtById(thread, builtins, ID(__build_class__));
1937 CHECK(!build_class_.isErrorNotFound(), "__build_class__ not found");
1938}
1939
1940void Runtime::builtinTypeCreated(Thread* thread, const Type& type) {
1941 LayoutId layout_id = type.instanceLayoutId();
1942 switch (layout_id) {
1943 case LayoutId::kObject:
1944 object_dunder_class_ = typeAtById(thread, type, ID(__class__));
1945 object_dunder_eq_ = typeAtById(thread, type, ID(__eq__));
1946 object_dunder_getattribute_ =
1947 typeAtById(thread, type, ID(__getattribute__));
1948 object_dunder_hash_ = typeAtById(thread, type, ID(__hash__));
1949 object_dunder_init_ = typeAtById(thread, type, ID(__init__));
1950 object_dunder_new_ = typeAtById(thread, type, ID(__new__));
1951 object_dunder_setattr_ = typeAtById(thread, type, ID(__setattr__));
1952 type.setFlags(static_cast<Type::Flag>(
1953 type.flags() | Type::Flag::kHasObjectDunderGetattribute |
1954 Type::Flag::kHasObjectDunderNew | Type::Flag::kHasObjectDunderHash));
1955 break;
1956 case LayoutId::kModule:
1957 module_dunder_getattribute_ =
1958 typeAtById(thread, type, ID(__getattribute__));
1959 type.setFlags(static_cast<Type::Flag>(
1960 type.flags() | Type::Flag::kHasModuleDunderGetattribute));
1961 break;
1962 case LayoutId::kNoneType:
1963 // NoneType.__class__ does *not* point to the same object as
1964 // object.__class_ to avoid descriptor resolution for NoneType, but their
1965 // observable behaviors are same. See the definition of NoneType in
1966 // builtins.py.
1967 type.setFlags(static_cast<Type::Flag>(type.flags() |
1968 Type::Flag::kHasObjectDunderClass));
1969 break;
1970 case LayoutId::kStr:
1971 str_dunder_eq_ = typeAtById(thread, type, ID(__eq__));
1972 str_dunder_hash_ = typeAtById(thread, type, ID(__hash__));
1973 type.setFlags(static_cast<Type::Flag>(type.flags() |
1974 Type::Flag::kHasStrDunderHash));
1975 break;
1976 case LayoutId::kType:
1977 type_dunder_getattribute_ =
1978 typeAtById(thread, type, ID(__getattribute__));
1979 type.setFlags(static_cast<Type::Flag>(
1980 type.flags() | Type::Flag::kHasTypeDunderGetattribute));
1981 break;
1982 default:
1983 break;
1984 }
1985
1986 HandleScope scope(thread);
1987 Function dunder_getattribute(
1988 &scope, typeLookupInMroById(thread, *type, ID(__getattribute__)));
1989 // This detects two instances of `object.__getattribute__`:
1990 // 1) Manually created `object.__getattribute__` before initializing `object`.
1991 // 2) Real `object.__getattribute__` after.
1992 if (Str::cast(dunder_getattribute.qualname())
1993 .equalsCStr("object.__getattribute__")) {
1994 type.setFlags(static_cast<Type::Flag>(
1995 type.flags() | Type::Flag::kHasObjectDunderGetattribute));
1996 }
1997
1998 Object dunder_new(&scope, typeLookupInMroById(thread, *type, ID(__new__)));
1999 if (*dunder_new == object_dunder_new_ ||
2000 // __new__ cannot be found in this type and this type is initialized
2001 // before `object`.
2002 (dunder_new.isErrorNotFound() && object_dunder_new_.isNoneType())) {
2003 type.setFlags(static_cast<Type::Flag>(type.flags() |
2004 Type::Flag::kHasObjectDunderNew));
2005 }
2006
2007 Object dunder_hash(&scope, typeLookupInMroById(thread, *type, ID(__hash__)));
2008 if (*dunder_hash == object_dunder_hash_ ||
2009 // __hash__ cannot be found in this type and this type is initialized
2010 // before `object`.
2011 (dunder_hash.isErrorNotFound() && object_dunder_hash_.isNoneType())) {
2012 type.setFlags(static_cast<Type::Flag>(type.flags() |
2013 Type::Flag::kHasObjectDunderHash));
2014 }
2015
2016 if (!typeLookupInMroById(thread, *type, ID(__bool__)).isErrorNotFound()) {
2017 type.setFlags(
2018 static_cast<Type::Flag>(type.flags() | Type::Flag::kHasDunderBool));
2019 }
2020
2021 if (!typeLookupInMroById(thread, *type, ID(__len__)).isErrorNotFound()) {
2022 type.setFlags(
2023 static_cast<Type::Flag>(type.flags() | Type::Flag::kHasDunderLen));
2024 }
2025
2026 Object dunder_class(&scope,
2027 typeLookupInMroById(thread, *type, ID(__class__)));
2028 if (*dunder_class == object_dunder_class_ ||
2029 // __class__ cannot be found in this type and this type is initialized
2030 // before `object`.
2031 (dunder_class.isErrorNotFound() && object_dunder_class_.isNoneType())) {
2032 type.setFlags(static_cast<Type::Flag>(type.flags() |
2033 Type::Flag::kHasObjectDunderClass));
2034 }
2035
2036 Object dunder_eq(&scope, typeLookupInMroById(thread, *type, ID(__eq__)));
2037 if (*dunder_eq == object_dunder_eq_ ||
2038 // __eq__ cannot be found in this type and this type is initialized
2039 // before `object`.
2040 (dunder_eq.isErrorNotFound() && object_dunder_eq_.isNoneType())) {
2041 type.setFlags(
2042 static_cast<Type::Flag>(type.flags() | Type::Flag::kHasObjectDunderEq));
2043 }
2044
2045 if (!typeLookupInMroById(thread, *type, ID(__get__)).isErrorNotFound()) {
2046 type.setFlags(
2047 static_cast<Type::Flag>(type.flags() | Type::Flag::kHasDunderGet));
2048 }
2049
2050 if (!typeLookupInMroById(thread, *type, ID(__set__)).isErrorNotFound()) {
2051 type.setFlags(
2052 static_cast<Type::Flag>(type.flags() | Type::Flag::kHasDunderSet));
2053 }
2054
2055 if (!typeLookupInMroById(thread, *type, ID(__delete__)).isErrorNotFound()) {
2056 type.setFlags(
2057 static_cast<Type::Flag>(type.flags() | Type::Flag::kHasDunderDelete));
2058 }
2059}
2060
2061void Runtime::cacheSysInstances(Thread* thread, const Module& sys) {
2062 sys_stderr_ = moduleValueCellAtById(thread, sys, ID(stderr));
2063 CHECK(!sys_stderr_.isErrorNotFound(), "sys.stderr not found");
2064 sys_stdin_ = moduleValueCellAtById(thread, sys, ID(stdin));
2065 CHECK(!sys_stdin_.isErrorNotFound(), "sys.stdin not found");
2066 sys_stdout_ = moduleValueCellAtById(thread, sys, ID(stdout));
2067 CHECK(!sys_stdout_.isErrorNotFound(), "sys.stdout not found");
2068 display_hook_ = moduleValueCellAtById(thread, sys, ID(displayhook));
2069 CHECK(!display_hook_.isErrorNotFound(), "sys.displayhook not found");
2070}
2071
2072void Runtime::visitRootsWithoutApiHandles(PointerVisitor* visitor) {
2073 visitRuntimeRoots(visitor);
2074 visitThreadRoots(visitor);
2075}
2076
2077void Runtime::visitRuntimeRoots(PointerVisitor* visitor) {
2078 // Visit builtin layouts
2079 for (word i = 0; i <= static_cast<word>(LayoutId::kLastBuiltinId); ++i) {
2080 visitor->visitPointer(
2081 reinterpret_cast<RawObject*>(Tuple::cast(layouts_).address() +
2082 i * kPointerSize),
2083 PointerKind::kLayout);
2084 }
2085
2086 // Visit internal types that are not described by a layout
2087 visitor->visitPointer(&large_bytes_, PointerKind::kRuntime);
2088 visitor->visitPointer(&large_int_, PointerKind::kRuntime);
2089 visitor->visitPointer(&large_str_, PointerKind::kRuntime);
2090 visitor->visitPointer(&small_bytes_, PointerKind::kRuntime);
2091 visitor->visitPointer(&small_int_, PointerKind::kRuntime);
2092 visitor->visitPointer(&small_str_, PointerKind::kRuntime);
2093
2094 // Visit instances
2095 visitor->visitPointer(&build_class_, PointerKind::kRuntime);
2096 visitor->visitPointer(&display_hook_, PointerKind::kRuntime);
2097 visitor->visitPointer(&ellipsis_, PointerKind::kRuntime);
2098 visitor->visitPointer(&empty_frozen_set_, PointerKind::kRuntime);
2099 visitor->visitPointer(&empty_mutable_bytes_, PointerKind::kRuntime);
2100 visitor->visitPointer(&empty_slice_, PointerKind::kRuntime);
2101 visitor->visitPointer(&empty_tuple_, PointerKind::kRuntime);
2102 visitor->visitPointer(&module_dunder_getattribute_, PointerKind::kRuntime);
2103 visitor->visitPointer(&object_dunder_class_, PointerKind::kRuntime);
2104 visitor->visitPointer(&object_dunder_eq_, PointerKind::kRuntime);
2105 visitor->visitPointer(&object_dunder_getattribute_, PointerKind::kRuntime);
2106 visitor->visitPointer(&object_dunder_hash_, PointerKind::kRuntime);
2107 visitor->visitPointer(&object_dunder_init_, PointerKind::kRuntime);
2108 visitor->visitPointer(&object_dunder_new_, PointerKind::kRuntime);
2109 visitor->visitPointer(&object_dunder_setattr_, PointerKind::kRuntime);
2110 visitor->visitPointer(&str_dunder_eq_, PointerKind::kRuntime);
2111 visitor->visitPointer(&str_dunder_hash_, PointerKind::kRuntime);
2112 visitor->visitPointer(&sys_stderr_, PointerKind::kRuntime);
2113 visitor->visitPointer(&sys_stdin_, PointerKind::kRuntime);
2114 visitor->visitPointer(&sys_stdout_, PointerKind::kRuntime);
2115 visitor->visitPointer(&type_dunder_getattribute_, PointerKind::kRuntime);
2116
2117 // Visit interned strings.
2118 visitor->visitPointer(&interned_, PointerKind::kRuntime);
2119
2120 // Visit modules
2121 visitor->visitPointer(&modules_, PointerKind::kRuntime);
2122
2123 // Visit symbols
2124 symbols_->visit(visitor);
2125
2126 // Visit GC callbacks
2127 visitor->visitPointer(&callbacks_, PointerKind::kRuntime);
2128
2129 // Visit signal callbacks
2130 visitor->visitPointer(&signal_callbacks_, PointerKind::kRuntime);
2131
2132 visitor->visitPointer(&profiling_new_thread_, PointerKind::kRuntime);
2133 visitor->visitPointer(&profiling_call_, PointerKind::kRuntime);
2134 visitor->visitPointer(&profiling_return_, PointerKind::kRuntime);
2135
2136 // Visit finalizable native instances
2137 visitor->visitPointer(&finalizable_references_, PointerKind::kRuntime);
2138}
2139
2140void Runtime::visitThreadRoots(PointerVisitor* visitor) {
2141 MutexGuard lock(&threads_mutex_);
2142 for (Thread* thread = main_thread_; thread != nullptr;
2143 thread = thread->next()) {
2144 thread->visitRoots(visitor);
2145 }
2146}
2147
2148RawObject Runtime::findModule(const Object& name) {
2149 // TODO(T53728922) it is possible to create modules with non-str names.
2150 DCHECK(name.isStr(), "name not a string");
2151
2152 Thread* thread = Thread::current();
2153 HandleScope scope(thread);
2154 Dict dict(&scope, modules());
2155 Str name_str(&scope, *name);
2156 return dictAtByStr(thread, dict, name_str);
2157}
2158
2159RawObject Runtime::findModuleById(SymbolId name) {
2160 HandleScope scope(Thread::current());
2161 Object name_obj(&scope, symbols()->at(name));
2162 return findModule(name_obj);
2163}
2164
2165RawObject Runtime::lookupNameInModule(Thread* thread, SymbolId module_name,
2166 SymbolId name) {
2167 HandleScope scope(thread);
2168 Object module_obj(&scope, findModuleById(module_name));
2169 DCHECK(!module_obj.isNoneType(),
2170 "The given module '%s' doesn't exist in modules dict",
2171 Symbols::predefinedSymbolAt(module_name));
2172 Module module(&scope, *module_obj);
2173 return moduleAtById(thread, module, name);
2174}
2175
2176void Runtime::initializeModules(Thread* thread) {
2177 // This function initializes module data that is fixed at compile time of the
2178 // runtime (code, most functions, types, platform name, ...).
2179 // Variable data should NOT be initialize here (runtime executable path,
2180 // PYTHONPATH, sys.flags, ...)
2181
2182 modules_ = newDict();
2183 for (SymbolId id : kRequiredModules) {
2184 CHECK(!ensureBuiltinModuleById(thread, id).isErrorException(),
2185 "failed to initialize built-in module %s",
2186 Symbols::predefinedSymbolAt(id));
2187 }
2188}
2189
2190RawObject Runtime::initialize(Thread* thread) {
2191 RawObject result = thread->invokeFunction0(ID(builtins), ID(_init));
2192 initialized_ = true;
2193 return result;
2194}
2195
2196RawObject Runtime::concreteTypeAt(LayoutId layout_id) {
2197 switch (layout_id) {
2198 case LayoutId::kLargeBytes:
2199 return large_bytes_;
2200 case LayoutId::kLargeInt:
2201 return large_int_;
2202 case LayoutId::kLargeStr:
2203 return large_str_;
2204 case LayoutId::kSmallBytes:
2205 return small_bytes_;
2206 case LayoutId::kSmallInt:
2207 return small_int_;
2208 case LayoutId::kSmallStr:
2209 return small_str_;
2210 default:
2211 return Layout::cast(layoutAt(layout_id)).describedType();
2212 }
2213}
2214
2215void Runtime::setLargeBytesType(const Type& type) { large_bytes_ = *type; }
2216
2217void Runtime::setLargeIntType(const Type& type) { large_int_ = *type; }
2218
2219void Runtime::setLargeStrType(const Type& type) { large_str_ = *type; }
2220
2221void Runtime::setSmallBytesType(const Type& type) { small_bytes_ = *type; }
2222
2223void Runtime::setSmallIntType(const Type& type) { small_int_ = *type; }
2224
2225void Runtime::setSmallStrType(const Type& type) { small_str_ = *type; }
2226
2227void Runtime::reinitInterpreter() {
2228 // TODO(T79826701) We should interrupt/sync all threads here.
2229
2230 MutexGuard lock(&threads_mutex_);
2231 for (Thread* thread = main_thread_; thread != nullptr;
2232 thread = thread->next()) {
2233 thread->interrupt(Thread::kReinitInterpreter);
2234 }
2235}
2236
2237void Runtime::setProfiling(const Object& new_thread_func,
2238 const Object& call_func, const Object& return_func) {
2239 profiling_new_thread_ = *new_thread_func;
2240 profiling_call_ = *call_func;
2241 profiling_return_ = *return_func;
2242}
2243
2244void Runtime::layoutAtPut(LayoutId layout_id, RawObject object) {
2245 MutableTuple::cast(layouts_).atPut(static_cast<word>(layout_id), object);
2246}
2247
2248RawObject Runtime::typeAt(LayoutId layout_id) {
2249 return Layout::cast(layoutAt(layout_id)).describedType();
2250}
2251
2252LayoutId Runtime::reserveLayoutId(Thread* thread) {
2253 word result = num_layouts_++;
2254 CHECK(result < Header::kMaxLayoutId, "layout id overflow");
2255 word length = Tuple::cast(layouts_).length();
2256 if (result >= length) {
2257 HandleScope scope(thread);
2258 Tuple old_tuple(&scope, layouts_);
2259 word new_length = newCapacity(length, kInitialLayoutTupleCapacity);
2260 MutableTuple new_tuple(&scope, newMutableTuple(new_length));
2261 new_tuple.replaceFromWith(0, *old_tuple, length);
2262 layouts_ = *new_tuple;
2263 }
2264 return static_cast<LayoutId>(result);
2265}
2266
2267word Runtime::reserveModuleId() {
2268 // TODO(T58039604): Come up with a scheme to reuse deallocated module IDs if
2269 // we run out.
2270 CHECK(max_module_id_ < RawModule::kMaxModuleId, "exceeded module ID space");
2271 return ++max_module_id_;
2272}
2273
2274word Runtime::newCapacity(word curr_capacity, word min_capacity) {
2275 word new_capacity = (curr_capacity < kInitialEnsuredCapacity)
2276 ? kInitialEnsuredCapacity
2277 : curr_capacity + (curr_capacity >> 1);
2278 if (new_capacity < min_capacity) {
2279 return min_capacity;
2280 }
2281 return Utils::minimum(new_capacity, SmallInt::kMaxValue);
2282}
2283
2284// Bytearray
2285
2286void Runtime::bytearrayEnsureCapacity(Thread* thread, const Bytearray& array,
2287 word min_capacity) {
2288 DCHECK_BOUND(min_capacity, SmallInt::kMaxValue);
2289 word curr_capacity = array.capacity();
2290 if (min_capacity <= curr_capacity) return;
2291 word new_capacity = newCapacity(curr_capacity, min_capacity);
2292 HandleScope scope(thread);
2293 MutableBytes old_bytes(&scope, array.items());
2294 MutableBytes new_bytes(&scope, newMutableBytesZeroed(new_capacity));
2295 byte* dst = reinterpret_cast<byte*>(new_bytes.address());
2296 word old_length = array.numItems();
2297 old_bytes.copyTo(dst, old_length);
2298 array.setItems(*new_bytes);
2299}
2300
2301void Runtime::bytearrayExtend(Thread* thread, const Bytearray& array,
2302 View<byte> view) {
2303 word length = view.length();
2304 if (length == 0) return;
2305 word num_items = array.numItems();
2306 word new_length = num_items + length;
2307 bytearrayEnsureCapacity(thread, array, new_length);
2308 byte* dst =
2309 reinterpret_cast<byte*>(MutableBytes::cast(array.items()).address());
2310 std::memcpy(dst + num_items, view.data(), view.length());
2311 array.setNumItems(new_length);
2312}
2313
2314void Runtime::bytearrayIadd(Thread* thread, const Bytearray& array,
2315 const Bytes& bytes, word length) {
2316 DCHECK_BOUND(length, bytes.length());
2317 if (length == 0) return;
2318 word num_items = array.numItems();
2319 word new_length = num_items + length;
2320 bytearrayEnsureCapacity(thread, array, new_length);
2321 MutableBytes::cast(array.items())
2322 .replaceFromWithBytes(num_items, *bytes, length);
2323 array.setNumItems(new_length);
2324}
2325
2326// Bytes
2327
2328RawObject Runtime::bytesConcat(Thread* thread, const Bytes& left,
2329 const Bytes& right) {
2330 word left_len = left.length();
2331 word right_len = right.length();
2332 word len = left_len + right_len;
2333 if (len <= SmallBytes::kMaxLength) {
2334 byte buffer[SmallBytes::kMaxLength];
2335 left.copyTo(buffer, left_len);
2336 right.copyTo(buffer + left_len, right_len);
2337 return SmallBytes::fromBytes({buffer, len});
2338 }
2339 HandleScope scope(thread);
2340 MutableBytes result(&scope, newMutableBytesUninitialized(len));
2341 result.replaceFromWithBytes(0, *left, left_len);
2342 result.replaceFromWithBytes(left_len, *right, right_len);
2343 return result.becomeImmutable();
2344}
2345
2346RawObject Runtime::bytesCopy(Thread* thread, const Bytes& src) {
2347 if (src.isSmallBytes()) return *src;
2348 return bytesSubseq(thread, src, 0, src.length());
2349}
2350
2351RawObject Runtime::bytesCopyWithSize(Thread* thread, const Bytes& original,
2352 word new_length) {
2353 DCHECK(new_length >= 0, "length must be nonnegative");
2354 if (new_length == 0) return Bytes::empty();
2355 word old_length = original.length();
2356 if (new_length <= SmallBytes::kMaxLength) {
2357 byte buffer[SmallBytes::kMaxLength];
2358 original.copyTo(buffer, Utils::minimum(old_length, new_length));
2359 return SmallBytes::fromBytes({buffer, new_length});
2360 }
2361 HandleScope scope(thread);
2362 MutableBytes copy(&scope, newMutableBytesUninitialized(new_length));
2363 if (old_length < new_length) {
2364 copy.replaceFromWithBytes(0, *original, old_length);
2365 copy.replaceFromWithByte(old_length, 0, new_length - old_length);
2366 } else {
2367 copy.replaceFromWith(0, LargeBytes::cast(*original), new_length);
2368 }
2369 return copy.becomeImmutable();
2370}
2371
2372RawObject Runtime::bytesEndsWith(const Bytes& bytes, word bytes_len,
2373 const Bytes& suffix, word suffix_len,
2374 word start, word end) {
2375 DCHECK_BOUND(bytes_len, bytes.length());
2376 DCHECK_BOUND(suffix_len, suffix.length());
2377 Slice::adjustSearchIndices(&start, &end, bytes_len);
2378 if (end - start < suffix_len || start > bytes_len) {
2379 return Bool::falseObj();
2380 }
2381 for (word i = end - suffix_len, j = 0; i < end; i++, j++) {
2382 if (bytes.byteAt(i) != suffix.byteAt(j)) {
2383 return Bool::falseObj();
2384 }
2385 }
2386 return Bool::trueObj();
2387}
2388
2389RawObject Runtime::bytesFromTuple(Thread* thread, const Tuple& items,
2390 word length) {
2391 DCHECK_BOUND(length, items.length());
2392 HandleScope scope(thread);
2393 MutableBytes result(&scope, empty_mutable_bytes_);
2394 byte buffer[SmallBytes::kMaxLength];
2395 byte* dst;
2396 if (length <= SmallBytes::kMaxLength) {
2397 dst = buffer;
2398 } else {
2399 result = newMutableBytesUninitialized(length);
2400 dst = reinterpret_cast<byte*>(MutableBytes::cast(*result).address());
2401 }
2402 for (word idx = 0; idx < length; idx++) {
2403 Object item(&scope, items.at(idx));
2404 if (!isInstanceOfInt(*item)) {
2405 // escape into slow path
2406 return NoneType::object();
2407 }
2408 OptInt<byte> current_byte = intUnderlying(*item).asInt<byte>();
2409 if (current_byte.error == CastError::None) {
2410 dst[idx] = current_byte.value;
2411 } else {
2412 // TODO(T55871582): Move error handling to caller
2413 return thread->raiseWithFmt(LayoutId::kValueError,
2414 "bytes must be in range(0, 256)");
2415 }
2416 }
2417 return length <= SmallBytes::kMaxLength
2418 ? SmallBytes::fromBytes({buffer, length})
2419 : result.becomeImmutable();
2420}
2421
2422RawObject Runtime::bytesRepeat(Thread* thread, const Bytes& source, word length,
2423 word count) {
2424 DCHECK_BOUND(length, source.length());
2425 DCHECK_BOUND(count, kMaxWord / length);
2426 if (count == 0 || length == 0) {
2427 return Bytes::empty();
2428 }
2429 bool is_mutable = source.isMutableBytes();
2430 if (length == 1) {
2431 byte item = source.byteAt(0);
2432 return is_mutable ? mutableBytesWith(count, item) : newBytes(count, item);
2433 }
2434 word new_length = length * count;
2435 if (!is_mutable && new_length <= SmallBytes::kMaxLength) {
2436 byte buffer[SmallBytes::kMaxLength];
2437 byte* dst = buffer;
2438 for (word i = 0; i < count; i++, dst += length) {
2439 source.copyTo(dst, length);
2440 }
2441 return SmallBytes::fromBytes({buffer, new_length});
2442 }
2443 HandleScope scope(thread);
2444 MutableBytes result(&scope, newMutableBytesUninitialized(new_length));
2445 for (word i = 0; i < count * length; i += length) {
2446 result.replaceFromWithBytes(i, *source, length);
2447 }
2448 return is_mutable ? *result : result.becomeImmutable();
2449}
2450
2451RawObject Runtime::bytesReplace(Thread* thread, const Bytes& src,
2452 const Bytes& old_bytes, word old_len,
2453 const Bytes& new_bytes, word new_len,
2454 word max_count) {
2455 word src_len = src.length();
2456 if (max_count == 0 || src_len == 0 || old_bytes.compare(*new_bytes) == 0) {
2457 return *src;
2458 }
2459 // Update the max_count to the number of occurences of old_bytes in src,
2460 // capped by the given max_count
2461 word count = bytesCount(src, src_len, old_bytes, old_len, 0, src_len);
2462 if (max_count < 0 || max_count > count) {
2463 max_count = count;
2464 }
2465 if (max_count == 0) {
2466 return *src;
2467 }
2468
2469 HandleScope scope(thread);
2470 word result_len = src_len + (new_len - old_len) * max_count;
2471 MutableBytes result(&scope, newMutableBytesUninitialized(result_len));
2472
2473 byte src_buffer[SmallBytes::kMaxLength], old_buffer[SmallBytes::kMaxLength];
2474 byte *src_ptr, *old_ptr;
2475 if (src.isLargeBytes()) {
2476 src_ptr = reinterpret_cast<byte*>(LargeBytes::cast(*src).address());
2477 } else {
2478 src.copyTo(src_buffer, src_len);
2479 src_ptr = src_buffer;
2480 }
2481 if (old_bytes.isLargeBytes()) {
2482 old_ptr = reinterpret_cast<byte*>(LargeBytes::cast(*old_bytes).address());
2483 } else {
2484 old_bytes.copyTo(old_buffer, old_len);
2485 old_ptr = old_buffer;
2486 }
2487
2488 word dst_idx = 0, src_idx = 0;
2489 for (; max_count > 0; max_count--) {
2490 byte* found_ptr = reinterpret_cast<byte*>(
2491 ::memmem(src_ptr + src_idx, src_len - src_idx, old_ptr, old_len));
2492 word prefix_len = found_ptr - (src_ptr + src_idx);
2493 result.replaceFromWithBytesStartAt(dst_idx, *src, prefix_len, src_idx);
2494 dst_idx += prefix_len;
2495 result.replaceFromWithBytesStartAt(dst_idx, *new_bytes, new_len, 0);
2496 dst_idx += new_len;
2497 src_idx += prefix_len + old_len;
2498 }
2499 result.replaceFromWithBytesStartAt(dst_idx, *src, src_len - src_idx, src_idx);
2500 return result.becomeImmutable();
2501}
2502
2503static void writeByteslikeRepr(const Byteslike& byteslike, byte* dst,
2504 word result_length, byte delimiter) {
2505 byte* ptr = dst;
2506 *ptr++ = 'b';
2507 *ptr++ = delimiter;
2508
2509 word length = byteslike.length();
2510 for (word i = 0; i < length; i++) {
2511 byte current = byteslike.byteAt(i);
2512 if (current == delimiter || current == '\\') {
2513 *ptr++ = '\\';
2514 *ptr++ = current;
2515 } else if (current == '\t') {
2516 *ptr++ = '\\';
2517 *ptr++ = 't';
2518 } else if (current == '\n') {
2519 *ptr++ = '\\';
2520 *ptr++ = 'n';
2521 } else if (current == '\r') {
2522 *ptr++ = '\\';
2523 *ptr++ = 'r';
2524 } else if (ASCII::isPrintable(current)) {
2525 *ptr++ = current;
2526 } else {
2527 *ptr++ = '\\';
2528 *ptr++ = 'x';
2529 uwordToHexadecimal(ptr, /*num_digits=*/2, current);
2530 ptr += 2;
2531 }
2532 }
2533 *ptr++ = delimiter;
2534 DCHECK(ptr - dst == result_length, "precalculated repr length was incorrect");
2535}
2536
2537RawObject Runtime::byteslikeRepr(Thread* thread, const Byteslike& byteslike,
2538 word result_length, byte delimiter) {
2539 if (result_length <= SmallStr::kMaxLength) {
2540 byte buffer[SmallStr::kMaxLength];
2541 writeByteslikeRepr(byteslike, buffer, result_length, delimiter);
2542 return SmallStr::fromBytes({buffer, result_length});
2543 }
2544
2545 HandleScope scope(thread);
2546 LargeStr result(&scope, createLargeStr(result_length));
2547 writeByteslikeRepr(byteslike, reinterpret_cast<byte*>(result.address()),
2548 result_length, delimiter);
2549 return *result;
2550}
2551
2552RawObject Runtime::bytesSlice(Thread* thread, const Bytes& bytes, word start,
2553 word stop, word step) {
2554 word length = Slice::length(start, stop, step);
2555 if (length <= SmallBytes::kMaxLength) {
2556 byte buffer[SmallBytes::kMaxLength];
2557 for (word i = 0, j = start; i < length; i++, j += step) {
2558 buffer[i] = bytes.byteAt(j);
2559 }
2560 return SmallBytes::fromBytes({buffer, length});
2561 }
2562 HandleScope scope(thread);
2563 MutableBytes result(&scope, newMutableBytesUninitialized(length));
2564 {
2565 byte* dst = reinterpret_cast<byte*>(result.address());
2566 for (word i = 0, j = start; i < length; i++, j += step) {
2567 dst[i] = bytes.byteAt(j);
2568 }
2569 }
2570 return result.becomeImmutable();
2571}
2572
2573RawObject Runtime::bytesStartsWith(const Bytes& bytes, word bytes_len,
2574 const Bytes& prefix, word prefix_len,
2575 word start, word end) {
2576 DCHECK_BOUND(bytes_len, bytes.length());
2577 DCHECK_BOUND(prefix_len, prefix.length());
2578 Slice::adjustSearchIndices(&start, &end, bytes_len);
2579 if (start + prefix_len > end) {
2580 return Bool::falseObj();
2581 }
2582 for (word i = start, j = 0; j < prefix_len; i++, j++) {
2583 if (bytes.byteAt(i) != prefix.byteAt(j)) {
2584 return Bool::falseObj();
2585 }
2586 }
2587 return Bool::trueObj();
2588}
2589
2590RawObject Runtime::bytesTranslate(Thread* thread, const Bytes& bytes,
2591 word length, const Bytes& table,
2592 word table_len, const Bytes& del,
2593 word del_len) {
2594 DCHECK_BOUND(length, bytes.length());
2595 DCHECK_BOUND(del_len, del.length());
2596 // calculate mapping table
2597 byte new_byte[kByteTranslationTableLength];
2598 if (table == Bytes::empty()) {
2599 for (word i = 0; i < kByteTranslationTableLength; i++) {
2600 new_byte[i] = i;
2601 }
2602 } else {
2603 DCHECK_BOUND(table_len, table.length());
2604 DCHECK(table_len == kByteTranslationTableLength,
2605 "translation table must map every possible byte value");
2606 for (word i = 0; i < kByteTranslationTableLength; i++) {
2607 new_byte[i] = table.byteAt(i);
2608 }
2609 }
2610 // make initial pass to calculate length
2611 bool delete_byte[kByteTranslationTableLength] = {};
2612 for (word i = 0; i < del_len; i++) {
2613 delete_byte[del.byteAt(i)] = true;
2614 }
2615 word new_length = length;
2616 for (word i = 0; i < length; i++) {
2617 if (delete_byte[bytes.byteAt(i)]) {
2618 new_length--;
2619 }
2620 }
2621 // replace or delete each byte
2622 bool is_mutable = bytes.isMutableBytes();
2623 if (new_length <= SmallBytes::kMaxLength && !is_mutable) {
2624 byte buffer[SmallBytes::kMaxLength];
2625 for (word i = 0, j = 0; j < new_length; i++) {
2626 DCHECK(i < length, "reached end of bytes before finishing translation");
2627 byte current = bytes.byteAt(i);
2628 if (!delete_byte[current]) {
2629 buffer[j++] = new_byte[current];
2630 }
2631 }
2632 return SmallBytes::fromBytes({buffer, new_length});
2633 }
2634 HandleScope scope(thread);
2635 MutableBytes result(&scope, newMutableBytesUninitialized(new_length));
2636 for (word i = 0, j = 0; j < new_length; i++) {
2637 DCHECK(i < length, "reached end of bytes before finishing translation");
2638 byte current = bytes.byteAt(i);
2639 if (!delete_byte[current]) {
2640 result.byteAtPut(j++, new_byte[current]);
2641 }
2642 }
2643 return is_mutable ? *result : result.becomeImmutable();
2644}
2645
2646// List
2647
2648void Runtime::listEnsureCapacity(Thread* thread, const List& list,
2649 word min_capacity) {
2650 DCHECK_BOUND(min_capacity, SmallInt::kMaxValue);
2651 word curr_capacity = list.capacity();
2652 if (min_capacity <= curr_capacity) return;
2653 word new_capacity = newCapacity(curr_capacity, min_capacity);
2654 HandleScope scope(thread);
2655 Tuple old_array(&scope, list.items());
2656 MutableTuple new_array(&scope, newMutableTuple(new_capacity));
2657 new_array.replaceFromWith(0, *old_array, list.numItems());
2658 list.setItems(*new_array);
2659}
2660
2661void Runtime::listAdd(Thread* thread, const List& list, const Object& value) {
2662 word index = list.numItems();
2663 listEnsureCapacity(thread, list, index + 1);
2664 list.setNumItems(index + 1);
2665 list.atPut(index, *value);
2666}
2667
2668// Dict
2669
2670RawObject Runtime::newDict() {
2671 word num_attributes = Dict::kSize / kPointerSize;
2672 word size = Instance::allocationSize(num_attributes);
2673 uword address;
2674 CHECK(heap()->allocate(size, &address), "out of memory");
2675 return Instance::initializeWithZero(address, num_attributes, LayoutId::kDict);
2676}
2677
2678RawObject Runtime::newDictWithSize(word initial_size) {
2679 Thread* thread = Thread::current();
2680 HandleScope scope(thread);
2681 // NOTE: Multiplying 2 will leave (initial_size * 2 * 2/3) - initial_size
2682 // items available after initial_size items are inserted before dict is
2683 // expanded.
2684 word indices_len = Utils::nextPowerOfTwo(initial_size) * 2;
2685 Dict dict(&scope, newDict());
2686 dictAllocateArrays(thread, dict, indices_len);
2687 return *dict;
2688}
2689
2690static RawObject NEVER_INLINE callDunderEq(Thread* thread, RawObject o0_raw,
2691 RawObject o1_raw) {
2692 HandleScope scope(thread);
2693 Object o0(&scope, o0_raw);
2694 Object o1(&scope, o1_raw);
2695 Runtime* runtime = thread->runtime();
2696 Type o0_type(&scope, runtime->typeOf(*o0));
2697 Type o1_type(&scope, runtime->typeOf(*o1));
2698 if ((o0_type.flags() & Type::Flag::kHasObjectDunderEq) &&
2699 (o1_type.flags() & Type::Flag::kHasObjectDunderEq)) {
2700 return Bool::fromBool(*o0 == *o1);
2701 }
2702 Object compare_result(
2703 &scope, Interpreter::compareOperation(thread, CompareOp::EQ, o0, o1));
2704 if (compare_result.isErrorException()) return *compare_result;
2705 Object result(&scope, Interpreter::isTrue(thread, *compare_result));
2706 if (result.isErrorException()) return *result;
2707 return *result;
2708}
2709
2710RawObject Runtime::objectEquals(Thread* thread, RawObject o0, RawObject o1) {
2711 if (o0 == o1) {
2712 return Bool::trueObj();
2713 }
2714 // Shortcuts to catch the common SmallStr, LargeStr and SmallInt cases.
2715 // Remember that we always have to check the layout/type of `o0` and `o1`
2716 // to ensure `o1` is not a subclass of `o0` which would result in a
2717 // `o1.__eq__(o0)` call.
2718 if (!o0.isHeapObject()) {
2719 if (o1.isLargeStr()) {
2720 return Bool::falseObj();
2721 }
2722 if (!o1.isHeapObject()) {
2723 if (o0.layoutId() != o1.layoutId()) {
2724 if (o0.isBool() && o1.isSmallInt()) {
2725 return Bool::fromBool((Bool::cast(o0).value() ? 1 : 0) ==
2726 SmallInt::cast(o1).value());
2727 }
2728 if (o0.isSmallInt() && o1.isBool()) {
2729 return Bool::fromBool(SmallInt::cast(o0).value() ==
2730 (Bool::cast(o1).value() ? 1 : 0));
2731 }
2732 }
2733 return Bool::falseObj();
2734 }
2735 } else if (o0.isLargeStr()) {
2736 if (o1.isLargeStr()) {
2737 return Bool::fromBool(LargeStr::cast(o0).equals(LargeStr::cast(o1)));
2738 }
2739 if (!o1.isHeapObject()) {
2740 return Bool::falseObj();
2741 }
2742 }
2743 return callDunderEq(thread, o0, o1);
2744}
2745
2746// DictItemIterator
2747
2748RawObject Runtime::newDictItemIterator(Thread* thread, const Dict& dict) {
2749 HandleScope scope(thread);
2750 DictItemIterator result(&scope,
2751 newInstanceWithSize(LayoutId::kDictItemIterator,
2752 DictItemIterator::kSize));
2753 result.setIndex(0);
2754 result.setIterable(*dict);
2755 result.setNumFound(0);
2756 return *result;
2757}
2758
2759// DictItems
2760
2761RawObject Runtime::newDictItems(Thread* thread, const Dict& dict) {
2762 HandleScope scope(thread);
2763 DictItems result(&scope,
2764 newInstanceWithSize(LayoutId::kDictItems, DictItems::kSize));
2765 result.setDict(*dict);
2766 return *result;
2767}
2768
2769// DictKeyIterator
2770
2771RawObject Runtime::newDictKeyIterator(Thread* thread, const Dict& dict) {
2772 HandleScope scope(thread);
2773 DictKeyIterator result(&scope, newInstanceWithSize(LayoutId::kDictKeyIterator,
2774 DictKeyIterator::kSize));
2775 result.setIndex(0);
2776 result.setIterable(*dict);
2777 result.setNumFound(0);
2778 return *result;
2779}
2780
2781// DictKeys
2782
2783RawObject Runtime::newDictKeys(Thread* thread, const Dict& dict) {
2784 HandleScope scope(thread);
2785 DictKeys result(&scope,
2786 newInstanceWithSize(LayoutId::kDictKeys, DictKeys::kSize));
2787 result.setDict(*dict);
2788 return *result;
2789}
2790
2791// DictValueIterator
2792
2793RawObject Runtime::newDictValueIterator(Thread* thread, const Dict& dict) {
2794 HandleScope scope(thread);
2795 DictValueIterator result(&scope,
2796 newInstanceWithSize(LayoutId::kDictValueIterator,
2797 DictValueIterator::kSize));
2798 result.setIndex(0);
2799 result.setIterable(*dict);
2800 result.setNumFound(0);
2801 return *result;
2802}
2803
2804// DictValues
2805
2806RawObject Runtime::newDictValues(Thread* thread, const Dict& dict) {
2807 HandleScope scope(thread);
2808 DictValues result(
2809 &scope, newInstanceWithSize(LayoutId::kDictValues, DictValues::kSize));
2810 result.setDict(*dict);
2811 return *result;
2812}
2813
2814// Set
2815
2816RawObject Runtime::newSet() {
2817 HandleScope scope(Thread::current());
2818 Set result(&scope, newInstanceWithSize(LayoutId::kSet, Set::kSize));
2819 result.setNumItems(0);
2820 result.setNumFilled(0);
2821 result.setData(empty_tuple_);
2822 return *result;
2823}
2824
2825RawObject Runtime::newFrozenSet() {
2826 HandleScope scope(Thread::current());
2827 FrozenSet result(&scope,
2828 newInstanceWithSize(LayoutId::kFrozenSet, FrozenSet::kSize));
2829 result.setNumItems(0);
2830 result.setNumFilled(0);
2831 result.setData(empty_tuple_);
2832 return *result;
2833}
2834
2835RawObject Runtime::tupleSubseq(Thread* thread, const Tuple& tuple, word start,
2836 word length) {
2837 DCHECK_BOUND(start, tuple.length());
2838 DCHECK_BOUND(length, tuple.length() - start);
2839 if (length == 0) return empty_tuple_;
2840 HandleScope scope(thread);
2841 MutableTuple result(&scope, newMutableTuple(length));
2842 for (word i = 0; i < length; i++) {
2843 result.atPut(i, tuple.at(i + start));
2844 }
2845 return result.becomeImmutable();
2846}
2847
2848RawObject Runtime::newValueCell() {
2849 return newInstanceWithSize(LayoutId::kValueCell, ValueCell::kSize);
2850}
2851
2852RawObject Runtime::newWeakLink(Thread* thread, const Object& referent,
2853 const Object& prev, const Object& next) {
2854 HandleScope scope(thread);
2855 DCHECK(referent.isNoneType() || referent.isHeapObject(),
2856 "expected heap object or None");
2857 WeakLink link(&scope,
2858 newInstanceWithSize(LayoutId::kWeakLink, WeakLink::kSize));
2859 link.setReferent(*referent);
2860 link.setCallback(NoneType::object());
2861 link.setPrev(*prev);
2862 link.setNext(*next);
2863 return *link;
2864}
2865
2866RawObject Runtime::newWeakRef(Thread* thread, const Object& referent) {
2867 DCHECK(referent.isNoneType() || referent.isHeapObject(),
2868 "expected heap object or None");
2869 HandleScope scope(thread);
2870 WeakRef ref(&scope, newInstanceWithSize(LayoutId::kWeakRef, WeakRef::kSize));
2871 ref.setReferent(*referent);
2872 return *ref;
2873}
2874
2875void Runtime::collectAttributes(const Code& code, const Dict& attributes) {
2876 Thread* thread = Thread::current();
2877 HandleScope scope(thread);
2878 Bytes bc(&scope, code.code());
2879 Tuple names(&scope, code.names());
2880
2881 word len = bc.length();
2882 word self = 0;
2883 word total_locals = code.nlocals() + code.numFreevars() + code.numCellvars();
2884 word reverse_self = total_locals - self - 1;
2885 for (word i = 0; i < len - (kCompilerCodeUnitSize + 1);
2886 i += kCompilerCodeUnitSize) {
2887 byte op = bc.byteAt(i);
2888 int32_t arg = bc.byteAt(i + 1);
2889 while (op == Bytecode::EXTENDED_ARG) {
2890 i += kCompilerCodeUnitSize;
2891 op = bc.byteAt(i);
2892 arg = (arg << kBitsPerByte) | bc.byteAt(i + 1);
2893 }
2894 // Check for LOAD_FAST 0 (self) or LOAD_FAST_REVERSE(_UNCHECKED) nlocals-1
2895 bool is_load_self =
2896 (op == Bytecode::LOAD_FAST && arg == self) ||
2897 (op == Bytecode::LOAD_FAST_REVERSE && arg == reverse_self) ||
2898 (op == Bytecode::LOAD_FAST_REVERSE_UNCHECKED && arg == reverse_self);
2899 if (!is_load_self) {
2900 continue;
2901 }
2902 // Followed by a STORE_ATTR
2903 if (bc.byteAt(i + 2) != Bytecode::STORE_ATTR) {
2904 continue;
2905 }
2906 word name_index = bc.byteAt(i + 3);
2907 Str name(&scope, names.at(name_index));
2908 dictAtPutByStr(thread, attributes, name, name);
2909 }
2910}
2911
2912RawObject Runtime::classConstructor(const Type& type) {
2913 Thread* thread = Thread::current();
2914 return typeAtById(thread, type, ID(__init__));
2915}
2916
2917RawObject Runtime::attributeAt(Thread* thread, const Object& receiver,
2918 const Object& name) {
2919 return attributeAtSetLocation(thread, receiver, name, nullptr, nullptr);
2920}
2921
2922RawObject Runtime::attributeAtSetLocation(Thread* thread,
2923 const Object& receiver,
2924 const Object& name,
2925 LoadAttrKind* kind,
2926 Object* location_out) {
2927 DCHECK(isInternedStr(thread, name), "name must be an interned str");
2928 HandleScope scope(thread);
2929 Runtime* runtime = thread->runtime();
2930 Type type(&scope, runtime->typeOf(*receiver));
2931 if (kind != nullptr) *kind = LoadAttrKind::kUnknown;
2932 if (type.hasFlag(Type::Flag::kHasObjectDunderGetattribute)) {
2933 DCHECK(objectDunderGetattribute().isNoneType() ||
2934 typeLookupInMroById(thread, *type, ID(__getattribute__)) ==
2935 objectDunderGetattribute(),
2936 "object.__getattribute__ is expected");
2937 Object result(&scope, objectGetAttributeSetLocation(thread, receiver, name,
2938 location_out, kind));
2939 if (!result.isErrorNotFound()) {
2940 return *result;
2941 }
2942 result = thread->invokeMethod2(receiver, ID(__getattr__), name);
2943 if (!result.isErrorNotFound()) {
2944 return *result;
2945 }
2946 if (location_out != nullptr && location_out->isUnbound()) {
2947 // hasattr doesn't need the full exception; don't format and raise.
2948 return Error::notFound();
2949 }
2950 return objectRaiseAttributeError(thread, receiver, name);
2951 }
2952 if (type.hasFlag(Type::Flag::kHasModuleDunderGetattribute) &&
2953 runtime->isInstanceOfModule(*receiver)) {
2954 DCHECK(runtime->moduleDunderGetattribute().isNoneType() ||
2955 typeLookupInMroById(thread, *type, ID(__getattribute__)) ==
2956 runtime->moduleDunderGetattribute(),
2957 "module.__getattribute__ is expected");
2958 Module module(&scope, *receiver);
2959 Object result(&scope, moduleGetAttributeSetLocation(thread, module, name,
2960 location_out));
2961 if (!result.isErrorNotFound()) {
2962 // We have a result that can be cached.
2963 if (kind != nullptr) *kind = LoadAttrKind::kModule;
2964 return *result;
2965 }
2966 // Try again
2967 result = thread->invokeMethod2(receiver, ID(__getattr__), name);
2968 if (!result.isErrorNotFound()) {
2969 return *result;
2970 }
2971 if (location_out != nullptr && location_out->isUnbound()) {
2972 // hasattr doesn't need the full exception; don't format and raise.
2973 return Error::notFound();
2974 }
2975 return moduleRaiseAttributeError(thread, module, name);
2976 }
2977 if (type.hasFlag(Type::Flag::kHasTypeDunderGetattribute) &&
2978 runtime->isInstanceOfType(*receiver)) {
2979 DCHECK(runtime->typeDunderGetattribute().isNoneType() ||
2980 typeLookupInMroById(thread, *type, ID(__getattribute__)) ==
2981 runtime->typeDunderGetattribute(),
2982 "type.__getattribute__ is expected");
2983 Type object_as_type(&scope, *receiver);
2984 Object result(&scope, typeGetAttributeSetLocation(thread, object_as_type,
2985 name, location_out));
2986 if (!result.isErrorNotFound()) {
2987 // We have a result that can be cached.
2988 if (kind != nullptr && location_out->isValueCell()) {
2989 *kind = LoadAttrKind::kType;
2990 }
2991 return *result;
2992 }
2993 // Try again
2994 result = thread->invokeMethod2(receiver, ID(__getattr__), name);
2995 if (!result.isErrorNotFound()) {
2996 return *result;
2997 }
2998 if (location_out != nullptr && location_out->isUnbound()) {
2999 // hasattr doesn't need the full exception; don't format and raise.
3000 return Error::notFound();
3001 }
3002 Object type_name(&scope, object_as_type.name());
3003 return thread->raiseWithFmt(LayoutId::kAttributeError,
3004 "type object '%S' has no attribute '%S'",
3005 &type_name, &name);
3006 }
3007 if (receiver.isSuper()) {
3008 Super object_as_super(&scope, *receiver);
3009 Object result(&scope, superGetAttribute(thread, object_as_super, name));
3010 if (!result.isErrorNotFound()) {
3011 return *result;
3012 }
3013 if (location_out != nullptr && location_out->isUnbound()) {
3014 // hasattr doesn't need the full exception; don't format and raise.
3015 return Error::notFound();
3016 }
3017 return thread->raiseWithFmt(LayoutId::kAttributeError,
3018 "super object has no attribute '%S'", &name);
3019 }
3020 Object dunder_getattribute(
3021 &scope,
3022 Interpreter::lookupMethod(thread, receiver, ID(__getattribute__)));
3023 DCHECK(!dunder_getattribute.isErrorNotFound(),
3024 "__getattribute__ is expected to be found");
3025 if (UNLIKELY(dunder_getattribute.isError())) return *dunder_getattribute;
3026 Object result(&scope, Interpreter::callMethod2(thread, dunder_getattribute,
3027 receiver, name));
3028 if (!result.isErrorException() ||
3029 !thread->pendingExceptionMatches(LayoutId::kAttributeError)) {
3030 return *result;
3031 }
3032
3033 // Save the attribute error and clear it then attempt to call `__getattr__`.
3034 Object saved_type(&scope, thread->pendingExceptionType());
3035 Object saved_value(&scope, thread->pendingExceptionValue());
3036 Object saved_traceback(&scope, thread->pendingExceptionTraceback());
3037 thread->clearPendingException();
3038 result = thread->invokeMethod2(receiver, ID(__getattr__), name);
3039 if (result.isErrorNotFound()) {
3040 thread->setPendingExceptionType(*saved_type);
3041 thread->setPendingExceptionValue(*saved_value);
3042 thread->setPendingExceptionTraceback(*saved_traceback);
3043 return Error::exception();
3044 }
3045 return *result;
3046}
3047
3048RawObject Runtime::attributeAtById(Thread* thread, const Object& receiver,
3049 SymbolId id) {
3050 HandleScope scope(thread);
3051 Object name(&scope, symbols()->at(id));
3052 return attributeAt(thread, receiver, name);
3053}
3054
3055RawObject Runtime::attributeAtByCStr(Thread* thread, const Object& receiver,
3056 const char* name) {
3057 HandleScope scope(thread);
3058 Object name_obj(&scope, internStrFromCStr(thread, name));
3059 return attributeAt(thread, receiver, name_obj);
3060}
3061
3062RawObject Runtime::attributeDel(Thread* thread, const Object& receiver,
3063 const Object& name) {
3064 HandleScope scope(thread);
3065 Object dunder_delattr(
3066 &scope, Interpreter::lookupMethod(thread, receiver, ID(__delattr__)));
3067 DCHECK(!dunder_delattr.isErrorNotFound(),
3068 "__delattr__ is expected to be found");
3069 if (dunder_delattr.isErrorException()) return *dunder_delattr;
3070 return Interpreter::callMethod2(thread, dunder_delattr, receiver, name);
3071}
3072
3073RawObject Runtime::strConcat(Thread* thread, const Str& left,
3074 const Str& right) {
3075 HandleScope scope(thread);
3076 word left_len = left.length();
3077 word right_len = right.length();
3078 word result_len = left_len + right_len;
3079 // Small result
3080 if (result_len <= RawSmallStr::kMaxLength) {
3081 byte buffer[RawSmallStr::kMaxLength];
3082 left.copyTo(buffer, left_len);
3083 right.copyTo(buffer + left_len, right_len);
3084 return SmallStr::fromBytes(View<byte>(buffer, result_len));
3085 }
3086 // Large result
3087 LargeStr result(&scope, createLargeStr(result_len));
3088 left.copyTo(reinterpret_cast<byte*>(result.address()), left_len);
3089 right.copyTo(reinterpret_cast<byte*>(result.address() + left_len), right_len);
3090 return *result;
3091}
3092
3093RawObject Runtime::strJoin(Thread* thread, const Str& sep, const Tuple& items,
3094 word allocated) {
3095 HandleScope scope(thread);
3096 word result_len = 0;
3097 Str str(&scope, Str::empty());
3098 for (word i = 0; i < allocated; ++i) {
3099 str = strUnderlying(items.at(i));
3100 result_len += str.length();
3101 }
3102 if (allocated > 1) {
3103 result_len += sep.length() * (allocated - 1);
3104 }
3105 // Small result
3106 Object elt(&scope, NoneType::object());
3107 if (result_len <= RawSmallStr::kMaxLength) {
3108 byte buffer[RawSmallStr::kMaxLength];
3109 for (word i = 0, offset = 0; i < allocated; ++i) {
3110 elt = items.at(i);
3111 str = strUnderlying(*elt);
3112 word str_len = str.length();
3113 str.copyTo(&buffer[offset], str_len);
3114 offset += str_len;
3115 if ((i + 1) < allocated) {
3116 word sep_len = sep.length();
3117 sep.copyTo(&buffer[offset], sep_len);
3118 offset += sep.length();
3119 }
3120 }
3121 return SmallStr::fromBytes(View<byte>(buffer, result_len));
3122 }
3123 // Large result
3124 LargeStr result(&scope, createLargeStr(result_len));
3125 for (word i = 0, offset = 0; i < allocated; ++i) {
3126 elt = items.at(i);
3127 str = strUnderlying(*elt);
3128 word str_len = str.length();
3129 str.copyTo(reinterpret_cast<byte*>(result.address() + offset), str_len);
3130 offset += str_len;
3131 if ((i + 1) < allocated) {
3132 word sep_len = sep.length();
3133 sep.copyTo(reinterpret_cast<byte*>(result.address() + offset), sep_len);
3134 offset += sep_len;
3135 }
3136 }
3137 return *result;
3138}
3139
3140RawObject Runtime::strRepeat(Thread* thread, const Str& str, word count) {
3141 DCHECK(count > 0, "count should be positive");
3142 byte buffer[SmallStr::kMaxLength];
3143 word length = str.length();
3144 DCHECK(length > 0, "length should be positive");
3145 DCHECK_BOUND(count, SmallInt::kMaxValue / length);
3146 word new_length = length * count;
3147 if (new_length <= SmallStr::kMaxLength) {
3148 // SmallStr result
3149 for (word i = 0; i < new_length; i++) {
3150 buffer[i] = str.byteAt(i % length);
3151 }
3152 return SmallStr::fromBytes(View<byte>(buffer, new_length));
3153 }
3154 // LargeStr result
3155 HandleScope scope(thread);
3156 LargeStr result(&scope, createLargeStr(new_length));
3157 const byte* src;
3158 if (length <= SmallStr::kMaxLength) {
3159 // SmallStr original
3160 str.copyTo(buffer, length);
3161 src = buffer;
3162 } else {
3163 // LargeStr original
3164 LargeStr source(&scope, *str);
3165 src = reinterpret_cast<byte*>(source.address());
3166 }
3167 byte* dst = reinterpret_cast<byte*>(result.address());
3168 for (word i = 0; i < count; i++, dst += length) {
3169 std::memcpy(dst, src, length);
3170 }
3171 return *result;
3172}
3173
3174RawObject Runtime::strSlice(Thread* thread, const Str& str, word start,
3175 word stop, word step) {
3176 word length = Slice::length(start, stop, step);
3177 word start_index = str.offsetByCodePoints(0, start);
3178
3179 if (step == 1) {
3180 word end_index = str.offsetByCodePoints(start_index, length);
3181 word num_chars = end_index - start_index;
3182 return strSubstr(thread, str, start_index, num_chars);
3183 }
3184
3185 word result_length = 0;
3186 for (word i = 0, char_index = start_index; i < length;
3187 i++, char_index = str.offsetByCodePoints(char_index, step)) {
3188 result_length += UTF8::numChars(str.byteAt(char_index));
3189 }
3190
3191 if (result_length <= SmallStr::kMaxLength) {
3192 byte buffer[SmallStr::kMaxLength];
3193 for (word i = 0, char_index = start_index; i < result_length;
3194 char_index = str.offsetByCodePoints(char_index, step)) {
3195 word num_chars = UTF8::numChars(str.byteAt(char_index));
3196 str.copyToStartAt(&buffer[i], num_chars, char_index);
3197 i += num_chars;
3198 }
3199 return SmallStr::fromBytes({buffer, result_length});
3200 }
3201
3202 HandleScope scope(thread);
3203 MutableBytes result(
3204 &scope, thread->runtime()->newMutableBytesUninitialized(result_length));
3205 for (word i = 0, char_index = start_index; i < result_length;
3206 char_index = str.offsetByCodePoints(char_index, step)) {
3207 word num_chars = UTF8::numChars(str.byteAt(char_index));
3208 result.replaceFromWithStrStartAt(i, *str, num_chars, char_index);
3209 i += num_chars;
3210 }
3211 return result.becomeStr();
3212}
3213
3214// StrArray
3215
3216void Runtime::strArrayAddASCII(Thread* thread, const StrArray& array,
3217 byte code_point) {
3218 DCHECK(code_point <= kMaxASCII, "can only add ASCII in strArrayAddASCII");
3219 word num_items = array.numItems();
3220 word new_length = num_items + 1;
3221 strArrayEnsureCapacity(thread, array, new_length);
3222 array.setNumItems(new_length);
3223 MutableBytes::cast(array.items()).byteAtPut(num_items, code_point);
3224}
3225
3226void Runtime::strArrayAddCodePoint(Thread* thread, const StrArray& array,
3227 int32_t code_point) {
3228 DCHECK_BOUND(code_point, kMaxUnicode);
3229 RawSmallStr str = SmallStr::fromCodePoint(code_point);
3230 word num_items = array.numItems();
3231 word length = str.length();
3232 word new_length = num_items + length;
3233 strArrayEnsureCapacity(thread, array, new_length);
3234 byte* dst =
3235 reinterpret_cast<byte*>(MutableBytes::cast(array.items()).address());
3236 str.copyTo(dst + num_items, length);
3237 array.setNumItems(new_length);
3238}
3239
3240void Runtime::strArrayAddStr(Thread* thread, const StrArray& array,
3241 const Str& str) {
3242 word length = str.length();
3243 if (length == 0) return;
3244 word num_items = array.numItems();
3245 word new_length = length + num_items;
3246 strArrayEnsureCapacity(thread, array, new_length);
3247 byte* dst =
3248 reinterpret_cast<byte*>(MutableBytes::cast(array.items()).address());
3249 str.copyTo(dst + num_items, length);
3250 array.setNumItems(new_length);
3251}
3252
3253void Runtime::strArrayAddStrArray(Thread* thread, const StrArray& array,
3254 const StrArray& str) {
3255 word length = str.numItems();
3256 if (length == 0) return;
3257 word num_items = array.numItems();
3258 word new_length = length + num_items;
3259 strArrayEnsureCapacity(thread, array, new_length);
3260 byte* dst =
3261 reinterpret_cast<byte*>(MutableBytes::cast(array.items()).address());
3262 str.copyTo(dst + num_items, length);
3263 array.setNumItems(new_length);
3264}
3265
3266void Runtime::strArrayEnsureCapacity(Thread* thread, const StrArray& array,
3267 word min_capacity) {
3268 DCHECK_BOUND(min_capacity, SmallInt::kMaxValue);
3269 word curr_capacity = array.capacity();
3270 if (min_capacity <= curr_capacity) return;
3271 word new_capacity = newCapacity(curr_capacity, min_capacity);
3272 HandleScope scope(thread);
3273 MutableBytes new_bytes(&scope, newMutableBytesZeroed(new_capacity));
3274 new_bytes.replaceFromWith(0, MutableBytes::cast(array.items()),
3275 array.numItems());
3276 array.setItems(*new_bytes);
3277}
3278
3279RawObject Runtime::newCell() {
3280 return newInstanceWithSize(LayoutId::kCell, Cell::kSize);
3281}
3282
3283RawObject Runtime::newClassMethod() {
3284 return newInstanceWithSize(LayoutId::kClassMethod, ClassMethod::kSize);
3285}
3286
3287RawObject Runtime::newSuper() {
3288 return newInstanceWithSize(LayoutId::kSuper, Super::kSize);
3289}
3290
3291RawObject Runtime::newStrIterator(const Object& str) {
3292 HandleScope scope(Thread::current());
3293 StrIterator result(
3294 &scope, newInstanceWithSize(LayoutId::kStrIterator, StrIterator::kSize));
3295 result.setIndex(0);
3296 result.setIterable(*str);
3297 return *result;
3298}
3299
3300RawObject Runtime::newTupleIterator(const Tuple& tuple, word length) {
3301 HandleScope scope(Thread::current());
3302 TupleIterator result(&scope, newInstanceWithSize(LayoutId::kTupleIterator,
3303 TupleIterator::kSize));
3304 result.setIndex(0);
3305 result.setIterable(*tuple);
3306 result.setLength(length);
3307 return *result;
3308}
3309
3310RawObject Runtime::newContext(const Dict& data) {
3311 HandleScope scope(Thread::current());
3312 Context result(&scope,
3313 newInstanceWithSize(LayoutId::kContext, Context::kSize));
3314 result.setData(*data);
3315 result.setPrevContext(NoneType::object());
3316 return *result;
3317}
3318
3319RawObject Runtime::newContextVar(const Str& name, const Object& default_value) {
3320 HandleScope scope(Thread::current());
3321 ContextVar result(
3322 &scope, newInstanceWithSize(LayoutId::kContextVar, ContextVar::kSize));
3323 result.setName(*name);
3324 result.setDefaultValue(*default_value);
3325 return *result;
3326}
3327
3328RawObject Runtime::newToken(const Context& ctx, const ContextVar& var,
3329 const Object& old_value) {
3330 HandleScope scope(Thread::current());
3331 Token result(&scope, newInstanceWithSize(LayoutId::kToken, Token::kSize));
3332 result.setContext(*ctx);
3333 result.setVar(*var);
3334 result.setOldValue(*old_value);
3335 result.setUsed(false);
3336 return *result;
3337}
3338
3339RawObject Runtime::emptyFrozenSet() { return empty_frozen_set_; }
3340
3341RawObject Runtime::layoutNewAttribute(const Object& name, AttributeInfo info) {
3342 RawMutableTuple result = MutableTuple::cast(newMutableTuple(2));
3343 result.atPut(0, *name);
3344 result.atPut(1, info.asSmallInt());
3345 return result.becomeImmutable();
3346}
3347
3348static RawObject layoutFollowEdge(RawObject edges, RawObject key) {
3349 RawList list = List::cast(edges);
3350 DCHECK(list.numItems() % 2 == 0,
3351 "edges must contain an even number of elements");
3352 for (word i = 0, num_items = list.numItems(); i < num_items; i += 2) {
3353 if (list.at(i) == key) {
3354 return list.at(i + 1);
3355 }
3356 }
3357 return Error::notFound();
3358}
3359
3360static void layoutAddEdge(Thread* thread, Runtime* runtime, const List& edges,
3361 const Object& key, const Object& layout) {
3362 DCHECK(edges.numItems() % 2 == 0,
3363 "edges must contain an even number of elements");
3364 runtime->listAdd(thread, edges, key);
3365 runtime->listAdd(thread, edges, layout);
3366}
3367
3368bool Runtime::layoutFindAttribute(RawLayout layout, const Object& name,
3369 AttributeInfo* info) {
3370 // Check in-object attributes
3371 RawTuple in_object = Tuple::cast(layout.inObjectAttributes());
3372 RawObject name_raw = *name;
3373 for (word i = in_object.length() - 1; i >= 0; i--) {
3374 RawTuple entry = Tuple::cast(in_object.at(i));
3375 if (entry.at(0) == name_raw) {
3376 *info = AttributeInfo(entry.at(1));
3377 return true;
3378 }
3379 }
3380
3381 // Check overflow attributes
3382 if (!layout.hasTupleOverflow()) {
3383 return false;
3384 }
3385
3386 RawTuple overflow = Tuple::cast(layout.overflowAttributes());
3387 for (word i = overflow.length() - 1; i >= 0; i--) {
3388 RawTuple entry = Tuple::cast(overflow.at(i));
3389 if (entry.at(0) == name_raw) {
3390 *info = AttributeInfo(entry.at(1));
3391 return true;
3392 }
3393 }
3394 return false;
3395}
3396
3397RawObject Runtime::layoutCreateCopy(Thread* thread, const Layout& layout) {
3398 HandleScope scope(thread);
3399 LayoutId id = reserveLayoutId(thread);
3400 Layout new_layout(&scope, newLayout(id));
3401 new_layout.setDescribedType(layout.describedType());
3402 new_layout.setNumInObjectAttributes(layout.numInObjectAttributes());
3403 new_layout.setInObjectAttributes(layout.inObjectAttributes());
3404 new_layout.setOverflowAttributes(layout.overflowAttributes());
3405 layoutAtPut(id, *new_layout);
3406 return *new_layout;
3407}
3408
3409RawObject Runtime::layoutAddAttributeEntry(Thread* thread, const Tuple& entries,
3410 const Object& name,
3411 AttributeInfo info) {
3412 HandleScope scope(thread);
3413 word entries_len = entries.length();
3414 MutableTuple new_entries(&scope, newMutableTuple(entries_len + 1));
3415 new_entries.replaceFromWith(0, *entries, entries_len);
3416
3417 new_entries.atPut(entries_len, layoutNewAttribute(name, info));
3418
3419 return new_entries.becomeImmutable();
3420}
3421
3422static RawUnbound kDictOverflowLayoutTransitionEdgeName = Unbound::object();
3423
3424RawObject Runtime::typeDictOnlyLayout(Thread* thread, const Type& type,
3425 word num_in_object_attr) {
3426 HandleScope scope(thread);
3427 Layout type_instance_layout(&scope, type.instanceLayout());
3428 // Find a layout derived from type, whose in-object attributes' length matches
3429 // the needed `num_in_object_attr`.
3430 List edges(&scope, type_instance_layout.deletions());
3431 DCHECK(edges.numItems() % 2 == 0,
3432 "edges must contain an even number of elements");
3433 // This name is used only for the internal layout transition edge from
3434 // a layout to a new one with dict overflow.
3435 Object key(&scope, kDictOverflowLayoutTransitionEdgeName);
3436 for (word i = 0, num_items = edges.numItems(); i < num_items; i += 2) {
3437 if (edges.at(i) == key) {
3438 if (Layout::cast(edges.at(i + 1)).numInObjectAttributes() ==
3439 num_in_object_attr) {
3440 return edges.at(i + 1);
3441 }
3442 }
3443 }
3444 Layout new_layout(&scope, layoutCreateCopy(thread, type_instance_layout));
3445 // This annotates `new_layout` to return it when requested next time.
3446 new_layout.setNumInObjectAttributes(num_in_object_attr);
3447 new_layout.setInObjectAttributes(emptyTuple());
3448 new_layout.setOverflowAttributes(emptyTuple());
3449 new_layout.setDictOverflowOffset(new_layout.overflowOffset());
3450 // Add the edge to the existing layout.
3451 layoutAddEdge(thread, this, edges, key, new_layout);
3452 return *new_layout;
3453}
3454
3455RawObject Runtime::layoutAddAttribute(Thread* thread, const Layout& layout,
3456 const Object& name, word flags,
3457 AttributeInfo* info) {
3458 // Check if a edge for the attribute addition already exists
3459 RawObject result = layoutFollowEdge(layout.additions(), *name);
3460 if (!result.isError()) {
3461 bool found = layoutFindAttribute(Layout::cast(result), name, info);
3462 DCHECK(found, "couldn't find attribute on new layout");
3463 return result;
3464 }
3465
3466 // Create a new layout and figure out where to place the attribute
3467 HandleScope scope(thread);
3468 Layout new_layout(&scope, layoutCreateCopy(thread, layout));
3469 Tuple inobject(&scope, layout.inObjectAttributes());
3470 if (inobject.length() < layout.numInObjectAttributes()) {
3471 *info = AttributeInfo(inobject.length() * kPointerSize,
3472 flags | AttributeFlags::kInObject);
3473 new_layout.setInObjectAttributes(
3474 layoutAddAttributeEntry(thread, inobject, name, *info));
3475 } else {
3476 Tuple overflow(&scope, layout.overflowAttributes());
3477 *info = AttributeInfo(overflow.length(), flags);
3478 new_layout.setOverflowAttributes(
3479 layoutAddAttributeEntry(thread, overflow, name, *info));
3480 }
3481
3482 // Add the edge to the existing layout
3483 List edges(&scope, layout.additions());
3484 layoutAddEdge(thread, this, edges, name, new_layout);
3485
3486 return *new_layout;
3487}
3488
3489RawObject Runtime::layoutSetDescribedType(Thread* thread, const Layout& from,
3490 const Type& to) {
3491 // Check if a edge for the attribute addition already exists
3492 HandleScope scope(thread);
3493 MutableTuple transitions(&scope, layout_type_transitions_);
3494 word length = transitions.length();
3495 word first_free = length;
3496 for (word i = 0; i < length; i += LayoutTypeTransition::kTransitionSize) {
3497 RawObject found_from = transitions.at(i + LayoutTypeTransition::kFrom);
3498 if (found_from == from &&
3499 transitions.at(i + LayoutTypeTransition::kTo) == to) {
3500 // The transition exists; return the result layout
3501 return transitions.at(i + LayoutTypeTransition::kResult);
3502 }
3503 if (first_free == length && found_from == SmallInt::fromWord(0)) {
3504 // There's an empty slot we can use to store the transition
3505 first_free = i;
3506 }
3507 }
3508
3509 // Make a new layout and transition the type
3510 Layout result(&scope, layoutCreateCopy(thread, from));
3511 result.setDescribedType(*to);
3512
3513 // If needed, grow the table
3514 word index = first_free;
3515 word needed_length = index + LayoutTypeTransition::kTransitionSize;
3516 if (needed_length > length) {
3517 word new_length = newCapacity(length, /*min_capacity=*/needed_length);
3518 MutableTuple new_tuple(&scope, newMutableTuple(new_length));
3519 new_tuple.replaceFromWith(0, *transitions, length);
3520 layout_type_transitions_ = *new_tuple;
3521 transitions = *new_tuple;
3522 }
3523
3524 // Add the edge to the layout
3525 transitions.atPut(index + LayoutTypeTransition::kFrom, *from);
3526 transitions.atPut(index + LayoutTypeTransition::kTo, *to);
3527 transitions.atPut(index + LayoutTypeTransition::kResult, *result);
3528
3529 return *result;
3530}
3531
3532static RawObject markEntryDeleted(Thread* thread, RawObject entries,
3533 const Object& name) {
3534 HandleScope scope(thread);
3535 Tuple entries_old(&scope, entries);
3536 word length = entries_old.length();
3537 DCHECK(length > 0, "length must be positive");
3538 Runtime* runtime = thread->runtime();
3539 MutableTuple entries_new(&scope, runtime->newMutableTuple(length));
3540 Object zero(&scope, SmallInt::fromWord(0));
3541 Tuple entry(&scope, runtime->emptyTuple());
3542 for (word i = 0; i < length; i++) {
3543 entry = entries_old.at(i);
3544 if (entry.at(0) == name) {
3545 AttributeInfo old_info(entry.at(1));
3546 AttributeInfo info(old_info.offset(), AttributeFlags::kDeleted);
3547 entry = runtime->layoutNewAttribute(/*name=*/zero, info);
3548 }
3549 entries_new.atPut(i, *entry);
3550 }
3551 return entries_new.becomeImmutable();
3552}
3553
3554RawObject Runtime::layoutDeleteAttribute(Thread* thread, const Layout& layout,
3555 const Object& name,
3556 AttributeInfo info) {
3557 // Check if an edge exists for removing the attribute
3558 RawObject next_layout = layoutFollowEdge(layout.deletions(), *name);
3559 if (!next_layout.isError()) {
3560 return next_layout;
3561 }
3562
3563 // No edge was found, create a new layout and add an edge
3564 HandleScope scope(thread);
3565 Layout new_layout(&scope, layoutCreateCopy(thread, layout));
3566 if (info.isInObject()) {
3567 new_layout.setInObjectAttributes(
3568 markEntryDeleted(thread, layout.inObjectAttributes(), name));
3569 } else {
3570 new_layout.setOverflowAttributes(
3571 markEntryDeleted(thread, layout.overflowAttributes(), name));
3572 }
3573
3574 // Add the edge to the existing layout
3575 List edges(&scope, layout.deletions());
3576 layoutAddEdge(thread, this, edges, name, new_layout);
3577
3578 return *new_layout;
3579}
3580
3581void Runtime::layoutSetTupleOverflow(RawLayout layout) {
3582 layout.setOverflowAttributes(emptyTuple());
3583}
3584
3585void Runtime::clearHandleScopes() {
3586 MutexGuard lock(&threads_mutex_);
3587 for (Thread* thread = main_thread_; thread != nullptr;
3588 thread = thread->next()) {
3589 Handles* handles = thread->handles();
3590 Object* handle = handles->head();
3591 while (handle != nullptr) {
3592 handle = handle->nextHandle();
3593 handles->pop(handle);
3594 }
3595 }
3596}
3597
3598void Runtime::freeApiHandles() {
3599 // Dealloc the Module handles first as they are the handle roots
3600 Thread* thread = Thread::current();
3601 HandleScope scope(thread);
3602 Dict modules(&scope, modules_);
3603 // Clear the modules dict and run a GC, to run dealloc slots on any now-dead
3604 // NativeProxy objects.
3605 dictClear(thread, modules);
3606
3607 // Dealloc modules referenced by modules_by_index.
3608 freeExtensionModules(thread);
3609
3610 // Process any native instance that is only referenced through the NativeProxy
3611 for (;;) {
3612 word before = numExtensionObjects(this) + numApiHandles(this);
3613 collectGarbage();
3614 word after = numExtensionObjects(this) + numApiHandles(this);
3615 word num_handles_collected = before - after;
3616 if (num_handles_collected == 0) {
3617 // Fixpoint: no change in tracking
3618 break;
3619 }
3620 }
3621 collectGarbage();
3622
3623 // Finally, skip trying to cleanly deallocate the object. Just free the
3624 // memory without calling the deallocation functions.
3625 disposeApiHandles(this);
3626 disposeExtensionObjects(this);
3627}
3628
3629RawObject Runtime::bytesToInt(Thread* thread, const Bytes& bytes,
3630 endian endianness, bool is_signed) {
3631 word length = bytes.length();
3632 DCHECK(length <= kMaxWord - kWordSize, "huge length will overflow");
3633 if (length == 0) {
3634 return SmallInt::fromWord(0);
3635 }
3636
3637 // Positive numbers that end up having the highest bit of their highest digit
3638 // set need an extra zero digit.
3639 byte high_byte = bytes.byteAt(endianness == endian::big ? 0 : length - 1);
3640 bool high_bit = high_byte & (1 << (kBitsPerByte - 1));
3641 bool extra_digit = high_bit && !is_signed && length % kWordSize == 0;
3642 word num_digits = (length + (kWordSize - 1)) / kWordSize + extra_digit;
3643 HandleScope scope(thread);
3644 LargeInt result(&scope, createLargeInt(num_digits));
3645
3646 byte sign_extension = (is_signed && high_bit) ? kMaxByte : 0;
3647 if (endianness == endian::little && endian::native == endian::little) {
3648 result.copyFrom(*bytes, sign_extension);
3649 } else {
3650 for (word d = 0; d < num_digits; ++d) {
3651 uword digit = 0;
3652 for (int w = 0; w < kWordSize; ++w) {
3653 word idx = d * kWordSize + w;
3654 byte b;
3655 if (idx >= length) {
3656 b = sign_extension;
3657 } else {
3658 b = bytes.byteAt(endianness == endian::big ? length - idx - 1 : idx);
3659 }
3660 digit |= static_cast<uword>(b) << (w * kBitsPerByte);
3661 }
3662 result.digitAtPut(d, digit);
3663 }
3664 }
3665 return normalizeLargeInt(thread, result);
3666}
3667
3668RawObject Runtime::normalizeLargeInt(Thread* thread,
3669 const LargeInt& large_int) {
3670 word shrink_to_digits = large_int.numDigits();
3671 for (word digit = large_int.digitAt(shrink_to_digits - 1), next_digit;
3672 shrink_to_digits > 1; --shrink_to_digits, digit = next_digit) {
3673 next_digit = large_int.digitAt(shrink_to_digits - 2);
3674 // break if we have neither a redundant sign-extension nor a redundnant
3675 // zero-extension.
3676 if ((digit != -1 || next_digit >= 0) && (digit != 0 || next_digit < 0)) {
3677 break;
3678 }
3679 }
3680 if (shrink_to_digits == 1 && SmallInt::isValid(large_int.digitAt(0))) {
3681 return SmallInt::fromWord(large_int.digitAt(0));
3682 }
3683 if (shrink_to_digits == large_int.numDigits()) {
3684 return *large_int;
3685 }
3686
3687 // Shrink. Future Optimization: Shrink in-place instead of copying.
3688 HandleScope scope(thread);
3689 LargeInt result(&scope, createLargeInt(shrink_to_digits));
3690 for (word i = 0; i < shrink_to_digits; ++i) {
3691 result.digitAtPut(i, large_int.digitAt(i));
3692 }
3693 return *result;
3694}
3695
3696static uword addWithCarry(uword x, uword y, uword carry_in, uword* carry_out) {
3697 DCHECK(carry_in <= 1, "carry must be 0 or 1");
3698 uword sum;
3699 uword carry0 = __builtin_add_overflow(x, y, &sum);
3700 uword carry1 = __builtin_add_overflow(sum, carry_in, &sum);
3701 *carry_out = carry0 | carry1;
3702 return sum;
3703}
3704
3705RawObject Runtime::intAdd(Thread* thread, const Int& left, const Int& right) {
3706 if (left.isSmallInt() && right.isSmallInt()) {
3707 // Take a shortcut because we know the result fits in a word.
3708 word left_digit = SmallInt::cast(*left).value();
3709 word right_digit = SmallInt::cast(*right).value();
3710 return newInt(left_digit + right_digit);
3711 }
3712
3713 HandleScope scope(thread);
3714 word left_digits = left.numDigits();
3715 word right_digits = right.numDigits();
3716 Int longer(&scope, left_digits > right_digits ? *left : *right);
3717 Int shorter(&scope, left_digits <= right_digits ? *left : *right);
3718
3719 word shorter_digits = shorter.numDigits();
3720 word longer_digits = longer.numDigits();
3721 word result_digits = longer_digits + 1;
3722 LargeInt result(&scope, createLargeInt(result_digits));
3723 uword carry = 0;
3724 for (word i = 0; i < shorter_digits; i++) {
3725 uword sum =
3726 addWithCarry(longer.digitAt(i), shorter.digitAt(i), carry, &carry);
3727 result.digitAtPut(i, sum);
3728 }
3729 uword shorter_sign_extension = shorter.isNegative() ? kMaxUword : 0;
3730 for (word i = shorter_digits; i < longer_digits; i++) {
3731 uword sum =
3732 addWithCarry(longer.digitAt(i), shorter_sign_extension, carry, &carry);
3733 result.digitAtPut(i, sum);
3734 }
3735 uword longer_sign_extension = longer.isNegative() ? kMaxUword : 0;
3736 uword high_digit = longer_sign_extension + shorter_sign_extension + carry;
3737 result.digitAtPut(result_digits - 1, high_digit);
3738 return normalizeLargeInt(thread, result);
3739}
3740
3741RawObject Runtime::intBinaryAnd(Thread* thread, const Int& left,
3742 const Int& right) {
3743 word left_digits = left.numDigits();
3744 word right_digits = right.numDigits();
3745 if (left_digits == 1 && right_digits == 1) {
3746 return newInt(left.asWord() & right.asWord());
3747 }
3748
3749 HandleScope scope(thread);
3750 Int longer(&scope, left_digits > right_digits ? *left : *right);
3751 Int shorter(&scope, left_digits <= right_digits ? *left : *right);
3752
3753 word num_digits = longer.numDigits();
3754 LargeInt result(&scope, createLargeInt(num_digits));
3755 for (word i = 0, e = shorter.numDigits(); i < e; ++i) {
3756 result.digitAtPut(i, longer.digitAt(i) & shorter.digitAt(i));
3757 }
3758 if (shorter.isNegative()) {
3759 for (word i = shorter.numDigits(); i < num_digits; ++i) {
3760 result.digitAtPut(i, longer.digitAt(i));
3761 }
3762 } else {
3763 for (word i = shorter.numDigits(); i < num_digits; ++i) {
3764 result.digitAtPut(i, 0);
3765 }
3766 }
3767 return normalizeLargeInt(thread, result);
3768}
3769
3770RawObject Runtime::intInvert(Thread* thread, const Int& value) {
3771 word num_digits = value.numDigits();
3772 if (num_digits == 1) {
3773 word value_word = value.asWord();
3774 return newInt(~value_word);
3775 }
3776 HandleScope scope(thread);
3777 LargeInt large_int(&scope, *value);
3778 LargeInt result(&scope, createLargeInt(num_digits));
3779 for (word i = 0; i < num_digits; ++i) {
3780 uword digit = large_int.digitAt(i);
3781 result.digitAtPut(i, ~digit);
3782 }
3783 DCHECK(result.isValid(), "valid large integer");
3784 return *result;
3785}
3786
3787RawObject Runtime::intNegate(Thread* thread, const Int& value) {
3788 word num_digits = value.numDigits();
3789 if (num_digits == 1) {
3790 word value_word = value.asWord();
3791 // Negating kMinWord results in a number with two digits.
3792 if (value_word == kMinWord) {
3793 const uword min_word[] = {static_cast<uword>(kMinWord), 0};
3794 return newLargeIntWithDigits(min_word);
3795 }
3796 return newInt(-value_word);
3797 }
3798
3799 HandleScope scope(thread);
3800 LargeInt large_int(&scope, *value);
3801
3802 auto digits_zero = [&](word up_to_digit) {
3803 for (word i = 0; i < up_to_digit; i++) {
3804 if (large_int.digitAt(i) != 0) {
3805 return false;
3806 }
3807 }
3808 return true;
3809 };
3810
3811 // The result of negating a number like `digits == {0, 0, ..., 0x800000.. }`
3812 // needs an extra digit.
3813 uword highest_digit = large_int.digitAt(num_digits - 1);
3814 if (highest_digit == static_cast<uword>(kMinWord) &&
3815 digits_zero(num_digits - 1)) {
3816 LargeInt result(&scope, createLargeInt(num_digits + 1));
3817 for (word i = 0; i < num_digits; i++) {
3818 result.digitAtPut(i, large_int.digitAt(i));
3819 }
3820 result.digitAtPut(num_digits, 0);
3821 DCHECK(result.isValid(), "Invalid LargeInt");
3822 return *result;
3823 }
3824 // The result of negating a number like `digits == {0, 0, ..., 0x800000.., 0}`
3825 // is one digit shorter.
3826 if (highest_digit == 0 &&
3827 large_int.digitAt(num_digits - 2) == static_cast<uword>(kMinWord) &&
3828 digits_zero(num_digits - 2)) {
3829 LargeInt result(&scope, createLargeInt(num_digits - 1));
3830 for (word i = 0; i < num_digits - 1; i++) {
3831 result.digitAtPut(i, large_int.digitAt(i));
3832 }
3833 DCHECK(result.isValid(), "Invalid LargeInt");
3834 return *result;
3835 }
3836
3837 LargeInt result(&scope, createLargeInt(num_digits));
3838 word carry = 1;
3839 for (word i = 0; i < num_digits; i++) {
3840 uword digit = large_int.digitAt(i);
3841 static_assert(sizeof(digit) == sizeof(long), "invalid builtin size");
3842 carry = __builtin_uaddl_overflow(~digit, carry, &digit);
3843 result.digitAtPut(i, digit);
3844 }
3845 DCHECK(carry == 0, "Carry should be zero");
3846 DCHECK(result.isValid(), "Invalid LargeInt");
3847 return *result;
3848}
3849
3850// The division algorithm operates on half words. This is because to implement
3851// multiword division we require a doubleword division operation such as
3852// (`uint128_t / uint64_t -> uint128_t`). Such an operation does not exist on
3853// most architectures (x86_64 only has `uint128_t / uint64_t -> uint64_t`,
3854// aarch64 only `uint64_t / uint64_t -> uint64_t`). Instead we perform the
3855// algorithm on half words and use a `uint64_t / uint32_t -> uint64_t` division.
3856// This is easier and faster than trying to emulate a doubleword division.
3857typedef uint32_t halfuword;
3858static_assert(sizeof(halfuword) == sizeof(uword) / 2, "halfuword size");
3859
3860const int kBitsPerHalfWord = kBitsPerByte * sizeof(halfuword);
3861
3862static void halvesInvert(halfuword* halves, word num_halves) {
3863 for (word i = 0; i < num_halves; i++) {
3864 halves[i] = ~halves[i];
3865 }
3866}
3867
3868static void halvesNegate(halfuword* halves, word num_halves) {
3869 uword carry = 1;
3870 for (word i = 0; i < num_halves; i++) {
3871 halfuword half = uword{~halves[i]} + carry;
3872 halves[i] = half;
3873 carry &= (half == 0);
3874 }
3875}
3876
3877static halfuword halvesAdd(halfuword* dest, const halfuword* src,
3878 word num_halves) {
3879 halfuword carry = 0;
3880 for (word i = 0; i < num_halves; i++) {
3881 uword sum = uword{dest[i]} + src[i] + carry;
3882 dest[i] = static_cast<halfuword>(sum);
3883 carry = sum >> kBitsPerHalfWord;
3884 }
3885 return carry;
3886}
3887
3888static void halvesIncrement(halfuword* halves, word num_halves,
3889 bool overflow_ok) {
3890 for (word i = 0; i < num_halves; i++) {
3891 halfuword half = halves[i] + 1;
3892 halves[i] = half;
3893 // We are done if there was no overflow.
3894 if (half != 0) break;
3895 DCHECK(overflow_ok || i < num_halves - 1, "overflow");
3896 }
3897}
3898
3899static void halvesFromIntMagnitude(halfuword* halves, const Int& number) {
3900 word num_digits = number.numDigits();
3901 for (word i = 0; i < num_digits; i++) {
3902 uword digit = number.digitAt(i);
3903 halves[i * 2] = static_cast<halfuword>(digit);
3904 halves[i * 2 + 1] = digit >> kBitsPerHalfWord;
3905 }
3906 if (number.isNegative()) {
3907 halvesNegate(halves, num_digits * 2);
3908 }
3909}
3910
3911// Given an array of size `num_halves` checks how many items at the end of the
3912// array is zero and returns a reduced length without them. Put another way:
3913// It drops leading zeros from an arbitrary precision little endian number.
3914static word halvesNormalize(halfuword* halves, word num_halves) {
3915 while (halves[num_halves - 1] == 0) {
3916 num_halves--;
3917 DCHECK(num_halves > 0, "must not have every digit zero");
3918 }
3919 return num_halves;
3920}
3921
3922static void halvesDecrement(halfuword* halves, word num_halves) {
3923 DCHECK(num_halves > 0, "must have at least one half");
3924 for (word i = 0; i < num_halves; i++) {
3925 halfuword half = halves[i] - 1;
3926 halves[i] = half;
3927 // We are done if there is no borrow left.
3928 if (half != ~halfuword{0}) return;
3929 }
3930 // Must only be used in situations that cannot underflow.
3931 UNREACHABLE("underflow");
3932}
3933
3934static void halvesShiftLeft(halfuword* halves, word num_halves, word shift) {
3935 DCHECK(shift < kBitsPerHalfWord, "must not shift more than a halfuword");
3936 if (shift == 0) return;
3937
3938 halfuword prev = 0;
3939 for (word i = 0; i < num_halves; i++) {
3940 halfuword half = halves[i];
3941 halves[i] = (half << shift) | (prev >> (kBitsPerHalfWord - shift));
3942 prev = half;
3943 }
3944 DCHECK(prev >> (kBitsPerHalfWord - shift) == 0, "must not overflow");
3945}
3946
3947static void halvesShiftRight(halfuword* halves, word num_halves, word shift) {
3948 DCHECK(shift < kBitsPerHalfWord, "must not shift more than a halfuword");
3949 if (shift == 0) return;
3950
3951 halfuword prev = 0;
3952 for (word i = num_halves - 1; i >= 0; i--) {
3953 halfuword half = halves[i];
3954 halves[i] = (half >> shift) | (prev << (kBitsPerHalfWord - shift));
3955 prev = half;
3956 }
3957}
3958
3959static RawObject largeIntFromHalves(Thread* thread, const halfuword* halves,
3960 word num_halves) {
3961 DCHECK(num_halves % 2 == 0, "must have even number of halves");
3962 word digits = num_halves / 2;
3963 HandleScope scope(thread);
3964 Runtime* runtime = thread->runtime();
3965 LargeInt result(&scope, runtime->createLargeInt(digits));
3966 for (word i = 0; i < digits; i++) {
3967 uword digit =
3968 halves[i * 2] | (uword{halves[i * 2 + 1]} << kBitsPerHalfWord);
3969 result.digitAtPut(i, digit);
3970 }
3971 return runtime->normalizeLargeInt(thread, result);
3972}
3973
3974// Compute quotient and modulo of dividing a large integer through a divisor
3975// whose magnitude fits in a `halfuword`.
3976static void divideModuloSingleHalfDivisor(Thread* thread, const Int& dividend,
3977 word divisor, Object* quotient,
3978 Object* modulo) {
3979 DCHECK(divisor >= 0 ? static_cast<halfuword>(divisor) == divisor
3980 : static_cast<halfuword>(-divisor) == -divisor,
3981 "divisor magnitude fits in half word");
3982
3983 word dividend_digits = dividend.numDigits();
3984 bool same_sign = dividend.isNegative() == (divisor < 0);
3985 halfuword divisor_half = divisor < 0 ? -divisor : divisor;
3986 uword result_halves = dividend_digits * 2;
3987 std::unique_ptr<halfuword[]> result(new halfuword[result_halves]);
3988 halvesFromIntMagnitude(result.get(), dividend);
3989 if (!same_sign) {
3990 halvesDecrement(result.get(), result_halves);
3991 }
3992 word significant_result_halves = halvesNormalize(result.get(), result_halves);
3993
3994 halfuword remainder = 0;
3995 for (word i = significant_result_halves - 1; i >= 0; i--) {
3996 uword digit = (uword{remainder} << kBitsPerHalfWord) | result[i];
3997 result[i] = digit / divisor_half;
3998 remainder = digit % divisor_half;
3999 // Note that the division result fits into a halfuword, because the upper
4000 // half is the remainder from last round and therefore smaller than
4001 // `divisor_half`.
4002 }
4003
4004 Runtime* runtime = thread->runtime();
4005 if (quotient) {
4006 if (!same_sign) {
4007 // Compute `-1 - quotient == -1 + (~quotient + 1) == ~quotient`.
4008 halvesInvert(result.get(), result_halves);
4009 }
4010
4011 *quotient = largeIntFromHalves(thread, result.get(), result_halves);
4012 }
4013 if (modulo) {
4014 word modulo_word;
4015 if (same_sign) {
4016 modulo_word = remainder;
4017 } else {
4018 modulo_word = -static_cast<word>(remainder) + divisor_half - 1;
4019 }
4020 if (divisor < 0) {
4021 modulo_word = -modulo_word;
4022 }
4023 *modulo = runtime->newInt(modulo_word);
4024 }
4025}
4026
4027// Perform unsigned integer division with multi-half dividend and divisor.
4028static void unsignedDivideRemainder(halfuword* result, word result_halves,
4029 halfuword* dividend,
4030 const halfuword* divisor,
4031 word divisor_halves) {
4032 // See Hackers Delight 9-2 "Multiword Division" and Knuth TAOCP volume 2,
4033 // 4.3.1 for this algorithm.
4034 DCHECK(divisor_halves > 1, "need at least 2 divisor halves");
4035 // Expects the divisor to be normalized by left shifting until the highest bit
4036 // is set. This ensures that the guess performed in each iteration step is off
4037 // by no more than 2 (see Knuth for details and a proof).
4038 DCHECK((divisor[divisor_halves - 1] & (1 << (kBitsPerHalfWord - 1))) != 0,
4039 "need normalized divisor");
4040
4041 // Performs some arithmetic with no more than half the bits of a `uword`.
4042 const uword half_mask = (uword{1} << kBitsPerHalfWord) - 1;
4043
4044 for (word r = result_halves - 1; r >= 0; r--) {
4045 // Take the two highest words of the dividend. We implicitly have
4046 // `dividend_halves = result_halves + divisor_halves - 1` (the actual
4047 // dividend array is guaranteed to have at least one more half filled with
4048 // zero on top for the first round). Since the dividend shrinks by 1 half
4049 // each round, the two highest digits can be found starting at
4050 // `r + divisor_halves - 1`.
4051 uword dividend_high_word =
4052 (uword{dividend[r + divisor_halves]} << kBitsPerHalfWord) |
4053 uword{dividend[r + divisor_halves - 1]};
4054 uword divisor_half = divisor[divisor_halves - 1];
4055
4056 // Guess this result half by dividing the two highest dividend halves.
4057 // The guess gets us close: `guess_quot - 2 <= quot <= guess_quot`.
4058 uword guess_quot = dividend_high_word / divisor_half;
4059 uword guess_remainder = dividend_high_word % divisor_half;
4060
4061 // Iterate until the guess is exact.
4062 while (guess_quot > half_mask ||
4063 guess_quot * divisor[divisor_halves - 2] >
4064 ((guess_remainder << kBitsPerHalfWord) |
4065 dividend[r + divisor_halves - 2])) {
4066 guess_quot--;
4067 guess_remainder += divisor_half;
4068 if (guess_remainder > half_mask) break;
4069 }
4070
4071 // Multiply and subtract from dividend.
4072 uword borrow = 0;
4073 for (word d = 0; d < divisor_halves; d++) {
4074 uword product = guess_quot * divisor[d];
4075 word diff =
4076 static_cast<word>(dividend[d + r]) - borrow - (product & half_mask);
4077 dividend[d + r] = static_cast<halfuword>(diff);
4078 borrow = (product >> kBitsPerHalfWord) - (diff >> kBitsPerHalfWord);
4079 }
4080 word diff = static_cast<word>(dividend[r + divisor_halves]) - borrow;
4081 dividend[r + divisor_halves] = static_cast<halfuword>(diff);
4082
4083 // If we subtracted too much, add back.
4084 if (diff < 0) {
4085 guess_quot--;
4086 halfuword carry = halvesAdd(÷nd[r], divisor, divisor_halves);
4087 dividend[r + divisor_halves] += carry;
4088 }
4089
4090 result[r] = guess_quot;
4091 }
4092}
4093
4094// Like Runtime::intDivideModulo() but specifically for the case of the
4095// divisor's magnitued being bigger than the dividend's.
4096static void divideWithBiggerDivisor(Thread* thread, const Int& dividend,
4097 const Int& divisor, Object* quotient,
4098 Object* modulo) {
4099 if (dividend.isZero()) {
4100 if (quotient != nullptr) *quotient = SmallInt::fromWord(0);
4101 if (modulo != nullptr) *modulo = SmallInt::fromWord(0);
4102 return;
4103 }
4104 bool same_sign = dividend.isNegative() == divisor.isNegative();
4105 if (quotient != nullptr) {
4106 *quotient = SmallInt::fromWord(same_sign ? 0 : -1);
4107 }
4108 if (modulo != nullptr) {
4109 if (!same_sign) {
4110 *modulo = thread->runtime()->intAdd(thread, divisor, dividend);
4111 } else if (dividend.isBool()) {
4112 *modulo = convertBoolToInt(*dividend);
4113 } else {
4114 *modulo = *dividend;
4115 }
4116 }
4117}
4118
4119bool Runtime::intDivideModulo(Thread* thread, const Int& dividend,
4120 const Int& divisor, Object* quotient,
4121 Object* modulo) {
4122 // Some notes for understanding this code:
4123 // - This is built around an unsigned division algorithm in
4124 // `unsignedDivideRemainder()`.
4125 // - Remember that this implements floor div and modulo which is different
4126 // from C++ giving you truncated div and remainder when operands are
4127 // negative.
4128 // - To build a signed floor division from an unsigned division primitive we
4129 // use the following formula when the sign of dividend and divisor differs:
4130 // floor_div = -1 - (abs(dividend) - 1) / abs(divisor)
4131 // modulo = divisor_sign *
4132 // (abs(divisor) - 1 - (abs(dividend) - 1) % abs(divisor))
4133
4134 // TODO(matthiasb): Optimization idea: Fuse the independent operations/loops
4135 // on arrays of `halfuword`s to reduce the number of passes over the data.
4136
4137 word divisor_digits = divisor.numDigits();
4138 word dividend_digits = dividend.numDigits();
4139 bool same_sign = dividend.isNegative() == divisor.isNegative();
4140 if (divisor_digits == 1) {
4141 word divisor_word = divisor.asWord();
4142 if (divisor_word == 0) {
4143 return false;
4144 }
4145 // Handle -1 as a special case because for dividend being the smallest
4146 // negative number possible for the amount of digits and `divisor == -1`
4147 // produces a result that is bigger than the input.
4148 if (divisor_word == -1) {
4149 if (quotient != nullptr) *quotient = intNegate(thread, dividend);
4150 if (modulo != nullptr) *modulo = SmallInt::fromWord(0);
4151 return true;
4152 }
4153 if (dividend_digits == 1) {
4154 word dividend_word = dividend.asWord();
4155 word quotient_word = dividend_word / divisor_word;
4156 word modulo_word = dividend_word % divisor_word;
4157 if (!same_sign && modulo_word) {
4158 DCHECK(quotient_word > kMinWord, "underflow");
4159 quotient_word--;
4160 modulo_word += divisor_word;
4161 }
4162 if (quotient != nullptr) *quotient = newInt(quotient_word);
4163 if (modulo != nullptr) *modulo = newInt(modulo_word);
4164 return true;
4165 }
4166
4167 // Handle the case where `abs(divisor)` fits in single half word.
4168 // This helps performance and simplifies `unsignedDivideRemainder()` because
4169 // it can assume to have at least 2 divisor half words.
4170 word max_half_uword = (word{1} << kBitsPerHalfWord) - 1;
4171 if (-max_half_uword <= divisor_word && divisor_word <= max_half_uword) {
4172 divideModuloSingleHalfDivisor(thread, dividend, divisor_word, quotient,
4173 modulo);
4174 return true;
4175 }
4176 }
4177
4178 if (divisor_digits > dividend_digits) {
4179 divideWithBiggerDivisor(thread, dividend, divisor, quotient, modulo);
4180 return true;
4181 }
4182
4183 // Convert divisor to `halfuword`s. Normalize by left shifting until the
4184 // highest bit (of the highest half) is set as required by
4185 // `unsignedDivideRemainder()`. We count the non-zero halves in the
4186 // `significant_xxx_halves` variables.
4187 word divisor_halves = divisor_digits * 2;
4188 std::unique_ptr<halfuword[]> divisor_n(new halfuword[divisor_halves]);
4189 halvesFromIntMagnitude(divisor_n.get(), divisor);
4190 word significant_divisor_halves =
4191 halvesNormalize(divisor_n.get(), divisor_halves);
4192 static_assert(sizeof(divisor_n[0]) == sizeof(unsigned),
4193 "choose right builtin");
4194 int shift = __builtin_clz(divisor_n[significant_divisor_halves - 1]);
4195 halvesShiftLeft(divisor_n.get(), significant_divisor_halves, shift);
4196
4197 // Convert dividend to `halfuword`s and shift by the same amount we used for
4198 // the divisor. We reserve 1 extra half so we can save a bounds check in
4199 // `unsignedDivideRemainder()` because `dividend_halves` will still be valid
4200 // to access at index `significant_divisor_halves`.
4201 word dividend_halves = (dividend_digits + 1) * 2;
4202 std::unique_ptr<halfuword[]> dividend_n(new halfuword[dividend_halves]);
4203 halvesFromIntMagnitude(dividend_n.get(), dividend);
4204 dividend_n[dividend_halves - 1] = 0;
4205 dividend_n[dividend_halves - 2] = 0;
4206 if (!same_sign) {
4207 halvesDecrement(dividend_n.get(), dividend_halves);
4208 }
4209 halvesShiftLeft(dividend_n.get(), dividend_halves, shift);
4210 word significant_dividend_halves =
4211 halvesNormalize(dividend_n.get(), dividend_halves);
4212
4213 // Handle special case of divisor being bigger than the dividend.
4214 if (significant_divisor_halves > significant_dividend_halves ||
4215 (significant_divisor_halves == significant_dividend_halves &&
4216 divisor_n[significant_divisor_halves - 1] >
4217 dividend_n[significant_divisor_halves - 1])) {
4218 divideWithBiggerDivisor(thread, dividend, divisor, quotient, modulo);
4219 return true;
4220 }
4221
4222 // Allocate storage for result. Make sure we have an even number of halves.
4223 word result_halves = (dividend_halves - divisor_halves + 2) & ~1;
4224 DCHECK(result_halves % 2 == 0, "even number of halves");
4225 std::unique_ptr<halfuword[]> result(new halfuword[result_halves]);
4226 word significant_result_halves =
4227 significant_dividend_halves - significant_divisor_halves + 1;
4228 DCHECK(significant_result_halves <= result_halves, "no overflow");
4229
4230 unsignedDivideRemainder(result.get(), significant_result_halves,
4231 dividend_n.get(), divisor_n.get(),
4232 significant_divisor_halves);
4233
4234 // TODO(matthiasb): We copy the data in result[] to a new LargeInt,
4235 // normalizeLargeInt will probably just copy it again. Should we normalize on
4236 // result[]? Can we do it without duplicating the normalization code?
4237
4238 if (quotient != nullptr) {
4239 for (word i = significant_result_halves; i < result_halves; i++) {
4240 result[i] = 0;
4241 }
4242 if (!same_sign) {
4243 // Compute `-1 - quotient == -1 + (~quotient + 1) == ~quotient`.
4244 halvesInvert(result.get(), result_halves);
4245 }
4246
4247 *quotient = largeIntFromHalves(thread, result.get(), result_halves);
4248 }
4249 if (modulo != nullptr) {
4250 // `dividend` contains the remainder now. First revert normalization shift.
4251 halvesShiftRight(dividend_n.get(), significant_dividend_halves, shift);
4252 if (!same_sign) {
4253 // Revert divisor shift.
4254 halvesShiftRight(divisor_n.get(), significant_divisor_halves, shift);
4255 // Compute `-remainder + divisor - 1`.
4256 halvesNegate(dividend_n.get(), dividend_halves);
4257 halfuword carry = halvesAdd(dividend_n.get(), divisor_n.get(),
4258 significant_divisor_halves);
4259 DCHECK(carry <= 1, "carry <= 1");
4260 if (carry) {
4261 halvesIncrement(dividend_n.get() + significant_divisor_halves,
4262 dividend_halves - significant_divisor_halves, true);
4263 }
4264
4265 halvesDecrement(dividend_n.get(), dividend_halves);
4266 }
4267 if (divisor.isNegative()) {
4268 halvesNegate(dividend_n.get(), dividend_halves);
4269 }
4270
4271 *modulo = largeIntFromHalves(thread, dividend_n.get(), dividend_halves);
4272 }
4273
4274 return true;
4275}
4276
4277static uword subtractWithBorrow(uword x, uword y, uword borrow_in,
4278 uword* borrow_out) {
4279 DCHECK(borrow_in <= 1, "borrow must be 0 or 1");
4280 uword difference;
4281 uword borrow0 = __builtin_sub_overflow(x, y, &difference);
4282 uword borrow1 = __builtin_sub_overflow(difference, borrow_in, &difference);
4283 *borrow_out = borrow0 | borrow1;
4284 return difference;
4285}
4286
4287static void fullMultiply(uword x, uword y, uword* result_low,
4288 uword* result_high) {
4289 static_assert(sizeof(uword) == 8, "assuming uword is 64bit");
4290 auto result = __extension__ static_cast<unsigned __int128>(x) * y;
4291 *result_low = static_cast<uword>(result);
4292 *result_high = static_cast<uword>(result >> 64);
4293}
4294
4295RawObject Runtime::intMultiply(Thread* thread, const Int& left,
4296 const Int& right) {
4297 // See also Hackers Delight Chapter 8 Multiplication.
4298 word left_digits = left.numDigits();
4299 word right_digits = right.numDigits();
4300 if (left_digits == 1 && right_digits == 1) {
4301 word left_digit = static_cast<word>(left.digitAt(0));
4302 word right_digit = static_cast<word>(right.digitAt(0));
4303 word result;
4304 if (!__builtin_mul_overflow(left_digit, right_digit, &result)) {
4305 return newInt(result);
4306 }
4307 }
4308
4309 HandleScope scope(thread);
4310 word result_digits = left.numDigits() + right.numDigits();
4311 LargeInt result(&scope, createLargeInt(result_digits));
4312
4313 for (word i = 0; i < result_digits; i++) {
4314 result.digitAtPut(i, 0);
4315 }
4316
4317 // Perform an unsigned multiplication.
4318 for (word l = 0; l < left_digits; l++) {
4319 uword digit_left = left.digitAt(l);
4320 uword carry = 0;
4321 for (word r = 0; r < right_digits; r++) {
4322 uword digit_right = right.digitAt(r);
4323 uword result_digit = result.digitAt(l + r);
4324
4325 uword product_low;
4326 uword product_high;
4327 fullMultiply(digit_left, digit_right, &product_low, &product_high);
4328 uword carry0;
4329 uword sum0 = addWithCarry(result_digit, product_low, 0, &carry0);
4330 uword carry1;
4331 uword sum1 = addWithCarry(sum0, carry, 0, &carry1);
4332 result.digitAtPut(l + r, sum1);
4333 // Note that this cannot overflow: Even with digit_left and digit_right
4334 // being kMaxUword the result is something like 0xfff...e0000...1, so
4335 // carry1 will be zero in these cases where the high word is close to
4336 // overflow.
4337 carry = product_high + carry0 + carry1;
4338 }
4339 result.digitAtPut(l + right_digits, carry);
4340 }
4341
4342 // Correct for `left` signedness:
4343 // Interpreting a negative number as unsigned means we are off by
4344 // `2**num_bits` (i.e. for a single byte `-3 = 0b11111101` gets interpreted
4345 // as 253, which is off by `256 = 253 - -3 = 2**8`).
4346 // Hence if we interpreted a negative `left` as unsigned, the multiplication
4347 // result will be off by `right * 2**left_num_bits`. We can correct that by
4348 // subtracting `right << left_num_bits`.
4349 if (left.isNegative()) {
4350 uword borrow = 0;
4351 for (word r = 0; r < right_digits; r++) {
4352 uword right_digit = right.digitAt(r);
4353 uword result_digit = result.digitAt(r + left_digits);
4354 uword difference =
4355 subtractWithBorrow(result_digit, right_digit, borrow, &borrow);
4356 result.digitAtPut(r + left_digits, difference);
4357 }
4358 }
4359 // Correct for `right` signedness, analogous to the `left` correction.
4360 if (right.isNegative()) {
4361 uword borrow = 0;
4362 for (word l = 0; l < left_digits; l++) {
4363 uword left_digit = left.digitAt(l);
4364 uword result_digit = result.digitAt(l + right_digits);
4365 uword difference =
4366 subtractWithBorrow(result_digit, left_digit, borrow, &borrow);
4367 result.digitAtPut(l + right_digits, difference);
4368 }
4369 }
4370
4371 return normalizeLargeInt(thread, result);
4372}
4373
4374RawObject Runtime::intBinaryOr(Thread* thread, const Int& left,
4375 const Int& right) {
4376 word left_digits = left.numDigits();
4377 word right_digits = right.numDigits();
4378 if (left_digits == 1 && right_digits == 1) {
4379 return newInt(left.asWord() | right.asWord());
4380 }
4381
4382 HandleScope scope(thread);
4383 Int longer(&scope, left_digits > right_digits ? *left : *right);
4384 Int shorter(&scope, left_digits <= right_digits ? *left : *right);
4385 word num_digits = longer.numDigits();
4386 LargeInt result(&scope, createLargeInt(num_digits));
4387 for (word i = 0, e = shorter.numDigits(); i < e; ++i) {
4388 result.digitAtPut(i, longer.digitAt(i) | shorter.digitAt(i));
4389 }
4390 if (shorter.isNegative()) {
4391 for (word i = shorter.numDigits(); i < num_digits; ++i) {
4392 result.digitAtPut(i, kMaxUword);
4393 }
4394 } else {
4395 for (word i = shorter.numDigits(); i < num_digits; ++i) {
4396 result.digitAtPut(i, longer.digitAt(i));
4397 }
4398 }
4399 return normalizeLargeInt(thread, result);
4400}
4401
4402RawObject Runtime::intBinaryRshift(Thread* thread, const Int& num,
4403 const Int& amount) {
4404 DCHECK(!amount.isNegative(), "shift amount must be positive");
4405 if (num.numDigits() == 1) {
4406 if (amount.numDigits() > 1) {
4407 return SmallInt::fromWord(0);
4408 }
4409 word amount_word = amount.asWord();
4410 if (amount_word >= kBitsPerWord) {
4411 return SmallInt::fromWord(0);
4412 }
4413 word num_word = num.asWord();
4414 return newInt(num_word >> amount_word);
4415 }
4416
4417 word amount_digits = amount.numDigits();
4418 uword digit0 = amount.digitAt(0);
4419 word shift_words = digit0 / kBitsPerWord;
4420 word shift_bits = digit0 % kBitsPerWord;
4421 if (amount_digits > 1) {
4422 // It is impossible to create a LargeInt so big that a two-digit amount
4423 // would result in a non-zero result.
4424 if (amount_digits > 2) {
4425 return SmallInt::fromWord(0);
4426 }
4427 uword digit1 = amount.digitAt(1);
4428 // Must fit in a word and be positive.
4429 if (digit1 / kBitsPerWord / 2 != 0) {
4430 return SmallInt::fromWord(0);
4431 }
4432 shift_words |= digit1 * (kMaxUword / kBitsPerWord + 1);
4433 }
4434
4435 word result_digits = num.numDigits() - shift_words;
4436 if (result_digits < 0) {
4437 return SmallInt::fromWord(0);
4438 }
4439 if (shift_bits == 0 && shift_words == 0) {
4440 return *num;
4441 }
4442 HandleScope scope(thread);
4443 LargeInt result(&scope, createLargeInt(result_digits));
4444 if (shift_bits == 0) {
4445 for (word i = 0; i < result_digits; i++) {
4446 result.digitAtPut(i, num.digitAt(shift_words + i));
4447 }
4448 } else {
4449 uword prev = num.isNegative() ? kMaxUword : 0;
4450 word prev_shift = kBitsPerWord - shift_bits;
4451 for (word i = result_digits - 1; i >= 0; i--) {
4452 uword digit = num.digitAt(shift_words + i);
4453 uword result_digit = prev << prev_shift | digit >> shift_bits;
4454 result.digitAtPut(i, result_digit);
4455 prev = digit;
4456 }
4457 }
4458 return normalizeLargeInt(thread, result);
4459}
4460
4461RawObject Runtime::intBinaryLshift(Thread* thread, const Int& num,
4462 const Int& amount) {
4463 DCHECK(!amount.isNegative(), "shift amount must be non-negative");
4464
4465 word num_digits = num.numDigits();
4466 if (num_digits == 1 && num.asWord() == 0) return SmallInt::fromWord(0);
4467 CHECK(amount.numDigits() == 1, "lshift result is too large");
4468
4469 word amount_word = amount.asWord();
4470 if (amount_word == 0) {
4471 if (num.isBool()) {
4472 return convertBoolToInt(*num);
4473 }
4474 return *num;
4475 }
4476
4477 word shift_bits = amount_word % kBitsPerWord;
4478 word shift_words = amount_word / kBitsPerWord;
4479 word high_digit = num.digitAt(num.numDigits() - 1);
4480
4481 // check if high digit overflows when shifted - if we need an extra digit
4482 word bit_length =
4483 Utils::highestBit(high_digit >= 0 ? high_digit : ~high_digit);
4484 bool overflow = bit_length + shift_bits >= kBitsPerWord;
4485
4486 // check if result fits into one word
4487 word result_digits = num_digits + shift_words + overflow;
4488 if (result_digits == 1) {
4489 return newInt(high_digit << shift_bits);
4490 }
4491
4492 // allocate large int and zero-initialize low digits
4493 HandleScope scope(thread);
4494 LargeInt result(&scope, createLargeInt(result_digits));
4495 for (word i = 0; i < shift_words; i++) {
4496 result.digitAtPut(i, 0);
4497 }
4498
4499 // iterate over digits of num and handle carrying
4500 if (shift_bits == 0) {
4501 for (word i = 0; i < num_digits; i++) {
4502 result.digitAtPut(i + shift_words, num.digitAt(i));
4503 }
4504 DCHECK(!overflow, "overflow must be false with shift_bits==0");
4505 } else {
4506 word right_shift = kBitsPerWord - shift_bits;
4507 uword prev = 0;
4508 for (word i = 0; i < num_digits; i++) {
4509 uword digit = num.digitAt(i);
4510 uword result_digit = (digit << shift_bits) | (prev >> right_shift);
4511 result.digitAtPut(i + shift_words, result_digit);
4512 prev = digit;
4513 }
4514 if (overflow) {
4515 // signed shift takes cares of keeping the sign
4516 word overflow_digit = static_cast<word>(prev) >> right_shift;
4517 result.digitAtPut(result_digits - 1, static_cast<uword>(overflow_digit));
4518 }
4519 }
4520 DCHECK(result.isValid(), "result must be valid");
4521 return *result;
4522}
4523
4524RawObject Runtime::intBinaryXor(Thread* thread, const Int& left,
4525 const Int& right) {
4526 word left_digits = left.numDigits();
4527 word right_digits = right.numDigits();
4528 if (left_digits == 1 && right_digits == 1) {
4529 return newInt(left.asWord() ^ right.asWord());
4530 }
4531
4532 HandleScope scope(thread);
4533 Int longer(&scope, left_digits > right_digits ? *left : *right);
4534 Int shorter(&scope, left_digits <= right_digits ? *left : *right);
4535
4536 word num_digits = longer.numDigits();
4537 LargeInt result(&scope, createLargeInt(num_digits));
4538 for (word i = 0, e = shorter.numDigits(); i < e; ++i) {
4539 result.digitAtPut(i, longer.digitAt(i) ^ shorter.digitAt(i));
4540 }
4541 if (shorter.isNegative()) {
4542 for (word i = shorter.numDigits(); i < num_digits; ++i) {
4543 result.digitAtPut(i, ~longer.digitAt(i));
4544 }
4545 } else {
4546 for (word i = shorter.numDigits(); i < num_digits; ++i) {
4547 result.digitAtPut(i, longer.digitAt(i));
4548 }
4549 }
4550 return normalizeLargeInt(thread, result);
4551}
4552
4553RawObject Runtime::intSubtract(Thread* thread, const Int& left,
4554 const Int& right) {
4555 if (left.isSmallInt() && right.isSmallInt()) {
4556 // Take a shortcut because we know the result fits in a word.
4557 word left_digit = SmallInt::cast(*left).value();
4558 word right_digit = SmallInt::cast(*right).value();
4559 return newInt(left_digit - right_digit);
4560 }
4561
4562 HandleScope scope(thread);
4563 word left_digits = left.numDigits();
4564 word right_digits = right.numDigits();
4565
4566 word shorter_digits = Utils::minimum(left_digits, right_digits);
4567 word longer_digits = Utils::maximum(left_digits, right_digits);
4568 word result_digits = longer_digits + 1;
4569 LargeInt result(&scope, createLargeInt(result_digits));
4570 uword borrow = 0;
4571 for (word i = 0; i < shorter_digits; i++) {
4572 uword difference =
4573 subtractWithBorrow(left.digitAt(i), right.digitAt(i), borrow, &borrow);
4574 result.digitAtPut(i, difference);
4575 }
4576 uword left_sign_extension = left.isNegative() ? kMaxUword : 0;
4577 uword right_sign_extension = right.isNegative() ? kMaxUword : 0;
4578 if (right_digits == longer_digits) {
4579 for (word i = shorter_digits; i < longer_digits; i++) {
4580 uword difference = subtractWithBorrow(left_sign_extension,
4581 right.digitAt(i), borrow, &borrow);
4582 result.digitAtPut(i, difference);
4583 }
4584 } else {
4585 for (word i = shorter_digits; i < longer_digits; i++) {
4586 uword difference = subtractWithBorrow(
4587 left.digitAt(i), right_sign_extension, borrow, &borrow);
4588 result.digitAtPut(i, difference);
4589 }
4590 }
4591 uword high_digit = left_sign_extension - right_sign_extension - borrow;
4592 result.digitAtPut(result_digits - 1, high_digit);
4593 return normalizeLargeInt(thread, result);
4594}
4595
4596RawObject Runtime::intToBytes(Thread* thread, const Int& num, word length,
4597 endian endianness) {
4598 HandleScope scope(thread);
4599 Object result(&scope, Unbound::object());
4600 byte buffer[SmallBytes::kMaxLength];
4601 byte* dst;
4602 if (length <= SmallBytes::kMaxLength) {
4603 dst = buffer;
4604 } else {
4605 result = thread->runtime()->createLargeBytes(length);
4606 dst = reinterpret_cast<byte*>(LargeBytes::cast(*result).address());
4607 }
4608 word extension_idx;
4609 word extension_length;
4610 if (endianness == endian::little && endian::native == endian::little) {
4611 word copied = num.copyTo(dst, length);
4612 extension_idx = copied;
4613 extension_length = length - copied;
4614 } else {
4615 word num_digits = num.numDigits();
4616 for (word i = 0; i < num_digits; ++i) {
4617 uword digit = num.digitAt(i);
4618 for (int x = 0; x < kWordSize; ++x) {
4619 word idx = i * kWordSize + x;
4620 byte b = digit & kMaxByte;
4621 // The last digit may have more (insignificant) bits than the
4622 // resulting buffer.
4623 if (idx >= length) {
4624 return length <= SmallBytes::kMaxLength
4625 ? SmallBytes::fromBytes({buffer, length})
4626 : *result;
4627 }
4628 if (endianness == endian::big) {
4629 idx = length - idx - 1;
4630 }
4631 dst[idx] = b;
4632 digit >>= kBitsPerByte;
4633 }
4634 }
4635 word num_bytes = num_digits * kWordSize;
4636 extension_idx = endianness == endian::big ? 0 : num_bytes;
4637 extension_length = length - num_bytes;
4638 }
4639 if (extension_length > 0) {
4640 byte sign_extension = num.isNegative() ? 0xff : 0;
4641 for (word i = 0; i < extension_length; ++i) {
4642 dst[extension_idx + i] = sign_extension;
4643 }
4644 }
4645 return length <= SmallBytes::kMaxLength
4646 ? SmallBytes::fromBytes({buffer, length})
4647 : *result;
4648}
4649
4650// Str replacement when the result can fit in SmallStr.
4651static RawObject strReplaceSmallStr(const Str& src, const Str& oldstr,
4652 const Str& newstr, word count,
4653 word result_len) {
4654 DCHECK_BOUND(result_len, SmallStr::kMaxLength);
4655 word src_len = src.length();
4656 word old_len = oldstr.length();
4657 word new_len = newstr.length();
4658 byte buffer[SmallStr::kMaxLength];
4659 byte* dst = buffer;
4660 for (word i = 0, match_count = 0; i < src_len;) {
4661 if (match_count == count || !strHasPrefix(src, oldstr, i)) {
4662 *dst++ = src.byteAt(i++);
4663 continue;
4664 }
4665 newstr.copyTo(dst, new_len);
4666 dst += new_len;
4667 i += old_len;
4668 match_count++;
4669 }
4670 return SmallStr::fromBytes(View<byte>(buffer, result_len));
4671}
4672
4673RawObject Runtime::strReplace(Thread* thread, const Str& src, const Str& oldstr,
4674 const Str& newstr, word count) {
4675 word src_len = src.length();
4676 if (count < 0) {
4677 count = SmallInt::kMaxValue; // PY_SSIZE_T_MAX.
4678 } else if (count == 0 || src_len == 0) {
4679 return *src;
4680 }
4681
4682 if (oldstr.equals(*newstr)) {
4683 return *src;
4684 }
4685
4686 // Update the count to the number of occurences of oldstr in src, capped by
4687 // the given count.
4688 count = strCountSubStr(src, oldstr, count);
4689 if (count == 0) {
4690 return *src;
4691 }
4692
4693 word old_len = oldstr.length();
4694 word new_len = newstr.length();
4695 word result_len = src_len + (new_len - old_len) * count;
4696 if (result_len <= SmallStr::kMaxLength) {
4697 return strReplaceSmallStr(src, oldstr, newstr, count, result_len);
4698 }
4699
4700 HandleScope scope(thread);
4701 LargeStr result(&scope, createLargeStr(result_len));
4702 word diff = new_len - old_len;
4703 word offset = 0;
4704 word match_count = 0;
4705 word i;
4706 for (i = 0; i < src_len && match_count < count;) {
4707 // TODO(T41400083): Use a different search algorithm
4708 if (strHasPrefix(src, oldstr, i)) {
4709 byte* dst = reinterpret_cast<byte*>(LargeStr::cast(*result).address());
4710 newstr.copyTo(dst + i + offset, new_len);
4711 match_count++;
4712 offset += diff;
4713 i += old_len;
4714 continue;
4715 }
4716 byte* dst = reinterpret_cast<byte*>(result.address());
4717 dst[i + offset] = src.byteAt(i);
4718 i++;
4719 }
4720
4721 // Copy the rest of the string.
4722 if (i < src_len) {
4723 if (src.isLargeStr()) {
4724 byte* src_byte = reinterpret_cast<byte*>(LargeStr::cast(*src).address());
4725 byte* dst = reinterpret_cast<byte*>(result.address());
4726 std::memcpy(dst + i + offset, src_byte + i, src_len - i);
4727 } else {
4728 for (; i < src_len; i++) {
4729 byte* dst = reinterpret_cast<byte*>(result.address());
4730 dst[i + offset] = src.byteAt(i);
4731 }
4732 }
4733 }
4734
4735 return *result;
4736}
4737
4738// TODO(T30392425) Ensure thread safety
4739word Runtime::nextModuleIndex() { return ++next_module_index_; }
4740
4741} // namespace py