1 // Copyright 2010 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 "v8.h" 29 30 #include "disassembler.h" 31 #include "factory.h" 32 #include "arm/simulator-arm.h" 33 #include "arm/assembler-arm-inl.h" 34 #include "cctest.h" 35 36 using namespace v8::internal; 37 38 39 // Define these function prototypes to match JSEntryFunction in execution.cc. 40 typedef Object* (*F1)(int x, int p1, int p2, int p3, int p4); 41 typedef Object* (*F2)(int x, int y, int p2, int p3, int p4); 42 typedef Object* (*F3)(void* p, int p1, int p2, int p3, int p4); 43 44 45 static v8::Persistent<v8::Context> env; 46 47 48 // The test framework does not accept flags on the command line, so we set them 49 static void InitializeVM() { 50 // enable generation of comments 51 FLAG_debug_code = true; 52 53 if (env.IsEmpty()) { 54 env = v8::Context::New(); 55 } 56 } 57 58 59 #define __ assm. 60 61 TEST(0) { 62 InitializeVM(); 63 v8::HandleScope scope; 64 65 Assembler assm(NULL, 0); 66 67 __ add(r0, r0, Operand(r1)); 68 __ mov(pc, Operand(lr)); 69 70 CodeDesc desc; 71 assm.GetCode(&desc); 72 Object* code = Heap::CreateCode(desc, 73 NULL, 74 Code::ComputeFlags(Code::STUB), 75 Handle<Object>(Heap::undefined_value())); 76 CHECK(code->IsCode()); 77 #ifdef DEBUG 78 Code::cast(code)->Print(); 79 #endif 80 F2 f = FUNCTION_CAST<F2>(Code::cast(code)->entry()); 81 int res = reinterpret_cast<int>(CALL_GENERATED_CODE(f, 3, 4, 0, 0, 0)); 82 ::printf("f() = %d\n", res); 83 CHECK_EQ(7, res); 84 } 85 86 87 TEST(1) { 88 InitializeVM(); 89 v8::HandleScope scope; 90 91 Assembler assm(NULL, 0); 92 Label L, C; 93 94 __ mov(r1, Operand(r0)); 95 __ mov(r0, Operand(0)); 96 __ b(&C); 97 98 __ bind(&L); 99 __ add(r0, r0, Operand(r1)); 100 __ sub(r1, r1, Operand(1)); 101 102 __ bind(&C); 103 __ teq(r1, Operand(0)); 104 __ b(ne, &L); 105 __ mov(pc, Operand(lr)); 106 107 CodeDesc desc; 108 assm.GetCode(&desc); 109 Object* code = Heap::CreateCode(desc, 110 NULL, 111 Code::ComputeFlags(Code::STUB), 112 Handle<Object>(Heap::undefined_value())); 113 CHECK(code->IsCode()); 114 #ifdef DEBUG 115 Code::cast(code)->Print(); 116 #endif 117 F1 f = FUNCTION_CAST<F1>(Code::cast(code)->entry()); 118 int res = reinterpret_cast<int>(CALL_GENERATED_CODE(f, 100, 0, 0, 0, 0)); 119 ::printf("f() = %d\n", res); 120 CHECK_EQ(5050, res); 121 } 122 123 124 TEST(2) { 125 InitializeVM(); 126 v8::HandleScope scope; 127 128 Assembler assm(NULL, 0); 129 Label L, C; 130 131 __ mov(r1, Operand(r0)); 132 __ mov(r0, Operand(1)); 133 __ b(&C); 134 135 __ bind(&L); 136 __ mul(r0, r1, r0); 137 __ sub(r1, r1, Operand(1)); 138 139 __ bind(&C); 140 __ teq(r1, Operand(0)); 141 __ b(ne, &L); 142 __ mov(pc, Operand(lr)); 143 144 // some relocated stuff here, not executed 145 __ RecordComment("dead code, just testing relocations"); 146 __ mov(r0, Operand(Factory::true_value())); 147 __ RecordComment("dead code, just testing immediate operands"); 148 __ mov(r0, Operand(-1)); 149 __ mov(r0, Operand(0xFF000000)); 150 __ mov(r0, Operand(0xF0F0F0F0)); 151 __ mov(r0, Operand(0xFFF0FFFF)); 152 153 CodeDesc desc; 154 assm.GetCode(&desc); 155 Object* code = Heap::CreateCode(desc, 156 NULL, 157 Code::ComputeFlags(Code::STUB), 158 Handle<Object>(Heap::undefined_value())); 159 CHECK(code->IsCode()); 160 #ifdef DEBUG 161 Code::cast(code)->Print(); 162 #endif 163 F1 f = FUNCTION_CAST<F1>(Code::cast(code)->entry()); 164 int res = reinterpret_cast<int>(CALL_GENERATED_CODE(f, 10, 0, 0, 0, 0)); 165 ::printf("f() = %d\n", res); 166 CHECK_EQ(3628800, res); 167 } 168 169 170 TEST(3) { 171 InitializeVM(); 172 v8::HandleScope scope; 173 174 typedef struct { 175 int i; 176 char c; 177 int16_t s; 178 } T; 179 T t; 180 181 Assembler assm(NULL, 0); 182 Label L, C; 183 184 __ mov(ip, Operand(sp)); 185 __ stm(db_w, sp, r4.bit() | fp.bit() | lr.bit()); 186 __ sub(fp, ip, Operand(4)); 187 __ mov(r4, Operand(r0)); 188 __ ldr(r0, MemOperand(r4, OFFSET_OF(T, i))); 189 __ mov(r2, Operand(r0, ASR, 1)); 190 __ str(r2, MemOperand(r4, OFFSET_OF(T, i))); 191 __ ldrsb(r2, MemOperand(r4, OFFSET_OF(T, c))); 192 __ add(r0, r2, Operand(r0)); 193 __ mov(r2, Operand(r2, LSL, 2)); 194 __ strb(r2, MemOperand(r4, OFFSET_OF(T, c))); 195 __ ldrsh(r2, MemOperand(r4, OFFSET_OF(T, s))); 196 __ add(r0, r2, Operand(r0)); 197 __ mov(r2, Operand(r2, ASR, 3)); 198 __ strh(r2, MemOperand(r4, OFFSET_OF(T, s))); 199 __ ldm(ia_w, sp, r4.bit() | fp.bit() | pc.bit()); 200 201 CodeDesc desc; 202 assm.GetCode(&desc); 203 Object* code = Heap::CreateCode(desc, 204 NULL, 205 Code::ComputeFlags(Code::STUB), 206 Handle<Object>(Heap::undefined_value())); 207 CHECK(code->IsCode()); 208 #ifdef DEBUG 209 Code::cast(code)->Print(); 210 #endif 211 F3 f = FUNCTION_CAST<F3>(Code::cast(code)->entry()); 212 t.i = 100000; 213 t.c = 10; 214 t.s = 1000; 215 int res = reinterpret_cast<int>(CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0)); 216 ::printf("f() = %d\n", res); 217 CHECK_EQ(101010, res); 218 CHECK_EQ(100000/2, t.i); 219 CHECK_EQ(10*4, t.c); 220 CHECK_EQ(1000/8, t.s); 221 } 222 223 224 TEST(4) { 225 // Test the VFP floating point instructions. 226 InitializeVM(); 227 v8::HandleScope scope; 228 229 typedef struct { 230 double a; 231 double b; 232 double c; 233 } T; 234 T t; 235 236 // Create a function that accepts &t, and loads, manipulates, and stores 237 // the doubles t.a, t.b, and t.c. 238 Assembler assm(NULL, 0); 239 Label L, C; 240 241 242 if (CpuFeatures::IsSupported(VFP3)) { 243 CpuFeatures::Scope scope(VFP3); 244 245 __ mov(ip, Operand(sp)); 246 __ stm(db_w, sp, r4.bit() | fp.bit() | lr.bit()); 247 __ sub(fp, ip, Operand(4)); 248 249 __ mov(r4, Operand(r0)); 250 __ vldr(d6, r4, OFFSET_OF(T, a)); 251 __ vldr(d7, r4, OFFSET_OF(T, b)); 252 __ vadd(d5, d6, d7); 253 __ vstr(d5, r4, OFFSET_OF(T, c)); 254 255 __ vmov(r2, r3, d5); 256 __ vmov(d4, r2, r3); 257 __ vstr(d4, r4, OFFSET_OF(T, b)); 258 259 __ ldm(ia_w, sp, r4.bit() | fp.bit() | pc.bit()); 260 261 CodeDesc desc; 262 assm.GetCode(&desc); 263 Object* code = Heap::CreateCode(desc, 264 NULL, 265 Code::ComputeFlags(Code::STUB), 266 Handle<Object>(Heap::undefined_value())); 267 CHECK(code->IsCode()); 268 #ifdef DEBUG 269 Code::cast(code)->Print(); 270 #endif 271 F3 f = FUNCTION_CAST<F3>(Code::cast(code)->entry()); 272 t.a = 1.5; 273 t.b = 2.75; 274 t.c = 17.17; 275 Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0); 276 USE(dummy); 277 CHECK_EQ(4.25, t.c); 278 CHECK_EQ(4.25, t.b); 279 CHECK_EQ(1.5, t.a); 280 } 281 } 282 283 #undef __ 284