1// Copyright 2013 the V8 project authors. All rights reserved. 2// Redistribution and use in source and binary forms, with or without 3// modification, are permitted provided that the following conditions are 4// met: 5// 6// * Redistributions of source code must retain the above copyright 7// notice, this list of conditions and the following disclaimer. 8// * Redistributions in binary form must reproduce the above 9// copyright notice, this list of conditions and the following 10// disclaimer in the documentation and/or other materials provided 11// with the distribution. 12// * Neither the name of Google Inc. nor the names of its 13// contributors may be used to endorse or promote products derived 14// from this software without specific prior written permission. 15// 16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28#include <stdlib.h> 29#include <iostream> // NOLINT(readability/streams) 30 31#include "src/v8.h" 32#include "test/cctest/cctest.h" 33 34#include "src/base/utils/random-number-generator.h" 35#include "src/macro-assembler.h" 36#include "src/mips64/macro-assembler-mips64.h" 37#include "src/mips64/simulator-mips64.h" 38 39 40using namespace v8::internal; 41 42typedef void* (*F)(int64_t x, int64_t y, int p2, int p3, int p4); 43typedef Object* (*F1)(int x, int p1, int p2, int p3, int p4); 44 45#define __ masm-> 46 47 48static byte to_non_zero(int n) { 49 return static_cast<unsigned>(n) % 255 + 1; 50} 51 52 53static bool all_zeroes(const byte* beg, const byte* end) { 54 CHECK(beg); 55 CHECK(beg <= end); 56 while (beg < end) { 57 if (*beg++ != 0) 58 return false; 59 } 60 return true; 61} 62 63 64TEST(CopyBytes) { 65 CcTest::InitializeVM(); 66 Isolate* isolate = CcTest::i_isolate(); 67 HandleScope handles(isolate); 68 69 const int data_size = 1 * KB; 70 size_t act_size; 71 72 // Allocate two blocks to copy data between. 73 byte* src_buffer = 74 static_cast<byte*>(v8::base::OS::Allocate(data_size, &act_size, 0)); 75 CHECK(src_buffer); 76 CHECK(act_size >= static_cast<size_t>(data_size)); 77 byte* dest_buffer = 78 static_cast<byte*>(v8::base::OS::Allocate(data_size, &act_size, 0)); 79 CHECK(dest_buffer); 80 CHECK(act_size >= static_cast<size_t>(data_size)); 81 82 // Storage for a0 and a1. 83 byte* a0_; 84 byte* a1_; 85 86 MacroAssembler assembler(isolate, NULL, 0, 87 v8::internal::CodeObjectRequired::kYes); 88 MacroAssembler* masm = &assembler; 89 90 // Code to be generated: The stuff in CopyBytes followed by a store of a0 and 91 // a1, respectively. 92 __ CopyBytes(a0, a1, a2, a3); 93 __ li(a2, Operand(reinterpret_cast<int64_t>(&a0_))); 94 __ li(a3, Operand(reinterpret_cast<int64_t>(&a1_))); 95 __ sd(a0, MemOperand(a2)); 96 __ jr(ra); 97 __ sd(a1, MemOperand(a3)); 98 99 CodeDesc desc; 100 masm->GetCode(&desc); 101 Handle<Code> code = isolate->factory()->NewCode( 102 desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); 103 104 ::F f = FUNCTION_CAST< ::F>(code->entry()); 105 106 // Initialise source data with non-zero bytes. 107 for (int i = 0; i < data_size; i++) { 108 src_buffer[i] = to_non_zero(i); 109 } 110 111 const int fuzz = 11; 112 113 for (int size = 0; size < 600; size++) { 114 for (const byte* src = src_buffer; src < src_buffer + fuzz; src++) { 115 for (byte* dest = dest_buffer; dest < dest_buffer + fuzz; dest++) { 116 memset(dest_buffer, 0, data_size); 117 CHECK(dest + size < dest_buffer + data_size); 118 (void)CALL_GENERATED_CODE(isolate, f, reinterpret_cast<int64_t>(src), 119 reinterpret_cast<int64_t>(dest), size, 0, 0); 120 // a0 and a1 should point at the first byte after the copied data. 121 CHECK_EQ(src + size, a0_); 122 CHECK_EQ(dest + size, a1_); 123 // Check that we haven't written outside the target area. 124 CHECK(all_zeroes(dest_buffer, dest)); 125 CHECK(all_zeroes(dest + size, dest_buffer + data_size)); 126 // Check the target area. 127 CHECK_EQ(0, memcmp(src, dest, size)); 128 } 129 } 130 } 131 132 // Check that the source data hasn't been clobbered. 133 for (int i = 0; i < data_size; i++) { 134 CHECK(src_buffer[i] == to_non_zero(i)); 135 } 136} 137 138 139TEST(LoadConstants) { 140 CcTest::InitializeVM(); 141 Isolate* isolate = CcTest::i_isolate(); 142 HandleScope handles(isolate); 143 144 int64_t refConstants[64]; 145 int64_t result[64]; 146 147 int64_t mask = 1; 148 for (int i = 0; i < 64; i++) { 149 refConstants[i] = ~(mask << i); 150 } 151 152 MacroAssembler assembler(isolate, NULL, 0, 153 v8::internal::CodeObjectRequired::kYes); 154 MacroAssembler* masm = &assembler; 155 156 __ mov(a4, a0); 157 for (int i = 0; i < 64; i++) { 158 // Load constant. 159 __ li(a5, Operand(refConstants[i])); 160 __ sd(a5, MemOperand(a4)); 161 __ Daddu(a4, a4, Operand(kPointerSize)); 162 } 163 164 __ jr(ra); 165 __ nop(); 166 167 CodeDesc desc; 168 masm->GetCode(&desc); 169 Handle<Code> code = isolate->factory()->NewCode( 170 desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); 171 172 ::F f = FUNCTION_CAST< ::F>(code->entry()); 173 (void)CALL_GENERATED_CODE(isolate, f, reinterpret_cast<int64_t>(result), 0, 0, 174 0, 0); 175 // Check results. 176 for (int i = 0; i < 64; i++) { 177 CHECK(refConstants[i] == result[i]); 178 } 179} 180 181 182TEST(LoadAddress) { 183 CcTest::InitializeVM(); 184 Isolate* isolate = CcTest::i_isolate(); 185 HandleScope handles(isolate); 186 187 MacroAssembler assembler(isolate, NULL, 0, 188 v8::internal::CodeObjectRequired::kYes); 189 MacroAssembler* masm = &assembler; 190 Label to_jump, skip; 191 __ mov(a4, a0); 192 193 __ Branch(&skip); 194 __ bind(&to_jump); 195 __ nop(); 196 __ nop(); 197 __ jr(ra); 198 __ nop(); 199 __ bind(&skip); 200 __ li(a4, Operand(masm->jump_address(&to_jump)), ADDRESS_LOAD); 201 int check_size = masm->InstructionsGeneratedSince(&skip); 202 CHECK_EQ(check_size, 4); 203 __ jr(a4); 204 __ nop(); 205 __ stop("invalid"); 206 __ stop("invalid"); 207 __ stop("invalid"); 208 __ stop("invalid"); 209 __ stop("invalid"); 210 211 212 CodeDesc desc; 213 masm->GetCode(&desc); 214 Handle<Code> code = isolate->factory()->NewCode( 215 desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); 216 217 ::F f = FUNCTION_CAST< ::F>(code->entry()); 218 (void)CALL_GENERATED_CODE(isolate, f, 0, 0, 0, 0, 0); 219 // Check results. 220} 221 222 223TEST(jump_tables4) { 224 // Similar to test-assembler-mips jump_tables1, with extra test for branch 225 // trampoline required before emission of the dd table (where trampolines are 226 // blocked), and proper transition to long-branch mode. 227 // Regression test for v8:4294. 228 CcTest::InitializeVM(); 229 Isolate* isolate = CcTest::i_isolate(); 230 HandleScope scope(isolate); 231 MacroAssembler assembler(isolate, NULL, 0, 232 v8::internal::CodeObjectRequired::kYes); 233 MacroAssembler* masm = &assembler; 234 235 const int kNumCases = 512; 236 int values[kNumCases]; 237 isolate->random_number_generator()->NextBytes(values, sizeof(values)); 238 Label labels[kNumCases]; 239 Label near_start, end; 240 241 __ daddiu(sp, sp, -8); 242 __ sd(ra, MemOperand(sp)); 243 244 __ mov(v0, zero_reg); 245 246 __ Branch(&end); 247 __ bind(&near_start); 248 249 // Generate slightly less than 32K instructions, which will soon require 250 // trampoline for branch distance fixup. 251 for (int i = 0; i < 32768 - 256; ++i) { 252 __ addiu(v0, v0, 1); 253 } 254 255 __ Align(8); 256 Label done; 257 { 258 __ BlockTrampolinePoolFor(kNumCases * 2 + 6); 259 PredictableCodeSizeScope predictable( 260 masm, (kNumCases * 2 + 6) * Assembler::kInstrSize); 261 Label here; 262 263 __ bal(&here); 264 __ dsll(at, a0, 3); // In delay slot. 265 __ bind(&here); 266 __ daddu(at, at, ra); 267 __ ld(at, MemOperand(at, 4 * Assembler::kInstrSize)); 268 __ jr(at); 269 __ nop(); // Branch delay slot nop. 270 for (int i = 0; i < kNumCases; ++i) { 271 __ dd(&labels[i]); 272 } 273 } 274 275 for (int i = 0; i < kNumCases; ++i) { 276 __ bind(&labels[i]); 277 __ lui(v0, (values[i] >> 16) & 0xffff); 278 __ ori(v0, v0, values[i] & 0xffff); 279 __ Branch(&done); 280 } 281 282 __ bind(&done); 283 __ ld(ra, MemOperand(sp)); 284 __ daddiu(sp, sp, 8); 285 __ jr(ra); 286 __ nop(); 287 288 __ bind(&end); 289 __ Branch(&near_start); 290 291 CodeDesc desc; 292 masm->GetCode(&desc); 293 Handle<Code> code = isolate->factory()->NewCode( 294 desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); 295#ifdef OBJECT_PRINT 296 code->Print(std::cout); 297#endif 298 F1 f = FUNCTION_CAST<F1>(code->entry()); 299 for (int i = 0; i < kNumCases; ++i) { 300 int64_t res = reinterpret_cast<int64_t>( 301 CALL_GENERATED_CODE(isolate, f, i, 0, 0, 0, 0)); 302 ::printf("f(%d) = %" PRId64 "\n", i, res); 303 CHECK_EQ(values[i], res); 304 } 305} 306 307 308TEST(jump_tables5) { 309 if (kArchVariant != kMips64r6) return; 310 311 // Similar to test-assembler-mips jump_tables1, with extra test for emitting a 312 // compact branch instruction before emission of the dd table. 313 CcTest::InitializeVM(); 314 Isolate* isolate = CcTest::i_isolate(); 315 HandleScope scope(isolate); 316 MacroAssembler assembler(isolate, nullptr, 0, 317 v8::internal::CodeObjectRequired::kYes); 318 MacroAssembler* masm = &assembler; 319 320 const int kNumCases = 512; 321 int values[kNumCases]; 322 isolate->random_number_generator()->NextBytes(values, sizeof(values)); 323 Label labels[kNumCases]; 324 Label done; 325 326 __ daddiu(sp, sp, -8); 327 __ sd(ra, MemOperand(sp)); 328 329 __ Align(8); 330 { 331 __ BlockTrampolinePoolFor(kNumCases * 2 + 7 + 1); 332 PredictableCodeSizeScope predictable( 333 masm, kNumCases * kPointerSize + ((7 + 1) * Assembler::kInstrSize)); 334 Label here; 335 336 __ bal(&here); 337 __ dsll(at, a0, 3); // In delay slot. 338 __ bind(&here); 339 __ daddu(at, at, ra); 340 __ ld(at, MemOperand(at, 6 * Assembler::kInstrSize)); 341 __ jalr(at); 342 __ nop(); // Branch delay slot nop. 343 __ bc(&done); 344 // A nop instruction must be generated by the forbidden slot guard 345 // (Assembler::dd(Label*)) so the first label goes to an 8 bytes aligned 346 // location. 347 for (int i = 0; i < kNumCases; ++i) { 348 __ dd(&labels[i]); 349 } 350 } 351 352 for (int i = 0; i < kNumCases; ++i) { 353 __ bind(&labels[i]); 354 __ lui(v0, (values[i] >> 16) & 0xffff); 355 __ ori(v0, v0, values[i] & 0xffff); 356 __ jr(ra); 357 __ nop(); 358 } 359 360 __ bind(&done); 361 __ ld(ra, MemOperand(sp)); 362 __ daddiu(sp, sp, 8); 363 __ jr(ra); 364 __ nop(); 365 366 CodeDesc desc; 367 masm->GetCode(&desc); 368 Handle<Code> code = isolate->factory()->NewCode( 369 desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); 370#ifdef OBJECT_PRINT 371 code->Print(std::cout); 372#endif 373 F1 f = FUNCTION_CAST<F1>(code->entry()); 374 for (int i = 0; i < kNumCases; ++i) { 375 int64_t res = reinterpret_cast<int64_t>( 376 CALL_GENERATED_CODE(isolate, f, i, 0, 0, 0, 0)); 377 ::printf("f(%d) = %" PRId64 "\n", i, res); 378 CHECK_EQ(values[i], res); 379 } 380} 381 382 383static uint64_t run_lsa(uint32_t rt, uint32_t rs, int8_t sa) { 384 Isolate* isolate = CcTest::i_isolate(); 385 HandleScope scope(isolate); 386 MacroAssembler assembler(isolate, nullptr, 0, 387 v8::internal::CodeObjectRequired::kYes); 388 MacroAssembler* masm = &assembler; 389 390 __ Lsa(v0, a0, a1, sa); 391 __ jr(ra); 392 __ nop(); 393 394 CodeDesc desc; 395 assembler.GetCode(&desc); 396 Handle<Code> code = isolate->factory()->NewCode( 397 desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); 398 399 F1 f = FUNCTION_CAST<F1>(code->entry()); 400 401 uint64_t res = reinterpret_cast<uint64_t>( 402 CALL_GENERATED_CODE(isolate, f, rt, rs, 0, 0, 0)); 403 404 return res; 405} 406 407 408TEST(Lsa) { 409 CcTest::InitializeVM(); 410 struct TestCaseLsa { 411 int32_t rt; 412 int32_t rs; 413 uint8_t sa; 414 uint64_t expected_res; 415 }; 416 417 struct TestCaseLsa tc[] = {// rt, rs, sa, expected_res 418 {0x4, 0x1, 1, 0x6}, 419 {0x4, 0x1, 2, 0x8}, 420 {0x4, 0x1, 3, 0xc}, 421 {0x4, 0x1, 4, 0x14}, 422 {0x4, 0x1, 5, 0x24}, 423 {0x0, 0x1, 1, 0x2}, 424 {0x0, 0x1, 2, 0x4}, 425 {0x0, 0x1, 3, 0x8}, 426 {0x0, 0x1, 4, 0x10}, 427 {0x0, 0x1, 5, 0x20}, 428 {0x4, 0x0, 1, 0x4}, 429 {0x4, 0x0, 2, 0x4}, 430 {0x4, 0x0, 3, 0x4}, 431 {0x4, 0x0, 4, 0x4}, 432 {0x4, 0x0, 5, 0x4}, 433 434 // Shift overflow. 435 {0x4, INT32_MAX, 1, 0x2}, 436 {0x4, INT32_MAX >> 1, 2, 0x0}, 437 {0x4, INT32_MAX >> 2, 3, 0xfffffffffffffffc}, 438 {0x4, INT32_MAX >> 3, 4, 0xfffffffffffffff4}, 439 {0x4, INT32_MAX >> 4, 5, 0xffffffffffffffe4}, 440 441 // Signed addition overflow. 442 {INT32_MAX - 1, 0x1, 1, 0xffffffff80000000}, 443 {INT32_MAX - 3, 0x1, 2, 0xffffffff80000000}, 444 {INT32_MAX - 7, 0x1, 3, 0xffffffff80000000}, 445 {INT32_MAX - 15, 0x1, 4, 0xffffffff80000000}, 446 {INT32_MAX - 31, 0x1, 5, 0xffffffff80000000}, 447 448 // Addition overflow. 449 {-2, 0x1, 1, 0x0}, 450 {-4, 0x1, 2, 0x0}, 451 {-8, 0x1, 3, 0x0}, 452 {-16, 0x1, 4, 0x0}, 453 {-32, 0x1, 5, 0x0}}; 454 455 size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseLsa); 456 for (size_t i = 0; i < nr_test_cases; ++i) { 457 uint64_t res = run_lsa(tc[i].rt, tc[i].rs, tc[i].sa); 458 PrintF("0x%" PRIx64 " =? 0x%" PRIx64 " == Lsa(v0, %x, %x, %hhu)\n", 459 tc[i].expected_res, res, tc[i].rt, tc[i].rs, tc[i].sa); 460 CHECK_EQ(tc[i].expected_res, res); 461 } 462} 463 464 465static uint64_t run_dlsa(uint64_t rt, uint64_t rs, int8_t sa) { 466 Isolate* isolate = CcTest::i_isolate(); 467 HandleScope scope(isolate); 468 MacroAssembler assembler(isolate, nullptr, 0, 469 v8::internal::CodeObjectRequired::kYes); 470 MacroAssembler* masm = &assembler; 471 472 __ Dlsa(v0, a0, a1, sa); 473 __ jr(ra); 474 __ nop(); 475 476 CodeDesc desc; 477 assembler.GetCode(&desc); 478 Handle<Code> code = isolate->factory()->NewCode( 479 desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); 480 481 ::F f = FUNCTION_CAST<::F>(code->entry()); 482 483 uint64_t res = reinterpret_cast<uint64_t>( 484 CALL_GENERATED_CODE(isolate, f, rt, rs, 0, 0, 0)); 485 486 return res; 487} 488 489 490TEST(Dlsa) { 491 CcTest::InitializeVM(); 492 struct TestCaseLsa { 493 int64_t rt; 494 int64_t rs; 495 uint8_t sa; 496 uint64_t expected_res; 497 }; 498 499 struct TestCaseLsa tc[] = {// rt, rs, sa, expected_res 500 {0x4, 0x1, 1, 0x6}, 501 {0x4, 0x1, 2, 0x8}, 502 {0x4, 0x1, 3, 0xc}, 503 {0x4, 0x1, 4, 0x14}, 504 {0x4, 0x1, 5, 0x24}, 505 {0x0, 0x1, 1, 0x2}, 506 {0x0, 0x1, 2, 0x4}, 507 {0x0, 0x1, 3, 0x8}, 508 {0x0, 0x1, 4, 0x10}, 509 {0x0, 0x1, 5, 0x20}, 510 {0x4, 0x0, 1, 0x4}, 511 {0x4, 0x0, 2, 0x4}, 512 {0x4, 0x0, 3, 0x4}, 513 {0x4, 0x0, 4, 0x4}, 514 {0x4, 0x0, 5, 0x4}, 515 516 // Shift overflow. 517 {0x4, INT64_MAX, 1, 0x2}, 518 {0x4, INT64_MAX >> 1, 2, 0x0}, 519 {0x4, INT64_MAX >> 2, 3, 0xfffffffffffffffc}, 520 {0x4, INT64_MAX >> 3, 4, 0xfffffffffffffff4}, 521 {0x4, INT64_MAX >> 4, 5, 0xffffffffffffffe4}, 522 523 // Signed addition overflow. 524 {INT64_MAX - 1, 0x1, 1, 0x8000000000000000}, 525 {INT64_MAX - 3, 0x1, 2, 0x8000000000000000}, 526 {INT64_MAX - 7, 0x1, 3, 0x8000000000000000}, 527 {INT64_MAX - 15, 0x1, 4, 0x8000000000000000}, 528 {INT64_MAX - 31, 0x1, 5, 0x8000000000000000}, 529 530 // Addition overflow. 531 {-2, 0x1, 1, 0x0}, 532 {-4, 0x1, 2, 0x0}, 533 {-8, 0x1, 3, 0x0}, 534 {-16, 0x1, 4, 0x0}, 535 {-32, 0x1, 5, 0x0}}; 536 537 size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseLsa); 538 for (size_t i = 0; i < nr_test_cases; ++i) { 539 uint64_t res = run_dlsa(tc[i].rt, tc[i].rs, tc[i].sa); 540 PrintF("0x%" PRIx64 " =? 0x%" PRIx64 " == Dlsa(v0, %" PRIx64 ", %" PRIx64 541 ", %hhu)\n", 542 tc[i].expected_res, res, tc[i].rt, tc[i].rs, tc[i].sa); 543 CHECK_EQ(tc[i].expected_res, res); 544 } 545} 546 547#undef __ 548