The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / deps / v8 / test / cctest / test-macro-assembler-x64.cc @ f230a1cf

History | View | Annotate | Download (75.2 KB)

1
// Copyright 2009 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 "macro-assembler.h"
33
#include "factory.h"
34
#include "platform.h"
35
#include "serialize.h"
36
#include "cctest.h"
37

    
38
using v8::internal::Assembler;
39
using v8::internal::CodeDesc;
40
using v8::internal::Condition;
41
using v8::internal::FUNCTION_CAST;
42
using v8::internal::HandleScope;
43
using v8::internal::Immediate;
44
using v8::internal::Isolate;
45
using v8::internal::Label;
46
using v8::internal::MacroAssembler;
47
using v8::internal::OS;
48
using v8::internal::Operand;
49
using v8::internal::RelocInfo;
50
using v8::internal::Representation;
51
using v8::internal::Smi;
52
using v8::internal::SmiIndex;
53
using v8::internal::byte;
54
using v8::internal::carry;
55
using v8::internal::greater;
56
using v8::internal::greater_equal;
57
using v8::internal::kIntSize;
58
using v8::internal::kPointerSize;
59
using v8::internal::kSmiTagMask;
60
using v8::internal::kSmiValueSize;
61
using v8::internal::less_equal;
62
using v8::internal::negative;
63
using v8::internal::not_carry;
64
using v8::internal::not_equal;
65
using v8::internal::not_zero;
66
using v8::internal::positive;
67
using v8::internal::r11;
68
using v8::internal::r13;
69
using v8::internal::r14;
70
using v8::internal::r15;
71
using v8::internal::r8;
72
using v8::internal::r9;
73
using v8::internal::rax;
74
using v8::internal::rbp;
75
using v8::internal::rbx;
76
using v8::internal::rcx;
77
using v8::internal::rdi;
78
using v8::internal::rdx;
79
using v8::internal::rsi;
80
using v8::internal::rsp;
81
using v8::internal::times_pointer_size;
82

    
83
// Test the x64 assembler by compiling some simple functions into
84
// a buffer and executing them.  These tests do not initialize the
85
// V8 library, create a context, or use any V8 objects.
86
// The AMD64 calling convention is used, with the first five arguments
87
// in RSI, RDI, RDX, RCX, R8, and R9, and floating point arguments in
88
// the XMM registers.  The return value is in RAX.
89
// This calling convention is used on Linux, with GCC, and on Mac OS,
90
// with GCC.  A different convention is used on 64-bit windows.
91

    
92
typedef int (*F0)();
93

    
94
#define __ masm->
95

    
96

    
97
static void EntryCode(MacroAssembler* masm) {
98
  // Smi constant register is callee save.
99
  __ push(v8::internal::kSmiConstantRegister);
100
  __ push(v8::internal::kRootRegister);
101
  __ InitializeSmiConstantRegister();
102
  __ InitializeRootRegister();
103
}
104

    
105

    
106
static void ExitCode(MacroAssembler* masm) {
107
  // Return -1 if kSmiConstantRegister was clobbered during the test.
108
  __ Move(rdx, Smi::FromInt(1));
109
  __ cmpq(rdx, v8::internal::kSmiConstantRegister);
110
  __ movq(rdx, Immediate(-1));
111
  __ cmovq(not_equal, rax, rdx);
112
  __ pop(v8::internal::kRootRegister);
113
  __ pop(v8::internal::kSmiConstantRegister);
114
}
115

    
116

    
117
TEST(Smi) {
118
  // Check that C++ Smi operations work as expected.
119
  int64_t test_numbers[] = {
120
      0, 1, -1, 127, 128, -128, -129, 255, 256, -256, -257,
121
      Smi::kMaxValue, static_cast<int64_t>(Smi::kMaxValue) + 1,
122
      Smi::kMinValue, static_cast<int64_t>(Smi::kMinValue) - 1
123
  };
124
  int test_number_count = 15;
125
  for (int i = 0; i < test_number_count; i++) {
126
    int64_t number = test_numbers[i];
127
    bool is_valid = Smi::IsValid(number);
128
    bool is_in_range = number >= Smi::kMinValue && number <= Smi::kMaxValue;
129
    CHECK_EQ(is_in_range, is_valid);
130
    if (is_valid) {
131
      Smi* smi_from_intptr = Smi::FromIntptr(number);
132
      if (static_cast<int>(number) == number) {  // Is a 32-bit int.
133
        Smi* smi_from_int = Smi::FromInt(static_cast<int32_t>(number));
134
        CHECK_EQ(smi_from_int, smi_from_intptr);
135
      }
136
      int64_t smi_value = smi_from_intptr->value();
137
      CHECK_EQ(number, smi_value);
138
    }
139
  }
140
}
141

    
142

    
143
static void TestMoveSmi(MacroAssembler* masm, Label* exit, int id, Smi* value) {
144
  __ movl(rax, Immediate(id));
145
  __ Move(rcx, value);
146
  __ Set(rdx, reinterpret_cast<intptr_t>(value));
147
  __ cmpq(rcx, rdx);
148
  __ j(not_equal, exit);
149
}
150

    
151

    
152
// Test that we can move a Smi value literally into a register.
153
TEST(SmiMove) {
154
  v8::internal::V8::Initialize(NULL);
155
  // Allocate an executable page of memory.
156
  size_t actual_size;
157
  byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
158
                                                   &actual_size,
159
                                                   true));
160
  CHECK(buffer);
161
  Isolate* isolate = CcTest::i_isolate();
162
  HandleScope handles(isolate);
163
  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
164
  MacroAssembler* masm = &assembler;  // Create a pointer for the __ macro.
165
  masm->set_allow_stub_calls(false);
166
  EntryCode(masm);
167
  Label exit;
168

    
169
  TestMoveSmi(masm, &exit, 1, Smi::FromInt(0));
170
  TestMoveSmi(masm, &exit, 2, Smi::FromInt(127));
171
  TestMoveSmi(masm, &exit, 3, Smi::FromInt(128));
172
  TestMoveSmi(masm, &exit, 4, Smi::FromInt(255));
173
  TestMoveSmi(masm, &exit, 5, Smi::FromInt(256));
174
  TestMoveSmi(masm, &exit, 6, Smi::FromInt(Smi::kMaxValue));
175
  TestMoveSmi(masm, &exit, 7, Smi::FromInt(-1));
176
  TestMoveSmi(masm, &exit, 8, Smi::FromInt(-128));
177
  TestMoveSmi(masm, &exit, 9, Smi::FromInt(-129));
178
  TestMoveSmi(masm, &exit, 10, Smi::FromInt(-256));
179
  TestMoveSmi(masm, &exit, 11, Smi::FromInt(-257));
180
  TestMoveSmi(masm, &exit, 12, Smi::FromInt(Smi::kMinValue));
181

    
182
  __ xor_(rax, rax);  // Success.
183
  __ bind(&exit);
184
  ExitCode(masm);
185
  __ ret(0);
186

    
187
  CodeDesc desc;
188
  masm->GetCode(&desc);
189
  // Call the function from C++.
190
  int result = FUNCTION_CAST<F0>(buffer)();
191
  CHECK_EQ(0, result);
192
}
193

    
194

    
195
void TestSmiCompare(MacroAssembler* masm, Label* exit, int id, int x, int y) {
196
  __ Move(rcx, Smi::FromInt(x));
197
  __ movq(r8, rcx);
198
  __ Move(rdx, Smi::FromInt(y));
199
  __ movq(r9, rdx);
200
  __ SmiCompare(rcx, rdx);
201
  if (x < y) {
202
    __ movl(rax, Immediate(id + 1));
203
    __ j(greater_equal, exit);
204
  } else if (x > y) {
205
    __ movl(rax, Immediate(id + 2));
206
    __ j(less_equal, exit);
207
  } else {
208
    ASSERT_EQ(x, y);
209
    __ movl(rax, Immediate(id + 3));
210
    __ j(not_equal, exit);
211
  }
212
  __ movl(rax, Immediate(id + 4));
213
  __ cmpq(rcx, r8);
214
  __ j(not_equal, exit);
215
  __ incq(rax);
216
  __ cmpq(rdx, r9);
217
  __ j(not_equal, exit);
218

    
219
  if (x != y) {
220
    __ SmiCompare(rdx, rcx);
221
    if (y < x) {
222
      __ movl(rax, Immediate(id + 9));
223
      __ j(greater_equal, exit);
224
    } else {
225
      ASSERT(y > x);
226
      __ movl(rax, Immediate(id + 10));
227
      __ j(less_equal, exit);
228
    }
229
  } else {
230
    __ cmpq(rcx, rcx);
231
    __ movl(rax, Immediate(id + 11));
232
    __ j(not_equal, exit);
233
    __ incq(rax);
234
    __ cmpq(rcx, r8);
235
    __ j(not_equal, exit);
236
  }
237
}
238

    
239

    
240
// Test that we can compare smis for equality (and more).
241
TEST(SmiCompare) {
242
  v8::internal::V8::Initialize(NULL);
243
  // Allocate an executable page of memory.
244
  size_t actual_size;
245
  byte* buffer =
246
      static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 2,
247
                                      &actual_size,
248
                                      true));
249
  CHECK(buffer);
250
  Isolate* isolate = CcTest::i_isolate();
251
  HandleScope handles(isolate);
252
  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
253

    
254
  MacroAssembler* masm = &assembler;
255
  masm->set_allow_stub_calls(false);
256
  EntryCode(masm);
257
  Label exit;
258

    
259
  TestSmiCompare(masm, &exit, 0x10, 0, 0);
260
  TestSmiCompare(masm, &exit, 0x20, 0, 1);
261
  TestSmiCompare(masm, &exit, 0x30, 1, 0);
262
  TestSmiCompare(masm, &exit, 0x40, 1, 1);
263
  TestSmiCompare(masm, &exit, 0x50, 0, -1);
264
  TestSmiCompare(masm, &exit, 0x60, -1, 0);
265
  TestSmiCompare(masm, &exit, 0x70, -1, -1);
266
  TestSmiCompare(masm, &exit, 0x80, 0, Smi::kMinValue);
267
  TestSmiCompare(masm, &exit, 0x90, Smi::kMinValue, 0);
268
  TestSmiCompare(masm, &exit, 0xA0, 0, Smi::kMaxValue);
269
  TestSmiCompare(masm, &exit, 0xB0, Smi::kMaxValue, 0);
270
  TestSmiCompare(masm, &exit, 0xC0, -1, Smi::kMinValue);
271
  TestSmiCompare(masm, &exit, 0xD0, Smi::kMinValue, -1);
272
  TestSmiCompare(masm, &exit, 0xE0, -1, Smi::kMaxValue);
273
  TestSmiCompare(masm, &exit, 0xF0, Smi::kMaxValue, -1);
274
  TestSmiCompare(masm, &exit, 0x100, Smi::kMinValue, Smi::kMinValue);
275
  TestSmiCompare(masm, &exit, 0x110, Smi::kMinValue, Smi::kMaxValue);
276
  TestSmiCompare(masm, &exit, 0x120, Smi::kMaxValue, Smi::kMinValue);
277
  TestSmiCompare(masm, &exit, 0x130, Smi::kMaxValue, Smi::kMaxValue);
278

    
279
  __ xor_(rax, rax);  // Success.
280
  __ bind(&exit);
281
  ExitCode(masm);
282
  __ ret(0);
283

    
284
  CodeDesc desc;
285
  masm->GetCode(&desc);
286
  // Call the function from C++.
287
  int result = FUNCTION_CAST<F0>(buffer)();
288
  CHECK_EQ(0, result);
289
}
290

    
291

    
292

    
293
TEST(Integer32ToSmi) {
294
  v8::internal::V8::Initialize(NULL);
295
  // Allocate an executable page of memory.
296
  size_t actual_size;
297
  byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
298
                                                 &actual_size,
299
                                                 true));
300
  CHECK(buffer);
301
  Isolate* isolate = CcTest::i_isolate();
302
  HandleScope handles(isolate);
303
  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
304

    
305
  MacroAssembler* masm = &assembler;
306
  masm->set_allow_stub_calls(false);
307
  EntryCode(masm);
308
  Label exit;
309

    
310
  __ movq(rax, Immediate(1));  // Test number.
311
  __ movl(rcx, Immediate(0));
312
  __ Integer32ToSmi(rcx, rcx);
313
  __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(0)));
314
  __ cmpq(rcx, rdx);
315
  __ j(not_equal, &exit);
316

    
317
  __ movq(rax, Immediate(2));  // Test number.
318
  __ movl(rcx, Immediate(1024));
319
  __ Integer32ToSmi(rcx, rcx);
320
  __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(1024)));
321
  __ cmpq(rcx, rdx);
322
  __ j(not_equal, &exit);
323

    
324
  __ movq(rax, Immediate(3));  // Test number.
325
  __ movl(rcx, Immediate(-1));
326
  __ Integer32ToSmi(rcx, rcx);
327
  __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(-1)));
328
  __ cmpq(rcx, rdx);
329
  __ j(not_equal, &exit);
330

    
331
  __ movq(rax, Immediate(4));  // Test number.
332
  __ movl(rcx, Immediate(Smi::kMaxValue));
333
  __ Integer32ToSmi(rcx, rcx);
334
  __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(Smi::kMaxValue)));
335
  __ cmpq(rcx, rdx);
336
  __ j(not_equal, &exit);
337

    
338
  __ movq(rax, Immediate(5));  // Test number.
339
  __ movl(rcx, Immediate(Smi::kMinValue));
340
  __ Integer32ToSmi(rcx, rcx);
341
  __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(Smi::kMinValue)));
342
  __ cmpq(rcx, rdx);
343
  __ j(not_equal, &exit);
344

    
345
  // Different target register.
346

    
347
  __ movq(rax, Immediate(6));  // Test number.
348
  __ movl(rcx, Immediate(0));
349
  __ Integer32ToSmi(r8, rcx);
350
  __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(0)));
351
  __ cmpq(r8, rdx);
352
  __ j(not_equal, &exit);
353

    
354
  __ movq(rax, Immediate(7));  // Test number.
355
  __ movl(rcx, Immediate(1024));
356
  __ Integer32ToSmi(r8, rcx);
357
  __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(1024)));
358
  __ cmpq(r8, rdx);
359
  __ j(not_equal, &exit);
360

    
361
  __ movq(rax, Immediate(8));  // Test number.
362
  __ movl(rcx, Immediate(-1));
363
  __ Integer32ToSmi(r8, rcx);
364
  __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(-1)));
365
  __ cmpq(r8, rdx);
366
  __ j(not_equal, &exit);
367

    
368
  __ movq(rax, Immediate(9));  // Test number.
369
  __ movl(rcx, Immediate(Smi::kMaxValue));
370
  __ Integer32ToSmi(r8, rcx);
371
  __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(Smi::kMaxValue)));
372
  __ cmpq(r8, rdx);
