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 "v8.h" 31 32 #include "disassembler.h" 33 #include "factory.h" 34 #include "macro-assembler.h" 35 #include "platform.h" 36 #include "serialize.h" 37 #include "cctest.h" 38 39 using namespace v8::internal; 40 41 42 typedef int (*F0)(); 43 typedef int (*F1)(int x); 44 typedef int (*F2)(int x, int y); 45 46 47 static v8::Persistent<v8::Context> env; 48 49 50 static void InitializeVM() { 51 if (env.IsEmpty()) { 52 env = v8::Context::New(); 53 } 54 } 55 56 57 #define __ assm. 58 59 TEST(AssemblerIa320) { 60 InitializeVM(); 61 v8::HandleScope scope; 62 63 v8::internal::byte buffer[256]; 64 Assembler assm(Isolate::Current(), buffer, sizeof buffer); 65 66 __ mov(eax, Operand(esp, 4)); 67 __ add(eax, Operand(esp, 8)); 68 __ ret(0); 69 70 CodeDesc desc; 71 assm.GetCode(&desc); 72 Object* code = HEAP->CreateCode( 73 desc, 74 Code::ComputeFlags(Code::STUB), 75 Handle<Object>(HEAP->undefined_value()))->ToObjectChecked(); 76 CHECK(code->IsCode()); 77 #ifdef OBJECT_PRINT 78 Code::cast(code)->Print(); 79 #endif 80 F2 f = FUNCTION_CAST<F2>(Code::cast(code)->entry()); 81 int res = f(3, 4); 82 ::printf("f() = %d\n", res); 83 CHECK_EQ(7, res); 84 } 85 86 87 TEST(AssemblerIa321) { 88 InitializeVM(); 89 v8::HandleScope scope; 90 91 v8::internal::byte buffer[256]; 92 Assembler assm(Isolate::Current(), buffer, sizeof buffer); 93 Label L, C; 94 95 __ mov(edx, Operand(esp, 4)); 96 __ xor_(eax, eax); // clear eax 97 __ jmp(&C); 98 99 __ bind(&L); 100 __ add(eax, edx); 101 __ sub(edx, Immediate(1)); 102 103 __ bind(&C); 104 __ test(edx, edx); 105 __ j(not_zero, &L); 106 __ ret(0); 107 108 CodeDesc desc; 109 assm.GetCode(&desc); 110 Object* code = HEAP->CreateCode( 111 desc, 112 Code::ComputeFlags(Code::STUB), 113 Handle<Object>(HEAP->undefined_value()))->ToObjectChecked(); 114 CHECK(code->IsCode()); 115 #ifdef OBJECT_PRINT 116 Code::cast(code)->Print(); 117 #endif 118 F1 f = FUNCTION_CAST<F1>(Code::cast(code)->entry()); 119 int res = f(100); 120 ::printf("f() = %d\n", res); 121 CHECK_EQ(5050, res); 122 } 123 124 125 TEST(AssemblerIa322) { 126 InitializeVM(); 127 v8::HandleScope scope; 128 129 v8::internal::byte buffer[256]; 130 Assembler assm(Isolate::Current(), buffer, sizeof buffer); 131 Label L, C; 132 133 __ mov(edx, Operand(esp, 4)); 134 __ mov(eax, 1); 135 __ jmp(&C); 136 137 __ bind(&L); 138 __ imul(eax, edx); 139 __ sub(edx, Immediate(1)); 140 141 __ bind(&C); 142 __ test(edx, edx); 143 __ j(not_zero, &L); 144 __ ret(0); 145 146 // some relocated stuff here, not executed 147 __ mov(eax, FACTORY->true_value()); 148 __ jmp(NULL, RelocInfo::RUNTIME_ENTRY); 149 150 CodeDesc desc; 151 assm.GetCode(&desc); 152 Object* code = HEAP->CreateCode( 153 desc, 154 Code::ComputeFlags(Code::STUB), 155 Handle<Object>(HEAP->undefined_value()))->ToObjectChecked(); 156 CHECK(code->IsCode()); 157 #ifdef OBJECT_PRINT 158 Code::cast(code)->Print(); 159 #endif 160 F1 f = FUNCTION_CAST<F1>(Code::cast(code)->entry()); 161 int res = f(10); 162 ::printf("f() = %d\n", res); 163 CHECK_EQ(3628800, res); 164 } 165 166 167 typedef int (*F3)(float x); 168 169 TEST(AssemblerIa323) { 170 InitializeVM(); 171 if (!CpuFeatures::IsSupported(SSE2)) return; 172 173 v8::HandleScope scope; 174 175 v8::internal::byte buffer[256]; 176 Assembler assm(Isolate::Current(), buffer, sizeof buffer); 177 178 CHECK(CpuFeatures::IsSupported(SSE2)); 179 { CpuFeatures::Scope fscope(SSE2); 180 __ cvttss2si(eax, Operand(esp, 4)); 181 __ ret(0); 182 } 183 184 CodeDesc desc; 185 assm.GetCode(&desc); 186 Code* code = Code::cast(HEAP->CreateCode( 187 desc, 188 Code::ComputeFlags(Code::STUB), 189 Handle<Object>(HEAP->undefined_value()))->ToObjectChecked()); 190 // don't print the code - our disassembler can't handle cvttss2si 191 // instead print bytes 192 Disassembler::Dump(stdout, 193 code->instruction_start(), 194 code->instruction_start() + code->instruction_size()); 195 F3 f = FUNCTION_CAST<F3>(code->entry()); 196 int res = f(static_cast<float>(-3.1415)); 197 ::printf("f() = %d\n", res); 198 CHECK_EQ(-3, res); 199 } 200 201 202 typedef int (*F4)(double x); 203 204 TEST(AssemblerIa324) { 205 InitializeVM(); 206 if (!CpuFeatures::IsSupported(SSE2)) return; 207 208 v8::HandleScope scope; 209 210 v8::internal::byte buffer[256]; 211 Assembler assm(Isolate::Current(), buffer, sizeof buffer); 212 213 CHECK(CpuFeatures::IsSupported(SSE2)); 214 CpuFeatures::Scope fscope(SSE2); 215 __ cvttsd2si(eax, Operand(esp, 4)); 216 __ ret(0); 217 218 CodeDesc desc; 219 assm.GetCode(&desc); 220 Code* code = Code::cast(HEAP->CreateCode( 221 desc, 222 Code::ComputeFlags(Code::STUB), 223 Handle<Object>(HEAP->undefined_value()))->ToObjectChecked()); 224 // don't print the code - our disassembler can't handle cvttsd2si 225 // instead print bytes 226 Disassembler::Dump(stdout, 227 code->instruction_start(), 228 code->instruction_start() + code->instruction_size()); 229 F4 f = FUNCTION_CAST<F4>(code->entry()); 230 int res = f(2.718281828); 231 ::printf("f() = %d\n", res); 232 CHECK_EQ(2, res); 233 } 234 235 236 static int baz = 42; 237 TEST(AssemblerIa325) { 238 InitializeVM(); 239 v8::HandleScope scope; 240 241 v8::internal::byte buffer[256]; 242 Assembler assm(Isolate::Current(), buffer, sizeof buffer); 243 244 __ mov(eax, Operand(reinterpret_cast<intptr_t>(&baz), RelocInfo::NONE)); 245 __ ret(0); 246 247 CodeDesc desc; 248 assm.GetCode(&desc); 249 Code* code = Code::cast(HEAP->CreateCode( 250 desc, 251 Code::ComputeFlags(Code::STUB), 252 Handle<Object>(HEAP->undefined_value()))->ToObjectChecked()); 253 F0 f = FUNCTION_CAST<F0>(code->entry()); 254 int res = f(); 255 CHECK_EQ(42, res); 256 } 257 258 259 typedef double (*F5)(double x, double y); 260 261 TEST(AssemblerIa326) { 262 InitializeVM(); 263 if (!CpuFeatures::IsSupported(SSE2)) return; 264 265 v8::HandleScope scope; 266 CHECK(CpuFeatures::IsSupported(SSE2)); 267 CpuFeatures::Scope fscope(SSE2); 268 v8::internal::byte buffer[256]; 269 Assembler assm(Isolate::Current(), buffer, sizeof buffer); 270 271 __ movdbl(xmm0, Operand(esp, 1 * kPointerSize)); 272 __ movdbl(xmm1, Operand(esp, 3 * kPointerSize)); 273 __ addsd(xmm0, xmm1); 274 __ mulsd(xmm0, xmm1); 275 __ subsd(xmm0, xmm1); 276 __ divsd(xmm0, xmm1); 277 // Copy xmm0 to st(0) using eight bytes of stack. 278 __ sub(esp, Immediate(8)); 279 __ movdbl(Operand(esp, 0), xmm0); 280 __ fld_d(Operand(esp, 0)); 281 __ add(esp, Immediate(8)); 282 __ ret(0); 283 284 CodeDesc desc; 285 assm.GetCode(&desc); 286 Code* code = Code::cast(HEAP->CreateCode( 287 desc, 288 Code::ComputeFlags(Code::STUB), 289 Handle<Object>(HEAP->undefined_value()))->ToObjectChecked()); 290 #ifdef DEBUG 291 ::printf("\n---\n"); 292 // don't print the code - our disassembler can't handle SSE instructions 293 // instead print bytes 294 Disassembler::Dump(stdout, 295 code->instruction_start(), 296 code->instruction_start() + code->instruction_size()); 297 #endif 298 F5 f = FUNCTION_CAST<F5>(code->entry()); 299 double res = f(2.2, 1.1); 300 ::printf("f() = %f\n", res); 301 CHECK(2.29 < res && res < 2.31); 302 } 303 304 305 typedef double (*F6)(int x); 306 307 TEST(AssemblerIa328) { 308 InitializeVM(); 309 if (!CpuFeatures::IsSupported(SSE2)) return; 310 311 v8::HandleScope scope; 312 CHECK(CpuFeatures::IsSupported(SSE2)); 313 CpuFeatures::Scope fscope(SSE2); 314 v8::internal::byte buffer[256]; 315 Assembler assm(Isolate::Current(), buffer, sizeof buffer); 316 __ mov(eax, Operand(esp, 4)); 317 __ cvtsi2sd(xmm0, eax); 318 // Copy xmm0 to st(0) using eight bytes of stack. 319 __ sub(esp, Immediate(8)); 320 __ movdbl(Operand(esp, 0), xmm0); 321 __ fld_d(Operand(esp, 0)); 322 __ add(esp, Immediate(8)); 323 __ ret(0); 324 CodeDesc desc; 325 assm.GetCode(&desc); 326 Code* code = Code::cast(HEAP->CreateCode( 327 desc, 328 Code::ComputeFlags(Code::STUB), 329 Handle<Object>(HEAP->undefined_value()))->ToObjectChecked()); 330 CHECK(code->IsCode()); 331 #ifdef OBJECT_PRINT 332 Code::cast(code)->Print(); 333 #endif 334 F6 f = FUNCTION_CAST<F6>(Code::cast(code)->entry()); 335 double res = f(12); 336 337 ::printf("f() = %f\n", res); 338 CHECK(11.99 < res && res < 12.001); 339 } 340 341 342 typedef int (*F7)(double x, double y); 343 344 TEST(AssemblerIa329) { 345 InitializeVM(); 346 v8::HandleScope scope; 347 v8::internal::byte buffer[256]; 348 MacroAssembler assm(Isolate::Current(), buffer, sizeof buffer); 349 enum { kEqual = 0, kGreater = 1, kLess = 2, kNaN = 3, kUndefined = 4 }; 350 Label equal_l, less_l, greater_l, nan_l; 351 __ fld_d(Operand(esp, 3 * kPointerSize)); 352 __ fld_d(Operand(esp, 1 * kPointerSize)); 353 __ FCmp(); 354 __ j(parity_even, &nan_l); 355 __ j(equal, &equal_l); 356 __ j(below, &less_l); 357 __ j(above, &greater_l); 358 359 __ mov(eax, kUndefined); 360 __ ret(0); 361 362 __ bind(&equal_l); 363 __ mov(eax, kEqual); 364 __ ret(0); 365 366 __ bind(&greater_l); 367 __ mov(eax, kGreater); 368 __ ret(0); 369 370 __ bind(&less_l); 371 __ mov(eax, kLess); 372 __ ret(0); 373 374 __ bind(&nan_l); 375 __ mov(eax, kNaN); 376 __ ret(0); 377 378 379 CodeDesc desc; 380 assm.GetCode(&desc); 381 Code* code = Code::cast(HEAP->CreateCode( 382 desc, 383 Code::ComputeFlags(Code::STUB), 384 Handle<Object>(HEAP->undefined_value()))->ToObjectChecked()); 385 CHECK(code->IsCode()); 386 #ifdef OBJECT_PRINT 387 Code::cast(code)->Print(); 388 #endif 389 390 F7 f = FUNCTION_CAST<F7>(Code::cast(code)->entry()); 391 CHECK_EQ(kLess, f(1.1, 2.2)); 392 CHECK_EQ(kEqual, f(2.2, 2.2)); 393 CHECK_EQ(kGreater, f(3.3, 2.2)); 394 CHECK_EQ(kNaN, f(OS::nan_value(), 1.1)); 395 } 396 397 398 TEST(AssemblerIa3210) { 399 // Test chaining of label usages within instructions (issue 1644). 400 InitializeVM(); 401 v8::HandleScope scope; 402 Assembler assm(Isolate::Current(), NULL, 0); 403 404 Label target; 405 __ j(equal, &target); 406 __ j(not_equal, &target); 407 __ bind(&target); 408 __ nop(); 409 } 410 411 412 TEST(AssemblerMultiByteNop) { 413 InitializeVM(); 414 v8::HandleScope scope; 415 v8::internal::byte buffer[1024]; 416 Assembler assm(Isolate::Current(), buffer, sizeof(buffer)); 417 __ push(ebx); 418 __ push(ecx); 419 __ push(edx); 420 __ push(edi); 421 __ push(esi); 422 __ mov(eax, 1); 423 __ mov(ebx, 2); 424 __ mov(ecx, 3); 425 __ mov(edx, 4); 426 __ mov(edi, 5); 427 __ mov(esi, 6); 428 for (int i = 0; i < 16; i++) { 429 int before = assm.pc_offset(); 430 __ Nop(i); 431 CHECK_EQ(assm.pc_offset() - before, i); 432 } 433 434 Label fail; 435 __ cmp(eax, 1); 436 __ j(not_equal, &fail); 437 __ cmp(ebx, 2); 438 __ j(not_equal, &fail); 439 __ cmp(ecx, 3); 440 __ j(not_equal, &fail); 441 __ cmp(edx, 4); 442 __ j(not_equal, &fail); 443 __ cmp(edi, 5); 444 __ j(not_equal, &fail); 445 __ cmp(esi, 6); 446 __ j(not_equal, &fail); 447 __ mov(eax, 42); 448 __ pop(esi); 449 __ pop(edi); 450 __ pop(edx); 451 __ pop(ecx); 452 __ pop(ebx); 453 __ ret(0); 454 __ bind(&fail); 455 __ mov(eax, 13); 456 __ pop(esi); 457 __ pop(edi); 458 __ pop(edx); 459 __ pop(ecx); 460 __ pop(ebx); 461 __ ret(0); 462 463 CodeDesc desc; 464 assm.GetCode(&desc); 465 Code* code = Code::cast(HEAP->CreateCode( 466 desc, 467 Code::ComputeFlags(Code::STUB), 468 Handle<Object>(HEAP->undefined_value()))->ToObjectChecked()); 469 CHECK(code->IsCode()); 470 471 F0 f = FUNCTION_CAST<F0>(code->entry()); 472 int res = f(); 473 CHECK_EQ(42, res); 474 } 475 476 477 478 479 #undef __ 480