this repo has no description
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com)
2#include "interpreter.h"
3
4#include <memory>
5
6#include "benchmark/benchmark.h"
7#include "gtest/gtest.h"
8
9#include "attributedict.h"
10#include "builtins-module.h"
11#include "bytecode.h"
12#include "compile-utils.h"
13#include "dict-builtins.h"
14#include "handles.h"
15#include "ic.h"
16#include "list-builtins.h"
17#include "module-builtins.h"
18#include "modules.h"
19#include "object-builtins.h"
20#include "objects.h"
21#include "runtime.h"
22#include "str-builtins.h"
23#include "test-utils.h"
24#include "trampolines.h"
25#include "type-builtins.h"
26
27namespace py {
28namespace testing {
29
30using InterpreterDeathTest = RuntimeFixture;
31using InterpreterTest = RuntimeFixture;
32using JitTest = RuntimeFixture;
33
34TEST_F(InterpreterTest, IsTrueBool) {
35 HandleScope scope(thread_);
36
37 Object true_value(&scope, Bool::trueObj());
38 EXPECT_EQ(Interpreter::isTrue(thread_, *true_value), Bool::trueObj());
39
40 Object false_object(&scope, Bool::falseObj());
41 EXPECT_EQ(Interpreter::isTrue(thread_, *false_object), Bool::falseObj());
42}
43
44TEST_F(InterpreterTest, IsTrueInt) {
45 HandleScope scope(thread_);
46
47 Object true_value(&scope, runtime_->newInt(1234));
48 EXPECT_EQ(Interpreter::isTrue(thread_, *true_value), Bool::trueObj());
49
50 Object false_value(&scope, runtime_->newInt(0));
51 EXPECT_EQ(Interpreter::isTrue(thread_, *false_value), Bool::falseObj());
52}
53
54TEST_F(InterpreterTest, IsTrueWithDunderBoolRaisingPropagatesException) {
55 HandleScope scope(thread_);
56 ASSERT_FALSE(runFromCStr(runtime_, R"(
57class Foo:
58 def __bool__(self):
59 raise UserWarning('')
60value = Foo()
61)")
62 .isError());
63 Object value(&scope, mainModuleAt(runtime_, "value"));
64 Object result(&scope, Interpreter::isTrue(thread_, *value));
65 EXPECT_TRUE(raised(*result, LayoutId::kUserWarning));
66}
67
68TEST_F(InterpreterTest, IsTrueWithDunderLenRaisingPropagatesException) {
69 HandleScope scope(thread_);
70 ASSERT_FALSE(runFromCStr(runtime_, R"(
71class Foo:
72 def __len__(self):
73 raise UserWarning('')
74value = Foo()
75)")
76 .isError());
77 Object value(&scope, mainModuleAt(runtime_, "value"));
78 Object result(&scope, Interpreter::isTrue(thread_, *value));
79 EXPECT_TRUE(raised(*result, LayoutId::kUserWarning));
80}
81
82TEST_F(InterpreterTest, IsTrueWithIntSubclassDunderLenUsesBaseInt) {
83 HandleScope scope(thread_);
84 ASSERT_FALSE(runFromCStr(runtime_, R"(
85class Foo(int): pass
86class Bar:
87 def __init__(self, length):
88 self.length = Foo(length)
89 def __len__(self):
90 return self.length
91true_value = Bar(10)
92false_value = Bar(0)
93)")
94 .isError());
95 Object true_value(&scope, mainModuleAt(runtime_, "true_value"));
96 Object false_value(&scope, mainModuleAt(runtime_, "false_value"));
97 EXPECT_EQ(Interpreter::isTrue(thread_, *true_value), Bool::trueObj());
98 EXPECT_EQ(Interpreter::isTrue(thread_, *false_value), Bool::falseObj());
99}
100
101TEST_F(InterpreterTest, IsTrueDunderLen) {
102 HandleScope scope(thread_);
103
104 List nonempty_list(&scope, runtime_->newList());
105 Object elt(&scope, NoneType::object());
106 runtime_->listAdd(thread_, nonempty_list, elt);
107
108 EXPECT_EQ(Interpreter::isTrue(thread_, *nonempty_list), Bool::trueObj());
109
110 List empty_list(&scope, runtime_->newList());
111 EXPECT_EQ(Interpreter::isTrue(thread_, *empty_list), Bool::falseObj());
112}
113
114TEST_F(InterpreterTest, UnaryOperationWithIntReturnsInt) {
115 HandleScope scope(thread_);
116 Object value(&scope, runtime_->newInt(23));
117 Object result(&scope,
118 Interpreter::unaryOperation(thread_, value, ID(__pos__)));
119 EXPECT_TRUE(isIntEqualsWord(*result, 23));
120}
121
122TEST_F(InterpreterTest, UnaryOperationWithBadTypeRaisesTypeError) {
123 HandleScope scope(thread_);
124 Object value(&scope, NoneType::object());
125 Object result(&scope,
126 Interpreter::unaryOperation(thread_, value, ID(__invert__)));
127 EXPECT_TRUE(
128 raisedWithStr(*result, LayoutId::kTypeError,
129 "bad operand type for unary '__invert__': 'NoneType'"));
130}
131
132TEST_F(InterpreterTest, UnaryOperationWithCustomDunderInvertReturnsString) {
133 HandleScope scope(thread_);
134 ASSERT_FALSE(runFromCStr(runtime_, R"(
135class C:
136 def __invert__(self):
137 return "custom invert"
138c = C()
139)")
140 .isError());
141 Object c(&scope, mainModuleAt(runtime_, "c"));
142 Object result(&scope,
143 Interpreter::unaryOperation(thread_, c, ID(__invert__)));
144 EXPECT_TRUE(isStrEqualsCStr(*result, "custom invert"));
145}
146
147TEST_F(InterpreterTest, UnaryOperationWithCustomRaisingDunderNegPropagates) {
148 HandleScope scope(thread_);
149 ASSERT_FALSE(runFromCStr(runtime_, R"(
150class C:
151 def __neg__(self):
152 raise UserWarning('')
153c = C()
154)")
155 .isError());
156 Object c(&scope, mainModuleAt(runtime_, "c"));
157 Object result(&scope, Interpreter::unaryOperation(thread_, c, ID(__neg__)));
158 EXPECT_TRUE(raised(*result, LayoutId::kUserWarning));
159}
160
161TEST_F(InterpreterTest, UnaryNotWithRaisingDunderBool) {
162 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, R"(
163class C:
164 def __bool__(self):
165 raise RuntimeError("too cool for bool")
166
167not C()
168)"),
169 LayoutId::kRuntimeError, "too cool for bool"));
170}
171
172TEST_F(InterpreterTest, BinaryOpCachedInsertsDependencyForBothOperandsTypes) {
173 HandleScope scope(thread_);
174 EXPECT_FALSE(runFromCStr(runtime_, R"(
175class A:
176 def __add__(self, other):
177 return "from class A"
178
179class B:
180 pass
181
182def cache_binary_op(a, b):
183 return a + b
184
185a = A()
186b = B()
187A__add__ = A.__add__
188result = cache_binary_op(a, b)
189)")
190 .isError());
191 ASSERT_TRUE(
192 isStrEqualsCStr(mainModuleAt(runtime_, "result"), "from class A"));
193
194 Function cache_binary_op(&scope, mainModuleAt(runtime_, "cache_binary_op"));
195 MutableTuple caches(&scope, cache_binary_op.caches());
196 Object a(&scope, mainModuleAt(runtime_, "a"));
197 Object b(&scope, mainModuleAt(runtime_, "b"));
198 Type type_a(&scope, mainModuleAt(runtime_, "A"));
199 Type type_b(&scope, mainModuleAt(runtime_, "B"));
200 BinaryOpFlags flag;
201 ASSERT_EQ(icLookupBinaryOp(*caches, 0, a.layoutId(), b.layoutId(), &flag),
202 mainModuleAt(runtime_, "A__add__"));
203
204 // Verify that A.__add__ has the dependent.
205 Object left_op_name(&scope, runtime_->symbols()->at(ID(__add__)));
206 Object type_a_attr(&scope, typeValueCellAt(*type_a, *left_op_name));
207 ASSERT_TRUE(type_a_attr.isValueCell());
208 ASSERT_TRUE(ValueCell::cast(*type_a_attr).dependencyLink().isWeakLink());
209 EXPECT_EQ(
210 WeakLink::cast(ValueCell::cast(*type_a_attr).dependencyLink()).referent(),
211 *cache_binary_op);
212
213 // Verify that B.__radd__ has the dependent.
214 Object right_op_name(&scope, runtime_->symbols()->at(ID(__radd__)));
215 Object type_b_attr(&scope, typeValueCellAt(*type_b, *right_op_name));
216 ASSERT_TRUE(type_b_attr.isValueCell());
217 ASSERT_TRUE(ValueCell::cast(*type_b_attr).dependencyLink().isWeakLink());
218 EXPECT_EQ(
219 WeakLink::cast(ValueCell::cast(*type_b_attr).dependencyLink()).referent(),
220 *cache_binary_op);
221}
222
223TEST_F(InterpreterTest, BinaryOpInvokesSelfMethod) {
224 HandleScope scope(thread_);
225
226 ASSERT_FALSE(runFromCStr(runtime_, R"(
227class C:
228 def __sub__(self, other):
229 return (C, '__sub__', self, other)
230
231left = C()
232right = C()
233)")
234 .isError());
235
236 Object left(&scope, mainModuleAt(runtime_, "left"));
237 Object right(&scope, mainModuleAt(runtime_, "right"));
238 Object c_class(&scope, mainModuleAt(runtime_, "C"));
239
240 Object result_obj(
241 &scope, Interpreter::binaryOperation(thread_, Interpreter::BinaryOp::SUB,
242 left, right));
243 ASSERT_TRUE(result_obj.isTuple());
244 Tuple result(&scope, *result_obj);
245 ASSERT_EQ(result.length(), 4);
246 EXPECT_EQ(result.at(0), *c_class);
247 EXPECT_TRUE(isStrEqualsCStr(result.at(1), "__sub__"));
248 EXPECT_EQ(result.at(2), *left);
249 EXPECT_EQ(result.at(3), *right);
250}
251
252TEST_F(InterpreterTest, BinaryOpInvokesSelfMethodIgnoresReflectedMethod) {
253 HandleScope scope(thread_);
254
255 ASSERT_FALSE(runFromCStr(runtime_, R"(
256class C:
257 def __sub__(self, other):
258 return (C, '__sub__', self, other)
259 def __rsub__(self, other):
260 return (C, '__rsub__', self, other)
261
262left = C()
263right = C()
264)")
265 .isError());
266
267 Object left(&scope, mainModuleAt(runtime_, "left"));
268 Object right(&scope, mainModuleAt(runtime_, "right"));
269 Object c_class(&scope, mainModuleAt(runtime_, "C"));
270
271 Object result_obj(
272 &scope, Interpreter::binaryOperation(thread_, Interpreter::BinaryOp::SUB,
273 left, right));
274 ASSERT_TRUE(result_obj.isTuple());
275 Tuple result(&scope, *result_obj);
276 ASSERT_EQ(result.length(), 4);
277 EXPECT_EQ(result.at(0), *c_class);
278 EXPECT_TRUE(isStrEqualsCStr(result.at(1), "__sub__"));
279 EXPECT_EQ(result.at(2), *left);
280 EXPECT_EQ(result.at(3), *right);
281}
282
283TEST_F(InterpreterTest, BinaryOperationInvokesSubclassReflectedMethod) {
284 HandleScope scope(thread_);
285
286 ASSERT_FALSE(runFromCStr(runtime_, R"(
287class C:
288 def __sub__(self, other):
289 return (C, '__sub__', self, other)
290
291class D(C):
292 def __rsub__(self, other):
293 return (D, '__rsub__', self, other)
294
295left = C()
296right = D()
297)")
298 .isError());
299
300 Object left(&scope, mainModuleAt(runtime_, "left"));
301 Object right(&scope, mainModuleAt(runtime_, "right"));
302 Object d_class(&scope, mainModuleAt(runtime_, "D"));
303
304 Object result_obj(
305 &scope, Interpreter::binaryOperation(thread_, Interpreter::BinaryOp::SUB,
306 left, right));
307 ASSERT_TRUE(result_obj.isTuple());
308 Tuple result(&scope, *result_obj);
309 ASSERT_EQ(result.length(), 4);
310 EXPECT_EQ(result.at(0), *d_class);
311 EXPECT_TRUE(isStrEqualsCStr(result.at(1), "__rsub__"));
312 EXPECT_EQ(result.at(2), *right);
313 EXPECT_EQ(result.at(3), *left);
314}
315
316TEST_F(InterpreterTest, BinaryOperationInvokesOtherReflectedMethod) {
317 HandleScope scope(thread_);
318
319 ASSERT_FALSE(runFromCStr(runtime_, R"(
320class C:
321 pass
322
323class D:
324 def __rsub__(self, other):
325 return (D, '__rsub__', self, other)
326
327left = C()
328right = D()
329)")
330 .isError());
331
332 Object left(&scope, mainModuleAt(runtime_, "left"));
333 Object right(&scope, mainModuleAt(runtime_, "right"));
334 Object d_class(&scope, mainModuleAt(runtime_, "D"));
335
336 Object result_obj(
337 &scope, Interpreter::binaryOperation(thread_, Interpreter::BinaryOp::SUB,
338 left, right));
339 ASSERT_TRUE(result_obj.isTuple());
340 Tuple result(&scope, *result_obj);
341 ASSERT_EQ(result.length(), 4);
342 EXPECT_EQ(result.at(0), *d_class);
343 EXPECT_TRUE(isStrEqualsCStr(result.at(1), "__rsub__"));
344 EXPECT_EQ(result.at(2), *right);
345 EXPECT_EQ(result.at(3), *left);
346}
347
348TEST_F(
349 InterpreterTest,
350 BinaryOperationInvokesLeftMethodWhenReflectedMethodReturnsNotImplemented) {
351 ASSERT_FALSE(runFromCStr(runtime_, R"(
352trace = ""
353class C:
354 def __add__(self, other):
355 global trace
356 trace += "C.__add__,"
357 return "C.__add__"
358
359 def __radd__(self, other):
360 raise Exception("should not be called")
361
362
363class D(C):
364 def __add__(self, other):
365 raise Exception("should not be called")
366
367 def __radd__(self, other):
368 global trace
369 trace += "D.__radd__,"
370 return NotImplemented
371
372result = C() + D()
373)")
374 .isError());
375
376 EXPECT_TRUE(isStrEqualsCStr(mainModuleAt(runtime_, "result"), "C.__add__"));
377 EXPECT_TRUE(isStrEqualsCStr(mainModuleAt(runtime_, "trace"),
378 "D.__radd__,C.__add__,"));
379}
380
381TEST_F(InterpreterTest, BinaryOperationLookupPropagatesException) {
382 HandleScope scope(thread_);
383 ASSERT_FALSE(runFromCStr(runtime_, R"(
384class RaisingDescriptor:
385 def __get__(self, obj, type):
386 raise UserWarning()
387class A:
388 __mul__ = RaisingDescriptor()
389a = A()
390)")
391 .isError());
392 Object a(&scope, mainModuleAt(runtime_, "a"));
393 Object result(&scope, Interpreter::binaryOperation(
394 thread_, Interpreter::BinaryOp::MUL, a, a));
395 EXPECT_TRUE(raised(*result, LayoutId::kUserWarning));
396}
397
398TEST_F(InterpreterTest,
399 BinaryOperationLookupReflectedMethodPropagatesException) {
400 HandleScope scope(thread_);
401 ASSERT_FALSE(runFromCStr(runtime_, R"(
402class RaisingDescriptor:
403 def __get__(self, obj, type):
404 raise UserWarning()
405class A:
406 def __mul__(self, other):
407 return 42
408class B(A):
409 __rmul__ = RaisingDescriptor()
410a = A()
411b = B()
412)")
413 .isError());
414 Object a(&scope, mainModuleAt(runtime_, "a"));
415 Object b(&scope, mainModuleAt(runtime_, "b"));
416 Object result(&scope, Interpreter::binaryOperation(
417 thread_, Interpreter::BinaryOp::MUL, a, b));
418 EXPECT_TRUE(raised(*result, LayoutId::kUserWarning));
419}
420
421TEST_F(InterpreterTest, BinaryOperationSetMethodSetsMethod) {
422 HandleScope scope(thread_);
423 Object v0(&scope, runtime_->newInt(13));
424 Object v1(&scope, runtime_->newInt(42));
425 Object method(&scope, NoneType::object());
426 BinaryOpFlags flags;
427 EXPECT_TRUE(isIntEqualsWord(
428 Interpreter::binaryOperationSetMethod(thread_, Interpreter::BinaryOp::SUB,
429 v0, v1, &method, &flags),
430 -29));
431 EXPECT_TRUE(method.isFunction());
432 EXPECT_EQ(flags, kBinaryOpNotImplementedRetry);
433
434 Object v2(&scope, runtime_->newInt(3));
435 Object v3(&scope, runtime_->newInt(8));
436 ASSERT_EQ(v0.layoutId(), v2.layoutId());
437 ASSERT_EQ(v1.layoutId(), v3.layoutId());
438 EXPECT_TRUE(isIntEqualsWord(
439 Interpreter::binaryOperationWithMethod(thread_, *method, flags, *v2, *v3),
440 -5));
441}
442
443TEST_F(InterpreterTest,
444 BinaryOperationSetMethodSetsReflectedMethodNotImplementedRetry) {
445 HandleScope scope(thread_);
446 ASSERT_FALSE(runFromCStr(runtime_, R"(
447class A:
448 def __init__(self, x):
449 self.x = x
450 def __sub__(self, other):
451 raise UserWarning("should not be called")
452class ASub(A):
453 def __rsub__(self, other):
454 return (self, other)
455v0 = A(3)
456v1 = ASub(7)
457v2 = A(8)
458v3 = ASub(2)
459)")
460 .isError());
461 Object v0(&scope, mainModuleAt(runtime_, "v0"));
462 Object v1(&scope, mainModuleAt(runtime_, "v1"));
463 Object v2(&scope, mainModuleAt(runtime_, "v2"));
464 Object v3(&scope, mainModuleAt(runtime_, "v3"));
465
466 Object method(&scope, NoneType::object());
467 BinaryOpFlags flags;
468 Object result_obj(&scope, Interpreter::binaryOperationSetMethod(
469 thread_, Interpreter::BinaryOp::SUB, v0, v1,
470 &method, &flags));
471 ASSERT_TRUE(result_obj.isTuple());
472 Tuple result(&scope, *result_obj);
473 ASSERT_EQ(result.length(), 2);
474 EXPECT_EQ(result.at(0), v1);
475 EXPECT_EQ(result.at(1), v0);
476 EXPECT_TRUE(method.isFunction());
477 EXPECT_EQ(flags, kBinaryOpReflected | kBinaryOpNotImplementedRetry);
478
479 ASSERT_EQ(v0.layoutId(), v2.layoutId());
480 ASSERT_EQ(v1.layoutId(), v3.layoutId());
481 result_obj =
482 Interpreter::binaryOperationWithMethod(thread_, *method, flags, *v2, *v3);
483 ASSERT_TRUE(result.isTuple());
484 result = *result_obj;
485 ASSERT_EQ(result.length(), 2);
486 EXPECT_EQ(result.at(0), v3);
487 EXPECT_EQ(result.at(1), v2);
488}
489
490TEST_F(InterpreterTest, BinaryOperationSetMethodSetsReflectedMethod) {
491 HandleScope scope(thread_);
492 ASSERT_FALSE(runFromCStr(runtime_, R"(
493class A:
494 def __init__(self, x):
495 self.x = x
496class B:
497 def __init__(self, x):
498 self.x = x
499 def __rsub__(self, other):
500 return other.x - self.x
501v0 = A(-4)
502v1 = B(8)
503v2 = A(33)
504v3 = B(-12)
505)")
506 .isError());
507 Object v0(&scope, mainModuleAt(runtime_, "v0"));
508 Object v1(&scope, mainModuleAt(runtime_, "v1"));
509 Object v2(&scope, mainModuleAt(runtime_, "v2"));
510 Object v3(&scope, mainModuleAt(runtime_, "v3"));
511
512 Object method(&scope, NoneType::object());
513 BinaryOpFlags flags;
514 EXPECT_TRUE(isIntEqualsWord(
515 Interpreter::binaryOperationSetMethod(thread_, Interpreter::BinaryOp::SUB,
516 v0, v1, &method, &flags),
517 -12));
518 EXPECT_TRUE(method.isFunction());
519 EXPECT_EQ(flags, kBinaryOpReflected);
520
521 ASSERT_EQ(v0.layoutId(), v2.layoutId());
522 ASSERT_EQ(v1.layoutId(), v3.layoutId());
523 EXPECT_TRUE(isIntEqualsWord(
524 Interpreter::binaryOperationWithMethod(thread_, *method, flags, *v2, *v3),
525 45));
526}
527
528TEST_F(InterpreterTest, BinaryOperationSetMethodSetsMethodNotImplementedRetry) {
529 HandleScope scope(thread_);
530 ASSERT_FALSE(runFromCStr(runtime_, R"(
531class A:
532 def __init__(self, x):
533 self.x = x
534 def __sub__(self, other):
535 return other.x - self.x
536class B:
537 def __init__(self, x):
538 self.x = x
539 def __rsub__(self, other):
540 return self.x - other.x
541v0 = A(4)
542v1 = B(6)
543v2 = A(9)
544v3 = B(1)
545)")
546 .isError());
547 Object v0(&scope, mainModuleAt(runtime_, "v0"));
548 Object v1(&scope, mainModuleAt(runtime_, "v1"));
549 Object v2(&scope, mainModuleAt(runtime_, "v2"));
550 Object v3(&scope, mainModuleAt(runtime_, "v3"));
551
552 Object method(&scope, NoneType::object());
553 BinaryOpFlags flags;
554 EXPECT_TRUE(isIntEqualsWord(
555 Interpreter::binaryOperationSetMethod(thread_, Interpreter::BinaryOp::SUB,
556 v0, v1, &method, &flags),
557 2));
558 EXPECT_TRUE(method.isFunction());
559 EXPECT_EQ(flags, kBinaryOpNotImplementedRetry);
560
561 ASSERT_EQ(v0.layoutId(), v2.layoutId());
562 ASSERT_EQ(v1.layoutId(), v3.layoutId());
563 EXPECT_TRUE(isIntEqualsWord(
564 Interpreter::binaryOperationWithMethod(thread_, *method, flags, *v2, *v3),
565 -8));
566}
567
568TEST_F(InterpreterTest, DoBinaryOpWithCacheHitCallsCachedMethod) {
569 HandleScope scope(thread_);
570
571 word left = SmallInt::kMaxValue + 1;
572 word right = -13;
573 const byte bytecode[] = {
574 LOAD_CONST, 0, LOAD_CONST, 1, BINARY_SUBTRACT, 0, RETURN_VALUE, 0,
575 };
576 Object left_obj(&scope, runtime_->newInt(left));
577 Object right_obj(&scope, runtime_->newInt(right));
578 Tuple consts(&scope, runtime_->newTupleWith2(left_obj, right_obj));
579 Code code(&scope, newCodeWithBytesConsts(bytecode, consts));
580
581 Object qualname(&scope, Str::empty());
582 Module module(&scope, findMainModule(runtime_));
583 Function function(
584 &scope, runtime_->newFunctionWithCode(thread_, qualname, code, module));
585
586 // Update inline cache.
587 EXPECT_TRUE(
588 isIntEqualsWord(Interpreter::call0(thread_, function), left - right));
589
590 ASSERT_TRUE(function.caches().isTuple());
591 MutableTuple caches(&scope, function.caches());
592 BinaryOpFlags dummy;
593 ASSERT_FALSE(icLookupBinaryOp(*caches, 0, LayoutId::kLargeInt,
594 LayoutId::kSmallInt, &dummy)
595 .isErrorNotFound());
596
597 // Call from inline cache.
598 EXPECT_TRUE(
599 isIntEqualsWord(Interpreter::call0(thread_, function), left - right));
600}
601
602TEST_F(InterpreterTest, DoBinaryOpWithCacheHitCallsRetry) {
603 HandleScope scope(thread_);
604 ASSERT_FALSE(runFromCStr(runtime_, R"(
605class MyInt(int):
606 def __sub__(self, other):
607 return NotImplemented
608 def __rsub__(self, other):
609 return NotImplemented
610v0 = MyInt(3)
611v1 = 7
612)")
613 .isError());
614 Object v0(&scope, mainModuleAt(runtime_, "v0"));
615 Object v1(&scope, mainModuleAt(runtime_, "v1"));
616
617 Tuple consts(&scope, runtime_->newTupleWith2(v0, v1));
618 const byte bytecode[] = {
619 LOAD_CONST, 0, LOAD_CONST, 1, BINARY_SUBTRACT, 0, RETURN_VALUE, 0,
620 };
621 Code code(&scope, newCodeWithBytesConsts(bytecode, consts));
622
623 Object qualname(&scope, Str::empty());
624 Module module(&scope, findMainModule(runtime_));
625 Function function(
626 &scope, runtime_->newFunctionWithCode(thread_, qualname, code, module));
627
628 // Update inline cache.
629 EXPECT_TRUE(isIntEqualsWord(Interpreter::call0(thread_, function), -4));
630
631 ASSERT_TRUE(function.caches().isTuple());
632 MutableTuple caches(&scope, function.caches());
633 BinaryOpFlags dummy;
634 ASSERT_FALSE(
635 icLookupBinaryOp(*caches, 0, v0.layoutId(), v1.layoutId(), &dummy)
636 .isErrorNotFound());
637
638 // Should hit the cache for __sub__ and then call binaryOperationRetry().
639 EXPECT_TRUE(isIntEqualsWord(Interpreter::call0(thread_, function), -4));
640}
641
642TEST_F(InterpreterTest, DoBinaryOpWithSmallIntsRewritesOpcode) {
643 HandleScope scope(thread_);
644
645 word left = 7;
646 word right = -13;
647 Object left_obj(&scope, runtime_->newInt(left));
648 Object right_obj(&scope, runtime_->newInt(right));
649 Tuple consts(&scope, runtime_->newTupleWith2(left_obj, right_obj));
650 const byte bytecode[] = {
651 LOAD_CONST, 0, LOAD_CONST, 1, BINARY_SUBTRACT, 0, RETURN_VALUE, 0,
652 };
653 Code code(&scope, newCodeWithBytesConsts(bytecode, consts));
654
655 Object qualname(&scope, Str::empty());
656 Module module(&scope, findMainModule(runtime_));
657 Function function(
658 &scope, runtime_->newFunctionWithCode(thread_, qualname, code, module));
659
660 // Update the opcode.
661 ASSERT_TRUE(
662 isIntEqualsWord(Interpreter::call0(thread_, function), left - right));
663
664 MutableBytes rewritten_bytecode(&scope, function.rewrittenBytecode());
665 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten_bytecode, 2), BINARY_SUB_SMALLINT);
666
667 // Updated opcode returns the same value.
668 EXPECT_TRUE(
669 isIntEqualsWord(Interpreter::call0(thread_, function), left - right));
670}
671
672static bool functionMatchesRef1(const Function& function,
673 const Object& reference, const Object& arg0) {
674 Thread* thread = Thread::current();
675 HandleScope scope(thread);
676 Object expected(&scope, Interpreter::call1(thread, reference, arg0));
677 EXPECT_FALSE(expected.isError());
678 Object actual(&scope, Interpreter::call1(thread, function, arg0));
679 EXPECT_FALSE(actual.isError());
680 return Runtime::objectEquals(thread, *expected, *actual) == Bool::trueObj();
681}
682
683static bool functionMatchesRef2(const Function& function,
684 const Object& reference, const Object& arg0,
685 const Object& arg1) {
686 Thread* thread = Thread::current();
687 HandleScope scope(thread);
688 Object expected(&scope, Interpreter::call2(thread, reference, arg0, arg1));
689 EXPECT_FALSE(expected.isError());
690 Object actual(&scope, Interpreter::call2(thread, function, arg0, arg1));
691 EXPECT_FALSE(actual.isError());
692 return Runtime::objectEquals(thread, *expected, *actual) == Bool::trueObj();
693}
694
695// Test that `function(arg0, arg1) == reference(arg0, arg1)` with the assumption
696// that `function` contains a `BINARY_OP_MONOMORPHIC` opcode that will be
697// specialized to `opcode_specialized` when called with `arg0` and `arg1`.
698// Calling the function with `arg_o` should trigger a revert to
699// `BINARY_OP_MONOMORPHIC`.
700static void testBinaryOpRewrite(const Function& function,
701 const Function& reference,
702 Bytecode opcode_specialized, const Object& arg0,
703 const Object& arg1, const Object& arg_o) {
704 EXPECT_TRUE(containsBytecode(function, BINARY_OP_ANAMORPHIC));
705
706 EXPECT_TRUE(functionMatchesRef2(function, reference, arg0, arg1));
707 EXPECT_FALSE(containsBytecode(function, BINARY_OP_ANAMORPHIC));
708 EXPECT_TRUE(containsBytecode(function, opcode_specialized));
709 EXPECT_TRUE(functionMatchesRef2(function, reference, arg1, arg0));
710 EXPECT_TRUE(containsBytecode(function, opcode_specialized));
711
712 EXPECT_TRUE(functionMatchesRef2(function, reference, arg0, arg_o));
713 EXPECT_TRUE(containsBytecode(function, BINARY_OP_MONOMORPHIC));
714 EXPECT_FALSE(containsBytecode(function, opcode_specialized));
715
716 EXPECT_TRUE(functionMatchesRef2(function, reference, arg0, arg1));
717}
718
719TEST_F(InterpreterTest, CallFunctionAnamorphicRewritesToCallFunctionTypeNew) {
720 HandleScope scope(thread_);
721 ASSERT_FALSE(runFromCStr(runtime_, R"(
722class C:
723 def __new__(cls):
724 return object.__new__(cls)
725def foo(fn):
726 return fn()
727def non_type():
728 return 5
729)")
730 .isError());
731 Function function(&scope, mainModuleAt(runtime_, "foo"));
732 EXPECT_TRUE(containsBytecode(function, CALL_FUNCTION_ANAMORPHIC));
733
734 Type type(&scope, mainModuleAt(runtime_, "C"));
735 Object expected(&scope, Interpreter::call1(thread_, function, type));
736 EXPECT_FALSE(expected.isError());
737 EXPECT_TRUE(containsBytecode(function, CALL_FUNCTION_TYPE_NEW));
738 EXPECT_EQ(expected.layoutId(), type.instanceLayoutId());
739
740 Object non_type(&scope, mainModuleAt(runtime_, "non_type"));
741 expected = Interpreter::call1(thread_, function, non_type);
742 EXPECT_FALSE(expected.isError());
743 EXPECT_TRUE(isIntEqualsWord(*expected, 5));
744 EXPECT_TRUE(containsBytecode(function, CALL_FUNCTION));
745}
746
747TEST_F(InterpreterTest,
748 CallFunctionTypeNewWithNewDunderNewRewritesToCallFunction) {
749 HandleScope scope(thread_);
750 ASSERT_FALSE(runFromCStr(runtime_, R"(
751class C:
752 def __new__(cls):
753 return object.__new__(cls)
754def foo(fn):
755 return fn()
756def new_new(cls):
757 return 5
758)")
759 .isError());
760 Function function(&scope, mainModuleAt(runtime_, "foo"));
761 EXPECT_TRUE(containsBytecode(function, CALL_FUNCTION_ANAMORPHIC));
762
763 Type type(&scope, mainModuleAt(runtime_, "C"));
764 Object expected(&scope, Interpreter::call1(thread_, function, type));
765 EXPECT_FALSE(expected.isError());
766 EXPECT_TRUE(containsBytecode(function, CALL_FUNCTION_TYPE_NEW));
767 EXPECT_EQ(expected.layoutId(), type.instanceLayoutId());
768
769 // Invalidate cache
770 Object new_new(&scope, mainModuleAt(runtime_, "new_new"));
771 typeAtPutById(thread_, type, ID(__new__), new_new);
772
773 // Cache miss
774 expected = Interpreter::call1(thread_, function, type);
775 EXPECT_FALSE(expected.isError());
776 EXPECT_TRUE(isIntEqualsWord(*expected, 5));
777 EXPECT_TRUE(containsBytecode(function, CALL_FUNCTION));
778}
779
780TEST_F(InterpreterTest,
781 CallFunctionTypeNewWithNewDunderInitRewritesToCallFunction) {
782 HandleScope scope(thread_);
783 ASSERT_FALSE(runFromCStr(runtime_, R"(
784class C:
785 def __new__(cls):
786 return object.__new__(cls)
787 def __init__(self):
788 pass
789def foo(fn):
790 return fn()
791def new_init(self):
792 pass
793)")
794 .isError());
795 Function function(&scope, mainModuleAt(runtime_, "foo"));
796 EXPECT_TRUE(containsBytecode(function, CALL_FUNCTION_ANAMORPHIC));
797
798 Type type(&scope, mainModuleAt(runtime_, "C"));
799 Object expected(&scope, Interpreter::call1(thread_, function, type));
800 EXPECT_FALSE(expected.isError());
801 EXPECT_TRUE(containsBytecode(function, CALL_FUNCTION_TYPE_NEW));
802 EXPECT_EQ(expected.layoutId(), type.instanceLayoutId());
803
804 // Invalidate cache
805 Object new_init(&scope, mainModuleAt(runtime_, "new_init"));
806 typeAtPutById(thread_, type, ID(__init__), new_init);
807
808 // Cache miss
809 expected = Interpreter::call1(thread_, function, type);
810 EXPECT_FALSE(expected.isError());
811 EXPECT_EQ(expected.layoutId(), type.instanceLayoutId());
812 EXPECT_TRUE(containsBytecode(function, CALL_FUNCTION));
813}
814
815TEST_F(InterpreterTest, CallFunctionAnamorphicRewritesToCallFunctionTypeInit) {
816 HandleScope scope(thread_);
817 ASSERT_FALSE(runFromCStr(runtime_, R"(
818class C:
819 def __init__(self):
820 pass
821def foo(fn):
822 return fn()
823def non_type():
824 return 5
825)")
826 .isError());
827 Function function(&scope, mainModuleAt(runtime_, "foo"));
828 EXPECT_TRUE(containsBytecode(function, CALL_FUNCTION_ANAMORPHIC));
829
830 Type type(&scope, mainModuleAt(runtime_, "C"));
831 Object expected(&scope, Interpreter::call1(thread_, function, type));
832 EXPECT_FALSE(expected.isError());
833 EXPECT_TRUE(containsBytecode(function, CALL_FUNCTION_TYPE_INIT));
834 EXPECT_EQ(expected.layoutId(), type.instanceLayoutId());
835
836 Object non_type(&scope, mainModuleAt(runtime_, "non_type"));
837 expected = Interpreter::call1(thread_, function, non_type);
838 EXPECT_FALSE(expected.isError());
839 EXPECT_TRUE(isIntEqualsWord(*expected, 5));
840 EXPECT_TRUE(containsBytecode(function, CALL_FUNCTION));
841}
842
843TEST_F(InterpreterTest,
844 CallFunctionTypeInitWithNewDunderInitRewritesToCallFunction) {
845 HandleScope scope(thread_);
846 ASSERT_FALSE(runFromCStr(runtime_, R"(
847class C:
848 def __init__(self):
849 pass
850def foo(fn):
851 return fn()
852def new_init(self):
853 pass
854)")
855 .isError());
856 Function function(&scope, mainModuleAt(runtime_, "foo"));
857 EXPECT_TRUE(containsBytecode(function, CALL_FUNCTION_ANAMORPHIC));
858
859 Type type(&scope, mainModuleAt(runtime_, "C"));
860 Object expected(&scope, Interpreter::call1(thread_, function, type));
861 EXPECT_FALSE(expected.isError());
862 EXPECT_TRUE(containsBytecode(function, CALL_FUNCTION_TYPE_INIT));
863 EXPECT_EQ(expected.layoutId(), type.instanceLayoutId());
864
865 // Invalidate cache
866 Object new_init(&scope, mainModuleAt(runtime_, "new_init"));
867 typeAtPutById(thread_, type, ID(__init__), new_init);
868
869 // Cache miss
870 expected = Interpreter::call1(thread_, function, type);
871 EXPECT_FALSE(expected.isError());
872 EXPECT_EQ(expected.layoutId(), type.instanceLayoutId());
873 EXPECT_TRUE(containsBytecode(function, CALL_FUNCTION));
874}
875
876TEST_F(InterpreterTest,
877 CallFunctionTypeInitWithNewDunderNewRewritesToCallFunction) {
878 HandleScope scope(thread_);
879 ASSERT_FALSE(runFromCStr(runtime_, R"(
880class C:
881 def __init__(self):
882 pass
883def foo(fn):
884 return fn()
885def new_new(self):
886 pass
887)")
888 .isError());
889 Function function(&scope, mainModuleAt(runtime_, "foo"));
890 EXPECT_TRUE(containsBytecode(function, CALL_FUNCTION_ANAMORPHIC));
891
892 Type type(&scope, mainModuleAt(runtime_, "C"));
893 Object expected(&scope, Interpreter::call1(thread_, function, type));
894 EXPECT_FALSE(expected.isError());
895 EXPECT_TRUE(containsBytecode(function, CALL_FUNCTION_TYPE_INIT));
896 EXPECT_EQ(expected.layoutId(), type.instanceLayoutId());
897
898 // Invalidate cache
899 Object new_new(&scope, mainModuleAt(runtime_, "new_new"));
900 typeAtPutById(thread_, type, ID(__new__), new_new);
901
902 // Cache miss
903 expected = Interpreter::call1(thread_, function, type);
904 EXPECT_FALSE(expected.isError());
905 EXPECT_EQ(expected.layoutId(), type.instanceLayoutId());
906 EXPECT_TRUE(containsBytecode(function, CALL_FUNCTION));
907}
908
909// Test that `function(arg0) == reference(arg0)` with the assumption
910// that `function` contains the original unary opcode that will be
911// specialized to `opcode_specialized` when called with `arg0`.
912// Calling the function with `arg_o` should trigger a revert to
913// the unspecialized unary op.
914static void testUnaryOpRewrite(const Function& function,
915 const Function& reference,
916 Bytecode opcode_unspecialized,
917 Bytecode opcode_specialized, const Object& arg0,
918 const Object& arg_o) {
919 EXPECT_TRUE(containsBytecode(function, UNARY_OP_ANAMORPHIC));
920
921 EXPECT_TRUE(functionMatchesRef1(function, reference, arg0));
922 EXPECT_FALSE(containsBytecode(function, BINARY_OP_ANAMORPHIC));
923 EXPECT_TRUE(containsBytecode(function, opcode_specialized));
924 EXPECT_TRUE(functionMatchesRef1(function, reference, arg0));
925 EXPECT_TRUE(containsBytecode(function, opcode_specialized));
926
927 EXPECT_TRUE(functionMatchesRef1(function, reference, arg_o));
928 EXPECT_TRUE(containsBytecode(function, opcode_unspecialized));
929 EXPECT_FALSE(containsBytecode(function, opcode_specialized));
930
931 EXPECT_TRUE(functionMatchesRef1(function, reference, arg0));
932}
933
934TEST_F(InterpreterTest, UnaryOpAnamorphicRewritesToUnaryNegativeSmallInt) {
935 HandleScope scope(thread_);
936 ASSERT_FALSE(runFromCStr(runtime_, R"(
937def function(obj):
938 return -obj
939reference = int.__neg__
940)")
941 .isError());
942 Function function(&scope, mainModuleAt(runtime_, "function"));
943 Function reference(&scope, mainModuleAt(runtime_, "reference"));
944 Object arg0(&scope, SmallInt::fromWord(34));
945 const uword digits2[] = {0x12345678, 0xabcdef};
946 Object arg_l(&scope, runtime_->newLargeIntWithDigits(digits2));
947 testUnaryOpRewrite(function, reference, UNARY_NEGATIVE,
948 UNARY_NEGATIVE_SMALLINT, arg0, arg_l);
949}
950
951TEST_F(InterpreterTest, BinaryOpAnamorphicRewritesToBinaryAddSmallInt) {
952 HandleScope scope(thread_);
953 ASSERT_FALSE(runFromCStr(runtime_, R"(
954def function(a, b):
955 return a + b
956reference = int.__add__
957)")
958 .isError());
959 Function function(&scope, mainModuleAt(runtime_, "function"));
960 Function reference(&scope, mainModuleAt(runtime_, "reference"));
961 Object arg0(&scope, SmallInt::fromWord(34));
962 Object arg1(&scope, SmallInt::fromWord(12));
963 const uword digits2[] = {0x12345678, 0xabcdef};
964 Object arg_l(&scope, runtime_->newLargeIntWithDigits(digits2));
965 testBinaryOpRewrite(function, reference, BINARY_ADD_SMALLINT, arg0, arg1,
966 arg_l);
967}
968
969TEST_F(InterpreterTest, BinaryOpAnamorphicRewritesToBinaryMulSmallInt) {
970 HandleScope scope(thread_);
971 ASSERT_FALSE(runFromCStr(runtime_, R"(
972def function(a, b):
973 return a * b
974reference = int.__mul__
975)")
976 .isError());
977 Function function(&scope, mainModuleAt(runtime_, "function"));
978 Function reference(&scope, mainModuleAt(runtime_, "reference"));
979 Object arg0(&scope, SmallInt::fromWord(34));
980 Object arg1(&scope, SmallInt::fromWord(12));
981 const uword digits2[] = {0x12345678, 0xabcdef};
982 Object arg_l(&scope, runtime_->newLargeIntWithDigits(digits2));
983 testBinaryOpRewrite(function, reference, BINARY_MUL_SMALLINT, arg0, arg1,
984 arg_l);
985}
986
987TEST_F(InterpreterTest, BinaryOpAnamorphicRewritesToBinarySubSmallInt) {
988 HandleScope scope(thread_);
989 ASSERT_FALSE(runFromCStr(runtime_, R"(
990def function(a, b):
991 return a - b
992reference = int.__sub__
993)")
994 .isError());
995 Function function(&scope, mainModuleAt(runtime_, "function"));
996 Function reference(&scope, mainModuleAt(runtime_, "reference"));
997 Object arg0(&scope, SmallInt::fromWord(94));
998 Object arg1(&scope, SmallInt::fromWord(21));
999 const uword digits2[] = {0x12345678, 0xabcdef};
1000 Object arg_l(&scope, runtime_->newLargeIntWithDigits(digits2));
1001 testBinaryOpRewrite(function, reference, BINARY_SUB_SMALLINT, arg0, arg1,
1002 arg_l);
1003}
1004
1005TEST_F(InterpreterTest, BinaryOpAnamorphicRewritesToBinaryOrSmallInt) {
1006 HandleScope scope(thread_);
1007 ASSERT_FALSE(runFromCStr(runtime_, R"(
1008def function(a, b):
1009 return a | b
1010reference = int.__or__
1011)")
1012 .isError());
1013 Function function(&scope, mainModuleAt(runtime_, "function"));
1014 Function reference(&scope, mainModuleAt(runtime_, "reference"));
1015 Object arg0(&scope, SmallInt::fromWord(0xa5));
1016 Object arg1(&scope, SmallInt::fromWord(0x42));
1017 const uword digits2[] = {0x12345678, 0xabcdef};
1018 Object arg_l(&scope, runtime_->newLargeIntWithDigits(digits2));
1019 testBinaryOpRewrite(function, reference, BINARY_OR_SMALLINT, arg0, arg1,
1020 arg_l);
1021}
1022
1023TEST_F(InterpreterTest, BinaryOpAnamorphicRewritesToBinaryAndSmallInt) {
1024 HandleScope scope(thread_);
1025 ASSERT_FALSE(runFromCStr(runtime_, R"(
1026def function(a, b):
1027 return a & b
1028reference = int.__and__
1029)")
1030 .isError());
1031 Function function(&scope, mainModuleAt(runtime_, "function"));
1032 Function reference(&scope, mainModuleAt(runtime_, "reference"));
1033 Object arg0(&scope, SmallInt::fromWord(0xa5));
1034 Object arg1(&scope, SmallInt::fromWord(0x42));
1035 const uword digits2[] = {0x12345678, 0xabcdef};
1036 Object arg_l(&scope, runtime_->newLargeIntWithDigits(digits2));
1037 testBinaryOpRewrite(function, reference, BINARY_AND_SMALLINT, arg0, arg1,
1038 arg_l);
1039}
1040
1041TEST_F(InterpreterTest, BinarySubscrWithListAndSmallInt) {
1042 HandleScope scope(thread_);
1043 ASSERT_FALSE(runFromCStr(runtime_, R"(
1044def foo(l, i):
1045 return l[i]
1046
1047l = [1,2,3]
1048)")
1049 .isError());
1050 Function foo(&scope, mainModuleAt(runtime_, "foo"));
1051 MutableBytes rewritten(&scope, foo.rewrittenBytecode());
1052 ASSERT_EQ(rewrittenBytecodeOpAt(rewritten, 2), BINARY_SUBSCR_ANAMORPHIC);
1053
1054 List l(&scope, mainModuleAt(runtime_, "l"));
1055 SmallInt zero(&scope, SmallInt::fromWord(0));
1056 EXPECT_TRUE(isIntEqualsWord(Interpreter::call2(thread_, foo, l, zero), 1));
1057 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten, 2), BINARY_SUBSCR_LIST);
1058
1059 SmallInt one(&scope, SmallInt::fromWord(1));
1060 EXPECT_TRUE(isIntEqualsWord(Interpreter::call2(thread_, foo, l, one), 2));
1061 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten, 2), BINARY_SUBSCR_LIST);
1062}
1063
1064TEST_F(InterpreterTest,
1065 BinarySubscrAnamorphicRewritesToBinarySubscrMonomorphic) {
1066 HandleScope scope(thread_);
1067 ASSERT_FALSE(runFromCStr(runtime_, R"(
1068def foo(l, i):
1069 return l[i]
1070
1071class L:
1072 def __getitem__(self, i): return i * 2
1073
1074L__getitem__ = L.__getitem__
1075l = L()
1076)")
1077 .isError());
1078 Function foo(&scope, mainModuleAt(runtime_, "foo"));
1079 MutableBytes rewritten(&scope, foo.rewrittenBytecode());
1080 ASSERT_EQ(rewrittenBytecodeOpAt(rewritten, 2), BINARY_SUBSCR_ANAMORPHIC);
1081
1082 Object l(&scope, mainModuleAt(runtime_, "l"));
1083 SmallInt key(&scope, SmallInt::fromWord(12));
1084 EXPECT_TRUE(isIntEqualsWord(Interpreter::call2(thread_, foo, l, key), 24));
1085 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten, 2), BINARY_SUBSCR_MONOMORPHIC);
1086
1087 SmallInt key2(&scope, SmallInt::fromWord(13));
1088 EXPECT_TRUE(isIntEqualsWord(Interpreter::call2(thread_, foo, l, key2), 26));
1089 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten, 2), BINARY_SUBSCR_MONOMORPHIC);
1090}
1091
1092TEST_F(InterpreterTest,
1093 BinarySubscrMonomorphicRewritesToBinarySubscrPolymorphic) {
1094 HandleScope scope(thread_);
1095 ASSERT_FALSE(runFromCStr(runtime_, R"(
1096def foo(l, i):
1097 return l[i]
1098
1099class A:
1100 def __getitem__(self, i): return i * 2
1101
1102class B:
1103 def __getitem__(self, i): return i * 3
1104
1105a = A()
1106b = B()
1107)")
1108 .isError());
1109 Function foo(&scope, mainModuleAt(runtime_, "foo"));
1110 MutableBytes rewritten(&scope, foo.rewrittenBytecode());
1111 ASSERT_EQ(rewrittenBytecodeOpAt(rewritten, 2), BINARY_SUBSCR_ANAMORPHIC);
1112
1113 Object a(&scope, mainModuleAt(runtime_, "a"));
1114 SmallInt key_a(&scope, SmallInt::fromWord(6));
1115 EXPECT_TRUE(isIntEqualsWord(Interpreter::call2(thread_, foo, a, key_a), 12));
1116 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten, 2), BINARY_SUBSCR_MONOMORPHIC);
1117
1118 Object b(&scope, mainModuleAt(runtime_, "b"));
1119 SmallInt key_b(&scope, SmallInt::fromWord(12));
1120 EXPECT_TRUE(isIntEqualsWord(Interpreter::call2(thread_, foo, b, key_b), 36));
1121 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten, 2), BINARY_SUBSCR_POLYMORPHIC);
1122}
1123
1124TEST_F(
1125 InterpreterTest,
1126 BinarySubscrDictRevertsBackToBinarySubscrMonomorphicWhenNonDictObserved) {
1127 HandleScope scope(thread_);
1128 ASSERT_FALSE(runFromCStr(runtime_, R"(
1129def foo(l, i):
1130 return l[i]
1131
1132d = {1: 2}
1133s = "abc"
1134)")
1135 .isError());
1136 Function foo(&scope, mainModuleAt(runtime_, "foo"));
1137 MutableBytes rewritten(&scope, foo.rewrittenBytecode());
1138 ASSERT_EQ(rewrittenBytecodeOpAt(rewritten, 2), BINARY_SUBSCR_ANAMORPHIC);
1139
1140 Dict d(&scope, mainModuleAt(runtime_, "d"));
1141 SmallInt key(&scope, SmallInt::fromWord(1));
1142 EXPECT_TRUE(isIntEqualsWord(Interpreter::call2(thread_, foo, d, key), 2));
1143 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten, 2), BINARY_SUBSCR_DICT);
1144
1145 // Revert back to caching __getitem__ when a non-list is observed.
1146 Object s(&scope, mainModuleAt(runtime_, "s"));
1147 EXPECT_TRUE(isStrEqualsCStr(Interpreter::call2(thread_, foo, s, key), "b"));
1148 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten, 2), BINARY_SUBSCR_MONOMORPHIC);
1149}
1150
1151TEST_F(
1152 InterpreterTest,
1153 BinarySubscrListRevertsBackToBinarySubscrMonomorphicWhenNonListObserved) {
1154 HandleScope scope(thread_);
1155 ASSERT_FALSE(runFromCStr(runtime_, R"(
1156def foo(l, i):
1157 return l[i]
1158
1159l = [1,2,3]
1160s = "abc"
1161)")
1162 .isError());
1163 Function foo(&scope, mainModuleAt(runtime_, "foo"));
1164 MutableBytes rewritten(&scope, foo.rewrittenBytecode());
1165 ASSERT_EQ(rewrittenBytecodeOpAt(rewritten, 2), BINARY_SUBSCR_ANAMORPHIC);
1166
1167 List l(&scope, mainModuleAt(runtime_, "l"));
1168 SmallInt key(&scope, SmallInt::fromWord(1));
1169 EXPECT_TRUE(isIntEqualsWord(Interpreter::call2(thread_, foo, l, key), 2));
1170 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten, 2), BINARY_SUBSCR_LIST);
1171
1172 // Revert back to caching __getitem__ when a non-list is observed.
1173 Object s(&scope, mainModuleAt(runtime_, "s"));
1174 EXPECT_TRUE(isStrEqualsCStr(Interpreter::call2(thread_, foo, s, key), "b"));
1175 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten, 2), BINARY_SUBSCR_MONOMORPHIC);
1176}
1177
1178TEST_F(
1179 InterpreterTest,
1180 BinarySubscrListRevertsBackToBinarySubscrMonomorphicWhenNonSmallIntKeyObserved) {
1181 HandleScope scope(thread_);
1182 ASSERT_FALSE(runFromCStr(runtime_, R"(
1183def foo(l, i):
1184 return l[i]
1185
1186l = [1,2,3]
1187large_int = 2**64
1188)")
1189 .isError());
1190 Function foo(&scope, mainModuleAt(runtime_, "foo"));
1191 MutableBytes rewritten(&scope, foo.rewrittenBytecode());
1192 ASSERT_EQ(rewrittenBytecodeOpAt(rewritten, 2), BINARY_SUBSCR_ANAMORPHIC);
1193
1194 List l(&scope, mainModuleAt(runtime_, "l"));
1195 SmallInt key(&scope, SmallInt::fromWord(1));
1196 EXPECT_TRUE(isIntEqualsWord(Interpreter::call2(thread_, foo, l, key), 2));
1197 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten, 2), BINARY_SUBSCR_LIST);
1198
1199 // Revert back to caching __getitem__ when the key is not SmallInt.
1200 LargeInt large_int(&scope, mainModuleAt(runtime_, "large_int"));
1201 EXPECT_TRUE(Interpreter::call2(thread_, foo, l, large_int).isError());
1202 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten, 2), BINARY_SUBSCR_MONOMORPHIC);
1203}
1204
1205TEST_F(
1206 InterpreterTest,
1207 BinarySubscrListRevertsBackToBinarySubscrMonomorphicWhenNegativeKeyObserved) {
1208 HandleScope scope(thread_);
1209 ASSERT_FALSE(runFromCStr(runtime_, R"(
1210def foo(l, i):
1211 return l[i]
1212
1213l = [1,2,3]
1214)")
1215 .isError());
1216 Function foo(&scope, mainModuleAt(runtime_, "foo"));
1217 MutableBytes rewritten(&scope, foo.rewrittenBytecode());
1218 ASSERT_EQ(rewrittenBytecodeOpAt(rewritten, 2), BINARY_SUBSCR_ANAMORPHIC);
1219
1220 List l(&scope, mainModuleAt(runtime_, "l"));
1221 SmallInt key(&scope, SmallInt::fromWord(1));
1222 EXPECT_TRUE(isIntEqualsWord(Interpreter::call2(thread_, foo, l, key), 2));
1223 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten, 2), BINARY_SUBSCR_LIST);
1224
1225 // Revert back to caching __getitem__ when the key is negative.
1226 SmallInt negative(&scope, SmallInt::fromWord(-1));
1227 EXPECT_TRUE(
1228 isIntEqualsWord(Interpreter::call2(thread_, foo, l, negative), 3));
1229 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten, 2), BINARY_SUBSCR_MONOMORPHIC);
1230}
1231
1232TEST_F(InterpreterTest, StoreSubscrWithDictRewritesToStoreSubscrDict) {
1233 HandleScope scope(thread_);
1234 ASSERT_FALSE(runFromCStr(runtime_, R"(
1235def foo(d, i):
1236 d[i] = 5
1237 return d[i]
1238
1239d = {}
1240)")
1241 .isError());
1242 Function foo(&scope, mainModuleAt(runtime_, "foo"));
1243 MutableBytes rewritten(&scope, foo.rewrittenBytecode());
1244 ASSERT_EQ(rewrittenBytecodeOpAt(rewritten, 3), STORE_SUBSCR_ANAMORPHIC);
1245
1246 Dict d(&scope, mainModuleAt(runtime_, "d"));
1247 SmallInt zero(&scope, SmallInt::fromWord(0));
1248 EXPECT_TRUE(isIntEqualsWord(Interpreter::call2(thread_, foo, d, zero), 5));
1249 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten, 3), STORE_SUBSCR_DICT);
1250
1251 SmallInt one(&scope, SmallInt::fromWord(1));
1252 EXPECT_TRUE(isIntEqualsWord(Interpreter::call2(thread_, foo, d, one), 5));
1253 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten, 3), STORE_SUBSCR_DICT);
1254}
1255
1256TEST_F(InterpreterTest,
1257 StoreSubscrDictRevertsBackToStoreSubscrMonomorphicWhenNonDictObserved) {
1258 HandleScope scope(thread_);
1259 ASSERT_FALSE(runFromCStr(runtime_, R"(
1260def foo(d, i):
1261 d[i] = 5
1262 return d[i]
1263
1264d = {1: -1}
1265b = bytearray(b"0000")
1266)")
1267 .isError());
1268 Function foo(&scope, mainModuleAt(runtime_, "foo"));
1269 MutableBytes rewritten(&scope, foo.rewrittenBytecode());
1270 ASSERT_EQ(rewrittenBytecodeOpAt(rewritten, 3), STORE_SUBSCR_ANAMORPHIC);
1271
1272 Dict d(&scope, mainModuleAt(runtime_, "d"));
1273 SmallInt key(&scope, SmallInt::fromWord(1));
1274 EXPECT_TRUE(isIntEqualsWord(Interpreter::call2(thread_, foo, d, key), 5));
1275 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten, 3), STORE_SUBSCR_DICT);
1276
1277 // Revert back to caching __getitem__ when a non-dict is observed.
1278 Object b(&scope, mainModuleAt(runtime_, "b"));
1279 EXPECT_TRUE(isIntEqualsWord(Interpreter::call2(thread_, foo, b, key), 5));
1280 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten, 3), STORE_SUBSCR_MONOMORPHIC);
1281}
1282
1283TEST_F(InterpreterTest, StoreSubscrWithListAndSmallInt) {
1284 HandleScope scope(thread_);
1285 ASSERT_FALSE(runFromCStr(runtime_, R"(
1286def foo(l, i):
1287 l[i] = 5
1288 return l[i]
1289
1290l = [1,2,3]
1291)")
1292 .isError());
1293 Function foo(&scope, mainModuleAt(runtime_, "foo"));
1294 MutableBytes rewritten(&scope, foo.rewrittenBytecode());
1295 ASSERT_EQ(rewrittenBytecodeOpAt(rewritten, 3), STORE_SUBSCR_ANAMORPHIC);
1296
1297 List l(&scope, mainModuleAt(runtime_, "l"));
1298 SmallInt zero(&scope, SmallInt::fromWord(0));
1299 EXPECT_TRUE(isIntEqualsWord(Interpreter::call2(thread_, foo, l, zero), 5));
1300 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten, 3), STORE_SUBSCR_LIST);
1301
1302 SmallInt one(&scope, SmallInt::fromWord(1));
1303 EXPECT_TRUE(isIntEqualsWord(Interpreter::call2(thread_, foo, l, one), 5));
1304 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten, 3), STORE_SUBSCR_LIST);
1305}
1306
1307TEST_F(InterpreterTest,
1308 StoreSubscrListRevertsBackToStoreSubscrMonomorphicWhenNonListObserved) {
1309 HandleScope scope(thread_);
1310 ASSERT_FALSE(runFromCStr(runtime_, R"(
1311def foo(l, i):
1312 l[i] = 5
1313 return l[i]
1314
1315l = [1,2,3]
1316d = {1: -1}
1317)")
1318 .isError());
1319 Function foo(&scope, mainModuleAt(runtime_, "foo"));
1320 MutableBytes rewritten(&scope, foo.rewrittenBytecode());
1321 ASSERT_EQ(rewrittenBytecodeOpAt(rewritten, 3), STORE_SUBSCR_ANAMORPHIC);
1322
1323 List l(&scope, mainModuleAt(runtime_, "l"));
1324 SmallInt key(&scope, SmallInt::fromWord(1));
1325 EXPECT_TRUE(isIntEqualsWord(Interpreter::call2(thread_, foo, l, key), 5));
1326 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten, 3), STORE_SUBSCR_LIST);
1327
1328 // Revert back to caching __getitem__ when a non-list is observed.
1329 Dict d(&scope, mainModuleAt(runtime_, "d"));
1330 EXPECT_TRUE(isIntEqualsWord(Interpreter::call2(thread_, foo, d, key), 5));
1331 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten, 3), STORE_SUBSCR_MONOMORPHIC);
1332}
1333
1334TEST_F(
1335 InterpreterTest,
1336 StoreSubscrListRevertsBackToStoreSubscrMonomorphicWhenNonSmallIntKeyObserved) {
1337 HandleScope scope(thread_);
1338 ASSERT_FALSE(runFromCStr(runtime_, R"(
1339def foo(l, i):
1340 l[i] = 5
1341 return l[i]
1342
1343l = [1,2,3]
1344large_int = 2**64
1345)")
1346 .isError());
1347 Function foo(&scope, mainModuleAt(runtime_, "foo"));
1348 MutableBytes rewritten(&scope, foo.rewrittenBytecode());
1349 ASSERT_EQ(rewrittenBytecodeOpAt(rewritten, 3), STORE_SUBSCR_ANAMORPHIC);
1350
1351 List l(&scope, mainModuleAt(runtime_, "l"));
1352 SmallInt key(&scope, SmallInt::fromWord(1));
1353 EXPECT_TRUE(isIntEqualsWord(Interpreter::call2(thread_, foo, l, key), 5));
1354 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten, 3), STORE_SUBSCR_LIST);
1355
1356 // Revert back to caching __getitem__ when the key is not SmallInt.
1357 LargeInt large_int(&scope, mainModuleAt(runtime_, "large_int"));
1358 EXPECT_TRUE(Interpreter::call2(thread_, foo, l, large_int).isError());
1359 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten, 3), STORE_SUBSCR_MONOMORPHIC);
1360}
1361
1362TEST_F(
1363 InterpreterTest,
1364 StoreSubscrListRevertsBackToStoreSubscrMonomorphicWhenNegativeKeyObserved) {
1365 HandleScope scope(thread_);
1366 ASSERT_FALSE(runFromCStr(runtime_, R"(
1367def foo(l, i):
1368 l[i] = 5
1369 return l[i]
1370
1371l = [1,2,3]
1372)")
1373 .isError());
1374 Function foo(&scope, mainModuleAt(runtime_, "foo"));
1375 MutableBytes rewritten(&scope, foo.rewrittenBytecode());
1376 ASSERT_EQ(rewrittenBytecodeOpAt(rewritten, 3), STORE_SUBSCR_ANAMORPHIC);
1377
1378 List l(&scope, mainModuleAt(runtime_, "l"));
1379 SmallInt key(&scope, SmallInt::fromWord(1));
1380 EXPECT_TRUE(isIntEqualsWord(Interpreter::call2(thread_, foo, l, key), 5));
1381 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten, 3), STORE_SUBSCR_LIST);
1382
1383 // Revert back to caching __getitem__ when the key is negative.
1384 SmallInt negative(&scope, SmallInt::fromWord(-1));
1385 EXPECT_TRUE(
1386 isIntEqualsWord(Interpreter::call2(thread_, foo, l, negative), 5));
1387 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten, 3), STORE_SUBSCR_MONOMORPHIC);
1388}
1389
1390TEST_F(InterpreterTest, BinarySubscrWithTupleAndSmallInt) {
1391 HandleScope scope(thread_);
1392 ASSERT_FALSE(runFromCStr(runtime_, R"(
1393def foo(l, i):
1394 return l[i]
1395
1396l = (1,2,3)
1397)")
1398 .isError());
1399 Function foo(&scope, mainModuleAt(runtime_, "foo"));
1400 MutableBytes rewritten(&scope, foo.rewrittenBytecode());
1401 ASSERT_EQ(rewrittenBytecodeOpAt(rewritten, 2), BINARY_SUBSCR_ANAMORPHIC);
1402
1403 Tuple l(&scope, mainModuleAt(runtime_, "l"));
1404 SmallInt zero(&scope, SmallInt::fromWord(0));
1405 EXPECT_TRUE(isIntEqualsWord(Interpreter::call2(thread_, foo, l, zero), 1));
1406 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten, 2), BINARY_SUBSCR_TUPLE);
1407
1408 SmallInt one(&scope, SmallInt::fromWord(1));
1409 EXPECT_TRUE(isIntEqualsWord(Interpreter::call2(thread_, foo, l, one), 2));
1410 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten, 2), BINARY_SUBSCR_TUPLE);
1411}
1412
1413TEST_F(
1414 InterpreterTest,
1415 BinarySubscrTupleRevertsBackToBinarySubscrMonomorphicWhenNonTupleObserved) {
1416 HandleScope scope(thread_);
1417 ASSERT_FALSE(runFromCStr(runtime_, R"(
1418def foo(l, i):
1419 return l[i]
1420
1421l = (1,2,3)
1422d = {1: -1}
1423)")
1424 .isError());
1425 Function foo(&scope, mainModuleAt(runtime_, "foo"));
1426 MutableBytes rewritten(&scope, foo.rewrittenBytecode());
1427 ASSERT_EQ(rewrittenBytecodeOpAt(rewritten, 2), BINARY_SUBSCR_ANAMORPHIC);
1428
1429 Tuple l(&scope, mainModuleAt(runtime_, "l"));
1430 SmallInt key(&scope, SmallInt::fromWord(1));
1431 EXPECT_TRUE(isIntEqualsWord(Interpreter::call2(thread_, foo, l, key), 2));
1432 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten, 2), BINARY_SUBSCR_TUPLE);
1433
1434 // Revert back to caching __getitem__ when a non-list is observed.
1435 Dict d(&scope, mainModuleAt(runtime_, "d"));
1436 EXPECT_TRUE(isIntEqualsWord(Interpreter::call2(thread_, foo, d, key), -1));
1437 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten, 2), BINARY_SUBSCR_MONOMORPHIC);
1438}
1439
1440TEST_F(
1441 InterpreterTest,
1442 BinarySubscrTupleRevertsBackToBinarySubscrMonomorphicWhenNonSmallIntKeyObserved) {
1443 HandleScope scope(thread_);
1444 ASSERT_FALSE(runFromCStr(runtime_, R"(
1445def foo(l, i):
1446 return l[i]
1447
1448l = (1,2,3)
1449large_int = 2**64
1450)")
1451 .isError());
1452 Function foo(&scope, mainModuleAt(runtime_, "foo"));
1453 MutableBytes rewritten(&scope, foo.rewrittenBytecode());
1454 ASSERT_EQ(rewrittenBytecodeOpAt(rewritten, 2), BINARY_SUBSCR_ANAMORPHIC);
1455
1456 Tuple l(&scope, mainModuleAt(runtime_, "l"));
1457 SmallInt key(&scope, SmallInt::fromWord(1));
1458 EXPECT_TRUE(isIntEqualsWord(Interpreter::call2(thread_, foo, l, key), 2));
1459 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten, 2), BINARY_SUBSCR_TUPLE);
1460
1461 // Revert back to caching __getitem__ when the key is not SmallInt.
1462 LargeInt large_int(&scope, mainModuleAt(runtime_, "large_int"));
1463 EXPECT_TRUE(Interpreter::call2(thread_, foo, l, large_int).isError());
1464 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten, 2), BINARY_SUBSCR_MONOMORPHIC);
1465}
1466
1467TEST_F(
1468 InterpreterTest,
1469 BinarySubscrTupleRevertsBackToBinarySubscrMonomorphicWhenNegativeKeyObserved) {
1470 HandleScope scope(thread_);
1471 ASSERT_FALSE(runFromCStr(runtime_, R"(
1472def foo(l, i):
1473 return l[i]
1474
1475l = (1,2,3)
1476)")
1477 .isError());
1478 Function foo(&scope, mainModuleAt(runtime_, "foo"));
1479 MutableBytes rewritten(&scope, foo.rewrittenBytecode());
1480 ASSERT_EQ(rewrittenBytecodeOpAt(rewritten, 2), BINARY_SUBSCR_ANAMORPHIC);
1481
1482 Tuple l(&scope, mainModuleAt(runtime_, "l"));
1483 SmallInt key(&scope, SmallInt::fromWord(1));
1484 EXPECT_TRUE(isIntEqualsWord(Interpreter::call2(thread_, foo, l, key), 2));
1485 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten, 2), BINARY_SUBSCR_TUPLE);
1486
1487 // Revert back to caching __getitem__ when the key is negative.
1488 SmallInt negative(&scope, SmallInt::fromWord(-1));
1489 EXPECT_TRUE(
1490 isIntEqualsWord(Interpreter::call2(thread_, foo, l, negative), 3));
1491 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten, 2), BINARY_SUBSCR_MONOMORPHIC);
1492}
1493
1494TEST_F(InterpreterTest, InplaceOpCachedInsertsDependencyForThreeAttributes) {
1495 HandleScope scope(thread_);
1496 EXPECT_FALSE(runFromCStr(runtime_, R"(
1497class A:
1498 def __imul__(self, other):
1499 return "from class A"
1500
1501class B:
1502 pass
1503
1504def cache_inplace_op(a, b):
1505 a *= b
1506
1507a = A()
1508b = B()
1509A__imul__ = A.__imul__
1510cache_inplace_op(a, b)
1511)")
1512 .isError());
1513 Function cache_inplace_op(&scope, mainModuleAt(runtime_, "cache_inplace_op"));
1514 MutableTuple caches(&scope, cache_inplace_op.caches());
1515 Object a(&scope, mainModuleAt(runtime_, "a"));
1516 Object b(&scope, mainModuleAt(runtime_, "b"));
1517 Type type_a(&scope, mainModuleAt(runtime_, "A"));
1518 Type type_b(&scope, mainModuleAt(runtime_, "B"));
1519 BinaryOpFlags flag;
1520 ASSERT_EQ(icLookupBinaryOp(*caches, 0, a.layoutId(), b.layoutId(), &flag),
1521 mainModuleAt(runtime_, "A__imul__"));
1522
1523 // Verify that A.__imul__ has the dependent.
1524 Object inplace_op_name(&scope, runtime_->symbols()->at(ID(__imul__)));
1525 Object inplace_attr(&scope, typeValueCellAt(*type_a, *inplace_op_name));
1526 ASSERT_TRUE(inplace_attr.isValueCell());
1527 ASSERT_TRUE(ValueCell::cast(*inplace_attr).dependencyLink().isWeakLink());
1528 EXPECT_EQ(WeakLink::cast(ValueCell::cast(*inplace_attr).dependencyLink())
1529 .referent(),
1530 *cache_inplace_op);
1531
1532 // Verify that A.__mul__ has the dependent.
1533 Object left_op_name(&scope, runtime_->symbols()->at(ID(__mul__)));
1534 Object type_a_attr(&scope, typeValueCellAt(*type_a, *left_op_name));
1535 ASSERT_TRUE(type_a_attr.isValueCell());
1536 ASSERT_TRUE(ValueCell::cast(*type_a_attr).dependencyLink().isWeakLink());
1537 EXPECT_EQ(
1538 WeakLink::cast(ValueCell::cast(*type_a_attr).dependencyLink()).referent(),
1539 *cache_inplace_op);
1540
1541 // Verify that B.__rmul__ has the dependent.
1542 Object right_op_name(&scope, runtime_->symbols()->at(ID(__rmul__)));
1543 Object type_b_attr(&scope, typeValueCellAt(*type_b, *right_op_name));
1544 ASSERT_TRUE(type_b_attr.isValueCell());
1545 ASSERT_TRUE(ValueCell::cast(*type_b_attr).dependencyLink().isWeakLink());
1546 EXPECT_EQ(
1547 WeakLink::cast(ValueCell::cast(*type_b_attr).dependencyLink()).referent(),
1548 *cache_inplace_op);
1549}
1550
1551TEST_F(InterpreterTest, ImportFromWithMissingAttributeRaisesImportError) {
1552 HandleScope scope(thread_);
1553 Str name(&scope, runtime_->newStrFromCStr("foo"));
1554 Module module(&scope, runtime_->newModule(name));
1555 Object modules(&scope, runtime_->modules());
1556 ASSERT_FALSE(
1557 objectSetItem(thread_, modules, name, module).isErrorException());
1558 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, "from foo import bar"),
1559 LayoutId::kImportError,
1560 "cannot import name 'bar' from 'foo'"));
1561}
1562
1563TEST_F(InterpreterTest, ImportFromCallsDunderGetattribute) {
1564 HandleScope scope(thread_);
1565 ASSERT_FALSE(runFromCStr(runtime_, R"(
1566class C:
1567 def __getattribute__(self, name):
1568 return f"getattribute '{name}'"
1569i = C()
1570)")
1571 .isError());
1572 Object i(&scope, mainModuleAt(runtime_, "i"));
1573
1574 Tuple consts(&scope, runtime_->newTupleWith1(i));
1575 Object name(&scope, Runtime::internStrFromCStr(thread_, "foo"));
1576 Tuple names(&scope, runtime_->newTupleWith1(name));
1577 const byte bytecode[] = {LOAD_CONST, 0, IMPORT_FROM, 0, RETURN_VALUE, 0};
1578 Code code(&scope, newCodeWithBytesConstsNames(bytecode, consts, names));
1579
1580 EXPECT_TRUE(isStrEqualsCStr(runCode(code), "getattribute 'foo'"));
1581}
1582
1583TEST_F(InterpreterTest, ImportFromWithNonModuleRaisesImportError) {
1584 HandleScope scope(thread_);
1585 Object obj(&scope, NoneType::object());
1586 Tuple consts(&scope, runtime_->newTupleWith1(obj));
1587 Object name(&scope, Runtime::internStrFromCStr(thread_, "foo"));
1588 Tuple names(&scope, runtime_->newTupleWith1(name));
1589 const byte bytecode[] = {LOAD_CONST, 0, IMPORT_FROM, 0, RETURN_VALUE, 0};
1590 Code code(&scope, newCodeWithBytesConstsNames(bytecode, consts, names));
1591
1592 EXPECT_TRUE(raisedWithStr(runCode(code), LayoutId::kImportError,
1593 "cannot import name 'foo'"));
1594}
1595
1596TEST_F(InterpreterTest, ImportFromWithNonModulePropagatesException) {
1597 HandleScope scope(thread_);
1598 ASSERT_FALSE(runFromCStr(runtime_, R"(
1599class C:
1600 def __getattribute__(self, name):
1601 raise UserWarning()
1602i = C()
1603)")
1604 .isError());
1605 Object i(&scope, mainModuleAt(runtime_, "i"));
1606
1607 Tuple consts(&scope, runtime_->newTupleWith1(i));
1608 Object name(&scope, Runtime::internStrFromCStr(thread_, "foo"));
1609 Tuple names(&scope, runtime_->newTupleWith1(name));
1610 const byte bytecode[] = {LOAD_CONST, 0, IMPORT_FROM, 0, RETURN_VALUE, 0};
1611 Code code(&scope, newCodeWithBytesConstsNames(bytecode, consts, names));
1612
1613 EXPECT_TRUE(raised(runCode(code), LayoutId::kUserWarning));
1614}
1615
1616TEST_F(InterpreterTest, InplaceOperationCallsInplaceMethod) {
1617 HandleScope scope(thread_);
1618
1619 ASSERT_FALSE(runFromCStr(runtime_, R"(
1620class C:
1621 def __isub__(self, other):
1622 return (C, '__isub__', self, other)
1623
1624left = C()
1625right = C()
1626)")
1627 .isError());
1628
1629 Object left(&scope, mainModuleAt(runtime_, "left"));
1630 Object right(&scope, mainModuleAt(runtime_, "right"));
1631 Object c_class(&scope, mainModuleAt(runtime_, "C"));
1632
1633 Object result_obj(
1634 &scope, Interpreter::inplaceOperation(thread_, Interpreter::BinaryOp::SUB,
1635 left, right));
1636 ASSERT_TRUE(result_obj.isTuple());
1637 Tuple result(&scope, *result_obj);
1638 ASSERT_EQ(result.length(), 4);
1639 EXPECT_EQ(result.at(0), *c_class);
1640 EXPECT_TRUE(isStrEqualsCStr(result.at(1), "__isub__"));
1641 EXPECT_EQ(result.at(2), *left);
1642 EXPECT_EQ(result.at(3), *right);
1643}
1644
1645TEST_F(InterpreterTest, InplaceOperationCallsBinaryMethod) {
1646 HandleScope scope(thread_);
1647
1648 ASSERT_FALSE(runFromCStr(runtime_, R"(
1649class C:
1650 def __sub__(self, other):
1651 return (C, '__sub__', self, other)
1652
1653left = C()
1654right = C()
1655)")
1656 .isError());
1657
1658 Object left(&scope, mainModuleAt(runtime_, "left"));
1659 Object right(&scope, mainModuleAt(runtime_, "right"));
1660 Object c_class(&scope, mainModuleAt(runtime_, "C"));
1661
1662 Object result_obj(
1663 &scope, Interpreter::inplaceOperation(thread_, Interpreter::BinaryOp::SUB,
1664 left, right));
1665 ASSERT_TRUE(result_obj.isTuple());
1666 Tuple result(&scope, *result_obj);
1667 ASSERT_EQ(result.length(), 4);
1668 EXPECT_EQ(result.at(0), *c_class);
1669 EXPECT_TRUE(isStrEqualsCStr(result.at(1), "__sub__"));
1670 EXPECT_EQ(result.at(2), *left);
1671 EXPECT_EQ(result.at(3), *right);
1672}
1673
1674TEST_F(InterpreterTest, InplaceOperationCallsBinaryMethodAfterNotImplemented) {
1675 HandleScope scope(thread_);
1676
1677 ASSERT_FALSE(runFromCStr(runtime_, R"(
1678class C:
1679 def __isub__(self, other):
1680 return NotImplemented
1681 def __sub__(self, other):
1682 return (C, '__sub__', self, other)
1683
1684left = C()
1685right = C()
1686)")
1687 .isError());
1688
1689 Object left(&scope, mainModuleAt(runtime_, "left"));
1690 Object right(&scope, mainModuleAt(runtime_, "right"));
1691 Object c_class(&scope, mainModuleAt(runtime_, "C"));
1692
1693 Object result_obj(
1694 &scope, Interpreter::inplaceOperation(thread_, Interpreter::BinaryOp::SUB,
1695 left, right));
1696 ASSERT_TRUE(result_obj.isTuple());
1697 Tuple result(&scope, *result_obj);
1698 ASSERT_EQ(result.length(), 4);
1699 EXPECT_EQ(result.at(0), *c_class);
1700 EXPECT_TRUE(isStrEqualsCStr(result.at(1), "__sub__"));
1701 EXPECT_EQ(result.at(2), *left);
1702 EXPECT_EQ(result.at(3), *right);
1703}
1704
1705TEST_F(InterpreterTest, InplaceOperationSetMethodSetsMethodFlagsBinaryOpRetry) {
1706 HandleScope scope(thread_);
1707 ASSERT_FALSE(runFromCStr(runtime_, R"(
1708class MyInt(int):
1709 def __isub__(self, other):
1710 return int(self) - other - 2
1711v0 = MyInt(9)
1712v1 = MyInt(-11)
1713v2 = MyInt(-3)
1714v3 = MyInt(7)
1715)")
1716 .isError());
1717 Object v0(&scope, mainModuleAt(runtime_, "v0"));
1718 Object v1(&scope, mainModuleAt(runtime_, "v1"));
1719 Object v2(&scope, mainModuleAt(runtime_, "v2"));
1720 Object v3(&scope, mainModuleAt(runtime_, "v3"));
1721 Object method(&scope, NoneType::object());
1722 BinaryOpFlags flags;
1723 EXPECT_TRUE(isIntEqualsWord(
1724 Interpreter::inplaceOperationSetMethod(
1725 thread_, Interpreter::BinaryOp::SUB, v0, v1, &method, &flags),
1726 18));
1727 EXPECT_EQ(flags, kInplaceBinaryOpRetry);
1728
1729 ASSERT_EQ(v0.layoutId(), v2.layoutId());
1730 ASSERT_EQ(v1.layoutId(), v3.layoutId());
1731 EXPECT_TRUE(isIntEqualsWord(
1732 Interpreter::binaryOperationWithMethod(thread_, *method, flags, *v2, *v3),
1733 -12));
1734}
1735
1736TEST_F(InterpreterTest, InplaceOperationSetMethodSetsMethodFlagsReverseRetry) {
1737 HandleScope scope(thread_);
1738 ASSERT_FALSE(runFromCStr(runtime_, R"(
1739class MyInt(int):
1740 pass
1741class MyIntSub(MyInt):
1742 def __rpow__(self, other):
1743 return int(other) ** int(self) - 7
1744v0 = MyInt(3)
1745v1 = MyIntSub(3)
1746v2 = MyInt(-4)
1747v3 = MyIntSub(4)
1748)")
1749 .isError());
1750 Object v0(&scope, mainModuleAt(runtime_, "v0"));
1751 Object v1(&scope, mainModuleAt(runtime_, "v1"));
1752 Object v2(&scope, mainModuleAt(runtime_, "v2"));
1753 Object v3(&scope, mainModuleAt(runtime_, "v3"));
1754 Object method(&scope, NoneType::object());
1755 BinaryOpFlags flags;
1756 EXPECT_TRUE(isIntEqualsWord(
1757 Interpreter::inplaceOperationSetMethod(
1758 thread_, Interpreter::BinaryOp::POW, v0, v1, &method, &flags),
1759 20));
1760 EXPECT_EQ(flags, kBinaryOpReflected | kBinaryOpNotImplementedRetry);
1761
1762 ASSERT_EQ(v0.layoutId(), v2.layoutId());
1763 ASSERT_EQ(v1.layoutId(), v3.layoutId());
1764 EXPECT_TRUE(isIntEqualsWord(
1765 Interpreter::binaryOperationWithMethod(thread_, *method, flags, *v2, *v3),
1766 249));
1767}
1768
1769TEST_F(InterpreterTest, InplaceAddWithSmallIntsRewritesOpcode) {
1770 HandleScope scope(thread_);
1771
1772 word left = 7;
1773 word right = -13;
1774 Object left_obj(&scope, runtime_->newInt(left));
1775 Object right_obj(&scope, runtime_->newInt(right));
1776 Tuple consts(&scope, runtime_->newTupleWith2(left_obj, right_obj));
1777 const byte bytecode[] = {
1778 LOAD_CONST, 0, LOAD_CONST, 1, INPLACE_ADD, 0, RETURN_VALUE, 0,
1779 };
1780 Code code(&scope, newCodeWithBytesConsts(bytecode, consts));
1781
1782 Object qualname(&scope, Str::empty());
1783 Module module(&scope, findMainModule(runtime_));
1784 Function function(
1785 &scope, runtime_->newFunctionWithCode(thread_, qualname, code, module));
1786
1787 // Update the opcode.
1788 ASSERT_TRUE(
1789 isIntEqualsWord(Interpreter::call0(thread_, function), left + right));
1790
1791 MutableBytes rewritten_bytecode(&scope, function.rewrittenBytecode());
1792 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten_bytecode, 2), INPLACE_ADD_SMALLINT);
1793
1794 // Updated opcode returns the same value.
1795 EXPECT_TRUE(
1796 isIntEqualsWord(Interpreter::call0(thread_, function), left + right));
1797}
1798
1799TEST_F(InterpreterTest, InplaceAddSmallInt) {
1800 HandleScope scope(thread_);
1801 ASSERT_FALSE(runFromCStr(runtime_, R"(
1802def foo(a, b):
1803 a += b
1804 return a
1805)")
1806 .isError());
1807 Function function(&scope, mainModuleAt(runtime_, "foo"));
1808 MutableBytes rewritten(&scope, function.rewrittenBytecode());
1809 ASSERT_EQ(rewrittenBytecodeOpAt(rewritten, 2), INPLACE_OP_ANAMORPHIC);
1810
1811 SmallInt left(&scope, SmallInt::fromWord(7));
1812 SmallInt right(&scope, SmallInt::fromWord(-13));
1813
1814 rewrittenBytecodeOpAtPut(rewritten, 2, INPLACE_ADD_SMALLINT);
1815 left = SmallInt::fromWord(7);
1816 right = SmallInt::fromWord(-13);
1817 // 7 + (-13)
1818 EXPECT_TRUE(
1819 isIntEqualsWord(Interpreter::call2(thread_, function, left, right), -6));
1820}
1821
1822TEST_F(InterpreterTest, InplaceAddSmallIntRevertsBackToInplaceOp) {
1823 HandleScope scope(thread_);
1824 ASSERT_FALSE(runFromCStr(runtime_, R"(
1825def foo(a, b):
1826 a += b
1827 return a
1828)")
1829 .isError());
1830 Function function(&scope, mainModuleAt(runtime_, "foo"));
1831 MutableBytes rewritten(&scope, function.rewrittenBytecode());
1832 ASSERT_EQ(rewrittenBytecodeOpAt(rewritten, 2), INPLACE_OP_ANAMORPHIC);
1833
1834 LargeInt left(&scope, runtime_->newInt(SmallInt::kMaxValue + 1));
1835 SmallInt right(&scope, SmallInt::fromWord(13));
1836
1837 rewrittenBytecodeOpAtPut(rewritten, 2, INPLACE_ADD_SMALLINT);
1838 // LARGE_SMALL_INT += SMALL_INT
1839 EXPECT_TRUE(
1840 isIntEqualsWord(Interpreter::call2(thread_, function, left, right),
1841 SmallInt::kMaxValue + 1 + 13));
1842 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten, 2), INPLACE_OP_MONOMORPHIC);
1843}
1844
1845TEST_F(InterpreterTest, InplaceSubtractWithSmallIntsRewritesOpcode) {
1846 HandleScope scope(thread_);
1847
1848 word left = 7;
1849 word right = -13;
1850 Object left_obj(&scope, runtime_->newInt(left));
1851 Object right_obj(&scope, runtime_->newInt(right));
1852 Tuple consts(&scope, runtime_->newTupleWith2(left_obj, right_obj));
1853 const byte bytecode[] = {
1854 LOAD_CONST, 0, LOAD_CONST, 1, INPLACE_SUBTRACT, 0, RETURN_VALUE, 0,
1855 };
1856 Code code(&scope, newCodeWithBytesConsts(bytecode, consts));
1857
1858 Object qualname(&scope, Str::empty());
1859 Module module(&scope, findMainModule(runtime_));
1860 Function function(
1861 &scope, runtime_->newFunctionWithCode(thread_, qualname, code, module));
1862
1863 // Update the opcode.
1864 ASSERT_TRUE(
1865 isIntEqualsWord(Interpreter::call0(thread_, function), left - right));
1866
1867 MutableBytes rewritten_bytecode(&scope, function.rewrittenBytecode());
1868 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten_bytecode, 2), INPLACE_SUB_SMALLINT);
1869
1870 // Updated opcode returns the same value.
1871 EXPECT_TRUE(
1872 isIntEqualsWord(Interpreter::call0(thread_, function), left - right));
1873}
1874
1875TEST_F(InterpreterTest, InplaceSubtractSmallInt) {
1876 HandleScope scope(thread_);
1877 ASSERT_FALSE(runFromCStr(runtime_, R"(
1878def foo(a, b):
1879 a -= b
1880 return a
1881)")
1882 .isError());
1883 Function function(&scope, mainModuleAt(runtime_, "foo"));
1884 MutableBytes rewritten(&scope, function.rewrittenBytecode());
1885 ASSERT_EQ(rewrittenBytecodeOpAt(rewritten, 2), INPLACE_OP_ANAMORPHIC);
1886
1887 SmallInt left(&scope, SmallInt::fromWord(7));
1888 SmallInt right(&scope, SmallInt::fromWord(-13));
1889
1890 rewrittenBytecodeOpAtPut(rewritten, 2, INPLACE_SUB_SMALLINT);
1891 left = SmallInt::fromWord(7);
1892 right = SmallInt::fromWord(-13);
1893 // 7 - (-13)
1894 EXPECT_TRUE(
1895 isIntEqualsWord(Interpreter::call2(thread_, function, left, right), 20));
1896}
1897
1898TEST_F(InterpreterTest, InplaceSubSmallIntRevertsBackToInplaceOp) {
1899 HandleScope scope(thread_);
1900 ASSERT_FALSE(runFromCStr(runtime_, R"(
1901def foo(a, b):
1902 a -= b
1903 return a
1904)")
1905 .isError());
1906 Function function(&scope, mainModuleAt(runtime_, "foo"));
1907 MutableBytes rewritten(&scope, function.rewrittenBytecode());
1908 ASSERT_EQ(rewrittenBytecodeOpAt(rewritten, 2), INPLACE_OP_ANAMORPHIC);
1909
1910 LargeInt left(&scope, runtime_->newInt(SmallInt::kMaxValue + 1));
1911 SmallInt right(&scope, SmallInt::fromWord(13));
1912
1913 rewrittenBytecodeOpAtPut(rewritten, 2, INPLACE_SUB_SMALLINT);
1914 // LARGE_SMALL_INT -= SMALL_INT
1915 EXPECT_TRUE(
1916 isIntEqualsWord(Interpreter::call2(thread_, function, left, right),
1917 SmallInt::kMaxValue + 1 - 13));
1918 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten, 2), INPLACE_OP_MONOMORPHIC);
1919}
1920
1921TEST_F(InterpreterDeathTest, InvalidOpcode) {
1922 HandleScope scope(thread_);
1923
1924 const byte bytecode[] = {NOP, 0, NOP, 0, UNUSED_BYTECODE_0, 17, NOP, 7};
1925 Code code(&scope, newCodeWithBytes(bytecode));
1926
1927 ASSERT_DEATH(static_cast<void>(runCode(code)),
1928 "bytecode 'UNUSED_BYTECODE_0'");
1929}
1930
1931TEST_F(InterpreterTest, CallDescriptorGetWithBuiltinTypeDescriptors) {
1932 ASSERT_FALSE(runFromCStr(runtime_, R"(
1933
1934def class_method_func(self): pass
1935
1936def static_method_func(cls): pass
1937
1938class C:
1939 class_method = classmethod(class_method_func)
1940
1941 static_method = staticmethod(static_method_func)
1942
1943 @property
1944 def property_field(self): return "property"
1945
1946 def function_field(self): pass
1947
1948i = C()
1949)")
1950 .isError());
1951 HandleScope scope(thread_);
1952 Type c(&scope, mainModuleAt(runtime_, "C"));
1953 Type type(&scope, runtime_->typeOf(*c));
1954 Object i(&scope, mainModuleAt(runtime_, "i"));
1955
1956 Object class_method_name(&scope,
1957 Runtime::internStrFromCStr(thread_, "class_method"));
1958 Object class_method(&scope, typeAt(c, class_method_name));
1959 BoundMethod class_method_result(
1960 &scope, Interpreter::callDescriptorGet(thread_, class_method, i, c));
1961 EXPECT_EQ(class_method_result.self(), *c);
1962 EXPECT_EQ(class_method_result.function(),
1963 mainModuleAt(runtime_, "class_method_func"));
1964
1965 Object static_method_name(
1966 &scope, Runtime::internStrFromCStr(thread_, "static_method"));
1967 Object static_method(&scope, typeAt(c, static_method_name));
1968 Function static_method_result(
1969 &scope, Interpreter::callDescriptorGet(thread_, static_method, c, type));
1970 EXPECT_EQ(*static_method_result,
1971 mainModuleAt(runtime_, "static_method_func"));
1972
1973 Object property_field_name(
1974 &scope, Runtime::internStrFromCStr(thread_, "property_field"));
1975 Object property_field(&scope, typeAt(c, property_field_name));
1976 Object property_field_result(
1977 &scope, Interpreter::callDescriptorGet(thread_, property_field, i, c));
1978 EXPECT_TRUE(isStrEqualsCStr(*property_field_result, "property"));
1979
1980 Object function_field_name(
1981 &scope, Runtime::internStrFromCStr(thread_, "function_field"));
1982 Object function_field(&scope, typeAt(c, function_field_name));
1983 BoundMethod function_field_result(
1984 &scope, Interpreter::callDescriptorGet(thread_, function_field, i, c));
1985 EXPECT_EQ(function_field_result.self(), *i);
1986 EXPECT_EQ(function_field_result.function(), *function_field);
1987
1988 Object none(&scope, NoneType::object());
1989 Function function_field_result_from_none_instance(
1990 &scope, Interpreter::callDescriptorGet(thread_, function_field, none, c));
1991 EXPECT_EQ(function_field_result_from_none_instance, *function_field);
1992
1993 Type none_type(&scope, runtime_->typeAt(LayoutId::kNoneType));
1994 BoundMethod function_field_result_from_none_instance_of_none_type(
1995 &scope,
1996 Interpreter::callDescriptorGet(thread_, function_field, none, none_type));
1997 EXPECT_EQ(function_field_result_from_none_instance_of_none_type.self(),
1998 *none);
1999 EXPECT_EQ(function_field_result_from_none_instance_of_none_type.function(),
2000 *function_field);
2001}
2002
2003TEST_F(InterpreterTest, CompareInAnamorphicWithStrRewritesOpcode) {
2004 HandleScope scope(thread_);
2005 Object obj1(&scope, runtime_->newStrFromCStr("test"));
2006 Object obj2(&scope, runtime_->newStrFromCStr("test string"));
2007 Tuple consts(&scope, runtime_->newTupleWith2(obj1, obj2));
2008 const byte bytecode[] = {
2009 LOAD_CONST, 0, LOAD_CONST, 1, COMPARE_IN_ANAMORPHIC, 0, RETURN_VALUE, 0,
2010 };
2011 Code code(&scope, newCodeWithBytesConsts(bytecode, consts));
2012
2013 Object qualname(&scope, Str::empty());
2014 Module module(&scope, findMainModule(runtime_));
2015 Function function(
2016 &scope, runtime_->newFunctionWithCode(thread_, qualname, code, module));
2017
2018 // Update the opcode.
2019 ASSERT_EQ(Interpreter::call0(thread_, function), Bool::trueObj());
2020
2021 MutableBytes rewritten_bytecode(&scope, function.rewrittenBytecode());
2022 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten_bytecode, 2), COMPARE_IN_STR);
2023
2024 // Updated opcode returns the same value.
2025 ASSERT_EQ(Interpreter::call0(thread_, function), Bool::trueObj());
2026}
2027
2028TEST_F(InterpreterTest, CompareInAnamorphicWithDictRewritesOpcode) {
2029 HandleScope scope(thread_);
2030 Dict dict(&scope, runtime_->newDict());
2031 Str key(&scope, runtime_->newStrFromCStr("test"));
2032 word key_hash = strHash(thread_, *key);
2033 dictAtPut(thread_, dict, key, key_hash, key);
2034 Tuple consts(&scope, runtime_->newTupleWith2(key, dict));
2035 const byte bytecode[] = {
2036 LOAD_CONST, 0, LOAD_CONST, 1, COMPARE_IN_ANAMORPHIC, 0, RETURN_VALUE, 0,
2037 };
2038 Code code(&scope, newCodeWithBytesConsts(bytecode, consts));
2039
2040 Object qualname(&scope, Str::empty());
2041 Module module(&scope, findMainModule(runtime_));
2042 Function function(
2043 &scope, runtime_->newFunctionWithCode(thread_, qualname, code, module));
2044
2045 // Update the opcode.
2046 ASSERT_EQ(Interpreter::call0(thread_, function), Bool::trueObj());
2047
2048 MutableBytes rewritten_bytecode(&scope, function.rewrittenBytecode());
2049 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten_bytecode, 2), COMPARE_IN_DICT);
2050
2051 // Updated opcode returns the same value.
2052 ASSERT_EQ(Interpreter::call0(thread_, function), Bool::trueObj());
2053}
2054
2055TEST_F(InterpreterTest, CompareInAnamorphicWithTupleRewritesOpcode) {
2056 HandleScope scope(thread_);
2057 Object obj(&scope, runtime_->newStrFromCStr("test"));
2058 Tuple tuple(&scope, runtime_->newTupleWith1(obj));
2059 Tuple consts(&scope, runtime_->newTupleWith2(obj, tuple));
2060 const byte bytecode[] = {
2061 LOAD_CONST, 0, LOAD_CONST, 1, COMPARE_IN_ANAMORPHIC, 0, RETURN_VALUE, 0,
2062 };
2063 Code code(&scope, newCodeWithBytesConsts(bytecode, consts));
2064
2065 Object qualname(&scope, Str::empty());
2066 Module module(&scope, findMainModule(runtime_));
2067 Function function(
2068 &scope, runtime_->newFunctionWithCode(thread_, qualname, code, module));
2069
2070 // Update the opcode.
2071 ASSERT_EQ(Interpreter::call0(thread_, function), Bool::trueObj());
2072
2073 MutableBytes rewritten_bytecode(&scope, function.rewrittenBytecode());
2074 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten_bytecode, 2), COMPARE_IN_TUPLE);
2075
2076 // Updated opcode returns the same value.
2077 ASSERT_EQ(Interpreter::call0(thread_, function), Bool::trueObj());
2078}
2079
2080TEST_F(InterpreterTest, CompareInAnamorphicWithListRewritesOpcode) {
2081 HandleScope scope(thread_);
2082 List list(&scope, runtime_->newList());
2083 Object value0(&scope, runtime_->newStrFromCStr("value0"));
2084 Object value1(&scope, runtime_->newStrFromCStr("test"));
2085 listInsert(thread_, list, value0, 0);
2086 listInsert(thread_, list, value1, 1);
2087 Tuple consts(&scope, runtime_->newTupleWith2(value1, list));
2088 const byte bytecode[] = {
2089 LOAD_CONST, 0, LOAD_CONST, 1, COMPARE_IN_ANAMORPHIC, 0, RETURN_VALUE, 0,
2090 };
2091 Code code(&scope, newCodeWithBytesConsts(bytecode, consts));
2092
2093 Object qualname(&scope, Str::empty());
2094 Module module(&scope, findMainModule(runtime_));
2095 Function function(
2096 &scope, runtime_->newFunctionWithCode(thread_, qualname, code, module));
2097
2098 // Update the opcode.
2099 ASSERT_EQ(Interpreter::call0(thread_, function), Bool::trueObj());
2100
2101 MutableBytes rewritten_bytecode(&scope, function.rewrittenBytecode());
2102 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten_bytecode, 2), COMPARE_IN_LIST);
2103
2104 // Updated opcode returns the same value.
2105 ASSERT_EQ(Interpreter::call0(thread_, function), Bool::trueObj());
2106}
2107
2108// To a rich comparison on two instances of the same type. In each case, the
2109// method on the left side of the comparison should be used.
2110TEST_F(InterpreterTest, CompareOpSameType) {
2111 HandleScope scope(thread_);
2112
2113 ASSERT_FALSE(runFromCStr(runtime_, R"(
2114class C:
2115 def __init__(self, value):
2116 self.value = value
2117
2118 def __lt__(self, other):
2119 return self.value < other.value
2120
2121c10 = C(10)
2122c20 = C(20)
2123)")
2124 .isError());
2125
2126 Object left(&scope, mainModuleAt(runtime_, "c10"));
2127 Object right(&scope, mainModuleAt(runtime_, "c20"));
2128
2129 Object left_lt_right(&scope, Interpreter::compareOperation(
2130 thread_, CompareOp::LT, left, right));
2131 EXPECT_EQ(left_lt_right, Bool::trueObj());
2132
2133 Object right_lt_left(&scope, Interpreter::compareOperation(
2134 thread_, CompareOp::LT, right, left));
2135 EXPECT_EQ(right_lt_left, Bool::falseObj());
2136}
2137
2138TEST_F(InterpreterTest, CompareOpFallback) {
2139 HandleScope scope(thread_);
2140
2141 ASSERT_FALSE(runFromCStr(runtime_, R"(
2142class C:
2143 def __init__(self, value):
2144 self.value = value
2145
2146c10 = C(10)
2147c20 = C(20)
2148)")
2149 .isError());
2150
2151 Object left(&scope, mainModuleAt(runtime_, "c10"));
2152 Object right(&scope, mainModuleAt(runtime_, "c20"));
2153
2154 Object left_eq_right(&scope, Interpreter::compareOperation(
2155 thread_, CompareOp::EQ, left, right));
2156 EXPECT_EQ(left_eq_right, Bool::falseObj());
2157 Object left_ne_right(&scope, Interpreter::compareOperation(
2158 thread_, CompareOp::NE, left, right));
2159 EXPECT_EQ(left_ne_right, Bool::trueObj());
2160
2161 Object right_eq_left(&scope, Interpreter::compareOperation(
2162 thread_, CompareOp::EQ, left, right));
2163 EXPECT_EQ(right_eq_left, Bool::falseObj());
2164 Object right_ne_left(&scope, Interpreter::compareOperation(
2165 thread_, CompareOp::NE, left, right));
2166 EXPECT_EQ(right_ne_left, Bool::trueObj());
2167}
2168
2169TEST_F(InterpreterTest, CompareOpSubclass) {
2170 HandleScope scope(thread_);
2171
2172 ASSERT_FALSE(runFromCStr(runtime_, R"(
2173called = None
2174class A:
2175 def __eq__(self, other):
2176 global called
2177 if (called is not None):
2178 called = "ERROR"
2179 else:
2180 called = "A"
2181 return False
2182
2183class B:
2184 def __eq__(self, other):
2185 global called
2186 if (called is not None):
2187 called = "ERROR"
2188 else:
2189 called = "B"
2190 return True
2191
2192class C(A):
2193 def __eq__(self, other):
2194 global called
2195 if (called is not None):
2196 called = "ERROR"
2197 else:
2198 called = "C"
2199 return True
2200
2201a = A()
2202b = B()
2203c = C()
2204)")
2205 .isError());
2206
2207 Object a(&scope, mainModuleAt(runtime_, "a"));
2208 Object b(&scope, mainModuleAt(runtime_, "b"));
2209 Object c(&scope, mainModuleAt(runtime_, "c"));
2210
2211 // Comparisons where rhs is not a subtype of lhs try lhs.__eq__(rhs) first.
2212 Object a_eq_b(&scope,
2213 Interpreter::compareOperation(thread_, CompareOp::EQ, a, b));
2214 EXPECT_EQ(a_eq_b, Bool::falseObj());
2215 Object called(&scope, mainModuleAt(runtime_, "called"));
2216 EXPECT_TRUE(isStrEqualsCStr(*called, "A"));
2217
2218 Object called_name(&scope, Runtime::internStrFromCStr(thread_, "called"));
2219 Object none(&scope, NoneType::object());
2220 Module main(&scope, findMainModule(runtime_));
2221 moduleAtPut(thread_, main, called_name, none);
2222 Object b_eq_a(&scope,
2223 Interpreter::compareOperation(thread_, CompareOp::EQ, b, a));
2224 EXPECT_EQ(b_eq_a, Bool::trueObj());
2225 called = mainModuleAt(runtime_, "called");
2226 EXPECT_TRUE(isStrEqualsCStr(*called, "B"));
2227
2228 moduleAtPut(thread_, main, called_name, none);
2229 Object c_eq_a(&scope,
2230 Interpreter::compareOperation(thread_, CompareOp::EQ, c, a));
2231 EXPECT_EQ(c_eq_a, Bool::trueObj());
2232 called = mainModuleAt(runtime_, "called");
2233 EXPECT_TRUE(isStrEqualsCStr(*called, "C"));
2234
2235 // When rhs is a subtype of lhs, only rhs.__eq__(rhs) is tried.
2236 moduleAtPut(thread_, main, called_name, none);
2237 Object a_eq_c(&scope,
2238 Interpreter::compareOperation(thread_, CompareOp::EQ, a, c));
2239 EXPECT_EQ(a_eq_c, Bool::trueObj());
2240 called = mainModuleAt(runtime_, "called");
2241 EXPECT_TRUE(isStrEqualsCStr(*called, "C"));
2242}
2243
2244TEST_F(InterpreterTest, CompareOpWithStrsRewritesOpcode) {
2245 HandleScope scope(thread_);
2246
2247 Object obj1(&scope, runtime_->newStrFromCStr("abc"));
2248 Object obj2(&scope, runtime_->newStrFromCStr("def"));
2249 Tuple consts(&scope, runtime_->newTupleWith2(obj1, obj2));
2250 const byte bytecode[] = {
2251 LOAD_CONST, 0,
2252 LOAD_CONST, 1,
2253 COMPARE_OP, static_cast<byte>(CompareOp::EQ),
2254 RETURN_VALUE, 0,
2255 };
2256 Code code(&scope, newCodeWithBytesConsts(bytecode, consts));
2257
2258 Object qualname(&scope, Str::empty());
2259 Module module(&scope, findMainModule(runtime_));
2260 Function function(
2261 &scope, runtime_->newFunctionWithCode(thread_, qualname, code, module));
2262
2263 // Update the opcode.
2264 ASSERT_EQ(Interpreter::call0(thread_, function), Bool::falseObj());
2265
2266 MutableBytes rewritten_bytecode(&scope, function.rewrittenBytecode());
2267 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten_bytecode, 2), COMPARE_EQ_STR);
2268
2269 // Updated opcode returns the same value.
2270 ASSERT_EQ(Interpreter::call0(thread_, function), Bool::falseObj());
2271}
2272
2273TEST_F(InterpreterTest, CompareOpWithNeOperatorWithStrsRewritesToCompareNeStr) {
2274 HandleScope scope(thread_);
2275
2276 Object obj1(&scope, runtime_->newStrFromCStr("abc"));
2277 Object obj2(&scope, runtime_->newStrFromCStr("def"));
2278 Tuple consts(&scope, runtime_->newTupleWith2(obj1, obj2));
2279 const byte bytecode[] = {
2280 LOAD_CONST, 0,
2281 LOAD_CONST, 1,
2282 COMPARE_OP, static_cast<byte>(CompareOp::NE),
2283 RETURN_VALUE, 0,
2284 };
2285 Code code(&scope, newCodeWithBytesConsts(bytecode, consts));
2286
2287 Object qualname(&scope, Str::empty());
2288 Module module(&scope, findMainModule(runtime_));
2289 Function function(
2290 &scope, runtime_->newFunctionWithCode(thread_, qualname, code, module));
2291
2292 // Update the opcode.
2293 EXPECT_EQ(Interpreter::call0(thread_, function), Bool::trueObj());
2294
2295 MutableBytes rewritten_bytecode(&scope, function.rewrittenBytecode());
2296 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten_bytecode, 2), COMPARE_NE_STR);
2297
2298 // Updated opcode returns the same value.
2299 EXPECT_EQ(Interpreter::call0(thread_, function), Bool::trueObj());
2300
2301 // Revert the opcode back to COMPARE_OP_MONOMIRPHIC in case a non-str argument
2302 // is observed by evaluating `str_obj` != `tuple_obj`.
2303 consts.atPut(0, runtime_->emptyTuple());
2304 EXPECT_EQ(Interpreter::call0(thread_, function), Bool::trueObj());
2305 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten_bytecode, 2),
2306 COMPARE_OP_MONOMORPHIC);
2307}
2308
2309TEST_F(InterpreterTest, CompareOpSmallIntsRewritesOpcode) {
2310 HandleScope scope(thread_);
2311
2312 word left = 7;
2313 word right = -13;
2314 Object obj1(&scope, runtime_->newInt(left));
2315 Object obj2(&scope, runtime_->newInt(right));
2316 Tuple consts(&scope, runtime_->newTupleWith2(obj1, obj2));
2317 const byte bytecode[] = {
2318 LOAD_CONST, 0,
2319 LOAD_CONST, 1,
2320 COMPARE_OP, static_cast<byte>(CompareOp::LT),
2321 RETURN_VALUE, 0,
2322 };
2323 Code code(&scope, newCodeWithBytesConsts(bytecode, consts));
2324
2325 Object qualname(&scope, Str::empty());
2326 Module module(&scope, findMainModule(runtime_));
2327 Function function(
2328 &scope, runtime_->newFunctionWithCode(thread_, qualname, code, module));
2329
2330 // Update the opcode.
2331 ASSERT_EQ(Interpreter::call0(thread_, function), Bool::falseObj());
2332
2333 MutableBytes rewritten_bytecode(&scope, function.rewrittenBytecode());
2334 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten_bytecode, 2), COMPARE_LT_SMALLINT);
2335
2336 // Updated opcode returns the same value.
2337 ASSERT_EQ(Interpreter::call0(thread_, function), Bool::falseObj());
2338}
2339
2340TEST_F(InterpreterTest, CompareOpWithSmallInts) {
2341 HandleScope scope(thread_);
2342 ASSERT_FALSE(runFromCStr(runtime_, R"(
2343def foo(a, b):
2344 return a == b
2345)")
2346 .isError());
2347 Function function(&scope, mainModuleAt(runtime_, "foo"));
2348 MutableBytes rewritten(&scope, function.rewrittenBytecode());
2349 ASSERT_EQ(rewrittenBytecodeOpAt(rewritten, 2), COMPARE_OP_ANAMORPHIC);
2350
2351 SmallInt left(&scope, SmallInt::fromWord(7));
2352 SmallInt right(&scope, SmallInt::fromWord(-13));
2353
2354 rewrittenBytecodeOpAtPut(rewritten, 2, COMPARE_EQ_SMALLINT);
2355 left = SmallInt::fromWord(7);
2356 right = SmallInt::fromWord(-13);
2357 // 7 == -13
2358 EXPECT_EQ(Interpreter::call2(thread_, function, left, right),
2359 Bool::falseObj());
2360 // 7 == 7
2361 left = SmallInt::fromWord(7);
2362 right = SmallInt::fromWord(7);
2363 EXPECT_EQ(Interpreter::call2(thread_, function, left, right),
2364 Bool::trueObj());
2365 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten, 2), COMPARE_EQ_SMALLINT);
2366
2367 rewrittenBytecodeOpAtPut(rewritten, 2, COMPARE_NE_SMALLINT);
2368 left = SmallInt::fromWord(7);
2369 right = SmallInt::fromWord(7);
2370 // 7 != 7
2371 EXPECT_EQ(Interpreter::call2(thread_, function, left, right),
2372 Bool::falseObj());
2373 left = SmallInt::fromWord(7);
2374 right = SmallInt::fromWord(-13);
2375 // 7 != -13
2376 EXPECT_EQ(Interpreter::call2(thread_, function, left, right),
2377 Bool::trueObj());
2378 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten, 2), COMPARE_NE_SMALLINT);
2379
2380 rewrittenBytecodeOpAtPut(rewritten, 2, COMPARE_GT_SMALLINT);
2381 left = SmallInt::fromWord(10);
2382 right = SmallInt::fromWord(10);
2383 // 10 > 10
2384 EXPECT_EQ(Interpreter::call2(thread_, function, left, right),
2385 Bool::falseObj());
2386 left = SmallInt::fromWord(10);
2387 right = SmallInt::fromWord(-10);
2388 // 10 > -10
2389 EXPECT_EQ(Interpreter::call2(thread_, function, left, right),
2390 Bool::trueObj());
2391 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten, 2), COMPARE_GT_SMALLINT);
2392
2393 rewrittenBytecodeOpAtPut(rewritten, 2, COMPARE_GE_SMALLINT);
2394 left = SmallInt::fromWord(-10);
2395 right = SmallInt::fromWord(10);
2396 // -10 >= 10
2397 EXPECT_EQ(Interpreter::call2(thread_, function, left, right),
2398 Bool::falseObj());
2399 left = SmallInt::fromWord(10);
2400 right = SmallInt::fromWord(10);
2401 // 10 >= 10
2402 EXPECT_EQ(Interpreter::call2(thread_, function, left, right),
2403 Bool::trueObj());
2404 left = SmallInt::fromWord(11);
2405 right = SmallInt::fromWord(10);
2406 // 11 > = 10
2407 EXPECT_EQ(Interpreter::call2(thread_, function, left, right),
2408 Bool::trueObj());
2409 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten, 2), COMPARE_GE_SMALLINT);
2410
2411 rewrittenBytecodeOpAtPut(rewritten, 2, COMPARE_LT_SMALLINT);
2412 left = SmallInt::fromWord(10);
2413 right = SmallInt::fromWord(-10);
2414 // 10 < -10
2415 EXPECT_EQ(Interpreter::call2(thread_, function, left, right),
2416 Bool::falseObj());
2417 left = SmallInt::fromWord(-10);
2418 right = SmallInt::fromWord(10);
2419 // -10 < 10
2420 EXPECT_EQ(Interpreter::call2(thread_, function, left, right),
2421 Bool::trueObj());
2422 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten, 2), COMPARE_LT_SMALLINT);
2423
2424 rewrittenBytecodeOpAtPut(rewritten, 2, COMPARE_LE_SMALLINT);
2425 left = SmallInt::fromWord(10);
2426 right = SmallInt::fromWord(-10);
2427 // 10 <= -10
2428 EXPECT_EQ(Interpreter::call2(thread_, function, left, right),
2429 Bool::falseObj());
2430 left = SmallInt::fromWord(10);
2431 right = SmallInt::fromWord(10);
2432 // 10 <= 10
2433 EXPECT_EQ(Interpreter::call2(thread_, function, left, right),
2434 Bool::trueObj());
2435 left = SmallInt::fromWord(9);
2436 right = SmallInt::fromWord(10);
2437 // 9 <= 10
2438 EXPECT_EQ(Interpreter::call2(thread_, function, left, right),
2439 Bool::trueObj());
2440 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten, 2), COMPARE_LE_SMALLINT);
2441}
2442
2443TEST_F(InterpreterTest, CompareOpWithSmallIntsRevertsBackToCompareOp) {
2444 HandleScope scope(thread_);
2445 ASSERT_FALSE(runFromCStr(runtime_, R"(
2446def foo(a, b):
2447 return a == b
2448)")
2449 .isError());
2450 Function function(&scope, mainModuleAt(runtime_, "foo"));
2451 MutableBytes rewritten(&scope, function.rewrittenBytecode());
2452 ASSERT_EQ(rewrittenBytecodeOpAt(rewritten, 2), COMPARE_OP_ANAMORPHIC);
2453
2454 LargeInt left(&scope, runtime_->newInt(SmallInt::kMaxValue + 1));
2455 LargeInt right(&scope, runtime_->newInt(SmallInt::kMaxValue + 1));
2456
2457 rewrittenBytecodeOpAtPut(rewritten, 2, COMPARE_EQ_SMALLINT);
2458 // LARGE_SMALL_INT == SMALL_INT
2459 EXPECT_EQ(Interpreter::call2(thread_, function, left, right),
2460 Bool::trueObj());
2461 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten, 2), COMPARE_OP_MONOMORPHIC);
2462}
2463
2464TEST_F(InterpreterTest, CompareOpSetMethodSetsMethod) {
2465 HandleScope scope(thread_);
2466 Object v0(&scope, runtime_->newInt(39));
2467 Object v1(&scope, runtime_->newInt(11));
2468 Object method(&scope, NoneType::object());
2469 BinaryOpFlags flags;
2470 EXPECT_EQ(Interpreter::compareOperationSetMethod(thread_, CompareOp::LT, v0,
2471 v1, &method, &flags),
2472 Bool::falseObj());
2473 EXPECT_TRUE(method.isFunction());
2474 EXPECT_EQ(flags, kBinaryOpNotImplementedRetry);
2475
2476 Object v2(&scope, runtime_->newInt(3));
2477 Object v3(&scope, runtime_->newInt(8));
2478 ASSERT_EQ(v0.layoutId(), v2.layoutId());
2479 ASSERT_EQ(v1.layoutId(), v3.layoutId());
2480 EXPECT_EQ(
2481 Interpreter::binaryOperationWithMethod(thread_, *method, flags, *v2, *v3),
2482 Bool::trueObj());
2483}
2484
2485TEST_F(InterpreterTest, CompareOpSetMethodSetsReverseMethod) {
2486 HandleScope scope(thread_);
2487 ASSERT_FALSE(runFromCStr(runtime_, R"(
2488class A:
2489 pass
2490
2491class B(A):
2492 def __ge__(self, other):
2493 return (self, other)
2494
2495a1 = A()
2496b1 = B()
2497a2 = A()
2498b2 = B()
2499)")
2500 .isError());
2501
2502 Object a1(&scope, mainModuleAt(runtime_, "a1"));
2503 Object b1(&scope, mainModuleAt(runtime_, "b1"));
2504 Object method(&scope, NoneType::object());
2505 BinaryOpFlags flags;
2506 Object result_obj(
2507 &scope, Interpreter::compareOperationSetMethod(thread_, CompareOp::LE, a1,
2508 b1, &method, &flags));
2509 EXPECT_TRUE(method.isFunction());
2510 EXPECT_EQ(flags, kBinaryOpReflected | kBinaryOpNotImplementedRetry);
2511 ASSERT_TRUE(result_obj.isTuple());
2512 Tuple result(&scope, *result_obj);
2513 ASSERT_EQ(result.length(), 2);
2514 EXPECT_EQ(result.at(0), b1);
2515 EXPECT_EQ(result.at(1), a1);
2516
2517 Object a2(&scope, mainModuleAt(runtime_, "a2"));
2518 Object b2(&scope, mainModuleAt(runtime_, "b2"));
2519 ASSERT_EQ(a1.layoutId(), a2.layoutId());
2520 ASSERT_EQ(b1.layoutId(), b2.layoutId());
2521 result_obj =
2522 Interpreter::binaryOperationWithMethod(thread_, *method, flags, *a2, *b2);
2523 ASSERT_TRUE(result_obj.isTuple());
2524 result = *result_obj;
2525 ASSERT_EQ(result.length(), 2);
2526 EXPECT_EQ(result.at(0), b2);
2527 EXPECT_EQ(result.at(1), a2);
2528}
2529
2530TEST_F(InterpreterTest,
2531 CompareOpSetMethodSetsReverseMethodNotImplementedRetry) {
2532 HandleScope scope(thread_);
2533 ASSERT_FALSE(runFromCStr(runtime_, R"(
2534class A:
2535 def __init__(self, x):
2536 self.x = x
2537 def __le__(self, other):
2538 raise UserWarning("should not be called")
2539class ASub(A):
2540 def __ge__(self, other):
2541 return (self, other)
2542v0 = A(3)
2543v1 = ASub(7)
2544v2 = A(8)
2545v3 = ASub(2)
2546)")
2547 .isError());
2548 Object v0(&scope, mainModuleAt(runtime_, "v0"));
2549 Object v1(&scope, mainModuleAt(runtime_, "v1"));
2550 Object v2(&scope, mainModuleAt(runtime_, "v2"));
2551 Object v3(&scope, mainModuleAt(runtime_, "v3"));
2552 Object method(&scope, NoneType::object());
2553 BinaryOpFlags flags;
2554 Object result_obj(
2555 &scope, Interpreter::compareOperationSetMethod(thread_, CompareOp::LE, v0,
2556 v1, &method, &flags));
2557 EXPECT_TRUE(method.isFunction());
2558 EXPECT_EQ(flags, kBinaryOpReflected | kBinaryOpNotImplementedRetry);
2559 ASSERT_TRUE(result_obj.isTuple());
2560 Tuple result(&scope, *result_obj);
2561 ASSERT_EQ(result.length(), 2);
2562 EXPECT_EQ(result.at(0), v1);
2563 EXPECT_EQ(result.at(1), v0);
2564
2565 ASSERT_EQ(v0.layoutId(), v2.layoutId());
2566 ASSERT_EQ(v1.layoutId(), v3.layoutId());
2567 result_obj =
2568 Interpreter::binaryOperationWithMethod(thread_, *method, flags, *v2, *v3);
2569 ASSERT_TRUE(result_obj.isTuple());
2570 result = *result_obj;
2571 ASSERT_EQ(result.length(), 2);
2572 EXPECT_EQ(result.at(0), v3);
2573 EXPECT_EQ(result.at(1), v2);
2574}
2575
2576TEST_F(InterpreterTest,
2577 CompareOpInvokesLeftMethodWhenReflectedMethodReturnsNotImplemented) {
2578 ASSERT_FALSE(runFromCStr(runtime_, R"(
2579trace = ""
2580class C:
2581 def __ge__(self, other):
2582 global trace
2583 trace += "C.__ge__,"
2584 return "C.__ge__"
2585
2586 def __le__(self, other):
2587 raise Exception("should not be called")
2588
2589class D(C):
2590 def __ge__(self, other):
2591 raise Exception("should not be called")
2592
2593 def __le__(self, other):
2594 global trace
2595 trace += "D.__le__,"
2596 return NotImplemented
2597
2598result = C() >= D()
2599)")
2600 .isError());
2601
2602 EXPECT_TRUE(isStrEqualsCStr(mainModuleAt(runtime_, "result"), "C.__ge__"));
2603 EXPECT_TRUE(
2604 isStrEqualsCStr(mainModuleAt(runtime_, "trace"), "D.__le__,C.__ge__,"));
2605}
2606
2607TEST_F(
2608 InterpreterTest,
2609 CompareOpCachedInsertsDependencyForBothOperandsTypesAppropriateAttributes) {
2610 HandleScope scope(thread_);
2611 EXPECT_FALSE(runFromCStr(runtime_, R"(
2612class A:
2613 def __ge__(self, other):
2614 return "from class A"
2615
2616class B:
2617 pass
2618
2619def cache_compare_op(a, b):
2620 return a >= b
2621
2622a = A()
2623b = B()
2624A__ge__ = A.__ge__
2625result = cache_compare_op(a, b)
2626)")
2627 .isError());
2628 ASSERT_TRUE(
2629 isStrEqualsCStr(mainModuleAt(runtime_, "result"), "from class A"));
2630
2631 Function cache_compare_op(&scope, mainModuleAt(runtime_, "cache_compare_op"));
2632 MutableTuple caches(&scope, cache_compare_op.caches());
2633 Object a_obj(&scope, mainModuleAt(runtime_, "a"));
2634 Object b_obj(&scope, mainModuleAt(runtime_, "b"));
2635 BinaryOpFlags flag;
2636 EXPECT_EQ(
2637 icLookupBinaryOp(*caches, 0, a_obj.layoutId(), b_obj.layoutId(), &flag),
2638 mainModuleAt(runtime_, "A__ge__"));
2639
2640 // Verify that A.__ge__ has the dependent.
2641 Type a_type(&scope, mainModuleAt(runtime_, "A"));
2642 Object left_op_name(&scope, runtime_->symbols()->at(ID(__ge__)));
2643 Object a_type_attr(&scope, typeValueCellAt(*a_type, *left_op_name));
2644 ASSERT_TRUE(a_type_attr.isValueCell());
2645 ASSERT_TRUE(ValueCell::cast(*a_type_attr).dependencyLink().isWeakLink());
2646 EXPECT_EQ(
2647 WeakLink::cast(ValueCell::cast(*a_type_attr).dependencyLink()).referent(),
2648 *cache_compare_op);
2649
2650 // Verify that B.__le__ has the dependent.
2651 Type b_type(&scope, mainModuleAt(runtime_, "B"));
2652 Object right_op_name(&scope, runtime_->symbols()->at(ID(__le__)));
2653 Object b_type_attr(&scope, typeValueCellAt(*b_type, *right_op_name));
2654 ASSERT_TRUE(b_type_attr.isValueCell());
2655 ASSERT_TRUE(ValueCell::cast(*b_type_attr).dependencyLink().isWeakLink());
2656 EXPECT_EQ(
2657 WeakLink::cast(ValueCell::cast(*b_type_attr).dependencyLink()).referent(),
2658 *cache_compare_op);
2659}
2660
2661TEST_F(InterpreterTest, DoStoreFastStoresValue) {
2662 HandleScope scope(thread_);
2663
2664 Object obj(&scope, SmallInt::fromWord(1111));
2665 Tuple consts(&scope, runtime_->newTupleWith1(obj));
2666 Tuple names(&scope, runtime_->emptyTuple());
2667 Locals locals;
2668 locals.varcount = 2;
2669 const byte bytecode[] = {LOAD_CONST, 0, 0, 0, STORE_FAST, 1, 0, 0,
2670 LOAD_FAST, 1, 0, 0, RETURN_VALUE, 0, 0, 0};
2671 Code code(&scope, newCodeWithBytesConstsNamesLocals(bytecode, consts, names,
2672 &locals));
2673
2674 EXPECT_TRUE(isIntEqualsWord(runCodeNoBytecodeRewriting(code), 1111));
2675}
2676
2677TEST_F(InterpreterTest, DoLoadFastReverseLoadsValue) {
2678 HandleScope scope(thread_);
2679
2680 Object obj1(&scope, SmallInt::fromWord(1));
2681 Object obj2(&scope, SmallInt::fromWord(22));
2682 Object obj3(&scope, SmallInt::fromWord(333));
2683 Object obj4(&scope, SmallInt::fromWord(4444));
2684 Tuple consts(&scope, runtime_->newTupleWith4(obj1, obj2, obj3, obj4));
2685 Tuple names(&scope, runtime_->emptyTuple());
2686 Locals locals;
2687 locals.varcount = 4;
2688 const byte bytecode[] = {
2689 LOAD_CONST, 0, 0, 0, STORE_FAST, 0, 0, 0,
2690 LOAD_CONST, 1, 0, 0, STORE_FAST, 1, 0, 0,
2691 LOAD_CONST, 2, 0, 0, STORE_FAST, 2, 0, 0,
2692 LOAD_CONST, 3, 0, 0, STORE_FAST, 3, 0, 0,
2693 LOAD_FAST_REVERSE, 3, 0, 0, // 1
2694 LOAD_FAST_REVERSE, 2, 0, 0, // 22
2695 LOAD_FAST_REVERSE, 0, 0, 0, // 4444
2696 LOAD_FAST_REVERSE, 1, 0, 0, // 333
2697 BUILD_TUPLE, 4, 0, 0, RETURN_VALUE, 0, 0, 0,
2698 };
2699 Code code(&scope, newCodeWithBytesConstsNamesLocals(bytecode, consts, names,
2700 &locals));
2701
2702 Object result_obj(&scope, runCodeNoBytecodeRewriting(code));
2703 ASSERT_TRUE(result_obj.isTuple());
2704 Tuple result(&scope, *result_obj);
2705 ASSERT_EQ(result.length(), 4);
2706 EXPECT_TRUE(isIntEqualsWord(result.at(0), 1));
2707 EXPECT_TRUE(isIntEqualsWord(result.at(1), 22));
2708 EXPECT_TRUE(isIntEqualsWord(result.at(2), 4444));
2709 EXPECT_TRUE(isIntEqualsWord(result.at(3), 333));
2710}
2711
2712TEST_F(InterpreterTest,
2713 DoLoadFastReverseFromUninitializedLocalRaisesUnboundLocalError) {
2714 HandleScope scope(thread_);
2715
2716 Object obj(&scope, SmallInt::fromWord(42));
2717 Tuple consts(&scope, runtime_->newTupleWith1(obj));
2718 Tuple names(&scope, runtime_->emptyTuple());
2719 Locals locals;
2720 locals.varcount = 3;
2721 const byte bytecode[] = {
2722 LOAD_CONST, 0, 0, 0, STORE_FAST, 0, 0, 0, LOAD_CONST, 0, 0, 0,
2723 STORE_FAST, 2, 0, 0, DELETE_FAST, 2, 0, 0, LOAD_FAST_REVERSE, 0, 0, 0,
2724 RETURN_VALUE, 0, 0, 0,
2725 };
2726 Code code(&scope, newCodeWithBytesConstsNamesLocals(bytecode, consts, names,
2727 &locals));
2728
2729 EXPECT_TRUE(raisedWithStr(
2730 runCodeNoBytecodeRewriting(code), LayoutId::kUnboundLocalError,
2731 "local variable 'var2' referenced before assignment"));
2732}
2733
2734TEST_F(InterpreterTest, DoStoreFastReverseStoresValue) {
2735 HandleScope scope(thread_);
2736
2737 Object obj1(&scope, SmallInt::fromWord(1));
2738 Object obj2(&scope, SmallInt::fromWord(22));
2739 Object obj3(&scope, SmallInt::fromWord(333));
2740 Object obj4(&scope, SmallInt::fromWord(4444));
2741 Tuple consts(&scope, runtime_->newTupleWith4(obj1, obj2, obj3, obj4));
2742 Tuple names(&scope, runtime_->emptyTuple());
2743 Locals locals;
2744 locals.varcount = 4;
2745 const byte bytecode[] = {
2746 LOAD_CONST, 0, 0, 0, STORE_FAST_REVERSE, 0, 0, 0,
2747 LOAD_CONST, 1, 0, 0, STORE_FAST_REVERSE, 1, 0, 0,
2748 LOAD_CONST, 2, 0, 0, STORE_FAST_REVERSE, 3, 0, 0,
2749 LOAD_CONST, 3, 0, 0, STORE_FAST_REVERSE, 2, 0, 0,
2750 LOAD_FAST, 0, 0, 0, // 333
2751 LOAD_FAST, 1, 0, 0, // 4444
2752 LOAD_FAST, 2, 0, 0, // 22
2753 LOAD_FAST, 3, 0, 0, // 1
2754 BUILD_TUPLE, 4, 0, 0, RETURN_VALUE, 0, 0, 0,
2755 };
2756 Code code(&scope, newCodeWithBytesConstsNamesLocals(bytecode, consts, names,
2757 &locals));
2758
2759 Object result_obj(&scope, runCodeNoBytecodeRewriting(code));
2760 ASSERT_TRUE(result_obj.isTuple());
2761 Tuple result(&scope, *result_obj);
2762 ASSERT_EQ(result.length(), 4);
2763 EXPECT_TRUE(isIntEqualsWord(result.at(0), 333));
2764 EXPECT_TRUE(isIntEqualsWord(result.at(1), 4444));
2765 EXPECT_TRUE(isIntEqualsWord(result.at(2), 22));
2766 EXPECT_TRUE(isIntEqualsWord(result.at(3), 1));
2767}
2768
2769TEST_F(InterpreterTest, DoStoreSubscrWithNoSetitemRaisesTypeError) {
2770 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, "1[5] = 'foo'"),
2771 LayoutId::kTypeError,
2772 "'int' object does not support item assignment"));
2773}
2774
2775TEST_F(InterpreterTest, DoStoreSubscrWithDescriptorPropagatesException) {
2776 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, R"(
2777class A:
2778 def __get__(self, *args):
2779 raise RuntimeError("foo")
2780
2781class B:
2782 __setitem__ = A()
2783
2784b = B()
2785b[5] = 'foo'
2786)"),
2787 LayoutId::kRuntimeError, "foo"));
2788}
2789
2790TEST_F(InterpreterTest, DoDeleteSubscrWithNoDelitemRaisesTypeError) {
2791 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, "del 1[5]"),
2792 LayoutId::kTypeError,
2793 "'int' object does not support item deletion"));
2794}
2795
2796TEST_F(InterpreterTest, DoDeleteSubscrWithDescriptorPropagatesException) {
2797 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, R"(
2798class A:
2799 def __get__(self, *args):
2800 raise RuntimeError("foo")
2801
2802class B:
2803 __delitem__ = A()
2804
2805b = B()
2806del b[5]
2807)"),
2808 LayoutId::kRuntimeError, "foo"));
2809}
2810
2811TEST_F(InterpreterTest, DoDeleteSubscrDoesntPushToStack) {
2812 HandleScope scope(thread_);
2813
2814 List list(&scope, runtime_->newList());
2815 Int one(&scope, runtime_->newInt(1));
2816 runtime_->listEnsureCapacity(thread_, list, 1);
2817 list.setNumItems(1);
2818 list.atPut(0, *one);
2819 Object obj1(&scope, SmallInt::fromWord(42));
2820 Object obj3(&scope, SmallInt::fromWord(0));
2821 Tuple consts(&scope, runtime_->newTupleWith3(obj1, list, obj3));
2822 const byte bytecode[] = {
2823 LOAD_CONST, 0, LOAD_CONST, 1, LOAD_CONST, 2,
2824 DELETE_SUBSCR, 0, RETURN_VALUE, 0,
2825 };
2826 Code code(&scope, newCodeWithBytesConsts(bytecode, consts));
2827
2828 Object result_obj(&scope, runCode(code));
2829 ASSERT_TRUE(result_obj.isInt());
2830 Int result(&scope, *result_obj);
2831 EXPECT_EQ(result.asWord(), 42);
2832 EXPECT_EQ(list.numItems(), 0);
2833}
2834
2835TEST_F(InterpreterTest, GetIterWithSequenceReturnsIterator) {
2836 ASSERT_FALSE(runFromCStr(runtime_, R"(
2837class Sequence:
2838 def __getitem__(s, i):
2839 return ("foo", "bar")[i]
2840
2841seq = Sequence()
2842)")
2843 .isError());
2844 HandleScope scope(thread_);
2845
2846 Object obj(&scope, mainModuleAt(runtime_, "seq"));
2847 Tuple consts(&scope, runtime_->newTupleWith1(obj));
2848 const byte bytecode[] = {
2849 LOAD_CONST, 0, GET_ITER, 0, RETURN_VALUE, 0,
2850 };
2851 Code code(&scope, newCodeWithBytesConsts(bytecode, consts));
2852
2853 Object result_obj(&scope, runCode(code));
2854 EXPECT_TRUE(runtime_->isIterator(thread_, result_obj));
2855 Type result_type(&scope, runtime_->typeOf(*result_obj));
2856 EXPECT_TRUE(isStrEqualsCStr(result_type.name(), "iterator"));
2857}
2858
2859TEST_F(InterpreterTest,
2860 GetIterWithRaisingDescriptorDunderIterPropagatesException) {
2861 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, R"(
2862class Desc:
2863 def __get__(self, obj, type):
2864 raise UserWarning("foo")
2865
2866class C:
2867 __iter__ = Desc()
2868
2869it = C()
2870result = [x for x in it]
2871)"),
2872 LayoutId::kTypeError,
2873 "'C' object is not iterable"));
2874}
2875
2876TEST_F(InterpreterTest, SequenceContains) {
2877 HandleScope scope(thread_);
2878
2879 ASSERT_FALSE(runFromCStr(runtime_, R"(
2880a = {1, 2}
2881
2882b = 1
2883c = 3
2884)")
2885 .isError());
2886
2887 Object container(&scope, mainModuleAt(runtime_, "a"));
2888 Object b(&scope, mainModuleAt(runtime_, "b"));
2889 Object c(&scope, mainModuleAt(runtime_, "c"));
2890 Object contains_true(&scope,
2891 Interpreter::sequenceContains(thread_, b, container));
2892 Object contains_false(&scope,
2893 Interpreter::sequenceContains(thread_, c, container));
2894 EXPECT_EQ(contains_true, Bool::trueObj());
2895 EXPECT_EQ(contains_false, Bool::falseObj());
2896}
2897
2898TEST_F(InterpreterTest, SequenceIterSearchWithNoDunderIterRaisesTypeError) {
2899 HandleScope scope(thread_);
2900 ASSERT_FALSE(runFromCStr(runtime_, R"(
2901class C: pass
2902container = C()
2903)")
2904 .isError());
2905 Object container(&scope, mainModuleAt(runtime_, "container"));
2906 Object val(&scope, NoneType::object());
2907 Object result(&scope,
2908 Interpreter::sequenceIterSearch(thread_, val, container));
2909 EXPECT_TRUE(raised(*result, LayoutId::kTypeError));
2910}
2911
2912TEST_F(InterpreterTest,
2913 SequenceIterSearchWithNonCallableDunderIterRaisesTypeError) {
2914 HandleScope scope(thread_);
2915 ASSERT_FALSE(runFromCStr(runtime_, R"(
2916class C:
2917 __iter__ = None
2918container = C()
2919)")
2920 .isError());
2921 Object container(&scope, mainModuleAt(runtime_, "container"));
2922 Object val(&scope, NoneType::object());
2923 Object result(&scope,
2924 Interpreter::sequenceIterSearch(thread_, val, container));
2925 EXPECT_TRUE(raised(*result, LayoutId::kTypeError));
2926}
2927
2928TEST_F(InterpreterTest, SequenceIterSearchWithNoDunderNextRaisesTypeError) {
2929 HandleScope scope(thread_);
2930 ASSERT_FALSE(runFromCStr(runtime_, R"(
2931class D: pass
2932class C:
2933 def __iter__(self):
2934 return D()
2935container = C()
2936)")
2937 .isError());
2938 Object container(&scope, mainModuleAt(runtime_, "container"));
2939 Object val(&scope, NoneType::object());
2940 Object result(&scope,
2941 Interpreter::sequenceIterSearch(thread_, val, container));
2942 EXPECT_TRUE(raised(*result, LayoutId::kTypeError));
2943}
2944
2945TEST_F(InterpreterTest,
2946 SequenceIterSearchWithNonCallableDunderNextRaisesTypeError) {
2947 HandleScope scope(thread_);
2948 ASSERT_FALSE(runFromCStr(runtime_, R"(
2949class D:
2950 __next__ = None
2951class C:
2952 def __iter__(self):
2953 return D()
2954container = C()
2955)")
2956 .isError());
2957 Object container(&scope, mainModuleAt(runtime_, "container"));
2958 Object val(&scope, NoneType::object());
2959 Object result(&scope,
2960 Interpreter::sequenceIterSearch(thread_, val, container));
2961 EXPECT_TRUE(raised(*result, LayoutId::kTypeError));
2962}
2963
2964TEST_F(InterpreterTest, SequenceIterSearchWithListReturnsTrue) {
2965 HandleScope scope(thread_);
2966 List container(&scope, listFromRange(1, 3));
2967 Object val(&scope, SmallInt::fromWord(2));
2968 Object result(&scope,
2969 Interpreter::sequenceIterSearch(thread_, val, container));
2970 ASSERT_FALSE(result.isError());
2971 EXPECT_EQ(result, Bool::trueObj());
2972}
2973
2974TEST_F(InterpreterTest, SequenceIterSearchWithListReturnsFalse) {
2975 HandleScope scope(thread_);
2976 Object container(&scope, listFromRange(1, 3));
2977 Object val(&scope, SmallInt::fromWord(5));
2978 Object result(&scope,
2979 Interpreter::sequenceIterSearch(thread_, val, container));
2980 ASSERT_FALSE(result.isError());
2981 EXPECT_EQ(result, Bool::falseObj());
2982}
2983
2984TEST_F(InterpreterTest, SequenceIterSearchWithSequenceSearchesIterator) {
2985 HandleScope scope(thread_);
2986 ASSERT_FALSE(runFromCStr(runtime_, R"(
2987class Seq:
2988 def __getitem__(s, i):
2989 return ("foo", "bar", 42)[i]
2990
2991seq_iter = Seq()
2992)")
2993 .isError());
2994 Object seq_iter(&scope, mainModuleAt(runtime_, "seq_iter"));
2995 Object obj_in_seq(&scope, SmallInt::fromWord(42));
2996 Object contains_true(
2997 &scope, Interpreter::sequenceIterSearch(thread_, obj_in_seq, seq_iter));
2998 EXPECT_EQ(contains_true, Bool::trueObj());
2999 Object obj_not_in_seq(&scope, NoneType::object());
3000 Object contains_false(&scope, Interpreter::sequenceIterSearch(
3001 thread_, obj_not_in_seq, seq_iter));
3002 EXPECT_EQ(contains_false, Bool::falseObj());
3003}
3004
3005TEST_F(InterpreterTest,
3006 SequenceIterSearchWithIterThatRaisesPropagatesException) {
3007 HandleScope scope(thread_);
3008 ASSERT_FALSE(runFromCStr(runtime_, R"(
3009class C:
3010 def __iter__(self):
3011 raise ZeroDivisionError("boom")
3012container = C()
3013)")
3014 .isError());
3015 Object container(&scope, mainModuleAt(runtime_, "container"));
3016 Object val(&scope, SmallInt::fromWord(5));
3017 Object result(&scope,
3018 Interpreter::sequenceIterSearch(thread_, val, container));
3019 EXPECT_TRUE(raised(*result, LayoutId::kZeroDivisionError));
3020}
3021
3022TEST_F(InterpreterTest, ContextManagerCallEnterExit) {
3023 const char* src = R"(
3024a = 1
3025class Foo:
3026 def __enter__(self):
3027 global a
3028 a = 2
3029
3030 def __exit__(self, e, t, b):
3031 global a
3032 a = 3
3033
3034b = 0
3035with Foo():
3036 b = a
3037
3038)";
3039 HandleScope scope(thread_);
3040 ASSERT_FALSE(runFromCStr(runtime_, src).isError());
3041 Object a(&scope, mainModuleAt(runtime_, "a"));
3042 EXPECT_TRUE(isIntEqualsWord(*a, 3));
3043 Object b(&scope, mainModuleAt(runtime_, "b"));
3044 EXPECT_TRUE(isIntEqualsWord(*b, 2));
3045}
3046
3047TEST_F(InterpreterTest, ContextManagerCallEnterExitOfNotFunctionType) {
3048 const char* src = R"(
3049class MyFunction:
3050 def __init__(self, fn):
3051 self.fn = fn
3052
3053 def __get__(self, instance, instance_type):
3054 return self.fn
3055
3056a = 1
3057
3058def my_enter():
3059 global a
3060 a = 2
3061
3062def my_exit(e, t, b):
3063 global a
3064 a = 3
3065
3066class Foo:
3067 __enter__ = MyFunction(my_enter)
3068 __exit__ = MyFunction(my_exit)
3069
3070b = 0
3071with Foo():
3072 b = a
3073)";
3074 HandleScope scope(thread_);
3075 ASSERT_FALSE(runFromCStr(runtime_, src).isError());
3076 Object a(&scope, mainModuleAt(runtime_, "a"));
3077 EXPECT_TRUE(isIntEqualsWord(*a, 3));
3078 Object b(&scope, mainModuleAt(runtime_, "b"));
3079 EXPECT_TRUE(isIntEqualsWord(*b, 2));
3080}
3081
3082TEST_F(InterpreterTest, StackCleanupAfterCallFunction) {
3083 // Build the following function
3084 // def foo(arg0=1, arg1=2):
3085 // return 42
3086 //
3087 // Then call as foo(1) and verify that the stack is cleaned up after
3088 // default argument expansion
3089 //
3090 HandleScope scope(thread_);
3091
3092 Object obj(&scope, SmallInt::fromWord(42));
3093 Tuple consts(&scope, runtime_->newTupleWith1(obj));
3094 Tuple names(&scope, runtime_->emptyTuple());
3095 Locals locals;
3096 locals.argcount = 2;
3097 const byte bytecode[] = {LOAD_CONST, 0, RETURN_VALUE, 0};
3098 Code code(&scope, newCodeWithBytesConstsNamesLocals(bytecode, consts, names,
3099 &locals));
3100
3101 Object qualname(&scope, Str::empty());
3102 Module module(&scope, findMainModule(runtime_));
3103 Function callee(
3104 &scope, runtime_->newFunctionWithCode(thread_, qualname, code, module));
3105
3106 Object obj1(&scope, SmallInt::fromWord(1));
3107 Object obj2(&scope, SmallInt::fromWord(2));
3108 Tuple defaults(&scope, runtime_->newTupleWith2(obj1, obj2));
3109 callee.setDefaults(*defaults);
3110
3111 // Save starting value stack top
3112 RawObject* value_stack_start = thread_->stackPointer();
3113
3114 // Push function pointer and argument
3115 thread_->stackPush(*callee);
3116 thread_->stackPush(SmallInt::fromWord(1));
3117
3118 // Make sure we got the right result and stack is back where it should be
3119 EXPECT_TRUE(isIntEqualsWord(Interpreter::call(thread_, 1), 42));
3120 EXPECT_EQ(value_stack_start, thread_->stackPointer());
3121}
3122
3123TEST_F(InterpreterTest, StackCleanupAfterCallExFunction) {
3124 // Build the following function
3125 // def foo(arg0=1, arg1=2):
3126 // return 42
3127 //
3128 // Then call as "f=(2,); foo(*f)" and verify that the stack is cleaned up
3129 // after ex and default argument expansion
3130 //
3131 HandleScope scope(thread_);
3132
3133 Object obj(&scope, SmallInt::fromWord(42));
3134 Tuple consts(&scope, runtime_->newTupleWith1(obj));
3135 Tuple names(&scope, runtime_->emptyTuple());
3136 Locals locals;
3137 locals.argcount = 2;
3138 const byte bytecode[] = {LOAD_CONST, 0, RETURN_VALUE, 0};
3139 Code code(&scope, newCodeWithBytesConstsNamesLocals(bytecode, consts, names,
3140 &locals));
3141
3142 Object qualname(&scope, Str::empty());
3143 Module module(&scope, findMainModule(runtime_));
3144 Function callee(
3145 &scope, runtime_->newFunctionWithCode(thread_, qualname, code, module));
3146
3147 Object obj1(&scope, SmallInt::fromWord(1));
3148 Object obj2(&scope, SmallInt::fromWord(2));
3149 Tuple defaults(&scope, runtime_->newTupleWith2(obj1, obj2));
3150 callee.setDefaults(*defaults);
3151
3152 // Save starting value stack top
3153 RawObject* value_stack_start = thread_->stackPointer();
3154
3155 // Push function pointer and argument
3156 Object arg(&scope, SmallInt::fromWord(2));
3157 Tuple ex(&scope, runtime_->newTupleWith1(arg));
3158 thread_->stackPush(*callee);
3159 thread_->stackPush(*ex);
3160
3161 // Make sure we got the right result and stack is back where it should be
3162 EXPECT_TRUE(isIntEqualsWord(Interpreter::callEx(thread_, 0), 42));
3163 EXPECT_EQ(value_stack_start, thread_->stackPointer());
3164}
3165
3166TEST_F(InterpreterTest, StackCleanupAfterCallKwFunction) {
3167 HandleScope scope(thread_);
3168
3169 // Build the following function
3170 // def foo(arg0=1, arg1=2):
3171 // return 42
3172 //
3173 // Then call as "foo(b=4)" and verify that the stack is cleaned up after
3174 // ex and default argument expansion
3175 //
3176
3177 Object obj(&scope, SmallInt::fromWord(42));
3178 Tuple consts(&scope, runtime_->newTupleWith1(obj));
3179 Tuple names(&scope, runtime_->emptyTuple());
3180 Locals locals;
3181 locals.argcount = 2;
3182 const byte bytecode[] = {LOAD_CONST, 0, RETURN_VALUE, 0};
3183 Code code(&scope, newCodeWithBytesConstsNamesLocals(bytecode, consts, names,
3184 &locals));
3185
3186 Object qualname(&scope, Str::empty());
3187 Module module(&scope, findMainModule(runtime_));
3188 Function callee(
3189 &scope, runtime_->newFunctionWithCode(thread_, qualname, code, module));
3190 Object default1(&scope, SmallInt::fromWord(1));
3191 Object default2(&scope, SmallInt::fromWord(2));
3192 Tuple defaults(&scope, runtime_->newTupleWith2(default1, default2));
3193 callee.setDefaults(*defaults);
3194
3195 // Save starting value stack top
3196 RawObject* value_stack_start = thread_->stackPointer();
3197
3198 // Push function pointer and argument
3199 Object arg(&scope, Runtime::internStrFromCStr(thread_, "arg1"));
3200 Tuple arg_names(&scope, runtime_->newTupleWith1(arg));
3201 thread_->stackPush(*callee);
3202 thread_->stackPush(SmallInt::fromWord(4));
3203 thread_->stackPush(*arg_names);
3204
3205 // Make sure we got the right result and stack is back where it should be
3206 EXPECT_TRUE(isIntEqualsWord(Interpreter::callKw(thread_, 1), 42));
3207 EXPECT_EQ(value_stack_start, thread_->stackPointer());
3208}
3209
3210TEST_F(InterpreterTest, LookupMethodInvokesDescriptor) {
3211 HandleScope scope(thread_);
3212 ASSERT_FALSE(runFromCStr(runtime_, R"(
3213def f(): pass
3214
3215class D:
3216 def __get__(self, obj, owner):
3217 return f
3218
3219class C:
3220 __call__ = D()
3221
3222c = C()
3223 )")
3224 .isError());
3225 Object c(&scope, mainModuleAt(runtime_, "c"));
3226 Object f(&scope, mainModuleAt(runtime_, "f"));
3227 Object method(&scope, Interpreter::lookupMethod(thread_, c, ID(__call__)));
3228 EXPECT_EQ(*f, *method);
3229}
3230
3231TEST_F(InterpreterTest, PrepareCallableCallUnpacksBoundMethod) {
3232 HandleScope scope(thread_);
3233 ASSERT_FALSE(runFromCStr(runtime_, R"(
3234class C:
3235 def foo():
3236 pass
3237meth = C().foo
3238)")
3239 .isError());
3240 Object meth_obj(&scope, mainModuleAt(runtime_, "meth"));
3241 ASSERT_TRUE(meth_obj.isBoundMethod());
3242
3243 thread_->stackPush(*meth_obj);
3244 thread_->stackPush(SmallInt::fromWord(1234));
3245 ASSERT_EQ(thread_->valueStackSize(), 2);
3246 word nargs = 1;
3247 Interpreter::PrepareCallableResult result =
3248 Interpreter::prepareCallableCall(thread_, nargs, nargs);
3249 ASSERT_TRUE(result.function.isFunction());
3250 ASSERT_EQ(result.nargs, 2);
3251 ASSERT_EQ(thread_->valueStackSize(), 3);
3252 EXPECT_TRUE(isIntEqualsWord(thread_->stackPeek(0), 1234));
3253 EXPECT_TRUE(thread_->stackPeek(1).isInstance());
3254 EXPECT_EQ(thread_->stackPeek(2), result.function);
3255}
3256
3257TEST_F(InterpreterTest, CallExWithListSubclassCallsDunderIter) {
3258 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, R"(
3259class C(list):
3260 def __iter__(self):
3261 raise UserWarning('foo')
3262
3263def f(a, b, c):
3264 return (a, b, c)
3265
3266c = C([1, 2, 3])
3267f(*c)
3268)"),
3269 LayoutId::kUserWarning, "foo"));
3270}
3271
3272static RawObject ALIGN_16 setPendingSignal(Thread* thread, Arguments) {
3273 thread->runtime()->setPendingSignal(thread, SIGINT);
3274 return NoneType::object();
3275}
3276
3277TEST_F(InterpreterTest, CallFunctionWithInterruptSetReturnsErrorException) {
3278 addBuiltin("set_pending_signal", setPendingSignal, {nullptr, 0}, 0);
3279 EXPECT_FALSE(runFromCStr(runtime_, R"(
3280executed = False
3281def foo():
3282 global executed
3283 executed = True
3284
3285def bar():
3286 set_pending_signal()
3287 foo()
3288)")
3289 .isError());
3290 HandleScope scope(thread_);
3291 Object bar(&scope, mainModuleAt(runtime_, "bar"));
3292 thread_->stackPush(*bar);
3293 EXPECT_TRUE(
3294 raised(Interpreter::call0(thread_, bar), LayoutId::kKeyboardInterrupt));
3295 Object executed(&scope, mainModuleAt(runtime_, "executed"));
3296 EXPECT_EQ(executed, Bool::falseObj());
3297}
3298
3299static RawObject ALIGN_16 abortBuiltin(Thread*, Arguments) { abort(); }
3300
3301TEST_F(InterpreterTest, CallFunctionWithBuiltinRaisesRecursionError) {
3302 addBuiltin("abort", abortBuiltin, {nullptr, 0}, 0);
3303 EXPECT_FALSE(runFromCStr(runtime_, R"(
3304x = None
3305def foo():
3306 global x
3307 x = 1
3308 abort()
3309 x = 2
3310)")
3311 .isError());
3312
3313 HandleScope scope(thread_);
3314 Object foo(&scope, mainModuleAt(runtime_, "foo"));
3315
3316 // Fill stack until we can fit exactly 1 function call.
3317 RawObject* saved_sp = thread_->stackPointer();
3318 while (!thread_->wouldStackOverflow(Frame::kSize * 2)) {
3319 thread_->stackPush(NoneType::object());
3320 }
3321 EXPECT_TRUE(
3322 raised(Interpreter::call0(thread_, foo), LayoutId::kRecursionError));
3323 Object x(&scope, mainModuleAt(runtime_, "x"));
3324 EXPECT_TRUE(isIntEqualsWord(*x, 1));
3325 thread_->setStackPointer(saved_sp);
3326}
3327
3328TEST_F(InterpreterTest, CallingUncallableRaisesTypeError) {
3329 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, "(1)()"),
3330 LayoutId::kTypeError,
3331 "'int' object is not callable"));
3332}
3333
3334TEST_F(InterpreterTest, CallingUncallableDunderCallRaisesTypeError) {
3335 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, R"(
3336class C:
3337 __call__ = 1
3338
3339c = C()
3340c()
3341 )"),
3342 LayoutId::kTypeError,
3343 "'int' object is not callable"));
3344}
3345
3346TEST_F(InterpreterTest,
3347 CallingBoundMethodWithNonFunctionDunderFuncCallsDunderFunc) {
3348 EXPECT_FALSE(runFromCStr(runtime_, R"(
3349# from types import MethodType
3350MethodType = method
3351
3352class C:
3353 def __call__(self, arg):
3354 return self, arg
3355
3356func = C()
3357instance = object()
3358bound_method = MethodType(func, instance)
3359result = bound_method()
3360 )")
3361 .isError());
3362 CHECK(!thread_->hasPendingException(), "no errors pls");
3363 HandleScope scope(thread_);
3364 Object result_obj(&scope, mainModuleAt(runtime_, "result"));
3365 ASSERT_TRUE(result_obj.isTuple());
3366 Tuple result(&scope, *result_obj);
3367 ASSERT_EQ(result.length(), 2);
3368 Object func(&scope, mainModuleAt(runtime_, "func"));
3369 EXPECT_EQ(result.at(0), *func);
3370 Object instance(&scope, mainModuleAt(runtime_, "instance"));
3371 EXPECT_EQ(result.at(1), *instance);
3372}
3373
3374TEST_F(InterpreterTest, CallingNonDescriptorDunderCallRaisesTypeError) {
3375 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, R"(
3376class D: pass
3377
3378class C:
3379 __call__ = D()
3380
3381c = C()
3382c()
3383 )"),
3384 LayoutId::kTypeError,
3385 "'D' object is not callable"));
3386}
3387
3388TEST_F(InterpreterTest, CallDescriptorReturningUncallableRaisesTypeError) {
3389 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, R"(
3390class D:
3391 def __get__(self, instance, owner):
3392 return 1
3393
3394class C:
3395 __call__ = D()
3396
3397c = C()
3398c()
3399 )"),
3400 LayoutId::kTypeError,
3401 "'int' object is not callable"));
3402}
3403
3404TEST_F(InterpreterTest, LookupMethodLoopsOnCallBoundToDescriptor) {
3405 HandleScope scope(thread_);
3406 ASSERT_FALSE(runFromCStr(runtime_, R"(
3407def f(args):
3408 return args
3409
3410class C0:
3411 def __get__(self, obj, owner):
3412 return f
3413
3414class C1:
3415 __call__ = C0()
3416
3417class C2:
3418 def __get__(self, obj, owner):
3419 return C1()
3420
3421class C3:
3422 __call__ = C2()
3423
3424c = C3()
3425result = c(42)
3426 )")
3427 .isError());
3428 Object result(&scope, mainModuleAt(runtime_, "result"));
3429 EXPECT_EQ(*result, SmallInt::fromWord(42));
3430}
3431
3432TEST_F(InterpreterTest, DunderIterReturnsNonIterable) {
3433 const char* src = R"(
3434class Foo:
3435 def __iter__(self):
3436 return 1
3437a, b = Foo()
3438)";
3439 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, src), LayoutId::kTypeError,
3440 "iter() returned non-iterator of type 'int'"));
3441}
3442
3443TEST_F(InterpreterTest, UnpackSequence) {
3444 HandleScope scope(thread_);
3445 ASSERT_FALSE(runFromCStr(runtime_, R"(
3446l = [1, 2, 3]
3447a, b, c = l
3448)")
3449 .isError());
3450 Object a(&scope, mainModuleAt(runtime_, "a"));
3451 Object b(&scope, mainModuleAt(runtime_, "b"));
3452 Object c(&scope, mainModuleAt(runtime_, "c"));
3453 EXPECT_TRUE(isIntEqualsWord(*a, 1));
3454 EXPECT_TRUE(isIntEqualsWord(*b, 2));
3455 EXPECT_TRUE(isIntEqualsWord(*c, 3));
3456}
3457
3458TEST_F(InterpreterTest, UnpackSequenceWithSeqIterator) {
3459 HandleScope scope(thread_);
3460 ASSERT_FALSE(runFromCStr(runtime_, R"(
3461class Seq:
3462 def __getitem__(s, i):
3463 return ("foo", "bar", 42)[i]
3464a, b, c = Seq()
3465)")
3466 .isError());
3467 Object a(&scope, mainModuleAt(runtime_, "a"));
3468 Object b(&scope, mainModuleAt(runtime_, "b"));
3469 Object c(&scope, mainModuleAt(runtime_, "c"));
3470 EXPECT_TRUE(isStrEqualsCStr(*a, "foo"));
3471 EXPECT_TRUE(isStrEqualsCStr(*b, "bar"));
3472 EXPECT_TRUE(isIntEqualsWord(*c, 42));
3473}
3474
3475TEST_F(InterpreterTest, UnpackSequenceTooFewObjects) {
3476 const char* src = R"(
3477l = [1, 2]
3478a, b, c = l
3479)";
3480 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, src), LayoutId::kValueError,
3481 "not enough values to unpack"));
3482}
3483
3484TEST_F(InterpreterTest, UnpackSequenceTooManyObjects) {
3485 const char* src = R"(
3486l = [1, 2, 3, 4]
3487a, b, c = l
3488)";
3489 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, src), LayoutId::kValueError,
3490 "too many values to unpack"));
3491}
3492
3493TEST_F(InterpreterTest, UnpackTuple) {
3494 HandleScope scope(thread_);
3495 ASSERT_FALSE(runFromCStr(runtime_, R"(
3496l = (1, 2, 3)
3497a, b, c = l
3498)")
3499 .isError());
3500 Object a(&scope, mainModuleAt(runtime_, "a"));
3501 Object b(&scope, mainModuleAt(runtime_, "b"));
3502 Object c(&scope, mainModuleAt(runtime_, "c"));
3503 EXPECT_TRUE(isIntEqualsWord(*a, 1));
3504 EXPECT_TRUE(isIntEqualsWord(*b, 2));
3505 EXPECT_TRUE(isIntEqualsWord(*c, 3));
3506}
3507
3508TEST_F(InterpreterTest, UnpackTupleTooFewObjects) {
3509 const char* src = R"(
3510l = (1, 2)
3511a, b, c = l
3512)";
3513 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, src), LayoutId::kValueError,
3514 "not enough values to unpack"));
3515}
3516
3517TEST_F(InterpreterTest, UnpackTupleTooManyObjects) {
3518 const char* src = R"(
3519l = (1, 2, 3, 4)
3520a, b, c = l
3521)";
3522 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, src), LayoutId::kValueError,
3523 "too many values to unpack"));
3524}
3525
3526TEST_F(InterpreterTest, UnpackSequenceWithStructseq) {
3527 ASSERT_FALSE(runFromCStr(runtime_, R"(
3528from _builtins import _structseq_new_type
3529C = _structseq_new_type("C", ("a", "b", "c"))
3530obj = C((1,2,3))
3531a, b, c = obj
3532)")
3533 .isError());
3534 HandleScope scope(thread_);
3535 Object a(&scope, mainModuleAt(runtime_, "a"));
3536 Object b(&scope, mainModuleAt(runtime_, "b"));
3537 Object c(&scope, mainModuleAt(runtime_, "c"));
3538 EXPECT_TRUE(isIntEqualsWord(*a, 1));
3539 EXPECT_TRUE(isIntEqualsWord(*b, 2));
3540 EXPECT_TRUE(isIntEqualsWord(*c, 3));
3541}
3542
3543TEST_F(InterpreterTest, UnpackSequenceWithStructseqTooFewObjects) {
3544 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, R"(
3545from _builtins import _structseq_new_type
3546C = _structseq_new_type("C", ("a", "b"))
3547obj = C((1,2))
3548a, b, c = obj
3549)"),
3550 LayoutId::kValueError,
3551 "not enough values to unpack"));
3552}
3553
3554TEST_F(InterpreterTest, UnpackSequenceWithStructseqTooManyObjects) {
3555 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, R"(
3556from _builtins import _structseq_new_type
3557C = _structseq_new_type("C", ("a", "b", "c"))
3558obj = C((1,2,3))
3559a, b = obj
3560)"),
3561 LayoutId::kValueError,
3562 "too many values to unpack"));
3563}
3564
3565TEST_F(InterpreterTest, UnpackSequenceWithStructseqInObj) {
3566 ASSERT_FALSE(runFromCStr(runtime_, R"(
3567from _builtins import _structseq_new_type
3568C = _structseq_new_type("C", ("a", "b", "c"), num_in_sequence=2)
3569obj = C((1,2,3))
3570a, b = obj
3571)")
3572 .isError());
3573 HandleScope scope(thread_);
3574 Object a(&scope, mainModuleAt(runtime_, "a"));
3575 Object b(&scope, mainModuleAt(runtime_, "b"));
3576 EXPECT_TRUE(isIntEqualsWord(*a, 1));
3577 EXPECT_TRUE(isIntEqualsWord(*b, 2));
3578}
3579
3580TEST_F(InterpreterTest, UnpackSequenceWithStructseqTooFewObjectsInSeq) {
3581 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, R"(
3582from _builtins import _structseq_new_type
3583C = _structseq_new_type("C", ("a", "b", "c"), num_in_sequence=2)
3584obj = C((1,2,3))
3585a, b, c = obj
3586)"),
3587 LayoutId::kValueError,
3588 "not enough values to unpack"));
3589}
3590
3591TEST_F(InterpreterTest, UnpackSequenceWithStructseqTooManyObjectsInSeq) {
3592 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, R"(
3593from _builtins import _structseq_new_type
3594C = _structseq_new_type("C", ("a", "b", "c", "d"), num_in_sequence=3)
3595obj = C((1,2,3,4))
3596a, b = obj
3597)"),
3598 LayoutId::kValueError,
3599 "too many values to unpack"));
3600}
3601
3602TEST_F(InterpreterTest, PrintExprInvokesDisplayhook) {
3603 HandleScope scope(thread_);
3604 ASSERT_FALSE(runFromCStr(runtime_, R"(
3605import sys
3606
3607MY_GLOBAL = 1234
3608
3609def my_displayhook(value):
3610 global MY_GLOBAL
3611 MY_GLOBAL = value
3612
3613sys.displayhook = my_displayhook
3614 )")
3615 .isError());
3616
3617 Object unique(&scope, runtime_->newList()); // unique object
3618
3619 Object none(&scope, NoneType::object());
3620 Tuple consts(&scope, runtime_->newTupleWith2(unique, none));
3621 const byte bytecode[] = {LOAD_CONST, 0, PRINT_EXPR, 0,
3622 LOAD_CONST, 1, RETURN_VALUE, 0};
3623 Code code(&scope, newCodeWithBytesConsts(bytecode, consts));
3624
3625 ASSERT_TRUE(runCode(code).isNoneType());
3626
3627 Object displayhook(&scope, moduleAtByCStr(runtime_, "sys", "displayhook"));
3628 Object my_displayhook(&scope, mainModuleAt(runtime_, "my_displayhook"));
3629 EXPECT_EQ(*displayhook, *my_displayhook);
3630
3631 Object my_global(&scope, mainModuleAt(runtime_, "MY_GLOBAL"));
3632 EXPECT_EQ(*my_global, *unique);
3633}
3634
3635TEST_F(InterpreterTest, PrintExprtDoesntPushToStack) {
3636 HandleScope scope(thread_);
3637 ASSERT_FALSE(runFromCStr(runtime_, R"(
3638import sys
3639
3640def my_displayhook(value):
3641 pass
3642
3643sys.displayhook = my_displayhook
3644 )")
3645 .isError());
3646
3647 Object obj1(&scope, SmallInt::fromWord(42));
3648 Object obj2(&scope, SmallInt::fromWord(0));
3649 Tuple consts(&scope, runtime_->newTupleWith2(obj1, obj2));
3650 // This bytecode loads 42 onto the stack, along with a value to print.
3651 // It then returns the top of the stack, which should be 42.
3652 const byte bytecode[] = {
3653 LOAD_CONST, 0, LOAD_CONST, 1, PRINT_EXPR, 0, RETURN_VALUE, 0,
3654 };
3655 Code code(&scope, newCodeWithBytesConsts(bytecode, consts));
3656
3657 Object result_obj(&scope, runCode(code));
3658 EXPECT_TRUE(isIntEqualsWord(*result_obj, 42));
3659}
3660
3661TEST_F(InterpreterTest, GetAiterCallsAiter) {
3662 HandleScope scope(thread_);
3663 ASSERT_FALSE(runFromCStr(runtime_, R"(
3664class AsyncIterable:
3665 def __aiter__(self):
3666 return 42
3667
3668a = AsyncIterable()
3669)")
3670 .isError());
3671
3672 Object a(&scope, mainModuleAt(runtime_, "a"));
3673
3674 Tuple consts(&scope, runtime_->newTupleWith1(a));
3675 const byte bytecode[] = {LOAD_CONST, 0, GET_AITER, 0, RETURN_VALUE, 0};
3676 Code code(&scope, newCodeWithBytesConsts(bytecode, consts));
3677
3678 Object result(&scope, runCode(code));
3679 EXPECT_TRUE(isIntEqualsWord(*result, 42));
3680}
3681
3682TEST_F(InterpreterTest, GetAiterOnNonIterable) {
3683 HandleScope scope(thread_);
3684 Object obj(&scope, SmallInt::fromWord(123));
3685 Tuple consts(&scope, runtime_->newTupleWith1(obj));
3686 const byte bytecode[] = {LOAD_CONST, 0, GET_AITER, 0, RETURN_VALUE, 0};
3687 Code code(&scope, newCodeWithBytesConsts(bytecode, consts));
3688
3689 Object result(&scope, runCode(code));
3690 EXPECT_TRUE(raised(*result, LayoutId::kTypeError));
3691}
3692
3693TEST_F(InterpreterTest, BeginFinallyPushesNone) {
3694 HandleScope scope(thread_);
3695 Tuple consts(&scope, runtime_->emptyTuple());
3696 const byte bytecode[] = {BEGIN_FINALLY, 0, RETURN_VALUE, 0};
3697 Code code(&scope, newCodeWithBytesConsts(bytecode, consts));
3698 Object result(&scope, runCode(code));
3699 EXPECT_TRUE(result.isNoneType());
3700}
3701
3702TEST_F(InterpreterTest, CallFinallyPushesNextPC) {
3703 HandleScope scope(thread_);
3704 Object obj(&scope, SmallInt::fromWord(123));
3705 Tuple consts(&scope, runtime_->newTupleWith1(obj));
3706 const byte bytecode[] = {CALL_FINALLY, 2, LOAD_CONST, 0, RETURN_VALUE, 0};
3707 Code code(&scope, newCodeWithBytesConsts(bytecode, consts));
3708 Object result(&scope, runCode(code));
3709 // Address of LOAD_CONST
3710 EXPECT_TRUE(isIntEqualsWord(*result, kCodeUnitSize));
3711}
3712
3713TEST_F(InterpreterTest, CallFinallyJumpsWithArgDelta) {
3714 HandleScope scope(thread_);
3715 Object obj(&scope, SmallInt::fromWord(123));
3716 Tuple consts(&scope, runtime_->newTupleWith1(obj));
3717 const byte bytecode[] = {CALL_FINALLY, 2, RETURN_VALUE, 0,
3718 LOAD_CONST, 0, RETURN_VALUE, 0};
3719 Code code(&scope, newCodeWithBytesConsts(bytecode, consts));
3720 Object result(&scope, runCode(code));
3721 // Result of LOAD_CONST
3722 EXPECT_TRUE(isIntEqualsWord(*result, 123));
3723}
3724
3725TEST_F(InterpreterTest, PopFinallyWithNoneExcAndZeroArgPopsExc) {
3726 HandleScope scope(thread_);
3727 Object return_value(&scope, SmallInt::fromWord(123));
3728 Object exc(&scope, NoneType::object());
3729 Tuple consts(&scope, runtime_->newTupleWith2(return_value, exc));
3730 const byte bytecode[] = {// Load return value
3731 LOAD_CONST, 0,
3732 // Load exc
3733 LOAD_CONST, 1,
3734 // 0 means don't pop from the stack
3735 POP_FINALLY, 0, RETURN_VALUE, 0};
3736 Code code(&scope, newCodeWithBytesConsts(bytecode, consts));
3737 Object result(&scope, runCode(code));
3738 EXPECT_TRUE(isIntEqualsWord(*result, 123));
3739}
3740
3741TEST_F(InterpreterTest, PopFinallyWithNoneExcAndNonzeroArgPopsExc) {
3742 HandleScope scope(thread_);
3743 Object obj(&scope, SmallInt::fromWord(123));
3744 Object exc(&scope, NoneType::object());
3745 Object return_value(&scope, SmallInt::fromWord(456));
3746 Tuple consts(&scope, runtime_->newTupleWith3(obj, exc, return_value));
3747 const byte bytecode[] = {
3748 // Load some random stuff onto the stack
3749 LOAD_CONST, 0,
3750 // Load exc
3751 LOAD_CONST, 1,
3752 // Load return value
3753 LOAD_CONST, 2,
3754 // 1 means pop first before fetching exc, and then push after
3755 POP_FINALLY, 1, RETURN_VALUE, 0};
3756 Code code(&scope, newCodeWithBytesConsts(bytecode, consts));
3757 Object result(&scope, runCode(code));
3758 EXPECT_TRUE(isIntEqualsWord(*result, 456));
3759}
3760
3761TEST_F(InterpreterTest, PopFinallyWithIntExcAndZeroArgPopsExc) {
3762 HandleScope scope(thread_);
3763 Object return_value(&scope, SmallInt::fromWord(123));
3764 Object exc(&scope, SmallInt::fromWord(456));
3765 Tuple consts(&scope, runtime_->newTupleWith2(return_value, exc));
3766 const byte bytecode[] = {// Load return value
3767 LOAD_CONST, 0,
3768 // Load exc
3769 LOAD_CONST, 1,
3770 // 0 means don't pop from the stack
3771 POP_FINALLY, 0, RETURN_VALUE, 0};
3772 Code code(&scope, newCodeWithBytesConsts(bytecode, consts));
3773 Object result(&scope, runCode(code));
3774 EXPECT_TRUE(isIntEqualsWord(*result, 123));
3775}
3776
3777TEST_F(InterpreterTest, PopFinallyWithIntExcAndNonzeroArgPopsExc) {
3778 HandleScope scope(thread_);
3779 Object obj(&scope, SmallInt::fromWord(123));
3780 Object exc(&scope, SmallInt::fromWord(456));
3781 Object return_value(&scope, SmallInt::fromWord(789));
3782 Tuple consts(&scope, runtime_->newTupleWith3(obj, exc, return_value));
3783 const byte bytecode[] = {
3784 // Load some random stuff onto the stack
3785 LOAD_CONST, 0,
3786 // Load exc
3787 LOAD_CONST, 1,
3788 // Load return value
3789 LOAD_CONST, 2,
3790 // 1 means pop first before fetching exc, and then push after
3791 POP_FINALLY, 1, RETURN_VALUE, 0};
3792 Code code(&scope, newCodeWithBytesConsts(bytecode, consts));
3793 Object result(&scope, runCode(code));
3794 EXPECT_TRUE(isIntEqualsWord(*result, 789));
3795}
3796
3797TEST_F(InterpreterTest, PopFinallyWithNonExceptHandlerRaisesSystemError) {
3798 HandleScope scope(thread_);
3799 Object obj1(&scope, SmallInt::fromWord(1));
3800 Object obj2(&scope, SmallInt::fromWord(2));
3801 Object exc_type(&scope, SmallInt::fromWord(3));
3802 Object exc_value(&scope, SmallInt::fromWord(4));
3803 Object exc_tb(&scope, SmallInt::fromWord(5));
3804 Object exc(&scope, SmallStr::fromCStr("exc"));
3805 Object return_value(&scope, SmallInt::fromWord(7));
3806 Tuple consts(&scope,
3807 runtime_->newTupleWithN(7, &obj1, &obj2, &exc_type, &exc_value,
3808 &exc_tb, &exc, &return_value));
3809 const byte bytecode[] = {
3810 // Load return value
3811 LOAD_CONST, 6,
3812 // Load exc traceback
3813 LOAD_CONST, 4,
3814 // Load exc value
3815 LOAD_CONST, 3,
3816 // Load exc type
3817 LOAD_CONST, 2,
3818 // Load ignored object
3819 LOAD_CONST, 0,
3820 // Load ignored object
3821 LOAD_CONST, 1,
3822 // Load exc
3823 LOAD_CONST, 5,
3824 // Push a non-ExceptHandler TryBlock on the block stack
3825 SETUP_FINALLY, 0, POP_FINALLY, 0, RETURN_VALUE, 0};
3826 Code code(&scope, newCodeWithBytesConsts(bytecode, consts));
3827 EXPECT_TRUE(raisedWithStr(runCode(code), LayoutId::kSystemError,
3828 "popped block is not an except handler"));
3829}
3830
3831TEST_F(InterpreterTest, EndAsyncForWithExceptionRaises) {
3832 HandleScope scope(thread_);
3833 const byte bytecode[] = {
3834 LOAD_CONST, 0, // exc_traceback
3835 LOAD_CONST, 1, // exc_value
3836 LOAD_CONST, 2, // exc_type
3837 END_ASYNC_FOR, 0,
3838 };
3839 Object exc_traceback(&scope, runtime_->newTraceback());
3840 Object exc_type(&scope, runtime_->typeAt(LayoutId::kUserWarning));
3841 Object exc_value(&scope, runtime_->newStrFromCStr("exc message"));
3842 Tuple consts(&scope,
3843 runtime_->newTupleWith3(exc_traceback, exc_value, exc_type));
3844 Code code(&scope, newCodeWithBytesConsts(bytecode, consts));
3845 EXPECT_TRUE(
3846 raisedWithStr(runCode(code), LayoutId::kUserWarning, "exc message"));
3847}
3848
3849TEST_F(InterpreterTest, EndAsyncForWithStopAsyncIterationContinues) {
3850 HandleScope scope(thread_);
3851 const byte bytecode[] = {
3852 LOAD_CONST, 5, // dummy
3853 SETUP_FINALLY, 10, LOAD_CONST, 0, // exc_traceback
3854 LOAD_CONST, 1, // exc_value
3855 LOAD_CONST, 2, // exc_type
3856 LOAD_CONST, 3, // stop_async_iteration
3857 RAISE_VARARGS, 1, END_ASYNC_FOR, 4, LOAD_CONST, 5, // dummy
3858 RETURN_VALUE, 0, LOAD_CONST, 4, // 42
3859 RETURN_VALUE, 0,
3860 };
3861 Object exc_traceback(&scope, runtime_->newTraceback());
3862 Object exc_value(&scope, runtime_->newStrFromCStr("exc message"));
3863 Object exc_type(&scope, runtime_->typeAt(LayoutId::kUserWarning));
3864 Object stop_async_iteration(&scope,
3865 runtime_->typeAt(LayoutId::kStopAsyncIteration));
3866 Object value(&scope, runtime_->newInt(42));
3867 Object dummy(&scope, runtime_->newInt(-7));
3868 Tuple consts(&scope,
3869 runtime_->newTupleWithN(6, &exc_traceback, &exc_value, &exc_type,
3870 &stop_async_iteration, &value, &dummy));
3871 Code code(&scope, newCodeWithBytesConsts(bytecode, consts));
3872 EXPECT_TRUE(isIntEqualsWord(runCode(code), 42));
3873}
3874
3875TEST_F(InterpreterTest, BeforeAsyncWithCallsDunderAenter) {
3876 HandleScope scope(thread_);
3877 ASSERT_FALSE(runFromCStr(runtime_, R"(
3878enter = None
3879exit = None
3880
3881class M:
3882 def __aenter__(self):
3883 global enter
3884 enter = self
3885
3886 def __aexit__(self, exc_type, exc_value, traceback):
3887 global exit
3888 exit = self
3889
3890manager = M()
3891 )")
3892 .isError());
3893 Object manager(&scope, mainModuleAt(runtime_, "manager"));
3894 Object main_obj(&scope, findMainModule(runtime_));
3895 ASSERT_TRUE(main_obj.isModule());
3896
3897 Object obj(&scope, SmallInt::fromWord(42));
3898 Tuple consts(&scope, runtime_->newTupleWith2(obj, manager));
3899 const byte bytecode[] = {LOAD_CONST, 1, BEFORE_ASYNC_WITH, 0, POP_TOP, 0,
3900 LOAD_CONST, 0, RETURN_VALUE, 0};
3901 Code code(&scope, newCodeWithBytesConsts(bytecode, consts));
3902
3903 EXPECT_TRUE(isIntEqualsWord(runCode(code), 42));
3904 Object enter(&scope, mainModuleAt(runtime_, "enter"));
3905 EXPECT_EQ(*enter, *manager);
3906 Object exit(&scope, mainModuleAt(runtime_, "exit"));
3907 EXPECT_EQ(*exit, NoneType::object());
3908}
3909
3910TEST_F(InterpreterTest, BeforeAsyncWithRaisesAttributeErrorIfAexitNotDefined) {
3911 HandleScope scope(thread_);
3912 ASSERT_FALSE(runFromCStr(runtime_, R"(
3913class M:
3914 pass
3915
3916manager = M()
3917 )")
3918 .isError());
3919
3920 Object manager(&scope, mainModuleAt(runtime_, "manager"));
3921 Tuple consts(&scope, runtime_->newTupleWith1(manager));
3922 const byte bytecode[] = {LOAD_CONST, 0, BEFORE_ASYNC_WITH, 0};
3923 Code code(&scope, newCodeWithBytesConsts(bytecode, consts));
3924
3925 EXPECT_TRUE(raisedWithStr(runCode(code), LayoutId::kAttributeError,
3926 "'M' object has no attribute '__aexit__'"));
3927}
3928
3929TEST_F(InterpreterTest, BeforeAsyncWithRaisesAttributeErrorIfAenterNotDefined) {
3930 HandleScope scope(thread_);
3931 ASSERT_FALSE(runFromCStr(runtime_, R"(
3932class M:
3933 def __aexit__(self):
3934 pass
3935
3936manager = M()
3937 )")
3938 .isError());
3939
3940 Object manager(&scope, mainModuleAt(runtime_, "manager"));
3941 Tuple consts(&scope, runtime_->newTupleWith1(manager));
3942 const byte bytecode[] = {LOAD_CONST, 0, BEFORE_ASYNC_WITH, 0};
3943 Code code(&scope, newCodeWithBytesConsts(bytecode, consts));
3944
3945 EXPECT_TRUE(raisedWithStr(runCode(code), LayoutId::kAttributeError,
3946 "'M' object has no attribute '__aenter__'"));
3947}
3948
3949TEST_F(InterpreterTest,
3950 BeforeAsyncWithPropagatesExceptionIfResolvingAexitDynamicallyRaises) {
3951 HandleScope scope(thread_);
3952 ASSERT_FALSE(runFromCStr(runtime_, R"(
3953class A:
3954 def __get__(self, obj, type=None):
3955 raise RuntimeError("foo")
3956
3957class M:
3958 __aexit__ = A()
3959
3960 async def __aenter__(self):
3961 pass
3962
3963manager = M()
3964 )")
3965 .isError());
3966
3967 Object manager(&scope, mainModuleAt(runtime_, "manager"));
3968 Tuple consts(&scope, runtime_->newTupleWith1(manager));
3969 const byte bytecode[] = {LOAD_CONST, 0, BEFORE_ASYNC_WITH, 0};
3970 Code code(&scope, newCodeWithBytesConsts(bytecode, consts));
3971
3972 EXPECT_TRUE(raisedWithStr(runCode(code), LayoutId::kRuntimeError, "foo"));
3973}
3974
3975TEST_F(InterpreterTest,
3976 BeforeAsyncWithPropagatesExceptionIfResolvingAenterDynamicallyRaises) {
3977 HandleScope scope(thread_);
3978 ASSERT_FALSE(runFromCStr(runtime_, R"(
3979class A:
3980 def __get__(self, obj, type=None):
3981 raise RuntimeError("foo")
3982
3983class M:
3984 __aenter__ = A()
3985
3986 async def __aexit__(self, a, b, c):
3987 pass
3988
3989manager = M()
3990 )")
3991 .isError());
3992
3993 Object manager(&scope, mainModuleAt(runtime_, "manager"));
3994 Tuple consts(&scope, runtime_->newTupleWith1(manager));
3995 const byte bytecode[] = {LOAD_CONST, 0, BEFORE_ASYNC_WITH, 0};
3996 Code code(&scope, newCodeWithBytesConsts(bytecode, consts));
3997
3998 EXPECT_TRUE(raisedWithStr(runCode(code), LayoutId::kRuntimeError, "foo"));
3999}
4000
4001TEST_F(InterpreterTest, SetupAsyncWithPushesBlock) {
4002 HandleScope scope(thread_);
4003 Object obj(&scope, SmallInt::fromWord(42));
4004 Tuple consts(&scope, runtime_->newTupleWith1(obj));
4005 const byte bytecode[] = {
4006 LOAD_CONST, 0, SETUP_ASYNC_WITH, 0, POP_BLOCK, 0, RETURN_VALUE, 0,
4007 };
4008 Code code(&scope, newCodeWithBytesConsts(bytecode, consts));
4009 EXPECT_EQ(runCode(code), SmallInt::fromWord(42));
4010}
4011
4012TEST_F(InterpreterTest, UnpackSequenceEx) {
4013 HandleScope scope(thread_);
4014 ASSERT_FALSE(runFromCStr(runtime_, R"(
4015l = [1, 2, 3, 4, 5, 6, 7]
4016a, b, c, *d, e, f, g = l
4017)")
4018 .isError());
4019 Object a(&scope, mainModuleAt(runtime_, "a"));
4020 Object b(&scope, mainModuleAt(runtime_, "b"));
4021 Object c(&scope, mainModuleAt(runtime_, "c"));
4022 EXPECT_TRUE(isIntEqualsWord(*a, 1));
4023 EXPECT_TRUE(isIntEqualsWord(*b, 2));
4024 EXPECT_TRUE(isIntEqualsWord(*c, 3));
4025
4026 Object d(&scope, mainModuleAt(runtime_, "d"));
4027 ASSERT_TRUE(d.isList());
4028 List list(&scope, *d);
4029 EXPECT_EQ(list.numItems(), 1);
4030 EXPECT_TRUE(isIntEqualsWord(list.at(0), 4));
4031
4032 Object e(&scope, mainModuleAt(runtime_, "e"));
4033 Object f(&scope, mainModuleAt(runtime_, "f"));
4034 Object g(&scope, mainModuleAt(runtime_, "g"));
4035 EXPECT_TRUE(isIntEqualsWord(*e, 5));
4036 EXPECT_TRUE(isIntEqualsWord(*f, 6));
4037 EXPECT_TRUE(isIntEqualsWord(*g, 7));
4038}
4039
4040TEST_F(InterpreterTest, UnpackSequenceExWithSeqIterator) {
4041 HandleScope scope(thread_);
4042 ASSERT_FALSE(runFromCStr(runtime_, R"(
4043class Seq:
4044 def __getitem__(s, i):
4045 return ("foo", "bar", 42)[i]
4046a, *b = Seq()
4047)")
4048 .isError());
4049 EXPECT_TRUE(isStrEqualsCStr(mainModuleAt(runtime_, "a"), "foo"));
4050 Object b(&scope, mainModuleAt(runtime_, "b"));
4051 EXPECT_PYLIST_EQ(b, {"bar", 42});
4052}
4053
4054TEST_F(InterpreterTest, UnpackSequenceExWithNoElementsAfter) {
4055 HandleScope scope(thread_);
4056 ASSERT_FALSE(runFromCStr(runtime_, R"(
4057l = [1, 2, 3, 4]
4058a, b, *c = l
4059)")
4060 .isError());
4061 Object a(&scope, mainModuleAt(runtime_, "a"));
4062 Object b(&scope, mainModuleAt(runtime_, "b"));
4063 Object c(&scope, mainModuleAt(runtime_, "c"));
4064 EXPECT_TRUE(isIntEqualsWord(*a, 1));
4065 EXPECT_TRUE(isIntEqualsWord(*b, 2));
4066
4067 ASSERT_TRUE(c.isList());
4068 List list(&scope, *c);
4069 ASSERT_EQ(list.numItems(), 2);
4070 EXPECT_TRUE(isIntEqualsWord(list.at(0), 3));
4071 EXPECT_TRUE(isIntEqualsWord(list.at(1), 4));
4072}
4073
4074TEST_F(InterpreterTest, UnpackSequenceExWithNoElementsBefore) {
4075 HandleScope scope(thread_);
4076 ASSERT_FALSE(runFromCStr(runtime_, R"(
4077l = [1, 2, 3, 4]
4078*a, b, c = l
4079)")
4080 .isError());
4081 Object a(&scope, mainModuleAt(runtime_, "a"));
4082 Object b(&scope, mainModuleAt(runtime_, "b"));
4083 Object c(&scope, mainModuleAt(runtime_, "c"));
4084 ASSERT_TRUE(a.isList());
4085 List list(&scope, *a);
4086 ASSERT_EQ(list.numItems(), 2);
4087 EXPECT_TRUE(isIntEqualsWord(list.at(0), 1));
4088 EXPECT_TRUE(isIntEqualsWord(list.at(1), 2));
4089
4090 EXPECT_TRUE(isIntEqualsWord(*b, 3));
4091 EXPECT_TRUE(isIntEqualsWord(*c, 4));
4092}
4093
4094TEST_F(InterpreterTest, BuildMapCallsDunderHashAndPropagatesException) {
4095 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, R"(
4096class C:
4097 def __hash__(self):
4098 raise ValueError('foo')
4099d = {C(): 4}
4100)"),
4101 LayoutId::kValueError, "foo"));
4102}
4103
4104TEST_F(InterpreterTest, BuildMapUnpackWithDict) {
4105 HandleScope scope(thread_);
4106 ASSERT_FALSE(runFromCStr(runtime_, R"(
4107d = {**{'a': 1, 'b': 2}, 'c': 3, **{'d': 4}}
4108)")
4109 .isError());
4110
4111 Object d(&scope, mainModuleAt(runtime_, "d"));
4112 ASSERT_TRUE(d.isDict());
4113
4114 Dict dict(&scope, *d);
4115 EXPECT_EQ(dict.numItems(), 4);
4116
4117 Str name(&scope, runtime_->newStrFromCStr("a"));
4118 Object el0(&scope, dictAtByStr(thread_, dict, name));
4119 EXPECT_TRUE(isIntEqualsWord(*el0, 1));
4120
4121 name = runtime_->newStrFromCStr("b");
4122 Object el1(&scope, dictAtByStr(thread_, dict, name));
4123 EXPECT_TRUE(isIntEqualsWord(*el1, 2));
4124
4125 name = runtime_->newStrFromCStr("c");
4126 Object el2(&scope, dictAtByStr(thread_, dict, name));
4127 EXPECT_TRUE(isIntEqualsWord(*el2, 3));
4128
4129 name = runtime_->newStrFromCStr("d");
4130 Object el3(&scope, dictAtByStr(thread_, dict, name));
4131 EXPECT_TRUE(isIntEqualsWord(*el3, 4));
4132}
4133
4134TEST_F(InterpreterTest, BuildMapUnpackWithListKeysMapping) {
4135 HandleScope scope(thread_);
4136 ASSERT_FALSE(runFromCStr(runtime_, R"(
4137class Foo:
4138 def __init__(self):
4139 self.idx = 0
4140 self._items = [('a', 1), ('b', 2), ('c', 3)]
4141
4142 def keys(self):
4143 return [x[0] for x in self._items]
4144
4145 def __getitem__(self, key):
4146 for k, v in self._items:
4147 if key == k:
4148 return v
4149 raise KeyError()
4150
4151d = {**Foo(), 'd': 4}
4152)")
4153 .isError());
4154
4155 Object d(&scope, mainModuleAt(runtime_, "d"));
4156 ASSERT_TRUE(d.isDict());
4157
4158 Dict dict(&scope, *d);
4159 EXPECT_EQ(dict.numItems(), 4);
4160
4161 Str name(&scope, runtime_->newStrFromCStr("a"));
4162 Object el0(&scope, dictAtByStr(thread_, dict, name));
4163 EXPECT_TRUE(isIntEqualsWord(*el0, 1));
4164
4165 name = runtime_->newStrFromCStr("b");
4166 Object el1(&scope, dictAtByStr(thread_, dict, name));
4167 EXPECT_TRUE(isIntEqualsWord(*el1, 2));
4168
4169 name = runtime_->newStrFromCStr("c");
4170 Object el2(&scope, dictAtByStr(thread_, dict, name));
4171 EXPECT_TRUE(isIntEqualsWord(*el2, 3));
4172
4173 name = runtime_->newStrFromCStr("d");
4174 Object el3(&scope, dictAtByStr(thread_, dict, name));
4175 EXPECT_TRUE(isIntEqualsWord(*el3, 4));
4176}
4177
4178TEST_F(InterpreterTest, BuildMapUnpackWithTupleKeysMapping) {
4179 HandleScope scope(thread_);
4180 ASSERT_FALSE(runFromCStr(runtime_, R"(
4181class Foo:
4182 def __init__(self):
4183 self.idx = 0
4184 self._items = [('a', 1), ('b', 2), ('c', 3)]
4185
4186 def keys(self):
4187 return ('a', 'b', 'c')
4188
4189 def __getitem__(self, key):
4190 for k, v in self._items:
4191 if key == k:
4192 return v
4193 raise KeyError()
4194
4195d = {**Foo(), 'd': 4}
4196)")
4197 .isError());
4198
4199 Object d(&scope, mainModuleAt(runtime_, "d"));
4200 ASSERT_TRUE(d.isDict());
4201
4202 Dict dict(&scope, *d);
4203 EXPECT_EQ(dict.numItems(), 4);
4204
4205 Str name(&scope, runtime_->newStrFromCStr("a"));
4206 Object el0(&scope, dictAtByStr(thread_, dict, name));
4207 EXPECT_TRUE(isIntEqualsWord(*el0, 1));
4208
4209 name = runtime_->newStrFromCStr("b");
4210 Object el1(&scope, dictAtByStr(thread_, dict, name));
4211 EXPECT_TRUE(isIntEqualsWord(*el1, 2));
4212
4213 name = runtime_->newStrFromCStr("c");
4214 Object el2(&scope, dictAtByStr(thread_, dict, name));
4215 EXPECT_TRUE(isIntEqualsWord(*el2, 3));
4216
4217 name = runtime_->newStrFromCStr("d");
4218 Object el3(&scope, dictAtByStr(thread_, dict, name));
4219 EXPECT_TRUE(isIntEqualsWord(*el3, 4));
4220}
4221
4222TEST_F(InterpreterTest, BuildMapUnpackWithIterableKeysMapping) {
4223 HandleScope scope(thread_);
4224 ASSERT_FALSE(runFromCStr(runtime_, R"(
4225class KeysIter:
4226 def __init__(self, keys):
4227 self.idx = 0
4228 self.keys = keys
4229
4230 def __iter__(self):
4231 return self
4232
4233 def __next__(self):
4234 if self.idx == len(self.keys):
4235 raise StopIteration
4236 r = self.keys[self.idx]
4237 self.idx += 1
4238 return r
4239
4240class Foo:
4241 def __init__(self):
4242 self.idx = 0
4243 self._items = [('a', 1), ('b', 2), ('c', 3)]
4244
4245 def keys(self):
4246 return KeysIter([x[0] for x in self._items])
4247
4248 def __getitem__(self, key):
4249 for k, v in self._items:
4250 if key == k:
4251 return v
4252 raise KeyError()
4253
4254d = {**Foo(), 'd': 4}
4255)")
4256 .isError());
4257
4258 Object d(&scope, mainModuleAt(runtime_, "d"));
4259 ASSERT_TRUE(d.isDict());
4260
4261 Dict dict(&scope, *d);
4262 EXPECT_EQ(dict.numItems(), 4);
4263
4264 Str name(&scope, runtime_->newStrFromCStr("a"));
4265 Object el0(&scope, dictAtByStr(thread_, dict, name));
4266 EXPECT_TRUE(isIntEqualsWord(*el0, 1));
4267
4268 name = runtime_->newStrFromCStr("b");
4269 Object el1(&scope, dictAtByStr(thread_, dict, name));
4270 EXPECT_TRUE(isIntEqualsWord(*el1, 2));
4271
4272 name = runtime_->newStrFromCStr("c");
4273 Object el2(&scope, dictAtByStr(thread_, dict, name));
4274 EXPECT_TRUE(isIntEqualsWord(*el2, 3));
4275
4276 name = runtime_->newStrFromCStr("d");
4277 Object el3(&scope, dictAtByStr(thread_, dict, name));
4278 EXPECT_TRUE(isIntEqualsWord(*el3, 4));
4279}
4280
4281TEST_F(InterpreterTest, BuildMapUnpackWithNonMapping) {
4282 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, R"(
4283class Foo:
4284 pass
4285
4286d = {**Foo(), 'd': 4}
4287 )"),
4288 LayoutId::kTypeError,
4289 "'Foo' object is not a mapping"));
4290}
4291
4292TEST_F(InterpreterTest, BuildMapUnpackWithUnsubscriptableMapping) {
4293 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, R"(
4294class Foo:
4295 def __init__(self):
4296 self.idx = 0
4297 self._items = [('a', 1), ('b', 2), ('c', 3)]
4298
4299 def keys(self):
4300 return ('a', 'b', 'c')
4301
4302d = {**Foo(), 'd': 4}
4303 )"),
4304 LayoutId::kTypeError,
4305 "'Foo' object is not a mapping"));
4306}
4307
4308TEST_F(InterpreterTest, BuildMapUnpackWithNonIterableKeys) {
4309 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, R"(
4310class Foo:
4311 def __init__(self):
4312 self.idx = 0
4313 self._items = [('a', 1), ('b', 2), ('c', 3)]
4314
4315 def keys(self):
4316 return None
4317
4318 def __getitem__(self, key):
4319 pass
4320
4321d = {**Foo(), 'd': 4}
4322 )"),
4323 LayoutId::kTypeError, "keys() is not iterable"));
4324}
4325
4326TEST_F(InterpreterTest, BuildMapUnpackWithBadIteratorKeys) {
4327 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, R"(
4328class KeysIter:
4329 def __iter__(self):
4330 return self
4331
4332class Foo:
4333 def __init__(self):
4334 pass
4335
4336 def keys(self):
4337 return KeysIter()
4338
4339 def __getitem__(self, key):
4340 pass
4341
4342d = {**Foo(), 'd': 4}
4343 )"),
4344 LayoutId::kTypeError, "keys() is not iterable"));
4345}
4346
4347TEST_F(InterpreterTest, BuildSetCallsDunderHashAndPropagatesException) {
4348 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, R"(
4349class C:
4350 def __hash__(self):
4351 raise ValueError('foo')
4352s = {C()}
4353)"),
4354 LayoutId::kValueError, "foo"));
4355}
4356
4357TEST_F(InterpreterTest, UnpackSequenceExWithTooFewObjectsBefore) {
4358 const char* src = R"(
4359l = [1, 2]
4360a, b, c, *d = l
4361)";
4362 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, src), LayoutId::kValueError,
4363 "not enough values to unpack"));
4364}
4365
4366TEST_F(InterpreterTest, UnpackSequenceExWithTooFewObjectsAfter) {
4367 const char* src = R"(
4368l = [1, 2]
4369*a, b, c, d = l
4370)";
4371 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, src), LayoutId::kValueError,
4372 "not enough values to unpack"));
4373}
4374
4375TEST_F(InterpreterTest, BuildTupleUnpackWithCall) {
4376 HandleScope scope(thread_);
4377 ASSERT_FALSE(runFromCStr(runtime_, R"(
4378def foo(*args):
4379 return args
4380
4381t = foo(*(1,2), *(3, 4))
4382)")
4383 .isError());
4384
4385 Object t(&scope, mainModuleAt(runtime_, "t"));
4386 ASSERT_TRUE(t.isTuple());
4387
4388 Tuple tuple(&scope, *t);
4389 EXPECT_TRUE(isIntEqualsWord(tuple.at(0), 1));
4390 EXPECT_TRUE(isIntEqualsWord(tuple.at(1), 2));
4391 EXPECT_TRUE(isIntEqualsWord(tuple.at(2), 3));
4392 EXPECT_TRUE(isIntEqualsWord(tuple.at(3), 4));
4393}
4394
4395TEST_F(InterpreterTest, FunctionDerefsVariable) {
4396 HandleScope scope(thread_);
4397 ASSERT_FALSE(runFromCStr(runtime_, R"(
4398def outer():
4399 var = 1
4400 def inner():
4401 return var
4402 del var
4403 return 0
4404
4405v = outer()
4406 )")
4407 .isError());
4408
4409 Object v(&scope, mainModuleAt(runtime_, "v"));
4410 EXPECT_TRUE(isIntEqualsWord(*v, 0));
4411}
4412
4413TEST_F(InterpreterTest, FunctionAccessesUnboundVariable) {
4414 const char* src = R"(
4415def outer():
4416 var = 1
4417 def inner():
4418 return var
4419 del var
4420 return var
4421
4422v = outer()
4423 )";
4424
4425 EXPECT_TRUE(
4426 raisedWithStr(runFromCStr(runtime_, src), LayoutId::kUnboundLocalError,
4427 "local variable 'var' referenced before assignment"));
4428}
4429
4430TEST_F(InterpreterTest, ImportStarImportsPublicSymbols) {
4431 HandleScope scope(thread_);
4432 Object module_src(&scope, runtime_->newStrFromCStr(R"(
4433def public_symbol():
4434 return 1
4435def public_symbol2():
4436 return 2
4437)"));
4438 Object filename(&scope, runtime_->newStrFromCStr("<test string>"));
4439
4440 // Preload the module
4441 Object name(&scope, runtime_->newStrFromCStr("test_module"));
4442 Code code(&scope, compile(thread_, module_src, filename, ID(exec),
4443 /*flags=*/0, /*optimize=*/0));
4444 ASSERT_FALSE(executeModuleFromCode(thread_, code, name).isError());
4445
4446 ASSERT_FALSE(runFromCStr(runtime_, R"(
4447from test_module import *
4448a = public_symbol()
4449b = public_symbol2()
4450)")
4451 .isError());
4452
4453 Object a(&scope, mainModuleAt(runtime_, "a"));
4454 Object b(&scope, mainModuleAt(runtime_, "b"));
4455 EXPECT_TRUE(isIntEqualsWord(*a, 1));
4456 EXPECT_TRUE(isIntEqualsWord(*b, 2));
4457}
4458
4459TEST_F(InterpreterTest, ImportStarDoesNotImportPrivateSymbols) {
4460 HandleScope scope(thread_);
4461 Object module_src(&scope, runtime_->newStrFromCStr(R"(
4462def public_symbol():
4463 return 1
4464def _private_symbol():
4465 return 2
4466)"));
4467 Object filename(&scope, runtime_->newStrFromCStr("<test string>"));
4468
4469 // Preload the module
4470 Object name(&scope, runtime_->newStrFromCStr("test_module"));
4471 Code code(&scope, compile(thread_, module_src, filename, ID(exec),
4472 /*flags=*/0, /*optimize=*/0));
4473 ASSERT_FALSE(executeModuleFromCode(thread_, code, name).isError());
4474
4475 const char* main_src = R"(
4476from test_module import *
4477a = public_symbol()
4478b = _private_symbol()
4479)";
4480
4481 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, main_src),
4482 LayoutId::kNameError,
4483 "name '_private_symbol' is not defined"));
4484}
4485
4486TEST_F(InterpreterTest, ImportStarWorksWithDictImplicitGlobals) {
4487 HandleScope scope(thread_);
4488 Object module_src(&scope, runtime_->newStrFromCStr(R"(
4489def foo():
4490 return "bar"
4491def baz():
4492 return "quux"
4493)"));
4494 Object filename(&scope, runtime_->newStrFromCStr("<test string>"));
4495
4496 // Preload the module
4497 Object name(&scope, runtime_->newStrFromCStr("test_module"));
4498 Code module_code(&scope, compile(thread_, module_src, filename, ID(exec),
4499 /*flags=*/0, /*optimize=*/0));
4500 ASSERT_FALSE(executeModuleFromCode(thread_, module_code, name).isError());
4501
4502 const char* main_src = R"(
4503from test_module import *
4504a = foo()
4505b = baz()
4506)";
4507
4508 Object str(&scope, runtime_->newStrFromCStr(main_src));
4509 Code main_code(&scope, compile(thread_, str, filename, ID(exec),
4510 /*flags=*/0, /*optimize=*/0));
4511 Module main_module(&scope, findMainModule(runtime_));
4512 Dict implicit_globals(&scope, runtime_->newDict());
4513 Object result(&scope,
4514 thread_->exec(main_code, main_module, implicit_globals));
4515 EXPECT_FALSE(result.isError());
4516 EXPECT_EQ(implicit_globals.numItems(), 4);
4517}
4518
4519TEST_F(InterpreterTest, ImportStarWorksWithUserDefinedImplicitGlobals) {
4520 HandleScope scope(thread_);
4521 Object module_src(&scope, runtime_->newStrFromCStr(R"(
4522def foo():
4523 return "bar"
4524def baz():
4525 return "quux"
4526)"));
4527 Object filename(&scope, runtime_->newStrFromCStr("<test string>"));
4528
4529 // Preload the module
4530 Object name(&scope, runtime_->newStrFromCStr("test_module"));
4531 Code module_code(&scope, compile(thread_, module_src, filename, ID(exec),
4532 /*flags=*/0, /*optimize=*/0));
4533 ASSERT_FALSE(executeModuleFromCode(thread_, module_code, name).isError());
4534
4535 EXPECT_FALSE(runFromCStr(runtime_, R"(
4536class C:
4537 def __init__(self):
4538 self.mydict = {}
4539 def __setitem__(self, key, value):
4540 self.mydict[key] = value
4541 def __getitem__(self, key):
4542 return self.mydict[key]
4543)")
4544 .isError());
4545
4546 const char* main_src = R"(
4547from test_module import *
4548a = foo()
4549b = baz()
4550)";
4551
4552 Object str(&scope, runtime_->newStrFromCStr(main_src));
4553 Code main_code(&scope, compile(thread_, str, filename, ID(exec),
4554 /*flags=*/0, /*optimize=*/0));
4555 Module main_module(&scope, findMainModule(runtime_));
4556 Type implicit_globals_type(&scope, mainModuleAt(runtime_, "C"));
4557 Object implicit_globals(
4558 &scope, thread_->invokeMethod1(implicit_globals_type, ID(__call__)));
4559 Object result(&scope,
4560 thread_->exec(main_code, main_module, implicit_globals));
4561 EXPECT_FALSE(result.isError());
4562}
4563
4564TEST_F(InterpreterTest, ImportCallsBuiltinsDunderImport) {
4565 ASSERT_TRUE(raisedWithStr(runFromCStr(runtime_, R"(
4566import builtins
4567def import_forbidden(name, globals, locals, fromlist, level):
4568 raise Exception("import forbidden")
4569builtins.__import__ = import_forbidden
4570import builtins
4571)"),
4572 LayoutId::kException, "import forbidden"));
4573}
4574
4575TEST_F(InterpreterTest, GetAnextCallsAnextAndAwait) {
4576 HandleScope scope(thread_);
4577 ASSERT_FALSE(runFromCStr(runtime_, R"(
4578anext_called = None
4579await_called = None
4580
4581class AsyncIterator:
4582 def __anext__(self):
4583 global anext_called
4584 anext_called = self
4585 return self
4586
4587 def __await__(self):
4588 global await_called
4589 await_called = self
4590 return self
4591
4592 # Return from __await__ must be an "iterable" type
4593 def __next__(self):
4594 pass
4595
4596a = AsyncIterator()
4597)")
4598 .isError());
4599 Object a(&scope, mainModuleAt(runtime_, "a"));
4600
4601 Tuple consts(&scope, runtime_->newTupleWith1(a));
4602 const byte bytecode[] = {LOAD_CONST, 0, GET_ANEXT, 0,
4603 BUILD_TUPLE, 2, RETURN_VALUE, 0};
4604 Code code(&scope, newCodeWithBytesConsts(bytecode, consts));
4605
4606 Tuple result(&scope, runCode(code));
4607 EXPECT_EQ(*a, result.at(0));
4608 EXPECT_EQ(*a, result.at(1));
4609 Object anext(&scope, mainModuleAt(runtime_, "anext_called"));
4610 EXPECT_EQ(*a, *anext);
4611 Object await(&scope, mainModuleAt(runtime_, "await_called"));
4612 EXPECT_EQ(*a, *await);
4613}
4614
4615TEST_F(InterpreterTest, GetAnextCallsAnextButNotAwaitOnAsyncGenerator) {
4616 HandleScope scope(thread_);
4617 ASSERT_FALSE(runFromCStr(runtime_, R"(
4618async def f():
4619 yield
4620
4621async_gen = f()
4622
4623class AsyncIterator:
4624 def __anext__(self):
4625 return async_gen
4626
4627async_it = AsyncIterator()
4628)")
4629 .isError());
4630 Object async_gen(&scope, mainModuleAt(runtime_, "async_gen"));
4631 Object async_it(&scope, mainModuleAt(runtime_, "async_it"));
4632 // The async generator object instance should not have an __await__() method.
4633 ASSERT_TRUE(Interpreter::lookupMethod(thread_, async_gen, ID(__await__))
4634 .isErrorNotFound());
4635 Tuple consts(&scope, runtime_->newTupleWith1(async_it));
4636 const byte bytecode[] = {LOAD_CONST, 0, GET_ANEXT, 0,
4637 BUILD_TUPLE, 2, RETURN_VALUE, 0};
4638 Code code(&scope, newCodeWithBytesConsts(bytecode, consts));
4639 Tuple result(&scope, runCode(code));
4640 EXPECT_EQ(*async_it, result.at(0));
4641 EXPECT_EQ(runtime_->typeOf(result.at(1)),
4642 runtime_->typeAt(LayoutId::kAsyncGenerator));
4643}
4644
4645TEST_F(InterpreterTest, GetAnextOnNonIterable) {
4646 HandleScope scope(thread_);
4647 Object obj(&scope, SmallInt::fromWord(123));
4648 Tuple consts(&scope, runtime_->newTupleWith1(obj));
4649 const byte bytecode[] = {LOAD_CONST, 0, GET_ANEXT, 0, RETURN_VALUE, 0};
4650 Code code(&scope, newCodeWithBytesConsts(bytecode, consts));
4651
4652 Object result(&scope, runCode(code));
4653 EXPECT_TRUE(raised(*result, LayoutId::kTypeError));
4654}
4655
4656TEST_F(InterpreterTest, GetAnextWithInvalidAnext) {
4657 HandleScope scope(thread_);
4658 ASSERT_FALSE(runFromCStr(runtime_, R"(
4659class AsyncIterator:
4660 def __anext__(self):
4661 return 42
4662
4663a = AsyncIterator()
4664)")
4665 .isError());
4666 Object a(&scope, mainModuleAt(runtime_, "a"));
4667
4668 Tuple consts(&scope, runtime_->newTupleWith1(a));
4669 const byte bytecode[] = {LOAD_CONST, 0, GET_ANEXT, 0, RETURN_VALUE, 0};
4670 Code code(&scope, newCodeWithBytesConsts(bytecode, consts));
4671
4672 Object result(&scope, runCode(code));
4673 EXPECT_TRUE(raised(*result, LayoutId::kTypeError));
4674}
4675
4676static RawObject runCodeCallingGetAwaitableOnObject(Thread* thread,
4677 const Object& obj) {
4678 HandleScope scope(thread);
4679 Runtime* runtime = thread->runtime();
4680 Tuple consts(&scope, runtime->newTupleWith1(obj));
4681 const byte bytecode[] = {LOAD_CONST, 0, GET_AWAITABLE, 0, RETURN_VALUE, 0};
4682 Code code(&scope, newCodeWithBytesConsts(bytecode, consts));
4683 return runCode(code);
4684}
4685
4686TEST_F(InterpreterTest, GetAwaitableCallsAwait) {
4687 HandleScope scope(thread_);
4688 ASSERT_FALSE(runFromCStr(runtime_, R"(
4689# Return from __await__ must be an "iterable" type
4690iterable = iter([])
4691
4692class Awaitable:
4693 def __await__(self):
4694 return iterable
4695
4696a = Awaitable()
4697)")
4698 .isError());
4699
4700 Object iterable(&scope, mainModuleAt(runtime_, "iterable"));
4701 Object a(&scope, mainModuleAt(runtime_, "a"));
4702 Object result(&scope, runCodeCallingGetAwaitableOnObject(thread_, a));
4703 EXPECT_EQ(result, iterable);
4704}
4705
4706TEST_F(InterpreterTest, GetAwaitableIsNoOpOnCoroutine) {
4707 HandleScope scope(thread_);
4708 ASSERT_FALSE(runFromCStr(runtime_, R"(
4709async def f(): pass
4710
4711coro = f()
4712)")
4713 .isError());
4714
4715 Object coro(&scope, mainModuleAt(runtime_, "coro"));
4716 Object result(&scope, runCodeCallingGetAwaitableOnObject(thread_, coro));
4717 EXPECT_TRUE(*result == *coro);
4718}
4719
4720TEST_F(InterpreterTest, GetAwaitableIsNoOpOnAsyncGenerator) {
4721 HandleScope scope(thread_);
4722 ASSERT_FALSE(runFromCStr(runtime_, R"(
4723async def f(): yield
4724
4725async_gen = f()
4726)")
4727 .isError());
4728
4729 Object async_gen(&scope, mainModuleAt(runtime_, "async_gen"));
4730 Object result(&scope, runCodeCallingGetAwaitableOnObject(thread_, async_gen));
4731 EXPECT_TRUE(*result == *async_gen);
4732}
4733
4734TEST_F(InterpreterTest, GetAwaitableRaisesOnUnflaggedGenerator) {
4735 HandleScope scope(thread_);
4736 ASSERT_FALSE(runFromCStr(runtime_, R"(
4737def f(): yield
4738
4739generator = f()
4740)")
4741 .isError());
4742
4743 Object generator(&scope, mainModuleAt(runtime_, "generator"));
4744 Object result(&scope, runCodeCallingGetAwaitableOnObject(thread_, generator));
4745 EXPECT_TRUE(raised(*result, LayoutId::kTypeError));
4746}
4747
4748TEST_F(InterpreterTest, GetAwaitableIsNoOpOnFlaggedGenerator) {
4749 HandleScope scope(thread_);
4750 ASSERT_FALSE(runFromCStr(runtime_, R"(
4751def f(): yield
4752)")
4753 .isError());
4754 Function generator_function(&scope, mainModuleAt(runtime_, "f"));
4755 generator_function.setFlags(generator_function.flags() |
4756 RawFunction::Flags::kIterableCoroutine);
4757 ASSERT_FALSE(runFromCStr(runtime_, R"(
4758generator = f()
4759)")
4760 .isError());
4761 Object generator(&scope, mainModuleAt(runtime_, "generator"));
4762 Object result(&scope, runCodeCallingGetAwaitableOnObject(thread_, generator));
4763 EXPECT_TRUE(*result == *generator);
4764}
4765
4766TEST_F(InterpreterTest, GetAwaitableOnNonAwaitable) {
4767 HandleScope scope(thread_);
4768 Object str(&scope, Runtime::internStrFromCStr(thread_, "foo"));
4769 Object result(&scope, runCodeCallingGetAwaitableOnObject(thread_, str));
4770 EXPECT_TRUE(raised(*result, LayoutId::kTypeError));
4771}
4772
4773TEST_F(InterpreterTest, BuildMapUnpackWithCallDict) {
4774 HandleScope scope(thread_);
4775 ASSERT_FALSE(runFromCStr(runtime_, R"(
4776def foo(**kwargs):
4777 return kwargs
4778
4779d = foo(**{'a': 1, 'b': 2}, **{'c': 3, 'd': 4})
4780)")
4781 .isError());
4782
4783 Object d(&scope, mainModuleAt(runtime_, "d"));
4784 ASSERT_TRUE(d.isDict());
4785
4786 Dict dict(&scope, *d);
4787 EXPECT_EQ(dict.numItems(), 4);
4788
4789 Str name(&scope, runtime_->newStrFromCStr("a"));
4790 Object el0(&scope, dictAtByStr(thread_, dict, name));
4791 EXPECT_TRUE(isIntEqualsWord(*el0, 1));
4792
4793 name = runtime_->newStrFromCStr("b");
4794 Object el1(&scope, dictAtByStr(thread_, dict, name));
4795 EXPECT_TRUE(isIntEqualsWord(*el1, 2));
4796
4797 name = runtime_->newStrFromCStr("c");
4798 Object el2(&scope, dictAtByStr(thread_, dict, name));
4799 EXPECT_TRUE(isIntEqualsWord(*el2, 3));
4800
4801 name = runtime_->newStrFromCStr("d");
4802 Object el3(&scope, dictAtByStr(thread_, dict, name));
4803 EXPECT_TRUE(isIntEqualsWord(*el3, 4));
4804}
4805
4806TEST_F(InterpreterTest, BuildMapUnpackWithCallTupleKeys) {
4807 HandleScope scope(thread_);
4808 ASSERT_FALSE(runFromCStr(runtime_, R"(
4809class Foo:
4810 def __init__(self, d):
4811 self.d = d
4812
4813 def keys(self):
4814 return ('c', 'd')
4815
4816 def __getitem__(self, key):
4817 return self.d[key]
4818
4819def foo(**kwargs):
4820 return kwargs
4821
4822d = foo(**{'a': 1, 'b': 2}, **Foo({'c': 3, 'd': 4}))
4823)")
4824 .isError());
4825
4826 Object d(&scope, mainModuleAt(runtime_, "d"));
4827 ASSERT_TRUE(d.isDict());
4828
4829 Dict dict(&scope, *d);
4830 EXPECT_EQ(dict.numItems(), 4);
4831
4832 Str name(&scope, runtime_->newStrFromCStr("a"));
4833 Object el0(&scope, dictAtByStr(thread_, dict, name));
4834 EXPECT_TRUE(isIntEqualsWord(*el0, 1));
4835
4836 name = runtime_->newStrFromCStr("b");
4837 Object el1(&scope, dictAtByStr(thread_, dict, name));
4838 EXPECT_TRUE(isIntEqualsWord(*el1, 2));
4839
4840 name = runtime_->newStrFromCStr("c");
4841 Object el2(&scope, dictAtByStr(thread_, dict, name));
4842 EXPECT_TRUE(isIntEqualsWord(*el2, 3));
4843
4844 name = runtime_->newStrFromCStr("d");
4845 Object el3(&scope, dictAtByStr(thread_, dict, name));
4846 EXPECT_TRUE(isIntEqualsWord(*el3, 4));
4847}
4848
4849TEST_F(InterpreterTest, BuildMapUnpackWithCallListKeys) {
4850 HandleScope scope(thread_);
4851 ASSERT_FALSE(runFromCStr(runtime_, R"(
4852class Foo:
4853 def __init__(self, d):
4854 self.d = d
4855
4856 def keys(self):
4857 return ['c', 'd']
4858
4859 def __getitem__(self, key):
4860 return self.d[key]
4861
4862def foo(**kwargs):
4863 return kwargs
4864
4865d = foo(**{'a': 1, 'b': 2}, **Foo({'c': 3, 'd': 4}))
4866)")
4867 .isError());
4868
4869 Object d(&scope, mainModuleAt(runtime_, "d"));
4870 ASSERT_TRUE(d.isDict());
4871
4872 Dict dict(&scope, *d);
4873 EXPECT_EQ(dict.numItems(), 4);
4874
4875 Str name(&scope, runtime_->newStrFromCStr("a"));
4876 Object el0(&scope, dictAtByStr(thread_, dict, name));
4877 EXPECT_TRUE(isIntEqualsWord(*el0, 1));
4878
4879 name = runtime_->newStrFromCStr("b");
4880 Object el1(&scope, dictAtByStr(thread_, dict, name));
4881 EXPECT_TRUE(isIntEqualsWord(*el1, 2));
4882
4883 name = runtime_->newStrFromCStr("c");
4884 Object el2(&scope, dictAtByStr(thread_, dict, name));
4885 EXPECT_TRUE(isIntEqualsWord(*el2, 3));
4886
4887 name = runtime_->newStrFromCStr("d");
4888 Object el3(&scope, dictAtByStr(thread_, dict, name));
4889 EXPECT_TRUE(isIntEqualsWord(*el3, 4));
4890}
4891
4892TEST_F(InterpreterTest, BuildMapUnpackWithCallIteratorKeys) {
4893 HandleScope scope(thread_);
4894 ASSERT_FALSE(runFromCStr(runtime_, R"(
4895class Iter:
4896 def __init__(self, keys):
4897 self.idx = 0
4898 self.keys = keys
4899
4900 def __iter__(self):
4901 return self
4902
4903 def __next__(self):
4904 if self.idx >= len(self.keys):
4905 raise StopIteration()
4906 r = self.keys[self.idx]
4907 self.idx += 1
4908 return r
4909
4910 def __length_hint__(self):
4911 return len(self.keys) - self.idx
4912
4913class Foo:
4914 def __init__(self, d):
4915 self.d = d
4916
4917 def keys(self):
4918 return Iter(['c', 'd'])
4919
4920 def __getitem__(self, key):
4921 return self.d[key]
4922
4923def foo(**kwargs):
4924 return kwargs
4925
4926d = foo(**{'a': 1, 'b': 2}, **Foo({'c': 3, 'd': 4}))
4927)")
4928 .isError());
4929
4930 Object d(&scope, mainModuleAt(runtime_, "d"));
4931 ASSERT_TRUE(d.isDict());
4932
4933 Dict dict(&scope, *d);
4934 EXPECT_EQ(dict.numItems(), 4);
4935
4936 Str name(&scope, runtime_->newStrFromCStr("a"));
4937 Object el0(&scope, dictAtByStr(thread_, dict, name));
4938 EXPECT_TRUE(isIntEqualsWord(*el0, 1));
4939
4940 name = runtime_->newStrFromCStr("b");
4941 Object el1(&scope, dictAtByStr(thread_, dict, name));
4942 EXPECT_TRUE(isIntEqualsWord(*el1, 2));
4943
4944 name = runtime_->newStrFromCStr("c");
4945 Object el2(&scope, dictAtByStr(thread_, dict, name));
4946 EXPECT_TRUE(isIntEqualsWord(*el2, 3));
4947
4948 name = runtime_->newStrFromCStr("d");
4949 Object el3(&scope, dictAtByStr(thread_, dict, name));
4950 EXPECT_TRUE(isIntEqualsWord(*el3, 4));
4951}
4952
4953TEST_F(InterpreterTest, BuildMapUnpackWithCallDictNonStrKey) {
4954 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, R"(
4955def foo(**kwargs):
4956 return kwargs
4957
4958foo(**{'a': 1, 'b': 2}, **{'c': 3, 4: 4})
4959 )"),
4960 LayoutId::kTypeError, "keywords must be strings"));
4961}
4962
4963TEST_F(InterpreterTest, BuildMapUnpackWithCallDictRepeatedKeys) {
4964 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, R"(
4965def foo(**kwargs):
4966 return kwargs
4967
4968foo(**{'a': 1, 'b': 2}, **{'c': 3, 'a': 4})
4969 )"),
4970 LayoutId::kTypeError,
4971 "got multiple values for keyword argument 'a'"));
4972}
4973
4974TEST_F(InterpreterTest, BuildMapUnpackWithCallNonMapping) {
4975 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, R"(
4976class Foo:
4977 pass
4978
4979def foo(**kwargs):
4980 return kwargs
4981
4982foo(**{'a': 1, 'b': 2}, **Foo())
4983 )"),
4984 LayoutId::kTypeError,
4985 "'Foo' object is not a mapping"));
4986}
4987
4988TEST_F(InterpreterTest, BuildMapUnpackWithCallNonSubscriptable) {
4989 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, R"(
4990class Foo:
4991 def keys(self):
4992 pass
4993
4994def foo(**kwargs):
4995 return kwargs
4996
4997foo(**{'a': 1, 'b': 2}, **Foo())
4998 )"),
4999 LayoutId::kTypeError,
5000 "'Foo' object is not a mapping"));
5001}
5002
5003TEST_F(InterpreterTest, BuildMapUnpackWithCallListKeysNonStrKey) {
5004 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, R"(
5005class Foo:
5006 def keys(self):
5007 return [1]
5008
5009 def __getitem__(self, key):
5010 pass
5011
5012def foo(**kwargs):
5013 return kwargs
5014
5015foo(**{'a': 1, 'b': 2}, **Foo())
5016 )"),
5017 LayoutId::kTypeError, "keywords must be strings"));
5018}
5019
5020TEST_F(InterpreterTest, BuildMapUnpackWithCallListKeysRepeatedKeys) {
5021 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, R"(
5022class Foo:
5023 def keys(self):
5024 return ['a']
5025
5026 def __getitem__(self, key):
5027 pass
5028
5029def foo(**kwargs):
5030 return kwargs
5031
5032foo(**{'a': 1, 'b': 2}, **Foo())
5033 )"),
5034 LayoutId::kTypeError,
5035 "got multiple values for keyword argument 'a'"));
5036}
5037
5038TEST_F(InterpreterTest, BuildMapUnpackWithCallTupleKeysNonStrKeys) {
5039 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, R"(
5040class Foo:
5041 def keys(self):
5042 return (1,)
5043
5044 def __getitem__(self, key):
5045 pass
5046
5047def foo(**kwargs):
5048 return kwargs
5049
5050foo(**{'a': 1, 'b': 2}, **Foo())
5051 )"),
5052 LayoutId::kTypeError, "keywords must be strings"));
5053}
5054
5055TEST_F(InterpreterTest, BuildMapUnpackWithCallTupleKeysRepeatedKeys) {
5056 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, R"(
5057class Foo:
5058 def keys(self):
5059 return ('a',)
5060
5061 def __getitem__(self, key):
5062 pass
5063
5064def foo(**kwargs):
5065 return kwargs
5066
5067foo(**{'a': 1, 'b': 2}, **Foo())
5068 )"),
5069 LayoutId::kTypeError,
5070 "got multiple values for keyword argument 'a'"));
5071}
5072
5073TEST_F(InterpreterTest, BuildMapUnpackWithCallNonIterableKeys) {
5074 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, R"(
5075class Foo:
5076 def keys(self):
5077 return None
5078
5079 def __getitem__(self, key):
5080 pass
5081
5082def foo(**kwargs):
5083 return kwargs
5084
5085foo(**{'a': 1, 'b': 2}, **Foo())
5086 )"),
5087 LayoutId::kTypeError, "keys() is not iterable"));
5088}
5089
5090TEST_F(InterpreterTest, BuildMapUnpackWithCallIterableWithoutNext) {
5091 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, R"(
5092class Iter:
5093 def __iter__(self):
5094 return self
5095
5096class Foo:
5097 def keys(self):
5098 return Iter()
5099
5100 def __getitem__(self, key):
5101 pass
5102
5103def foo(**kwargs):
5104 return kwargs
5105
5106foo(**{'a': 1, 'b': 2}, **Foo())
5107 )"),
5108 LayoutId::kTypeError, "keys() is not iterable"));
5109}
5110
5111TEST_F(InterpreterTest, BuildMapUnpackWithCallIterableNonStrKey) {
5112 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, R"(
5113class Iter:
5114 def __init__(self, keys):
5115 self.idx = 0
5116 self.keys = keys
5117
5118 def __iter__(self):
5119 return self
5120
5121 def __next__(self):
5122 if self.idx >= len(self.keys):
5123 raise StopIteration()
5124 r = self.keys[self.idx]
5125 self.idx += 1
5126 return r
5127
5128 def __length_hint__(self):
5129 return len(self.keys) - self.idx
5130
5131class Foo:
5132 def keys(self):
5133 return Iter((1, 2, 3))
5134
5135 def __getitem__(self, key):
5136 return 0
5137
5138def foo(**kwargs):
5139 return kwargs
5140
5141foo(**{'a': 1, 'b': 2}, **Foo())
5142 )"),
5143 LayoutId::kTypeError, "keywords must be strings"));
5144}
5145
5146TEST_F(InterpreterTest, BuildMapUnpackWithCallIterableRepeatedKeys) {
5147 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, R"(
5148class Iter:
5149 def __init__(self, keys):
5150 self.idx = 0
5151 self.keys = keys
5152
5153 def __iter__(self):
5154 return self
5155
5156 def __next__(self):
5157 if self.idx >= len(self.keys):
5158 raise StopIteration()
5159 r = self.keys[self.idx]
5160 self.idx += 1
5161 return r
5162
5163 def __length_hint__(self):
5164 return len(self.keys) - self.idx
5165
5166class Foo:
5167 def keys(self):
5168 return Iter(('a', 'a'))
5169
5170 def __getitem__(self, key):
5171 return 0
5172
5173def foo(**kwargs):
5174 return kwargs
5175
5176foo(**{'a': 1, 'b': 2}, **Foo())
5177 )"),
5178 LayoutId::kTypeError,
5179 "got multiple values for keyword argument 'a'"));
5180}
5181
5182TEST_F(InterpreterTest, YieldFromIterReturnsIter) {
5183 HandleScope scope(thread_);
5184
5185 ASSERT_FALSE(runFromCStr(runtime_, R"(
5186class FooIterator:
5187 def __next__(self):
5188 pass
5189
5190class Foo:
5191 def __iter__(self):
5192 return FooIterator()
5193
5194foo = Foo()
5195 )")
5196 .isError());
5197
5198 Object foo(&scope, mainModuleAt(runtime_, "foo"));
5199
5200 // Create a code object and set the foo instance as a const
5201 Tuple consts(&scope, runtime_->newTupleWith1(foo));
5202
5203 // Python code:
5204 // foo = Foo()
5205 // def bar():
5206 // yield from foo
5207 const byte bytecode[] = {
5208 LOAD_CONST, 0, // (foo)
5209 GET_YIELD_FROM_ITER, 0, // iter(foo)
5210 RETURN_VALUE, 0,
5211 };
5212 Code code(&scope, newCodeWithBytesConsts(bytecode, consts));
5213
5214 // Confirm that the returned value is the iterator of Foo
5215 Object result(&scope, runCode(code));
5216 Type result_type(&scope, runtime_->typeOf(*result));
5217 EXPECT_TRUE(isStrEqualsCStr(result_type.name(), "FooIterator"));
5218}
5219
5220TEST_F(InterpreterTest, YieldFromIterWithSequenceReturnsIter) {
5221 HandleScope scope(thread_);
5222
5223 ASSERT_FALSE(runFromCStr(runtime_, R"(
5224class FooSequence:
5225 def __getitem__(self, i):
5226 return ("foo", "bar")[i]
5227
5228foo = FooSequence()
5229 )")
5230 .isError());
5231
5232 Object foo(&scope, mainModuleAt(runtime_, "foo"));
5233
5234 // Create a code object and set the foo instance as a const
5235 Tuple consts(&scope, runtime_->newTupleWith1(foo));
5236
5237 // Python code:
5238 // foo = FooSequence()
5239 // def bar():
5240 // yield from foo
5241 const byte bytecode[] = {
5242 LOAD_CONST, 0, // (foo)
5243 GET_YIELD_FROM_ITER, 0, // iter(foo)
5244 RETURN_VALUE, 0,
5245 };
5246 Code code(&scope, newCodeWithBytesConsts(bytecode, consts));
5247
5248 // Confirm that the returned value is a sequence iterator
5249 Object result(&scope, runCode(code));
5250 Type result_type(&scope, runtime_->typeOf(*result));
5251 EXPECT_TRUE(isStrEqualsCStr(result_type.name(), "iterator"));
5252}
5253
5254TEST_F(InterpreterTest, YieldFromIterRaisesException) {
5255 const char* src = R"(
5256def yield_from_func():
5257 yield from 1
5258
5259for i in yield_from_func():
5260 pass
5261 )";
5262
5263 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, src), LayoutId::kTypeError,
5264 "'int' object is not iterable"));
5265}
5266
5267TEST_F(InterpreterTest, YieldFromCoroutineInNonCoroutineIterRaisesException) {
5268 const char* src = R"(
5269async def coro():
5270 pass
5271
5272def f():
5273 yield from coro()
5274
5275f().send(None)
5276 )";
5277
5278 EXPECT_TRUE(
5279 raisedWithStr(runFromCStr(runtime_, src), LayoutId::kTypeError,
5280 "cannot 'yield from' a coroutine object in a non-coroutine "
5281 "generator"));
5282}
5283
5284TEST_F(InterpreterTest, MakeFunctionSetsDunderModule) {
5285 HandleScope scope(thread_);
5286 Object module_name(&scope, runtime_->newStrFromCStr("foo"));
5287 Object module_src(&scope, runtime_->newStrFromCStr(R"(
5288def bar(): pass
5289)"));
5290 Object filename(&scope, runtime_->newStrFromCStr("<test string>"));
5291 Code code(&scope, compile(thread_, module_src, filename, ID(exec),
5292 /*flags=*/0, /*optimize=*/0));
5293 ASSERT_FALSE(executeModuleFromCode(thread_, code, module_name).isError());
5294 ASSERT_FALSE(runFromCStr(runtime_, R"(
5295import foo
5296def baz(): pass
5297a = getattr(foo.bar, '__module__')
5298b = getattr(baz, '__module__')
5299)")
5300 .isError());
5301 Object a(&scope, mainModuleAt(runtime_, "a"));
5302 ASSERT_TRUE(a.isStr());
5303 EXPECT_TRUE(Str::cast(*a).equalsCStr("foo"));
5304 Object b(&scope, mainModuleAt(runtime_, "b"));
5305 ASSERT_TRUE(b.isStr());
5306 EXPECT_TRUE(Str::cast(*b).equalsCStr("__main__"));
5307}
5308
5309TEST_F(InterpreterTest, MakeFunctionSetsDunderQualname) {
5310 HandleScope scope(thread_);
5311 ASSERT_FALSE(runFromCStr(runtime_, R"(
5312class Foo():
5313 def bar(): pass
5314def baz(): pass
5315a = getattr(Foo.bar, '__qualname__')
5316b = getattr(baz, '__qualname__')
5317)")
5318 .isError());
5319 Object a(&scope, mainModuleAt(runtime_, "a"));
5320 ASSERT_TRUE(a.isStr());
5321 EXPECT_TRUE(Str::cast(*a).equalsCStr("Foo.bar"));
5322 Object b(&scope, mainModuleAt(runtime_, "b"));
5323 ASSERT_TRUE(b.isStr());
5324 EXPECT_TRUE(Str::cast(*b).equalsCStr("baz"));
5325}
5326
5327TEST_F(InterpreterTest, MakeFunctionSetsDunderDoc) {
5328 HandleScope scope(thread_);
5329 ASSERT_FALSE(runFromCStr(runtime_, R"(
5330def foo():
5331 """This is a docstring"""
5332 pass
5333def bar(): pass
5334)")
5335 .isError());
5336 Object foo(&scope, testing::mainModuleAt(runtime_, "foo"));
5337 ASSERT_TRUE(foo.isFunction());
5338 Object foo_docstring(&scope, Function::cast(*foo).doc());
5339 ASSERT_TRUE(foo_docstring.isStr());
5340 EXPECT_TRUE(Str::cast(*foo_docstring).equalsCStr("This is a docstring"));
5341
5342 Object bar(&scope, testing::mainModuleAt(runtime_, "bar"));
5343 ASSERT_TRUE(bar.isFunction());
5344 Object bar_docstring(&scope, Function::cast(*bar).doc());
5345 EXPECT_TRUE(bar_docstring.isNoneType());
5346}
5347
5348TEST_F(InterpreterTest, OpcodesAreCounted) {
5349 if (useCppInterpreter()) {
5350 GTEST_SKIP();
5351 }
5352
5353 HandleScope scope(thread_);
5354 ASSERT_FALSE(runFromCStr(runtime_, R"(
5355def a(a, b):
5356 return a + b
5357def func():
5358 return a(7, 88)
5359)")
5360 .isError());
5361 Object func(&scope, mainModuleAt(runtime_, "func"));
5362 EXPECT_EQ(thread_->opcodeCount(), 0);
5363 ASSERT_FALSE(Interpreter::call0(thread_, func).isError());
5364 EXPECT_EQ(thread_->opcodeCount(), 0);
5365
5366 runtime_->interpreter()->setOpcodeCounting(true);
5367 runtime_->reinitInterpreter();
5368
5369 word count_before = thread_->opcodeCount();
5370 ASSERT_FALSE(Interpreter::call0(thread_, func).isError());
5371 EXPECT_EQ(thread_->opcodeCount() - count_before, 9);
5372
5373 runtime_->interpreter()->setOpcodeCounting(false);
5374 runtime_->reinitInterpreter();
5375
5376 count_before = thread_->opcodeCount();
5377 ASSERT_FALSE(Interpreter::call0(thread_, func).isError());
5378 EXPECT_EQ(thread_->opcodeCount() - count_before, 0);
5379}
5380
5381static ALIGN_16 RawObject startCounting(Thread* thread, Arguments) {
5382 thread->runtime()->interpreter()->setOpcodeCounting(true);
5383 thread->runtime()->reinitInterpreter();
5384 return NoneType::object();
5385}
5386
5387static ALIGN_16 RawObject stopCounting(Thread* thread, Arguments) {
5388 thread->runtime()->interpreter()->setOpcodeCounting(false);
5389 thread->runtime()->reinitInterpreter();
5390 return NoneType::object();
5391}
5392
5393TEST_F(InterpreterTest, ReinitInterpreterEnablesOpcodeCounting) {
5394 if (useCppInterpreter()) {
5395 GTEST_SKIP();
5396 }
5397
5398 addBuiltin("start_counting", startCounting, {nullptr, 0}, 0);
5399 addBuiltin("stop_counting", stopCounting, {nullptr, 0}, 0);
5400
5401 EXPECT_EQ(thread_->opcodeCount(), 0);
5402 ASSERT_FALSE(runFromCStr(runtime_, R"(
5403def bar():
5404 start_counting()
5405def func():
5406 x = 5
5407 x = 5
5408 x = 5
5409 x = 5
5410 x = 5
5411 x = 5
5412 x = 5
5413 x = 5
5414 x = 5
5415 x = 5
5416 return 5
5417func()
5418bar()
5419func()
5420stop_counting()
5421func()
5422)")
5423 .isError());
5424 // I do not want to hardcode opcode counts for the calls here (since that
5425 // may change in the future). So this just checks that we have at least
5426 // 10*2 = 20 opcodes for a `func()` call, but no more than double that amount
5427 // to make sure we did not consider the `foo()` call before and after
5428 // counting was enabled.
5429 word count = thread_->opcodeCount();
5430 EXPECT_TRUE(20 < count && count < 40);
5431}
5432
5433TEST_F(InterpreterTest, FunctionCallWithNonFunctionRaisesTypeError) {
5434 HandleScope scope(thread_);
5435 Str not_a_func(&scope, Str::empty());
5436 thread_->stackPush(*not_a_func);
5437 EXPECT_TRUE(raised(Interpreter::call(thread_, 0), LayoutId::kTypeError));
5438}
5439
5440TEST_F(InterpreterTest, FunctionCallExWithNonFunctionRaisesTypeError) {
5441 HandleScope scope(thread_);
5442 Str not_a_func(&scope, Str::empty());
5443 thread_->stackPush(*not_a_func);
5444 Tuple empty_args(&scope, runtime_->emptyTuple());
5445 thread_->stackPush(*empty_args);
5446 EXPECT_TRUE(raisedWithStr(Interpreter::callEx(thread_, 0),
5447 LayoutId::kTypeError,
5448 "'str' object is not callable"));
5449}
5450
5451TEST_F(InterpreterTest, CallExWithDescriptorDunderCall) {
5452 ASSERT_FALSE(runFromCStr(runtime_, R"(
5453class FakeFunc:
5454 def __get__(self, obj, owner):
5455 return self
5456 def __call__(self, arg):
5457 return arg
5458
5459class C:
5460 __call__ = FakeFunc()
5461
5462args = ["hello!"]
5463result = C()(*args)
5464)")
5465 .isError());
5466 EXPECT_TRUE(isStrEqualsCStr(mainModuleAt(runtime_, "result"), "hello!"));
5467}
5468
5469TEST_F(InterpreterTest, DoDeleteNameOnDictSubclass) {
5470 ASSERT_FALSE(runFromCStr(runtime_, R"(
5471class MyDict(dict): pass
5472class Meta(type):
5473 @classmethod
5474 def __prepare__(cls, *args, **kwargs):
5475 d = MyDict()
5476 d['x'] = 42
5477 return d
5478class C(metaclass=Meta):
5479 del x
5480)")
5481 .isError());
5482}
5483
5484TEST_F(InterpreterTest, DoStoreNameOnDictSubclass) {
5485 ASSERT_FALSE(runFromCStr(runtime_, R"(
5486class MyDict(dict): pass
5487class Meta(type):
5488 @classmethod
5489 def __prepare__(cls, *args, **kwargs):
5490 return MyDict()
5491class C(metaclass=Meta):
5492 x = 42
5493)")
5494 .isError());
5495}
5496
5497TEST_F(InterpreterTest, StoreSubscr) {
5498 ASSERT_FALSE(runFromCStr(runtime_, R"(
5499l = [0]
5500for i in range(5):
5501 l[0] += i
5502)")
5503 .isError());
5504
5505 HandleScope scope(thread_);
5506 Object l_obj(&scope, testing::mainModuleAt(runtime_, "l"));
5507 ASSERT_TRUE(l_obj.isList());
5508 List l(&scope, *l_obj);
5509 ASSERT_EQ(l.numItems(), 1);
5510 EXPECT_EQ(l.at(0), SmallInt::fromWord(10));
5511}
5512
5513TEST_F(InterpreterTest, StoreSubscrWithListRewritesToStoreSubscrList) {
5514 HandleScope scope(thread_);
5515 ASSERT_FALSE(runFromCStr(runtime_, R"(
5516def foo(l, i):
5517 l[i] = 4
5518 return 100
5519
5520l = [1,2,3]
5521d = {1: -1}
5522)")
5523 .isError());
5524 Function foo(&scope, mainModuleAt(runtime_, "foo"));
5525 MutableBytes rewritten(&scope, foo.rewrittenBytecode());
5526 ASSERT_EQ(rewrittenBytecodeOpAt(rewritten, 3), STORE_SUBSCR_ANAMORPHIC);
5527
5528 List l(&scope, mainModuleAt(runtime_, "l"));
5529 SmallInt key(&scope, SmallInt::fromWord(1));
5530 EXPECT_TRUE(isIntEqualsWord(Interpreter::call2(thread_, foo, l, key), 100));
5531 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten, 3), STORE_SUBSCR_LIST);
5532
5533 // Revert back to caching __getitem__ when a non-list is observed.
5534 Dict d(&scope, mainModuleAt(runtime_, "d"));
5535 EXPECT_TRUE(isIntEqualsWord(Interpreter::call2(thread_, foo, d, key), 100));
5536 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten, 3), STORE_SUBSCR_MONOMORPHIC);
5537}
5538
5539// TODO(bsimmers) Rewrite these exception tests to ensure that the specific
5540// bytecodes we care about are being exercised, so we're not be at the mercy of
5541// compiler optimizations or changes.
5542TEST_F(InterpreterTest, ExceptCatchesException) {
5543 ASSERT_FALSE(runFromCStr(runtime_, R"(
5544n = 0
5545try:
5546 raise RuntimeError("something went wrong")
5547 n = 1
5548except:
5549 if n == 0:
5550 n = 2
5551)")
5552 .isError());
5553
5554 HandleScope scope(thread_);
5555 Object n(&scope, testing::mainModuleAt(runtime_, "n"));
5556 EXPECT_TRUE(isIntEqualsWord(*n, 2));
5557}
5558
5559TEST_F(InterpreterTest, RaiseCrossesFunctions) {
5560 ASSERT_FALSE(runFromCStr(runtime_, R"(
5561def sub():
5562 raise RuntimeError("from sub")
5563
5564def main():
5565 sub()
5566
5567n = 0
5568try:
5569 main()
5570 n = 1
5571except:
5572 if n == 0:
5573 n = 2
5574)")
5575 .isError());
5576
5577 HandleScope scope(thread_);
5578 Object n(&scope, testing::mainModuleAt(runtime_, "n"));
5579 EXPECT_TRUE(isIntEqualsWord(*n, 2));
5580}
5581
5582TEST_F(InterpreterTest, RaiseFromSetsCause) {
5583 ASSERT_FALSE(runFromCStr(runtime_, R"(
5584try:
5585 try:
5586 raise RuntimeError
5587 except Exception as e:
5588 raise TypeError from e
5589except Exception as e:
5590 exc = e
5591)")
5592 .isError());
5593
5594 HandleScope scope(thread_);
5595 Object exc_obj(&scope, testing::mainModuleAt(runtime_, "exc"));
5596 ASSERT_EQ(exc_obj.layoutId(), LayoutId::kTypeError);
5597 BaseException exc(&scope, *exc_obj);
5598 EXPECT_EQ(exc.cause().layoutId(), LayoutId::kRuntimeError);
5599}
5600
5601TEST_F(InterpreterTest, ExceptWithRightTypeCatches) {
5602 ASSERT_FALSE(runFromCStr(runtime_, R"(
5603n = 0
5604try:
5605 raise RuntimeError("whoops")
5606 n = 1
5607except RuntimeError:
5608 if n == 0:
5609 n = 2
5610)")
5611 .isError());
5612
5613 HandleScope scope(thread_);
5614 Object n(&scope, testing::mainModuleAt(runtime_, "n"));
5615 EXPECT_TRUE(isIntEqualsWord(*n, 2));
5616}
5617
5618TEST_F(InterpreterTest, ExceptWithRightTupleTypeCatches) {
5619 ASSERT_FALSE(runFromCStr(runtime_, R"(
5620n = 0
5621try:
5622 raise RuntimeError()
5623 n = 1
5624except (StopIteration, RuntimeError, ImportError):
5625 if n == 0:
5626 n = 2
5627)")
5628 .isError());
5629
5630 HandleScope scope(thread_);
5631 Object n(&scope, testing::mainModuleAt(runtime_, "n"));
5632 EXPECT_TRUE(isIntEqualsWord(*n, 2));
5633}
5634
5635TEST_F(InterpreterTest, ExceptWithWrongTypePasses) {
5636 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, R"(
5637try:
5638 raise RuntimeError("something went wrong")
5639except StopIteration:
5640 pass
5641)"),
5642 LayoutId::kRuntimeError, "something went wrong"));
5643}
5644
5645TEST_F(InterpreterTest, ExceptWithWrongTupleTypePasses) {
5646 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, R"(
5647try:
5648 raise RuntimeError("something went wrong")
5649except (StopIteration, ImportError):
5650 pass
5651)"),
5652 LayoutId::kRuntimeError, "something went wrong"));
5653}
5654
5655TEST_F(InterpreterTest, RaiseTypeCreatesException) {
5656 EXPECT_TRUE(raised(runFromCStr(runtime_, "raise StopIteration"),
5657 LayoutId::kStopIteration));
5658}
5659
5660TEST_F(InterpreterTest, BareRaiseReraises) {
5661 ASSERT_FALSE(runFromCStr(runtime_, R"(
5662class MyError(Exception):
5663 pass
5664
5665inner = None
5666outer = None
5667try:
5668 try:
5669 raise MyError()
5670 except Exception as exc:
5671 inner = exc
5672 raise
5673except Exception as exc:
5674 outer = exc
5675)")
5676 .isError());
5677
5678 HandleScope scope(thread_);
5679 Object my_error(&scope, testing::mainModuleAt(runtime_, "MyError"));
5680 EXPECT_EQ(runtime_->typeOf(*my_error), runtime_->typeAt(LayoutId::kType));
5681 Object inner(&scope, testing::mainModuleAt(runtime_, "inner"));
5682 EXPECT_EQ(runtime_->typeOf(*inner), *my_error);
5683 Object outer(&scope, testing::mainModuleAt(runtime_, "outer"));
5684 EXPECT_EQ(*inner, *outer);
5685}
5686
5687TEST_F(InterpreterTest, ExceptWithNonExceptionTypeRaisesTypeError) {
5688 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, R"(
5689try:
5690 raise RuntimeError
5691except str:
5692 pass
5693)"),
5694 LayoutId::kTypeError,
5695 "catching classes that do not inherit from "
5696 "BaseException is not allowed"));
5697}
5698
5699TEST_F(InterpreterTest, ExceptWithNonExceptionTypeInTupleRaisesTypeError) {
5700 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, R"(
5701try:
5702 raise RuntimeError
5703except (StopIteration, int, RuntimeError):
5704 pass
5705)"),
5706 LayoutId::kTypeError,
5707 "catching classes that do not inherit from "
5708 "BaseException is not allowed"));
5709}
5710
5711TEST_F(InterpreterTest, RaiseWithNoActiveExceptionRaisesRuntimeError) {
5712 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, "raise\n"),
5713 LayoutId::kRuntimeError,
5714 "No active exception to reraise"));
5715}
5716
5717TEST_F(InterpreterTest, LoadAttrWithoutAttrUnwindsAttributeException) {
5718 HandleScope scope(thread_);
5719
5720 // Set up a code object that runs: {}.foo
5721 Object foo(&scope, Runtime::internStrFromCStr(thread_, "foo"));
5722 Tuple names(&scope, runtime_->newTupleWith1(foo));
5723 Tuple consts(&scope, runtime_->emptyTuple());
5724
5725 // load arguments and execute the code
5726 const byte bytecode[] = {BUILD_MAP, 0, LOAD_ATTR, 0};
5727 Code code(&scope, newCodeWithBytesConstsNames(bytecode, consts, names));
5728
5729 // Execute the code and make sure to get the unwinded Error
5730 EXPECT_TRUE(runCode(code).isError());
5731}
5732
5733TEST_F(InterpreterTest, ExplodeCallAcceptsList) {
5734 HandleScope scope(thread_);
5735 ASSERT_FALSE(runFromCStr(runtime_, R"(
5736def f(a, b):
5737 return [b, a]
5738
5739args = ['a', 'b']
5740result = f(*args)
5741)")
5742 .isError());
5743
5744 Object result(&scope, mainModuleAt(runtime_, "result"));
5745 EXPECT_PYLIST_EQ(result, {"b", "a"});
5746}
5747
5748TEST_F(InterpreterTest, ExplodeWithIterableCalls) {
5749 HandleScope scope(thread_);
5750 EXPECT_FALSE(runFromCStr(runtime_, R"(
5751def f(a, b):
5752 return (b, a)
5753def gen():
5754 yield 1
5755 yield 2
5756result = f(*gen())
5757)")
5758 .isError());
5759
5760 Object result_obj(&scope, mainModuleAt(runtime_, "result"));
5761 ASSERT_TRUE(result_obj.isTuple());
5762 Tuple result(&scope, *result_obj);
5763 EXPECT_TRUE(isIntEqualsWord(result.at(0), 2));
5764 EXPECT_TRUE(isIntEqualsWord(result.at(1), 1));
5765}
5766
5767TEST_F(InterpreterTest, ForIterAnamorphicWithBuiltinIterRewritesOpcode) {
5768 HandleScope scope(thread_);
5769 ASSERT_FALSE(runFromCStr(runtime_, R"(
5770def foo(i, s=0):
5771 for a in i:
5772 s += a
5773 return s
5774
5775list_obj = [4,5]
5776dict_obj = {4: "a", 5: "b"}
5777tuple_obj = (4,5)
5778range_obj = range(4,6)
5779str_obj = "45"
5780
5781def gen():
5782 yield 5
5783 yield 7
5784gen_obj = gen()
5785
5786class C:
5787 def __iter__(self):
5788 return D()
5789
5790class D:
5791 def __init__(self):
5792 self.used = False
5793
5794 def __next__(self):
5795 if self.used:
5796 raise StopIteration
5797 self.used = True
5798 return 400
5799
5800user_obj = C()
5801)")
5802 .isError());
5803 Function foo(&scope, mainModuleAt(runtime_, "foo"));
5804 MutableBytes bytecode(&scope, foo.rewrittenBytecode());
5805 ASSERT_EQ(rewrittenBytecodeOpAt(bytecode, 2), FOR_ITER_ANAMORPHIC);
5806
5807 Object arg(&scope, mainModuleAt(runtime_, "list_obj"));
5808 EXPECT_TRUE(isIntEqualsWord(Interpreter::call1(thread_, foo, arg), 9));
5809 EXPECT_EQ(rewrittenBytecodeOpAt(bytecode, 2), FOR_ITER_LIST);
5810
5811 arg = mainModuleAt(runtime_, "dict_obj");
5812 EXPECT_TRUE(isIntEqualsWord(Interpreter::call1(thread_, foo, arg), 9));
5813 EXPECT_EQ(rewrittenBytecodeOpAt(bytecode, 2), FOR_ITER_DICT);
5814
5815 arg = mainModuleAt(runtime_, "tuple_obj");
5816 EXPECT_TRUE(isIntEqualsWord(Interpreter::call1(thread_, foo, arg), 9));
5817 EXPECT_EQ(rewrittenBytecodeOpAt(bytecode, 2), FOR_ITER_TUPLE);
5818
5819 arg = mainModuleAt(runtime_, "range_obj");
5820 EXPECT_TRUE(isIntEqualsWord(Interpreter::call1(thread_, foo, arg), 9));
5821 EXPECT_EQ(rewrittenBytecodeOpAt(bytecode, 2), FOR_ITER_RANGE);
5822
5823 arg = mainModuleAt(runtime_, "str_obj");
5824 Str s(&scope, runtime_->newStrFromCStr(""));
5825 EXPECT_TRUE(isStrEqualsCStr(Interpreter::call2(thread_, foo, arg, s), "45"));
5826 EXPECT_EQ(rewrittenBytecodeOpAt(bytecode, 2), FOR_ITER_STR);
5827
5828 arg = mainModuleAt(runtime_, "gen_obj");
5829 EXPECT_TRUE(isIntEqualsWord(Interpreter::call1(thread_, foo, arg), 12));
5830 EXPECT_EQ(rewrittenBytecodeOpAt(bytecode, 2), FOR_ITER_GENERATOR);
5831
5832 // Resetting the opcode.
5833 arg = mainModuleAt(runtime_, "user_obj");
5834 EXPECT_TRUE(isIntEqualsWord(Interpreter::call1(thread_, foo, arg), 400));
5835 EXPECT_EQ(rewrittenBytecodeOpAt(bytecode, 2), FOR_ITER_MONOMORPHIC);
5836}
5837
5838TEST_F(InterpreterTest, FormatValueCallsDunderStr) {
5839 HandleScope scope(thread_);
5840 ASSERT_FALSE(runFromCStr(runtime_, R"(
5841class C:
5842 def __str__(self):
5843 return "foobar"
5844result = f"{C()!s}"
5845)")
5846 .isError());
5847 Object result(&scope, mainModuleAt(runtime_, "result"));
5848 EXPECT_TRUE(isStrEqualsCStr(*result, "foobar"));
5849}
5850
5851TEST_F(InterpreterTest, FormatValueFallsBackToDunderRepr) {
5852 HandleScope scope(thread_);
5853 ASSERT_FALSE(runFromCStr(runtime_, R"(
5854class C:
5855 def __repr__(self):
5856 return "foobar"
5857result = f"{C()!s}"
5858)")
5859 .isError());
5860 Object result(&scope, mainModuleAt(runtime_, "result"));
5861 EXPECT_TRUE(isStrEqualsCStr(*result, "foobar"));
5862}
5863
5864TEST_F(InterpreterTest, FormatValueCallsDunderRepr) {
5865 HandleScope scope(thread_);
5866 ASSERT_FALSE(runFromCStr(runtime_, R"(
5867class C:
5868 def __repr__(self):
5869 return "foobar"
5870result = f"{C()!r}"
5871)")
5872 .isError());
5873 Object result(&scope, mainModuleAt(runtime_, "result"));
5874 EXPECT_TRUE(isStrEqualsCStr(*result, "foobar"));
5875}
5876
5877TEST_F(InterpreterTest, FormatValueAsciiCallsDunderRepr) {
5878 HandleScope scope(thread_);
5879 ASSERT_FALSE(runFromCStr(runtime_, R"(
5880class C:
5881 def __repr__(self):
5882 return "foobar"
5883result = f"{C()!a}"
5884)")
5885 .isError());
5886 Object result(&scope, mainModuleAt(runtime_, "result"));
5887 EXPECT_TRUE(isStrEqualsCStr(*result, "foobar"));
5888}
5889
5890TEST_F(InterpreterTest, BreakInTryBreaks) {
5891 HandleScope scope(thread_);
5892 ASSERT_FALSE(runFromCStr(runtime_, R"(
5893result = 0
5894for i in range(5):
5895 try:
5896 break
5897 except:
5898 pass
5899result = 10
5900)")
5901 .isError());
5902 Object result(&scope, mainModuleAt(runtime_, "result"));
5903 EXPECT_TRUE(isIntEqualsWord(*result, 10));
5904}
5905
5906TEST_F(InterpreterTest, ContinueInExceptContinues) {
5907 HandleScope scope(thread_);
5908 ASSERT_FALSE(runFromCStr(runtime_, R"(
5909result = 0
5910for i in range(5):
5911 try:
5912 if i == 3:
5913 raise RuntimeError()
5914 except:
5915 result += i
5916 continue
5917 result -= i
5918)")
5919 .isError());
5920 Object result(&scope, mainModuleAt(runtime_, "result"));
5921 EXPECT_TRUE(isIntEqualsWord(*result, -4));
5922}
5923
5924TEST_F(InterpreterTest, RaiseInLoopRaisesRuntimeError) {
5925 HandleScope scope(thread_);
5926 ASSERT_FALSE(runFromCStr(runtime_, R"(
5927result = 0
5928try:
5929 for i in range(5):
5930 result += i
5931 if i == 2:
5932 raise RuntimeError()
5933 result += 100
5934except:
5935 result += 1000
5936)")
5937 .isError());
5938 Object result(&scope, mainModuleAt(runtime_, "result"));
5939 EXPECT_TRUE(isIntEqualsWord(*result, 1003));
5940}
5941
5942TEST_F(InterpreterTest, ReturnInsideTryRunsFinally) {
5943 HandleScope scope(thread_);
5944 ASSERT_FALSE(runFromCStr(runtime_, R"(
5945ran_finally = False
5946
5947def f():
5948 try:
5949 return 56789
5950 finally:
5951 global ran_finally
5952 ran_finally = True
5953
5954result = f()
5955)")
5956 .isError());
5957 Object result(&scope, mainModuleAt(runtime_, "result"));
5958 EXPECT_TRUE(isIntEqualsWord(*result, 56789));
5959
5960 Object ran_finally(&scope, mainModuleAt(runtime_, "ran_finally"));
5961 EXPECT_EQ(*ran_finally, Bool::trueObj());
5962}
5963
5964TEST_F(InterpreterTest, ReturnInsideFinallyOverridesEarlierReturn) {
5965 HandleScope scope(thread_);
5966 ASSERT_FALSE(runFromCStr(runtime_, R"(
5967def f():
5968 try:
5969 return 123
5970 finally:
5971 return 456
5972
5973result = f()
5974)")
5975 .isError());
5976 Object result(&scope, mainModuleAt(runtime_, "result"));
5977 EXPECT_TRUE(isIntEqualsWord(*result, 456));
5978}
5979
5980TEST_F(InterpreterTest, ReturnInsideWithRunsDunderExit) {
5981 HandleScope scope(thread_);
5982 ASSERT_FALSE(runFromCStr(runtime_, R"(
5983sequence = ""
5984
5985class Mgr:
5986 def __enter__(self):
5987 global sequence
5988 sequence += "enter "
5989 def __exit__(self, exc, value, tb):
5990 global sequence
5991 sequence += "exit"
5992
5993def foo():
5994 with Mgr():
5995 global sequence
5996 sequence += "in foo "
5997 return 1234
5998
5999result = foo()
6000)")
6001 .isError());
6002 Object result(&scope, mainModuleAt(runtime_, "result"));
6003 EXPECT_TRUE(isIntEqualsWord(*result, 1234));
6004
6005 Object sequence(&scope, mainModuleAt(runtime_, "sequence"));
6006 EXPECT_TRUE(isStrEqualsCStr(*sequence, "enter in foo exit"));
6007}
6008
6009TEST_F(InterpreterTest,
6010 WithStatementWithManagerWithoutEnterRaisesAttributeError) {
6011 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, R"(
6012with None:
6013 pass
6014)"),
6015 LayoutId::kAttributeError, "__enter__"));
6016}
6017
6018TEST_F(InterpreterTest,
6019 WithStatementWithManagerWithoutExitRaisesAttributeError) {
6020 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, R"(
6021class C:
6022 def __enter__(self):
6023 pass
6024with C():
6025 pass
6026)"),
6027 LayoutId::kAttributeError, "__exit__"));
6028}
6029
6030TEST_F(InterpreterTest,
6031 WithStatementWithManagerEnterRaisingPropagatesException) {
6032 EXPECT_TRUE(raised(runFromCStr(runtime_, R"(
6033class C:
6034 def __enter__(self):
6035 raise UserWarning('')
6036 def __exit__(self, *args):
6037 pass
6038with C():
6039 pass
6040)"),
6041 LayoutId::kUserWarning));
6042}
6043
6044TEST_F(InterpreterTest, WithStatementPropagatesException) {
6045 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, R"(
6046class Mgr:
6047 def __enter__(self):
6048 pass
6049 def __exit__(self, exc, value, tb):
6050 return ()
6051
6052def raises():
6053 raise RuntimeError("It's dead, Jim")
6054
6055with Mgr():
6056 raises()
6057)"),
6058 LayoutId::kRuntimeError, "It's dead, Jim"));
6059}
6060
6061TEST_F(InterpreterTest, WithStatementPassesCorrectExceptionToExit) {
6062 HandleScope scope(thread_);
6063 EXPECT_TRUE(raised(runFromCStr(runtime_, R"(
6064raised_exc = None
6065exit_info = None
6066
6067class Mgr:
6068 def __enter__(self):
6069 pass
6070 def __exit__(self, exc, value, tb):
6071 global exit_info
6072 exit_info = (exc, value, tb)
6073
6074def raises():
6075 global raised_exc
6076 raised_exc = StopIteration("nope")
6077 raise raised_exc
6078
6079with Mgr():
6080 raises()
6081)"),
6082 LayoutId::kStopIteration));
6083 Object exit_info(&scope, mainModuleAt(runtime_, "exit_info"));
6084 ASSERT_TRUE(exit_info.isTuple());
6085 Tuple tuple(&scope, *exit_info);
6086 ASSERT_EQ(tuple.length(), 3);
6087 EXPECT_EQ(tuple.at(0), runtime_->typeAt(LayoutId::kStopIteration));
6088
6089 Object raised_exc(&scope, mainModuleAt(runtime_, "raised_exc"));
6090 EXPECT_EQ(tuple.at(1), *raised_exc);
6091
6092 // TODO(bsimmers): Check traceback once we record them.
6093}
6094
6095TEST_F(InterpreterTest, WithStatementSwallowsException) {
6096 HandleScope scope(thread_);
6097 EXPECT_FALSE(runFromCStr(runtime_, R"(
6098class Mgr:
6099 def __enter__(self):
6100 pass
6101 def __exit__(self, exc, value, tb):
6102 return 1
6103
6104def raises():
6105 raise RuntimeError()
6106
6107with Mgr():
6108 raises()
6109result = 1234
6110)")
6111 .isError());
6112
6113 Object result(&scope, mainModuleAt(runtime_, "result"));
6114 EXPECT_TRUE(isIntEqualsWord(*result, 1234));
6115}
6116
6117TEST_F(InterpreterTest, WithStatementWithRaisingExitRaises) {
6118 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, R"(
6119class Mgr:
6120 def __enter__(self):
6121 pass
6122 def __exit__(self, exc, value, tb):
6123 raise RuntimeError("from exit")
6124
6125def raises():
6126 raise RuntimeError("from raises")
6127
6128with Mgr():
6129 raises()
6130)"),
6131 LayoutId::kRuntimeError, "from exit"));
6132
6133 // TODO(T40269344): Inspect __context__ from the raised exception.
6134}
6135
6136TEST_F(InterpreterTest, LoadNameReturnsSameResultAsCahedValueFromLoadGlobal) {
6137 EXPECT_FALSE(runFromCStr(runtime_, R"(
6138t = 400
6139
6140def update_t():
6141 global t
6142 t = 500
6143
6144def get_t():
6145 global t
6146 return t
6147
6148update_t()
6149load_name_t = t
6150load_global_t = get_t()
6151)")
6152 .isError());
6153 EXPECT_EQ(mainModuleAt(runtime_, "load_name_t"),
6154 mainModuleAt(runtime_, "load_global_t"));
6155}
6156
6157TEST_F(InterpreterTest, LoadGlobalCachedReturnsModuleDictValue) {
6158 HandleScope scope(thread_);
6159 EXPECT_FALSE(runFromCStr(runtime_, R"(
6160a = 400
6161
6162def foo():
6163 return a + a
6164
6165result = foo()
6166)")
6167 .isError());
6168 EXPECT_TRUE(isIntEqualsWord(mainModuleAt(runtime_, "result"), 800));
6169 Function function(&scope, mainModuleAt(runtime_, "foo"));
6170 ASSERT_TRUE(isStrEqualsCStr(
6171 Tuple::cast(Code::cast(function.code()).names()).at(0), "a"));
6172 MutableTuple caches(&scope, function.caches());
6173 EXPECT_TRUE(
6174 isIntEqualsWord(valueCellValue(icLookupGlobalVar(*caches, 0)), 400));
6175}
6176
6177TEST_F(InterpreterTest,
6178 LoadGlobalCachedReturnsBuiltinDictValueAndSetsPlaceholder) {
6179 HandleScope scope(thread_);
6180 EXPECT_FALSE(runFromCStr(runtime_, R"(
6181__builtins__.a = 400
6182
6183def foo():
6184 return a + a
6185
6186result = foo()
6187)")
6188 .isError());
6189 EXPECT_TRUE(isIntEqualsWord(mainModuleAt(runtime_, "result"), 800));
6190 Function function(&scope, mainModuleAt(runtime_, "foo"));
6191 ASSERT_TRUE(isStrEqualsCStr(
6192 Tuple::cast(Code::cast(function.code()).names()).at(0), "a"));
6193 MutableTuple caches(&scope, function.caches());
6194 EXPECT_TRUE(
6195 isIntEqualsWord(valueCellValue(icLookupGlobalVar(*caches, 0)), 400));
6196
6197 Module module(&scope, function.moduleObject());
6198 Object name(&scope, Runtime::internStrFromCStr(thread_, "a"));
6199 RawObject module_entry = NoneType::object();
6200 EXPECT_TRUE(attributeValueCellAt(*module, *name, &module_entry));
6201 ASSERT_TRUE(module_entry.isValueCell());
6202 EXPECT_TRUE(ValueCell::cast(module_entry).isPlaceholder());
6203}
6204
6205TEST_F(InterpreterTest, StoreGlobalCachedInvalidatesCachedBuiltinToBeShadowed) {
6206 HandleScope scope(thread_);
6207 EXPECT_FALSE(runFromCStr(runtime_, R"(
6208__builtins__.a = 400
6209
6210def foo():
6211 return a + a
6212
6213def bar():
6214 # Shadowing `__builtins__.a`.
6215 global a
6216 a = 123
6217
6218foo()
6219bar()
6220)")
6221 .isError());
6222 Function function(&scope, mainModuleAt(runtime_, "foo"));
6223 ASSERT_TRUE(isStrEqualsCStr(
6224 Tuple::cast(Code::cast(function.code()).names()).at(0), "a"));
6225 MutableTuple caches(&scope, function.caches());
6226 EXPECT_TRUE(icLookupGlobalVar(*caches, 0).isNoneType());
6227}
6228
6229TEST_F(InterpreterTest, DeleteGlobalInvalidatesCachedValue) {
6230 HandleScope scope(thread_);
6231 EXPECT_FALSE(runFromCStr(runtime_, R"(
6232a = 400
6233def foo():
6234 return a + a
6235
6236def bar():
6237 global a
6238 del a
6239
6240foo()
6241bar()
6242)")
6243 .isError());
6244 Function function(&scope, mainModuleAt(runtime_, "foo"));
6245 ASSERT_TRUE(isStrEqualsCStr(
6246 Tuple::cast(Code::cast(function.code()).names()).at(0), "a"));
6247 MutableTuple caches(&scope, function.caches());
6248 EXPECT_TRUE(icLookupGlobalVar(*caches, 0).isNoneType());
6249}
6250
6251TEST_F(InterpreterTest, StoreNameInvalidatesCachedBuiltinToBeShadowed) {
6252 HandleScope scope(thread_);
6253 EXPECT_FALSE(runFromCStr(runtime_, R"(
6254__builtins__.a = 400
6255
6256def foo():
6257 return a + a
6258
6259foo()
6260a = 800
6261)")
6262 .isError());
6263 Function function(&scope, mainModuleAt(runtime_, "foo"));
6264 ASSERT_TRUE(isStrEqualsCStr(
6265 Tuple::cast(Code::cast(function.code()).names()).at(0), "a"));
6266 MutableTuple caches(&scope, function.caches());
6267 EXPECT_TRUE(icLookupGlobalVar(*caches, 0).isNoneType());
6268}
6269
6270TEST_F(InterpreterTest, DeleteNameInvalidatesCachedGlobalVar) {
6271 HandleScope scope(thread_);
6272 EXPECT_FALSE(runFromCStr(runtime_, R"(
6273a = 400
6274def foo():
6275 return a + a
6276
6277foo()
6278del a
6279)")
6280 .isError());
6281 Function function(&scope, mainModuleAt(runtime_, "foo"));
6282 ASSERT_TRUE(isStrEqualsCStr(
6283 Tuple::cast(Code::cast(function.code()).names()).at(0), "a"));
6284 MutableTuple caches(&scope, function.caches());
6285 EXPECT_TRUE(icLookupGlobalVar(*caches, 0).isNoneType());
6286}
6287
6288TEST_F(
6289 InterpreterTest,
6290 StoreAttrCachedInvalidatesInstanceOffsetCachesByAssigningTypeDescriptor) {
6291 HandleScope scope(thread_);
6292 EXPECT_FALSE(runFromCStr(runtime_, R"(
6293class C:
6294 def __init__(self):
6295 self.foo = 400
6296
6297def get_foo(c):
6298 return c.foo
6299
6300def do_not_invalidate0():
6301 C.bar = property (lambda self: "data descriptor in a different attr")
6302
6303def do_not_invalidate1():
6304 C.foo = 9999
6305
6306def invalidate():
6307 C.foo = property (lambda self: "data descriptor")
6308
6309c = C()
6310)")
6311 .isError());
6312 Object c(&scope, mainModuleAt(runtime_, "c"));
6313 Function get_foo(&scope, mainModuleAt(runtime_, "get_foo"));
6314 Function do_not_invalidate0(&scope,
6315 mainModuleAt(runtime_, "do_not_invalidate0"));
6316 Function do_not_invalidate1(&scope,
6317 mainModuleAt(runtime_, "do_not_invalidate1"));
6318 Function invalidate(&scope, mainModuleAt(runtime_, "invalidate"));
6319 MutableTuple caches(&scope, get_foo.caches());
6320 // Load the cache
6321 ASSERT_TRUE(icLookupAttr(*caches, 1, c.layoutId()).isErrorNotFound());
6322 ASSERT_TRUE(isIntEqualsWord(Interpreter::call1(thread_, get_foo, c), 400));
6323 ASSERT_TRUE(icLookupAttr(*caches, 1, c.layoutId()).isSmallInt());
6324
6325 // Assign a data descriptor to a different attribute name.
6326 ASSERT_TRUE(Interpreter::call0(thread_, do_not_invalidate0).isNoneType());
6327 EXPECT_TRUE(icLookupAttr(*caches, 1, c.layoutId()).isSmallInt());
6328
6329 // Assign a non-data descriptor to the cache's attribute name.
6330 ASSERT_TRUE(Interpreter::call0(thread_, do_not_invalidate1).isNoneType());
6331 EXPECT_TRUE(icLookupAttr(*caches, 1, c.layoutId()).isSmallInt());
6332
6333 // Assign a data descriptor the cache's attribute name that actually causes
6334 // invalidation.
6335 ASSERT_TRUE(Interpreter::call0(thread_, invalidate).isNoneType());
6336 // Verify that the cache is empty and calling get_foo() returns a fresh value.
6337 EXPECT_TRUE(icLookupAttr(*caches, 1, c.layoutId()).isErrorNotFound());
6338 EXPECT_TRUE(isStrEqualsCStr(Interpreter::call1(thread_, get_foo, c),
6339 "data descriptor"));
6340}
6341
6342TEST_F(InterpreterTest,
6343 StoreAttrCachedInvalidatesTypeAttrCachesByUpdatingTypeAttribute) {
6344 HandleScope scope(thread_);
6345 EXPECT_FALSE(runFromCStr(runtime_, R"(
6346class C:
6347 def foo(self):
6348 return 400;
6349
6350def call_foo(c):
6351 return c.foo()
6352
6353def do_not_invalidate():
6354 C.bar = lambda c: "new type attr"
6355
6356def invalidate():
6357 C.foo = lambda c: "new type attr"
6358
6359old_foo = C.foo
6360c = C()
6361)")
6362 .isError());
6363 Object c(&scope, mainModuleAt(runtime_, "c"));
6364 Function old_foo(&scope, mainModuleAt(runtime_, "old_foo"));
6365 Function call_foo(&scope, mainModuleAt(runtime_, "call_foo"));
6366 Function do_not_invalidate(&scope,
6367 mainModuleAt(runtime_, "do_not_invalidate"));
6368 Function invalidate(&scope, mainModuleAt(runtime_, "invalidate"));
6369 MutableTuple caches(&scope, call_foo.caches());
6370 // Load the cache
6371 ASSERT_TRUE(icLookupAttr(*caches, 1, c.layoutId()).isErrorNotFound());
6372 ASSERT_TRUE(isIntEqualsWord(Interpreter::call1(thread_, call_foo, c), 400));
6373 ASSERT_EQ(icLookupAttr(*caches, 1, c.layoutId()), *old_foo);
6374
6375 // Assign a non-data descriptor to different attribute name.
6376 ASSERT_TRUE(Interpreter::call0(thread_, do_not_invalidate).isNoneType());
6377 ASSERT_EQ(icLookupAttr(*caches, 1, c.layoutId()), *old_foo);
6378
6379 // Invalidate the cache.
6380 ASSERT_TRUE(Interpreter::call0(thread_, invalidate).isNoneType());
6381 // Verify that the cache is empty and calling get_foo() returns a fresh value.
6382 EXPECT_TRUE(icLookupAttr(*caches, 1, c.layoutId()).isErrorNotFound());
6383 EXPECT_TRUE(isStrEqualsCStr(Interpreter::call1(thread_, call_foo, c),
6384 "new type attr"));
6385}
6386
6387TEST_F(
6388 InterpreterTest,
6389 StoreAttrCachedInvalidatesAttributeCachesByUpdatingMatchingTypeAttributesOfSuperclass) {
6390 HandleScope scope(thread_);
6391 EXPECT_FALSE(runFromCStr(runtime_, R"(
6392class B:
6393 pass
6394
6395class C(B):
6396 def __init__(self):
6397 self.foo = 400
6398
6399class D(C):
6400 pass
6401
6402def get_foo(c):
6403 return c.foo
6404
6405def do_not_invalidate():
6406 D.foo = property (lambda self: "data descriptor")
6407
6408def invalidate():
6409 B.foo = property (lambda self: "data descriptor")
6410
6411c = C()
6412)")
6413 .isError());
6414 Type type_b(&scope, mainModuleAt(runtime_, "B"));
6415 Type type_c(&scope, mainModuleAt(runtime_, "C"));
6416 Object c(&scope, mainModuleAt(runtime_, "c"));
6417 Function get_foo(&scope, mainModuleAt(runtime_, "get_foo"));
6418 Function do_not_invalidate(&scope,
6419 mainModuleAt(runtime_, "do_not_invalidate"));
6420 Function invalidate(&scope, mainModuleAt(runtime_, "invalidate"));
6421 MutableTuple caches(&scope, get_foo.caches());
6422 // Load the cache.
6423 ASSERT_TRUE(icLookupAttr(*caches, 1, c.layoutId()).isErrorNotFound());
6424 ASSERT_TRUE(isIntEqualsWord(Interpreter::call1(thread_, get_foo, c), 400));
6425 ASSERT_TRUE(icLookupAttr(*caches, 1, c.layoutId()).isSmallInt());
6426
6427 // Updating a subclass' type attribute doesn't invalidate the cache.
6428 ASSERT_TRUE(Interpreter::call0(thread_, do_not_invalidate).isNoneType());
6429 ASSERT_TRUE(icLookupAttr(*caches, 1, c.layoutId()).isSmallInt());
6430
6431 // Verify that all type dictionaries in C's mro have dependentices to get_foo.
6432 Object foo_name(&scope, Runtime::internStrFromCStr(thread_, "foo"));
6433 Object result(&scope, typeValueCellAt(*type_b, *foo_name));
6434 ASSERT_TRUE(result.isValueCell());
6435 ASSERT_TRUE(ValueCell::cast(*result).dependencyLink().isWeakLink());
6436 EXPECT_EQ(
6437 WeakLink::cast(ValueCell::cast(*result).dependencyLink()).referent(),
6438 *get_foo);
6439
6440 result = typeValueCellAt(*type_c, *foo_name);
6441 ASSERT_TRUE(result.isValueCell());
6442 ASSERT_TRUE(ValueCell::cast(*result).dependencyLink().isWeakLink());
6443 EXPECT_EQ(
6444 WeakLink::cast(ValueCell::cast(*result).dependencyLink()).referent(),
6445 *get_foo);
6446
6447 // Invalidate the cache.
6448 ASSERT_TRUE(Interpreter::call0(thread_, invalidate).isNoneType());
6449 // Verify that the cache is empty and calling get_foo() returns a fresh value.
6450 EXPECT_TRUE(icLookupAttr(*caches, 1, c.layoutId()).isErrorNotFound());
6451 EXPECT_TRUE(isStrEqualsCStr(Interpreter::call1(thread_, get_foo, c),
6452 "data descriptor"));
6453}
6454
6455TEST_F(InterpreterTest, StoreAttrCachedInvalidatesBinaryOpCaches) {
6456 HandleScope scope(thread_);
6457 EXPECT_FALSE(runFromCStr(runtime_, R"(
6458def cache_A_add(a, b):
6459 return a + b
6460
6461class A:
6462 def __add__(self, other): return "A.__add__"
6463
6464class B:
6465 pass
6466
6467def update_A_add():
6468 A.__add__ = lambda self, other: "new A.__add__"
6469
6470a = A()
6471b = B()
6472
6473A_add = A.__add__
6474
6475cache_A_add(a, b)
6476)")
6477 .isError());
6478 Object a(&scope, mainModuleAt(runtime_, "a"));
6479 Object b(&scope, mainModuleAt(runtime_, "b"));
6480 Object a_add(&scope, mainModuleAt(runtime_, "A_add"));
6481
6482 Function cache_a_add(&scope, mainModuleAt(runtime_, "cache_A_add"));
6483 BinaryOpFlags flags_out;
6484 // Ensure that A.__add__ is cached in cache_A_add.
6485 Object cached_in_cache_a_add(
6486 &scope, icLookupBinaryOp(MutableTuple::cast(cache_a_add.caches()), 0,
6487 a.layoutId(), b.layoutId(), &flags_out));
6488 ASSERT_EQ(cached_in_cache_a_add, *a_add);
6489
6490 // Ensure that cache_a_add is being tracked as a dependent from A.__add__.
6491 Type type_a(&scope, mainModuleAt(runtime_, "A"));
6492 Str dunder_add(&scope, runtime_->symbols()->at(ID(__add__)));
6493 ValueCell a_add_value_cell(&scope, typeValueCellAt(*type_a, *dunder_add));
6494 ASSERT_FALSE(a_add_value_cell.isPlaceholder());
6495 EXPECT_EQ(WeakLink::cast(a_add_value_cell.dependencyLink()).referent(),
6496 *cache_a_add);
6497
6498 // Ensure that cache_a_add is being tracked as a dependent from B.__radd__.
6499 Type type_b(&scope, mainModuleAt(runtime_, "B"));
6500 Str dunder_radd(&scope, runtime_->symbols()->at(ID(__radd__)));
6501 ValueCell b_radd_value_cell(&scope, typeValueCellAt(*type_b, *dunder_radd));
6502 ASSERT_TRUE(b_radd_value_cell.isPlaceholder());
6503 EXPECT_EQ(WeakLink::cast(b_radd_value_cell.dependencyLink()).referent(),
6504 *cache_a_add);
6505
6506 // Updating A.__add__ invalidates the cache.
6507 Function invalidate(&scope, mainModuleAt(runtime_, "update_A_add"));
6508 ASSERT_TRUE(Interpreter::call0(thread_, invalidate).isNoneType());
6509 // Verify that the cache is evicted.
6510 EXPECT_TRUE(icLookupBinaryOp(MutableTuple::cast(cache_a_add.caches()), 0,
6511 a.layoutId(), b.layoutId(), &flags_out)
6512 .isErrorNotFound());
6513 // Verify that the dependencies are deleted.
6514 EXPECT_TRUE(a_add_value_cell.dependencyLink().isNoneType());
6515 EXPECT_TRUE(b_radd_value_cell.dependencyLink().isNoneType());
6516}
6517
6518TEST_F(InterpreterTest, StoreAttrCachedInvalidatesCompareOpTypeAttrCaches) {
6519 HandleScope scope(thread_);
6520 EXPECT_FALSE(runFromCStr(runtime_, R"(
6521def cache_compare_op(a, b):
6522 return a >= b
6523
6524class A:
6525 def __le__(self, other): return True
6526
6527 def __ge__(self, other): return True
6528
6529class B:
6530 def __le__(self, other): return True
6531
6532 def __ge__(self, other): return True
6533
6534def do_not_invalidate():
6535 A.__le__ = lambda self, other: False
6536 B.__ge__ = lambda self, other: False
6537
6538def invalidate():
6539 A.__ge__ = lambda self, other: False
6540
6541a = A()
6542b = B()
6543A__ge__ = A.__ge__
6544c = cache_compare_op(a, b)
6545)")
6546 .isError());
6547 Object a(&scope, mainModuleAt(runtime_, "a"));
6548 Object b(&scope, mainModuleAt(runtime_, "b"));
6549 Object type_a__dunder_ge(&scope, mainModuleAt(runtime_, "A__ge__"));
6550
6551 // Ensure that A.__ge__ is cached.
6552 Function cache_compare_op(&scope, mainModuleAt(runtime_, "cache_compare_op"));
6553 MutableTuple caches(&scope, cache_compare_op.caches());
6554 BinaryOpFlags flags_out;
6555 Object cached(&scope, icLookupBinaryOp(*caches, 0, a.layoutId(), b.layoutId(),
6556 &flags_out));
6557 ASSERT_EQ(*cached, *type_a__dunder_ge);
6558
6559 // Updating irrelevant compare op dunder functions doesn't trigger
6560 // invalidation.
6561 Function do_not_invalidate(&scope,
6562 mainModuleAt(runtime_, "do_not_invalidate"));
6563 ASSERT_TRUE(Interpreter::call0(thread_, do_not_invalidate).isNoneType());
6564 cached = icLookupBinaryOp(*caches, 0, a.layoutId(), b.layoutId(), &flags_out);
6565 EXPECT_EQ(*cached, *type_a__dunder_ge);
6566
6567 // Updating relevant compare op dunder functions triggers invalidation.
6568 Function invalidate(&scope, mainModuleAt(runtime_, "invalidate"));
6569 ASSERT_TRUE(Interpreter::call0(thread_, invalidate).isNoneType());
6570 ASSERT_TRUE(
6571 icLookupBinaryOp(*caches, 0, a.layoutId(), b.layoutId(), &flags_out)
6572 .isErrorNotFound());
6573}
6574
6575TEST_F(InterpreterTest, StoreAttrCachedInvalidatesInplaceOpCaches) {
6576 HandleScope scope(thread_);
6577 EXPECT_FALSE(runFromCStr(runtime_, R"(
6578def cache_A_iadd(a, b):
6579 a += b
6580
6581class A:
6582 def __iadd__(self, other): return "A.__iadd__"
6583
6584class B:
6585 pass
6586
6587def update_A_iadd():
6588 A.__iadd__ = lambda self, other: "new A.__add__"
6589
6590a = A()
6591b = B()
6592
6593A_iadd = A.__iadd__
6594
6595cache_A_iadd(a, b)
6596)")
6597 .isError());
6598 Object a(&scope, mainModuleAt(runtime_, "a"));
6599 Object b(&scope, mainModuleAt(runtime_, "b"));
6600 Object a_iadd(&scope, mainModuleAt(runtime_, "A_iadd"));
6601
6602 Function cache_a_iadd(&scope, mainModuleAt(runtime_, "cache_A_iadd"));
6603 BinaryOpFlags flags_out;
6604 // Ensure that A.__iadd__ is cached in cache_A_iadd.
6605 Object cached_in_cache_a_iadd(
6606 &scope, icLookupBinaryOp(MutableTuple::cast(cache_a_iadd.caches()), 0,
6607 a.layoutId(), b.layoutId(), &flags_out));
6608 ASSERT_EQ(cached_in_cache_a_iadd, *a_iadd);
6609
6610 // Ensure that cache_a_iadd is being tracked as a dependent from A.__iadd__.
6611 Type type_a(&scope, mainModuleAt(runtime_, "A"));
6612 Str dunder_iadd(&scope, runtime_->symbols()->at(ID(__iadd__)));
6613 ValueCell a_iadd_value_cell(&scope, typeValueCellAt(*type_a, *dunder_iadd));
6614 ASSERT_FALSE(a_iadd_value_cell.isPlaceholder());
6615 EXPECT_EQ(WeakLink::cast(a_iadd_value_cell.dependencyLink()).referent(),
6616 *cache_a_iadd);
6617
6618 Str dunder_add(&scope, runtime_->symbols()->at(ID(__add__)));
6619 ValueCell a_add_value_cell(&scope, typeValueCellAt(*type_a, *dunder_add));
6620 ASSERT_TRUE(a_add_value_cell.isPlaceholder());
6621 EXPECT_EQ(WeakLink::cast(a_add_value_cell.dependencyLink()).referent(),
6622 *cache_a_iadd);
6623
6624 // Ensure that cache_a_iadd is being tracked as a dependent from B.__riadd__.
6625 Type type_b(&scope, mainModuleAt(runtime_, "B"));
6626 Str dunder_radd(&scope, runtime_->symbols()->at(ID(__radd__)));
6627 ValueCell b_radd_value_cell(&scope, typeValueCellAt(*type_b, *dunder_radd));
6628 ASSERT_TRUE(b_radd_value_cell.isPlaceholder());
6629 EXPECT_EQ(WeakLink::cast(b_radd_value_cell.dependencyLink()).referent(),
6630 *cache_a_iadd);
6631
6632 // Updating A.__iadd__ invalidates the cache.
6633 Function invalidate(&scope, mainModuleAt(runtime_, "update_A_iadd"));
6634 ASSERT_TRUE(Interpreter::call0(thread_, invalidate).isNoneType());
6635 // Verify that the cache is evicted.
6636 EXPECT_TRUE(icLookupBinaryOp(MutableTuple::cast(cache_a_iadd.caches()), 0,
6637 a.layoutId(), b.layoutId(), &flags_out)
6638 .isErrorNotFound());
6639 // Verify that the dependencies are deleted.
6640 EXPECT_TRUE(a_iadd_value_cell.dependencyLink().isNoneType());
6641 EXPECT_TRUE(a_add_value_cell.dependencyLink().isNoneType());
6642 EXPECT_TRUE(b_radd_value_cell.dependencyLink().isNoneType());
6643}
6644
6645TEST_F(InterpreterTest, LoadMethodLoadingMethodFollowedByCallMethod) {
6646 HandleScope scope(thread_);
6647 EXPECT_FALSE(runFromCStr(runtime_, R"(
6648class C:
6649 def __init__(self):
6650 self.val = 40
6651
6652 def compute(self, arg0, arg1):
6653 return self.val + arg0 + arg1
6654
6655def test():
6656 return c.compute(10, 20)
6657
6658c = C()
6659)")
6660 .isError());
6661 Function test_function(&scope, mainModuleAt(runtime_, "test"));
6662 MutableBytes bytecode(&scope, test_function.rewrittenBytecode());
6663 ASSERT_EQ(rewrittenBytecodeOpAt(bytecode, 1), LOAD_METHOD_ANAMORPHIC);
6664 ASSERT_EQ(rewrittenBytecodeOpAt(bytecode, 4), CALL_METHOD);
6665
6666 EXPECT_TRUE(isIntEqualsWord(Interpreter::call0(thread_, test_function), 70));
6667}
6668
6669TEST_F(InterpreterTest, LoadMethodInitDoesNotCacheInstanceAttributes) {
6670 HandleScope scope(thread_);
6671 EXPECT_FALSE(runFromCStr(runtime_, R"(
6672class C:
6673 def __init__(self):
6674 self.val = 40
6675
6676def foo(a, b): return a + b
6677c = C()
6678c.compute = foo
6679def test():
6680 return c.compute(10, 20)
6681)")
6682 .isError());
6683 Function test_function(&scope, mainModuleAt(runtime_, "test"));
6684 MutableBytes bytecode(&scope, test_function.rewrittenBytecode());
6685 ASSERT_EQ(rewrittenBytecodeOpAt(bytecode, 1), LOAD_METHOD_ANAMORPHIC);
6686 ASSERT_EQ(rewrittenBytecodeOpAt(bytecode, 4), CALL_METHOD);
6687
6688 Object c(&scope, mainModuleAt(runtime_, "c"));
6689 LayoutId layout_id = c.layoutId();
6690 MutableTuple caches(&scope, test_function.caches());
6691 // Cache miss.
6692 ASSERT_TRUE(
6693 icLookupAttr(*caches, rewrittenBytecodeArgAt(bytecode, 1), layout_id)
6694 .isErrorNotFound());
6695 EXPECT_TRUE(isIntEqualsWord(Interpreter::call0(thread_, test_function), 30));
6696
6697 // Still cache miss.
6698 ASSERT_TRUE(
6699 icLookupAttr(*caches, rewrittenBytecodeArgAt(bytecode, 1), layout_id)
6700 .isErrorNotFound());
6701}
6702
6703TEST_F(InterpreterTest, LoadMethodCachedCachingFunctionFollowedByCallMethod) {
6704 HandleScope scope(thread_);
6705 EXPECT_FALSE(runFromCStr(runtime_, R"(
6706class C:
6707 def __init__(self):
6708 self.val = 40
6709
6710 def compute(self, arg0, arg1):
6711 return self.val + arg0 + arg1
6712
6713def test():
6714 return c.compute(10, 20)
6715
6716c = C()
6717)")
6718 .isError());
6719 Function test_function(&scope, mainModuleAt(runtime_, "test"));
6720 MutableBytes bytecode(&scope, test_function.rewrittenBytecode());
6721 ASSERT_EQ(rewrittenBytecodeOpAt(bytecode, 1), LOAD_METHOD_ANAMORPHIC);
6722 ASSERT_EQ(rewrittenBytecodeOpAt(bytecode, 4), CALL_METHOD);
6723
6724 // Cache miss.
6725 Object c(&scope, mainModuleAt(runtime_, "c"));
6726 LayoutId layout_id = c.layoutId();
6727 MutableTuple caches(&scope, test_function.caches());
6728 ASSERT_TRUE(
6729 icLookupAttr(*caches, rewrittenBytecodeArgAt(bytecode, 1), layout_id)
6730 .isErrorNotFound());
6731 EXPECT_TRUE(isIntEqualsWord(Interpreter::call0(thread_, test_function), 70));
6732
6733 // Cache hit.
6734 ASSERT_TRUE(
6735 icLookupAttr(*caches, rewrittenBytecodeArgAt(bytecode, 1), layout_id)
6736 .isFunction());
6737 EXPECT_TRUE(isIntEqualsWord(Interpreter::call0(thread_, test_function), 70));
6738}
6739
6740TEST_F(InterpreterTest, LoadMethodCachedModuleFunction) {
6741 EXPECT_FALSE(runFromCStr(runtime_, R"(
6742import sys
6743
6744class C:
6745 def getdefaultencoding(self):
6746 return "no-utf8"
6747
6748def test(obj):
6749 return obj.getdefaultencoding()
6750
6751cached = sys.getdefaultencoding
6752obj = C()
6753)")
6754 .isError());
6755 HandleScope scope(thread_);
6756 Function test_function(&scope, mainModuleAt(runtime_, "test"));
6757 Function expected_value(&scope, mainModuleAt(runtime_, "cached"));
6758 MutableBytes bytecode(&scope, test_function.rewrittenBytecode());
6759 ASSERT_EQ(rewrittenBytecodeOpAt(bytecode, 1), LOAD_METHOD_ANAMORPHIC);
6760 ASSERT_EQ(rewrittenBytecodeOpAt(bytecode, 2), CALL_METHOD);
6761
6762 // Cache miss.
6763 Module sys_module(&scope, runtime_->findModuleById(ID(sys)));
6764 MutableTuple caches(&scope, test_function.caches());
6765 word cache_index =
6766 rewrittenBytecodeCacheAt(bytecode, 1) * kIcPointersPerEntry;
6767 Object key(&scope, caches.at(cache_index + kIcEntryKeyOffset));
6768 EXPECT_EQ(*key, NoneType::object());
6769
6770 // Call.
6771 EXPECT_TRUE(isStrEqualsCStr(
6772 Interpreter::call1(thread_, test_function, sys_module), "utf-8"));
6773 EXPECT_EQ(rewrittenBytecodeOpAt(bytecode, 1), LOAD_METHOD_MODULE);
6774
6775 // Cache hit.
6776 key = caches.at(cache_index + kIcEntryKeyOffset);
6777 EXPECT_TRUE(isIntEqualsWord(*key, sys_module.id()));
6778 Object value(&scope, caches.at(cache_index + kIcEntryValueOffset));
6779 ASSERT_TRUE(value.isValueCell());
6780 EXPECT_EQ(ValueCell::cast(*value).value(), *expected_value);
6781
6782 // Call.
6783 EXPECT_TRUE(isStrEqualsCStr(
6784 Interpreter::call1(thread_, test_function, sys_module), "utf-8"));
6785
6786 // Rewrite.
6787 Object obj(&scope, mainModuleAt(runtime_, "obj"));
6788 EXPECT_TRUE(isStrEqualsCStr(Interpreter::call1(thread_, test_function, obj),
6789 "no-utf8"));
6790 EXPECT_EQ(rewrittenBytecodeOpAt(bytecode, 1), LOAD_METHOD_INSTANCE_FUNCTION);
6791 key = caches.at(cache_index + kIcEntryKeyOffset);
6792 EXPECT_FALSE(key.isValueCell());
6793}
6794
6795TEST_F(InterpreterTest,
6796 LoadMethodWithModuleAndNonFunctionRewritesToLoadMethodModule) {
6797 EXPECT_FALSE(runFromCStr(runtime_, R"(
6798import sys
6799
6800class C:
6801 def __call__(self):
6802 return 123
6803
6804mymodule = type(sys)("mymodule")
6805mymodule.getdefaultencoding = C()
6806
6807def test(obj):
6808 return obj.getdefaultencoding()
6809)")
6810 .isError());
6811 HandleScope scope(thread_);
6812 Function test_function(&scope, mainModuleAt(runtime_, "test"));
6813 MutableBytes bytecode(&scope, test_function.rewrittenBytecode());
6814 Module mymodule(&scope, mainModuleAt(runtime_, "mymodule"));
6815 ASSERT_EQ(rewrittenBytecodeOpAt(bytecode, 1), LOAD_METHOD_ANAMORPHIC);
6816 ASSERT_EQ(rewrittenBytecodeOpAt(bytecode, 2), CALL_METHOD);
6817
6818 // Cache miss.
6819 MutableTuple caches(&scope, test_function.caches());
6820 word cache_index =
6821 rewrittenBytecodeCacheAt(bytecode, 1) * kIcPointersPerEntry;
6822 Object key(&scope, caches.at(cache_index + kIcEntryKeyOffset));
6823 EXPECT_EQ(*key, NoneType::object());
6824
6825 // Call.
6826 EXPECT_TRUE(isIntEqualsWord(
6827 Interpreter::call1(thread_, test_function, mymodule), 123));
6828 EXPECT_EQ(rewrittenBytecodeOpAt(bytecode, 1), LOAD_METHOD_MODULE);
6829}
6830
6831TEST_F(InterpreterTest, LoadMethodModuleGetsEvicted) {
6832 EXPECT_FALSE(runFromCStr(runtime_, R"(
6833import sys
6834
6835def test(obj):
6836 return obj.getdefaultencoding()
6837)")
6838 .isError());
6839 HandleScope scope(thread_);
6840 Function test_function(&scope, mainModuleAt(runtime_, "test"));
6841 MutableBytes bytecode(&scope, test_function.rewrittenBytecode());
6842 ASSERT_EQ(rewrittenBytecodeOpAt(bytecode, 1), LOAD_METHOD_ANAMORPHIC);
6843 ASSERT_EQ(rewrittenBytecodeOpAt(bytecode, 2), CALL_METHOD);
6844
6845 // Cache miss.
6846 Module sys_module(&scope, runtime_->findModuleById(ID(sys)));
6847 MutableTuple caches(&scope, test_function.caches());
6848 word cache_index =
6849 rewrittenBytecodeCacheAt(bytecode, 1) * kIcPointersPerEntry;
6850 Object key(&scope, caches.at(cache_index + kIcEntryKeyOffset));
6851 EXPECT_EQ(*key, NoneType::object());
6852
6853 // Call.
6854 EXPECT_TRUE(isStrEqualsCStr(
6855 Interpreter::call1(thread_, test_function, sys_module), "utf-8"));
6856 EXPECT_EQ(rewrittenBytecodeOpAt(bytecode, 1), LOAD_METHOD_MODULE);
6857
6858 // Update module.
6859 Str getdefaultencoding(
6860 &scope, runtime_->internStrFromCStr(thread_, "getdefaultencoding"));
6861 Object result(&scope,
6862 moduleDeleteAttribute(thread_, sys_module, getdefaultencoding));
6863 ASSERT_TRUE(result.isNoneType());
6864
6865 // Cache is empty.
6866 key = caches.at(cache_index + kIcEntryKeyOffset);
6867 EXPECT_TRUE(key.isNoneType());
6868
6869 // Cache miss.
6870 EXPECT_TRUE(
6871 raisedWithStr(Interpreter::call1(thread_, test_function, sys_module),
6872 LayoutId::kAttributeError,
6873 "module 'sys' has no attribute 'getdefaultencoding'"));
6874
6875 // Bytecode gets rewritten after next call.
6876 EXPECT_EQ(rewrittenBytecodeOpAt(bytecode, 1), LOAD_METHOD_ANAMORPHIC);
6877}
6878
6879TEST_F(InterpreterTest, LoadMethodModuleWithModuleMismatchUpdatesCache) {
6880 EXPECT_FALSE(runFromCStr(runtime_, R"(
6881import sys
6882
6883mymodule = type(sys)("mymodule")
6884mymodule.getdefaultencoding = lambda: "hello"
6885
6886def test(obj):
6887 return obj.getdefaultencoding()
6888)")
6889 .isError());
6890 HandleScope scope(thread_);
6891 Function test_function(&scope, mainModuleAt(runtime_, "test"));
6892 Module mymodule(&scope, mainModuleAt(runtime_, "mymodule"));
6893 MutableBytes bytecode(&scope, test_function.rewrittenBytecode());
6894 ASSERT_EQ(rewrittenBytecodeOpAt(bytecode, 1), LOAD_METHOD_ANAMORPHIC);
6895 ASSERT_EQ(rewrittenBytecodeOpAt(bytecode, 2), CALL_METHOD);
6896
6897 // Cache miss.
6898 Module sys_module(&scope, runtime_->findModuleById(ID(sys)));
6899 MutableTuple caches(&scope, test_function.caches());
6900 word cache_index =
6901 rewrittenBytecodeCacheAt(bytecode, 1) * kIcPointersPerEntry;
6902 Object key(&scope, caches.at(cache_index + kIcEntryKeyOffset));
6903 EXPECT_EQ(*key, NoneType::object());
6904
6905 // Call.
6906 EXPECT_TRUE(isStrEqualsCStr(
6907 Interpreter::call1(thread_, test_function, sys_module), "utf-8"));
6908 EXPECT_EQ(rewrittenBytecodeOpAt(bytecode, 1), LOAD_METHOD_MODULE);
6909
6910 // Cache contains sys.
6911 key = caches.at(cache_index + kIcEntryKeyOffset);
6912 EXPECT_TRUE(isIntEqualsWord(*key, sys_module.id()));
6913
6914 // Call.
6915 EXPECT_TRUE(isStrEqualsCStr(
6916 Interpreter::call1(thread_, test_function, mymodule), "hello"));
6917 EXPECT_EQ(rewrittenBytecodeOpAt(bytecode, 1), LOAD_METHOD_MODULE);
6918
6919 // Cache contains mymodule.
6920 key = caches.at(cache_index + kIcEntryKeyOffset);
6921 EXPECT_TRUE(isIntEqualsWord(*key, mymodule.id()));
6922}
6923
6924TEST_F(InterpreterTest, LoadMethodModuleGetsScannedInOtherEviction) {
6925 EXPECT_FALSE(runFromCStr(runtime_, R"(
6926import sys
6927
6928class C:
6929 def __init__(self):
6930 self.foo = 123
6931
6932c = C()
6933
6934def test(obj):
6935 c.foo
6936 return obj.getdefaultencoding()
6937
6938def invalidate():
6939 C.foo = property(lambda self: 456)
6940)")
6941 .isError());
6942 HandleScope scope(thread_);
6943 Function test_function(&scope, mainModuleAt(runtime_, "test"));
6944 Function invalidate(&scope, mainModuleAt(runtime_, "invalidate"));
6945 MutableBytes bytecode(&scope, test_function.rewrittenBytecode());
6946 ASSERT_EQ(rewrittenBytecodeOpAt(bytecode, 4), LOAD_METHOD_ANAMORPHIC);
6947 ASSERT_EQ(rewrittenBytecodeOpAt(bytecode, 5), CALL_METHOD);
6948
6949 // Cache miss.
6950 Module sys_module(&scope, runtime_->findModuleById(ID(sys)));
6951 MutableTuple caches(&scope, test_function.caches());
6952 word cache_index =
6953 rewrittenBytecodeCacheAt(bytecode, 4) * kIcPointersPerEntry;
6954 Object key(&scope, caches.at(cache_index + kIcEntryKeyOffset));
6955 EXPECT_EQ(*key, NoneType::object());
6956
6957 // Call.
6958 EXPECT_TRUE(isStrEqualsCStr(
6959 Interpreter::call1(thread_, test_function, sys_module), "utf-8"));
6960 EXPECT_EQ(rewrittenBytecodeOpAt(bytecode, 4), LOAD_METHOD_MODULE);
6961
6962 // Evict the caches in the `test' function.
6963 ASSERT_TRUE(Interpreter::call0(thread_, invalidate).isNoneType());
6964
6965 // The LOAD_METHOD_MODULE is not affected.
6966 EXPECT_EQ(rewrittenBytecodeOpAt(bytecode, 4), LOAD_METHOD_MODULE);
6967 EXPECT_TRUE(isStrEqualsCStr(
6968 Interpreter::call1(thread_, test_function, sys_module), "utf-8"));
6969 EXPECT_EQ(rewrittenBytecodeOpAt(bytecode, 4), LOAD_METHOD_MODULE);
6970}
6971
6972TEST_F(InterpreterTest, LoadMethodCachedDoesNotCacheProperty) {
6973 HandleScope scope(thread_);
6974 EXPECT_FALSE(runFromCStr(runtime_, R"(
6975class C:
6976 @property
6977 def foo(self): return lambda: 1234
6978
6979def call_foo(c):
6980 return c.foo()
6981
6982c = C()
6983call_foo(c)
6984)")
6985 .isError());
6986 Function call_foo(&scope, mainModuleAt(runtime_, "call_foo"));
6987 MutableBytes bytecode(&scope, call_foo.rewrittenBytecode());
6988 ASSERT_EQ(rewrittenBytecodeOpAt(bytecode, 1), LOAD_METHOD_ANAMORPHIC);
6989 ASSERT_EQ(rewrittenBytecodeOpAt(bytecode, 2), CALL_METHOD);
6990
6991 MutableTuple caches(&scope, call_foo.caches());
6992 EXPECT_TRUE(icIsCacheEmpty(caches, rewrittenBytecodeArgAt(bytecode, 1)));
6993}
6994
6995TEST_F(InterpreterTest, LoadMethodUpdatesOpcodeWithCaching) {
6996 HandleScope scope(thread_);
6997 EXPECT_FALSE(runFromCStr(runtime_, R"(
6998class C:
6999 def foo(self):
7000 return 4
7001
7002class D:
7003 def foo(self):
7004 return -4
7005
7006def test(c):
7007 return c.foo()
7008
7009c = C()
7010d = D()
7011)")
7012 .isError());
7013 Function test_function(&scope, mainModuleAt(runtime_, "test"));
7014 Object c(&scope, mainModuleAt(runtime_, "c"));
7015 Object d(&scope, mainModuleAt(runtime_, "d"));
7016 MutableBytes bytecode(&scope, test_function.rewrittenBytecode());
7017 ASSERT_EQ(rewrittenBytecodeOpAt(bytecode, 1), LOAD_METHOD_ANAMORPHIC);
7018 ASSERT_TRUE(
7019 isIntEqualsWord(Interpreter::call1(thread_, test_function, c), 4));
7020 EXPECT_EQ(rewrittenBytecodeOpAt(bytecode, 1), LOAD_METHOD_INSTANCE_FUNCTION);
7021
7022 ASSERT_TRUE(
7023 isIntEqualsWord(Interpreter::call1(thread_, test_function, d), -4));
7024 EXPECT_EQ(rewrittenBytecodeOpAt(bytecode, 1), LOAD_METHOD_POLYMORPHIC);
7025}
7026
7027TEST_F(InterpreterTest, DoLoadImmediate) {
7028 HandleScope scope(thread_);
7029 EXPECT_FALSE(runFromCStr(runtime_, R"(
7030def test():
7031 return None
7032
7033result = test()
7034)")
7035 .isError());
7036 Function test_function(&scope, mainModuleAt(runtime_, "test"));
7037 MutableBytes bytecode(&scope, test_function.rewrittenBytecode());
7038 // Verify that rewriting replaces LOAD_CONST for LOAD_IMMEDIATE.
7039 EXPECT_EQ(rewrittenBytecodeOpAt(bytecode, 0), LOAD_IMMEDIATE);
7040 EXPECT_EQ(rewrittenBytecodeArgAt(bytecode, 0),
7041 static_cast<byte>(NoneType::object().raw()));
7042 EXPECT_TRUE(mainModuleAt(runtime_, "result").isNoneType());
7043}
7044
7045TEST_F(InterpreterTest, LoadAttrCachedInsertsExecutingFunctionAsDependent) {
7046 EXPECT_FALSE(runFromCStr(runtime_, R"(
7047class C:
7048 def __init__(self):
7049 self.foo = 400
7050
7051def cache_attribute(c):
7052 return c.foo
7053
7054c = C()
7055)")
7056 .isError());
7057 HandleScope scope(thread_);
7058 Type type_c(&scope, mainModuleAt(runtime_, "C"));
7059 Object c(&scope, mainModuleAt(runtime_, "c"));
7060 Function cache_attribute(&scope, mainModuleAt(runtime_, "cache_attribute"));
7061 MutableTuple caches(&scope, cache_attribute.caches());
7062 ASSERT_EQ(caches.length(), 2 * kIcPointersPerEntry);
7063
7064 // Load the cache.
7065 ASSERT_TRUE(icLookupAttr(*caches, 1, c.layoutId()).isErrorNotFound());
7066 ASSERT_TRUE(
7067 isIntEqualsWord(Interpreter::call1(thread_, cache_attribute, c), 400));
7068 ASSERT_TRUE(icLookupAttr(*caches, 1, c.layoutId()).isSmallInt());
7069
7070 // Verify that cache_attribute function is added as a dependent.
7071 Object foo_name(&scope, Runtime::internStrFromCStr(thread_, "foo"));
7072 ValueCell value_cell(&scope, typeValueCellAt(*type_c, *foo_name));
7073 ASSERT_TRUE(value_cell.dependencyLink().isWeakLink());
7074 EXPECT_EQ(WeakLink::cast(value_cell.dependencyLink()).referent(),
7075 *cache_attribute);
7076}
7077
7078TEST_F(InterpreterTest, LoadAttrDunderClassRewritesToLoadType) {
7079 EXPECT_FALSE(runFromCStr(runtime_, R"(
7080class C:
7081 pass
7082
7083class D:
7084 @property
7085 def __class__(self):
7086 return 123
7087
7088def cache_attribute(c):
7089 return c.__class__
7090
7091c = C()
7092d = D()
7093)")
7094 .isError());
7095 HandleScope scope(thread_);
7096 Type type_c(&scope, mainModuleAt(runtime_, "C"));
7097 Object c(&scope, mainModuleAt(runtime_, "c"));
7098 Function cache_attribute(&scope, mainModuleAt(runtime_, "cache_attribute"));
7099 MutableBytes bytecode(&scope, cache_attribute.rewrittenBytecode());
7100 ASSERT_EQ(rewrittenBytecodeOpAt(bytecode, 1), LOAD_ATTR_ANAMORPHIC);
7101 MutableTuple caches(&scope, cache_attribute.caches());
7102 ASSERT_EQ(caches.length(), 2 * kIcPointersPerEntry);
7103
7104 // Load the cache.
7105 ASSERT_TRUE(icLookupAttr(*caches, 1, c.layoutId()).isErrorNotFound());
7106 ASSERT_EQ(Interpreter::call1(thread_, cache_attribute, c), *type_c);
7107 // It won't be in the cache.
7108 EXPECT_TRUE(icLookupAttr(*caches, 1, c.layoutId()).isErrorNotFound());
7109 ASSERT_EQ(rewrittenBytecodeOpAt(bytecode, 1), LOAD_TYPE);
7110
7111 // Verify that cache_attribute function is added as a dependent.
7112 Object attr_name(&scope, Runtime::internStrFromCStr(thread_, "__class__"));
7113 ValueCell value_cell(&scope, typeValueCellAt(*type_c, *attr_name));
7114 ASSERT_TRUE(value_cell.dependencyLink().isWeakLink());
7115 EXPECT_EQ(WeakLink::cast(value_cell.dependencyLink()).referent(),
7116 *cache_attribute);
7117
7118 // Invalidate the cache with something that overrides __class__.
7119 Object d(&scope, mainModuleAt(runtime_, "d"));
7120 ASSERT_TRUE(
7121 isIntEqualsWord(Interpreter::call1(thread_, cache_attribute, d), 123));
7122 ASSERT_EQ(rewrittenBytecodeOpAt(bytecode, 1), LOAD_ATTR_INSTANCE_PROPERTY);
7123}
7124
7125TEST_F(InterpreterTest, LoadAttrDunderClassWithPropertyDoesNotCache) {
7126 EXPECT_FALSE(runFromCStr(runtime_, R"(
7127class C:
7128 @property
7129 def __class__(self):
7130 return 5
7131
7132def cache_attribute(c):
7133 return c.__class__
7134
7135c = C()
7136)")
7137 .isError());
7138 HandleScope scope(thread_);
7139 Object c(&scope, mainModuleAt(runtime_, "c"));
7140 Function cache_attribute(&scope, mainModuleAt(runtime_, "cache_attribute"));
7141 MutableBytes bytecode(&scope, cache_attribute.rewrittenBytecode());
7142 ASSERT_EQ(rewrittenBytecodeOpAt(bytecode, 1), LOAD_ATTR_ANAMORPHIC);
7143 MutableTuple caches(&scope, cache_attribute.caches());
7144 ASSERT_EQ(caches.length(), 2 * kIcPointersPerEntry);
7145
7146 // Load the cache.
7147 ASSERT_TRUE(icLookupAttr(*caches, 1, c.layoutId()).isErrorNotFound());
7148 ASSERT_TRUE(
7149 isIntEqualsWord(Interpreter::call1(thread_, cache_attribute, c), 5));
7150 // It is a cached property getter, not LOAD_TYPE.
7151 EXPECT_TRUE(icLookupAttr(*caches, 1, c.layoutId()).isFunction());
7152 EXPECT_EQ(rewrittenBytecodeOpAt(bytecode, 1), LOAD_ATTR_INSTANCE_PROPERTY);
7153}
7154
7155TEST_F(InterpreterTest,
7156 LoadAttrInstanceOnInvalidatedCacheUpdatesCacheCorrectly) {
7157 EXPECT_FALSE(runFromCStr(runtime_, R"(
7158class C:
7159 def __init__(self):
7160 self.foo = "instance attribute"
7161
7162def cache_attribute(c):
7163 return c.foo
7164
7165def invalidate_attribute(c):
7166 C.foo = property(lambda e: "descriptor attribute")
7167
7168c = C()
7169)")
7170 .isError());
7171 HandleScope scope(thread_);
7172 Object c(&scope, mainModuleAt(runtime_, "c"));
7173 Function cache_attribute(&scope, mainModuleAt(runtime_, "cache_attribute"));
7174 MutableBytes bytecode(&scope, cache_attribute.rewrittenBytecode());
7175 ASSERT_EQ(rewrittenBytecodeOpAt(bytecode, 1), LOAD_ATTR_ANAMORPHIC);
7176 Tuple caches(&scope, cache_attribute.caches());
7177 ASSERT_EQ(caches.length(), 2 * kIcPointersPerEntry);
7178
7179 // Load the cache.
7180 ASSERT_EQ(icCurrentState(*caches, 1), ICState::kAnamorphic);
7181 ASSERT_TRUE(isStrEqualsCStr(Interpreter::call1(thread_, cache_attribute, c),
7182 "instance attribute"));
7183 ASSERT_EQ(icCurrentState(*caches, 1), ICState::kMonomorphic);
7184 ASSERT_EQ(rewrittenBytecodeOpAt(bytecode, 1), LOAD_ATTR_INSTANCE);
7185
7186 // Invalidate the cache.
7187 Function invalidate_attribute(&scope,
7188 mainModuleAt(runtime_, "invalidate_attribute"));
7189 ASSERT_TRUE(
7190 Interpreter::call1(thread_, invalidate_attribute, c).isNoneType());
7191 ASSERT_EQ(icCurrentState(*caches, 1), ICState::kAnamorphic);
7192 ASSERT_EQ(rewrittenBytecodeOpAt(bytecode, 1), LOAD_ATTR_INSTANCE);
7193
7194 // Load the cache again.
7195 EXPECT_TRUE(isStrEqualsCStr(Interpreter::call1(thread_, cache_attribute, c),
7196 "descriptor attribute"));
7197 EXPECT_EQ(icCurrentState(*caches, 1), ICState::kMonomorphic);
7198 EXPECT_EQ(rewrittenBytecodeOpAt(bytecode, 1), LOAD_ATTR_INSTANCE_PROPERTY);
7199}
7200
7201TEST_F(InterpreterTest, StoreAttrCachedInsertsExecutingFunctionAsDependent) {
7202 EXPECT_FALSE(runFromCStr(runtime_, R"(
7203class C:
7204 def __init__(self):
7205 self.foo = 400
7206
7207def cache_attribute(c):
7208 c.foo = 500
7209
7210c = C()
7211)")
7212 .isError());
7213 HandleScope scope(thread_);
7214 Type type_c(&scope, mainModuleAt(runtime_, "C"));
7215 Object c(&scope, mainModuleAt(runtime_, "c"));
7216 Function cache_attribute(&scope, mainModuleAt(runtime_, "cache_attribute"));
7217 MutableTuple caches(&scope, cache_attribute.caches());
7218 ASSERT_EQ(caches.length(), 2 * kIcPointersPerEntry);
7219
7220 // Load the cache.
7221 ASSERT_TRUE(icLookupAttr(*caches, 1, c.layoutId()).isErrorNotFound());
7222 ASSERT_TRUE(Interpreter::call1(thread_, cache_attribute, c).isNoneType());
7223 ASSERT_TRUE(icLookupAttr(*caches, 1, c.layoutId()).isSmallInt());
7224
7225 // Verify that cache_attribute function is added as a dependent.
7226 Object foo_name(&scope, Runtime::internStrFromCStr(thread_, "foo"));
7227 ValueCell value_cell(&scope, typeValueCellAt(*type_c, *foo_name));
7228 ASSERT_TRUE(value_cell.dependencyLink().isWeakLink());
7229 EXPECT_EQ(WeakLink::cast(value_cell.dependencyLink()).referent(),
7230 *cache_attribute);
7231}
7232
7233TEST_F(InterpreterTest, StoreAttrsCausingShadowingInvalidatesCache) {
7234 EXPECT_FALSE(runFromCStr(runtime_, R"(
7235class A:
7236 def foo(self): return 40
7237
7238class B(A):
7239 def foo(self): return 50
7240
7241class C(B):
7242 pass
7243
7244def function_that_caches_attr_lookup(a, b, c):
7245 return a.foo() + b.foo() + c.foo()
7246
7247def func_that_causes_shadowing_of_attr_a():
7248 A.foo = lambda self: 300
7249
7250def func_that_causes_shadowing_of_attr_b():
7251 B.foo = lambda self: 200
7252
7253
7254# Caching A.foo and B.foo in cache_attribute.
7255a = A()
7256b = B()
7257c = C()
7258a_foo = A.foo
7259b_foo = B.foo
7260function_that_caches_attr_lookup(a, b, c)
7261)")
7262 .isError());
7263 HandleScope scope(thread_);
7264 Type type_a(&scope, mainModuleAt(runtime_, "A"));
7265 Type type_b(&scope, mainModuleAt(runtime_, "B"));
7266 Type type_c(&scope, mainModuleAt(runtime_, "C"));
7267 Object a(&scope, mainModuleAt(runtime_, "a"));
7268 Object b(&scope, mainModuleAt(runtime_, "b"));
7269 Object c(&scope, mainModuleAt(runtime_, "c"));
7270 Function function_that_caches_attr_lookup(
7271 &scope, mainModuleAt(runtime_, "function_that_caches_attr_lookup"));
7272 MutableTuple caches(&scope, function_that_caches_attr_lookup.caches());
7273 // 0: global variable
7274 // 1: a.foo
7275 // 2: b.foo
7276 // 3: binary op cache
7277 // 4: c.foo
7278 // 5, binary op cache
7279 Function a_foo(&scope, mainModuleAt(runtime_, "a_foo"));
7280 Function b_foo(&scope, mainModuleAt(runtime_, "b_foo"));
7281 ASSERT_EQ(caches.length(), 6 * kIcPointersPerEntry);
7282 ASSERT_EQ(icLookupAttr(*caches, 1, a.layoutId()), *a_foo);
7283 ASSERT_EQ(icLookupAttr(*caches, 2, b.layoutId()), *b_foo);
7284 ASSERT_EQ(icLookupAttr(*caches, 4, c.layoutId()), *b_foo);
7285
7286 // Verify that function_that_caches_attr_lookup cached the attribute lookup
7287 // and appears on the dependency list of A.foo.
7288 Object foo_name(&scope, Runtime::internStrFromCStr(thread_, "foo"));
7289 ValueCell foo_in_a(&scope, typeValueCellAt(*type_a, *foo_name));
7290 ASSERT_TRUE(foo_in_a.dependencyLink().isWeakLink());
7291 ASSERT_EQ(WeakLink::cast(foo_in_a.dependencyLink()).referent(),
7292 *function_that_caches_attr_lookup);
7293
7294 // Verify that function_that_caches_attr_lookup cached the attribute lookup
7295 // and appears on the dependency list of B.foo.
7296 ValueCell foo_in_b(&scope, typeValueCellAt(*type_b, *foo_name));
7297 ASSERT_TRUE(foo_in_b.dependencyLink().isWeakLink());
7298 ASSERT_EQ(WeakLink::cast(foo_in_b.dependencyLink()).referent(),
7299 *function_that_caches_attr_lookup);
7300
7301 // Verify that function_that_caches_attr_lookup cached the attribute lookup
7302 // and appears on the dependency list of C.foo.
7303 ValueCell foo_in_c(&scope, typeValueCellAt(*type_c, *foo_name));
7304 ASSERT_TRUE(foo_in_c.dependencyLink().isWeakLink());
7305 ASSERT_EQ(WeakLink::cast(foo_in_c.dependencyLink()).referent(),
7306 *function_that_caches_attr_lookup);
7307
7308 // Change the class A so that any caches that reference A.foo are invalidated.
7309 Function func_that_causes_shadowing_of_attr_a(
7310 &scope, mainModuleAt(runtime_, "func_that_causes_shadowing_of_attr_a"));
7311 ASSERT_TRUE(Interpreter::call0(thread_, func_that_causes_shadowing_of_attr_a)
7312 .isNoneType());
7313 // Verify that the cache for A.foo is cleared out, and dependent does not
7314 // depend on A.foo anymore.
7315 EXPECT_TRUE(icLookupAttr(*caches, 1, a.layoutId()).isErrorNotFound());
7316 EXPECT_TRUE(foo_in_a.dependencyLink().isNoneType());
7317 // Check that any lookups of B have not been invalidated.
7318 EXPECT_EQ(icLookupAttr(*caches, 2, b.layoutId()), *b_foo);
7319 EXPECT_EQ(WeakLink::cast(foo_in_b.dependencyLink()).referent(),
7320 *function_that_caches_attr_lookup);
7321 // Check that any lookups of C have not been invalidated.
7322 EXPECT_EQ(icLookupAttr(*caches, 4, c.layoutId()), *b_foo);
7323 EXPECT_EQ(WeakLink::cast(foo_in_c.dependencyLink()).referent(),
7324 *function_that_caches_attr_lookup);
7325
7326 // Invalidate the cache for B.foo.
7327 Function func_that_causes_shadowing_of_attr_b(
7328 &scope, mainModuleAt(runtime_, "func_that_causes_shadowing_of_attr_b"));
7329 ASSERT_TRUE(Interpreter::call0(thread_, func_that_causes_shadowing_of_attr_b)
7330 .isNoneType());
7331 // Check that caches for A are still invalidated.
7332 EXPECT_TRUE(icLookupAttr(*caches, 1, a.layoutId()).isErrorNotFound());
7333 EXPECT_TRUE(foo_in_a.dependencyLink().isNoneType());
7334 // Check that caches for B and C got just invalidated since they refer to
7335 // B.foo.
7336 EXPECT_TRUE(icLookupAttr(*caches, 2, b.layoutId()).isErrorNotFound());
7337 EXPECT_TRUE(foo_in_b.dependencyLink().isNoneType());
7338 EXPECT_TRUE(icLookupAttr(*caches, 4, c.layoutId()).isErrorNotFound());
7339 EXPECT_TRUE(foo_in_c.dependencyLink().isNoneType());
7340}
7341
7342TEST_F(InterpreterTest, IntrinsicWithSlowPathDoesNotAlterStack) {
7343 HandleScope scope(thread_);
7344 Object obj(&scope, runtime_->newList());
7345 thread_->stackPush(*obj);
7346 Module module(&scope, runtime_->findModuleById(ID(_builtins)));
7347 Function tuple_len_func(&scope,
7348 moduleAtById(thread_, module, ID(_tuple_len)));
7349 IntrinsicFunction function =
7350 reinterpret_cast<IntrinsicFunction>(tuple_len_func.intrinsic());
7351 ASSERT_NE(function, nullptr);
7352 ASSERT_FALSE(function(thread_));
7353 EXPECT_EQ(thread_->stackPeek(0), *obj);
7354}
7355
7356TEST_F(JitTest, CompileFunctionSetsEntryAsm) {
7357 if (useCppInterpreter()) {
7358 GTEST_SKIP();
7359 }
7360 HandleScope scope(thread_);
7361 Object obj1(&scope, NoneType::object());
7362 Tuple consts(&scope, runtime_->newTupleWith1(obj1));
7363 const byte bytecode[] = {
7364 LOAD_CONST,
7365 0,
7366 RETURN_VALUE,
7367 0,
7368 };
7369 Code code(&scope, newCodeWithBytesConsts(bytecode, consts));
7370 Object qualname(&scope, Str::empty());
7371 Module module(&scope, findMainModule(runtime_));
7372 Function function(
7373 &scope, runtime_->newFunctionWithCode(thread_, qualname, code, module));
7374 void* entry_before = function.entryAsm();
7375 compileFunction(thread_, function);
7376 EXPECT_NE(function.entryAsm(), entry_before);
7377}
7378
7379// Create the function:
7380// def caller():
7381// return foo()
7382// without rewriting the bytecode.
7383static RawObject createTrampolineFunction(Thread* thread) {
7384 HandleScope scope(thread);
7385 Str foo(&scope, Runtime::internStrFromCStr(thread, "foo"));
7386 Runtime* runtime = thread->runtime();
7387 Tuple names(&scope, runtime->newTupleWith1(foo));
7388 Tuple consts(&scope, runtime->emptyTuple());
7389 const byte bytecode[] = {
7390 LOAD_GLOBAL, 0, CALL_FUNCTION, 0, RETURN_VALUE, 0,
7391 };
7392 Code code(&scope, newCodeWithBytesConstsNames(bytecode, consts, names));
7393 Str qualname(&scope, runtime->newStrFromCStr("qualname"));
7394 Module module(&scope, findMainModule(runtime));
7395 Function function(
7396 &scope, runtime->newFunctionWithCode(thread, qualname, code, module));
7397 Bytes bytecode_bytes(&scope, runtime->newBytesWithAll(bytecode));
7398 MutableBytes rewritten(&scope, expandBytecode(thread, bytecode_bytes));
7399 function.setRewrittenBytecode(*rewritten);
7400 return *function;
7401}
7402
7403// Create the function:
7404// def caller():
7405// return foo(obj)
7406// where obj is the parameter to createTrampolineFunction1, without rewriting
7407// the bytecode.
7408static RawObject createTrampolineFunction1(Thread* thread, const Object& obj) {
7409 HandleScope scope(thread);
7410 Str foo(&scope, Runtime::internStrFromCStr(thread, "foo"));
7411 Runtime* runtime = thread->runtime();
7412 Tuple names(&scope, runtime->newTupleWith1(foo));
7413 Tuple consts(&scope, runtime->newTupleWith1(obj));
7414 const byte bytecode[] = {
7415 LOAD_GLOBAL, 0, LOAD_CONST, 0, CALL_FUNCTION, 1, RETURN_VALUE, 0,
7416 };
7417 Code code(&scope, newCodeWithBytesConstsNames(bytecode, consts, names));
7418 Str qualname(&scope, runtime->newStrFromCStr("qualname"));
7419 Module module(&scope, findMainModule(runtime));
7420 Function function(
7421 &scope, runtime->newFunctionWithCode(thread, qualname, code, module));
7422 Bytes bytecode_bytes(&scope, runtime->newBytesWithAll(bytecode));
7423 MutableBytes rewritten(&scope, expandBytecode(thread, bytecode_bytes));
7424 function.setRewrittenBytecode(*rewritten);
7425 return *function;
7426}
7427
7428// Create the function:
7429// def caller():
7430// return foo(left, right)
7431// where obj is the parameter to createTrampolineFunction2, without rewriting
7432// the bytecode.
7433static RawObject createTrampolineFunction2(Thread* thread, const Object& left,
7434 const Object& right) {
7435 HandleScope scope(thread);
7436 Str foo(&scope, Runtime::internStrFromCStr(thread, "foo"));
7437 Runtime* runtime = thread->runtime();
7438 Tuple names(&scope, runtime->newTupleWith1(foo));
7439 Tuple consts(&scope, runtime->newTupleWith2(left, right));
7440 const byte bytecode[] = {
7441 LOAD_GLOBAL, 0, LOAD_CONST, 0, LOAD_CONST, 1,
7442 CALL_FUNCTION, 2, RETURN_VALUE, 0,
7443 };
7444 Code code(&scope, newCodeWithBytesConstsNames(bytecode, consts, names));
7445 Str qualname(&scope, runtime->newStrFromCStr("qualname"));
7446 Module module(&scope, findMainModule(runtime));
7447 Function function(
7448 &scope, runtime->newFunctionWithCode(thread, qualname, code, module));
7449 Bytes bytecode_bytes(&scope, runtime->newBytesWithAll(bytecode));
7450 MutableBytes rewritten(&scope, expandBytecode(thread, bytecode_bytes));
7451 function.setRewrittenBytecode(*rewritten);
7452 return *function;
7453}
7454
7455// Replace the bytecode with an empty bytes object after a function has been
7456// compiled so that the function cannot be interpreted normally. This is useful
7457// for ensuring that we are running the JITed function.
7458static void setEmptyBytecode(const Function& function) {
7459 function.setRewrittenBytecode(SmallBytes::empty());
7460}
7461
7462static RawObject compileAndCallJITFunction(Thread* thread,
7463 const Function& function) {
7464 HandleScope scope(thread);
7465 Function caller(&scope, createTrampolineFunction(thread));
7466 compileFunction(thread, function);
7467 setEmptyBytecode(function);
7468 return Interpreter::call0(thread, caller);
7469}
7470
7471static RawObject compileAndCallJITFunction1(Thread* thread,
7472 const Function& function,
7473 const Object& param) {
7474 HandleScope scope(thread);
7475 Function caller(&scope, createTrampolineFunction1(thread, param));
7476 compileFunction(thread, function);
7477 setEmptyBytecode(function);
7478 return Interpreter::call0(thread, caller);
7479}
7480
7481static RawObject compileAndCallJITFunction2(Thread* thread,
7482 const Function& function,
7483 const Object& param1,
7484 const Object& param2) {
7485 HandleScope scope(thread);
7486 Function caller(&scope, createTrampolineFunction2(thread, param1, param2));
7487 compileFunction(thread, function);
7488 setEmptyBytecode(function);
7489 return Interpreter::call0(thread, caller);
7490}
7491
7492TEST_F(JitTest, CallFunctionWithTooFewArgsRaisesTypeError) {
7493 if (useCppInterpreter()) {
7494 GTEST_SKIP();
7495 }
7496 EXPECT_FALSE(runFromCStr(runtime_, R"(
7497def foo(obj):
7498 return (1, 2, 3)
7499)")
7500 .isError());
7501
7502 HandleScope scope(thread_);
7503 Function function(&scope, mainModuleAt(runtime_, "foo"));
7504 EXPECT_TRUE(containsBytecode(function, LOAD_CONST));
7505 Object result(&scope, compileAndCallJITFunction(thread_, function));
7506 EXPECT_TRUE(
7507 raisedWithStr(*result, LayoutId::kTypeError,
7508 "'foo' takes min 1 positional arguments but 0 given"));
7509}
7510
7511// TODO(T89353729): Add test for calling a JIT function with a signal set.
7512
7513TEST_F(JitTest, LoadConstLoadsConstant) {
7514 if (useCppInterpreter()) {
7515 GTEST_SKIP();
7516 }
7517 EXPECT_FALSE(runFromCStr(runtime_, R"(
7518def foo():
7519 return (1, 2, 3)
7520)")
7521 .isError());
7522
7523 HandleScope scope(thread_);
7524 Function function(&scope, mainModuleAt(runtime_, "foo"));
7525 EXPECT_TRUE(containsBytecode(function, LOAD_CONST));
7526 Object result_obj(&scope, compileAndCallJITFunction(thread_, function));
7527 ASSERT_TRUE(result_obj.isTuple());
7528 Tuple result(&scope, *result_obj);
7529 ASSERT_EQ(result.length(), 3);
7530 EXPECT_TRUE(isIntEqualsWord(result.at(0), 1));
7531 EXPECT_TRUE(isIntEqualsWord(result.at(1), 2));
7532 EXPECT_TRUE(isIntEqualsWord(result.at(2), 3));
7533}
7534
7535TEST_F(JitTest, LoadBoolLoadsBool) {
7536 if (useCppInterpreter()) {
7537 GTEST_SKIP();
7538 }
7539 EXPECT_FALSE(runFromCStr(runtime_, R"(
7540def foo():
7541 return True
7542)")
7543 .isError());
7544
7545 HandleScope scope(thread_);
7546 Function function(&scope, mainModuleAt(runtime_, "foo"));
7547 EXPECT_TRUE(containsBytecode(function, LOAD_BOOL));
7548 Object result(&scope, compileAndCallJITFunction(thread_, function));
7549 EXPECT_EQ(*result, Bool::trueObj());
7550}
7551
7552TEST_F(JitTest, LoadImmediateLoadsImmediate) {
7553 if (useCppInterpreter()) {
7554 GTEST_SKIP();
7555 }
7556 EXPECT_FALSE(runFromCStr(runtime_, R"(
7557def foo():
7558 return None
7559)")
7560 .isError());
7561
7562 HandleScope scope(thread_);
7563 Function function(&scope, mainModuleAt(runtime_, "foo"));
7564 EXPECT_TRUE(containsBytecode(function, LOAD_IMMEDIATE));
7565 Object result(&scope, compileAndCallJITFunction(thread_, function));
7566 EXPECT_EQ(*result, NoneType::object());
7567}
7568
7569TEST_F(JitTest, LoadFastReverseLoadsLocal) {
7570 if (useCppInterpreter()) {
7571 GTEST_SKIP();
7572 }
7573 EXPECT_FALSE(runFromCStr(runtime_, R"(
7574def foo():
7575 var = 5
7576 return var
7577)")
7578 .isError());
7579
7580 HandleScope scope(thread_);
7581 Function function(&scope, mainModuleAt(runtime_, "foo"));
7582 EXPECT_TRUE(containsBytecode(function, LOAD_FAST_REVERSE_UNCHECKED));
7583 Object result(&scope, compileAndCallJITFunction(thread_, function));
7584 EXPECT_TRUE(isIntEqualsWord(*result, 5));
7585}
7586
7587TEST_F(JitTest, LoadFastReverseWithUnboundNameRaisesUnboundLocalError) {
7588 if (useCppInterpreter()) {
7589 GTEST_SKIP();
7590 }
7591 EXPECT_FALSE(runFromCStr(runtime_, R"(
7592def foo():
7593 var = 5
7594 del var
7595 return var
7596)")
7597 .isError());
7598
7599 HandleScope scope(thread_);
7600 Function function(&scope, mainModuleAt(runtime_, "foo"));
7601 EXPECT_TRUE(containsBytecode(function, LOAD_FAST_REVERSE));
7602 void* entry_before = function.entryAsm();
7603 compileFunction(thread_, function);
7604 EXPECT_NE(function.entryAsm(), entry_before);
7605 Function deopt_caller(&scope, createTrampolineFunction(thread_));
7606 Object result(&scope, Interpreter::call0(thread_, deopt_caller));
7607 EXPECT_TRUE(raised(*result, LayoutId::kUnboundLocalError));
7608 EXPECT_EQ(function.entryAsm(), entry_before);
7609}
7610
7611TEST_F(JitTest, LoadFastReverseUncheckedLoadsParameter) {
7612 if (useCppInterpreter()) {
7613 GTEST_SKIP();
7614 }
7615 EXPECT_FALSE(runFromCStr(runtime_, R"(
7616def foo(param):
7617 return param
7618)")
7619 .isError());
7620
7621 HandleScope scope(thread_);
7622 Function function(&scope, mainModuleAt(runtime_, "foo"));
7623 EXPECT_TRUE(containsBytecode(function, LOAD_FAST_REVERSE_UNCHECKED));
7624 Object param(&scope, SmallInt::fromWord(123));
7625 Object result(&scope, compileAndCallJITFunction1(thread_, function, param));
7626 EXPECT_TRUE(isIntEqualsWord(*result, 123));
7627}
7628
7629TEST_F(JitTest, StoreFastReverseWritesToParameter) {
7630 if (useCppInterpreter()) {
7631 GTEST_SKIP();
7632 }
7633 EXPECT_FALSE(runFromCStr(runtime_, R"(
7634def foo(param):
7635 param = 3
7636 return param
7637)")
7638 .isError());
7639
7640 HandleScope scope(thread_);
7641 Function function(&scope, mainModuleAt(runtime_, "foo"));
7642 EXPECT_TRUE(containsBytecode(function, LOAD_FAST_REVERSE_UNCHECKED));
7643 Object param(&scope, SmallInt::fromWord(123));
7644 Object result(&scope, compileAndCallJITFunction1(thread_, function, param));
7645 EXPECT_TRUE(isIntEqualsWord(*result, 3));
7646}
7647
7648TEST_F(JitTest, CompareIsWithSameObjectsReturnsTrue) {
7649 if (useCppInterpreter()) {
7650 GTEST_SKIP();
7651 }
7652 EXPECT_FALSE(runFromCStr(runtime_, R"(
7653def foo():
7654 return 123 is 123
7655)")
7656 .isError());
7657
7658 HandleScope scope(thread_);
7659 Function function(&scope, mainModuleAt(runtime_, "foo"));
7660 EXPECT_TRUE(containsBytecode(function, COMPARE_IS));
7661 Object result(&scope, compileAndCallJITFunction(thread_, function));
7662 EXPECT_EQ(*result, Bool::trueObj());
7663}
7664
7665TEST_F(JitTest, CompareIsWithDifferentObjectsReturnsFalse) {
7666 if (useCppInterpreter()) {
7667 GTEST_SKIP();
7668 }
7669 EXPECT_FALSE(runFromCStr(runtime_, R"(
7670def foo():
7671 return 123 is 124
7672)")
7673 .isError());
7674
7675 HandleScope scope(thread_);
7676 Function function(&scope, mainModuleAt(runtime_, "foo"));
7677 EXPECT_TRUE(containsBytecode(function, COMPARE_IS));
7678 Object result(&scope, compileAndCallJITFunction(thread_, function));
7679 EXPECT_EQ(*result, Bool::falseObj());
7680}
7681
7682TEST_F(JitTest, CompareIsNotWithSameObjectsReturnsFalse) {
7683 if (useCppInterpreter()) {
7684 GTEST_SKIP();
7685 }
7686 EXPECT_FALSE(runFromCStr(runtime_, R"(
7687def foo():
7688 return 123 is not 123
7689)")
7690 .isError());
7691
7692 HandleScope scope(thread_);
7693 Function function(&scope, mainModuleAt(runtime_, "foo"));
7694 EXPECT_TRUE(containsBytecode(function, COMPARE_IS_NOT));
7695 Object result(&scope, compileAndCallJITFunction(thread_, function));
7696 EXPECT_EQ(*result, Bool::falseObj());
7697}
7698
7699TEST_F(JitTest, CompareIsNotWithDifferentObjectsReturnsTrue) {
7700 if (useCppInterpreter()) {
7701 GTEST_SKIP();
7702 }
7703 EXPECT_FALSE(runFromCStr(runtime_, R"(
7704def foo():
7705 return 123 is not 124
7706)")
7707 .isError());
7708
7709 HandleScope scope(thread_);
7710 Function function(&scope, mainModuleAt(runtime_, "foo"));
7711 EXPECT_TRUE(containsBytecode(function, COMPARE_IS_NOT));
7712 Object result(&scope, compileAndCallJITFunction(thread_, function));
7713 EXPECT_EQ(*result, Bool::trueObj());
7714}
7715
7716TEST_F(JitTest, BinaryAddSmallintWithSmallIntsReturnsInt) {
7717 if (useCppInterpreter()) {
7718 GTEST_SKIP();
7719 }
7720 EXPECT_FALSE(runFromCStr(runtime_, R"(
7721def foo(left, right):
7722 return left + right
7723
7724# Rewrite BINARY_OP_ANAMORPHIC to BINARY_ADD_SMALLINT
7725foo(1, 1)
7726)")
7727 .isError());
7728
7729 HandleScope scope(thread_);
7730 Function function(&scope, mainModuleAt(runtime_, "foo"));
7731 EXPECT_TRUE(containsBytecode(function, BINARY_ADD_SMALLINT));
7732 Object left(&scope, SmallInt::fromWord(5));
7733 Object right(&scope, SmallInt::fromWord(10));
7734 Object result(&scope,
7735 compileAndCallJITFunction2(thread_, function, left, right));
7736 EXPECT_TRUE(isIntEqualsWord(*result, 15));
7737}
7738
7739TEST_F(JitTest, BinaryAndSmallintWithSmallIntsReturnsInt) {
7740 if (useCppInterpreter()) {
7741 GTEST_SKIP();
7742 }
7743 EXPECT_FALSE(runFromCStr(runtime_, R"(
7744def foo(left, right):
7745 return left & right
7746
7747# Rewrite BINARY_OP_ANAMORPHIC to BINARY_AND_SMALLINT
7748foo(1, 1)
7749)")
7750 .isError());
7751
7752 HandleScope scope(thread_);
7753 Function function(&scope, mainModuleAt(runtime_, "foo"));
7754 EXPECT_TRUE(containsBytecode(function, BINARY_AND_SMALLINT));
7755 Object left(&scope, SmallInt::fromWord(0xff));
7756 Object right(&scope, SmallInt::fromWord(0x0f));
7757 Object result(&scope,
7758 compileAndCallJITFunction2(thread_, function, left, right));
7759 EXPECT_TRUE(isIntEqualsWord(*result, 0x0f));
7760}
7761
7762TEST_F(JitTest, BinaryOrSmallintWithSmallIntsReturnsInt) {
7763 if (useCppInterpreter()) {
7764 GTEST_SKIP();
7765 }
7766 EXPECT_FALSE(runFromCStr(runtime_, R"(
7767def foo(left, right):
7768 return left | right
7769
7770# Rewrite BINARY_OP_ANAMORPHIC to BINARY_OR_SMALLINT
7771foo(1, 1)
7772)")
7773 .isError());
7774
7775 HandleScope scope(thread_);
7776 Function function(&scope, mainModuleAt(runtime_, "foo"));
7777 EXPECT_TRUE(containsBytecode(function, BINARY_OR_SMALLINT));
7778 Object left(&scope, SmallInt::fromWord(0xf0));
7779 Object right(&scope, SmallInt::fromWord(0x0f));
7780 Object result(&scope,
7781 compileAndCallJITFunction2(thread_, function, left, right));
7782 EXPECT_TRUE(isIntEqualsWord(*result, 0xff));
7783}
7784
7785TEST_F(JitTest, BinarySubSmallintWithSmallIntsReturnsInt) {
7786 if (useCppInterpreter()) {
7787 GTEST_SKIP();
7788 }
7789 EXPECT_FALSE(runFromCStr(runtime_, R"(
7790def foo(left, right):
7791 return left - right
7792
7793# Rewrite BINARY_OP_ANAMORPHIC to BINARY_SUB_SMALLINT
7794foo(1, 1)
7795)")
7796 .isError());
7797
7798 HandleScope scope(thread_);
7799 Function function(&scope, mainModuleAt(runtime_, "foo"));
7800 EXPECT_TRUE(containsBytecode(function, BINARY_SUB_SMALLINT));
7801 Object left(&scope, SmallInt::fromWord(7));
7802 Object right(&scope, SmallInt::fromWord(4));
7803 Object result(&scope,
7804 compileAndCallJITFunction2(thread_, function, left, right));
7805 EXPECT_TRUE(isIntEqualsWord(*result, 3));
7806}
7807
7808TEST_F(JitTest, CompareEqSmallintWithSmallIntsReturnsBool) {
7809 if (useCppInterpreter()) {
7810 GTEST_SKIP();
7811 }
7812 EXPECT_FALSE(runFromCStr(runtime_, R"(
7813def foo(left, right):
7814 return left == right
7815
7816# Rewrite BINARY_OP_ANAMORPHIC to COMPARE_EQ_SMALLINT
7817foo(1, 1)
7818)")
7819 .isError());
7820
7821 HandleScope scope(thread_);
7822 Function function(&scope, mainModuleAt(runtime_, "foo"));
7823 EXPECT_TRUE(containsBytecode(function, COMPARE_EQ_SMALLINT));
7824 Object left(&scope, SmallInt::fromWord(7));
7825 Object right(&scope, SmallInt::fromWord(4));
7826 Object result(&scope,
7827 compileAndCallJITFunction2(thread_, function, left, right));
7828 EXPECT_EQ(*result, Bool::falseObj());
7829}
7830
7831TEST_F(JitTest, CompareNeSmallintWithSmallIntsReturnsBool) {
7832 if (useCppInterpreter()) {
7833 GTEST_SKIP();
7834 }
7835 EXPECT_FALSE(runFromCStr(runtime_, R"(
7836def foo(left, right):
7837 return left != right
7838
7839# Rewrite BINARY_OP_ANAMORPHIC to COMPARE_NE_SMALLINT
7840foo(1, 1)
7841)")
7842 .isError());
7843
7844 HandleScope scope(thread_);
7845 Function function(&scope, mainModuleAt(runtime_, "foo"));
7846 EXPECT_TRUE(containsBytecode(function, COMPARE_NE_SMALLINT));
7847 Object left(&scope, SmallInt::fromWord(7));
7848 Object right(&scope, SmallInt::fromWord(4));
7849 Object result(&scope,
7850 compileAndCallJITFunction2(thread_, function, left, right));
7851 EXPECT_EQ(*result, Bool::trueObj());
7852}
7853
7854TEST_F(JitTest, CompareGtSmallintWithSmallIntsReturnsBool) {
7855 if (useCppInterpreter()) {
7856 GTEST_SKIP();
7857 }
7858 EXPECT_FALSE(runFromCStr(runtime_, R"(
7859def foo(left, right):
7860 return left > right
7861
7862# Rewrite BINARY_OP_ANAMORPHIC to COMPARE_GT_SMALLINT
7863foo(1, 1)
7864)")
7865 .isError());
7866
7867 HandleScope scope(thread_);
7868 Function function(&scope, mainModuleAt(runtime_, "foo"));
7869 EXPECT_TRUE(containsBytecode(function, COMPARE_GT_SMALLINT));
7870 Object left(&scope, SmallInt::fromWord(7));
7871 Object right(&scope, SmallInt::fromWord(4));
7872 Object result(&scope,
7873 compileAndCallJITFunction2(thread_, function, left, right));
7874 EXPECT_EQ(*result, Bool::trueObj());
7875}
7876
7877TEST_F(JitTest, CompareGeSmallintWithSmallIntsReturnsBool) {
7878 if (useCppInterpreter()) {
7879 GTEST_SKIP();
7880 }
7881 EXPECT_FALSE(runFromCStr(runtime_, R"(
7882def foo(left, right):
7883 return left >= right
7884
7885# Rewrite BINARY_OP_ANAMORPHIC to COMPARE_GE_SMALLINT
7886foo(1, 1)
7887)")
7888 .isError());
7889
7890 HandleScope scope(thread_);
7891 Function function(&scope, mainModuleAt(runtime_, "foo"));
7892 EXPECT_TRUE(containsBytecode(function, COMPARE_GE_SMALLINT));
7893 Object left(&scope, SmallInt::fromWord(7));
7894 Object right(&scope, SmallInt::fromWord(4));
7895 Object result(&scope,
7896 compileAndCallJITFunction2(thread_, function, left, right));
7897 EXPECT_EQ(*result, Bool::trueObj());
7898}
7899
7900TEST_F(JitTest, CompareLtSmallintWithSmallIntsReturnsBool) {
7901 if (useCppInterpreter()) {
7902 GTEST_SKIP();
7903 }
7904 EXPECT_FALSE(runFromCStr(runtime_, R"(
7905def foo(left, right):
7906 return left < right
7907
7908# Rewrite BINARY_OP_ANAMORPHIC to COMPARE_LT_SMALLINT
7909foo(1, 1)
7910)")
7911 .isError());
7912
7913 HandleScope scope(thread_);
7914 Function function(&scope, mainModuleAt(runtime_, "foo"));
7915 EXPECT_TRUE(containsBytecode(function, COMPARE_LT_SMALLINT));
7916 Object left(&scope, SmallInt::fromWord(7));
7917 Object right(&scope, SmallInt::fromWord(4));
7918 Object result(&scope,
7919 compileAndCallJITFunction2(thread_, function, left, right));
7920 EXPECT_EQ(*result, Bool::falseObj());
7921}
7922
7923TEST_F(JitTest, CompareLeSmallintWithSmallIntsReturnsBool) {
7924 if (useCppInterpreter()) {
7925 GTEST_SKIP();
7926 }
7927 EXPECT_FALSE(runFromCStr(runtime_, R"(
7928def foo(left, right):
7929 return left <= right
7930
7931# Rewrite BINARY_OP_ANAMORPHIC to COMPARE_LE_SMALLINT
7932foo(1, 1)
7933)")
7934 .isError());
7935
7936 HandleScope scope(thread_);
7937 Function function(&scope, mainModuleAt(runtime_, "foo"));
7938 EXPECT_TRUE(containsBytecode(function, COMPARE_LE_SMALLINT));
7939 Object left(&scope, SmallInt::fromWord(7));
7940 Object right(&scope, SmallInt::fromWord(4));
7941 Object result(&scope,
7942 compileAndCallJITFunction2(thread_, function, left, right));
7943 EXPECT_EQ(*result, Bool::falseObj());
7944}
7945
7946TEST_F(JitTest, UnaryNotWithBoolReturnsBool) {
7947 if (useCppInterpreter()) {
7948 GTEST_SKIP();
7949 }
7950 EXPECT_FALSE(runFromCStr(runtime_, R"(
7951def foo(obj):
7952 return not obj
7953)")
7954 .isError());
7955
7956 HandleScope scope(thread_);
7957 Function function(&scope, mainModuleAt(runtime_, "foo"));
7958 EXPECT_TRUE(containsBytecode(function, UNARY_NOT));
7959 Object param(&scope, Bool::trueObj());
7960 Object result(&scope, compileAndCallJITFunction1(thread_, function, param));
7961 EXPECT_EQ(*result, Bool::falseObj());
7962}
7963
7964TEST_F(JitTest, BinaryAddSmallintWithNonSmallintDeoptimizes) {
7965 if (useCppInterpreter()) {
7966 GTEST_SKIP();
7967 }
7968 // Don't use compileAndCallJITFunction2 in this function because we want to
7969 // test deoptimizing back into the interpreter. This requires valid bytecode.
7970 EXPECT_FALSE(runFromCStr(runtime_, R"(
7971def foo(left, right):
7972 return left + right
7973
7974# Rewrite BINARY_OP_ANAMORPHIC to BINARY_ADD_SMALLINT
7975foo(1, 1)
7976)")
7977 .isError());
7978
7979 HandleScope scope(thread_);
7980 Function function(&scope, mainModuleAt(runtime_, "foo"));
7981 EXPECT_TRUE(containsBytecode(function, BINARY_ADD_SMALLINT));
7982 Object left_int(&scope, SmallInt::fromWord(5));
7983 Object right_int(&scope, SmallInt::fromWord(10));
7984 void* entry_before = function.entryAsm();
7985 Function caller(&scope,
7986 createTrampolineFunction2(thread_, left_int, right_int));
7987 compileFunction(thread_, function);
7988 Object result(&scope, Interpreter::call0(thread_, caller));
7989 EXPECT_NE(function.entryAsm(), entry_before);
7990 Object left_str(&scope, SmallStr::fromCStr("hello"));
7991 Object right_str(&scope, SmallStr::fromCStr(" world"));
7992 Function deopt_caller(
7993 &scope, createTrampolineFunction2(thread_, left_str, right_str));
7994 result = Interpreter::call0(thread_, deopt_caller);
7995 EXPECT_TRUE(containsBytecode(function, BINARY_OP_MONOMORPHIC));
7996 EXPECT_TRUE(isStrEqualsCStr(*result, "hello world"));
7997 EXPECT_EQ(function.entryAsm(), entry_before);
7998}
7999
8000TEST_F(JitTest, BinarySubscrListReturnsItem) {
8001 if (useCppInterpreter()) {
8002 GTEST_SKIP();
8003 }
8004 EXPECT_FALSE(runFromCStr(runtime_, R"(
8005def foo(obj):
8006 return obj[0]
8007
8008# Rewrite BINARY_SUBSCR_ANAMORPHIC to BINARY_SUBSCR_LIST
8009foo([3, 2, 1])
8010)")
8011 .isError());
8012
8013 HandleScope scope(thread_);
8014 Function function(&scope, mainModuleAt(runtime_, "foo"));
8015 EXPECT_TRUE(containsBytecode(function, BINARY_SUBSCR_LIST));
8016 List list(&scope, runtime_->newList());
8017 Object obj(&scope, SmallStr::fromCStr("bar"));
8018 runtime_->listAdd(thread_, list, obj);
8019 Object result(&scope, compileAndCallJITFunction1(thread_, function, list));
8020 EXPECT_TRUE(isStrEqualsCStr(*result, "bar"));
8021}
8022
8023TEST_F(JitTest, BinarySubscrListWithNonListDeoptimizes) {
8024 if (useCppInterpreter()) {
8025 GTEST_SKIP();
8026 }
8027 EXPECT_FALSE(runFromCStr(runtime_, R"(
8028def foo(obj):
8029 return obj[0]
8030
8031# Rewrite BINARY_SUBSCR_ANAMORPHIC to BINARY_SUBSCR_LIST
8032foo([3, 2, 1])
8033)")
8034 .isError());
8035
8036 HandleScope scope(thread_);
8037 Function function(&scope, mainModuleAt(runtime_, "foo"));
8038 EXPECT_TRUE(containsBytecode(function, BINARY_SUBSCR_LIST));
8039 void* entry_before = function.entryAsm();
8040 compileFunction(thread_, function);
8041 EXPECT_NE(function.entryAsm(), entry_before);
8042 Object obj(&scope, SmallInt::fromWord(7));
8043 Object non_list(&scope, runtime_->newTupleWith1(obj));
8044 Function deopt_caller(&scope, createTrampolineFunction1(thread_, non_list));
8045 Object result(&scope, Interpreter::call0(thread_, deopt_caller));
8046 EXPECT_TRUE(containsBytecode(function, BINARY_SUBSCR_MONOMORPHIC));
8047 EXPECT_TRUE(isIntEqualsWord(*result, 7));
8048 EXPECT_EQ(function.entryAsm(), entry_before);
8049}
8050
8051TEST_F(JitTest, StoreSubscrListStoresItem) {
8052 if (useCppInterpreter()) {
8053 GTEST_SKIP();
8054 }
8055 EXPECT_FALSE(runFromCStr(runtime_, R"(
8056def foo(obj):
8057 obj[0] = 123
8058
8059# Rewrite STORE_SUBSCR_ANAMORPHIC to STORE_SUBSCR_LIST
8060foo([3, 2, 1])
8061)")
8062 .isError());
8063
8064 HandleScope scope(thread_);
8065 Function function(&scope, mainModuleAt(runtime_, "foo"));
8066 EXPECT_TRUE(containsBytecode(function, STORE_SUBSCR_LIST));
8067 List list(&scope, runtime_->newList());
8068 Object obj(&scope, SmallStr::fromCStr("bar"));
8069 runtime_->listAdd(thread_, list, obj);
8070 Object result(&scope, compileAndCallJITFunction1(thread_, function, list));
8071 EXPECT_EQ(*result, NoneType::object());
8072 EXPECT_TRUE(isIntEqualsWord(list.at(0), 123));
8073}
8074
8075TEST_F(JitTest, StoreSubscrListWithNonListDeoptimizes) {
8076 if (useCppInterpreter()) {
8077 GTEST_SKIP();
8078 }
8079 EXPECT_FALSE(runFromCStr(runtime_, R"(
8080class C(list):
8081 pass
8082
8083def foo(obj):
8084 obj[0] = 123
8085
8086# Rewrite STORE_SUBSCR_ANAMORPHIC to STORE_SUBSCR_LIST
8087foo([3, 2, 1])
8088instance = C([4, 5, 6])
8089)")
8090 .isError());
8091
8092 HandleScope scope(thread_);
8093 Function function(&scope, mainModuleAt(runtime_, "foo"));
8094 EXPECT_TRUE(containsBytecode(function, STORE_SUBSCR_LIST));
8095 void* entry_before = function.entryAsm();
8096 compileFunction(thread_, function);
8097 EXPECT_NE(function.entryAsm(), entry_before);
8098 List instance(&scope, mainModuleAt(runtime_, "instance"));
8099 Function deopt_caller(&scope, createTrampolineFunction1(thread_, instance));
8100 Object result(&scope, Interpreter::call0(thread_, deopt_caller));
8101 EXPECT_EQ(function.entryAsm(), entry_before);
8102 EXPECT_EQ(*result, NoneType::object());
8103 EXPECT_TRUE(isIntEqualsWord(instance.at(0), 123));
8104}
8105
8106TEST_F(JitTest, InplaceAddSmallintAddsIntegers) {
8107 if (useCppInterpreter()) {
8108 GTEST_SKIP();
8109 }
8110 EXPECT_FALSE(runFromCStr(runtime_, R"(
8111def foo(obj):
8112 obj += 1
8113 return obj
8114
8115# Rewrite INPLACE_OP_ANAMORPHIC to INPLACE_ADD_SMALLINT
8116foo(1)
8117)")
8118 .isError());
8119 HandleScope scope(thread_);
8120 Function function(&scope, mainModuleAt(runtime_, "foo"));
8121 EXPECT_TRUE(containsBytecode(function, INPLACE_ADD_SMALLINT));
8122 Object obj(&scope, SmallInt::fromWord(12));
8123 Object result(&scope, compileAndCallJITFunction1(thread_, function, obj));
8124 EXPECT_TRUE(isIntEqualsWord(*result, 13));
8125}
8126
8127TEST_F(JitTest, InplaceAddSmallintWithNonIntDeoptimizes) {
8128 if (useCppInterpreter()) {
8129 GTEST_SKIP();
8130 }
8131 EXPECT_FALSE(runFromCStr(runtime_, R"(
8132def foo(left, right):
8133 left += right
8134 return left
8135
8136# Rewrite INPLACE_OP_MONOMORPHIC to INPLACE_ADD_SMALLINT
8137foo(1, 2)
8138)")
8139 .isError());
8140
8141 HandleScope scope(thread_);
8142 Function function(&scope, mainModuleAt(runtime_, "foo"));
8143 EXPECT_TRUE(containsBytecode(function, INPLACE_ADD_SMALLINT));
8144 void* entry_before = function.entryAsm();
8145 compileFunction(thread_, function);
8146 EXPECT_NE(function.entryAsm(), entry_before);
8147 Str left(&scope, SmallStr::fromCStr("hello"));
8148 Str right(&scope, SmallStr::fromCStr(" world"));
8149 Function deopt_caller(&scope,
8150 createTrampolineFunction2(thread_, left, right));
8151 Object result(&scope, Interpreter::call0(thread_, deopt_caller));
8152 EXPECT_EQ(function.entryAsm(), entry_before);
8153 EXPECT_TRUE(isStrEqualsCStr(*result, "hello world"));
8154}
8155
8156TEST_F(JitTest, InplaceSubSmallintSubsIntegers) {
8157 if (useCppInterpreter()) {
8158 GTEST_SKIP();
8159 }
8160 EXPECT_FALSE(runFromCStr(runtime_, R"(
8161def foo(obj):
8162 obj -= 1
8163 return obj
8164
8165# Rewrite INPLACE_OP_ANAMORPHIC to INPLACE_SUB_SMALLINT
8166foo(1)
8167)")
8168 .isError());
8169 HandleScope scope(thread_);
8170 Function function(&scope, mainModuleAt(runtime_, "foo"));
8171 EXPECT_TRUE(containsBytecode(function, INPLACE_SUB_SMALLINT));
8172 Object obj(&scope, SmallInt::fromWord(12));
8173 Object result(&scope, compileAndCallJITFunction1(thread_, function, obj));
8174 EXPECT_TRUE(isIntEqualsWord(*result, 11));
8175}
8176
8177TEST_F(JitTest, InplaceSubSmallintWithNonIntDeoptimizes) {
8178 if (useCppInterpreter()) {
8179 GTEST_SKIP();
8180 }
8181 EXPECT_FALSE(runFromCStr(runtime_, R"(
8182class C(int):
8183 pass
8184
8185def foo(obj):
8186 obj -= 1
8187 return obj
8188
8189# Rewrite INPLACE_OP_MONOMORPHIC to INPLACE_SUB_SMALLINT
8190foo(1)
8191instance = C(12)
8192)")
8193 .isError());
8194
8195 HandleScope scope(thread_);
8196 Function function(&scope, mainModuleAt(runtime_, "foo"));
8197 EXPECT_TRUE(containsBytecode(function, INPLACE_SUB_SMALLINT));
8198 void* entry_before = function.entryAsm();
8199 compileFunction(thread_, function);
8200 EXPECT_NE(function.entryAsm(), entry_before);
8201 Object instance(&scope, mainModuleAt(runtime_, "instance"));
8202 Function deopt_caller(&scope, createTrampolineFunction1(thread_, instance));
8203 Object result(&scope, Interpreter::call0(thread_, deopt_caller));
8204 EXPECT_EQ(function.entryAsm(), entry_before);
8205 EXPECT_TRUE(runtime_->isInstanceOfInt(*result));
8206 EXPECT_TRUE(isIntEqualsWord(intUnderlying(*result), 11));
8207}
8208
8209TEST_F(JitTest, LoadAttrInstanceWithInstanceReturnsAttribute) {
8210 if (useCppInterpreter()) {
8211 GTEST_SKIP();
8212 }
8213 EXPECT_FALSE(runFromCStr(runtime_, R"(
8214class C:
8215 def __init__(self, value):
8216 self.foo = value
8217
8218def foo(obj):
8219 return obj.foo
8220
8221# Rewrite LOAD_ATTR_ANAMORPHIC to LOAD_ATTR_INSTANCE
8222foo(C(4))
8223instance = C(10)
8224)")
8225 .isError());
8226 HandleScope scope(thread_);
8227 Function function(&scope, mainModuleAt(runtime_, "foo"));
8228 EXPECT_TRUE(containsBytecode(function, LOAD_ATTR_INSTANCE));
8229 Object obj(&scope, mainModuleAt(runtime_, "instance"));
8230 Object result(&scope, compileAndCallJITFunction1(thread_, function, obj));
8231 EXPECT_TRUE(isIntEqualsWord(*result, 10));
8232}
8233
8234TEST_F(JitTest, LoadAttrInstanceWithNewTypeDeoptimizes) {
8235 if (useCppInterpreter()) {
8236 GTEST_SKIP();
8237 }
8238 EXPECT_FALSE(runFromCStr(runtime_, R"(
8239class C:
8240 def __init__(self, value):
8241 self.foo = value
8242
8243class D:
8244 def __init__(self, value):
8245 self.foo = value
8246
8247def foo(obj):
8248 return obj.foo
8249
8250# Rewrite LOAD_ATTR_ANAMORPHIC to LOAD_ATTR_INSTANCE
8251foo(C(4))
8252instance = D(10)
8253)")
8254 .isError());
8255
8256 HandleScope scope(thread_);
8257 Function function(&scope, mainModuleAt(runtime_, "foo"));
8258 EXPECT_TRUE(containsBytecode(function, LOAD_ATTR_INSTANCE));
8259 void* entry_before = function.entryAsm();
8260 compileFunction(thread_, function);
8261 EXPECT_NE(function.entryAsm(), entry_before);
8262 Object instance(&scope, mainModuleAt(runtime_, "instance"));
8263 Function deopt_caller(&scope, createTrampolineFunction1(thread_, instance));
8264 Object result(&scope, Interpreter::call0(thread_, deopt_caller));
8265 EXPECT_TRUE(containsBytecode(function, LOAD_ATTR_POLYMORPHIC));
8266 EXPECT_TRUE(isIntEqualsWord(*result, 10));
8267 EXPECT_EQ(function.entryAsm(), entry_before);
8268}
8269
8270TEST_F(JitTest, JumpAbsoluteJumps) {
8271 if (useCppInterpreter()) {
8272 GTEST_SKIP();
8273 }
8274 HandleScope scope(thread_);
8275 const byte bytecode[] = {
8276 JUMP_ABSOLUTE, 4, // to LOAD_CONST, 1
8277 LOAD_CONST, 0, LOAD_CONST, 1, RETURN_VALUE, 0,
8278 };
8279 Object none(&scope, NoneType::object());
8280 Object one(&scope, SmallInt::fromWord(1));
8281 Tuple consts(&scope, runtime_->newTupleWith2(none, one));
8282 Code code(&scope, newCodeWithBytesConsts(bytecode, consts));
8283
8284 Str qualname(&scope, SmallStr::fromCStr("foo"));
8285 Module module(&scope, findMainModule(runtime_));
8286 Function function(
8287 &scope, runtime_->newFunctionWithCode(thread_, qualname, code, module));
8288 moduleAtPutByCStr(thread_, module, "foo", function);
8289 Object result(&scope, compileAndCallJITFunction(thread_, function));
8290 EXPECT_TRUE(isIntEqualsWord(*result, 1));
8291}
8292
8293TEST_F(JitTest, JumpForwardJumps) {
8294 if (useCppInterpreter()) {
8295 GTEST_SKIP();
8296 }
8297 HandleScope scope(thread_);
8298 const byte bytecode[] = {
8299 JUMP_FORWARD, 2, // to LOAD_CONST, 1
8300 LOAD_CONST, 0, LOAD_CONST, 1, RETURN_VALUE, 0,
8301 };
8302 Object none(&scope, NoneType::object());
8303 Object one(&scope, SmallInt::fromWord(1));
8304 Tuple consts(&scope, runtime_->newTupleWith2(none, one));
8305 Code code(&scope, newCodeWithBytesConsts(bytecode, consts));
8306
8307 Str qualname(&scope, SmallStr::fromCStr("foo"));
8308 Module module(&scope, findMainModule(runtime_));
8309 Function function(
8310 &scope, runtime_->newFunctionWithCode(thread_, qualname, code, module));
8311 moduleAtPutByCStr(thread_, module, "foo", function);
8312 Object result(&scope, compileAndCallJITFunction(thread_, function));
8313 EXPECT_TRUE(isIntEqualsWord(*result, 1));
8314}
8315
8316TEST_F(JitTest, PopJumpIfTrueJumpsIfTrue) {
8317 if (useCppInterpreter()) {
8318 GTEST_SKIP();
8319 }
8320 HandleScope scope(thread_);
8321 const byte bytecode[] = {
8322 LOAD_CONST, 2, POP_JUMP_IF_TRUE, 8, // to LOAD_CONST, 1
8323 LOAD_CONST, 0, JUMP_FORWARD, 2, // to RETURN_VALUE
8324 LOAD_CONST, 1, RETURN_VALUE, 0,
8325 };
8326 Object none(&scope, NoneType::object());
8327 Object one(&scope, SmallInt::fromWord(1));
8328 Object truthy(&scope, Bool::trueObj());
8329 Tuple consts(&scope, runtime_->newTupleWith3(none, one, truthy));
8330 Code code(&scope, newCodeWithBytesConsts(bytecode, consts));
8331
8332 Str qualname(&scope, SmallStr::fromCStr("foo"));
8333 Module module(&scope, findMainModule(runtime_));
8334 Function function(
8335 &scope, runtime_->newFunctionWithCode(thread_, qualname, code, module));
8336 moduleAtPutByCStr(thread_, module, "foo", function);
8337 Object result(&scope, compileAndCallJITFunction(thread_, function));
8338 EXPECT_TRUE(isIntEqualsWord(*result, 1));
8339}
8340
8341TEST_F(JitTest, PopJumpIfTrueJumpsIfTrueNonBool) {
8342 if (useCppInterpreter()) {
8343 GTEST_SKIP();
8344 }
8345 HandleScope scope(thread_);
8346 const byte bytecode[] = {
8347 LOAD_CONST, 2, POP_JUMP_IF_TRUE, 8, // to LOAD_CONST, 1
8348 LOAD_CONST, 0, JUMP_FORWARD, 2, // to RETURN_VALUE
8349 LOAD_CONST, 1, RETURN_VALUE, 0,
8350 };
8351 Object none(&scope, NoneType::object());
8352 Object one(&scope, SmallInt::fromWord(1));
8353 Object truthy(&scope, runtime_->newTupleWith1(one));
8354 Tuple consts(&scope, runtime_->newTupleWith3(none, one, truthy));
8355 Code code(&scope, newCodeWithBytesConsts(bytecode, consts));
8356
8357 Str qualname(&scope, SmallStr::fromCStr("foo"));
8358 Module module(&scope, findMainModule(runtime_));
8359 Function function(
8360 &scope, runtime_->newFunctionWithCode(thread_, qualname, code, module));
8361 moduleAtPutByCStr(thread_, module, "foo", function);
8362 Function caller(&scope, createTrampolineFunction(thread_));
8363 compileFunction(thread_, function);
8364 Object result(&scope, Interpreter::call0(thread_, caller));
8365 EXPECT_TRUE(isIntEqualsWord(*result, 1));
8366}
8367
8368TEST_F(JitTest, PopJumpIfTrueDoesNotJumpIfFalse) {
8369 if (useCppInterpreter()) {
8370 GTEST_SKIP();
8371 }
8372 HandleScope scope(thread_);
8373 const byte bytecode[] = {
8374 LOAD_CONST, 2, POP_JUMP_IF_TRUE, 8, // to LOAD_CONST, 1
8375 LOAD_CONST, 0, JUMP_FORWARD, 2, // to RETURN_VALUE
8376 LOAD_CONST, 1, RETURN_VALUE, 0,
8377 };
8378 Object none(&scope, NoneType::object());
8379 Object one(&scope, SmallInt::fromWord(1));
8380 Object falsy(&scope, Bool::falseObj());
8381 Tuple consts(&scope, runtime_->newTupleWith3(none, one, falsy));
8382 Code code(&scope, newCodeWithBytesConsts(bytecode, consts));
8383
8384 Str qualname(&scope, SmallStr::fromCStr("foo"));
8385 Module module(&scope, findMainModule(runtime_));
8386 Function function(
8387 &scope, runtime_->newFunctionWithCode(thread_, qualname, code, module));
8388 moduleAtPutByCStr(thread_, module, "foo", function);
8389 Object result(&scope, compileAndCallJITFunction(thread_, function));
8390 EXPECT_EQ(*result, NoneType::object());
8391}
8392
8393TEST_F(JitTest, PopJumpIfFalseJumpsIfFalse) {
8394 if (useCppInterpreter()) {
8395 GTEST_SKIP();
8396 }
8397 HandleScope scope(thread_);
8398 const byte bytecode[] = {
8399 LOAD_CONST, 2, POP_JUMP_IF_FALSE, 8, // to LOAD_CONST, 1
8400 LOAD_CONST, 0, JUMP_FORWARD, 2, // to RETURN_VALUE
8401 LOAD_CONST, 1, RETURN_VALUE, 0,
8402 };
8403 Object none(&scope, NoneType::object());
8404 Object one(&scope, SmallInt::fromWord(1));
8405 Object falsy(&scope, Bool::falseObj());
8406 Tuple consts(&scope, runtime_->newTupleWith3(none, one, falsy));
8407 Code code(&scope, newCodeWithBytesConsts(bytecode, consts));
8408
8409 Str qualname(&scope, SmallStr::fromCStr("foo"));
8410 Module module(&scope, findMainModule(runtime_));
8411 Function function(
8412 &scope, runtime_->newFunctionWithCode(thread_, qualname, code, module));
8413 moduleAtPutByCStr(thread_, module, "foo", function);
8414 Object result(&scope, compileAndCallJITFunction(thread_, function));
8415 EXPECT_TRUE(isIntEqualsWord(*result, 1));
8416}
8417
8418TEST_F(JitTest, PopJumpIfFalseDoesNotJumpIfTrue) {
8419 if (useCppInterpreter()) {
8420 GTEST_SKIP();
8421 }
8422 HandleScope scope(thread_);
8423 const byte bytecode[] = {
8424 LOAD_CONST, 2, POP_JUMP_IF_FALSE, 8, // to LOAD_CONST, 1
8425 LOAD_CONST, 0, JUMP_FORWARD, 2, // to RETURN_VALUE
8426 LOAD_CONST, 1, RETURN_VALUE, 0,
8427 };
8428 Object none(&scope, NoneType::object());
8429 Object one(&scope, SmallInt::fromWord(1));
8430 Object truthy(&scope, Bool::trueObj());
8431 Tuple consts(&scope, runtime_->newTupleWith3(none, one, truthy));
8432 Code code(&scope, newCodeWithBytesConsts(bytecode, consts));
8433
8434 Str qualname(&scope, SmallStr::fromCStr("foo"));
8435 Module module(&scope, findMainModule(runtime_));
8436 Function function(
8437 &scope, runtime_->newFunctionWithCode(thread_, qualname, code, module));
8438 moduleAtPutByCStr(thread_, module, "foo", function);
8439 Object result(&scope, compileAndCallJITFunction(thread_, function));
8440 EXPECT_EQ(*result, NoneType::object());
8441}
8442
8443TEST_F(JitTest, JumpIfTrueOrPopJumpsIfTrue) {
8444 if (useCppInterpreter()) {
8445 GTEST_SKIP();
8446 }
8447 HandleScope scope(thread_);
8448 const byte bytecode[] = {
8449 LOAD_CONST, 1, JUMP_IF_TRUE_OR_POP, 6, // to RETURN_VALUE
8450 LOAD_CONST, 0, RETURN_VALUE, 0,
8451 };
8452 Object none(&scope, NoneType::object());
8453 Object truthy(&scope, Bool::trueObj());
8454 Tuple consts(&scope, runtime_->newTupleWith2(none, truthy));
8455 Code code(&scope, newCodeWithBytesConsts(bytecode, consts));
8456
8457 Str qualname(&scope, SmallStr::fromCStr("foo"));
8458 Module module(&scope, findMainModule(runtime_));
8459 Function function(
8460 &scope, runtime_->newFunctionWithCode(thread_, qualname, code, module));
8461 moduleAtPutByCStr(thread_, module, "foo", function);
8462 Object result(&scope, compileAndCallJITFunction(thread_, function));
8463 EXPECT_EQ(*result, Bool::trueObj());
8464}
8465
8466TEST_F(JitTest, JumpIfTrueOrPopPopsIfFalse) {
8467 if (useCppInterpreter()) {
8468 GTEST_SKIP();
8469 }
8470 HandleScope scope(thread_);
8471 const byte bytecode[] = {
8472 LOAD_CONST, 1, JUMP_IF_TRUE_OR_POP, 6, // to RETURN_VALUE
8473 LOAD_CONST, 0, RETURN_VALUE, 0,
8474 };
8475 Object none(&scope, NoneType::object());
8476 Object falsy(&scope, Bool::falseObj());
8477 Tuple consts(&scope, runtime_->newTupleWith2(none, falsy));
8478 Code code(&scope, newCodeWithBytesConsts(bytecode, consts));
8479
8480 Str qualname(&scope, SmallStr::fromCStr("foo"));
8481 Module module(&scope, findMainModule(runtime_));
8482 Function function(
8483 &scope, runtime_->newFunctionWithCode(thread_, qualname, code, module));
8484 moduleAtPutByCStr(thread_, module, "foo", function);
8485 Object result(&scope, compileAndCallJITFunction(thread_, function));
8486 EXPECT_EQ(*result, NoneType::object());
8487}
8488
8489TEST_F(JitTest, JumpIfFalseOrPopJumpsIfFalse) {
8490 if (useCppInterpreter()) {
8491 GTEST_SKIP();
8492 }
8493 HandleScope scope(thread_);
8494 const byte bytecode[] = {
8495 LOAD_CONST, 1, JUMP_IF_FALSE_OR_POP, 6, // to RETURN_VALUE
8496 LOAD_CONST, 0, RETURN_VALUE, 0,
8497 };
8498 Object none(&scope, NoneType::object());
8499 Object falsy(&scope, Bool::falseObj());
8500 Tuple consts(&scope, runtime_->newTupleWith2(none, falsy));
8501 Code code(&scope, newCodeWithBytesConsts(bytecode, consts));
8502
8503 Str qualname(&scope, SmallStr::fromCStr("foo"));
8504 Module module(&scope, findMainModule(runtime_));
8505 Function function(
8506 &scope, runtime_->newFunctionWithCode(thread_, qualname, code, module));
8507 moduleAtPutByCStr(thread_, module, "foo", function);
8508 Object result(&scope, compileAndCallJITFunction(thread_, function));
8509 EXPECT_EQ(*result, Bool::falseObj());
8510}
8511
8512TEST_F(JitTest, JumpIfFalseOrPopPopsIfTrue) {
8513 if (useCppInterpreter()) {
8514 GTEST_SKIP();
8515 }
8516 HandleScope scope(thread_);
8517 const byte bytecode[] = {
8518 LOAD_CONST, 1, JUMP_IF_FALSE_OR_POP, 6, // to RETURN_VALUE
8519 LOAD_CONST, 0, RETURN_VALUE, 0,
8520 };
8521 Object none(&scope, NoneType::object());
8522 Object truthy(&scope, Bool::trueObj());
8523 Tuple consts(&scope, runtime_->newTupleWith2(none, truthy));
8524 Code code(&scope, newCodeWithBytesConsts(bytecode, consts));
8525
8526 Str qualname(&scope, SmallStr::fromCStr("foo"));
8527 Module module(&scope, findMainModule(runtime_));
8528 Function function(
8529 &scope, runtime_->newFunctionWithCode(thread_, qualname, code, module));
8530 moduleAtPutByCStr(thread_, module, "foo", function);
8531 Object result(&scope, compileAndCallJITFunction(thread_, function));
8532 EXPECT_EQ(*result, NoneType::object());
8533}
8534
8535TEST_F(JitTest, ForIterListIteratesOverList) {
8536 if (useCppInterpreter()) {
8537 GTEST_SKIP();
8538 }
8539 EXPECT_FALSE(runFromCStr(runtime_, R"(
8540def foo(obj):
8541 result = 0
8542 for item in obj:
8543 result += item
8544 return result
8545
8546# Rewrite FOR_ITER_ANAMORPHIC with FOR_ITER_LIST
8547foo([1, 2, 3])
8548instance = [4, 5, 6]
8549)")
8550 .isError());
8551 HandleScope scope(thread_);
8552 Function function(&scope, mainModuleAt(runtime_, "foo"));
8553 EXPECT_TRUE(containsBytecode(function, FOR_ITER_LIST));
8554 List list(&scope, mainModuleAt(runtime_, "instance"));
8555 Object result(&scope, compileAndCallJITFunction1(thread_, function, list));
8556 EXPECT_TRUE(isIntEqualsWord(*result, 15));
8557}
8558
8559TEST_F(JitTest, ForIterListWithNonListDeoptimizes) {
8560 if (useCppInterpreter()) {
8561 GTEST_SKIP();
8562 }
8563 EXPECT_FALSE(runFromCStr(runtime_, R"(
8564class D:
8565 def __next__(self):
8566 raise StopIteration
8567
8568class C:
8569 def __iter__(self):
8570 return D()
8571
8572def foo(obj):
8573 result = 0
8574 for item in obj:
8575 result += item
8576 return result
8577
8578# Rewrite FOR_ITER_ANAMORPHIC to FOR_ITER_LIST
8579foo([1, 2, 3])
8580instance = C()
8581)")
8582 .isError());
8583
8584 HandleScope scope(thread_);
8585 Function function(&scope, mainModuleAt(runtime_, "foo"));
8586 EXPECT_TRUE(containsBytecode(function, FOR_ITER_LIST));
8587 void* entry_before = function.entryAsm();
8588 compileFunction(thread_, function);
8589 EXPECT_NE(function.entryAsm(), entry_before);
8590 Object instance(&scope, mainModuleAt(runtime_, "instance"));
8591 Function deopt_caller(&scope, createTrampolineFunction1(thread_, instance));
8592 Object result(&scope, Interpreter::call0(thread_, deopt_caller));
8593 EXPECT_TRUE(containsBytecode(function, FOR_ITER_MONOMORPHIC));
8594 EXPECT_TRUE(isIntEqualsWord(*result, 0));
8595 EXPECT_EQ(function.entryAsm(), entry_before);
8596}
8597
8598TEST_F(JitTest, ForIterRangeIteratesOverRange) {
8599 if (useCppInterpreter()) {
8600 GTEST_SKIP();
8601 }
8602 EXPECT_FALSE(runFromCStr(runtime_, R"(
8603def foo(obj):
8604 result = 0
8605 for item in obj:
8606 result += item
8607 return result
8608
8609# Rewrite FOR_ITER_ANAMORPHIC with FOR_ITER_RANGE
8610foo(range(1, 4))
8611instance = range(4, 7)
8612)")
8613 .isError());
8614 HandleScope scope(thread_);
8615 Function function(&scope, mainModuleAt(runtime_, "foo"));
8616 EXPECT_TRUE(containsBytecode(function, FOR_ITER_RANGE));
8617 Range range(&scope, mainModuleAt(runtime_, "instance"));
8618 Object result(&scope, compileAndCallJITFunction1(thread_, function, range));
8619 EXPECT_TRUE(isIntEqualsWord(*result, 15));
8620}
8621
8622TEST_F(JitTest, ForIterRangeWithNonRangeDeoptimizes) {
8623 if (useCppInterpreter()) {
8624 GTEST_SKIP();
8625 }
8626 EXPECT_FALSE(runFromCStr(runtime_, R"(
8627class D:
8628 def __next__(self):
8629 raise StopIteration
8630
8631class C:
8632 def __iter__(self):
8633 return D()
8634
8635def foo(obj):
8636 result = 0
8637 for item in obj:
8638 result += item
8639 return result
8640
8641# Rewrite FOR_ITER_ANAMORPHIC to FOR_ITER_RANGE
8642foo(range(1, 4))
8643instance = C()
8644)")
8645 .isError());
8646
8647 HandleScope scope(thread_);
8648 Function function(&scope, mainModuleAt(runtime_, "foo"));
8649 EXPECT_TRUE(containsBytecode(function, FOR_ITER_RANGE));
8650 void* entry_before = function.entryAsm();
8651 compileFunction(thread_, function);
8652 EXPECT_NE(function.entryAsm(), entry_before);
8653 Object instance(&scope, mainModuleAt(runtime_, "instance"));
8654 Function deopt_caller(&scope, createTrampolineFunction1(thread_, instance));
8655 Object result(&scope, Interpreter::call0(thread_, deopt_caller));
8656 EXPECT_TRUE(containsBytecode(function, FOR_ITER_MONOMORPHIC));
8657 EXPECT_TRUE(isIntEqualsWord(*result, 0));
8658 EXPECT_EQ(function.entryAsm(), entry_before);
8659}
8660
8661TEST_F(JitTest, LoadAttrInstanceTypeBoundMethodWithInstanceReturnsBoundMethod) {
8662 if (useCppInterpreter()) {
8663 GTEST_SKIP();
8664 }
8665 EXPECT_FALSE(runFromCStr(runtime_, R"(
8666class C:
8667 def foo(self):
8668 pass
8669
8670def foo(obj):
8671 return obj.foo
8672
8673# Rewrite LOAD_ATTR_ANAMORPHIC to LOAD_ATTR_INSTANCE_TYPE_BOUND_METHOD
8674foo(C())
8675instance = C()
8676)")
8677 .isError());
8678 HandleScope scope(thread_);
8679 Function function(&scope, mainModuleAt(runtime_, "foo"));
8680 EXPECT_TRUE(containsBytecode(function, LOAD_ATTR_INSTANCE_TYPE_BOUND_METHOD));
8681 Object obj(&scope, mainModuleAt(runtime_, "instance"));
8682 Object result_obj(&scope, compileAndCallJITFunction1(thread_, function, obj));
8683 ASSERT_TRUE(result_obj.isBoundMethod());
8684 BoundMethod result(&scope, *result_obj);
8685 EXPECT_EQ(result.self(), *obj);
8686}
8687
8688TEST_F(JitTest, LoadAttrInstanceTypeBoundMethodWithNewTypeDeoptimizes) {
8689 if (useCppInterpreter()) {
8690 GTEST_SKIP();
8691 }
8692 EXPECT_FALSE(runFromCStr(runtime_, R"(
8693class C:
8694 def foo(self):
8695 pass
8696
8697class D:
8698 def foo(self):
8699 pass
8700
8701def foo(obj):
8702 return obj.foo
8703
8704# Rewrite LOAD_ATTR_ANAMORPHIC to LOAD_ATTR_INSTANCE_TYPE_BOUND_METHOD
8705foo(C())
8706instance = D()
8707)")
8708 .isError());
8709
8710 HandleScope scope(thread_);
8711 Function function(&scope, mainModuleAt(runtime_, "foo"));
8712 EXPECT_TRUE(containsBytecode(function, LOAD_ATTR_INSTANCE_TYPE_BOUND_METHOD));
8713 void* entry_before = function.entryAsm();
8714 compileFunction(thread_, function);
8715 EXPECT_NE(function.entryAsm(), entry_before);
8716 Object instance(&scope, mainModuleAt(runtime_, "instance"));
8717 Function deopt_caller(&scope, createTrampolineFunction1(thread_, instance));
8718 Object result_obj(&scope, Interpreter::call0(thread_, deopt_caller));
8719 EXPECT_TRUE(containsBytecode(function, LOAD_ATTR_POLYMORPHIC));
8720 ASSERT_TRUE(result_obj.isBoundMethod());
8721 BoundMethod result(&scope, *result_obj);
8722 EXPECT_EQ(result.self(), *instance);
8723 EXPECT_EQ(function.entryAsm(), entry_before);
8724}
8725
8726TEST_F(JitTest, LoadAttrPolymorphicWithCacheHitReturnsAttribute) {
8727 if (useCppInterpreter()) {
8728 GTEST_SKIP();
8729 }
8730 EXPECT_FALSE(runFromCStr(runtime_, R"(
8731class C:
8732 def __init__(self, value):
8733 self.value = value
8734
8735class D(C):
8736 pass
8737
8738def foo(obj):
8739 return obj.value
8740
8741# Rewrite LOAD_ATTR_ANAMORPHIC to LOAD_ATTR_INSTANCE
8742foo(C(1))
8743# Rewrite LOAD_ATTR_INSTANCE to LOAD_ATTR_POLYMORPHIC
8744foo(D(2))
8745instance = C(3)
8746)")
8747 .isError());
8748 HandleScope scope(thread_);
8749 Function function(&scope, mainModuleAt(runtime_, "foo"));
8750 EXPECT_TRUE(containsBytecode(function, LOAD_ATTR_POLYMORPHIC));
8751 Object obj(&scope, mainModuleAt(runtime_, "instance"));
8752 Object result(&scope, compileAndCallJITFunction1(thread_, function, obj));
8753 EXPECT_TRUE(isIntEqualsWord(*result, 3));
8754}
8755
8756TEST_F(JitTest, LoadAttrPolymorphicWithCacheMissReturnsAttribute) {
8757 if (useCppInterpreter()) {
8758 GTEST_SKIP();
8759 }
8760 EXPECT_FALSE(runFromCStr(runtime_, R"(
8761class C:
8762 def __init__(self, value):
8763 self.value = value
8764
8765class D(C):
8766 pass
8767
8768class E(C):
8769 pass
8770
8771def foo(obj):
8772 return obj.value
8773
8774# Rewrite LOAD_ATTR_ANAMORPHIC to LOAD_ATTR_INSTANCE
8775foo(C(1))
8776# Rewrite LOAD_ATTR_INSTANCE to LOAD_ATTR_POLYMORPHIC
8777foo(D(2))
8778instance = E(3)
8779)")
8780 .isError());
8781 HandleScope scope(thread_);
8782 Function function(&scope, mainModuleAt(runtime_, "foo"));
8783 EXPECT_TRUE(containsBytecode(function, LOAD_ATTR_POLYMORPHIC));
8784 compileFunction(thread_, function);
8785 // Can't use compileAndCallJITFunction1 because the doLoadAttrPolymorphic
8786 // fallback needs to read the cache index off the bytecode.
8787 void* entry_jit = function.entryAsm();
8788 Object instance(&scope, mainModuleAt(runtime_, "instance"));
8789 Function deopt_caller(&scope, createTrampolineFunction1(thread_, instance));
8790 Object result(&scope, Interpreter::call0(thread_, deopt_caller));
8791 EXPECT_TRUE(containsBytecode(function, LOAD_ATTR_POLYMORPHIC));
8792 EXPECT_TRUE(isIntEqualsWord(*result, 3));
8793 EXPECT_NE(function.entryAsm(), entry_jit);
8794}
8795
8796TEST_F(JitTest, StoreAttrInstanceWithInstanceStoresAttribute) {
8797 if (useCppInterpreter()) {
8798 GTEST_SKIP();
8799 }
8800 EXPECT_FALSE(runFromCStr(runtime_, R"(
8801class C:
8802 def __init__(self, value):
8803 self.foo = value
8804
8805def foo(obj):
8806 obj.foo = 17
8807 return obj.foo
8808
8809# Rewrite STORE_ATTR_ANAMORPHIC to STORE_ATTR_INSTANCE
8810foo(C(4))
8811instance = C(10)
8812)")
8813 .isError());
8814 HandleScope scope(thread_);
8815 Function function(&scope, mainModuleAt(runtime_, "foo"));
8816 EXPECT_TRUE(containsBytecode(function, STORE_ATTR_INSTANCE));
8817 Object obj(&scope, mainModuleAt(runtime_, "instance"));
8818 Object result(&scope, compileAndCallJITFunction1(thread_, function, obj));
8819 EXPECT_TRUE(isIntEqualsWord(*result, 17));
8820}
8821
8822TEST_F(JitTest, StoreAttrInstanceWithNewTypeDeoptimizes) {
8823 if (useCppInterpreter()) {
8824 GTEST_SKIP();
8825 }
8826 EXPECT_FALSE(runFromCStr(runtime_, R"(
8827class C:
8828 def __init__(self, value):
8829 self.foo = value
8830
8831class D:
8832 def __init__(self, value):
8833 self.foo = value
8834
8835def foo(obj):
8836 obj.foo = 17
8837 return obj.foo
8838
8839# Rewrite STORE_ATTR_ANAMORPHIC to STORE_ATTR_INSTANCE
8840foo(C(4))
8841instance = D(10)
8842)")
8843 .isError());
8844
8845 HandleScope scope(thread_);
8846 Function function(&scope, mainModuleAt(runtime_, "foo"));
8847 EXPECT_TRUE(containsBytecode(function, STORE_ATTR_INSTANCE));
8848 void* entry_before = function.entryAsm();
8849 compileFunction(thread_, function);
8850 EXPECT_NE(function.entryAsm(), entry_before);
8851 Object instance(&scope, mainModuleAt(runtime_, "instance"));
8852 Function deopt_caller(&scope, createTrampolineFunction1(thread_, instance));
8853 Object result(&scope, Interpreter::call0(thread_, deopt_caller));
8854 EXPECT_TRUE(containsBytecode(function, STORE_ATTR_POLYMORPHIC));
8855 EXPECT_TRUE(isIntEqualsWord(*result, 17));
8856 EXPECT_EQ(function.entryAsm(), entry_before);
8857}
8858
8859TEST_F(JitTest, StoreAttrPolymorphicWithCacheHitReturnsAttribute) {
8860 if (useCppInterpreter()) {
8861 GTEST_SKIP();
8862 }
8863 EXPECT_FALSE(runFromCStr(runtime_, R"(
8864class C:
8865 def __init__(self, value):
8866 self.value = value
8867
8868class D(C):
8869 pass
8870
8871def foo(obj):
8872 obj.value = 17
8873 return obj.value
8874
8875# Rewrite STORE_ATTR_ANAMORPHIC to STORE_ATTR_INSTANCE
8876foo(C(1))
8877# Rewrite STORE_ATTR_INSTANCE to STORE_ATTR_POLYMORPHIC
8878foo(D(2))
8879instance = C(3)
8880)")
8881 .isError());
8882 HandleScope scope(thread_);
8883 Function function(&scope, mainModuleAt(runtime_, "foo"));
8884 EXPECT_TRUE(containsBytecode(function, STORE_ATTR_POLYMORPHIC));
8885 Object obj(&scope, mainModuleAt(runtime_, "instance"));
8886 Object result(&scope, compileAndCallJITFunction1(thread_, function, obj));
8887 EXPECT_TRUE(isIntEqualsWord(*result, 17));
8888}
8889
8890TEST_F(JitTest, StoreAttrPolymorphicWithCacheMissReturnsAttribute) {
8891 if (useCppInterpreter()) {
8892 GTEST_SKIP();
8893 }
8894 EXPECT_FALSE(runFromCStr(runtime_, R"(
8895class C:
8896 def __init__(self, value):
8897 self.value = value
8898
8899class D(C):
8900 pass
8901
8902class E(C):
8903 pass
8904
8905def foo(obj):
8906 obj.value = 17
8907 return obj.value
8908
8909# Rewrite STORE_ATTR_ANAMORPHIC to STORE_ATTR_INSTANCE
8910foo(C(1))
8911# Rewrite STORE_ATTR_INSTANCE to STORE_ATTR_POLYMORPHIC
8912foo(D(2))
8913instance = E(3)
8914)")
8915 .isError());
8916 HandleScope scope(thread_);
8917 Function function(&scope, mainModuleAt(runtime_, "foo"));
8918 EXPECT_TRUE(containsBytecode(function, STORE_ATTR_POLYMORPHIC));
8919 compileFunction(thread_, function);
8920 // Can't use compileAndCallJITFunction1 because the doStoreAttrPolymorphic
8921 // fallback needs to read the cache index off the bytecode.
8922 void* entry_jit = function.entryAsm();
8923 Object instance(&scope, mainModuleAt(runtime_, "instance"));
8924 Function deopt_caller(&scope, createTrampolineFunction1(thread_, instance));
8925 Object result(&scope, Interpreter::call0(thread_, deopt_caller));
8926 EXPECT_TRUE(containsBytecode(function, STORE_ATTR_POLYMORPHIC));
8927 EXPECT_TRUE(isIntEqualsWord(*result, 17));
8928 EXPECT_NE(function.entryAsm(), entry_jit);
8929}
8930
8931TEST_F(JitTest, StoreAttrInstanceOverflowWithInstanceStoresAttribute) {
8932 if (useCppInterpreter()) {
8933 GTEST_SKIP();
8934 }
8935 EXPECT_FALSE(runFromCStr(runtime_, R"(
8936class C:
8937 pass
8938
8939def foo(obj):
8940 obj.foo = 17
8941 return obj.foo
8942
8943# Rewrite STORE_ATTR_ANAMORPHIC to STORE_ATTR_INSTANCE_OVERFLOW
8944obj1 = C()
8945obj1.foo = 1
8946foo(obj1)
8947instance = C()
8948instance.foo = 1
8949)")
8950 .isError());
8951 HandleScope scope(thread_);
8952 Function function(&scope, mainModuleAt(runtime_, "foo"));
8953 EXPECT_TRUE(containsBytecode(function, STORE_ATTR_INSTANCE_OVERFLOW));
8954 Object obj(&scope, mainModuleAt(runtime_, "instance"));
8955 Object result(&scope, compileAndCallJITFunction1(thread_, function, obj));
8956 EXPECT_TRUE(isIntEqualsWord(*result, 17));
8957}
8958
8959TEST_F(JitTest, StoreAttrInstanceOverflowWithNewTypeDeoptimizes) {
8960 if (useCppInterpreter()) {
8961 GTEST_SKIP();
8962 }
8963 EXPECT_FALSE(runFromCStr(runtime_, R"(
8964class C:
8965 pass
8966
8967class D:
8968 pass
8969
8970def foo(obj):
8971 obj.foo = 17
8972 return obj.foo
8973
8974# Rewrite STORE_ATTR_ANAMORPHIC to STORE_ATTR_INSTANCE_OVERFLOW
8975obj1 = C()
8976obj1.foo = 1
8977foo(obj1)
8978instance = D()
8979instance.foo = 2
8980)")
8981 .isError());
8982
8983 HandleScope scope(thread_);
8984 Function function(&scope, mainModuleAt(runtime_, "foo"));
8985 EXPECT_TRUE(containsBytecode(function, STORE_ATTR_INSTANCE_OVERFLOW));
8986 void* entry_before = function.entryAsm();
8987 compileFunction(thread_, function);
8988 EXPECT_NE(function.entryAsm(), entry_before);
8989 Object instance(&scope, mainModuleAt(runtime_, "instance"));
8990 Function deopt_caller(&scope, createTrampolineFunction1(thread_, instance));
8991 Object result(&scope, Interpreter::call0(thread_, deopt_caller));
8992 EXPECT_TRUE(containsBytecode(function, STORE_ATTR_POLYMORPHIC));
8993 EXPECT_TRUE(isIntEqualsWord(*result, 17));
8994 EXPECT_EQ(function.entryAsm(), entry_before);
8995}
8996
8997TEST_F(JitTest, BuildListReturnsList) {
8998 if (useCppInterpreter()) {
8999 GTEST_SKIP();
9000 }
9001 EXPECT_FALSE(runFromCStr(runtime_, R"(
9002def foo():
9003 return [1, 2, 3]
9004)")
9005 .isError());
9006 HandleScope scope(thread_);
9007 Function function(&scope, mainModuleAt(runtime_, "foo"));
9008 EXPECT_TRUE(containsBytecode(function, BUILD_LIST));
9009 Object result(&scope, compileAndCallJITFunction(thread_, function));
9010 EXPECT_PYLIST_EQ(result, {1, 2, 3});
9011}
9012
9013TEST_F(JitTest, BuildListUnpackReturnsList) {
9014 if (useCppInterpreter()) {
9015 GTEST_SKIP();
9016 }
9017 EXPECT_FALSE(runFromCStr(runtime_, R"(
9018def foo():
9019 a = [2, 3]
9020 return [1, *a]
9021)")
9022 .isError());
9023 HandleScope scope(thread_);
9024 Function function(&scope, mainModuleAt(runtime_, "foo"));
9025 EXPECT_TRUE(containsBytecode(function, BUILD_LIST_UNPACK));
9026 Object result(&scope, compileAndCallJITFunction(thread_, function));
9027 EXPECT_PYLIST_EQ(result, {1, 2, 3});
9028}
9029
9030TEST_F(JitTest, BuildMapReturnsDict) {
9031 if (useCppInterpreter()) {
9032 GTEST_SKIP();
9033 }
9034 EXPECT_FALSE(runFromCStr(runtime_, R"(
9035def foo():
9036 return {"hello": "world"}
9037)")
9038 .isError());
9039 HandleScope scope(thread_);
9040 Function function(&scope, mainModuleAt(runtime_, "foo"));
9041 EXPECT_TRUE(containsBytecode(function, BUILD_MAP));
9042 Object result(&scope, compileAndCallJITFunction(thread_, function));
9043 ASSERT_TRUE(result.isDict());
9044 EXPECT_EQ(Dict::cast(*result).numItems(), 1);
9045}
9046
9047TEST_F(JitTest, BuildMapUnpackReturnsDict) {
9048 if (useCppInterpreter()) {
9049 GTEST_SKIP();
9050 }
9051 EXPECT_FALSE(runFromCStr(runtime_, R"(
9052def foo():
9053 a = {"goodbye": "world"}
9054 return {"hello": "world", **a}
9055)")
9056 .isError());
9057 HandleScope scope(thread_);
9058 Function function(&scope, mainModuleAt(runtime_, "foo"));
9059 EXPECT_TRUE(containsBytecode(function, BUILD_MAP_UNPACK));
9060 Object result(&scope, compileAndCallJITFunction(thread_, function));
9061 ASSERT_TRUE(result.isDict());
9062 EXPECT_EQ(Dict::cast(*result).numItems(), 2);
9063}
9064
9065TEST_F(JitTest, BuildSetReturnsSet) {
9066 if (useCppInterpreter()) {
9067 GTEST_SKIP();
9068 }
9069 EXPECT_FALSE(runFromCStr(runtime_, R"(
9070def foo():
9071 return {"hello", "world"}
9072)")
9073 .isError());
9074 HandleScope scope(thread_);
9075 Function function(&scope, mainModuleAt(runtime_, "foo"));
9076 EXPECT_TRUE(containsBytecode(function, BUILD_SET));
9077 Object result(&scope, compileAndCallJITFunction(thread_, function));
9078 ASSERT_TRUE(result.isSet());
9079 EXPECT_EQ(Set::cast(*result).numItems(), 2);
9080}
9081
9082TEST_F(JitTest, BuildSetUnpackReturnsSet) {
9083 if (useCppInterpreter()) {
9084 GTEST_SKIP();
9085 }
9086 EXPECT_FALSE(runFromCStr(runtime_, R"(
9087def foo():
9088 a = {"goodbye", "world"}
9089 return {"hello", "world", *a}
9090)")
9091 .isError());
9092 HandleScope scope(thread_);
9093 Function function(&scope, mainModuleAt(runtime_, "foo"));
9094 EXPECT_TRUE(containsBytecode(function, BUILD_SET_UNPACK));
9095 Object result(&scope, compileAndCallJITFunction(thread_, function));
9096 ASSERT_TRUE(result.isSet());
9097 EXPECT_EQ(Set::cast(*result).numItems(), 3);
9098}
9099
9100TEST_F(JitTest, BuildTupleReturnsTuple) {
9101 if (useCppInterpreter()) {
9102 GTEST_SKIP();
9103 }
9104 EXPECT_FALSE(runFromCStr(runtime_, R"(
9105def foo():
9106 a = 1
9107 return (a, 2)
9108)")
9109 .isError());
9110 HandleScope scope(thread_);
9111 Function function(&scope, mainModuleAt(runtime_, "foo"));
9112 EXPECT_TRUE(containsBytecode(function, BUILD_TUPLE));
9113 Object result(&scope, compileAndCallJITFunction(thread_, function));
9114 ASSERT_TRUE(result.isTuple());
9115 EXPECT_EQ(Tuple::cast(*result).length(), 2);
9116}
9117
9118TEST_F(JitTest, BuildTupleUnpackReturnsTuple) {
9119 if (useCppInterpreter()) {
9120 GTEST_SKIP();
9121 }
9122 EXPECT_FALSE(runFromCStr(runtime_, R"(
9123def foo():
9124 a = (2, 3)
9125 return (1, *a)
9126)")
9127 .isError());
9128 HandleScope scope(thread_);
9129 Function function(&scope, mainModuleAt(runtime_, "foo"));
9130 EXPECT_TRUE(containsBytecode(function, BUILD_TUPLE_UNPACK));
9131 Object result(&scope, compileAndCallJITFunction(thread_, function));
9132 ASSERT_TRUE(result.isTuple());
9133 EXPECT_EQ(Tuple::cast(*result).length(), 3);
9134}
9135
9136TEST_F(JitTest, BuildStringReturnsString) {
9137 if (useCppInterpreter()) {
9138 GTEST_SKIP();
9139 }
9140 HandleScope scope(thread_);
9141 const byte bytecode[] = {
9142 LOAD_CONST, 0, LOAD_CONST, 1, BUILD_STRING, 2, RETURN_VALUE, 0,
9143 };
9144 Object left(&scope, SmallStr::fromCStr("hello"));
9145 Object right(&scope, SmallStr::fromCStr(" world"));
9146 Tuple consts(&scope, runtime_->newTupleWith2(left, right));
9147 Code code(&scope, newCodeWithBytesConsts(bytecode, consts));
9148
9149 Str qualname(&scope, SmallStr::fromCStr("foo"));
9150 Module module(&scope, findMainModule(runtime_));
9151 Function function(
9152 &scope, runtime_->newFunctionWithCode(thread_, qualname, code, module));
9153 moduleAtPutByCStr(thread_, module, "foo", function);
9154 Object result(&scope, compileAndCallJITFunction(thread_, function));
9155 EXPECT_TRUE(isStrEqualsCStr(*result, "hello world"));
9156}
9157
9158TEST_F(JitTest, FormatValueReturnsString) {
9159 if (useCppInterpreter()) {
9160 GTEST_SKIP();
9161 }
9162 EXPECT_FALSE(runFromCStr(runtime_, R"(
9163def foo(obj):
9164 return f"foo{obj}bar"
9165)")
9166 .isError());
9167 HandleScope scope(thread_);
9168 Function function(&scope, mainModuleAt(runtime_, "foo"));
9169 EXPECT_TRUE(containsBytecode(function, FORMAT_VALUE));
9170 Object obj(&scope, SmallInt::fromWord(123));
9171 Object result(&scope, compileAndCallJITFunction1(thread_, function, obj));
9172 EXPECT_TRUE(isStrEqualsCStr(*result, "foo123bar"));
9173}
9174
9175TEST_F(JitTest, DupTopTwoDuplicatesTwoTwoStackElements) {
9176 if (useCppInterpreter()) {
9177 GTEST_SKIP();
9178 }
9179 HandleScope scope(thread_);
9180 byte bytecode[] = {
9181 LOAD_CONST, 0, LOAD_CONST, 1, DUP_TOP_TWO, 0,
9182 BUILD_LIST, 4, RETURN_VALUE, 0,
9183 };
9184 Object left(&scope, SmallInt::fromWord(1));
9185 Object right(&scope, SmallInt::fromWord(2));
9186 Tuple consts(&scope, runtime_->newTupleWith2(left, right));
9187 Code code(&scope, newCodeWithBytesConsts(bytecode, consts));
9188
9189 Str qualname(&scope, SmallStr::fromCStr("foo"));
9190 Module module(&scope, findMainModule(runtime_));
9191 Function function(
9192 &scope, runtime_->newFunctionWithCode(thread_, qualname, code, module));
9193 moduleAtPutByCStr(thread_, module, "foo", function);
9194 Object result(&scope, compileAndCallJITFunction(thread_, function));
9195 EXPECT_PYLIST_EQ(result, {1, 2, 1, 2});
9196}
9197
9198TEST_F(JitTest, RotFourRotatesStackElements) {
9199 if (useCppInterpreter()) {
9200 GTEST_SKIP();
9201 }
9202 HandleScope scope(thread_);
9203 const byte bytecode[] = {
9204 LOAD_CONST, 0, LOAD_CONST, 1, LOAD_CONST, 2, LOAD_CONST, 3,
9205 ROT_FOUR, 0, BUILD_LIST, 4, RETURN_VALUE, 0,
9206 };
9207 Object obj1(&scope, SmallInt::fromWord(1));
9208 Object obj2(&scope, SmallInt::fromWord(2));
9209 Object obj3(&scope, SmallInt::fromWord(3));
9210 Object obj4(&scope, SmallInt::fromWord(4));
9211 Tuple consts(&scope, runtime_->newTupleWith4(obj1, obj2, obj3, obj4));
9212 Code code(&scope, newCodeWithBytesConsts(bytecode, consts));
9213
9214 Str qualname(&scope, SmallStr::fromCStr("foo"));
9215 Module module(&scope, findMainModule(runtime_));
9216 Function function(
9217 &scope, runtime_->newFunctionWithCode(thread_, qualname, code, module));
9218 moduleAtPutByCStr(thread_, module, "foo", function);
9219 Object result(&scope, compileAndCallJITFunction(thread_, function));
9220 EXPECT_PYLIST_EQ(result, {4, 1, 2, 3});
9221}
9222
9223TEST_F(JitTest, RotThreeRotatesStackElements) {
9224 if (useCppInterpreter()) {
9225 GTEST_SKIP();
9226 }
9227 HandleScope scope(thread_);
9228 const byte bytecode[] = {
9229 LOAD_CONST, 0, LOAD_CONST, 1, LOAD_CONST, 2,
9230 ROT_THREE, 0, BUILD_LIST, 3, RETURN_VALUE, 0,
9231 };
9232 Object obj1(&scope, SmallInt::fromWord(1));
9233 Object obj2(&scope, SmallInt::fromWord(2));
9234 Object obj3(&scope, SmallInt::fromWord(3));
9235 Tuple consts(&scope, runtime_->newTupleWith3(obj1, obj2, obj3));
9236 Code code(&scope, newCodeWithBytesConsts(bytecode, consts));
9237
9238 Str qualname(&scope, SmallStr::fromCStr("foo"));
9239 Module module(&scope, findMainModule(runtime_));
9240 Function function(
9241 &scope, runtime_->newFunctionWithCode(thread_, qualname, code, module));
9242 moduleAtPutByCStr(thread_, module, "foo", function);
9243 Object result(&scope, compileAndCallJITFunction(thread_, function));
9244 EXPECT_PYLIST_EQ(result, {3, 1, 2});
9245}
9246
9247TEST_F(JitTest, UnaryNegativeCallsDunderNeg) {
9248 if (useCppInterpreter()) {
9249 GTEST_SKIP();
9250 }
9251 ASSERT_FALSE(runFromCStr(runtime_, R"(
9252class C:
9253 def __neg__(self):
9254 return 5
9255def foo(obj):
9256 return -obj
9257instance = C()
9258foo(instance) # Change UNARY_OP_ANAMORPHIC to UNARY_NEGATIVE
9259)")
9260 .isError());
9261 HandleScope scope(thread_);
9262 Function function(&scope, mainModuleAt(runtime_, "foo"));
9263 EXPECT_TRUE(containsBytecode(function, UNARY_NEGATIVE));
9264 Object obj(&scope, mainModuleAt(runtime_, "instance"));
9265 Object result(&scope, compileAndCallJITFunction1(thread_, function, obj));
9266 EXPECT_TRUE(isIntEqualsWord(*result, 5));
9267}
9268
9269TEST_F(JitTest, UnaryNegativeSmallIntWithPositiveReturnsNegative) {
9270 if (useCppInterpreter()) {
9271 GTEST_SKIP();
9272 }
9273 ASSERT_FALSE(runFromCStr(runtime_, R"(
9274def foo(obj):
9275 return -obj
9276foo(0) # Change UNARY_OP_ANAMORPHIC to UNARY_NEGATIVE_SMALLINT
9277)")
9278 .isError());
9279 HandleScope scope(thread_);
9280 Function function(&scope, mainModuleAt(runtime_, "foo"));
9281 EXPECT_TRUE(containsBytecode(function, UNARY_NEGATIVE_SMALLINT));
9282 Object obj(&scope, SmallInt::fromWord(123));
9283 Object result(&scope, compileAndCallJITFunction1(thread_, function, obj));
9284 EXPECT_TRUE(isIntEqualsWord(*result, -123));
9285}
9286
9287TEST_F(JitTest, UnaryNegativeSmallIntWithNegativeReturnsPositive) {
9288 if (useCppInterpreter()) {
9289 GTEST_SKIP();
9290 }
9291 ASSERT_FALSE(runFromCStr(runtime_, R"(
9292def foo(obj):
9293 return -obj
9294foo(0) # Change UNARY_OP_ANAMORPHIC to UNARY_NEGATIVE_SMALLINT
9295)")
9296 .isError());
9297 HandleScope scope(thread_);
9298 Function function(&scope, mainModuleAt(runtime_, "foo"));
9299 EXPECT_TRUE(containsBytecode(function, UNARY_NEGATIVE_SMALLINT));
9300 Object obj(&scope, SmallInt::fromWord(-123));
9301 Object result(&scope, compileAndCallJITFunction1(thread_, function, obj));
9302 EXPECT_TRUE(isIntEqualsWord(*result, 123));
9303}
9304
9305TEST_F(JitTest, UnaryNegativeSmallIntWithZeroReturnsZero) {
9306 if (useCppInterpreter()) {
9307 GTEST_SKIP();
9308 }
9309 ASSERT_FALSE(runFromCStr(runtime_, R"(
9310def foo(obj):
9311 return -obj
9312foo(0) # Change UNARY_OP_ANAMORPHIC to UNARY_NEGATIVE_SMALLINT
9313)")
9314 .isError());
9315 HandleScope scope(thread_);
9316 Function function(&scope, mainModuleAt(runtime_, "foo"));
9317 EXPECT_TRUE(containsBytecode(function, UNARY_NEGATIVE_SMALLINT));
9318 Object obj(&scope, SmallInt::fromWord(0));
9319 Object result(&scope, compileAndCallJITFunction1(thread_, function, obj));
9320 EXPECT_TRUE(isIntEqualsWord(*result, 0));
9321}
9322
9323TEST_F(JitTest, UnaryPositiveCallsDunderPos) {
9324 if (useCppInterpreter()) {
9325 GTEST_SKIP();
9326 }
9327 ASSERT_FALSE(runFromCStr(runtime_, R"(
9328class C:
9329 def __pos__(self):
9330 return 5
9331def foo(obj):
9332 return +obj
9333instance = C()
9334)")
9335 .isError());
9336 HandleScope scope(thread_);
9337 Function function(&scope, mainModuleAt(runtime_, "foo"));
9338 EXPECT_TRUE(containsBytecode(function, UNARY_POSITIVE));
9339 Object obj(&scope, mainModuleAt(runtime_, "instance"));
9340 Object result(&scope, compileAndCallJITFunction1(thread_, function, obj));
9341 EXPECT_TRUE(isIntEqualsWord(*result, 5));
9342}
9343
9344TEST_F(JitTest, UnaryInvertCallsDunderInvert) {
9345 if (useCppInterpreter()) {
9346 GTEST_SKIP();
9347 }
9348 ASSERT_FALSE(runFromCStr(runtime_, R"(
9349class C:
9350 def __invert__(self):
9351 return 5
9352def foo(obj):
9353 return ~obj
9354instance = C()
9355)")
9356 .isError());
9357 HandleScope scope(thread_);
9358 Function function(&scope, mainModuleAt(runtime_, "foo"));
9359 EXPECT_TRUE(containsBytecode(function, UNARY_INVERT));
9360 Object obj(&scope, mainModuleAt(runtime_, "instance"));
9361 Object result(&scope, compileAndCallJITFunction1(thread_, function, obj));
9362 EXPECT_TRUE(isIntEqualsWord(*result, 5));
9363}
9364
9365TEST_F(JitTest, BinaryMulSmallintWithSmallIntsReturnsInt) {
9366 if (useCppInterpreter()) {
9367 GTEST_SKIP();
9368 }
9369 EXPECT_FALSE(runFromCStr(runtime_, R"(
9370def foo(left, right):
9371 return left * right
9372
9373# Rewrite BINARY_OP_ANAMORPHIC to BINARY_MUL_SMALLINT
9374foo(1, 1)
9375)")
9376 .isError());
9377
9378 HandleScope scope(thread_);
9379 Function function(&scope, mainModuleAt(runtime_, "foo"));
9380 EXPECT_TRUE(containsBytecode(function, BINARY_MUL_SMALLINT));
9381 Object left(&scope, SmallInt::fromWord(5));
9382 Object right(&scope, SmallInt::fromWord(10));
9383 Object result(&scope,
9384 compileAndCallJITFunction2(thread_, function, left, right));
9385 EXPECT_TRUE(isIntEqualsWord(*result, 50));
9386}
9387
9388TEST_F(JitTest, BinaryMulSmallintWithNonSmallintDeoptimizes) {
9389 if (useCppInterpreter()) {
9390 GTEST_SKIP();
9391 }
9392 // Don't use compileAndCallJITFunction2 in this function because we want to
9393 // test deoptimizing back into the interpreter. This requires valid bytecode.
9394 EXPECT_FALSE(runFromCStr(runtime_, R"(
9395def foo(left, right):
9396 return left * right
9397
9398# Rewrite BINARY_OP_ANAMORPHIC to BINARY_MUL_SMALLINT
9399foo(1, 1)
9400)")
9401 .isError());
9402
9403 HandleScope scope(thread_);
9404 Function function(&scope, mainModuleAt(runtime_, "foo"));
9405 EXPECT_TRUE(containsBytecode(function, BINARY_MUL_SMALLINT));
9406 void* entry_before = function.entryAsm();
9407 compileFunction(thread_, function);
9408 EXPECT_NE(function.entryAsm(), entry_before);
9409 Object left_str(&scope, SmallStr::fromCStr("hello"));
9410 Object right(&scope, SmallInt::fromWord(2));
9411 Function deopt_caller(&scope,
9412 createTrampolineFunction2(thread_, left_str, right));
9413 Object result(&scope, Interpreter::call0(thread_, deopt_caller));
9414 EXPECT_TRUE(containsBytecode(function, BINARY_OP_MONOMORPHIC));
9415 EXPECT_TRUE(isStrEqualsCStr(*result, "hellohello"));
9416 EXPECT_EQ(function.entryAsm(), entry_before);
9417}
9418
9419TEST_F(JitTest, BinaryMulSmallintWithOverflowDeoptimizes) {
9420 if (useCppInterpreter()) {
9421 GTEST_SKIP();
9422 }
9423 // Don't use compileAndCallJITFunction2 in this function because we want to
9424 // test deoptimizing back into the interpreter. This requires valid bytecode.
9425 EXPECT_FALSE(runFromCStr(runtime_, R"(
9426def foo(left, right):
9427 return left * right
9428
9429# Rewrite BINARY_OP_ANAMORPHIC to BINARY_MUL_SMALLINT
9430foo(1, 1)
9431)")
9432 .isError());
9433
9434 HandleScope scope(thread_);
9435 Function function(&scope, mainModuleAt(runtime_, "foo"));
9436 EXPECT_TRUE(containsBytecode(function, BINARY_MUL_SMALLINT));
9437 void* entry_before = function.entryAsm();
9438 compileFunction(thread_, function);
9439 EXPECT_NE(function.entryAsm(), entry_before);
9440 Object left(&scope, SmallInt::fromWord(SmallInt::kMaxValue));
9441 Object right(&scope, SmallInt::fromWord(2));
9442 Function deopt_caller(&scope,
9443 createTrampolineFunction2(thread_, left, right));
9444 Object result(&scope, Interpreter::call0(thread_, deopt_caller));
9445 EXPECT_TRUE(containsBytecode(function, BINARY_OP_MONOMORPHIC));
9446 EXPECT_TRUE(isIntEqualsWord(*result, SmallInt::kMaxValue * 2));
9447 EXPECT_EQ(function.entryAsm(), entry_before);
9448}
9449
9450TEST_F(JitTest, BinaryMulSmallintWithUnderflowDeoptimizes) {
9451 if (useCppInterpreter()) {
9452 GTEST_SKIP();
9453 }
9454 // Don't use compileAndCallJITFunction2 in this function because we want to
9455 // test deoptimizing back into the interpreter. This requires valid bytecode.
9456 EXPECT_FALSE(runFromCStr(runtime_, R"(
9457def foo(left, right):
9458 return left * right
9459
9460# Rewrite BINARY_OP_ANAMORPHIC to BINARY_MUL_SMALLINT
9461foo(1, 1)
9462)")
9463 .isError());
9464
9465 HandleScope scope(thread_);
9466 Function function(&scope, mainModuleAt(runtime_, "foo"));
9467 EXPECT_TRUE(containsBytecode(function, BINARY_MUL_SMALLINT));
9468 void* entry_before = function.entryAsm();
9469 compileFunction(thread_, function);
9470 EXPECT_NE(function.entryAsm(), entry_before);
9471 Object left(&scope, SmallInt::fromWord(SmallInt::kMinValue));
9472 Object right(&scope, SmallInt::fromWord(2));
9473 Function deopt_caller(&scope,
9474 createTrampolineFunction2(thread_, left, right));
9475 Object result(&scope, Interpreter::call0(thread_, deopt_caller));
9476 EXPECT_TRUE(containsBytecode(function, BINARY_OP_MONOMORPHIC));
9477 EXPECT_TRUE(isIntEqualsWord(*result, SmallInt::kMinValue * 2));
9478 EXPECT_EQ(function.entryAsm(), entry_before);
9479}
9480
9481TEST_F(JitTest, CallFunctionWithInterpretedFunctionCallsFunction) {
9482 if (useCppInterpreter()) {
9483 GTEST_SKIP();
9484 }
9485 ASSERT_FALSE(runFromCStr(runtime_, R"(
9486def bar(a, b):
9487 return a + b
9488def foo():
9489 return bar(3, 4)
9490# Rewrite CALL_FUNCTION_ANAMORPHIC to CALL_FUNCTION
9491foo()
9492)")
9493 .isError());
9494 HandleScope scope(thread_);
9495 Function function(&scope, mainModuleAt(runtime_, "foo"));
9496 EXPECT_TRUE(containsBytecode(function, CALL_FUNCTION));
9497 Object result(&scope, compileAndCallJITFunction(thread_, function));
9498 EXPECT_TRUE(isIntEqualsWord(*result, 7));
9499}
9500
9501TEST_F(JitTest, CallFunctionWithGeneratorFunctionCallsFunction) {
9502 if (useCppInterpreter()) {
9503 GTEST_SKIP();
9504 }
9505 ASSERT_FALSE(runFromCStr(runtime_, R"(
9506def bar(a, b):
9507 yield a + b
9508def foo():
9509 return bar(3, 4)
9510# Rewrite CALL_FUNCTION_ANAMORPHIC to CALL_FUNCTION
9511foo()
9512)")
9513 .isError());
9514 HandleScope scope(thread_);
9515 Function function(&scope, mainModuleAt(runtime_, "foo"));
9516 EXPECT_TRUE(containsBytecode(function, CALL_FUNCTION));
9517 Object result(&scope, compileAndCallJITFunction(thread_, function));
9518 EXPECT_TRUE(result.isGenerator());
9519}
9520
9521static ALIGN_16 RawObject addTwoNumbers(Thread*, Arguments args) {
9522 return SmallInt::fromWord(SmallInt::cast(args.get(0)).value() +
9523 SmallInt::cast(args.get(1)).value());
9524}
9525
9526TEST_F(JitTest, CallFunctionWithBuiltinFunctionCallsFunction) {
9527 if (useCppInterpreter()) {
9528 GTEST_SKIP();
9529 }
9530 const char* params[] = {"a", "b"};
9531 addBuiltin("bar", addTwoNumbers, params, 0);
9532 ASSERT_FALSE(runFromCStr(runtime_, R"(
9533def foo():
9534 return bar(3, 4)
9535# Rewrite CALL_FUNCTION_ANAMORPHIC to CALL_FUNCTION
9536foo()
9537)")
9538 .isError());
9539 HandleScope scope(thread_);
9540 Function function(&scope, mainModuleAt(runtime_, "foo"));
9541 EXPECT_TRUE(containsBytecode(function, CALL_FUNCTION));
9542 Object result(&scope, compileAndCallJITFunction(thread_, function));
9543 EXPECT_TRUE(isIntEqualsWord(*result, 7));
9544}
9545
9546TEST_F(JitTest, CallFunctionWithCallableCallsDunderCall) {
9547 if (useCppInterpreter()) {
9548 GTEST_SKIP();
9549 }
9550 ASSERT_FALSE(runFromCStr(runtime_, R"(
9551def function():
9552 return 5
9553def foo(fn):
9554 return fn()
9555# Rewrite CALL_FUNCTION_ANAMORPHIC to CALL_FUNCTION
9556foo(function)
9557class C:
9558 def __call__(self):
9559 return 10
9560instance = C()
9561)")
9562 .isError());
9563 HandleScope scope(thread_);
9564 Function function(&scope, mainModuleAt(runtime_, "foo"));
9565 EXPECT_TRUE(containsBytecode(function, CALL_FUNCTION));
9566 Object callable(&scope, mainModuleAt(runtime_, "instance"));
9567 Object result(&scope,
9568 compileAndCallJITFunction1(thread_, function, callable));
9569 EXPECT_TRUE(isIntEqualsWord(*result, 10));
9570}
9571
9572TEST_F(JitTest, BinarySubscrMonomorphicCallsDunderGetitem) {
9573 if (useCppInterpreter()) {
9574 GTEST_SKIP();
9575 }
9576 ASSERT_FALSE(runFromCStr(runtime_, R"(
9577class C:
9578 def __getitem__(self, key):
9579 return key * 2
9580
9581def foo(ls):
9582 return ls[3]
9583
9584# Rewrite BINARY_SUBSCR_ANAMORPHIC to BINARY_SUBSCR_MONOMORPHIC
9585foo(C())
9586
9587instance = C()
9588)")
9589 .isError());
9590 HandleScope scope(thread_);
9591 Function function(&scope, mainModuleAt(runtime_, "foo"));
9592 EXPECT_TRUE(containsBytecode(function, BINARY_SUBSCR_MONOMORPHIC));
9593 Object callable(&scope, mainModuleAt(runtime_, "instance"));
9594 Object result(&scope,
9595 compileAndCallJITFunction1(thread_, function, callable));
9596 EXPECT_TRUE(isIntEqualsWord(*result, 6));
9597}
9598
9599TEST_F(JitTest, BinarySubscrMonomorphicWithNewTypeDeoptimizes) {
9600 if (useCppInterpreter()) {
9601 GTEST_SKIP();
9602 }
9603 ASSERT_FALSE(runFromCStr(runtime_, R"(
9604class C:
9605 def __getitem__(self, key):
9606 return 7
9607
9608class D:
9609 def __getitem__(self, key):
9610 return 13
9611
9612def foo(ls):
9613 return ls[3]
9614
9615# Rewrite BINARY_SUBSCR_ANAMORPHIC to BINARY_SUBSCR_MONOMORPHIC
9616foo(C())
9617
9618instance = D()
9619)")
9620 .isError());
9621 HandleScope scope(thread_);
9622 Function function(&scope, mainModuleAt(runtime_, "foo"));
9623 EXPECT_TRUE(containsBytecode(function, BINARY_SUBSCR_MONOMORPHIC));
9624 Object instance(&scope, mainModuleAt(runtime_, "instance"));
9625 void* entry_before = function.entryAsm();
9626 compileFunction(thread_, function);
9627 EXPECT_NE(function.entryAsm(), entry_before);
9628 Function deopt_caller(&scope, createTrampolineFunction1(thread_, instance));
9629 Object result(&scope, Interpreter::call0(thread_, deopt_caller));
9630 EXPECT_TRUE(containsBytecode(function, BINARY_SUBSCR_POLYMORPHIC));
9631 EXPECT_TRUE(isIntEqualsWord(*result, 13));
9632 EXPECT_EQ(function.entryAsm(), entry_before);
9633}
9634
9635TEST_F(JitTest, StoreAttrInstanceUpdateWithInstanceStoresAttribute) {
9636 if (useCppInterpreter()) {
9637 GTEST_SKIP();
9638 }
9639 EXPECT_FALSE(runFromCStr(runtime_, R"(
9640class C:
9641 def __init__(self, value):
9642 self.bar = value
9643
9644foo = C.__init__
9645
9646# Rewrite STORE_ATTR_ANAMORPHIC to STORE_ATTR_INSTANCE_UPDATE
9647instance = C(10)
9648)")
9649 .isError());
9650 HandleScope scope(thread_);
9651 Function function(&scope, mainModuleAt(runtime_, "foo"));
9652 EXPECT_TRUE(containsBytecode(function, STORE_ATTR_INSTANCE_UPDATE));
9653 // Don't use compileAndCallJITFunction2 in this function because the C++
9654 // handler needs to be able to read the cache index off the bytecode.
9655 compileFunction(thread_, function);
9656 Object self(&scope, mainModuleAt(runtime_, "instance"));
9657 Object value(&scope, SmallInt::fromWord(10));
9658 Function caller(&scope, createTrampolineFunction2(thread_, self, value));
9659 Object result(&scope, Interpreter::call0(thread_, caller));
9660 EXPECT_TRUE(result.isNoneType());
9661}
9662
9663TEST_F(JitTest, StoreAttrInstanceUpdateWithNewTypeDeoptimizes) {
9664 if (useCppInterpreter()) {
9665 GTEST_SKIP();
9666 }
9667 EXPECT_FALSE(runFromCStr(runtime_, R"(
9668class C:
9669 def __init__(self, value):
9670 self.bar = value
9671
9672foo = C.__init__
9673
9674# Rewrite STORE_ATTR_ANAMORPHIC to STORE_ATTR_INSTANCE_UPDATE
9675instance = C(10)
9676# Change the layout of `instance'
9677instance.attr = "blah"
9678)")
9679 .isError());
9680
9681 HandleScope scope(thread_);
9682 Function function(&scope, mainModuleAt(runtime_, "foo"));
9683 EXPECT_TRUE(containsBytecode(function, STORE_ATTR_INSTANCE_UPDATE));
9684 void* entry_before = function.entryAsm();
9685 // Don't use compileAndCallJITFunction2 in this function because we want to
9686 // test deoptimizing back into the interpreter. This requires valid bytecode.
9687 compileFunction(thread_, function);
9688 EXPECT_NE(function.entryAsm(), entry_before);
9689 Object self(&scope, mainModuleAt(runtime_, "instance"));
9690 Object value(&scope, SmallInt::fromWord(10));
9691 Function deopt_caller(&scope,
9692 createTrampolineFunction2(thread_, self, value));
9693 Object result(&scope, Interpreter::call0(thread_, deopt_caller));
9694 EXPECT_TRUE(result.isNoneType());
9695 EXPECT_TRUE(containsBytecode(function, STORE_ATTR_INSTANCE));
9696 EXPECT_EQ(function.entryAsm(), entry_before);
9697}
9698
9699TEST_F(JitTest, BinaryOpMonomorphicCallsCachedFunction) {
9700 if (useCppInterpreter()) {
9701 GTEST_SKIP();
9702 }
9703 EXPECT_FALSE(runFromCStr(runtime_, R"(
9704class C:
9705 def __mul__(self, other):
9706 return other * 10
9707
9708def foo(left, right):
9709 return left * right
9710
9711# Rewrite BINARY_OP_ANAMORPHIC to BINARY_OP_MONOMORPHIC
9712foo(C(), 1)
9713instance = C()
9714)")
9715 .isError());
9716
9717 HandleScope scope(thread_);
9718 Function function(&scope, mainModuleAt(runtime_, "foo"));
9719 EXPECT_TRUE(containsBytecode(function, BINARY_OP_MONOMORPHIC));
9720 // Don't use compileAndCallJITFunction2 in this function because the C++
9721 // handler needs to be able to read the cache index off the bytecode.
9722 compileFunction(thread_, function);
9723 Object left(&scope, mainModuleAt(runtime_, "instance"));
9724 Object right(&scope, SmallInt::fromWord(5));
9725 Function caller(&scope, createTrampolineFunction2(thread_, left, right));
9726 Object result(&scope, Interpreter::call0(thread_, caller));
9727 EXPECT_TRUE(isIntEqualsWord(*result, 50));
9728}
9729
9730TEST_F(JitTest, BinaryOpMonomorphicWithNewTypeDeoptimizes) {
9731 if (useCppInterpreter()) {
9732 GTEST_SKIP();
9733 }
9734 // Don't use compileAndCallJITFunction2 in this function because we want to
9735 // test deoptimizing back into the interpreter. This requires valid bytecode.
9736 EXPECT_FALSE(runFromCStr(runtime_, R"(
9737class C:
9738 def __mul__(self, other):
9739 return other * 10
9740
9741class D(C):
9742 pass
9743
9744def foo(left, right):
9745 return left * right
9746
9747# Rewrite BINARY_OP_ANAMORPHIC to BINARY_MUL_SMALLINT
9748foo(C(), 1)
9749instance = D()
9750)")
9751 .isError());
9752
9753 HandleScope scope(thread_);
9754 Function function(&scope, mainModuleAt(runtime_, "foo"));
9755 EXPECT_TRUE(containsBytecode(function, BINARY_OP_MONOMORPHIC));
9756 void* entry_before = function.entryAsm();
9757 compileFunction(thread_, function);
9758 EXPECT_NE(function.entryAsm(), entry_before);
9759 Object left(&scope, mainModuleAt(runtime_, "instance"));
9760 Object right(&scope, SmallInt::fromWord(2));
9761 Function deopt_caller(&scope,
9762 createTrampolineFunction2(thread_, left, right));
9763 Object result(&scope, Interpreter::call0(thread_, deopt_caller));
9764 EXPECT_TRUE(containsBytecode(function, BINARY_OP_POLYMORPHIC));
9765 EXPECT_TRUE(isIntEqualsWord(*result, 20));
9766 EXPECT_EQ(function.entryAsm(), entry_before);
9767}
9768
9769// Benchmarks
9770class InterpreterBenchmark : public benchmark::Fixture {
9771 public:
9772 void SetUp(benchmark::State&) {
9773 runtime_ = createTestRuntime();
9774 thread_ = Thread::current();
9775 }
9776
9777 void TearDown(benchmark::State&) { delete runtime_; }
9778
9779 protected:
9780 Runtime* runtime_;
9781 Thread* thread_;
9782};
9783
9784BENCHMARK_F(InterpreterBenchmark, SimpleFunction)(benchmark::State& state) {
9785 EXPECT_FALSE(runFromCStr(runtime_, R"(
9786def foo():
9787 x = 1
9788 y = 2
9789 return x + y
9790)")
9791 .isError());
9792 HandleScope scope(thread_);
9793 Function foo(&scope, mainModuleAt(runtime_, "foo"));
9794 for (auto _ : state) {
9795 Object result(&scope, Interpreter::call0(thread_, foo));
9796 static_cast<void>(result);
9797 }
9798}
9799
9800} // namespace testing
9801} // namespace py