1 // Copyright 2011 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 30 #include "src/v8.h" 31 32 #include "src/base/platform/platform.h" 33 #include "src/base/utils/random-number-generator.h" 34 #include "src/disassembler.h" 35 #include "src/factory.h" 36 #include "src/macro-assembler.h" 37 #include "src/ostreams.h" 38 #include "test/cctest/cctest.h" 39 40 using namespace v8::internal; 41 42 43 typedef int (*F0)(); 44 typedef int (*F1)(int x); 45 typedef int (*F2)(int x, int y); 46 47 48 #define __ assm. 49 50 TEST(AssemblerIa320) { 51 CcTest::InitializeVM(); 52 Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate()); 53 HandleScope scope(isolate); 54 55 v8::internal::byte buffer[256]; 56 Assembler assm(isolate, buffer, sizeof buffer); 57 58 __ mov(eax, Operand(esp, 4)); 59 __ add(eax, Operand(esp, 8)); 60 __ ret(0); 61 62 CodeDesc desc; 63 assm.GetCode(&desc); 64 Handle<Code> code = isolate->factory()->NewCode( 65 desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); 66 #ifdef OBJECT_PRINT 67 OFStream os(stdout); 68 code->Print(os); 69 #endif 70 F2 f = FUNCTION_CAST<F2>(code->entry()); 71 int res = f(3, 4); 72 ::printf("f() = %d\n", res); 73 CHECK_EQ(7, res); 74 } 75 76 77 TEST(AssemblerIa321) { 78 CcTest::InitializeVM(); 79 Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate()); 80 HandleScope scope(isolate); 81 82 v8::internal::byte buffer[256]; 83 Assembler assm(isolate, buffer, sizeof buffer); 84 Label L, C; 85 86 __ mov(edx, Operand(esp, 4)); 87 __ xor_(eax, eax); // clear eax 88 __ jmp(&C); 89 90 __ bind(&L); 91 __ add(eax, edx); 92 __ sub(edx, Immediate(1)); 93 94 __ bind(&C); 95 __ test(edx, edx); 96 __ j(not_zero, &L); 97 __ ret(0); 98 99 CodeDesc desc; 100 assm.GetCode(&desc); 101 Handle<Code> code = isolate->factory()->NewCode( 102 desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); 103 #ifdef OBJECT_PRINT 104 OFStream os(stdout); 105 code->Print(os); 106 #endif 107 F1 f = FUNCTION_CAST<F1>(code->entry()); 108 int res = f(100); 109 ::printf("f() = %d\n", res); 110 CHECK_EQ(5050, res); 111 } 112 113 114 TEST(AssemblerIa322) { 115 CcTest::InitializeVM(); 116 Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate()); 117 HandleScope scope(isolate); 118 119 v8::internal::byte buffer[256]; 120 Assembler assm(isolate, buffer, sizeof buffer); 121 Label L, C; 122 123 __ mov(edx, Operand(esp, 4)); 124 __ mov(eax, 1); 125 __ jmp(&C); 126 127 __ bind(&L); 128 __ imul(eax, edx); 129 __ sub(edx, Immediate(1)); 130 131 __ bind(&C); 132 __ test(edx, edx); 133 __ j(not_zero, &L); 134 __ ret(0); 135 136 // some relocated stuff here, not executed 137 __ mov(eax, isolate->factory()->true_value()); 138 __ jmp(NULL, RelocInfo::RUNTIME_ENTRY); 139 140 CodeDesc desc; 141 assm.GetCode(&desc); 142 Handle<Code> code = isolate->factory()->NewCode( 143 desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); 144 #ifdef OBJECT_PRINT 145 OFStream os(stdout); 146 code->Print(os); 147 #endif 148 F1 f = FUNCTION_CAST<F1>(code->entry()); 149 int res = f(10); 150 ::printf("f() = %d\n", res); 151 CHECK_EQ(3628800, res); 152 } 153 154 155 typedef int (*F3)(float x); 156 157 typedef int (*F4)(double x); 158 159 static int baz = 42; 160 TEST(AssemblerIa325) { 161 CcTest::InitializeVM(); 162 Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate()); 163 HandleScope scope(isolate); 164 165 v8::internal::byte buffer[256]; 166 Assembler assm(isolate, buffer, sizeof buffer); 167 168 __ mov(eax, Operand(reinterpret_cast<intptr_t>(&baz), RelocInfo::NONE32)); 169 __ ret(0); 170 171 CodeDesc desc; 172 assm.GetCode(&desc); 173 Handle<Code> code = isolate->factory()->NewCode( 174 desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); 175 F0 f = FUNCTION_CAST<F0>(code->entry()); 176 int res = f(); 177 CHECK_EQ(42, res); 178 } 179 180 181 typedef int (*F7)(double x, double y); 182 183 TEST(AssemblerIa329) { 184 CcTest::InitializeVM(); 185 Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate()); 186 HandleScope scope(isolate); 187 v8::internal::byte buffer[256]; 188 MacroAssembler assm(isolate, buffer, sizeof(buffer), 189 v8::internal::CodeObjectRequired::kYes); 190 enum { kEqual = 0, kGreater = 1, kLess = 2, kNaN = 3, kUndefined = 4 }; 191 Label equal_l, less_l, greater_l, nan_l; 192 __ fld_d(Operand(esp, 3 * kPointerSize)); 193 __ fld_d(Operand(esp, 1 * kPointerSize)); 194 __ FCmp(); 195 __ j(parity_even, &nan_l); 196 __ j(equal, &equal_l); 197 __ j(below, &less_l); 198 __ j(above, &greater_l); 199 200 __ mov(eax, kUndefined); 201 __ ret(0); 202 203 __ bind(&equal_l); 204 __ mov(eax, kEqual); 205 __ ret(0); 206 207 __ bind(&greater_l); 208 __ mov(eax, kGreater); 209 __ ret(0); 210 211 __ bind(&less_l); 212 __ mov(eax, kLess); 213 __ ret(0); 214 215 __ bind(&nan_l); 216 __ mov(eax, kNaN); 217 __ ret(0); 218 219 220 CodeDesc desc; 221 assm.GetCode(&desc); 222 Handle<Code> code = isolate->factory()->NewCode( 223 desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); 224 #ifdef OBJECT_PRINT 225 OFStream os(stdout); 226 code->Print(os); 227 #endif 228 229 F7 f = FUNCTION_CAST<F7>(code->entry()); 230 CHECK_EQ(kLess, f(1.1, 2.2)); 231 CHECK_EQ(kEqual, f(2.2, 2.2)); 232 CHECK_EQ(kGreater, f(3.3, 2.2)); 233 CHECK_EQ(kNaN, f(std::numeric_limits<double>::quiet_NaN(), 1.1)); 234 } 235 236 237 TEST(AssemblerIa3210) { 238 // Test chaining of label usages within instructions (issue 1644). 239 CcTest::InitializeVM(); 240 Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate()); 241 HandleScope scope(isolate); 242 Assembler assm(isolate, NULL, 0); 243 244 Label target; 245 __ j(equal, &target); 246 __ j(not_equal, &target); 247 __ bind(&target); 248 __ nop(); 249 } 250 251 252 TEST(AssemblerMultiByteNop) { 253 CcTest::InitializeVM(); 254 Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate()); 255 HandleScope scope(isolate); 256 v8::internal::byte buffer[1024]; 257 Assembler assm(isolate, buffer, sizeof(buffer)); 258 __ push(ebx); 259 __ push(ecx); 260 __ push(edx); 261 __ push(edi); 262 __ push(esi); 263 __ mov(eax, 1); 264 __ mov(ebx, 2); 265 __ mov(ecx, 3); 266 __ mov(edx, 4); 267 __ mov(edi, 5); 268 __ mov(esi, 6); 269 for (int i = 0; i < 16; i++) { 270 int before = assm.pc_offset(); 271 __ Nop(i); 272 CHECK_EQ(assm.pc_offset() - before, i); 273 } 274 275 Label fail; 276 __ cmp(eax, 1); 277 __ j(not_equal, &fail); 278 __ cmp(ebx, 2); 279 __ j(not_equal, &fail); 280 __ cmp(ecx, 3); 281 __ j(not_equal, &fail); 282 __ cmp(edx, 4); 283 __ j(not_equal, &fail); 284 __ cmp(edi, 5); 285 __ j(not_equal, &fail); 286 __ cmp(esi, 6); 287 __ j(not_equal, &fail); 288 __ mov(eax, 42); 289 __ pop(esi); 290 __ pop(edi); 291 __ pop(edx); 292 __ pop(ecx); 293 __ pop(ebx); 294 __ ret(0); 295 __ bind(&fail); 296 __ mov(eax, 13); 297 __ pop(esi); 298 __ pop(edi); 299 __ pop(edx); 300 __ pop(ecx); 301 __ pop(ebx); 302 __ ret(0); 303 304 CodeDesc desc; 305 assm.GetCode(&desc); 306 Handle<Code> code = isolate->factory()->NewCode( 307 desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); 308 CHECK(code->IsCode()); 309 310 F0 f = FUNCTION_CAST<F0>(code->entry()); 311 int res = f(); 312 CHECK_EQ(42, res); 313 } 314 315 316 TEST(AssemblerIa32JumpTables1) { 317 // Test jump tables with forward jumps. 318 CcTest::InitializeVM(); 319 Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate()); 320 HandleScope scope(isolate); 321 Assembler assm(isolate, nullptr, 0); 322 323 const int kNumCases = 512; 324 int values[kNumCases]; 325 isolate->random_number_generator()->NextBytes(values, sizeof(values)); 326 Label labels[kNumCases]; 327 328 Label done, table; 329 __ mov(eax, Operand(esp, 4)); 330 __ jmp(Operand::JumpTable(eax, times_4, &table)); 331 __ ud2(); 332 __ bind(&table); 333 for (int i = 0; i < kNumCases; ++i) { 334 __ dd(&labels[i]); 335 } 336 337 for (int i = 0; i < kNumCases; ++i) { 338 __ bind(&labels[i]); 339 __ mov(eax, Immediate(values[i])); 340 __ jmp(&done); 341 } 342 343 __ bind(&done); 344 __ ret(0); 345 346 CodeDesc desc; 347 assm.GetCode(&desc); 348 Handle<Code> code = isolate->factory()->NewCode( 349 desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); 350 #ifdef OBJECT_PRINT 351 OFStream os(stdout); 352 code->Print(os); 353 #endif 354 F1 f = FUNCTION_CAST<F1>(code->entry()); 355 for (int i = 0; i < kNumCases; ++i) { 356 int res = f(i); 357 ::printf("f(%d) = %d\n", i, res); 358 CHECK_EQ(values[i], res); 359 } 360 } 361 362 363 TEST(AssemblerIa32JumpTables2) { 364 // Test jump tables with backward jumps. 365 CcTest::InitializeVM(); 366 Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate()); 367 HandleScope scope(isolate); 368 Assembler assm(isolate, nullptr, 0); 369 370 const int kNumCases = 512; 371 int values[kNumCases]; 372 isolate->random_number_generator()->NextBytes(values, sizeof(values)); 373 Label labels[kNumCases]; 374 375 Label done, table; 376 __ mov(eax, Operand(esp, 4)); 377 __ jmp(Operand::JumpTable(eax, times_4, &table)); 378 __ ud2(); 379 380 for (int i = 0; i < kNumCases; ++i) { 381 __ bind(&labels[i]); 382 __ mov(eax, Immediate(values[i])); 383 __ jmp(&done); 384 } 385 386 __ bind(&table); 387 for (int i = 0; i < kNumCases; ++i) { 388 __ dd(&labels[i]); 389 } 390 391 __ bind(&done); 392 __ ret(0); 393 394 CodeDesc desc; 395 assm.GetCode(&desc); 396 Handle<Code> code = isolate->factory()->NewCode( 397 desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); 398 #ifdef OBJECT_PRINT 399 OFStream os(stdout); 400 code->Print(os); 401 #endif 402 F1 f = FUNCTION_CAST<F1>(code->entry()); 403 for (int i = 0; i < kNumCases; ++i) { 404 int res = f(i); 405 ::printf("f(%d) = %d\n", i, res); 406 CHECK_EQ(values[i], res); 407 } 408 } 409 410 #undef __ 411