1// Copyright 2013 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#include "macro-assembler.h"
32#include "arm/macro-assembler-arm.h"
33#include "arm/simulator-arm.h"
34#include "cctest.h"
35
36
37using namespace v8::internal;
38
39typedef void* (*F)(int x, int y, int p2, int p3, int p4);
40
41#define __ masm->
42
43
44static byte to_non_zero(int n) {
45  return static_cast<unsigned>(n) % 255 + 1;
46}
47
48
49static bool all_zeroes(const byte* beg, const byte* end) {
50  CHECK(beg);
51  CHECK(beg <= end);
52  while (beg < end) {
53    if (*beg++ != 0)
54      return false;
55  }
56  return true;
57}
58
59
60TEST(CopyBytes) {
61  CcTest::InitializeVM();
62  Isolate* isolate = Isolate::Current();
63  HandleScope handles(isolate);
64
65  const int data_size = 1 * KB;
66  size_t act_size;
67
68  // Allocate two blocks to copy data between.
69  byte* src_buffer = static_cast<byte*>(OS::Allocate(data_size, &act_size, 0));
70  CHECK(src_buffer);
71  CHECK(act_size >= static_cast<size_t>(data_size));
72  byte* dest_buffer = static_cast<byte*>(OS::Allocate(data_size, &act_size, 0));
73  CHECK(dest_buffer);
74  CHECK(act_size >= static_cast<size_t>(data_size));
75
76  // Storage for R0 and R1.
77  byte* r0_;
78  byte* r1_;
79
80  MacroAssembler assembler(isolate, NULL, 0);
81  MacroAssembler* masm = &assembler;
82
83  // Code to be generated: The stuff in CopyBytes followed by a store of R0 and
84  // R1, respectively.
85  __ CopyBytes(r0, r1, r2, r3);
86  __ mov(r2, Operand(reinterpret_cast<int>(&r0_)));
87  __ mov(r3, Operand(reinterpret_cast<int>(&r1_)));
88  __ str(r0, MemOperand(r2));
89  __ str(r1, MemOperand(r3));
90  __ bx(lr);
91
92  CodeDesc desc;
93  masm->GetCode(&desc);
94  Object* code = isolate->heap()->CreateCode(
95      desc,
96      Code::ComputeFlags(Code::STUB),
97      Handle<Code>())->ToObjectChecked();
98  CHECK(code->IsCode());
99
100  F f = FUNCTION_CAST<F>(Code::cast(code)->entry());
101
102  // Initialise source data with non-zero bytes.
103  for (int i = 0; i < data_size; i++) {
104    src_buffer[i] = to_non_zero(i);
105  }
106
107  const int fuzz = 11;
108
109  for (int size = 0; size < 600; size++) {
110    for (const byte* src = src_buffer; src < src_buffer + fuzz; src++) {
111      for (byte* dest = dest_buffer; dest < dest_buffer + fuzz; dest++) {
112        memset(dest_buffer, 0, data_size);
113        CHECK(dest + size < dest_buffer + data_size);
114        (void) CALL_GENERATED_CODE(f, reinterpret_cast<int>(src),
115                                      reinterpret_cast<int>(dest), size, 0, 0);
116        // R0 and R1 should point at the first byte after the copied data.
117        CHECK_EQ(src + size, r0_);
118        CHECK_EQ(dest + size, r1_);
119        // Check that we haven't written outside the target area.
120        CHECK(all_zeroes(dest_buffer, dest));
121        CHECK(all_zeroes(dest + size, dest_buffer + data_size));
122        // Check the target area.
123        CHECK_EQ(0, memcmp(src, dest, size));
124      }
125    }
126  }
127
128  // Check that the source data hasn't been clobbered.
129  for (int i = 0; i < data_size; i++) {
130    CHECK(src_buffer[i] == to_non_zero(i));
131  }
132}
133
134
135typedef int (*F5)(void*, void*, void*, void*, void*);
136
137
138TEST(LoadAndStoreWithRepresentation) {
139  v8::internal::V8::Initialize(NULL);
140
141  // Allocate an executable page of memory.
142  size_t actual_size;
143  byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
144                                                 &actual_size,
145                                                 true));
146  CHECK(buffer);
147  Isolate* isolate = CcTest::i_isolate();
148  HandleScope handles(isolate);
149  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
150  MacroAssembler* masm = &assembler;  // Create a pointer for the __ macro.
151  __ sub(sp, sp, Operand(1 * kPointerSize));
152  Label exit;
153
154  // Test 1.
155  __ mov(r0, Operand(1));  // Test number.
156  __ mov(r1, Operand(0));
157  __ str(r1, MemOperand(sp, 0 * kPointerSize));
158  __ mov(r2, Operand(-1));
159  __ Store(r2, MemOperand(sp, 0 * kPointerSize), Representation::UInteger8());
160  __ ldr(r3, MemOperand(sp, 0 * kPointerSize));
161  __ mov(r2, Operand(255));
162  __ cmp(r3, r2);
163  __ b(ne, &exit);
164  __ mov(r2, Operand(255));
165  __ Load(r3, MemOperand(sp, 0 * kPointerSize), Representation::UInteger8());
166  __ cmp(r3, r2);
167  __ b(ne, &exit);
168
169  // Test 2.
170  __ mov(r0, Operand(2));  // Test number.
171  __ mov(r1, Operand(0));
172  __ str(r1, MemOperand(sp, 0 * kPointerSize));
173  __ mov(r2, Operand(-1));
174  __ Store(r2, MemOperand(sp, 0 * kPointerSize), Representation::Integer8());
175  __ ldr(r3, MemOperand(sp, 0 * kPointerSize));
176  __ mov(r2, Operand(255));
177  __ cmp(r3, r2);
178  __ b(ne, &exit);
179  __ mov(r2, Operand(-1));
180  __ Load(r3, MemOperand(sp, 0 * kPointerSize), Representation::Integer8());
181  __ cmp(r3, r2);
182  __ b(ne, &exit);
183
184  // Test 3.
185  __ mov(r0, Operand(3));  // Test number.
186  __ mov(r1, Operand(0));
187  __ str(r1, MemOperand(sp, 0 * kPointerSize));
188  __ mov(r2, Operand(-1));
189  __ Store(r2, MemOperand(sp, 0 * kPointerSize), Representation::UInteger16());
190  __ ldr(r3, MemOperand(sp, 0 * kPointerSize));
191  __ mov(r2, Operand(65535));
192  __ cmp(r3, r2);
193  __ b(ne, &exit);
194  __ mov(r2, Operand(65535));
195  __ Load(r3, MemOperand(sp, 0 * kPointerSize), Representation::UInteger16());
196  __ cmp(r3, r2);
197  __ b(ne, &exit);
198
199  // Test 4.
200  __ mov(r0, Operand(4));  // Test number.
201  __ mov(r1, Operand(0));
202  __ str(r1, MemOperand(sp, 0 * kPointerSize));
203  __ mov(r2, Operand(-1));
204  __ Store(r2, MemOperand(sp, 0 * kPointerSize), Representation::Integer16());
205  __ ldr(r3, MemOperand(sp, 0 * kPointerSize));
206  __ mov(r2, Operand(65535));
207  __ cmp(r3, r2);
208  __ b(ne, &exit);
209  __ mov(r2, Operand(-1));
210  __ Load(r3, MemOperand(sp, 0 * kPointerSize), Representation::Integer16());
211  __ cmp(r3, r2);
212  __ b(ne, &exit);
213
214  __ mov(r0, Operand(0));  // Success.
215  __ bind(&exit);
216  __ add(sp, sp, Operand(1 * kPointerSize));
217  __ bx(lr);
218
219  CodeDesc desc;
220  masm->GetCode(&desc);
221  Object* code = isolate->heap()->CreateCode(
222      desc,
223      Code::ComputeFlags(Code::STUB),
224      Handle<Code>())->ToObjectChecked();
225  CHECK(code->IsCode());
226
227  // Call the function from C++.
228  F5 f = FUNCTION_CAST<F5>(Code::cast(code)->entry());
229  CHECK_EQ(0, CALL_GENERATED_CODE(f, 0, 0, 0, 0, 0));
230}
231
232#undef __
233