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
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.
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.
32 #include "src/disassembler.h"
33 #include "src/factory.h"
34 #include "src/macro-assembler.h"
35 #include "src/platform.h"
36 #include "src/serialize.h"
37 #include "test/cctest/cctest.h"
39 using namespace v8::internal;
43 typedef int (*F1)(int x);
44 typedef int (*F2)(int x, int y);
49 TEST(AssemblerIa320) {
50 CcTest::InitializeVM();
51 Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
52 HandleScope scope(isolate);
54 v8::internal::byte buffer[256];
55 Assembler assm(isolate, buffer, sizeof buffer);
57 __ mov(eax, Operand(esp, 4));
58 __ add(eax, Operand(esp, 8));
63 Handle<Code> code = isolate->factory()->NewCode(
64 desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
68 F2 f = FUNCTION_CAST<F2>(code->entry());
70 ::printf("f() = %d\n", res);
75 TEST(AssemblerIa321) {
76 CcTest::InitializeVM();
77 Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
78 HandleScope scope(isolate);
80 v8::internal::byte buffer[256];
81 Assembler assm(isolate, buffer, sizeof buffer);
84 __ mov(edx, Operand(esp, 4));
85 __ xor_(eax, eax); // clear eax
90 __ sub(edx, Immediate(1));
99 Handle<Code> code = isolate->factory()->NewCode(
100 desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
104 F1 f = FUNCTION_CAST<F1>(code->entry());
106 ::printf("f() = %d\n", res);
111 TEST(AssemblerIa322) {
112 CcTest::InitializeVM();
113 Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
114 HandleScope scope(isolate);
116 v8::internal::byte buffer[256];
117 Assembler assm(isolate, buffer, sizeof buffer);
120 __ mov(edx, Operand(esp, 4));
126 __ sub(edx, Immediate(1));
133 // some relocated stuff here, not executed
134 __ mov(eax, isolate->factory()->true_value());
135 __ jmp(NULL, RelocInfo::RUNTIME_ENTRY);
139 Handle<Code> code = isolate->factory()->NewCode(
140 desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
144 F1 f = FUNCTION_CAST<F1>(code->entry());
146 ::printf("f() = %d\n", res);
147 CHECK_EQ(3628800, res);
151 typedef int (*F3)(float x);
153 TEST(AssemblerIa323) {
154 CcTest::InitializeVM();
156 Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
157 HandleScope scope(isolate);
159 v8::internal::byte buffer[256];
160 Assembler assm(isolate, buffer, sizeof buffer);
162 __ cvttss2si(eax, Operand(esp, 4));
167 Handle<Code> code = isolate->factory()->NewCode(
168 desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
169 // don't print the code - our disassembler can't handle cvttss2si
170 // instead print bytes
171 Disassembler::Dump(stdout,
172 code->instruction_start(),
173 code->instruction_start() + code->instruction_size());
174 F3 f = FUNCTION_CAST<F3>(code->entry());
175 int res = f(static_cast<float>(-3.1415));
176 ::printf("f() = %d\n", res);
181 typedef int (*F4)(double x);
183 TEST(AssemblerIa324) {
184 CcTest::InitializeVM();
186 Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
187 HandleScope scope(isolate);
189 v8::internal::byte buffer[256];
190 Assembler assm(isolate, buffer, sizeof buffer);
192 __ cvttsd2si(eax, Operand(esp, 4));
197 Handle<Code> code = isolate->factory()->NewCode(
198 desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
199 // don't print the code - our disassembler can't handle cvttsd2si
200 // instead print bytes
201 Disassembler::Dump(stdout,
202 code->instruction_start(),
203 code->instruction_start() + code->instruction_size());
204 F4 f = FUNCTION_CAST<F4>(code->entry());
205 int res = f(2.718281828);
206 ::printf("f() = %d\n", res);
212 TEST(AssemblerIa325) {
213 CcTest::InitializeVM();
214 Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
215 HandleScope scope(isolate);
217 v8::internal::byte buffer[256];
218 Assembler assm(isolate, buffer, sizeof buffer);
220 __ mov(eax, Operand(reinterpret_cast<intptr_t>(&baz), RelocInfo::NONE32));
225 Handle<Code> code = isolate->factory()->NewCode(
226 desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
227 F0 f = FUNCTION_CAST<F0>(code->entry());
233 typedef double (*F5)(double x, double y);
235 TEST(AssemblerIa326) {
236 CcTest::InitializeVM();
238 Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
239 HandleScope scope(isolate);
240 v8::internal::byte buffer[256];
241 Assembler assm(isolate, buffer, sizeof buffer);
243 __ movsd(xmm0, Operand(esp, 1 * kPointerSize));
244 __ movsd(xmm1, Operand(esp, 3 * kPointerSize));
245 __ addsd(xmm0, xmm1);
246 __ mulsd(xmm0, xmm1);
247 __ subsd(xmm0, xmm1);
248 __ divsd(xmm0, xmm1);
249 // Copy xmm0 to st(0) using eight bytes of stack.
250 __ sub(esp, Immediate(8));
251 __ movsd(Operand(esp, 0), xmm0);
252 __ fld_d(Operand(esp, 0));
253 __ add(esp, Immediate(8));
258 Handle<Code> code = isolate->factory()->NewCode(
259 desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
262 // don't print the code - our disassembler can't handle SSE instructions
263 // instead print bytes
264 Disassembler::Dump(stdout,
265 code->instruction_start(),
266 code->instruction_start() + code->instruction_size());
268 F5 f = FUNCTION_CAST<F5>(code->entry());
269 double res = f(2.2, 1.1);
270 ::printf("f() = %f\n", res);
271 CHECK(2.29 < res && res < 2.31);
275 typedef double (*F6)(int x);
277 TEST(AssemblerIa328) {
278 CcTest::InitializeVM();
280 Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
281 HandleScope scope(isolate);
282 v8::internal::byte buffer[256];
283 Assembler assm(isolate, buffer, sizeof buffer);
284 __ mov(eax, Operand(esp, 4));
285 __ cvtsi2sd(xmm0, eax);
286 // Copy xmm0 to st(0) using eight bytes of stack.
287 __ sub(esp, Immediate(8));
288 __ movsd(Operand(esp, 0), xmm0);
289 __ fld_d(Operand(esp, 0));
290 __ add(esp, Immediate(8));
294 Handle<Code> code = isolate->factory()->NewCode(
295 desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
299 F6 f = FUNCTION_CAST<F6>(code->entry());
302 ::printf("f() = %f\n", res);
303 CHECK(11.99 < res && res < 12.001);
307 typedef int (*F7)(double x, double y);
309 TEST(AssemblerIa329) {
310 CcTest::InitializeVM();
311 Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
312 HandleScope scope(isolate);
313 v8::internal::byte buffer[256];
314 MacroAssembler assm(isolate, buffer, sizeof buffer);
315 enum { kEqual = 0, kGreater = 1, kLess = 2, kNaN = 3, kUndefined = 4 };
316 Label equal_l, less_l, greater_l, nan_l;
317 __ fld_d(Operand(esp, 3 * kPointerSize));
318 __ fld_d(Operand(esp, 1 * kPointerSize));
320 __ j(parity_even, &nan_l);
321 __ j(equal, &equal_l);
322 __ j(below, &less_l);
323 __ j(above, &greater_l);
325 __ mov(eax, kUndefined);
333 __ mov(eax, kGreater);
347 Handle<Code> code = isolate->factory()->NewCode(
348 desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
353 F7 f = FUNCTION_CAST<F7>(code->entry());
354 CHECK_EQ(kLess, f(1.1, 2.2));
355 CHECK_EQ(kEqual, f(2.2, 2.2));
356 CHECK_EQ(kGreater, f(3.3, 2.2));
357 CHECK_EQ(kNaN, f(OS::nan_value(), 1.1));
361 TEST(AssemblerIa3210) {
362 // Test chaining of label usages within instructions (issue 1644).
363 CcTest::InitializeVM();
364 Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
365 HandleScope scope(isolate);
366 Assembler assm(isolate, NULL, 0);
369 __ j(equal, &target);
370 __ j(not_equal, &target);
376 TEST(AssemblerMultiByteNop) {
377 CcTest::InitializeVM();
378 Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
379 HandleScope scope(isolate);
380 v8::internal::byte buffer[1024];
381 Assembler assm(isolate, buffer, sizeof(buffer));
393 for (int i = 0; i < 16; i++) {
394 int before = assm.pc_offset();
396 CHECK_EQ(assm.pc_offset() - before, i);
401 __ j(not_equal, &fail);
403 __ j(not_equal, &fail);
405 __ j(not_equal, &fail);
407 __ j(not_equal, &fail);
409 __ j(not_equal, &fail);
411 __ j(not_equal, &fail);
430 Handle<Code> code = isolate->factory()->NewCode(
431 desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
432 CHECK(code->IsCode());
434 F0 f = FUNCTION_CAST<F0>(code->entry());
441 #define ELEMENT_COUNT 4
443 void DoSSE2(const v8::FunctionCallbackInfo<v8::Value>& args) {
444 Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
445 HandleScope scope(isolate);
447 CHECK(args[0]->IsArray());
448 v8::Local<v8::Array> vec = v8::Local<v8::Array>::Cast(args[0]);
449 CHECK_EQ(ELEMENT_COUNT, vec->Length());
451 v8::internal::byte buffer[256];
452 Assembler assm(isolate, buffer, sizeof buffer);
454 // Remove return address from the stack for fix stack frame alignment.
457 // Store input vector on the stack.
458 for (int i = 0; i < ELEMENT_COUNT; ++i) {
459 __ push(Immediate(vec->Get(i)->Int32Value()));
462 // Read vector into a xmm register.
464 __ movdqa(xmm0, Operand(esp, 0));
465 // Create mask and store it in the return register.
466 __ movmskps(eax, xmm0);
468 // Remove unused data from the stack.
469 __ add(esp, Immediate(ELEMENT_COUNT * sizeof(int32_t)));
470 // Restore return address.
478 Handle<Code> code = isolate->factory()->NewCode(
479 desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
481 F0 f = FUNCTION_CAST<F0>(code->entry());
483 args.GetReturnValue().Set(v8::Integer::New(CcTest::isolate(), res));
487 TEST(StackAlignmentForSSE2) {
488 CcTest::InitializeVM();
489 CHECK_EQ(0, OS::ActivationFrameAlignment() % 16);
491 v8::Isolate* isolate = CcTest::isolate();
492 v8::HandleScope handle_scope(isolate);
493 v8::Handle<v8::ObjectTemplate> global_template =
494 v8::ObjectTemplate::New(isolate);
495 global_template->Set(v8_str("do_sse2"),
496 v8::FunctionTemplate::New(isolate, DoSSE2));
498 LocalContext env(NULL, global_template);
500 "function foo(vec) {"
501 " return do_sse2(vec);"
504 v8::Local<v8::Object> global_object = env->Global();
505 v8::Local<v8::Function> foo =
506 v8::Local<v8::Function>::Cast(global_object->Get(v8_str("foo")));
508 int32_t vec[ELEMENT_COUNT] = { -1, 1, 1, 1 };
509 v8::Local<v8::Array> v8_vec = v8::Array::New(isolate, ELEMENT_COUNT);
510 for (int i = 0; i < ELEMENT_COUNT; i++) {
511 v8_vec->Set(i, v8_num(vec[i]));
514 v8::Local<v8::Value> args[] = { v8_vec };
515 v8::Local<v8::Value> result = foo->Call(global_object, 1, args);
517 // The mask should be 0b1000.
518 CHECK_EQ(8, result->Int32Value());
525 TEST(AssemblerIa32Extractps) {
526 CcTest::InitializeVM();
527 if (!CpuFeatures::IsSupported(SSE4_1)) return;
529 Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
530 HandleScope scope(isolate);
531 v8::internal::byte buffer[256];
532 MacroAssembler assm(isolate, buffer, sizeof buffer);
533 { CpuFeatureScope fscope41(&assm, SSE4_1);
534 __ movsd(xmm1, Operand(esp, 4));
535 __ extractps(eax, xmm1, 0x1);
541 Handle<Code> code = isolate->factory()->NewCode(
542 desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
547 F4 f = FUNCTION_CAST<F4>(code->entry());
548 uint64_t value1 = V8_2PART_UINT64_C(0x12345678, 87654321);
549 CHECK_EQ(0x12345678, f(uint64_to_double(value1)));
550 uint64_t value2 = V8_2PART_UINT64_C(0x87654321, 12345678);
551 CHECK_EQ(0x87654321, f(uint64_to_double(value2)));
555 typedef int (*F8)(float x, float y);
556 TEST(AssemblerIa32SSE) {
557 CcTest::InitializeVM();
559 Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
560 HandleScope scope(isolate);
561 v8::internal::byte buffer[256];
562 MacroAssembler assm(isolate, buffer, sizeof buffer);
564 __ movss(xmm0, Operand(esp, kPointerSize));
565 __ movss(xmm1, Operand(esp, 2 * kPointerSize));
566 __ shufps(xmm0, xmm0, 0x0);
567 __ shufps(xmm1, xmm1, 0x0);
568 __ movaps(xmm2, xmm1);
569 __ addps(xmm2, xmm0);
570 __ mulps(xmm2, xmm1);
571 __ subps(xmm2, xmm0);
572 __ divps(xmm2, xmm1);
573 __ cvttss2si(eax, xmm2);
579 Handle<Code> code = isolate->factory()->NewCode(
580 desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
585 F8 f = FUNCTION_CAST<F8>(code->entry());
586 CHECK_EQ(2, f(1.0, 2.0));