v8  3.14.5(node0.10.28)
V8 is Google's open source JavaScript engine
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
test-assembler-ia32.cc
Go to the documentation of this file.
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 
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());
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 
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 
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;
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;
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 __
int(* F3)(float x)
#define __
#define CHECK_EQ(expected, value)
Definition: checks.h:219
const Register esp
static bool IsSupported(CpuFeature f)
#define CHECK(condition)
Definition: checks.h:56
int(* F1)(int x)
static Code * cast(Object *obj)
const Register edi
uint8_t byte
Definition: globals.h:156
const Register eax
int(* F2)(int x, int y)
const XMMRegister xmm1
byte * instruction_start()
Definition: objects-inl.h:4649
void GetCode(CodeDesc *desc)
const int kPointerSize
Definition: globals.h:220
const Register ecx
int(* F0)()
static Flags ComputeFlags(Kind kind, InlineCacheState ic_state=UNINITIALIZED, ExtraICState extra_ic_state=kNoExtraICState, StubType type=NORMAL, int argc=-1, InlineCacheHolderFlag holder=OWN_MAP)
Definition: objects-inl.h:3491
int(* F7)(double x, double y)
static double nan_value()
const Register ebx
double(* F5)(double x, double y)
int baz
#define HEAP
Definition: isolate.h:1433
const Register esi
bool IsEmpty() const
Definition: v8.h:209
#define FACTORY
Definition: isolate.h:1434
activate correct semantics for inheriting readonliness enable harmony semantics for typeof enable harmony enable harmony proxies enable all harmony harmony_scoping harmony_proxies harmony_scoping tracks arrays with only smi values automatically unbox arrays of doubles use crankshaft use hydrogen range analysis use hydrogen global value numbering use function inlining maximum number of AST nodes considered for a single inlining loop invariant code motion print statistics for hydrogen trace generated IR for specified phases trace register allocator trace range analysis trace representation types environment for every instruction put a break point before deoptimizing polymorphic inlining perform array bounds checks elimination use dead code elimination trace on stack replacement optimize closures cache optimized code for closures functions with arguments object loop weight for representation inference allow uint32 values on optimize frames if they are used only in safe operations track parallel recompilation enable all profiler experiments number of stack frames inspected by the profiler call recompile stub directly when self optimizing trigger profiler ticks based on counting instead of timing weight back edges by jump distance for interrupt triggering percentage of ICs that must have type info to allow optimization watch_ic_patching retry_self_opt interrupt_at_exit extra verbose compilation tracing generate extra emit comments in code disassembly enable use of SSE3 instructions if available enable use of CMOV instruction if available enable use of SAHF instruction if enable use of VFP3 instructions if available this implies enabling ARMv7 and VFP2 enable use of VFP2 instructions if available enable use of SDIV and UDIV instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of MIPS FPU instructions if NULL
Definition: flags.cc:301
static Persistent< Context > New(ExtensionConfiguration *extensions=NULL, Handle< ObjectTemplate > global_template=Handle< ObjectTemplate >(), Handle< Value > global_object=Handle< Value >())
Definition: api.cc:4411
#define RUNTIME_ENTRY(name, nargs, ressize)
activate correct semantics for inheriting readonliness enable harmony semantics for typeof enable harmony enable harmony proxies enable all harmony harmony_scoping harmony_proxies harmony_scoping tracks arrays with only smi values automatically unbox arrays of doubles use crankshaft use hydrogen range analysis use hydrogen global value numbering use function inlining maximum number of AST nodes considered for a single inlining loop invariant code motion print statistics for hydrogen trace generated IR for specified phases trace register allocator trace range analysis trace representation types environment for every instruction put a break point before deoptimizing polymorphic inlining perform array bounds checks elimination use dead code elimination trace on stack replacement optimize closures cache optimized code for closures functions with arguments object loop weight for representation inference allow uint32 values on optimize frames if they are used only in safe operations track parallel recompilation enable all profiler experiments number of stack frames inspected by the profiler call recompile stub directly when self optimizing trigger profiler ticks based on counting instead of timing weight back edges by jump distance for interrupt triggering percentage of ICs that must have type info to allow optimization watch_ic_patching retry_self_opt interrupt_at_exit extra verbose compilation tracing generate extra code(assertions) for debugging") DEFINE_bool(code_comments
const Register edx
static void Dump(FILE *f, byte *begin, byte *end)
double(* F6)(int x)
int(* F4)(double x)
const XMMRegister xmm0