373
  __ j(not_equal, &exit);
374

    
375
  __ movq(rax, Immediate(10));  // Test number.
376
  __ movl(rcx, Immediate(Smi::kMinValue));
377
  __ Integer32ToSmi(r8, rcx);
378
  __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(Smi::kMinValue)));
379
  __ cmpq(r8, rdx);
380
  __ j(not_equal, &exit);
381

    
382

    
383
  __ xor_(rax, rax);  // Success.
384
  __ bind(&exit);
385
  ExitCode(masm);
386
  __ ret(0);
387

    
388
  CodeDesc desc;
389
  masm->GetCode(&desc);
390
  // Call the function from C++.
391
  int result = FUNCTION_CAST<F0>(buffer)();
392
  CHECK_EQ(0, result);
393
}
394

    
395

    
396
void TestI64PlusConstantToSmi(MacroAssembler* masm,
397
                              Label* exit,
398
                              int id,
399
                              int64_t x,
400
                              int y) {
401
  int64_t result = x + y;
402
  ASSERT(Smi::IsValid(result));
403
  __ movl(rax, Immediate(id));
404
  __ Move(r8, Smi::FromInt(static_cast<int>(result)));
405
  __ movq(rcx, x, RelocInfo::NONE64);
406
  __ movq(r11, rcx);
407
  __ Integer64PlusConstantToSmi(rdx, rcx, y);
408
  __ cmpq(rdx, r8);
409
  __ j(not_equal, exit);
410

    
411
  __ incq(rax);
412
  __ cmpq(r11, rcx);
413
  __ j(not_equal, exit);
414

    
415
  __ incq(rax);
416
  __ Integer64PlusConstantToSmi(rcx, rcx, y);
417
  __ cmpq(rcx, r8);
418
  __ j(not_equal, exit);
419
}
420

    
421

    
422
TEST(Integer64PlusConstantToSmi) {
423
  v8::internal::V8::Initialize(NULL);
424
  // Allocate an executable page of memory.
425
  size_t actual_size;
426
  byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
427
                                                 &actual_size,
428
                                                 true));
429
  CHECK(buffer);
430
  Isolate* isolate = CcTest::i_isolate();
431
  HandleScope handles(isolate);
432
  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
433

    
434
  MacroAssembler* masm = &assembler;
435
  masm->set_allow_stub_calls(false);
436
  EntryCode(masm);
437
  Label exit;
438

    
439
  int64_t twice_max = static_cast<int64_t>(Smi::kMaxValue) * 2;
440

    
441
  TestI64PlusConstantToSmi(masm, &exit, 0x10, 0, 0);
442
  TestI64PlusConstantToSmi(masm, &exit, 0x20, 0, 1);
443
  TestI64PlusConstantToSmi(masm, &exit, 0x30, 1, 0);
444
  TestI64PlusConstantToSmi(masm, &exit, 0x40, Smi::kMaxValue - 5, 5);
445
  TestI64PlusConstantToSmi(masm, &exit, 0x50, Smi::kMinValue + 5, 5);
446
  TestI64PlusConstantToSmi(masm, &exit, 0x60, twice_max, -Smi::kMaxValue);
447
  TestI64PlusConstantToSmi(masm, &exit, 0x70, -twice_max, Smi::kMaxValue);
448
  TestI64PlusConstantToSmi(masm, &exit, 0x80, 0, Smi::kMinValue);
449
  TestI64PlusConstantToSmi(masm, &exit, 0x90, 0, Smi::kMaxValue);
450
  TestI64PlusConstantToSmi(masm, &exit, 0xA0, Smi::kMinValue, 0);
451
  TestI64PlusConstantToSmi(masm, &exit, 0xB0, Smi::kMaxValue, 0);
452
  TestI64PlusConstantToSmi(masm, &exit, 0xC0, twice_max, Smi::kMinValue);
453

    
454
  __ xor_(rax, rax);  // Success.
455
  __ bind(&exit);
456
  ExitCode(masm);
457
  __ ret(0);
458

    
459
  CodeDesc desc;
460
  masm->GetCode(&desc);
461
  // Call the function from C++.
462
  int result = FUNCTION_CAST<F0>(buffer)();
463
  CHECK_EQ(0, result);
464
}
465

    
466

    
467
TEST(SmiCheck) {
468
  v8::internal::V8::Initialize(NULL);
469
  // Allocate an executable page of memory.
470
  size_t actual_size;
471
  byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
472
                                                   &actual_size,
473
                                                   true));
474
  CHECK(buffer);
475
  Isolate* isolate = CcTest::i_isolate();
476
  HandleScope handles(isolate);
477
  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
478

    
479
  MacroAssembler* masm = &assembler;
480
  masm->set_allow_stub_calls(false);
481
  EntryCode(masm);
482
  Label exit;
483
  Condition cond;
484

    
485
  __ movl(rax, Immediate(1));  // Test number.
486

    
487
  // CheckSmi
488

    
489
  __ movl(rcx, Immediate(0));
490
  __ Integer32ToSmi(rcx, rcx);
491
  cond = masm->CheckSmi(rcx);
492
  __ j(NegateCondition(cond), &exit);
493

    
494
  __ incq(rax);
495
  __ xor_(rcx, Immediate(kSmiTagMask));
496
  cond = masm->CheckSmi(rcx);
497
  __ j(cond, &exit);
498

    
499
  __ incq(rax);
500
  __ movl(rcx, Immediate(-1));
501
  __ Integer32ToSmi(rcx, rcx);
502
  cond = masm->CheckSmi(rcx);
503
  __ j(NegateCondition(cond), &exit);
504

    
505
  __ incq(rax);
506
  __ xor_(rcx, Immediate(kSmiTagMask));
507
  cond = masm->CheckSmi(rcx);
508
  __ j(cond, &exit);
509

    
510
  __ incq(rax);
511
  __ movl(rcx, Immediate(Smi::kMaxValue));
512
  __ Integer32ToSmi(rcx, rcx);
513
  cond = masm->CheckSmi(rcx);
514
  __ j(NegateCondition(cond), &exit);
515

    
516
  __ incq(rax);
517
  __ xor_(rcx, Immediate(kSmiTagMask));
518
  cond = masm->CheckSmi(rcx);
519
  __ j(cond, &exit);
520

    
521
  __ incq(rax);
522
  __ movl(rcx, Immediate(Smi::kMinValue));
523
  __ Integer32ToSmi(rcx, rcx);
524
  cond = masm->CheckSmi(rcx);
525
  __ j(NegateCondition(cond), &exit);
526

    
527
  __ incq(rax);
528
  __ xor_(rcx, Immediate(kSmiTagMask));
529
  cond = masm->CheckSmi(rcx);
530
  __ j(cond, &exit);
531

    
532
  // CheckPositiveSmi
533

    
534
  __ incq(rax);
535
  __ movl(rcx, Immediate(0));
536
  __ Integer32ToSmi(rcx, rcx);
537
  cond = masm->CheckNonNegativeSmi(rcx);
538
  __ j(NegateCondition(cond), &exit);
539

    
540
  __ incq(rax);
541
  __ xor_(rcx, Immediate(kSmiTagMask));
542
  cond = masm->CheckNonNegativeSmi(rcx);  // "zero" non-smi.
543
  __ j(cond, &exit);
544

    
545
  __ incq(rax);
546
  __ movq(rcx, Immediate(-1));
547
  __ Integer32ToSmi(rcx, rcx);
548
  cond = masm->CheckNonNegativeSmi(rcx);  // Negative smis are not positive.
549
  __ j(cond, &exit);
550

    
551
  __ incq(rax);
552
  __ movq(rcx, Immediate(Smi::kMinValue));
553
  __ Integer32ToSmi(rcx, rcx);
554
  cond = masm->CheckNonNegativeSmi(rcx);  // Most negative smi is not positive.
555
  __ j(cond, &exit);
556

    
557
  __ incq(rax);
558
  __ xor_(rcx, Immediate(kSmiTagMask));
559
  cond = masm->CheckNonNegativeSmi(rcx);  // "Negative" non-smi.
560
  __ j(cond, &exit);
561

    
562
  __ incq(rax);
563
  __ movq(rcx, Immediate(Smi::kMaxValue));
564
  __ Integer32ToSmi(rcx, rcx);
565
  cond = masm->CheckNonNegativeSmi(rcx);  // Most positive smi is positive.
566
  __ j(NegateCondition(cond), &exit);
567

    
568
  __ incq(rax);
569
  __ xor_(rcx, Immediate(kSmiTagMask));
570
  cond = masm->CheckNonNegativeSmi(rcx);  // "Positive" non-smi.
571
  __ j(cond, &exit);
572

    
573
  // CheckIsMinSmi
574

    
575
  __ incq(rax);
576
  __ movq(rcx, Immediate(Smi::kMaxValue));
577
  __ Integer32ToSmi(rcx, rcx);
578
  cond = masm->CheckIsMinSmi(rcx);
579
  __ j(cond, &exit);
580

    
581
  __ incq(rax);
582
  __ movq(rcx, Immediate(0));
583
  __ Integer32ToSmi(rcx, rcx);
584
  cond = masm->CheckIsMinSmi(rcx);
585
  __ j(cond, &exit);
586

    
587
  __ incq(rax);
588
  __ movq(rcx, Immediate(Smi::kMinValue));
589
  __ Integer32ToSmi(rcx, rcx);
590
  cond = masm->CheckIsMinSmi(rcx);
591
  __ j(NegateCondition(cond), &exit);
592

    
593
  __ incq(rax);
594
  __ movq(rcx, Immediate(Smi::kMinValue + 1));
595
  __ Integer32ToSmi(rcx, rcx);
596
  cond = masm->CheckIsMinSmi(rcx);
597
  __ j(cond, &exit);
598

    
599
  // CheckBothSmi
600

    
601
  __ incq(rax);
602
  __ movq(rcx, Immediate(Smi::kMaxValue));
603
  __ Integer32ToSmi(rcx, rcx);
604
  __ movq(rdx, Immediate(Smi::kMinValue));
605
  __ Integer32ToSmi(rdx, rdx);
606
  cond = masm->CheckBothSmi(rcx, rdx);
607
  __ j(NegateCondition(cond), &exit);
608

    
609
  __ incq(rax);
610
  __ xor_(rcx, Immediate(kSmiTagMask));
611
  cond = masm->CheckBothSmi(rcx, rdx);
612
  __ j(cond, &exit);
613

    
614
  __ incq(rax);
615
  __ xor_(rdx, Immediate(kSmiTagMask));
616
  cond = masm->CheckBothSmi(rcx, rdx);
617
  __ j(cond, &exit);
618

    
619
  __ incq(rax);
620
  __ xor_(rcx, Immediate(kSmiTagMask));
621
  cond = masm->CheckBothSmi(rcx, rdx);
622
  __ j(cond, &exit);
623

    
624
  __ incq(rax);
625
  cond = masm->CheckBothSmi(rcx, rcx);
626
  __ j(NegateCondition(cond), &exit);
627

    
628
  __ incq(rax);
629
  cond = masm->CheckBothSmi(rdx, rdx);
630
  __ j(cond, &exit);
631

    
632
  // CheckInteger32ValidSmiValue
633
  __ incq(rax);
634
  __ movq(rcx, Immediate(0));
635
  cond = masm->CheckInteger32ValidSmiValue(rax);
636
  __ j(NegateCondition(cond), &exit);
637

    
638
  __ incq(rax);
639
  __ movq(rcx, Immediate(-1));
640
  cond = masm->CheckInteger32ValidSmiValue(rax);
641
  __ j(NegateCondition(cond), &exit);
642

    
643
  __ incq(rax);
644
  __ movq(rcx, Immediate(Smi::kMaxValue));
645
  cond = masm->CheckInteger32ValidSmiValue(rax);
646
  __ j(NegateCondition(cond), &exit);
647

    
648
  __ incq(rax);
649
  __ movq(rcx, Immediate(Smi::kMinValue));
650
  cond = masm->CheckInteger32ValidSmiValue(rax);
651
  __ j(NegateCondition(cond), &exit);
652

    
653
  // Success
654
  __ xor_(rax, rax);
655

    
656
  __ bind(&exit);
657
  ExitCode(masm);
658
  __ ret(0);
659

    
660
  CodeDesc desc;
661
  masm->GetCode(&desc);
662
  // Call the function from C++.
663
  int result = FUNCTION_CAST<F0>(buffer)();
664
  CHECK_EQ(0, result);
665
}
666

    
667

    
668

    
669
void TestSmiNeg(MacroAssembler* masm, Label* exit, int id, int x) {
670
  __ Move(rcx, Smi::FromInt(x));
671
  __ movq(r11, rcx);
672
  if (x == Smi::kMinValue || x == 0) {
673
    // Negation fails.
674
    __ movl(rax, Immediate(id + 8));
675
    __ SmiNeg(r9, rcx, exit);
676

    
677
    __ incq(rax);
678
    __ cmpq(r11, rcx);
679
    __ j(not_equal, exit);
680

    
681
    __ incq(rax);
682
    __ SmiNeg(rcx, rcx, exit);
683

    
684
    __ incq(rax);
685
    __ cmpq(r11, rcx);
686
    __ j(not_equal, exit);
687
  } else {
688
    Label smi_ok, smi_ok2;
689
    int result = -x;
690
    __ movl(rax, Immediate(id));
691
    __ Move(r8, Smi::FromInt(result));
692

    
693
    __ SmiNeg(r9, rcx, &smi_ok);
694
    __ jmp(exit);
695
    __ bind(&smi_ok);
696
    __ incq(rax);
697
    __ cmpq(r9, r8);
698
    __ j(not_equal, exit);
699

    
700
    __ incq(rax);
701
    __ cmpq(r11, rcx);
702
    __ j(not_equal, exit);
703

    
704
    __ incq(rax);
705
    __ SmiNeg(rcx, rcx, &smi_ok2);
706
    __ jmp(exit);
707
    __ bind(&smi_ok2);
708
    __ incq(rax);
709
    __ cmpq(rcx, r8);
710
    __ j(not_equal, exit);
711
  }
712
}
713

    
714

    
715
TEST(SmiNeg) {
716
  v8::internal::V8::Initialize(NULL);
717
  // Allocate an executable page of memory.
718
  size_t actual_size;
719
  byte* buffer =
720
      static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
721
                                      &actual_size,
722
                                      true));
723
  CHECK(buffer);
724
  Isolate* isolate = CcTest::i_isolate();
725
  HandleScope handles(isolate);
726
  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
727

    
728
  MacroAssembler* masm = &assembler;
729
  masm->set_allow_stub_calls(false);
730
  EntryCode(masm);
731
  Label exit;
732

    
733
  TestSmiNeg(masm, &exit, 0x10, 0);
734
  TestSmiNeg(masm, &exit, 0x20, 1);
735
  TestSmiNeg(masm, &exit, 0x30, -1);
736
  TestSmiNeg(masm, &exit, 0x40, 127);
