OLD | NEW |
(Empty) | |
| 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 "v8.h" |
| 29 |
| 30 #include "codegen-inl.h" |
| 31 #include "register-allocator-inl.h" |
| 32 #include "scopes.h" |
| 33 |
| 34 namespace v8 { namespace internal { |
| 35 |
| 36 // ------------------------------------------------------------------------- |
| 37 // VirtualFrame implementation. |
| 38 |
| 39 #define __ ACCESS_MASM(masm_) |
| 40 |
| 41 |
| 42 // On entry to a function, the virtual frame already contains the |
| 43 // receiver and the parameters. All initial frame elements are in |
| 44 // memory. |
| 45 VirtualFrame::VirtualFrame(CodeGenerator* cgen) |
| 46 : cgen_(cgen), |
| 47 masm_(cgen->masm()), |
| 48 elements_(cgen->scope()->num_parameters() |
| 49 + cgen->scope()->num_stack_slots() |
| 50 + kPreallocatedElements), |
| 51 parameter_count_(cgen->scope()->num_parameters()), |
| 52 local_count_(0), |
| 53 stack_pointer_(parameter_count_), // 0-based index of TOS. |
| 54 frame_pointer_(kIllegalIndex) { |
| 55 for (int i = 0; i < parameter_count_ + 1; i++) { |
| 56 elements_.Add(FrameElement::MemoryElement()); |
| 57 } |
| 58 for (int i = 0; i < kNumRegisters; i++) { |
| 59 register_locations_[i] = kIllegalIndex; |
| 60 } |
| 61 } |
| 62 |
| 63 |
| 64 void VirtualFrame::SyncElementBelowStackPointer(int index) { |
| 65 UNREACHABLE(); |
| 66 } |
| 67 |
| 68 |
| 69 void VirtualFrame::SyncElementByPushing(int index) { |
| 70 UNREACHABLE(); |
| 71 } |
| 72 |
| 73 |
| 74 void VirtualFrame::MergeTo(VirtualFrame* expected) { |
| 75 Comment cmnt(masm_, "[ Merge frame"); |
| 76 // We should always be merging the code generator's current frame to an |
| 77 // expected frame. |
| 78 ASSERT(cgen_->frame() == this); |
| 79 |
| 80 // Adjust the stack pointer upward (toward the top of the virtual |
| 81 // frame) if necessary. |
| 82 if (stack_pointer_ < expected->stack_pointer_) { |
| 83 int difference = expected->stack_pointer_ - stack_pointer_; |
| 84 stack_pointer_ = expected->stack_pointer_; |
| 85 __ sub(sp, sp, Operand(difference * kPointerSize)); |
| 86 } |
| 87 |
| 88 MergeMoveRegistersToMemory(expected); |
| 89 MergeMoveRegistersToRegisters(expected); |
| 90 MergeMoveMemoryToRegisters(expected); |
| 91 |
| 92 // Fix any sync bit problems from the bottom-up, stopping when we |
| 93 // hit the stack pointer or the top of the frame if the stack |
| 94 // pointer is floating above the frame. |
| 95 int limit = Min(stack_pointer_, elements_.length() - 1); |
| 96 for (int i = 0; i <= limit; i++) { |
| 97 FrameElement source = elements_[i]; |
| 98 FrameElement target = expected->elements_[i]; |
| 99 if (source.is_synced() && !target.is_synced()) { |
| 100 elements_[i].clear_sync(); |
| 101 } else if (!source.is_synced() && target.is_synced()) { |
| 102 SyncElementAt(i); |
| 103 } |
| 104 } |
| 105 |
| 106 // Adjust the stack point downard if necessary. |
| 107 if (stack_pointer_ > expected->stack_pointer_) { |
| 108 int difference = stack_pointer_ - expected->stack_pointer_; |
| 109 stack_pointer_ = expected->stack_pointer_; |
| 110 __ add(sp, sp, Operand(difference * kPointerSize)); |
| 111 } |
| 112 |
| 113 // At this point, the frames should be identical. |
| 114 ASSERT(Equals(expected)); |
| 115 } |
| 116 |
| 117 |
| 118 void VirtualFrame::MergeMoveRegistersToMemory(VirtualFrame* expected) { |
| 119 ASSERT(stack_pointer_ >= expected->stack_pointer_); |
| 120 |
| 121 // Move registers, constants, and copies to memory. Perform moves |
| 122 // from the top downward in the frame in order to leave the backing |
| 123 // stores of copies in registers. |
| 124 // On ARM, all elements are in memory. |
| 125 |
| 126 #ifdef DEBUG |
| 127 int start = Min(stack_pointer_, elements_.length() - 1); |
| 128 for (int i = start; i >= 0; i--) { |
| 129 ASSERT(elements_[i].is_memory()); |
| 130 ASSERT(expected->elements_[i].is_memory()); |
| 131 } |
| 132 #endif |
| 133 } |
| 134 |
| 135 |
| 136 void VirtualFrame::MergeMoveRegistersToRegisters(VirtualFrame* expected) { |
| 137 } |
| 138 |
| 139 |
| 140 void VirtualFrame::MergeMoveMemoryToRegisters(VirtualFrame *expected) { |
| 141 } |
| 142 |
| 143 |
| 144 void VirtualFrame::Enter() { |
| 145 Comment cmnt(masm_, "[ Enter JS frame"); |
| 146 |
| 147 #ifdef DEBUG |
| 148 // Verify that r1 contains a JS function. The following code relies |
| 149 // on r2 being available for use. |
| 150 { Label map_check, done; |
| 151 __ tst(r1, Operand(kSmiTagMask)); |
| 152 __ b(ne, &map_check); |
| 153 __ stop("VirtualFrame::Enter - r1 is not a function (smi check)."); |
| 154 __ bind(&map_check); |
| 155 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset)); |
| 156 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset)); |
| 157 __ cmp(r2, Operand(JS_FUNCTION_TYPE)); |
| 158 __ b(eq, &done); |
| 159 __ stop("VirtualFrame::Enter - r1 is not a function (map check)."); |
| 160 __ bind(&done); |
| 161 } |
| 162 #endif // DEBUG |
| 163 |
| 164 // We are about to push four values to the frame. |
| 165 Adjust(4); |
| 166 __ stm(db_w, sp, r1.bit() | cp.bit() | fp.bit() | lr.bit()); |
| 167 // Adjust FP to point to saved FP. |
| 168 frame_pointer_ = elements_.length() - 2; |
| 169 __ add(fp, sp, Operand(2 * kPointerSize)); |
| 170 cgen_->allocator()->Unuse(r1); |
| 171 cgen_->allocator()->Unuse(lr); |
| 172 } |
| 173 |
| 174 |
| 175 void VirtualFrame::Exit() { |
| 176 Comment cmnt(masm_, "[ Exit JS frame"); |
| 177 // Drop the execution stack down to the frame pointer and restore the caller |
| 178 // frame pointer and return address. |
| 179 __ mov(sp, fp); |
| 180 __ ldm(ia_w, sp, fp.bit() | lr.bit()); |
| 181 } |
| 182 |
| 183 |
| 184 void VirtualFrame::AllocateStackSlots(int count) { |
| 185 ASSERT(height() == 0); |
| 186 local_count_ = count; |
| 187 Adjust(count); |
| 188 if (count > 0) { |
| 189 Comment cmnt(masm_, "[ Allocate space for locals"); |
| 190 // Initialize stack slots with 'undefined' value. |
| 191 __ mov(ip, Operand(Factory::undefined_value())); |
| 192 for (int i = 0; i < count; i++) { |
| 193 __ push(ip); |
| 194 } |
| 195 } |
| 196 } |
| 197 |
| 198 |
| 199 void VirtualFrame::SaveContextRegister() { |
| 200 UNIMPLEMENTED(); |
| 201 } |
| 202 |
| 203 |
| 204 void VirtualFrame::RestoreContextRegister() { |
| 205 UNIMPLEMENTED(); |
| 206 } |
| 207 |
| 208 |
| 209 void VirtualFrame::PushReceiverSlotAddress() { |
| 210 UNIMPLEMENTED(); |
| 211 } |
| 212 |
| 213 |
| 214 int VirtualFrame::InvalidateFrameSlotAt(int index) { |
| 215 UNIMPLEMENTED(); |
| 216 return kIllegalIndex; |
| 217 } |
| 218 |
| 219 |
| 220 void VirtualFrame::TakeFrameSlotAt(int index) { |
| 221 UNIMPLEMENTED(); |
| 222 } |
| 223 |
| 224 |
| 225 void VirtualFrame::StoreToFrameSlotAt(int index) { |
| 226 UNIMPLEMENTED(); |
| 227 } |
| 228 |
| 229 |
| 230 void VirtualFrame::PushTryHandler(HandlerType type) { |
| 231 // Grow the expression stack by handler size less one (the return address |
| 232 // is already pushed by a call instruction). |
| 233 Adjust(kHandlerSize - 1); |
| 234 __ PushTryHandler(IN_JAVASCRIPT, type); |
| 235 } |
| 236 |
| 237 |
| 238 Result VirtualFrame::RawCallStub(CodeStub* stub) { |
| 239 ASSERT(cgen_->HasValidEntryRegisters()); |
| 240 __ CallStub(stub); |
| 241 Result result = cgen_->allocator()->Allocate(r0); |
| 242 ASSERT(result.is_valid()); |
| 243 return result; |
| 244 } |
| 245 |
| 246 |
| 247 Result VirtualFrame::CallStub(CodeStub* stub, Result* arg) { |
| 248 PrepareForCall(0, 0); |
| 249 arg->Unuse(); |
| 250 return RawCallStub(stub); |
| 251 } |
| 252 |
| 253 |
| 254 Result VirtualFrame::CallStub(CodeStub* stub, Result* arg0, Result* arg1) { |
| 255 PrepareForCall(0, 0); |
| 256 arg0->Unuse(); |
| 257 arg1->Unuse(); |
| 258 return RawCallStub(stub); |
| 259 } |
| 260 |
| 261 |
| 262 Result VirtualFrame::CallRuntime(Runtime::Function* f, int arg_count) { |
| 263 PrepareForCall(arg_count, arg_count); |
| 264 ASSERT(cgen_->HasValidEntryRegisters()); |
| 265 __ CallRuntime(f, arg_count); |
| 266 Result result = cgen_->allocator()->Allocate(r0); |
| 267 ASSERT(result.is_valid()); |
| 268 return result; |
| 269 } |
| 270 |
| 271 |
| 272 Result VirtualFrame::CallRuntime(Runtime::FunctionId id, int arg_count) { |
| 273 PrepareForCall(arg_count, arg_count); |
| 274 ASSERT(cgen_->HasValidEntryRegisters()); |
| 275 __ CallRuntime(id, arg_count); |
| 276 Result result = cgen_->allocator()->Allocate(r0); |
| 277 ASSERT(result.is_valid()); |
| 278 return result; |
| 279 } |
| 280 |
| 281 |
| 282 Result VirtualFrame::InvokeBuiltin(Builtins::JavaScript id, |
| 283 InvokeJSFlags flags, |
| 284 Result* arg_count_register, |
| 285 int arg_count) { |
| 286 ASSERT(arg_count_register->reg().is(r0)); |
| 287 PrepareForCall(arg_count, arg_count); |
| 288 arg_count_register->Unuse(); |
| 289 __ InvokeBuiltin(id, flags); |
| 290 Result result = cgen_->allocator()->Allocate(r0); |
| 291 return result; |
| 292 } |
| 293 |
| 294 |
| 295 Result VirtualFrame::RawCallCodeObject(Handle<Code> code, |
| 296 RelocInfo::Mode rmode) { |
| 297 ASSERT(cgen_->HasValidEntryRegisters()); |
| 298 __ Call(code, rmode); |
| 299 Result result = cgen_->allocator()->Allocate(r0); |
| 300 ASSERT(result.is_valid()); |
| 301 return result; |
| 302 } |
| 303 |
| 304 |
| 305 Result VirtualFrame::CallCodeObject(Handle<Code> code, |
| 306 RelocInfo::Mode rmode, |
| 307 int dropped_args) { |
| 308 int spilled_args = 0; |
| 309 switch (code->kind()) { |
| 310 case Code::CALL_IC: |
| 311 spilled_args = dropped_args + 1; |
| 312 break; |
| 313 case Code::FUNCTION: |
| 314 spilled_args = dropped_args + 1; |
| 315 break; |
| 316 case Code::KEYED_LOAD_IC: |
| 317 ASSERT(dropped_args == 0); |
| 318 spilled_args = 2; |
| 319 break; |
| 320 default: |
| 321 // The other types of code objects are called with values |
| 322 // in specific registers, and are handled in functions with |
| 323 // a different signature. |
| 324 UNREACHABLE(); |
| 325 break; |
| 326 } |
| 327 PrepareForCall(spilled_args, dropped_args); |
| 328 return RawCallCodeObject(code, rmode); |
| 329 } |
| 330 |
| 331 |
| 332 Result VirtualFrame::CallCodeObject(Handle<Code> code, |
| 333 RelocInfo::Mode rmode, |
| 334 Result* arg, |
| 335 int dropped_args) { |
| 336 int spilled_args = 0; |
| 337 switch (code->kind()) { |
| 338 case Code::LOAD_IC: |
| 339 ASSERT(arg->reg().is(r2)); |
| 340 ASSERT(dropped_args == 0); |
| 341 spilled_args = 1; |
| 342 break; |
| 343 case Code::KEYED_STORE_IC: |
| 344 ASSERT(arg->reg().is(r0)); |
| 345 ASSERT(dropped_args == 0); |
| 346 spilled_args = 2; |
| 347 break; |
| 348 default: |
| 349 // No other types of code objects are called with values |
| 350 // in exactly one register. |
| 351 UNREACHABLE(); |
| 352 break; |
| 353 } |
| 354 PrepareForCall(spilled_args, dropped_args); |
| 355 arg->Unuse(); |
| 356 return RawCallCodeObject(code, rmode); |
| 357 } |
| 358 |
| 359 |
| 360 Result VirtualFrame::CallCodeObject(Handle<Code> code, |
| 361 RelocInfo::Mode rmode, |
| 362 Result* arg0, |
| 363 Result* arg1, |
| 364 int dropped_args) { |
| 365 int spilled_args = 1; |
| 366 switch (code->kind()) { |
| 367 case Code::STORE_IC: |
| 368 ASSERT(arg0->reg().is(r0)); |
| 369 ASSERT(arg1->reg().is(r2)); |
| 370 ASSERT(dropped_args == 0); |
| 371 spilled_args = 1; |
| 372 break; |
| 373 case Code::BUILTIN: |
| 374 ASSERT(*code == Builtins::builtin(Builtins::JSConstructCall)); |
| 375 ASSERT(arg0->reg().is(r0)); |
| 376 ASSERT(arg1->reg().is(r1)); |
| 377 spilled_args = dropped_args + 1; |
| 378 break; |
| 379 default: |
| 380 // No other types of code objects are called with values |
| 381 // in exactly two registers. |
| 382 UNREACHABLE(); |
| 383 break; |
| 384 } |
| 385 PrepareForCall(spilled_args, dropped_args); |
| 386 arg0->Unuse(); |
| 387 arg1->Unuse(); |
| 388 return RawCallCodeObject(code, rmode); |
| 389 } |
| 390 |
| 391 |
| 392 void VirtualFrame::Drop(int count) { |
| 393 ASSERT(height() >= count); |
| 394 int num_virtual_elements = (elements_.length() - 1) - stack_pointer_; |
| 395 |
| 396 // Emit code to lower the stack pointer if necessary. |
| 397 if (num_virtual_elements < count) { |
| 398 int num_dropped = count - num_virtual_elements; |
| 399 stack_pointer_ -= num_dropped; |
| 400 __ add(sp, sp, Operand(num_dropped * kPointerSize)); |
| 401 } |
| 402 |
| 403 // Discard elements from the virtual frame and free any registers. |
| 404 for (int i = 0; i < count; i++) { |
| 405 FrameElement dropped = elements_.RemoveLast(); |
| 406 if (dropped.is_register()) { |
| 407 Unuse(dropped.reg()); |
| 408 } |
| 409 } |
| 410 } |
| 411 |
| 412 |
| 413 Result VirtualFrame::Pop() { |
| 414 UNIMPLEMENTED(); |
| 415 Result invalid(cgen_); |
| 416 return invalid; |
| 417 } |
| 418 |
| 419 |
| 420 void VirtualFrame::EmitPop(Register reg) { |
| 421 ASSERT(stack_pointer_ == elements_.length() - 1); |
| 422 stack_pointer_--; |
| 423 elements_.RemoveLast(); |
| 424 __ pop(reg); |
| 425 } |
| 426 |
| 427 |
| 428 void VirtualFrame::EmitPush(Register reg) { |
| 429 ASSERT(stack_pointer_ == elements_.length() - 1); |
| 430 elements_.Add(FrameElement::MemoryElement()); |
| 431 stack_pointer_++; |
| 432 __ push(reg); |
| 433 } |
| 434 |
| 435 |
| 436 #undef __ |
| 437 |
| 438 } } // namespace v8::internal |
OLD | NEW |