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-assembler-ia32.cc @ f230a1cf

History | View | Annotate | Download (15.8 KB)

1
// Copyright 2011 the V8 project authors. All rights reserved.
2
// Redistribution and use in source and binary forms, with or without
3
// modification, are permitted provided that the following conditions are
4
// met:
5
//
6
//     * Redistributions of source code must retain the above copyright
7
//       notice, this list of conditions and the following disclaimer.
8
//     * Redistributions in binary form must reproduce the above
9
//       copyright notice, this list of conditions and the following
10
//       disclaimer in the documentation and/or other materials provided
11
//       with the distribution.
12
//     * Neither the name of Google Inc. nor the names of its
13
//       contributors may be used to endorse or promote products derived
14
//       from this software without specific prior written permission.
15
//
16
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27

    
28
#include <stdlib.h>
29

    
30
#include "v8.h"
31

    
32
#include "disassembler.h"
33
#include "factory.h"
34
#include "macro-assembler.h"
35
#include "platform.h"
36
#include "serialize.h"
37
#include "cctest.h"
38

    
39
using namespace v8::internal;
40

    
41

    
42
typedef int (*F0)();
43
typedef int (*F1)(int x);
44
typedef int (*F2)(int x, int y);
45

    
46

    
47
#define __ assm.
48

    
49
TEST(AssemblerIa320) {
50
  CcTest::InitializeVM();
51
  Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
52
  HandleScope scope(isolate);
53

    
54
  v8::internal::byte buffer[256];
55
  Assembler assm(isolate, buffer, sizeof buffer);
56

    
57
  __ mov(eax, Operand(esp, 4));
58
  __ add(eax, Operand(esp, 8));
59
  __ ret(0);
60

    
61
  CodeDesc desc;
62
  assm.GetCode(&desc);
63
  Object* code = isolate->heap()->CreateCode(
64
      desc,
65
      Code::ComputeFlags(Code::STUB),
66
      Handle<Code>())->ToObjectChecked();
67
  CHECK(code->IsCode());
68
#ifdef OBJECT_PRINT
69
  Code::cast(code)->Print();
70
#endif
71
  F2 f = FUNCTION_CAST<F2>(Code::cast(code)->entry());
72
  int res = f(3, 4);
73
  ::printf("f() = %d\n", res);
74
  CHECK_EQ(7, res);
75
}
76

    
77

    
78
TEST(AssemblerIa321) {
79
  CcTest::InitializeVM();
80
  Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
81
  HandleScope scope(isolate);
82

    
83
  v8::internal::byte buffer[256];
84
  Assembler assm(isolate, buffer, sizeof buffer);
85
  Label L, C;
86

    
87
  __ mov(edx, Operand(esp, 4));
88
  __ xor_(eax, eax);  // clear eax
89
  __ jmp(&C);
90

    
91
  __ bind(&L);
92
  __ add(eax, edx);
93
  __ sub(edx, Immediate(1));
94

    
95
  __ bind(&C);
96
  __ test(edx, edx);
97
  __ j(not_zero, &L);
98
  __ ret(0);
99

    
100
  CodeDesc desc;
101
  assm.GetCode(&desc);
102
  Object* code = isolate->heap()->CreateCode(
103
      desc,
104
      Code::ComputeFlags(Code::STUB),
105
      Handle<Code>())->ToObjectChecked();
106
  CHECK(code->IsCode());
107
#ifdef OBJECT_PRINT
108
  Code::cast(code)->Print();
109
#endif
110
  F1 f = FUNCTION_CAST<F1>(Code::cast(code)->entry());
111
  int res = f(100);
112
  ::printf("f() = %d\n", res);
113
  CHECK_EQ(5050, res);
114
}
115

    
116

    
117
TEST(AssemblerIa322) {
118
  CcTest::InitializeVM();
119
  Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
120
  HandleScope scope(isolate);
121

    
122
  v8::internal::byte buffer[256];
123
  Assembler assm(isolate, buffer, sizeof buffer);
124
  Label L, C;
125

    
126
  __ mov(edx, Operand(esp, 4));
127
  __ mov(eax, 1);
128
  __ jmp(&C);
129

    
130
  __ bind(&L);
131
  __ imul(eax, edx);
132
  __ sub(edx, Immediate(1));
133

    
134
  __ bind(&C);
135
  __ test(edx, edx);
136
  __ j(not_zero, &L);
137
  __ ret(0);
138

    
139
  // some relocated stuff here, not executed
140
  __ mov(eax, isolate->factory()->true_value());
141
  __ jmp(NULL, RelocInfo::RUNTIME_ENTRY);
142

    
143
  CodeDesc desc;
144
  assm.GetCode(&desc);
145
  Object* code = isolate->heap()->CreateCode(
146
      desc,
147
      Code::ComputeFlags(Code::STUB),
148
      Handle<Code>())->ToObjectChecked();
149
  CHECK(code->IsCode());
150
#ifdef OBJECT_PRINT
151
  Code::cast(code)->Print();
152
#endif
153
  F1 f = FUNCTION_CAST<F1>(Code::cast(code)->entry());
154
  int res = f(10);
155
  ::printf("f() = %d\n", res);
156
  CHECK_EQ(3628800, res);
157
}
158

    
159

    
160
typedef int (*F3)(float x);
161

    
162
TEST(AssemblerIa323) {
163
  CcTest::InitializeVM();
164
  if (!CpuFeatures::IsSupported(SSE2)) return;
165

    
166
  Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
167
  HandleScope scope(isolate);
168

    
169
  v8::internal::byte buffer[256];
170
  Assembler assm(isolate, buffer, sizeof buffer);
171

    
172
  CHECK(CpuFeatures::IsSupported(SSE2));
173
  { CpuFeatureScope fscope(&assm, SSE2);
174
    __ cvttss2si(eax, Operand(esp, 4));
175
    __ ret(0);
176
  }
177

    
178
  CodeDesc desc;
179
  assm.GetCode(&desc);
180
  Code* code = Code::cast(isolate->heap()->CreateCode(
181
      desc,
182
      Code::ComputeFlags(Code::STUB),
183
      Handle<Code>())->ToObjectChecked());
184
  // don't print the code - our disassembler can't handle cvttss2si
185
  // instead print bytes
186
  Disassembler::Dump(stdout,
187
                     code->instruction_start(),
188
                     code->instruction_start() + code->instruction_size());
189
  F3 f = FUNCTION_CAST<F3>(code->entry());
190
  int res = f(static_cast<float>(-3.1415));
191
  ::printf("f() = %d\n", res);
192
  CHECK_EQ(-3, res);
193
}
194

    
195

    
196
typedef int (*F4)(double x);
197

    
198
TEST(AssemblerIa324) {
199
  CcTest::InitializeVM();
200
  if (!CpuFeatures::IsSupported(SSE2)) return;
201

    
202
  Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
203
  HandleScope scope(isolate);
204

    
205
  v8::internal::byte buffer[256];
206
  Assembler assm(isolate, buffer, sizeof buffer);
207

    
208
  CHECK(CpuFeatures::IsSupported(SSE2));
209
  CpuFeatureScope fscope(&assm, SSE2);
210
  __ cvttsd2si(eax, Operand(esp, 4));
211
  __ ret(0);
212

    
213
  CodeDesc desc;
214
  assm.GetCode(&desc);
215
  Code* code = Code::cast(isolate->heap()->CreateCode(
216
      desc,
217
      Code::ComputeFlags(Code::STUB),
218
      Handle<Code>())->ToObjectChecked());
219
  // don't print the code - our disassembler can't handle cvttsd2si
220
  // instead print bytes
221
  Disassembler::Dump(stdout,
222
                     code->instruction_start(),
223
                     code->instruction_start() + code->instruction_size());
224
  F4 f = FUNCTION_CAST<F4>(code->entry());
225
  int res = f(2.718281828);
226
  ::printf("f() = %d\n", res);
227
  CHECK_EQ(2, res);
228
}
229

    
230

    
231
static int baz = 42;
232
TEST(AssemblerIa325) {
233
  CcTest::InitializeVM();
234
  Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
235
  HandleScope scope(isolate);
236

    
237
  v8::internal::byte buffer[256];
238
  Assembler assm(isolate, buffer, sizeof buffer);
239

    
240
  __ mov(eax, Operand(reinterpret_cast<intptr_t>(&baz), RelocInfo::NONE32));
241
  __ ret(0);
242

    
243
  CodeDesc desc;
244
  assm.GetCode(&desc);
245
  Code* code = Code::cast(isolate->heap()->CreateCode(
246
      desc,
247
      Code::ComputeFlags(Code::STUB),
248
      Handle<Code>())->ToObjectChecked());
249
  F0 f = FUNCTION_CAST<F0>(code->entry());
250
  int res = f();
251
  CHECK_EQ(42, res);
252
}
253

    
254

    
255
typedef double (*F5)(double x, double y);
256

    
257
TEST(AssemblerIa326) {
258
  CcTest::InitializeVM();
259
  if (!CpuFeatures::IsSupported(SSE2)) return;
260

    
261
  Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
262
  HandleScope scope(isolate);
263
  v8::internal::byte buffer[256];
264
  Assembler assm(isolate, buffer, sizeof buffer);
265

    
266
  CpuFeatureScope fscope(&assm, SSE2);
267
  __ movsd(xmm0, Operand(esp, 1 * kPointerSize));
268
  __ movsd(xmm1, Operand(esp, 3 * kPointerSize));
269
  __ addsd(xmm0, xmm1);
270
  __ mulsd(xmm0, xmm1);
271
  __ subsd(xmm0, xmm1);
272
  __ divsd(xmm0, xmm1);
273
  // Copy xmm0 to st(0) using eight bytes of stack.
274
  __ sub(esp, Immediate(8));
275
  __ movsd(Operand(esp, 0), xmm0);
276
  __ fld_d(Operand(esp, 0));
277
  __ add(esp, Immediate(8));
278
  __ ret(0);
279

    
280
  CodeDesc desc;
281
  assm.GetCode(&desc);
282
  Code* code = Code::cast(isolate->heap()->CreateCode(
283
      desc,
284
      Code::ComputeFlags(Code::STUB),
285
      Handle<Code>())->ToObjectChecked());
286
#ifdef DEBUG
287
  ::printf("\n---\n");
288
  // don't print the code - our disassembler can't handle SSE instructions
289
  // instead print bytes
290
  Disassembler::Dump(stdout,
291
                     code->instruction_start(),
292
                     code->instruction_start() + code->instruction_size());
293
#endif
294
  F5 f = FUNCTION_CAST<F5>(code->entry());
295
  double res = f(2.2, 1.1);
296
  ::printf("f() = %f\n", res);
297
  CHECK(2.29 < res && res < 2.31);
298
}
299

    
300

    
301
typedef double (*F6)(int x);
302

    
303
TEST(AssemblerIa328) {
304
  CcTest::InitializeVM();
305
  if (!CpuFeatures::IsSupported(SSE2)) return;
306

    
307
  Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
308
  HandleScope scope(isolate);
309
  v8::internal::byte buffer[256];
310
  Assembler assm(isolate, buffer, sizeof buffer);
311
  CpuFeatureScope fscope(&assm, SSE2);
312
  __ mov(eax, Operand(esp, 4));
313
  __ cvtsi2sd(xmm0, eax);
314
  // Copy xmm0 to st(0) using eight bytes of stack.
315
  __ sub(esp, Immediate(8));
316
  __ movsd(Operand(esp, 0), xmm0);
317
  __ fld_d(Operand(esp, 0));
318
  __ add(esp, Immediate(8));
319
  __ ret(0);
320
  CodeDesc desc;
321
  assm.GetCode(&desc);
322
  Code* code = Code::cast(isolate->heap()->CreateCode(
323
      desc,
324
      Code::ComputeFlags(Code::STUB),
325
      Handle<Code>())->ToObjectChecked());
326
  CHECK(code->IsCode());
327
#ifdef OBJECT_PRINT
328
  Code::cast(code)->Print();
329
#endif
330
  F6 f = FUNCTION_CAST<F6>(Code::cast(code)->entry());
331
  double res = f(12);
332

    
333
  ::printf("f() = %f\n", res);
334
  CHECK(11.99 < res && res < 12.001);
335
}
336

    
337

    
338
typedef int (*F7)(double x, double y);
339

    
340
TEST(AssemblerIa329) {
341
  CcTest::InitializeVM();
342
  Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
343
  HandleScope scope(isolate);
344
  v8::internal::byte buffer[256];
345
  MacroAssembler assm(isolate, buffer, sizeof buffer);
346
  enum { kEqual = 0, kGreater = 1, kLess = 2, kNaN = 3, kUndefined = 4 };
347
  Label equal_l, less_l, greater_l, nan_l;
348
  __ fld_d(Operand(esp, 3 * kPointerSize));
349
  __ fld_d(Operand(esp, 1 * kPointerSize));
350
  __ FCmp();
351
  __ j(parity_even, &nan_l);
352
  __ j(equal, &equal_l);
353
  __ j(below, &less_l);
354
  __ j(above, &greater_l);
355

    
356
  __ mov(eax, kUndefined);
357
  __ ret(0);
358

    
359
  __ bind(&equal_l);
360
  __ mov(eax, kEqual);
361
  __ ret(0);
362

    
363
  __ bind(&greater_l);
364
  __ mov(eax, kGreater);
365
  __ ret(0);
366

    
367
  __ bind(&less_l);
368
  __ mov(eax, kLess);
369
  __ ret(0);
370

    
371
  __ bind(&nan_l);
372
  __ mov(eax, kNaN);
373
  __ ret(0);
374

    
375

    
376
  CodeDesc desc;
377
  assm.GetCode(&desc);
378
  Code* code = Code::cast(isolate->heap()->CreateCode(
379
      desc,
380
      Code::ComputeFlags(Code::STUB),
381
      Handle<Code>())->ToObjectChecked());
382
  CHECK(code->IsCode());
383
#ifdef OBJECT_PRINT
384
  Code::cast(code)->Print();
385
#endif
386

    
387
  F7 f = FUNCTION_CAST<F7>(Code::cast(code)->entry());
388
  CHECK_EQ(kLess, f(1.1, 2.2));
389
  CHECK_EQ(kEqual, f(2.2, 2.2));
390
  CHECK_EQ(kGreater, f(3.3, 2.2));
391
  CHECK_EQ(kNaN, f(OS::nan_value(), 1.1));
392
}
393

    
394

    
395
TEST(AssemblerIa3210) {
396
  // Test chaining of label usages within instructions (issue 1644).
397
  CcTest::InitializeVM();
398
  Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
399
  HandleScope scope(isolate);
400
  Assembler assm(isolate, NULL, 0);
401

    
402
  Label target;
403
  __ j(equal, &target);
404
  __ j(not_equal, &target);
405
  __ bind(&target);
406
  __ nop();
407
}
408

    
409

    
410
TEST(AssemblerMultiByteNop) {
411
  CcTest::InitializeVM();
412
  Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
413
  HandleScope scope(isolate);
414
  v8::internal::byte buffer[1024];
415
  Assembler assm(isolate, buffer, sizeof(buffer));
416
  __ push(ebx);
417
  __ push(ecx);
418
  __ push(edx);
419
  __ push(edi);
420
  __ push(esi);
421
  __ mov(eax, 1);
422
  __ mov(ebx, 2);
423
  __ mov(ecx, 3);
424
  __ mov(edx, 4);
425
  __ mov(edi, 5);
426
  __ mov(esi, 6);
427
  for (int i = 0; i < 16; i++) {
428
    int before = assm.pc_offset();
429
    __ Nop(i);
430
    CHECK_EQ(assm.pc_offset() - before, i);
431
  }
432

    
433
  Label fail;
434
  __ cmp(eax, 1);
435
  __ j(not_equal, &fail);
436
  __ cmp(ebx, 2);
437
  __ j(not_equal, &fail);
438
  __ cmp(ecx, 3);
439
  __ j(not_equal, &fail);
440
  __ cmp(edx, 4);
441
  __ j(not_equal, &fail);
442
  __ cmp(edi, 5);
443
  __ j(not_equal, &fail);
444
  __ cmp(esi, 6);
445
  __ j(not_equal, &fail);
446
  __ mov(eax, 42);
447
  __ pop(esi);
448
  __ pop(edi);
449
  __ pop(edx);
450
  __ pop(ecx);
451
  __ pop(ebx);
452
  __ ret(0);
453
  __ bind(&fail);
454
  __ mov(eax, 13);
455
  __ pop(esi);
456
  __ pop(edi);
457
  __ pop(edx);
458
  __ pop(ecx);
459
  __ pop(ebx);
460
  __ ret(0);
461

    
462
  CodeDesc desc;
463
  assm.GetCode(&desc);
464
  Code* code = Code::cast(isolate->heap()->CreateCode(
465
      desc,
466
      Code::ComputeFlags(Code::STUB),
467
      Handle<Code>())->ToObjectChecked());
468
  CHECK(code->IsCode());
469

    
470
  F0 f = FUNCTION_CAST<F0>(code->entry());
471
  int res = f();
472
  CHECK_EQ(42, res);
473
}
474

    
475

    
476
#ifdef __GNUC__
477
#define ELEMENT_COUNT 4
478

    
479
void DoSSE2(const v8::FunctionCallbackInfo<v8::Value>& args) {
480
  Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
481
  HandleScope scope(isolate);
482

    
483
  CHECK(args[0]->IsArray());
484
  v8::Local<v8::Array> vec = v8::Local<v8::Array>::Cast(args[0]);
485
  CHECK_EQ(ELEMENT_COUNT, vec->Length());
486

    
487
  v8::internal::byte buffer[256];
488
  Assembler assm(isolate, buffer, sizeof buffer);
489

    
490
  ASSERT(CpuFeatures::IsSupported(SSE2));
491
  CpuFeatureScope fscope(&assm, SSE2);
492

    
493
  // Remove return address from the stack for fix stack frame alignment.
494
  __ pop(ecx);
495

    
496
  // Store input vector on the stack.
497
  for (int i = 0; i < ELEMENT_COUNT; ++i) {
498
    __ push(Immediate(vec->Get(i)->Int32Value()));
499
  }
500

    
501
  // Read vector into a xmm register.
502
  __ pxor(xmm0, xmm0);
503
  __ movdqa(xmm0, Operand(esp, 0));
504
  // Create mask and store it in the return register.
505
  __ movmskps(eax, xmm0);
506

    
507
  // Remove unused data from the stack.
508
  __ add(esp, Immediate(ELEMENT_COUNT * sizeof(int32_t)));
509
  // Restore return address.
510
  __ push(ecx);
511

    
512
  __ ret(0);
513

    
514
  CodeDesc desc;
515
  assm.GetCode(&desc);
516

    
517
  Object* code = isolate->heap()->CreateCode(
518
      desc,
519
      Code::ComputeFlags(Code::STUB),
520
      Handle<Code>())->ToObjectChecked();
521
  CHECK(code->IsCode());
522

    
523
  F0 f = FUNCTION_CAST<F0>(Code::cast(code)->entry());
524
  int res = f();
525
  args.GetReturnValue().Set(v8::Integer::New(res));
526
}
527

    
528

    
529
TEST(StackAlignmentForSSE2) {
530
  CcTest::InitializeVM();
531
  if (!CpuFeatures::IsSupported(SSE2)) return;
532

    
533
  CHECK_EQ(0, OS::ActivationFrameAlignment() % 16);
534

    
535
  v8::Isolate* isolate = CcTest::isolate();
536
  v8::HandleScope handle_scope(isolate);
537
  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
538
  global_template->Set(v8_str("do_sse2"), v8::FunctionTemplate::New(DoSSE2));
539

    
540
  LocalContext env(NULL, global_template);
541
  CompileRun(
542
      "function foo(vec) {"
543
      "  return do_sse2(vec);"
544
      "}");
545

    
546
  v8::Local<v8::Object> global_object = env->Global();
547
  v8::Local<v8::Function> foo =
548
      v8::Local<v8::Function>::Cast(global_object->Get(v8_str("foo")));
549

    
550
  int32_t vec[ELEMENT_COUNT] = { -1, 1, 1, 1 };
551
  v8::Local<v8::Array> v8_vec = v8::Array::New(ELEMENT_COUNT);
552
  for (int i = 0; i < ELEMENT_COUNT; i++) {
553
      v8_vec->Set(i, v8_num(vec[i]));
554
  }
555

    
556
  v8::Local<v8::Value> args[] = { v8_vec };
557
  v8::Local<v8::Value> result = foo->Call(global_object, 1, args);
558

    
559
  // The mask should be 0b1000.
560
  CHECK_EQ(8, result->Int32Value());
561
}
562

    
563
#undef ELEMENT_COUNT
564
#endif  // __GNUC__
565

    
566

    
567
TEST(AssemblerIa32Extractps) {
568
  CcTest::InitializeVM();
569
  if (!CpuFeatures::IsSupported(SSE2) ||
570
      !CpuFeatures::IsSupported(SSE4_1)) return;
571

    
572
  Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
573
  HandleScope scope(isolate);
574
  v8::internal::byte buffer[256];
575
  MacroAssembler assm(isolate, buffer, sizeof buffer);
576
  { CpuFeatureScope fscope2(&assm, SSE2);
577
    CpuFeatureScope fscope41(&assm, SSE4_1);
578
    __ movsd(xmm1, Operand(esp, 4));
579
    __ extractps(eax, xmm1, 0x1);
580
    __ ret(0);
581
  }
582

    
583
  CodeDesc desc;
584
  assm.GetCode(&desc);
585
  Code* code = Code::cast(isolate->heap()->CreateCode(
586
      desc,
587
      Code::ComputeFlags(Code::STUB),
588
      Handle<Code>())->ToObjectChecked());
589
  CHECK(code->IsCode());
590
#ifdef OBJECT_PRINT
591
  Code::cast(code)->Print();
592
#endif
593

    
594
  F4 f = FUNCTION_CAST<F4>(Code::cast(code)->entry());
595
  uint64_t value1 = V8_2PART_UINT64_C(0x12345678, 87654321);
596
  CHECK_EQ(0x12345678, f(uint64_to_double(value1)));
597
  uint64_t value2 = V8_2PART_UINT64_C(0x87654321, 12345678);
598
  CHECK_EQ(0x87654321, f(uint64_to_double(value2)));
599
}
600

    
601

    
602
#undef __