737
  TestSmiNeg(masm, &exit, 0x50, 65535);
738
  TestSmiNeg(masm, &exit, 0x60, Smi::kMinValue);
739
  TestSmiNeg(masm, &exit, 0x70, Smi::kMaxValue);
740
  TestSmiNeg(masm, &exit, 0x80, -Smi::kMaxValue);
741

    
742
  __ xor_(rax, rax);  // Success.
743
  __ bind(&exit);
744
  ExitCode(masm);
745
  __ ret(0);
746

    
747
  CodeDesc desc;
748
  masm->GetCode(&desc);
749
  // Call the function from C++.
750
  int result = FUNCTION_CAST<F0>(buffer)();
751
  CHECK_EQ(0, result);
752
}
753

    
754

    
755
static void SmiAddTest(MacroAssembler* masm,
756
                       Label* exit,
757
                       int id,
758
                       int first,
759
                       int second) {
760
  __ movl(rcx, Immediate(first));
761
  __ Integer32ToSmi(rcx, rcx);
762
  __ movl(rdx, Immediate(second));
763
  __ Integer32ToSmi(rdx, rdx);
764
  __ movl(r8, Immediate(first + second));
765
  __ Integer32ToSmi(r8, r8);
766

    
767
  __ movl(rax, Immediate(id));  // Test number.
768
  __ SmiAdd(r9, rcx, rdx, exit);
769
  __ cmpq(r9, r8);
770
  __ j(not_equal, exit);
771

    
772
  __ incq(rax);
773
  __ SmiAdd(rcx, rcx, rdx, exit);                              \
774
  __ cmpq(rcx, r8);
775
  __ j(not_equal, exit);
776

    
777
  __ movl(rcx, Immediate(first));
778
  __ Integer32ToSmi(rcx, rcx);
779

    
780
  __ incq(rax);
781
  __ SmiAddConstant(r9, rcx, Smi::FromInt(second));
782
  __ cmpq(r9, r8);
783
  __ j(not_equal, exit);
784

    
785
  __ SmiAddConstant(rcx, rcx, Smi::FromInt(second));
786
  __ cmpq(rcx, r8);
787
  __ j(not_equal, exit);
788

    
789
  __ movl(rcx, Immediate(first));
790
  __ Integer32ToSmi(rcx, rcx);
791

    
792
  __ incq(rax);
793
  __ SmiAddConstant(r9, rcx, Smi::FromInt(second), exit);
794
  __ cmpq(r9, r8);
795
  __ j(not_equal, exit);
796

    
797
  __ incq(rax);
798
  __ SmiAddConstant(rcx, rcx, Smi::FromInt(second), exit);
799
  __ cmpq(rcx, r8);
800
  __ j(not_equal, exit);
801
}
802

    
803

    
804
static void SmiAddOverflowTest(MacroAssembler* masm,
805
                               Label* exit,
806
                               int id,
807
                               int x) {
808
  // Adds a Smi to x so that the addition overflows.
809
  ASSERT(x != 0);  // Can't overflow by adding a Smi.
810
  int y_max = (x > 0) ? (Smi::kMaxValue + 0) : (Smi::kMinValue - x - 1);
811
  int y_min = (x > 0) ? (Smi::kMaxValue - x + 1) : (Smi::kMinValue + 0);
812

    
813
  __ movl(rax, Immediate(id));
814
  __ Move(rcx, Smi::FromInt(x));
815
  __ movq(r11, rcx);  // Store original Smi value of x in r11.
816
  __ Move(rdx, Smi::FromInt(y_min));
817
  {
818
    Label overflow_ok;
819
    __ SmiAdd(r9, rcx, rdx, &overflow_ok);
820
    __ jmp(exit);
821
    __ bind(&overflow_ok);
822
    __ incq(rax);
823
    __ cmpq(rcx, r11);
824
    __ j(not_equal, exit);
825
  }
826

    
827
  {
828
    Label overflow_ok;
829
    __ incq(rax);
830
    __ SmiAdd(rcx, rcx, rdx, &overflow_ok);
831
    __ jmp(exit);
832
    __ bind(&overflow_ok);
833
    __ incq(rax);
834
    __ cmpq(rcx, r11);
835
    __ j(not_equal, exit);
836
  }
837

    
838
  __ movq(rcx, r11);
839
  {
840
    Label overflow_ok;
841
    __ incq(rax);
842
    __ SmiAddConstant(r9, rcx, Smi::FromInt(y_min), &overflow_ok);
843
    __ jmp(exit);
844
    __ bind(&overflow_ok);
845
    __ incq(rax);
846
    __ cmpq(rcx, r11);
847
    __ j(not_equal, exit);
848
  }
849

    
850
  {
851
    Label overflow_ok;
852
    __ incq(rax);
853
    __ SmiAddConstant(rcx, rcx, Smi::FromInt(y_min), &overflow_ok);
854
    __ jmp(exit);
855
    __ bind(&overflow_ok);
856
    __ incq(rax);
857
    __ cmpq(rcx, r11);
858
    __ j(not_equal, exit);
859
  }
860

    
861
  __ Move(rdx, Smi::FromInt(y_max));
862

    
863
  {
864
    Label overflow_ok;
865
    __ incq(rax);
866
    __ SmiAdd(r9, rcx, rdx, &overflow_ok);
867
    __ jmp(exit);
868
    __ bind(&overflow_ok);
869
    __ incq(rax);
870
    __ cmpq(rcx, r11);
871
    __ j(not_equal, exit);
872
  }
873

    
874
  {
875
    Label overflow_ok;
876
    __ incq(rax);
877
    __ SmiAdd(rcx, rcx, rdx, &overflow_ok);
878
    __ jmp(exit);
879
    __ bind(&overflow_ok);
880
    __ incq(rax);
881
    __ cmpq(rcx, r11);
882
    __ j(not_equal, exit);
883
  }
884

    
885
  __ movq(rcx, r11);
886
  {
887
    Label overflow_ok;
888
    __ incq(rax);
889
    __ SmiAddConstant(r9, rcx, Smi::FromInt(y_max), &overflow_ok);
890
    __ jmp(exit);
891
    __ bind(&overflow_ok);
892
    __ incq(rax);
893
    __ cmpq(rcx, r11);
894
    __ j(not_equal, exit);
895
  }
896

    
897
  {
898
    Label overflow_ok;
899
    __ incq(rax);
900
    __ SmiAddConstant(rcx, rcx, Smi::FromInt(y_max), &overflow_ok);
901
    __ jmp(exit);
902
    __ bind(&overflow_ok);
903
    __ incq(rax);
904
    __ cmpq(rcx, r11);
905
    __ j(not_equal, exit);
906
  }
907
}
908

    
909

    
910
TEST(SmiAdd) {
911
  v8::internal::V8::Initialize(NULL);
912
  // Allocate an executable page of memory.
913
  size_t actual_size;
914
  byte* buffer =
915
      static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 2,
916
                                      &actual_size,
917
                                      true));
918
  CHECK(buffer);
919
  Isolate* isolate = CcTest::i_isolate();
920
  HandleScope handles(isolate);
921
  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
922

    
923
  MacroAssembler* masm = &assembler;
924
  masm->set_allow_stub_calls(false);
925
  EntryCode(masm);
926
  Label exit;
927

    
928
  // No-overflow tests.
929
  SmiAddTest(masm, &exit, 0x10, 1, 2);
930
  SmiAddTest(masm, &exit, 0x20, 1, -2);
931
  SmiAddTest(masm, &exit, 0x30, -1, 2);
932
  SmiAddTest(masm, &exit, 0x40, -1, -2);
933
  SmiAddTest(masm, &exit, 0x50, 0x1000, 0x2000);
934
  SmiAddTest(masm, &exit, 0x60, Smi::kMinValue, 5);
935
  SmiAddTest(masm, &exit, 0x70, Smi::kMaxValue, -5);
936
  SmiAddTest(masm, &exit, 0x80, Smi::kMaxValue, Smi::kMinValue);
937

    
938
  SmiAddOverflowTest(masm, &exit, 0x90, -1);
939
  SmiAddOverflowTest(masm, &exit, 0xA0, 1);
940
  SmiAddOverflowTest(masm, &exit, 0xB0, 1024);
941
  SmiAddOverflowTest(masm, &exit, 0xC0, Smi::kMaxValue);
942
  SmiAddOverflowTest(masm, &exit, 0xD0, -2);
943
  SmiAddOverflowTest(masm, &exit, 0xE0, -42000);
944
  SmiAddOverflowTest(masm, &exit, 0xF0, Smi::kMinValue);
945

    
946
  __ xor_(rax, rax);  // Success.
947
  __ bind(&exit);
948
  ExitCode(masm);
949
  __ ret(0);
950

    
951
  CodeDesc desc;
952
  masm->GetCode(&desc);
953
  // Call the function from C++.
954
  int result = FUNCTION_CAST<F0>(buffer)();
955
  CHECK_EQ(0, result);
956
}
957

    
958

    
959
static void SmiSubTest(MacroAssembler* masm,
960
                      Label* exit,
961
                      int id,
962
                      int first,
963
                      int second) {
964
  __ Move(rcx, Smi::FromInt(first));
965
  __ Move(rdx, Smi::FromInt(second));
966
  __ Move(r8, Smi::FromInt(first - second));
967

    
968
  __ movl(rax, Immediate(id));  // Test 0.
969
  __ SmiSub(r9, rcx, rdx, exit);
970
  __ cmpq(r9, r8);
971
  __ j(not_equal, exit);
972

    
973
  __ incq(rax);  // Test 1.
974
  __ SmiSub(rcx, rcx, rdx, exit);
975
  __ cmpq(rcx, r8);
976
  __ j(not_equal, exit);
977

    
978
  __ Move(rcx, Smi::FromInt(first));
979

    
980
  __ incq(rax);  // Test 2.
981
  __ SmiSubConstant(r9, rcx, Smi::FromInt(second));
982
  __ cmpq(r9, r8);
983
  __ j(not_equal, exit);
984

    
985
  __ incq(rax);  // Test 3.
986
  __ SmiSubConstant(rcx, rcx, Smi::FromInt(second));
987
  __ cmpq(rcx, r8);
988
  __ j(not_equal, exit);
989

    
990
  __ Move(rcx, Smi::FromInt(first));
991

    
992
  __ incq(rax);  // Test 4.
993
  __ SmiSubConstant(r9, rcx, Smi::FromInt(second), exit);
994
  __ cmpq(r9, r8);
995
  __ j(not_equal, exit);
996

    
997
  __ incq(rax);  // Test 5.
998
  __ SmiSubConstant(rcx, rcx, Smi::FromInt(second), exit);
999
  __ cmpq(rcx, r8);
1000
  __ j(not_equal, exit);
1001
}
1002

    
1003

    
1004
static void SmiSubOverflowTest(MacroAssembler* masm,
1005
                               Label* exit,
1006
                               int id,
1007
                               int x) {
1008
  // Subtracts a Smi from x so that the subtraction overflows.
1009
  ASSERT(x != -1);  // Can't overflow by subtracting a Smi.
1010
  int y_max = (x < 0) ? (Smi::kMaxValue + 0) : (Smi::kMinValue + 0);
1011
  int y_min = (x < 0) ? (Smi::kMaxValue + x + 2) : (Smi::kMinValue + x);
1012

    
1013
  __ movl(rax, Immediate(id));
1014
  __ Move(rcx, Smi::FromInt(x));
1015
  __ movq(r11, rcx);  // Store original Smi value of x in r11.
1016
  __ Move(rdx, Smi::FromInt(y_min));
1017
  {
1018
    Label overflow_ok;
1019
    __ SmiSub(r9, rcx, rdx, &overflow_ok);
1020
    __ jmp(exit);
1021
    __ bind(&overflow_ok);
1022
    __ incq(rax);
1023
    __ cmpq(rcx, r11);
1024
    __ j(not_equal, exit);
1025
  }
1026

    
1027
  {
1028
    Label overflow_ok;
1029
    __ incq(rax);
1030
    __ SmiSub(rcx, rcx, rdx, &overflow_ok);
1031
    __ jmp(exit);
1032
    __ bind(&overflow_ok);
1033
    __ incq(rax);
1034
    __ cmpq(rcx, r11);
1035
    __ j(not_equal, exit);
1036
  }
1037

    
1038
  __ movq(rcx, r11);
1039
  {
1040
    Label overflow_ok;
1041
    __ incq(rax);
1042
    __ SmiSubConstant(r9, rcx, Smi::FromInt(y_min), &overflow_ok);
1043
    __ jmp(exit);
1044
    __ bind(&overflow_ok);
1045
    __ incq(rax);
1046
    __ cmpq(rcx, r11);
1047
    __ j(not_equal, exit);
1048
  }
1049

    
1050
  {
1051
    Label overflow_ok;
1052
    __ incq(rax);
1053
    __ SmiSubConstant(rcx, rcx, Smi::FromInt(y_min), &overflow_ok);
1054
    __ jmp(exit);
1055
    __ bind(&overflow_ok);
1056
    __ incq(rax);
1057
    __ cmpq(rcx, r11);
1058
    __ j(not_equal, exit);
1059
  }
1060

    
1061
  __ Move(rdx, Smi::FromInt(y_max));
1062

    
1063
  {
1064
    Label overflow_ok;
1065
    __ incq(rax);
1066
    __ SmiSub(r9, rcx, rdx, &overflow_ok);
1067
    __ jmp(exit);
1068
    __ bind(&overflow_ok);
1069
    __ incq(rax);
1070
    __ cmpq(rcx, r11);
1071
    __ j(not_equal, exit);
1072
  }
1073

    
1074
  {
1075
    Label overflow_ok;
1076
    __ incq(rax);
1077
    __ SmiSub(rcx, rcx, rdx, &overflow_ok);
1078
    __ jmp(exit);
1079
    __ bind(&overflow_ok);
1080
    __ incq(rax);
1081
    __ cmpq(rcx, r11);
1082
    __ j(not_equal, exit);
1083
  }
1084

    
1085
  __ movq(rcx, r11);
1086
  {
1087
    Label overflow_ok;
1088
    __ incq(rax);
1089
    __ SmiSubConstant(r9, rcx, Smi::FromInt(y_max), &overflow_ok);
1090
    __ jmp(exit);
1091
    __ bind(&overflow_ok);
1092
    __ incq(rax);
1093
    __ cmpq(rcx, r11);
1094
    __ j(not_equal, exit);
1095
  }
1096

    
1097
  {
1098
    Label overflow_ok;
1099
    __ incq(rax);
1100
    __ SmiSubConstant(rcx, rcx, Smi::FromInt(y_max), &overflow_ok);
1101
    __ jmp(exit);
1102
    __ bind(&overflow_ok);
1103
    __ incq(rax);
1104
    __ cmpq(rcx, r11);
1105
    __ j(not_equal, exit);
1106
  }
1107
}
1108

    
1109

    
1110
TEST(SmiSub) {
1111
  v8::internal::V8::Initialize(NULL);
1112
  // Allocate an executable page of memory.
1113
  size_t actual_size;
1114
  byte* buffer =
1115
      static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 2,
1116
                                      &actual_size,
1117
                                      true));
