this repo has no description
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com)
2#include "bytecode.h"
3
4#include "gtest/gtest.h"
5
6#include "ic.h"
7#include "test-utils.h"
8
9namespace py {
10namespace testing {
11
12using BytecodeTest = RuntimeFixture;
13
14TEST_F(BytecodeTest, NextBytecodeOpReturnsNextBytecodeOpPair) {
15 HandleScope scope(thread_);
16 const byte bytecode_raw[] = {
17 NOP, 99, 0, 0, EXTENDED_ARG, 0xca, 0, 0,
18 LOAD_ATTR, 0xfe, 0, 0, LOAD_GLOBAL, 10, 0, 0,
19 EXTENDED_ARG, 1, 0, 0, EXTENDED_ARG, 2, 0, 0,
20 EXTENDED_ARG, 3, 0, 0, LOAD_ATTR, 4, 0, 0};
21 Bytes original_bytecode(&scope, runtime_->newBytesWithAll(bytecode_raw));
22 MutableBytes bytecode(
23 &scope, runtime_->mutableBytesFromBytes(thread_, original_bytecode));
24 word index = 0;
25 BytecodeOp bc = nextBytecodeOp(bytecode, &index);
26 EXPECT_EQ(bc.bc, NOP);
27 EXPECT_EQ(bc.arg, 99);
28
29 bc = nextBytecodeOp(bytecode, &index);
30 EXPECT_EQ(bc.bc, LOAD_ATTR);
31 EXPECT_EQ(bc.arg, 0xcafe);
32
33 bc = nextBytecodeOp(bytecode, &index);
34 EXPECT_EQ(bc.bc, LOAD_GLOBAL);
35 EXPECT_EQ(bc.arg, 10);
36
37 bc = nextBytecodeOp(bytecode, &index);
38 EXPECT_EQ(bc.bc, LOAD_ATTR);
39 EXPECT_EQ(bc.arg, 0x01020304);
40}
41
42TEST_F(BytecodeTest, OpargFromObject) {
43 EXPECT_EQ(NoneType::object(),
44 objectFromOparg(opargFromObject(NoneType::object())));
45 EXPECT_EQ(SmallInt::fromWord(-1),
46 objectFromOparg(opargFromObject(SmallInt::fromWord(-1))));
47 EXPECT_EQ(SmallInt::fromWord(-64),
48 objectFromOparg(opargFromObject(SmallInt::fromWord(-64))));
49 EXPECT_EQ(SmallInt::fromWord(0),
50 objectFromOparg(opargFromObject(SmallInt::fromWord(0))));
51 EXPECT_EQ(SmallInt::fromWord(63),
52 objectFromOparg(opargFromObject(SmallInt::fromWord(63))));
53 EXPECT_EQ(Str::empty(), objectFromOparg(opargFromObject(Str::empty())));
54 // Not immediate since it doesn't fit in byte.
55 EXPECT_NE(SmallInt::fromWord(64),
56 objectFromOparg(opargFromObject(SmallInt::fromWord(64))));
57}
58
59TEST_F(BytecodeTest, RewriteBytecodeWithMoreThanCacheLimitCapsRewriting) {
60 HandleScope scope(thread_);
61 Object name(&scope, Str::empty());
62 static const int cache_limit = 65536;
63 byte bytecode[(cache_limit + 2) * kCompilerCodeUnitSize];
64 std::memset(bytecode, 0, sizeof bytecode);
65 for (word i = 0; i < cache_limit; i++) {
66 bytecode[i * kCompilerCodeUnitSize] = LOAD_ATTR;
67 bytecode[(i * kCompilerCodeUnitSize) + 1] = i * 3;
68 }
69 // LOAD_GLOBAL 1039 == 4 * 256 + 15.
70 bytecode[cache_limit * kCompilerCodeUnitSize] = EXTENDED_ARG;
71 bytecode[cache_limit * kCompilerCodeUnitSize + 1] = 4;
72 bytecode[(cache_limit + 1) * kCompilerCodeUnitSize] = LOAD_GLOBAL;
73 bytecode[(cache_limit + 1) * kCompilerCodeUnitSize + 1] = 15;
74
75 word global_names_length = 600;
76 Tuple consts(&scope, runtime_->emptyTuple());
77 MutableTuple names(&scope, runtime_->newMutableTuple(global_names_length));
78 for (word i = 0; i < global_names_length; i++) {
79 names.atPut(i, runtime_->newStrFromFmt("g%w", i));
80 }
81 Tuple names_tuple(&scope, names.becomeImmutable());
82 Code code(&scope, newCodeWithBytesConstsNames(bytecode, consts, names_tuple));
83
84 Module module(&scope, findMainModule(runtime_));
85 Function function(&scope,
86 runtime_->newFunctionWithCode(thread_, name, code, module));
87
88 // newFunctionWithCode() calls rewriteBytecode().
89 Object rewritten_bytecode_obj(&scope, function.rewrittenBytecode());
90 ASSERT_TRUE(rewritten_bytecode_obj.isMutableBytes());
91 MutableBytes rewritten_bytecode(&scope, *rewritten_bytecode_obj);
92 word expected_cache = global_names_length / kIcPointersPerEntry;
93 word i = 0;
94 for (; i < cache_limit - global_names_length / kIcPointersPerEntry;) {
95 BytecodeOp op = nextBytecodeOp(rewritten_bytecode, &i);
96 EXPECT_EQ(op.bc, LOAD_ATTR_ANAMORPHIC)
97 << "unexpected " << kBytecodeNames[op.bc] << " at idx " << i;
98 EXPECT_EQ(op.arg, ((i - 1) * 3) % 256); // What fits in a byte
99 EXPECT_EQ(op.cache, expected_cache);
100 expected_cache++;
101 }
102 for (; i < cache_limit;) {
103 BytecodeOp op = nextBytecodeOp(rewritten_bytecode, &i);
104 EXPECT_EQ(op.bc, LOAD_ATTR)
105 << "unexpected " << kBytecodeNames[op.bc] << " at idx " << i;
106 }
107 BytecodeOp op = nextBytecodeOp(rewritten_bytecode, &i);
108 EXPECT_EQ(op.bc, LOAD_GLOBAL);
109 EXPECT_EQ(op.arg, 1039);
110 EXPECT_EQ(op.cache, 0);
111 EXPECT_EQ(Tuple::cast(function.caches()).length(),
112 cache_limit * kIcPointersPerEntry);
113 // The cache for LOAD_GLOBAL was populated.
114 EXPECT_GT(Tuple::cast(function.caches()).length(), 527);
115}
116
117TEST_F(BytecodeTest, RewriteBytecodeRewritesLoadAttrOperations) {
118 HandleScope scope(thread_);
119 Object name(&scope, Str::empty());
120 const byte bytecode[] = {
121 NOP, 99, EXTENDED_ARG, 0xca, LOAD_ATTR, 0xfe,
122 NOP, 106, EXTENDED_ARG, 1, EXTENDED_ARG, 2,
123 EXTENDED_ARG, 3, LOAD_ATTR, 4, LOAD_ATTR, 77,
124 };
125 Code code(&scope, newCodeWithBytes(bytecode));
126 Module module(&scope, findMainModule(runtime_));
127 Function function(&scope,
128 runtime_->newFunctionWithCode(thread_, name, code, module));
129 // newFunctionWithCode() calls rewriteBytecode().
130
131 byte expected[] = {
132 NOP,
133 99,
134 0,
135 0,
136 EXTENDED_ARG,
137 0xca,
138 0,
139 0,
140 LOAD_ATTR_ANAMORPHIC,
141 0xfe,
142 0,
143 0,
144 NOP,
145 106,
146 0,
147 0,
148 EXTENDED_ARG,
149 1,
150 0,
151 0,
152 EXTENDED_ARG,
153 2,
154 0,
155 0,
156 EXTENDED_ARG,
157 3,
158 0,
159 0,
160 LOAD_ATTR_ANAMORPHIC,
161 4,
162 1,
163 0,
164 LOAD_ATTR_ANAMORPHIC,
165 77,
166 2,
167 0,
168 };
169 Object rewritten_bytecode(&scope, function.rewrittenBytecode());
170 EXPECT_TRUE(isMutableBytesEqualsBytes(rewritten_bytecode, expected));
171
172 ASSERT_TRUE(function.caches().isTuple());
173 Tuple caches(&scope, function.caches());
174 EXPECT_EQ(caches.length(), 3 * kIcPointersPerEntry);
175 for (word i = 0, length = caches.length(); i < length; i++) {
176 EXPECT_TRUE(caches.at(i).isNoneType()) << "index " << i;
177 }
178}
179
180TEST_F(BytecodeTest, RewriteBytecodeRewritesLoadConstOperations) {
181 HandleScope scope(thread_);
182 Object name(&scope, Str::empty());
183 const byte bytecode[] = {LOAD_CONST, 0, LOAD_CONST, 1, LOAD_CONST, 2,
184 LOAD_CONST, 3, LOAD_CONST, 4};
185
186 // Immediate objects.
187 Object obj0(&scope, NoneType::object());
188 Object obj1(&scope, SmallInt::fromWord(0));
189 Object obj2(&scope, Str::empty());
190 // Not immediate since it doesn't fit in byte.
191 Object obj3(&scope, SmallInt::fromWord(64));
192 // Not immediate since it's a heap object.
193 Object obj4(&scope, runtime_->newList());
194 Tuple consts(&scope,
195 runtime_->newTupleWithN(5, &obj0, &obj1, &obj2, &obj3, &obj4));
196 Code code(&scope, newCodeWithBytesConsts(bytecode, consts));
197
198 Module module(&scope, findMainModule(runtime_));
199 Function function(&scope,
200 runtime_->newFunctionWithCode(thread_, name, code, module));
201
202 byte expected[] = {
203 LOAD_IMMEDIATE,
204 static_cast<byte>(opargFromObject(NoneType::object())),
205 0,
206 0,
207 LOAD_IMMEDIATE,
208 static_cast<byte>(opargFromObject(SmallInt::fromWord(0))),
209 0,
210 0,
211 LOAD_IMMEDIATE,
212 static_cast<byte>(opargFromObject(Str::empty())),
213 0,
214 0,
215 LOAD_CONST,
216 3,
217 0,
218 0,
219 LOAD_CONST,
220 4,
221 0,
222 0,
223 };
224 MutableBytes rewritten_bytecode(&scope, function.rewrittenBytecode());
225 EXPECT_TRUE(isMutableBytesEqualsBytes(rewritten_bytecode, expected));
226}
227
228TEST_F(BytecodeTest, RewriteBytecodeRewritesLoadConstToLoadBool) {
229 HandleScope scope(thread_);
230 Object name(&scope, Str::empty());
231 const byte bytecode[] = {LOAD_CONST, 0, LOAD_CONST, 1};
232
233 // Immediate objects.
234 Object obj0(&scope, Bool::trueObj());
235 Object obj1(&scope, Bool::falseObj());
236 Tuple consts(&scope, runtime_->newTupleWith2(obj0, obj1));
237 Code code(&scope, newCodeWithBytesConsts(bytecode, consts));
238
239 Module module(&scope, findMainModule(runtime_));
240 Function function(&scope,
241 runtime_->newFunctionWithCode(thread_, name, code, module));
242
243 byte expected[] = {
244 LOAD_BOOL, 0x80, 0, 0, LOAD_BOOL, 0, 0, 0,
245 };
246 MutableBytes rewritten_bytecode(&scope, function.rewrittenBytecode());
247 EXPECT_TRUE(isMutableBytesEqualsBytes(rewritten_bytecode, expected));
248}
249
250TEST_F(BytecodeTest, RewriteBytecodeRewritesLoadMethodOperations) {
251 HandleScope scope(thread_);
252 Object name(&scope, Str::empty());
253 const byte bytecode[] = {
254 NOP, 99, EXTENDED_ARG, 0xca, LOAD_METHOD, 0xfe,
255 NOP, 160, EXTENDED_ARG, 1, EXTENDED_ARG, 2,
256 EXTENDED_ARG, 3, LOAD_METHOD, 4, LOAD_METHOD, 77,
257 };
258 Code code(&scope, newCodeWithBytes(bytecode));
259
260 Module module(&scope, findMainModule(runtime_));
261 Function function(&scope,
262 runtime_->newFunctionWithCode(thread_, name, code, module));
263 // newFunctionWithCode() calls rewriteBytecode().
264
265 byte expected[] = {
266 NOP,
267 99,
268 0,
269 0,
270 EXTENDED_ARG,
271 0xca,
272 0,
273 0,
274 LOAD_METHOD_ANAMORPHIC,
275 0xfe,
276 0,
277 0,
278 NOP,
279 160,
280 0,
281 0,
282 EXTENDED_ARG,
283 1,
284 0,
285 0,
286 EXTENDED_ARG,
287 2,
288 0,
289 0,
290 EXTENDED_ARG,
291 3,
292 0,
293 0,
294 LOAD_METHOD_ANAMORPHIC,
295 4,
296 1,
297 0,
298 LOAD_METHOD_ANAMORPHIC,
299 77,
300 2,
301 0,
302 };
303 Object rewritten_bytecode(&scope, function.rewrittenBytecode());
304 EXPECT_TRUE(isMutableBytesEqualsBytes(rewritten_bytecode, expected));
305
306 ASSERT_TRUE(function.caches().isTuple());
307 Tuple caches(&scope, function.caches());
308 EXPECT_EQ(caches.length(), 3 * kIcPointersPerEntry);
309 for (word i = 0, length = caches.length(); i < length; i++) {
310 EXPECT_TRUE(caches.at(i).isNoneType()) << "index " << i;
311 }
312}
313
314TEST_F(BytecodeTest, RewriteBytecodeRewritesStoreAttr) {
315 HandleScope scope(thread_);
316 Object name(&scope, Str::empty());
317 const byte bytecode[] = {STORE_ATTR, 48};
318 Code code(&scope, newCodeWithBytes(bytecode));
319
320 Module module(&scope, findMainModule(runtime_));
321 Function function(&scope,
322 runtime_->newFunctionWithCode(thread_, name, code, module));
323 // newFunctionWithCode() calls rewriteBytecode().
324
325 byte expected[] = {
326 STORE_ATTR_ANAMORPHIC,
327 48,
328 0,
329 0,
330 };
331 Object rewritten_bytecode(&scope, function.rewrittenBytecode());
332 EXPECT_TRUE(isMutableBytesEqualsBytes(rewritten_bytecode, expected));
333}
334
335TEST_F(BytecodeTest, RewriteBytecodeRewritesBinaryOpcodes) {
336 HandleScope scope(thread_);
337 Object name(&scope, Str::empty());
338 const byte bytecode[] = {
339 BINARY_MATRIX_MULTIPLY,
340 0,
341 BINARY_POWER,
342 0,
343 BINARY_MULTIPLY,
344 0,
345 BINARY_MODULO,
346 0,
347 BINARY_ADD,
348 0,
349 BINARY_SUBTRACT,
350 0,
351 BINARY_FLOOR_DIVIDE,
352 0,
353 BINARY_TRUE_DIVIDE,
354 0,
355 BINARY_LSHIFT,
356 0,
357 BINARY_RSHIFT,
358 0,
359 BINARY_AND,
360 0,
361 BINARY_XOR,
362 0,
363 BINARY_OR,
364 0,
365 };
366 Code code(&scope, newCodeWithBytes(bytecode));
367
368 Module module(&scope, findMainModule(runtime_));
369 Function function(&scope,
370 runtime_->newFunctionWithCode(thread_, name, code, module));
371 // newFunctionWithCode() calls rewriteBytecode().
372
373 byte expected[] = {
374 BINARY_OP_ANAMORPHIC,
375 static_cast<word>(Interpreter::BinaryOp::MATMUL),
376 0,
377 0,
378 BINARY_OP_ANAMORPHIC,
379 static_cast<word>(Interpreter::BinaryOp::POW),
380 1,
381 0,
382 BINARY_OP_ANAMORPHIC,
383 static_cast<word>(Interpreter::BinaryOp::MUL),
384 2,
385 0,
386 BINARY_OP_ANAMORPHIC,
387 static_cast<word>(Interpreter::BinaryOp::MOD),
388 3,
389 0,
390 BINARY_OP_ANAMORPHIC,
391 static_cast<word>(Interpreter::BinaryOp::ADD),
392 4,
393 0,
394 BINARY_OP_ANAMORPHIC,
395 static_cast<word>(Interpreter::BinaryOp::SUB),
396 5,
397 0,
398 BINARY_OP_ANAMORPHIC,
399 static_cast<word>(Interpreter::BinaryOp::FLOORDIV),
400 6,
401 0,
402 BINARY_OP_ANAMORPHIC,
403 static_cast<word>(Interpreter::BinaryOp::TRUEDIV),
404 7,
405 0,
406 BINARY_OP_ANAMORPHIC,
407 static_cast<word>(Interpreter::BinaryOp::LSHIFT),
408 8,
409 0,
410 BINARY_OP_ANAMORPHIC,
411 static_cast<word>(Interpreter::BinaryOp::RSHIFT),
412 9,
413 0,
414 BINARY_OP_ANAMORPHIC,
415 static_cast<word>(Interpreter::BinaryOp::AND),
416 10,
417 0,
418 BINARY_OP_ANAMORPHIC,
419 static_cast<word>(Interpreter::BinaryOp::XOR),
420 11,
421 0,
422 BINARY_OP_ANAMORPHIC,
423 static_cast<word>(Interpreter::BinaryOp::OR),
424 12,
425 0,
426 };
427 Object rewritten_bytecode(&scope, function.rewrittenBytecode());
428 EXPECT_TRUE(isMutableBytesEqualsBytes(rewritten_bytecode, expected));
429}
430
431TEST_F(BytecodeTest, RewriteBytecodeRewritesInplaceOpcodes) {
432 HandleScope scope(thread_);
433 Object name(&scope, Str::empty());
434 const byte bytecode[] = {
435 INPLACE_MATRIX_MULTIPLY,
436 0,
437 INPLACE_POWER,
438 0,
439 INPLACE_MULTIPLY,
440 0,
441 INPLACE_MODULO,
442 0,
443 INPLACE_ADD,
444 0,
445 INPLACE_SUBTRACT,
446 0,
447 INPLACE_FLOOR_DIVIDE,
448 0,
449 INPLACE_TRUE_DIVIDE,
450 0,
451 INPLACE_LSHIFT,
452 0,
453 INPLACE_RSHIFT,
454 0,
455 INPLACE_AND,
456 0,
457 INPLACE_XOR,
458 0,
459 INPLACE_OR,
460 0,
461 };
462 Code code(&scope, newCodeWithBytes(bytecode));
463
464 Module module(&scope, findMainModule(runtime_));
465 Function function(&scope,
466 runtime_->newFunctionWithCode(thread_, name, code, module));
467 // newFunctionWithCode() calls rewriteBytecode().
468
469 byte expected[] = {
470 INPLACE_OP_ANAMORPHIC,
471 static_cast<word>(Interpreter::BinaryOp::MATMUL),
472 0,
473 0,
474 INPLACE_OP_ANAMORPHIC,
475 static_cast<word>(Interpreter::BinaryOp::POW),
476 1,
477 0,
478 INPLACE_OP_ANAMORPHIC,
479 static_cast<word>(Interpreter::BinaryOp::MUL),
480 2,
481 0,
482 INPLACE_OP_ANAMORPHIC,
483 static_cast<word>(Interpreter::BinaryOp::MOD),
484 3,
485 0,
486 INPLACE_OP_ANAMORPHIC,
487 static_cast<word>(Interpreter::BinaryOp::ADD),
488 4,
489 0,
490 INPLACE_OP_ANAMORPHIC,
491 static_cast<word>(Interpreter::BinaryOp::SUB),
492 5,
493 0,
494 INPLACE_OP_ANAMORPHIC,
495 static_cast<word>(Interpreter::BinaryOp::FLOORDIV),
496 6,
497 0,
498 INPLACE_OP_ANAMORPHIC,
499 static_cast<word>(Interpreter::BinaryOp::TRUEDIV),
500 7,
501 0,
502 INPLACE_OP_ANAMORPHIC,
503 static_cast<word>(Interpreter::BinaryOp::LSHIFT),
504 8,
505 0,
506 INPLACE_OP_ANAMORPHIC,
507 static_cast<word>(Interpreter::BinaryOp::RSHIFT),
508 9,
509 0,
510 INPLACE_OP_ANAMORPHIC,
511 static_cast<word>(Interpreter::BinaryOp::AND),
512 10,
513 0,
514 INPLACE_OP_ANAMORPHIC,
515 static_cast<word>(Interpreter::BinaryOp::XOR),
516 11,
517 0,
518 INPLACE_OP_ANAMORPHIC,
519 static_cast<word>(Interpreter::BinaryOp::OR),
520 12,
521 0,
522 };
523 Object rewritten_bytecode(&scope, function.rewrittenBytecode());
524 EXPECT_TRUE(isMutableBytesEqualsBytes(rewritten_bytecode, expected));
525}
526
527TEST_F(BytecodeTest, RewriteBytecodeRewritesCompareOpOpcodes) {
528 HandleScope scope(thread_);
529 Object name(&scope, Str::empty());
530 const byte bytecode[] = {
531 COMPARE_OP, CompareOp::LT, COMPARE_OP, CompareOp::LE,
532 COMPARE_OP, CompareOp::EQ, COMPARE_OP, CompareOp::NE,
533 COMPARE_OP, CompareOp::GT, COMPARE_OP, CompareOp::GE,
534 COMPARE_OP, CompareOp::IN, COMPARE_OP, CompareOp::NOT_IN,
535 COMPARE_OP, CompareOp::IS, COMPARE_OP, CompareOp::IS_NOT,
536 COMPARE_OP, CompareOp::EXC_MATCH,
537 };
538 Code code(&scope, newCodeWithBytes(bytecode));
539
540 Module module(&scope, findMainModule(runtime_));
541 Function function(&scope,
542 runtime_->newFunctionWithCode(thread_, name, code, module));
543 // newFunctionWithCode() calls rewriteBytecode().
544
545 byte expected[] = {
546 COMPARE_OP_ANAMORPHIC,
547 CompareOp::LT,
548 0,
549 0,
550 COMPARE_OP_ANAMORPHIC,
551 CompareOp::LE,
552 1,
553 0,
554 COMPARE_OP_ANAMORPHIC,
555 CompareOp::EQ,
556 2,
557 0,
558 COMPARE_OP_ANAMORPHIC,
559 CompareOp::NE,
560 3,
561 0,
562 COMPARE_OP_ANAMORPHIC,
563 CompareOp::GT,
564 4,
565 0,
566 COMPARE_OP_ANAMORPHIC,
567 CompareOp::GE,
568 5,
569 0,
570 COMPARE_IN_ANAMORPHIC,
571 0,
572 6,
573 0,
574 COMPARE_OP,
575 CompareOp::NOT_IN,
576 0,
577 0,
578 COMPARE_IS,
579 0,
580 0,
581 0,
582 COMPARE_IS_NOT,
583 0,
584 0,
585 0,
586 COMPARE_OP,
587 CompareOp::EXC_MATCH,
588 0,
589 0,
590 };
591 Object rewritten_bytecode(&scope, function.rewrittenBytecode());
592 EXPECT_TRUE(isMutableBytesEqualsBytes(rewritten_bytecode, expected));
593}
594
595TEST_F(BytecodeTest, RewriteBytecodeRewritesReservesCachesForGlobalVariables) {
596 HandleScope scope(thread_);
597 Object name(&scope, Str::empty());
598 const byte bytecode[] = {
599 LOAD_GLOBAL, 0, STORE_GLOBAL, 1, LOAD_ATTR, 9, DELETE_GLOBAL, 2,
600 STORE_NAME, 3, DELETE_NAME, 4, LOAD_ATTR, 9, LOAD_NAME, 5,
601 };
602 Tuple consts(&scope, runtime_->emptyTuple());
603 MutableTuple names(&scope, runtime_->newMutableTuple(12));
604 for (word i = 0; i < 12; i++) {
605 names.atPut(i, runtime_->newStrFromFmt("g%w", i));
606 }
607 Tuple names_tuple(&scope, names.becomeImmutable());
608 Code code(&scope, newCodeWithBytesConstsNames(bytecode, consts, names_tuple));
609
610 Module module(&scope, findMainModule(runtime_));
611 Function function(&scope,
612 runtime_->newFunctionWithCode(thread_, name, code, module));
613 // newFunctionWithCode() calls rewriteBytecode().
614
615 byte expected[] = {
616 LOAD_GLOBAL,
617 0,
618 0,
619 0,
620 STORE_GLOBAL,
621 1,
622 0,
623 0,
624 // Note that LOAD_ATTR's cache index starts at 6 to reserve the first 6
625 // cache lines for 12 global variables.
626 LOAD_ATTR_ANAMORPHIC,
627 9,
628 6,
629 0,
630 DELETE_GLOBAL,
631 2,
632 0,
633 0,
634 STORE_NAME,
635 3,
636 0,
637 0,
638 DELETE_NAME,
639 4,
640 0,
641 0,
642 LOAD_ATTR_ANAMORPHIC,
643 9,
644 7,
645 0,
646 LOAD_NAME,
647 5,
648 0,
649 0,
650 };
651 Object rewritten_bytecode(&scope, function.rewrittenBytecode());
652 EXPECT_TRUE(isMutableBytesEqualsBytes(rewritten_bytecode, expected));
653
654 Tuple caches(&scope, function.caches());
655 word num_global = 6;
656 word num_attr = 2;
657 EXPECT_EQ(caches.length(), (num_global + num_attr) * kIcPointersPerEntry);
658}
659
660TEST_F(
661 BytecodeTest,
662 RewriteBytecodeDoesNotRewriteLoadFastAndStoreFastOpcodesWithLargeLocalCount) {
663 HandleScope scope(thread_);
664 Object arg0(&scope, Runtime::internStrFromCStr(thread_, "arg0"));
665 Object var0(&scope, Runtime::internStrFromCStr(thread_, "var0"));
666 Object var1(&scope, Runtime::internStrFromCStr(thread_, "var1"));
667 Tuple varnames(&scope, runtime_->newTupleWith3(arg0, var0, var1));
668 Object freevar0(&scope, Runtime::internStrFromCStr(thread_, "freevar0"));
669 Tuple freevars(&scope, runtime_->newTupleWith1(freevar0));
670 Object cellvar0(&scope, Runtime::internStrFromCStr(thread_, "cellvar0"));
671 Tuple cellvars(&scope, runtime_->newTupleWith1(cellvar0));
672 word argcount = 1;
673 // Set nlocals > 255
674 word nlocals = kMaxByte + 3;
675 byte bytecode[] = {
676 LOAD_FAST, 2, LOAD_FAST, 1, LOAD_FAST, 1,
677 STORE_FAST, 2, STORE_FAST, 1, STORE_FAST, 0,
678 };
679 Bytes code_code(&scope, runtime_->newBytesWithAll(bytecode));
680 Object empty_tuple(&scope, runtime_->emptyTuple());
681 Object empty_string(&scope, Str::empty());
682 Object lnotab(&scope, Bytes::empty());
683 word flags = Code::Flags::kOptimized | Code::Flags::kNewlocals;
684 Code code(&scope,
685 runtime_->newCode(argcount, /*posonlyargcount=*/0,
686 /*kwonlyargcount=*/0, nlocals,
687 /*stacksize=*/0, /*flags=*/flags, code_code,
688 /*consts=*/empty_tuple, /*names=*/empty_tuple,
689 varnames, freevars, cellvars,
690 /*filename=*/empty_string, /*name=*/empty_string,
691 /*firstlineno=*/0, lnotab));
692
693 Module module(&scope, findMainModule(runtime_));
694 Function function(&scope, runtime_->newFunctionWithCode(thread_, empty_string,
695 code, module));
696 // newFunctionWithCode() calls rewriteBytecode().
697
698 byte expected[] = {
699 LOAD_FAST, 2, 0, 0, LOAD_FAST, 1, 0, 0, LOAD_FAST, 1, 0, 0,
700 STORE_FAST, 2, 0, 0, STORE_FAST, 1, 0, 0, STORE_FAST, 0, 0, 0,
701 };
702
703 Object rewritten_bytecode(&scope, function.rewrittenBytecode());
704 EXPECT_TRUE(isMutableBytesEqualsBytes(rewritten_bytecode, expected));
705 EXPECT_TRUE(function.caches().isNoneType());
706}
707
708TEST_F(BytecodeTest, RewriteBytecodeRewritesLoadFastAndStoreFastOpcodes) {
709 HandleScope scope(thread_);
710 Object arg0(&scope, Runtime::internStrFromCStr(thread_, "arg0"));
711 Object var0(&scope, Runtime::internStrFromCStr(thread_, "var0"));
712 Object var1(&scope, Runtime::internStrFromCStr(thread_, "var1"));
713 Tuple varnames(&scope, runtime_->newTupleWith3(arg0, var0, var1));
714 Object freevar0(&scope, Runtime::internStrFromCStr(thread_, "freevar0"));
715 Tuple freevars(&scope, runtime_->newTupleWith1(freevar0));
716 Object cellvar0(&scope, Runtime::internStrFromCStr(thread_, "cellvar0"));
717 Tuple cellvars(&scope, runtime_->newTupleWith1(cellvar0));
718 word argcount = 1;
719 word nlocals = 3;
720 byte bytecode[] = {
721 LOAD_FAST, 2, LOAD_FAST, 1, LOAD_FAST, 1,
722 STORE_FAST, 2, STORE_FAST, 1, STORE_FAST, 0,
723 };
724 Bytes code_code(&scope, runtime_->newBytesWithAll(bytecode));
725 Object empty_tuple(&scope, runtime_->emptyTuple());
726 Object empty_string(&scope, Str::empty());
727 Object lnotab(&scope, Bytes::empty());
728 word flags = Code::Flags::kOptimized | Code::Flags::kNewlocals;
729 Code code(&scope,
730 runtime_->newCode(argcount, /*posonlyargcount=*/0,
731 /*kwonlyargcount=*/0, nlocals,
732 /*stacksize=*/0, /*flags=*/flags, code_code,
733 /*consts=*/empty_tuple, /*names=*/empty_tuple,
734 varnames, freevars, cellvars,
735 /*filename=*/empty_string, /*name=*/empty_string,
736 /*firstlineno=*/0, lnotab));
737
738 Module module(&scope, findMainModule(runtime_));
739 Function function(&scope, runtime_->newFunctionWithCode(thread_, empty_string,
740 code, module));
741 // newFunctionWithCode() calls rewriteBytecode().
742
743 byte expected[] = {
744 LOAD_FAST_REVERSE, 2, 0, 0, LOAD_FAST_REVERSE, 3, 0, 0,
745 LOAD_FAST_REVERSE, 3, 0, 0, STORE_FAST_REVERSE, 2, 0, 0,
746 STORE_FAST_REVERSE, 3, 0, 0, STORE_FAST_REVERSE, 4, 0, 0,
747 };
748 Object rewritten_bytecode(&scope, function.rewrittenBytecode());
749 EXPECT_TRUE(isMutableBytesEqualsBytes(rewritten_bytecode, expected));
750 EXPECT_TRUE(function.caches().isNoneType());
751}
752
753TEST_F(
754 BytecodeTest,
755 RewriteBytecodeRewritesLoadFastToLoadFastReverseWhenDeleteFastIsPresent) {
756 HandleScope scope(thread_);
757 Object arg0(&scope, Runtime::internStrFromCStr(thread_, "arg0"));
758 Object var0(&scope, Runtime::internStrFromCStr(thread_, "var0"));
759 Object var1(&scope, Runtime::internStrFromCStr(thread_, "var1"));
760 Tuple varnames(&scope, runtime_->newTupleWith3(arg0, var0, var1));
761 Object freevar0(&scope, Runtime::internStrFromCStr(thread_, "freevar0"));
762 Tuple freevars(&scope, runtime_->newTupleWith1(freevar0));
763 Object cellvar0(&scope, Runtime::internStrFromCStr(thread_, "cellvar0"));
764 Tuple cellvars(&scope, runtime_->newTupleWith1(cellvar0));
765 word argcount = 1;
766 word nlocals = 3;
767 const byte bytecode[] = {
768 LOAD_FAST, 2, LOAD_FAST, 1, LOAD_FAST, 0, STORE_FAST, 2,
769 STORE_FAST, 1, STORE_FAST, 0, DELETE_FAST, 0,
770 };
771 Bytes code_code(&scope, runtime_->newBytesWithAll(bytecode));
772 Object empty_tuple(&scope, runtime_->emptyTuple());
773 Object empty_string(&scope, Str::empty());
774 Object lnotab(&scope, Bytes::empty());
775 word flags = Code::Flags::kOptimized | Code::Flags::kNewlocals;
776 Code code(&scope,
777 runtime_->newCode(argcount, /*posonlyargcount=*/0,
778 /*kwonlyargcount=*/0, nlocals,
779 /*stacksize=*/0, /*flags=*/flags, code_code,
780 /*consts=*/empty_tuple, /*names=*/empty_tuple,
781 varnames, freevars, cellvars,
782 /*filename=*/empty_string, /*name=*/empty_string,
783 /*firstlineno=*/0, lnotab));
784
785 Module module(&scope, findMainModule(runtime_));
786 Function function(&scope, runtime_->newFunctionWithCode(thread_, empty_string,
787 code, module));
788 // newFunctionWithCode() calls rewriteBytecode().
789
790 byte expected[] = {
791 LOAD_FAST_REVERSE, 2, 0, 0, LOAD_FAST_REVERSE, 3, 0, 0,
792 LOAD_FAST_REVERSE, 4, 0, 0, STORE_FAST_REVERSE, 2, 0, 0,
793 STORE_FAST_REVERSE, 3, 0, 0, STORE_FAST_REVERSE, 4, 0, 0,
794 DELETE_FAST, 0, 0, 0,
795 };
796 Object rewritten_bytecode(&scope, function.rewrittenBytecode());
797 EXPECT_TRUE(isMutableBytesEqualsBytes(rewritten_bytecode, expected));
798 EXPECT_TRUE(function.caches().isNoneType());
799}
800
801TEST_F(BytecodeTest,
802 RewriteBytecodeDoesNotRewriteFunctionsWithNoOptimizedNorNewLocalsFlag) {
803 HandleScope scope(thread_);
804 Object name(&scope, Str::empty());
805 Tuple consts(&scope, runtime_->emptyTuple());
806 Tuple names(&scope, runtime_->emptyTuple());
807 const byte bytecode[] = {
808 NOP, 99, EXTENDED_ARG, 0xca, LOAD_ATTR, 0xfe,
809 NOP, 106, EXTENDED_ARG, 1, EXTENDED_ARG, 2,
810 EXTENDED_ARG, 3, LOAD_ATTR, 4, LOAD_ATTR, 77,
811 };
812 Code code(&scope,
813 newCodeWithBytesConstsNamesFlags(bytecode, consts, names, 0));
814
815 Module module(&scope, findMainModule(runtime_));
816 Function function(&scope,
817 runtime_->newFunctionWithCode(thread_, name, code, module));
818
819 byte expected[] = {
820 NOP, 99, 0, 0, EXTENDED_ARG, 0xca, 0, 0,
821 LOAD_ATTR, 0xfe, 0, 0, NOP, 106, 0, 0,
822 EXTENDED_ARG, 1, 0, 0, EXTENDED_ARG, 2, 0, 0,
823 EXTENDED_ARG, 3, 0, 0, LOAD_ATTR, 4, 0, 0,
824 LOAD_ATTR, 77, 0, 0,
825 };
826 Object rewritten_bytecode(&scope, function.rewrittenBytecode());
827 EXPECT_TRUE(isMutableBytesEqualsBytes(rewritten_bytecode, expected));
828}
829
830} // namespace testing
831} // namespace py