1118
  CHECK(buffer);
1119
  Isolate* isolate = CcTest::i_isolate();
1120
  HandleScope handles(isolate);
1121
  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
1122

    
1123
  MacroAssembler* masm = &assembler;
1124
  masm->set_allow_stub_calls(false);
1125
  EntryCode(masm);
1126
  Label exit;
1127

    
1128
  SmiSubTest(masm, &exit, 0x10, 1, 2);
1129
  SmiSubTest(masm, &exit, 0x20, 1, -2);
1130
  SmiSubTest(masm, &exit, 0x30, -1, 2);
1131
  SmiSubTest(masm, &exit, 0x40, -1, -2);
1132
  SmiSubTest(masm, &exit, 0x50, 0x1000, 0x2000);
1133
  SmiSubTest(masm, &exit, 0x60, Smi::kMinValue, -5);
1134
  SmiSubTest(masm, &exit, 0x70, Smi::kMaxValue, 5);
1135
  SmiSubTest(masm, &exit, 0x80, -Smi::kMaxValue, Smi::kMinValue);
1136
  SmiSubTest(masm, &exit, 0x90, 0, Smi::kMaxValue);
1137

    
1138
  SmiSubOverflowTest(masm, &exit, 0xA0, 1);
1139
  SmiSubOverflowTest(masm, &exit, 0xB0, 1024);
1140
  SmiSubOverflowTest(masm, &exit, 0xC0, Smi::kMaxValue);
1141
  SmiSubOverflowTest(masm, &exit, 0xD0, -2);
1142
  SmiSubOverflowTest(masm, &exit, 0xE0, -42000);
1143
  SmiSubOverflowTest(masm, &exit, 0xF0, Smi::kMinValue);
1144
  SmiSubOverflowTest(masm, &exit, 0x100, 0);
1145

    
1146
  __ xor_(rax, rax);  // Success.
1147
  __ bind(&exit);
1148
  ExitCode(masm);
1149
  __ ret(0);
1150

    
1151
  CodeDesc desc;
1152
  masm->GetCode(&desc);
1153
  // Call the function from C++.
1154
  int result = FUNCTION_CAST<F0>(buffer)();
1155
  CHECK_EQ(0, result);
1156
}
1157

    
1158

    
1159

    
1160
void TestSmiMul(MacroAssembler* masm, Label* exit, int id, int x, int y) {
1161
  int64_t result = static_cast<int64_t>(x) * static_cast<int64_t>(y);
1162
  bool negative_zero = (result == 0) && (x < 0 || y < 0);
1163
  __ Move(rcx, Smi::FromInt(x));
1164
  __ movq(r11, rcx);
1165
  __ Move(rdx, Smi::FromInt(y));
1166
  if (Smi::IsValid(result) && !negative_zero) {
1167
    __ movl(rax, Immediate(id));
1168
    __ Move(r8, Smi::FromIntptr(result));
1169
    __ SmiMul(r9, rcx, rdx, exit);
1170
    __ incq(rax);
1171
    __ cmpq(r11, rcx);
1172
    __ j(not_equal, exit);
1173
    __ incq(rax);
1174
    __ cmpq(r9, r8);
1175
    __ j(not_equal, exit);
1176

    
1177
    __ incq(rax);
1178
    __ SmiMul(rcx, rcx, rdx, exit);
1179
    __ cmpq(rcx, r8);
1180
    __ j(not_equal, exit);
1181
  } else {
1182
    __ movl(rax, Immediate(id + 8));
1183
    Label overflow_ok, overflow_ok2;
1184
    __ SmiMul(r9, rcx, rdx, &overflow_ok);
1185
    __ jmp(exit);
1186
    __ bind(&overflow_ok);
1187
    __ incq(rax);
1188
    __ cmpq(r11, rcx);
1189
    __ j(not_equal, exit);
1190
    __ incq(rax);
1191
    __ SmiMul(rcx, rcx, rdx, &overflow_ok2);
1192
    __ jmp(exit);
1193
    __ bind(&overflow_ok2);
1194
    // 31-bit version doesn't preserve rcx on failure.
1195
    // __ incq(rax);
1196
    // __ cmpq(r11, rcx);
1197
    // __ j(not_equal, exit);
1198
  }
1199
}
1200

    
1201

    
1202
TEST(SmiMul) {
1203
  v8::internal::V8::Initialize(NULL);
1204
  // Allocate an executable page of memory.
1205
  size_t actual_size;
1206
  byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
1207
                                                 &actual_size,
1208
                                                 true));
1209
  CHECK(buffer);
1210
  Isolate* isolate = CcTest::i_isolate();
1211
  HandleScope handles(isolate);
1212
  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
1213

    
1214
  MacroAssembler* masm = &assembler;
1215
  masm->set_allow_stub_calls(false);
1216
  EntryCode(masm);
1217
  Label exit;
1218

    
1219
  TestSmiMul(masm, &exit, 0x10, 0, 0);
1220
  TestSmiMul(masm, &exit, 0x20, -1, 0);
1221
  TestSmiMul(masm, &exit, 0x30, 0, -1);
1222
  TestSmiMul(masm, &exit, 0x40, -1, -1);
1223
  TestSmiMul(masm, &exit, 0x50, 0x10000, 0x10000);
1224
  TestSmiMul(masm, &exit, 0x60, 0x10000, 0xffff);
1225
  TestSmiMul(masm, &exit, 0x70, 0x10000, 0xffff);
1226
  TestSmiMul(masm, &exit, 0x80, Smi::kMaxValue, -1);
1227
  TestSmiMul(masm, &exit, 0x90, Smi::kMaxValue, -2);
1228
  TestSmiMul(masm, &exit, 0xa0, Smi::kMaxValue, 2);
1229
  TestSmiMul(masm, &exit, 0xb0, (Smi::kMaxValue / 2), 2);
1230
  TestSmiMul(masm, &exit, 0xc0, (Smi::kMaxValue / 2) + 1, 2);
1231
  TestSmiMul(masm, &exit, 0xd0, (Smi::kMinValue / 2), 2);
1232
  TestSmiMul(masm, &exit, 0xe0, (Smi::kMinValue / 2) - 1, 2);
1233

    
1234
  __ xor_(rax, rax);  // Success.
1235
  __ bind(&exit);
1236
  ExitCode(masm);
1237
  __ ret(0);
1238

    
1239
  CodeDesc desc;
1240
  masm->GetCode(&desc);
1241
  // Call the function from C++.
1242
  int result = FUNCTION_CAST<F0>(buffer)();
1243
  CHECK_EQ(0, result);
1244
}
1245

    
1246

    
1247
void TestSmiDiv(MacroAssembler* masm, Label* exit, int id, int x, int y) {
1248
  bool division_by_zero = (y == 0);
1249
  bool negative_zero = (x == 0 && y < 0);
1250
#if V8_TARGET_ARCH_X64
1251
  bool overflow = (x == Smi::kMinValue && y < 0);  // Safe approx. used.
1252
#else
1253
  bool overflow = (x == Smi::kMinValue && y == -1);
1254
#endif
1255
  bool fraction = !division_by_zero && !overflow && (x % y != 0);
1256
  __ Move(r11, Smi::FromInt(x));
1257
  __ Move(r14, Smi::FromInt(y));
1258
  if (!fraction && !overflow && !negative_zero && !division_by_zero) {
1259
    // Division succeeds
1260
    __ movq(rcx, r11);
1261
    __ movq(r15, Immediate(id));
1262
    int result = x / y;
1263
    __ Move(r8, Smi::FromInt(result));
1264
    __ SmiDiv(r9, rcx, r14, exit);
1265
    // Might have destroyed rcx and r14.
1266
    __ incq(r15);
1267
    __ cmpq(r9, r8);
1268
    __ j(not_equal, exit);
1269

    
1270
    __ incq(r15);
1271
    __ movq(rcx, r11);
1272
    __ Move(r14, Smi::FromInt(y));
1273
    __ cmpq(rcx, r11);
1274
    __ j(not_equal, exit);
1275

    
1276
    __ incq(r15);
1277
    __ SmiDiv(rcx, rcx, r14, exit);
1278

    
1279
    __ incq(r15);
1280
    __ cmpq(rcx, r8);
1281
    __ j(not_equal, exit);
1282
  } else {
1283
    // Division fails.
1284
    __ movq(r15, Immediate(id + 8));
1285

    
1286
    Label fail_ok, fail_ok2;
1287
    __ movq(rcx, r11);
1288
    __ SmiDiv(r9, rcx, r14, &fail_ok);
1289
    __ jmp(exit);
1290
    __ bind(&fail_ok);
1291

    
1292
    __ incq(r15);
1293
    __ cmpq(rcx, r11);
1294
    __ j(not_equal, exit);
1295

    
1296
    __ incq(r15);
1297
    __ SmiDiv(rcx, rcx, r14, &fail_ok2);
1298
    __ jmp(exit);
1299
    __ bind(&fail_ok2);
1300

    
1301
    __ incq(r15);
1302
    __ cmpq(rcx, r11);
1303
    __ j(not_equal, exit);
1304
  }
1305
}
1306

    
1307

    
1308
TEST(SmiDiv) {
1309
  v8::internal::V8::Initialize(NULL);
1310
  // Allocate an executable page of memory.
1311
  size_t actual_size;
1312
  byte* buffer =
1313
      static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 2,
1314
                                      &actual_size,
1315
                                      true));
1316
  CHECK(buffer);
1317
  Isolate* isolate = CcTest::i_isolate();
1318
  HandleScope handles(isolate);
1319
  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
1320

    
1321
  MacroAssembler* masm = &assembler;
1322
  masm->set_allow_stub_calls(false);
1323
  EntryCode(masm);
1324
  Label exit;
1325

    
1326
  __ push(r14);
1327
  __ push(r15);
1328
  TestSmiDiv(masm, &exit, 0x10, 1, 1);
1329
  TestSmiDiv(masm, &exit, 0x20, 1, 0);
1330
  TestSmiDiv(masm, &exit, 0x30, -1, 0);
1331
  TestSmiDiv(masm, &exit, 0x40, 0, 1);
1332
  TestSmiDiv(masm, &exit, 0x50, 0, -1);
1333
  TestSmiDiv(masm, &exit, 0x60, 4, 2);
1334
  TestSmiDiv(masm, &exit, 0x70, -4, 2);
1335
  TestSmiDiv(masm, &exit, 0x80, 4, -2);
1336
  TestSmiDiv(masm, &exit, 0x90, -4, -2);
1337
  TestSmiDiv(masm, &exit, 0xa0, 3, 2);
1338
  TestSmiDiv(masm, &exit, 0xb0, 3, 4);
1339
  TestSmiDiv(masm, &exit, 0xc0, 1, Smi::kMaxValue);
1340
  TestSmiDiv(masm, &exit, 0xd0, -1, Smi::kMaxValue);
1341
  TestSmiDiv(masm, &exit, 0xe0, Smi::kMaxValue, 1);
1342
  TestSmiDiv(masm, &exit, 0xf0, Smi::kMaxValue, Smi::kMaxValue);
1343
  TestSmiDiv(masm, &exit, 0x100, Smi::kMaxValue, -Smi::kMaxValue);
1344
  TestSmiDiv(masm, &exit, 0x110, Smi::kMaxValue, -1);
1345
  TestSmiDiv(masm, &exit, 0x120, Smi::kMinValue, 1);
1346
  TestSmiDiv(masm, &exit, 0x130, Smi::kMinValue, Smi::kMinValue);
1347
  TestSmiDiv(masm, &exit, 0x140, Smi::kMinValue, -1);
1348

    
1349
  __ xor_(r15, r15);  // Success.
1350
  __ bind(&exit);
1351
  __ movq(rax, r15);
1352
  __ pop(r15);
1353
  __ pop(r14);
1354
  ExitCode(masm);
1355
  __ ret(0);
1356

    
1357
  CodeDesc desc;
1358
  masm->GetCode(&desc);
1359
  // Call the function from C++.
1360
  int result = FUNCTION_CAST<F0>(buffer)();
1361
  CHECK_EQ(0, result);
1362
}
1363

    
1364

    
1365
void TestSmiMod(MacroAssembler* masm, Label* exit, int id, int x, int y) {
1366
  bool division_by_zero = (y == 0);
1367
  bool division_overflow = (x == Smi::kMinValue) && (y == -1);
1368
  bool fraction = !division_by_zero && !division_overflow && ((x % y) != 0);
1369
  bool negative_zero = (!fraction && x < 0);
1370
  __ Move(rcx, Smi::FromInt(x));
1371
  __ movq(r11, rcx);
1372
  __ Move(r14, Smi::FromInt(y));
1373
  if (!division_overflow && !negative_zero && !division_by_zero) {
1374
    // Modulo succeeds
1375
    __ movq(r15, Immediate(id));
1376
    int result = x % y;
1377
    __ Move(r8, Smi::FromInt(result));
1378
    __ SmiMod(r9, rcx, r14, exit);
1379

    
1380
    __ incq(r15);
1381
    __ cmpq(r9, r8);
1382
    __ j(not_equal, exit);
1383

    
1384
    __ incq(r15);
1385
    __ cmpq(rcx, r11);
1386
    __ j(not_equal, exit);
1387

    
1388
    __ incq(r15);
1389
    __ SmiMod(rcx, rcx, r14, exit);
1390

    
1391
    __ incq(r15);
1392
    __ cmpq(rcx, r8);
1393
    __ j(not_equal, exit);
1394
  } else {
1395
    // Modulo fails.
1396
    __ movq(r15, Immediate(id + 8));
1397

    
1398
    Label fail_ok, fail_ok2;
1399
    __ SmiMod(r9, rcx, r14, &fail_ok);
1400
    __ jmp(exit);
1401
    __ bind(&fail_ok);
1402

    
1403
    __ incq(r15);
1404
    __ cmpq(rcx, r11);
1405
    __ j(not_equal, exit);
1406

    
1407
    __ incq(r15);
1408
    __ SmiMod(rcx, rcx, r14, &fail_ok2);
1409
    __ jmp(exit);
1410
    __ bind(&fail_ok2);
1411

    
1412
    __ incq(r15);
1413
    __ cmpq(rcx, r11);
1414
    __ j(not_equal, exit);
1415
  }
1416
}
1417

    
1418

    
1419
TEST(SmiMod) {
1420
  v8::internal::V8::Initialize(NULL);
1421
  // Allocate an executable page of memory.
1422
  size_t actual_size;
1423
  byte* buffer =
1424
      static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 2,
1425
                                      &actual_size,
1426
                                      true));
1427
  CHECK(buffer);
1428
  Isolate* isolate = CcTest::i_isolate();
1429
  HandleScope handles(isolate);
1430
  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
1431

    
1432
  MacroAssembler* masm = &assembler;
1433
  masm->set_allow_stub_calls(false);
1434
  EntryCode(masm);
1435
  Label exit;
1436

    
1437
  __ push(r14);
1438
  __ push(r15);
1439
  TestSmiMod(masm, &exit, 0x10, 1, 1);
1440
  TestSmiMod(masm, &exit, 0x20, 1, 0);
1441
  TestSmiMod(masm, &exit, 0x30, -1, 0);
1442
  TestSmiMod(masm, &exit, 0x40, 0, 1);
1443
  TestSmiMod(masm, &exit, 0x50, 0, -1);
1444
  TestSmiMod(masm, &exit, 0x60, 4, 2);
1445
  TestSmiMod(masm, &exit, 0x70, -4, 2);
1446
  TestSmiMod(masm, &exit, 0x80, 4, -2);
1447
  TestSmiMod(masm, &exit, 0x90, -4, -2);
1448
  TestSmiMod(masm, &exit, 0xa0, 3, 2);
1449
  TestSmiMod(masm, &exit, 0xb0, 3, 4);
1450
  TestSmiMod(masm, &exit, 0xc0, 1, Smi::kMaxValue);
1451
  TestSmiMod(masm, &exit, 0xd0, -1, Smi::kMaxValue);
1452
  TestSmiMod(masm, &exit, 0xe0, Smi::kMaxValue, 1);
1453
  TestSmiMod(masm, &exit, 0xf0, Smi::kMaxValue, Smi::kMaxValue);
1454
  TestSmiMod(masm, &exit, 0x100, Smi::kMaxValue, -Smi::kMaxValue);
1455
  TestSmiMod(masm, &exit, 0x110, Smi::kMaxValue, -1);
1456
  TestSmiMod(masm, &exit, 0x120, Smi::kMinValue, 1);
1457
  TestSmiMod(masm, &exit, 0x130, Smi::kMinValue, Smi::kMinValue);
1458
  TestSmiMod(masm, &exit, 0x140, Smi::kMinValue, -1);
1459

    
1460
  __ xor_(r15, r15);  // Success.
1461
  __ bind(&exit);
1462
  __ movq(rax, r15);
1463
  __ pop(r15);
1464
  __ pop(r14);
1465
  ExitCode(masm);
1466
  __ ret(0);
1467

    
1468
  CodeDesc desc;
1469
  masm->GetCode(&desc);
1470
  // Call the function from C++.
1471
  int result = FUNCTION_CAST<F0>(buffer)();
1472
  CHECK_EQ(0, result);
1473
}
1474

    
1475

    
1476
void TestSmiIndex(MacroAssembler* masm, Label* exit, int id, int x) {
1477
  __ movl(rax, Immediate(id));
1478

    
1479
  for (int i = 0; i < 8; i++) {
1480
    __ Move(rcx, Smi::FromInt(x));
1481
    SmiIndex index = masm->SmiToIndex(rdx, rcx, i);
1482
    ASSERT(index.reg.is(rcx) || index.reg.is(rdx));
1483
    __ shl(index.reg, Immediate(index.scale));
1484
    __ Set(r8, static_cast<intptr_t>(x) << i);
1485
    __ cmpq(index.reg, r8);
1486
    __ j(not_equal, exit);
1487
    __ incq(rax);
1488
    __ Move(rcx, Smi::FromInt(x));
1489
    index = masm->SmiToIndex(rcx, rcx, i);
1490
    ASSERT(index.reg.is(rcx));
1491
    __ shl(rcx, Immediate(index.scale));
1492
    __ Set(r8, static_cast<intptr_t>(x) << i);
1493
    __ cmpq(rcx, r8);
1494
    __ j(not_equal, exit);
1495
    __ incq(rax);
1496

    
1497
    __ Move(rcx, Smi::FromInt(x));
1498
    index = masm->SmiToNegativeIndex(rdx, rcx, i);
1499
    ASSERT(index.reg.is(rcx) || index.reg.is(rdx));
1500
    __ shl(index.reg, Immediate(index.scale));
1501
    __ Set(r8, static_cast<intptr_t>(-x) << i);
1502
    __ cmpq(index.reg, r8);
1503
    __ j(not_equal, exit);
1504
    __ incq(rax);
1505
    __ Move(rcx, Smi::FromInt(x));
1506
    index = masm->SmiToNegativeIndex(rcx, rcx, i);
1507
    ASSERT(index.reg.is(rcx));
1508
    __ shl(rcx, Immediate(index.scale));
1509
    __ Set(r8, static_cast<intptr_t>(-x) << i);
1510
    __ cmpq(rcx, r8);
1511
    __ j(not_equal, exit);
1512
    __ incq(rax);
1513
  }
1514
}
1515

    
1516

    
1517
TEST(SmiIndex) {
1518
  v8::internal::V8::Initialize(NULL);
1519
  // Allocate an executable page of memory.
1520
  size_t actual_size;
1521
  byte* buffer =
1522
      static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 3,
1523
                                      &actual_size,
1524
                                      true));
1525
  CHECK(buffer);
1526
  Isolate* isolate = CcTest::i_isolate();
1527
  HandleScope handles(isolate);
1528
  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
1529

    
1530
  MacroAssembler* masm = &assembler;
1531
  masm->set_allow_stub_calls(false);
1532
  EntryCode(masm);
1533
  Label exit;
1534

    
1535
  TestSmiIndex(masm, &exit, 0x10, 0);
1536
  TestSmiIndex(masm, &exit, 0x20, 1);
1537
  TestSmiIndex(masm, &exit, 0x30, 100);
1538
  TestSmiIndex(masm, &exit, 0x40, 1000);
1539
  TestSmiIndex(masm, &exit, 0x50, Smi::kMaxValue);
1540

    
1541
  __ xor_(rax, rax);  // Success.
1542
  __ bind(&exit);
1543
  ExitCode(masm);
1544
  __ ret(0);
1545

    
1546
  CodeDesc desc;
1547
  masm->GetCode(&desc);
1548
  // Call the function from C++.
1549
  int result = FUNCTION_CAST<F0>(buffer)();
1550
  CHECK_EQ(0, result);
1551
}
1552

    
1553

    
1554
void TestSelectNonSmi(MacroAssembler* masm, Label* exit, int id, int x, int y) {
1555
  __ movl(rax, Immediate(id));
1556
  __ Move(rcx, Smi::FromInt(x));
1557
  __ Move(rdx, Smi::FromInt(y));
1558
  __ xor_(rdx, Immediate(kSmiTagMask));
1559
  __ SelectNonSmi(r9, rcx, rdx, exit);
1560

    
1561
  __ incq(rax);
1562
  __ cmpq(r9, rdx);
1563
  __ j(not_equal, exit);
1564

    
1565
  __ incq(rax);
1566
  __ Move(rcx, Smi::FromInt(x));
1567
  __ Move(rdx, Smi::FromInt(y));
1568
  __ xor_(rcx, Immediate(kSmiTagMask));
1569
  __ SelectNonSmi(r9, rcx, rdx, exit);
1570

    
1571
  __ incq(rax);
1572
  __ cmpq(r9, rcx);
1573
  __ j(not_equal, exit);
1574

    
1575
  __ incq(rax);
1576
  Label fail_ok;
1577
  __ Move(rcx, Smi::FromInt(x));
1578
  __ Move(rdx, Smi::FromInt(y));
1579
  __ xor_(rcx, Immediate(kSmiTagMask));
1580
  __ xor_(rdx, Immediate(kSmiTagMask));
1581
  __ SelectNonSmi(r9, rcx, rdx, &fail_ok);
1582
  __ jmp(exit);
1583
  __ bind(&fail_ok);
1584
}
1585

    
1586

    
1587
TEST(SmiSelectNonSmi) {
1588
  v8::internal::V8::Initialize(NULL);
1589
  // Allocate an executable page of memory.
1590
  size_t actual_size;
1591
  byte* buffer =
1592
      static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
1593
                                      &actual_size,
1594
                                      true));
1595
  CHECK(buffer);
1596
  Isolate* isolate = CcTest::i_isolate();
1597
  HandleScope handles(isolate);
1598
  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
1599

    
1600
  MacroAssembler* masm = &assembler;
1601
  masm->set_allow_stub_calls(false);  // Avoid inline checks.
1602
  EntryCode(masm);
1603
  Label exit;
1604

    
1605
  TestSelectNonSmi(masm, &exit, 0x10, 0, 0);
1606
  TestSelectNonSmi(masm, &exit, 0x20, 0, 1);
1607
  TestSelectNonSmi(masm, &exit, 0x30, 1, 0);
1608
  TestSelectNonSmi(masm, &exit, 0x40, 0, -1);
1609
  TestSelectNonSmi(masm, &exit, 0x50, -1, 0);
1610
  TestSelectNonSmi(masm, &exit, 0x60, -1, -1);
1611
  TestSelectNonSmi(masm, &exit, 0x70, 1, 1);
1612
  TestSelectNonSmi(masm, &exit, 0x80, Smi::kMinValue, Smi::kMaxValue);
1613
  TestSelectNonSmi(masm, &exit, 0x90, Smi::kMinValue, Smi::kMinValue);
1614

    
1615
  __ xor_(rax, rax);  // Success.
1616
  __ bind(&exit);
1617
  ExitCode(masm);
1618
  __ ret(0);
1619

    
1620
  CodeDesc desc;
1621
  masm->GetCode(&desc);
1622
  // Call the function from C++.
1623
  int result = FUNCTION_CAST<F0>(buffer)();
1624
  CHECK_EQ(0, result);
1625
}
1626

    
1627

    
1628
void TestSmiAnd(MacroAssembler* masm, Label* exit, int id, int x, int y) {
1629
  int result = x & y;
1630

    
1631
  __ movl(rax, Immediate(id));
1632

    
1633
  __ Move(rcx, Smi::FromInt(x));
1634
  __ movq(r11, rcx);
1635
  __ Move(rdx, Smi::FromInt(y));
1636
  __ Move(r8, Smi::FromInt(result));
1637
  __ SmiAnd(r9, rcx, rdx);
1638
  __ cmpq(r8, r9);
1639
  __ j(not_equal, exit);
1640

    
1641
  __ incq(rax);
1642
  __ cmpq(r11, rcx);
1643
  __ j(not_equal, exit);
1644

    
1645
  __ incq(rax);
1646
  __ SmiAnd(rcx, rcx, rdx);
1647
  __ cmpq(r8, rcx);
1648
  __ j(not_equal, exit);
1649

    
1650
  __ movq(rcx, r11);
1651
  __ incq(rax);
1652
  __ SmiAndConstant(r9, rcx, Smi::FromInt(y));
1653
  __ cmpq(r8, r9);
1654
  __ j(not_equal, exit);
1655

    
1656
  __ incq(rax);
1657
  __ cmpq(r11, rcx);
1658
  __ j(not_equal, exit);
1659

    
1660
  __ incq(rax);
1661
  __ SmiAndConstant(rcx, rcx, Smi::FromInt(y));
1662
  __ cmpq(r8, rcx);
1663
  __ j(not_equal, exit);
1664
}
1665

    
1666

    
1667
TEST(SmiAnd) {
1668
  v8::internal::V8::Initialize(NULL);
1669
  // Allocate an executable page of memory.
1670
  size_t actual_size;
1671
  byte* buffer =
1672
      static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
1673
                                      &actual_size,
1674
                                      true));
1675
  CHECK(buffer);
1676
  Isolate* isolate = CcTest::i_isolate();
1677
  HandleScope handles(isolate);
1678
  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
1679

    
1680
  MacroAssembler* masm = &assembler;
1681
  masm->set_allow_stub_calls(false);
1682
  EntryCode(masm);
1683
  Label exit;
1684

    
1685
  TestSmiAnd(masm, &exit, 0x10, 0, 0);
1686
  TestSmiAnd(masm, &exit, 0x20, 0, 1);
1687
  TestSmiAnd(masm, &exit, 0x30, 1, 0);
1688
  TestSmiAnd(masm, &exit, 0x40, 0, -1);
1689
  TestSmiAnd(masm, &exit, 0x50, -1, 0);
1690
  TestSmiAnd(masm, &exit, 0x60, -1, -1);
1691
  TestSmiAnd(masm, &exit, 0x70, 1, 1);
1692
  TestSmiAnd(masm, &exit, 0x80, Smi::kMinValue, Smi::kMaxValue);
1693
  TestSmiAnd(masm, &exit, 0x90, Smi::kMinValue, Smi::kMinValue);
1694
  TestSmiAnd(masm, &exit, 0xA0, Smi::kMinValue, -1);
1695
  TestSmiAnd(masm, &exit, 0xB0, Smi::kMinValue, -1);
1696

    
1697
  __ xor_(rax, rax);  // Success.
1698
  __ bind(&exit);
1699
  ExitCode(masm);
1700
  __ ret(0);
1701

    
1702
  CodeDesc desc;
1703
  masm->GetCode(&desc);
1704
  // Call the function from C++.
1705
  int result = FUNCTION_CAST<F0>(buffer)();
1706
  CHECK_EQ(0, result);
1707
}
1708

    
1709

    
1710
void TestSmiOr(MacroAssembler* masm, Label* exit, int id, int x, int y) {
1711
  int result = x | y;
1712

    
1713
  __ movl(rax, Immediate(id));
1714

    
1715
  __ Move(rcx, Smi::FromInt(x));
1716
  __ movq(r11, rcx);
1717
  __ Move(rdx, Smi::FromInt(y));
1718
  __ Move(r8, Smi::FromInt(result));
1719
  __ SmiOr(r9, rcx, rdx);
1720
  __ cmpq(r8, r9);
1721
  __ j(not_equal, exit);
1722

    
1723
  __ incq(rax);
1724
  __ cmpq(r11, rcx);
1725
  __ j(not_equal, exit);
1726

    
1727
  __ incq(rax);
1728
  __ SmiOr(rcx, rcx, rdx);
1729
  __ cmpq(r8, rcx);
1730
  __ j(not_equal, exit);
1731

    
1732
  __ movq(rcx, r11);
1733
  __ incq(rax);
1734
  __ SmiOrConstant(r9, rcx, Smi::FromInt(y));
1735
  __ cmpq(r8, r9);
1736
  __ j(not_equal, exit);
1737

    
1738
  __ incq(rax);
1739
  __ cmpq(r11, rcx);
1740
  __ j(not_equal, exit);
1741

    
1742
  __ incq(rax);
1743
  __ SmiOrConstant(rcx, rcx, Smi::FromInt(y));
1744
  __ cmpq(r8, rcx);
1745
  __ j(not_equal, exit);
1746
}
1747

    
1748

    
1749
TEST(SmiOr) {
1750
  v8::internal::V8::Initialize(NULL);
1751
  // Allocate an executable page of memory.
1752
  size_t actual_size;
1753
  byte* buffer =
1754
      static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
1755
                                      &actual_size,
1756
                                      true));
1757
  CHECK(buffer);
1758
  Isolate* isolate = CcTest::i_isolate();
1759
  HandleScope handles(isolate);
1760
  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
1761

    
1762
  MacroAssembler* masm = &assembler;
1763
  masm->set_allow_stub_calls(false);
1764
  EntryCode(masm);
1765
  Label exit;
1766

    
1767
  TestSmiOr(masm, &exit, 0x10, 0, 0);
1768
  TestSmiOr(masm, &exit, 0x20, 0, 1);
1769
  TestSmiOr(masm, &exit, 0x30, 1, 0);
1770
  TestSmiOr(masm, &exit, 0x40, 0, -1);
1771
  TestSmiOr(masm, &exit, 0x50, -1, 0);
1772
  TestSmiOr(masm, &exit, 0x60, -1, -1);
1773
  TestSmiOr(masm, &exit, 0x70, 1, 1);
1774
  TestSmiOr(masm, &exit, 0x80, Smi::kMinValue, Smi::kMaxValue);
1775
  TestSmiOr(masm, &exit, 0x90, Smi::kMinValue, Smi::kMinValue);
1776
  TestSmiOr(masm, &exit, 0xA0, Smi::kMinValue, -1);
1777
  TestSmiOr(masm, &exit, 0xB0, 0x05555555, 0x01234567);
1778
  TestSmiOr(masm, &exit, 0xC0, 0x05555555, 0x0fedcba9);
1779
  TestSmiOr(masm, &exit, 0xD0, Smi::kMinValue, -1);
1780

    
1781
  __ xor_(rax, rax);  // Success.
1782
  __ bind(&exit);
1783
  ExitCode(masm);
1784
  __ ret(0);
1785

    
1786
  CodeDesc desc;
1787
  masm->GetCode(&desc);
1788
  // Call the function from C++.
1789
  int result = FUNCTION_CAST<F0>(buffer)();
1790
  CHECK_EQ(0, result);
1791
}
1792

    
1793

    
1794
void TestSmiXor(MacroAssembler* masm, Label* exit, int id, int x, int y) {
1795
  int result = x ^ y;
1796

    
1797
  __ movl(rax, Immediate(id));
1798

    
1799
  __ Move(rcx, Smi::FromInt(x));
1800
  __ movq(r11, rcx);
1801
  __ Move(rdx, Smi::FromInt(y));
1802
  __ Move(r8, Smi::FromInt(result));
1803
  __ SmiXor(r9, rcx, rdx);
1804
  __ cmpq(r8, r9);
1805
  __ j(not_equal, exit);
1806

    
1807
  __ incq(rax);
1808
  __ cmpq(r11, rcx);
1809
  __ j(not_equal, exit);
1810

    
1811
  __ incq(rax);
1812
  __ SmiXor(rcx, rcx, rdx);
1813
  __ cmpq(r8, rcx);
1814
  __ j(not_equal, exit);
1815

    
1816
  __ movq(rcx, r11);
1817
  __ incq(rax);
1818
  __ SmiXorConstant(r9, rcx, Smi::FromInt(y));
1819
  __ cmpq(r8, r9);
1820
  __ j(not_equal, exit);
1821

    
1822
  __ incq(rax);
1823
  __ cmpq(r11, rcx);
1824
  __ j(not_equal, exit);
1825

    
1826
  __ incq(rax);
1827
  __ SmiXorConstant(rcx, rcx, Smi::FromInt(y));
1828
  __ cmpq(r8, rcx);
1829
  __ j(not_equal, exit);
1830
}
1831

    
1832

    
1833
TEST(SmiXor) {
1834
  v8::internal::V8::Initialize(NULL);
1835
  // Allocate an executable page of memory.
1836
  size_t actual_size;
1837
  byte* buffer =
1838
      static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
1839
                                      &actual_size,
1840
                                      true));
1841
  CHECK(buffer);
1842
  Isolate* isolate = CcTest::i_isolate();
1843
  HandleScope handles(isolate);
1844
  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
1845

    
1846
  MacroAssembler* masm = &assembler;
1847
  masm->set_allow_stub_calls(false);
1848
  EntryCode(masm);
1849
  Label exit;
1850

    
1851
  TestSmiXor(masm, &exit, 0x10, 0, 0);
1852
  TestSmiXor(masm, &exit, 0x20, 0, 1);
1853
  TestSmiXor(masm, &exit, 0x30, 1, 0);
1854
  TestSmiXor(masm, &exit, 0x40, 0, -1);
1855
  TestSmiXor(masm, &exit, 0x50, -1, 0);
1856
  TestSmiXor(masm, &exit, 0x60, -1, -1);
1857
  TestSmiXor(masm, &exit, 0x70, 1, 1);
1858
  TestSmiXor(masm, &exit, 0x80, Smi::kMinValue, Smi::kMaxValue);
1859
  TestSmiXor(masm, &exit, 0x90, Smi::kMinValue, Smi::kMinValue);
1860
  TestSmiXor(masm, &exit, 0xA0, Smi::kMinValue, -1);
1861
  TestSmiXor(masm, &exit, 0xB0, 0x5555555, 0x01234567);
1862
  TestSmiXor(masm, &exit, 0xC0, 0x5555555, 0x0fedcba9);
1863
  TestSmiXor(masm, &exit, 0xD0, Smi::kMinValue, -1);
1864

    
1865
  __ xor_(rax, rax);  // Success.
1866
  __ bind(&exit);
1867
  ExitCode(masm);
1868
  __ ret(0);
1869

    
1870
  CodeDesc desc;
1871
  masm->GetCode(&desc);
1872
  // Call the function from C++.
1873
  int result = FUNCTION_CAST<F0>(buffer)();
1874
  CHECK_EQ(0, result);
1875
}
1876

    
1877

    
1878
void TestSmiNot(MacroAssembler* masm, Label* exit, int id, int x) {
1879
  int result = ~x;
1880
  __ movl(rax, Immediate(id));
1881

    
1882
  __ Move(r8, Smi::FromInt(result));
1883
  __ Move(rcx, Smi::FromInt(x));
1884
  __ movq(r11, rcx);
1885

    
1886
  __ SmiNot(r9, rcx);
1887
  __ cmpq(r9, r8);
1888
  __ j(not_equal, exit);
1889

    
1890
  __ incq(rax);
1891
  __ cmpq(r11, rcx);
1892
  __ j(not_equal, exit);
1893

    
1894
  __ incq(rax);
1895
  __ SmiNot(rcx, rcx);
1896
  __ cmpq(rcx, r8);
1897
  __ j(not_equal, exit);
1898
}
1899

    
1900

    
1901
TEST(SmiNot) {
1902
  v8::internal::V8::Initialize(NULL);
1903
  // Allocate an executable page of memory.
1904
  size_t actual_size;
1905
  byte* buffer =
1906
      static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
1907
                                      &actual_size,
1908
                                      true));
1909
  CHECK(buffer);
1910
  Isolate* isolate = CcTest::i_isolate();
1911
  HandleScope handles(isolate);
1912
  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
1913

    
1914
  MacroAssembler* masm = &assembler;
1915
  masm->set_allow_stub_calls(false);
1916
  EntryCode(masm);
1917
  Label exit;
1918

    
1919
  TestSmiNot(masm, &exit, 0x10, 0);
1920
  TestSmiNot(masm, &exit, 0x20, 1);
1921
  TestSmiNot(masm, &exit, 0x30, -1);
1922
  TestSmiNot(masm, &exit, 0x40, 127);
1923
  TestSmiNot(masm, &exit, 0x50, 65535);
1924
  TestSmiNot(masm, &exit, 0x60, Smi::kMinValue);
1925
  TestSmiNot(masm, &exit, 0x70, Smi::kMaxValue);
1926
  TestSmiNot(masm, &exit, 0x80, 0x05555555);
1927

    
1928
  __ xor_(rax, rax);  // Success.
1929
  __ bind(&exit);
1930
  ExitCode(masm);
1931
  __ ret(0);
1932

    
1933
  CodeDesc desc;
1934
  masm->GetCode(&desc);
1935
  // Call the function from C++.
1936
  int result = FUNCTION_CAST<F0>(buffer)();
1937
  CHECK_EQ(0, result);
1938
}
1939

    
1940

    
1941
void TestSmiShiftLeft(MacroAssembler* masm, Label* exit, int id, int x) {
1942
  const int shifts[] = { 0, 1, 7, 24, kSmiValueSize - 1};
1943
  const int kNumShifts = 5;
1944
  __ movl(rax, Immediate(id));
1945
  for (int i = 0; i < kNumShifts; i++) {
1946
    // rax == id + i * 10.
1947
    int shift = shifts[i];
1948
    int result = x << shift;
1949
    CHECK(Smi::IsValid(result));
1950
    __ Move(r8, Smi::FromInt(result));
1951
    __ Move(rcx, Smi::FromInt(x));
1952
    __ SmiShiftLeftConstant(r9, rcx, shift);
1953

    
1954
    __ incq(rax);
1955
    __ cmpq(r9, r8);
1956
    __ j(not_equal, exit);
1957

    
1958
    __ incq(rax);
1959
    __ Move(rcx, Smi::FromInt(x));
1960
    __ SmiShiftLeftConstant(rcx, rcx, shift);
1961

    
1962
    __ incq(rax);
1963
    __ cmpq(rcx, r8);
1964
    __ j(not_equal, exit);
1965

    
1966
    __ incq(rax);
1967
    __ Move(rdx, Smi::FromInt(x));
1968
    __ Move(rcx, Smi::FromInt(shift));
1969
    __ SmiShiftLeft(r9, rdx, rcx);
1970

    
1971
    __ incq(rax);
1972
    __ cmpq(r9, r8);
1973
    __ j(not_equal, exit);
1974

    
1975
    __ incq(rax);
1976
    __ Move(rdx, Smi::FromInt(x));
1977
    __ Move(r11, Smi::FromInt(shift));
1978
    __ SmiShiftLeft(r9, rdx, r11);
1979

    
1980
    __ incq(rax);
1981
    __ cmpq(r9, r8);
1982
    __ j(not_equal, exit);
1983

    
1984
    __ incq(rax);
1985
    __ Move(rdx, Smi::FromInt(x));
1986
    __ Move(r11, Smi::FromInt(shift));
1987
    __ SmiShiftLeft(rdx, rdx, r11);
1988

    
1989
    __ incq(rax);
1990
    __ cmpq(rdx, r8);
1991
    __ j(not_equal, exit);
1992

    
1993
    __ incq(rax);
1994
  }
1995
}
1996

    
1997

    
1998
TEST(SmiShiftLeft) {
1999
  v8::internal::V8::Initialize(NULL);
2000
  // Allocate an executable page of memory.
2001
  size_t actual_size;
2002
  byte* buffer =
2003
      static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 4,
2004
                                      &actual_size,
2005
                                      true));
2006
  CHECK(buffer);
2007
  Isolate* isolate = CcTest::i_isolate();
2008
  HandleScope handles(isolate);
2009
  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
2010

    
2011
  MacroAssembler* masm = &assembler;
2012
  masm->set_allow_stub_calls(false);
2013
  EntryCode(masm);
2014
  Label exit;
2015

    
2016
  TestSmiShiftLeft(masm, &exit, 0x10, 0);
2017
  TestSmiShiftLeft(masm, &exit, 0x50, 1);
2018
  TestSmiShiftLeft(masm, &exit, 0x90, 127);
2019
  TestSmiShiftLeft(masm, &exit, 0xD0, 65535);
2020
  TestSmiShiftLeft(masm, &exit, 0x110, Smi::kMaxValue);
2021
  TestSmiShiftLeft(masm, &exit, 0x150, Smi::kMinValue);
2022
  TestSmiShiftLeft(masm, &exit, 0x190, -1);
2023

    
2024
  __ xor_(rax, rax);  // Success.
2025
  __ bind(&exit);
2026
  ExitCode(masm);
2027
  __ ret(0);
2028

    
2029
  CodeDesc desc;
2030
  masm->GetCode(&desc);
2031
  // Call the function from C++.
2032
  int result = FUNCTION_CAST<F0>(buffer)();
2033
  CHECK_EQ(0, result);
2034
}
2035

    
2036

    
2037
void TestSmiShiftLogicalRight(MacroAssembler* masm,
2038
                              Label* exit,
2039
                              int id,
2040
                              int x) {
2041
  const int shifts[] = { 0, 1, 7, 24, kSmiValueSize - 1};
2042
  const int kNumShifts = 5;
2043
  __ movl(rax, Immediate(id));
2044
  for (int i = 0; i < kNumShifts; i++) {
2045
    int shift = shifts[i];
2046
    intptr_t result = static_cast<unsigned int>(x) >> shift;
2047
    if (Smi::IsValid(result)) {
2048
      __ Move(r8, Smi::FromInt(static_cast<int>(result)));
2049
      __ Move(rcx, Smi::FromInt(x));
2050
      __ SmiShiftLogicalRightConstant(r9, rcx, shift, exit);
2051

    
2052
      __ incq(rax);
2053
      __ cmpq(r9, r8);
2054
      __ j(not_equal, exit);
2055

    
2056
      __ incq(rax);
2057
      __ Move(rdx, Smi::FromInt(x));
2058
      __ Move(rcx, Smi::FromInt(shift));
2059
      __ SmiShiftLogicalRight(r9, rdx, rcx, exit);
2060

    
2061
      __ incq(rax);
2062
      __ cmpq(r9, r8);
2063
      __ j(not_equal, exit);
2064

    
2065
      __ incq(rax);
2066
      __ Move(rdx, Smi::FromInt(x));
2067
      __ Move(r11, Smi::FromInt(shift));
2068
      __ SmiShiftLogicalRight(r9, rdx, r11, exit);
2069

    
2070
      __ incq(rax);
2071
      __ cmpq(r9, r8);
2072
      __ j(not_equal, exit);
2073

    
2074
      __ incq(rax);
2075
    } else {
2076
      // Cannot happen with long smis.
2077
      Label fail_ok;
2078
      __ Move(rcx, Smi::FromInt(x));
2079
      __ movq(r11, rcx);
2080
      __ SmiShiftLogicalRightConstant(r9, rcx, shift, &fail_ok);
2081
      __ jmp(exit);
2082
      __ bind(&fail_ok);
2083

    
2084
      __ incq(rax);
2085
      __ cmpq(rcx, r11);
2086
      __ j(not_equal, exit);
2087

    
2088
      __ incq(rax);
2089
      __ Move(r8, Smi::FromInt(shift));
2090
      Label fail_ok3;
2091
      __ SmiShiftLogicalRight(r9, rcx, r8, &fail_ok3);
2092
      __ jmp(exit);
2093
      __ bind(&fail_ok3);
2094

    
2095
      __ incq(rax);
2096
      __ cmpq(rcx, r11);
2097
      __ j(not_equal, exit);
2098

    
2099
      __ addq(rax, Immediate(3));
2100
    }
2101
  }
2102
}
2103

    
2104

    
2105
TEST(SmiShiftLogicalRight) {
2106
  v8::internal::V8::Initialize(NULL);
2107
  // Allocate an executable page of memory.
2108
  size_t actual_size;
2109
  byte* buffer =
2110
      static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 3,
2111
                                      &actual_size,
2112
                                      true));
2113
  CHECK(buffer);
2114
  Isolate* isolate = CcTest::i_isolate();
2115
  HandleScope handles(isolate);
2116
  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
2117

    
2118
  MacroAssembler* masm = &assembler;
2119
  masm->set_allow_stub_calls(false);
2120
  EntryCode(masm);
2121
  Label exit;
2122

    
2123
  TestSmiShiftLogicalRight(masm, &exit, 0x10, 0);
2124
  TestSmiShiftLogicalRight(masm, &exit, 0x30, 1);
2125
  TestSmiShiftLogicalRight(masm, &exit, 0x50, 127);
2126
  TestSmiShiftLogicalRight(masm, &exit, 0x70, 65535);
2127
  TestSmiShiftLogicalRight(masm, &exit, 0x90, Smi::kMaxValue);
2128
  TestSmiShiftLogicalRight(masm, &exit, 0xB0, Smi::kMinValue);
2129
  TestSmiShiftLogicalRight(masm, &exit, 0xD0, -1);
2130

    
2131
  __ xor_(rax, rax);  // Success.
2132
  __ bind(&exit);
2133
  ExitCode(masm);
2134
  __ ret(0);
2135

    
2136
  CodeDesc desc;
2137
  masm->GetCode(&desc);
2138
  // Call the function from C++.
2139
  int result = FUNCTION_CAST<F0>(buffer)();
2140
  CHECK_EQ(0, result);
2141
}
2142

    
2143

    
2144
void TestSmiShiftArithmeticRight(MacroAssembler* masm,
2145
                                 Label* exit,
2146
                                 int id,
2147
                                 int x) {
2148
  const int shifts[] = { 0, 1, 7, 24, kSmiValueSize - 1};
2149
  const int kNumShifts = 5;
2150
  __ movl(rax, Immediate(id));
2151
  for (int i = 0; i < kNumShifts; i++) {
2152
    int shift = shifts[i];
2153
    // Guaranteed arithmetic shift.
2154
    int result = (x < 0) ? ~((~x) >> shift) : (x >> shift);
2155
    __ Move(r8, Smi::FromInt(result));
2156
    __ Move(rcx, Smi::FromInt(x));
2157
    __ SmiShiftArithmeticRightConstant(rcx, rcx, shift);
2158

    
2159
    __ cmpq(rcx, r8);
2160
    __ j(not_equal, exit);
2161

    
2162
    __ incq(rax);
2163
    __ Move(rdx, Smi::FromInt(x));
2164
    __ Move(r11, Smi::FromInt(shift));
2165
    __ SmiShiftArithmeticRight(rdx, rdx, r11);
2166

    
2167
    __ cmpq(rdx, r8);
2168
    __ j(not_equal, exit);
2169

    
2170
    __ incq(rax);
2171
  }
2172
}
2173

    
2174

    
2175
TEST(SmiShiftArithmeticRight) {
2176
  v8::internal::V8::Initialize(NULL);
2177
  // Allocate an executable page of memory.
2178
  size_t actual_size;
2179
  byte* buffer =
2180
      static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 2,
2181
                                      &actual_size,
2182
                                      true));
2183
  CHECK(buffer);
2184
  Isolate* isolate = CcTest::i_isolate();
2185
  HandleScope handles(isolate);
2186
  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
2187

    
2188
  MacroAssembler* masm = &assembler;
2189
  masm->set_allow_stub_calls(false);
2190
  EntryCode(masm);
2191
  Label exit;
2192

    
2193
  TestSmiShiftArithmeticRight(masm, &exit, 0x10, 0);
2194
  TestSmiShiftArithmeticRight(masm, &exit, 0x20, 1);
2195
  TestSmiShiftArithmeticRight(masm, &exit, 0x30, 127);
2196
  TestSmiShiftArithmeticRight(masm, &exit, 0x40, 65535);
2197
  TestSmiShiftArithmeticRight(masm, &exit, 0x50, Smi::kMaxValue);
2198
  TestSmiShiftArithmeticRight(masm, &exit, 0x60, Smi::kMinValue);
2199
  TestSmiShiftArithmeticRight(masm, &exit, 0x70, -1);
2200

    
2201
  __ xor_(rax, rax);  // Success.
2202
  __ bind(&exit);
2203
  ExitCode(masm);
2204
  __ ret(0);
2205

    
2206
  CodeDesc desc;
2207
  masm->GetCode(&desc);
2208
  // Call the function from C++.
2209
  int result = FUNCTION_CAST<F0>(buffer)();
2210
  CHECK_EQ(0, result);
2211
}
2212

    
2213

    
2214
void TestPositiveSmiPowerUp(MacroAssembler* masm, Label* exit, int id, int x) {
2215
  ASSERT(x >= 0);
2216
  int powers[] = { 0, 1, 2, 3, 8, 16, 24, 31 };
2217
  int power_count = 8;
2218
  __ movl(rax, Immediate(id));
2219
  for (int i = 0; i  < power_count; i++) {
2220
    int power = powers[i];
2221
    intptr_t result = static_cast<intptr_t>(x) << power;
2222
    __ Set(r8, result);
2223
    __ Move(rcx, Smi::FromInt(x));
2224
    __ movq(r11, rcx);
2225
    __ PositiveSmiTimesPowerOfTwoToInteger64(rdx, rcx, power);
2226
    __ cmpq(rdx, r8);
2227
    __ j(not_equal, exit);
2228
    __ incq(rax);
2229
    __ cmpq(r11, rcx);  // rcx unchanged.
2230
    __ j(not_equal, exit);
2231
    __ incq(rax);
2232
    __ PositiveSmiTimesPowerOfTwoToInteger64(rcx, rcx, power);
2233
    __ cmpq(rdx, r8);
2234
    __ j(not_equal, exit);
2235
    __ incq(rax);
2236
  }
2237
}
2238

    
2239

    
2240
TEST(PositiveSmiTimesPowerOfTwoToInteger64) {
2241
  v8::internal::V8::Initialize(NULL);
2242
  // Allocate an executable page of memory.
2243
  size_t actual_size;
2244
  byte* buffer =
2245
      static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 4,
2246
                                      &actual_size,
2247
                                      true));
2248
  CHECK(buffer);
2249
  Isolate* isolate = CcTest::i_isolate();
2250
  HandleScope handles(isolate);
2251
  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
2252

    
2253
  MacroAssembler* masm = &assembler;
2254
  masm->set_allow_stub_calls(false);
2255
  EntryCode(masm);
2256
  Label exit;
2257

    
2258
  TestPositiveSmiPowerUp(masm, &exit, 0x20, 0);
2259
  TestPositiveSmiPowerUp(masm, &exit, 0x40, 1);
2260
  TestPositiveSmiPowerUp(masm, &exit, 0x60, 127);
2261
  TestPositiveSmiPowerUp(masm, &exit, 0x80, 128);
2262
  TestPositiveSmiPowerUp(masm, &exit, 0xA0, 255);
2263
  TestPositiveSmiPowerUp(masm, &exit, 0xC0, 256);
2264
  TestPositiveSmiPowerUp(masm, &exit, 0x100, 65535);
2265
  TestPositiveSmiPowerUp(masm, &exit, 0x120, 65536);
2266
  TestPositiveSmiPowerUp(masm, &exit, 0x140, Smi::kMaxValue);
2267

    
2268
  __ xor_(rax, rax);  // Success.
2269
  __ bind(&exit);
2270
  ExitCode(masm);
2271
  __ ret(0);
2272

    
2273
  CodeDesc desc;
2274
  masm->GetCode(&desc);
2275
  // Call the function from C++.
2276
  int result = FUNCTION_CAST<F0>(buffer)();
2277
  CHECK_EQ(0, result);
2278
}
2279

    
2280

    
2281
TEST(OperandOffset) {
2282
  v8::internal::V8::Initialize(NULL);
2283
  int data[256];
2284
  for (int i = 0; i < 256; i++) { data[i] = i * 0x01010101; }
2285

    
2286
  // Allocate an executable page of memory.
2287
  size_t actual_size;
2288
  byte* buffer =
2289
      static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 2,
2290
                                      &actual_size,
2291
                                      true));
2292
  CHECK(buffer);
2293
  Isolate* isolate = CcTest::i_isolate();
2294
  HandleScope handles(isolate);
2295
  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
2296

    
2297
  MacroAssembler* masm = &assembler;
2298
  masm->set_allow_stub_calls(false);
2299
  Label exit;
2300

    
2301
  EntryCode(masm);
2302
  __ push(r13);
2303
  __ push(r14);
2304
  __ push(rbx);
2305
  __ push(rbp);
2306
  __ push(Immediate(0x100));  // <-- rbp
2307
  __ movq(rbp, rsp);
2308
  __ push(Immediate(0x101));
2309
  __ push(Immediate(0x102));
2310
  __ push(Immediate(0x103));
2311
  __ push(Immediate(0x104));
2312
  __ push(Immediate(0x105));  // <-- rbx
2313
  __ push(Immediate(0x106));
2314
  __ push(Immediate(0x107));
2315
  __ push(Immediate(0x108));
2316
  __ push(Immediate(0x109));  // <-- rsp
2317
  // rbp = rsp[9]
2318
  // r15 = rsp[3]
2319
  // rbx = rsp[5]
2320
  // r13 = rsp[7]
2321
  __ lea(r14, Operand(rsp, 3 * kPointerSize));
2322
  __ lea(r13, Operand(rbp, -3 * kPointerSize));
2323
  __ lea(rbx, Operand(rbp, -5 * kPointerSize));
2324
  __ movl(rcx, Immediate(2));
2325
  __ movq(r8, reinterpret_cast<uintptr_t>(&data[128]), RelocInfo::NONE64);
2326
  __ movl(rax, Immediate(1));
2327

    
2328
  Operand sp0 = Operand(rsp, 0);
2329

    
2330
  // Test 1.
2331
  __ movl(rdx, sp0);  // Sanity check.
2332
  __ cmpl(rdx, Immediate(0x109));
2333
  __ j(not_equal, &exit);
2334
  __ incq(rax);
2335

    
2336
  // Test 2.
2337
  // Zero to non-zero displacement.
2338
  __ movl(rdx, Operand(sp0, 2 * kPointerSize));
2339
  __ cmpl(rdx, Immediate(0x107));
2340
  __ j(not_equal, &exit);
2341
  __ incq(rax);
2342

    
2343
  Operand sp2 = Operand(rsp, 2 * kPointerSize);
2344

    
2345
  // Test 3.
2346
  __ movl(rdx, sp2);  // Sanity check.
2347
  __ cmpl(rdx, Immediate(0x107));
2348
  __ j(not_equal, &exit);
2349
  __ incq(rax);
2350

    
2351
  __ movl(rdx, Operand(sp2, 2 * kPointerSize));
2352
  __ cmpl(rdx, Immediate(0x105));
2353
  __ j(not_equal, &exit);
2354
  __ incq(rax);
2355

    
2356
  // Non-zero to zero displacement.
2357
  __ movl(rdx, Operand(sp2, -2 * kPointerSize));
2358
  __ cmpl(rdx, Immediate(0x109));
2359
  __ j(not_equal, &exit);
2360
  __ incq(rax);
2361

    
2362
  Operand sp2c2 = Operand(rsp, rcx, times_pointer_size, 2 * kPointerSize);
2363

    
2364
  // Test 6.
2365
  __ movl(rdx, sp2c2);  // Sanity check.
2366
  __ cmpl(rdx, Immediate(0x105));
2367
  __ j(not_equal, &exit);
2368
  __ incq(rax);
2369

    
2370
  __ movl(rdx, Operand(sp2c2, 2 * kPointerSize));
2371
  __ cmpl(rdx, Immediate(0x103));
2372
  __ j(not_equal, &exit);
2373
  __ incq(rax);
2374

    
2375
  // Non-zero to zero displacement.
2376
  __ movl(rdx, Operand(sp2c2, -2 * kPointerSize));
2377
  __ cmpl(rdx, Immediate(0x107));
2378
  __ j(not_equal, &exit);
2379
  __ incq(rax);
2380

    
2381

    
2382
  Operand bp0 = Operand(rbp, 0);
2383

    
2384
  // Test 9.
2385
  __ movl(rdx, bp0);  // Sanity check.
2386
  __ cmpl(rdx, Immediate(0x100));
2387
  __ j(not_equal, &exit);
2388
  __ incq(rax);
2389

    
2390
  // Zero to non-zero displacement.
2391
  __ movl(rdx, Operand(bp0, -2 * kPointerSize));
2392
  __ cmpl(rdx, Immediate(0x102));
2393
  __ j(not_equal, &exit);
2394
  __ incq(rax);
2395

    
2396
  Operand bp2 = Operand(rbp, -2 * kPointerSize);
2397

    
2398
  // Test 11.
2399
  __ movl(rdx, bp2);  // Sanity check.
2400
  __ cmpl(rdx, Immediate(0x102));
2401
  __ j(not_equal, &exit);
2402
  __ incq(rax);
2403

    
2404
  // Non-zero to zero displacement.
2405
  __ movl(rdx, Operand(bp2, 2 * kPointerSize));
2406
  __ cmpl(rdx, Immediate(0x100));
2407
  __ j(not_equal, &exit);
2408
  __ incq(rax);
2409

    
2410
  __ movl(rdx, Operand(bp2, -2 * kPointerSize));
2411
  __ cmpl(rdx, Immediate(0x104));
2412
  __ j(not_equal, &exit);
2413
  __ incq(rax);
2414

    
2415
  Operand bp2c4 = Operand(rbp, rcx, times_pointer_size, -4 * kPointerSize);
2416

    
2417
  // Test 14:
2418
  __ movl(rdx, bp2c4);  // Sanity check.
2419
  __ cmpl(rdx, Immediate(0x102));
2420
  __ j(not_equal, &exit);
2421
  __ incq(rax);
2422

    
2423
  __ movl(rdx, Operand(bp2c4, 2 * kPointerSize));
2424
  __ cmpl(rdx, Immediate(0x100));
2425
  __ j(not_equal, &exit);
2426
  __ incq(rax);
2427

    
2428
  __ movl(rdx, Operand(bp2c4, -2 * kPointerSize));
2429
  __ cmpl(rdx, Immediate(0x104));
2430
  __ j(not_equal, &exit);
2431
  __ incq(rax);
2432

    
2433
  Operand bx0 = Operand(rbx, 0);
2434

    
2435
  // Test 17.
2436
  __ movl(rdx, bx0);  // Sanity check.
2437
  __ cmpl(rdx, Immediate(0x105));
2438
  __ j(not_equal, &exit);
2439
  __ incq(rax);
2440

    
2441
  __ movl(rdx, Operand(bx0, 5 * kPointerSize));
2442
  __ cmpl(rdx, Immediate(0x100));
2443
  __ j(not_equal, &exit);
2444
  __ incq(rax);
2445

    
2446
  __ movl(rdx, Operand(bx0, -4 * kPointerSize));
2447
  __ cmpl(rdx, Immediate(0x109));
2448
  __ j(not_equal, &exit);
2449
  __ incq(rax);
2450

    
2451
  Operand bx2 = Operand(rbx, 2 * kPointerSize);
2452

    
2453
  // Test 20.
2454
  __ movl(rdx, bx2);  // Sanity check.
2455
  __ cmpl(rdx, Immediate(0x103));
2456
  __ j(not_equal, &exit);
2457
  __ incq(rax);
2458

    
2459
  __ movl(rdx, Operand(bx2, 2 * kPointerSize));
2460
  __ cmpl(rdx, Immediate(0x101));
2461
  __ j(not_equal, &exit);
2462
  __ incq(rax);
2463

    
2464
  // Non-zero to zero displacement.
2465
  __ movl(rdx, Operand(bx2, -2 * kPointerSize));
2466
  __ cmpl(rdx, Immediate(0x105));
2467
  __ j(not_equal, &exit);
2468
  __ incq(rax);
2469

    
2470
  Operand bx2c2 = Operand(rbx, rcx, times_pointer_size, -2 * kPointerSize);
2471

    
2472
  // Test 23.
2473
  __ movl(rdx, bx2c2);  // Sanity check.
2474
  __ cmpl(rdx, Immediate(0x105));
2475
  __ j(not_equal, &exit);
2476
  __ incq(rax);
2477

    
2478
  __ movl(rdx, Operand(bx2c2, 2 * kPointerSize));
2479
  __ cmpl(rdx, Immediate(0x103));
2480
  __ j(not_equal, &exit);
2481
  __ incq(rax);
2482

    
2483
  __ movl(rdx, Operand(bx2c2, -2 * kPointerSize));
2484
  __ cmpl(rdx, Immediate(0x107));
2485
  __ j(not_equal, &exit);
2486
  __ incq(rax);
2487

    
2488
  Operand r80 = Operand(r8, 0);
2489

    
2490
  // Test 26.
2491
  __ movl(rdx, r80);  // Sanity check.
2492
  __ cmpl(rdx, Immediate(0x80808080));
2493
  __ j(not_equal, &exit);
2494
  __ incq(rax);
2495

    
2496
  __ movl(rdx, Operand(r80, -8 * kIntSize));
2497
  __ cmpl(rdx, Immediate(0x78787878));
2498
  __ j(not_equal, &exit);
2499
  __ incq(rax);
2500

    
2501
  __ movl(rdx, Operand(r80, 8 * kIntSize));
2502
  __ cmpl(rdx, Immediate(0x88888888));
2503
  __ j(not_equal, &exit);
2504
  __ incq(rax);
2505

    
2506
  __ movl(rdx, Operand(r80, -64 * kIntSize));
2507
  __ cmpl(rdx, Immediate(0x40404040));
2508
  __ j(not_equal, &exit);
2509
  __ incq(rax);
2510

    
2511
  __ movl(rdx, Operand(r80, 64 * kIntSize));
2512
  __ cmpl(rdx, Immediate(0xC0C0C0C0));
2513
  __ j(not_equal, &exit);
2514
  __ incq(rax);
2515

    
2516
  Operand r88 = Operand(r8, 8 * kIntSize);
2517

    
2518
  // Test 31.
2519
  __ movl(rdx, r88);  // Sanity check.
2520
  __ cmpl(rdx, Immediate(0x88888888));
2521
  __ j(not_equal, &exit);
2522
  __ incq(rax);
2523

    
2524
  __ movl(rdx, Operand(r88, -8 * kIntSize));
2525
  __ cmpl(rdx, Immediate(0x80808080));
2526
  __ j(not_equal, &exit);
2527
  __ incq(rax);
2528

    
2529
  __ movl(rdx, Operand(r88, 8 * kIntSize));
2530
  __ cmpl(rdx, Immediate(0x90909090));
2531
  __ j(not_equal, &exit);
2532
  __ incq(rax);
2533

    
2534
  __ movl(rdx, Operand(r88, -64 * kIntSize));
2535
  __ cmpl(rdx, Immediate(0x48484848));
2536
  __ j(not_equal, &exit);
2537
  __ incq(rax);
2538

    
2539
  __ movl(rdx, Operand(r88, 64 * kIntSize));
2540
  __ cmpl(rdx, Immediate(0xC8C8C8C8));
2541
  __ j(not_equal, &exit);
2542
  __ incq(rax);
2543

    
2544

    
2545
  Operand r864 = Operand(r8, 64 * kIntSize);
2546

    
2547
  // Test 36.
2548
  __ movl(rdx, r864);  // Sanity check.
2549
  __ cmpl(rdx, Immediate(0xC0C0C0C0));
2550
  __ j(not_equal, &exit);
2551
  __ incq(rax);
2552

    
2553
  __ movl(rdx, Operand(r864, -8 * kIntSize));
2554
  __ cmpl(rdx, Immediate(0xB8B8B8B8));
2555
  __ j(not_equal, &exit);
2556
  __ incq(rax);
2557

    
2558
  __ movl(rdx, Operand(r864, 8 * kIntSize));
2559
  __ cmpl(rdx, Immediate(0xC8C8C8C8));
2560
  __ j(not_equal, &exit);
2561
  __ incq(rax);
2562

    
2563
  __ movl(rdx, Operand(r864, -64 * kIntSize));
2564
  __ cmpl(rdx, Immediate(0x80808080));
2565
  __ j(not_equal, &exit);
2566
  __ incq(rax);
2567

    
2568
  __ movl(rdx, Operand(r864, 32 * kIntSize));
2569
  __ cmpl(rdx, Immediate(0xE0E0E0E0));
2570
  __ j(not_equal, &exit);
2571
  __ incq(rax);
2572

    
2573
  // 32-bit offset to 8-bit offset.
2574
  __ movl(rdx, Operand(r864, -60 * kIntSize));
2575
  __ cmpl(rdx, Immediate(0x84848484));
2576
  __ j(not_equal, &exit);
2577
  __ incq(rax);
2578

    
2579
  __ movl(rdx, Operand(r864, 60 * kIntSize));
2580
  __ cmpl(rdx, Immediate(0xFCFCFCFC));
2581
  __ j(not_equal, &exit);
2582
  __ incq(rax);
2583

    
2584
  // Test unaligned offsets.
2585

    
2586
  // Test 43.
2587
  __ movl(rdx, Operand(r80, 2));
2588
  __ cmpl(rdx, Immediate(0x81818080));
2589
  __ j(not_equal, &exit);
2590
  __ incq(rax);
2591

    
2592
  __ movl(rdx, Operand(r80, -2));
2593
  __ cmpl(rdx, Immediate(0x80807F7F));
2594
  __ j(not_equal, &exit);
2595
  __ incq(rax);
2596

    
2597
  __ movl(rdx, Operand(r80, 126));
2598
  __ cmpl(rdx, Immediate(0xA0A09F9F));
2599
  __ j(not_equal, &exit);
2600
  __ incq(rax);
2601

    
2602
  __ movl(rdx, Operand(r80, -126));
2603
  __ cmpl(rdx, Immediate(0x61616060));
2604
  __ j(not_equal, &exit);
2605
  __ incq(rax);
2606

    
2607
  __ movl(rdx, Operand(r80, 254));
2608
  __ cmpl(rdx, Immediate(0xC0C0BFBF));
2609
  __ j(not_equal, &exit);
2610
  __ incq(rax);
2611

    
2612
  __ movl(rdx, Operand(r80, -254));
2613
  __ cmpl(rdx, Immediate(0x41414040));
2614
  __ j(not_equal, &exit);
2615
  __ incq(rax);
2616

    
2617
  // Success.
2618

    
2619
  __ movl(rax, Immediate(0));
2620
  __ bind(&exit);
2621
  __ lea(rsp, Operand(rbp, kPointerSize));
2622
  __ pop(rbp);
2623
  __ pop(rbx);
2624
  __ pop(r14);
2625
  __ pop(r13);
2626
  ExitCode(masm);
2627
  __ ret(0);
2628

    
2629

    
2630
  CodeDesc desc;
2631
  masm->GetCode(&desc);
2632
  // Call the function from C++.
2633
  int result = FUNCTION_CAST<F0>(buffer)();
2634
  CHECK_EQ(0, result);
2635
}
2636

    
2637

    
2638
TEST(LoadAndStoreWithRepresentation) {
2639
  v8::internal::V8::Initialize(NULL);
2640

    
2641
  // Allocate an executable page of memory.
2642
  size_t actual_size;
2643
  byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
2644
                                                 &actual_size,
2645
                                                 true));
2646
  CHECK(buffer);
2647
  Isolate* isolate = CcTest::i_isolate();
2648
  HandleScope handles(isolate);
2649
  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
2650
  MacroAssembler* masm = &assembler;  // Create a pointer for the __ macro.
2651
  masm->set_allow_stub_calls(false);
2652
  EntryCode(masm);
2653
  __ subq(rsp, Immediate(1 * kPointerSize));
2654
  Label exit;
2655

    
2656
  // Test 1.
2657
  __ movq(rax, Immediate(1));  // Test number.
2658
  __ movq(Operand(rsp, 0 * kPointerSize), Immediate(0));
2659
  __ movq(rcx, Immediate(-1));
2660
  __ Store(Operand(rsp, 0 * kPointerSize), rcx, Representation::Byte());
2661
  __ movq(rcx, Operand(rsp, 0 * kPointerSize));
2662
  __ movl(rdx, Immediate(255));
2663
  __ cmpq(rcx, rdx);
2664
  __ j(not_equal, &exit);
2665
  __ Load(rdx, Operand(rsp, 0 * kPointerSize), Representation::Byte());
2666
  __ cmpq(rcx, rdx);
2667
  __ j(not_equal, &exit);
2668

    
2669
  // Test 2.
2670
  __ movq(rax, Immediate(2));  // Test number.
2671
  __ movq(Operand(rsp, 0 * kPointerSize), Immediate(0));
2672
  __ Set(rcx, V8_2PART_UINT64_C(0xdeadbeaf, 12345678));
2673
  __ Store(Operand(rsp, 0 * kPointerSize), rcx, Representation::Smi());
2674
  __ movq(rcx, Operand(rsp, 0 * kPointerSize));
2675
  __ Set(rdx, V8_2PART_UINT64_C(0xdeadbeaf, 12345678));
2676
  __ cmpq(rcx, rdx);
2677
  __ j(not_equal, &exit);
2678
  __ Load(rdx, Operand(rsp, 0 * kPointerSize), Representation::Smi());
2679
  __ cmpq(rcx, rdx);
2680
  __ j(not_equal, &exit);
2681

    
2682
  // Test 3.
2683
  __ movq(rax, Immediate(3));  // Test number.
2684
  __ movq(Operand(rsp, 0 * kPointerSize), Immediate(0));
2685
  __ movq(rcx, Immediate(-1));
2686
  __ Store(Operand(rsp, 0 * kPointerSize), rcx, Representation::Integer32());
2687
  __ movq(rcx, Operand(rsp, 0 * kPointerSize));
2688
  __ movl(rdx, Immediate(-1));
2689
  __ cmpq(rcx, rdx);
2690
  __ j(not_equal, &exit);
2691
  __ Load(rdx, Operand(rsp, 0 * kPointerSize), Representation::Integer32());
2692
  __ cmpq(rcx, rdx);
2693
  __ j(not_equal, &exit);
2694

    
2695
  // Test 4.
2696
  __ movq(rax, Immediate(4));  // Test number.
2697
  __ movq(Operand(rsp, 0 * kPointerSize), Immediate(0));
2698
  __ movl(rcx, Immediate(0x44332211));
2699
  __ Store(Operand(rsp, 0 * kPointerSize), rcx, Representation::HeapObject());
2700
  __ movq(rcx, Operand(rsp, 0 * kPointerSize));
2701
  __ movl(rdx, Immediate(0x44332211));
2702
  __ cmpq(rcx, rdx);
2703
  __ j(not_equal, &exit);
2704
  __ Load(rdx, Operand(rsp, 0 * kPointerSize), Representation::HeapObject());
2705
  __ cmpq(rcx, rdx);
2706
  __ j(not_equal, &exit);
2707

    
2708
  // Test 5.
2709
  __ movq(rax, Immediate(5));  // Test number.
2710
  __ movq(Operand(rsp, 0 * kPointerSize), Immediate(0));
2711
  __ Set(rcx, V8_2PART_UINT64_C(0x12345678, deadbeaf));
2712
  __ Store(Operand(rsp, 0 * kPointerSize), rcx, Representation::Tagged());
2713
  __ movq(rcx, Operand(rsp, 0 * kPointerSize));
2714
  __ Set(rdx, V8_2PART_UINT64_C(0x12345678, deadbeaf));
2715
  __ cmpq(rcx, rdx);
2716
  __ j(not_equal, &exit);
2717
  __ Load(rdx, Operand(rsp, 0 * kPointerSize), Representation::Tagged());
2718
  __ cmpq(rcx, rdx);
2719
  __ j(not_equal, &exit);
2720

    
2721
  // Test 6.
2722
  __ movq(rax, Immediate(6));  // Test number.
2723
  __ movq(Operand(rsp, 0 * kPointerSize), Immediate(0));
2724
  __ Set(rcx, V8_2PART_UINT64_C(0x11223344, 55667788));
2725
  __ Store(Operand(rsp, 0 * kPointerSize), rcx, Representation::External());
2726
  __ movq(rcx, Operand(rsp, 0 * kPointerSize));
2727
  __ Set(rdx, V8_2PART_UINT64_C(0x11223344, 55667788));
2728
  __ cmpq(rcx, rdx);
2729
  __ j(not_equal, &exit);
2730
  __ Load(rdx, Operand(rsp, 0 * kPointerSize), Representation::External());
2731
  __ cmpq(rcx, rdx);
2732
  __ j(not_equal, &exit);
2733

    
2734
  __ xor_(rax, rax);  // Success.
2735
  __ bind(&exit);
2736
  __ addq(rsp, Immediate(1 * kPointerSize));
2737
  ExitCode(masm);
2738
  __ ret(0);
2739

    
2740
  CodeDesc desc;
2741
  masm->GetCode(&desc);
2742
  // Call the function from C++.
2743
  int result = FUNCTION_CAST<F0>(buffer)();
2744
  CHECK_EQ(0, result);
2745
}
2746

    
2747

    
2748
#undef __