| OLD | NEW |
| 1 // Copyright 2008 the V8 project authors. All rights reserved. | 1 // Copyright 2008 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 23 matching lines...) Expand all Loading... |
| 34 namespace v8 { namespace internal { | 34 namespace v8 { namespace internal { |
| 35 | 35 |
| 36 #define __ masm_-> | 36 #define __ masm_-> |
| 37 | 37 |
| 38 // ------------------------------------------------------------------------- | 38 // ------------------------------------------------------------------------- |
| 39 // VirtualFrame implementation. | 39 // VirtualFrame implementation. |
| 40 | 40 |
| 41 // On entry to a function, the virtual frame already contains the receiver, | 41 // On entry to a function, the virtual frame already contains the receiver, |
| 42 // the parameters, and a return address. All frame elements are in memory. | 42 // the parameters, and a return address. All frame elements are in memory. |
| 43 VirtualFrame::VirtualFrame(CodeGenerator* cgen) | 43 VirtualFrame::VirtualFrame(CodeGenerator* cgen) |
| 44 : masm_(cgen->masm()), | 44 : cgen_(cgen), |
| 45 masm_(cgen->masm()), |
| 45 elements_(0), | 46 elements_(0), |
| 46 parameter_count_(cgen->scope()->num_parameters()), | 47 parameter_count_(cgen->scope()->num_parameters()), |
| 47 local_count_(0), | 48 local_count_(0), |
| 48 stack_pointer_(parameter_count_ + 1), // 0-based index of TOS. | 49 stack_pointer_(parameter_count_ + 1), // 0-based index of TOS. |
| 49 frame_pointer_(kIllegalIndex) { | 50 frame_pointer_(kIllegalIndex) { |
| 51 FrameElement memory_element; |
| 50 for (int i = 0; i < parameter_count_ + 2; i++) { | 52 for (int i = 0; i < parameter_count_ + 2; i++) { |
| 51 elements_.Add(FrameElement()); | 53 elements_.Add(memory_element); |
| 52 } | 54 } |
| 53 } | 55 } |
| 54 | 56 |
| 55 | 57 |
| 56 // When cloned, a frame is a deep copy of the original. | 58 // When cloned, a frame is a deep copy of the original. |
| 57 VirtualFrame::VirtualFrame(VirtualFrame* original) | 59 VirtualFrame::VirtualFrame(VirtualFrame* original) |
| 58 : masm_(original->masm_), | 60 : cgen_(original->cgen_), |
| 61 masm_(original->masm_), |
| 59 elements_(original->elements_.length()), | 62 elements_(original->elements_.length()), |
| 60 parameter_count_(original->parameter_count_), | 63 parameter_count_(original->parameter_count_), |
| 61 local_count_(original->local_count_), | 64 local_count_(original->local_count_), |
| 62 stack_pointer_(original->stack_pointer_), | 65 stack_pointer_(original->stack_pointer_), |
| 63 frame_pointer_(original->frame_pointer_) { | 66 frame_pointer_(original->frame_pointer_), |
| 67 frame_registers_(original->frame_registers_) { |
| 64 // Copy all the elements from the original. | 68 // Copy all the elements from the original. |
| 65 for (int i = 0; i < original->elements_.length(); i++) { | 69 for (int i = 0; i < original->elements_.length(); i++) { |
| 66 elements_.Add(original->elements_[i]); | 70 elements_.Add(original->elements_[i]); |
| 67 } | 71 } |
| 68 } | 72 } |
| 69 | 73 |
| 70 | 74 |
| 71 // Modify the state of the virtual frame to match the actual frame by adding | 75 // Modify the state of the virtual frame to match the actual frame by adding |
| 72 // extra in-memory elements to the top of the virtual frame. The extra | 76 // extra in-memory elements to the top of the virtual frame. The extra |
| 73 // elements will be externally materialized on the actual frame (eg, by | 77 // elements will be externally materialized on the actual frame (eg, by |
| (...skipping 13 matching lines...) Expand all Loading... |
| 87 // removing elements from the top of the virtual frame. The elements will | 91 // removing elements from the top of the virtual frame. The elements will |
| 88 // be externally popped from the actual frame (eg, by a runtime call). No | 92 // be externally popped from the actual frame (eg, by a runtime call). No |
| 89 // code is emitted. | 93 // code is emitted. |
| 90 void VirtualFrame::Forget(int count) { | 94 void VirtualFrame::Forget(int count) { |
| 91 ASSERT(count >= 0); | 95 ASSERT(count >= 0); |
| 92 ASSERT(stack_pointer_ == elements_.length() - 1); | 96 ASSERT(stack_pointer_ == elements_.length() - 1); |
| 93 ASSERT(elements_.length() >= count); | 97 ASSERT(elements_.length() >= count); |
| 94 | 98 |
| 95 stack_pointer_ -= count; | 99 stack_pointer_ -= count; |
| 96 for (int i = 0; i < count; i++) { | 100 for (int i = 0; i < count; i++) { |
| 97 elements_.RemoveLast(); | 101 FrameElement last = elements_.RemoveLast(); |
| 102 if (last.is_register()) { |
| 103 Unuse(last.reg()); |
| 104 } |
| 98 } | 105 } |
| 99 } | 106 } |
| 100 | 107 |
| 101 | 108 |
| 109 void VirtualFrame::Use(Register reg) { |
| 110 frame_registers_.Use(reg); |
| 111 cgen_->allocator()->Use(reg); |
| 112 } |
| 113 |
| 114 |
| 115 void VirtualFrame::Unuse(Register reg) { |
| 116 frame_registers_.Unuse(reg); |
| 117 cgen_->allocator()->Unuse(reg); |
| 118 } |
| 119 |
| 120 |
| 102 // Clear the dirty bit for the element at a given index. We can only | 121 // Clear the dirty bit for the element at a given index. We can only |
| 103 // allocate space in the actual frame for the virtual element immediately | 122 // allocate space in the actual frame for the virtual element immediately |
| 104 // above the stack pointer. | 123 // above the stack pointer. |
| 105 void VirtualFrame::SyncElementAt(int index) { | 124 void VirtualFrame::SyncElementAt(int index) { |
| 106 FrameElement element = elements_[index]; | 125 FrameElement element = elements_[index]; |
| 107 | 126 |
| 108 if (element.is_dirty()) { | 127 if (!element.is_synced()) { |
| 109 if (index <= stack_pointer_) { | 128 if (index <= stack_pointer_) { |
| 110 // Write elements below the stack pointer to their (already allocated) | 129 // Write elements below the stack pointer to their (already allocated) |
| 111 // actual frame location. | 130 // actual frame location. |
| 112 if (element.is_constant()) { | 131 if (element.is_constant()) { |
| 113 __ Set(Operand(ebp, fp_relative(index)), Immediate(element.handle())); | 132 __ Set(Operand(ebp, fp_relative(index)), Immediate(element.handle())); |
| 114 } else { | 133 } else { |
| 115 ASSERT(element.is_register()); | 134 ASSERT(element.is_register()); |
| 116 __ mov(Operand(ebp, fp_relative(index)), element.reg()); | 135 __ mov(Operand(ebp, fp_relative(index)), element.reg()); |
| 117 } | 136 } |
| 118 } else { | 137 } else { |
| 119 // Push elements above the stack pointer to allocate space and sync | 138 // Push elements above the stack pointer to allocate space and sync |
| 120 // them. Space should have already been allocated in the actual frame | 139 // them. Space should have already been allocated in the actual frame |
| 121 // for all the elements below this one. | 140 // for all the elements below this one. |
| 122 ASSERT(index == stack_pointer_ + 1); | 141 ASSERT(index == stack_pointer_ + 1); |
| 123 stack_pointer_++; | 142 stack_pointer_++; |
| 124 if (element.is_constant()) { | 143 if (element.is_constant()) { |
| 125 __ push(Immediate(element.handle())); | 144 __ push(Immediate(element.handle())); |
| 126 } else { | 145 } else { |
| 127 ASSERT(element.is_register()); | 146 ASSERT(element.is_register()); |
| 128 __ push(element.reg()); | 147 __ push(element.reg()); |
| 129 } | 148 } |
| 130 } | 149 } |
| 150 |
| 151 elements_[index].set_sync(); |
| 131 } | 152 } |
| 132 } | 153 } |
| 133 | 154 |
| 134 | 155 |
| 156 // Spill any register if possible, making its reference count zero. |
| 157 Register VirtualFrame::SpillAnyRegister() { |
| 158 // Find the leftmost (ordered by register code), least |
| 159 // internally-referenced register whose internal reference count matches |
| 160 // its external reference count (so that spilling it from the frame frees |
| 161 // it for use). |
| 162 int min_count = kMaxInt; |
| 163 int best_register_code = no_reg.code(); |
| 164 |
| 165 for (int i = 0; i < RegisterFile::kNumRegisters; i++) { |
| 166 int count = frame_registers_.count(i); |
| 167 if (count < min_count && count == cgen_->allocator()->count(i)) { |
| 168 min_count = count; |
| 169 best_register_code = i; |
| 170 } |
| 171 } |
| 172 |
| 173 if (best_register_code != no_reg.code()) { |
| 174 // Spill all occurrences of the register. There are min_count |
| 175 // occurrences, stop when we've spilled them all to avoid syncing |
| 176 // elements unnecessarily. |
| 177 int i = 0; |
| 178 while (min_count > 0) { |
| 179 ASSERT(i < elements_.length()); |
| 180 if (elements_[i].is_register() && |
| 181 elements_[i].reg().code() == best_register_code) { |
| 182 // Found an instance of the best_register being used in the frame. |
| 183 // Spill it. |
| 184 SpillElementAt(i); |
| 185 min_count--; |
| 186 } else { |
| 187 if (i > stack_pointer_) { |
| 188 // Make sure to materialize elements on the virtual frame in |
| 189 // memory. We rely on this to spill occurrences of the register |
| 190 // lying above the current virtual stack pointer. |
| 191 SyncElementAt(i); |
| 192 } |
| 193 } |
| 194 } |
| 195 } |
| 196 |
| 197 Register result = { best_register_code }; |
| 198 return result; |
| 199 } |
| 200 |
| 201 |
| 135 // Make the type of the element at a given index be MEMORY. We can only | 202 // Make the type of the element at a given index be MEMORY. We can only |
| 136 // allocate space in the actual frame for the virtual element immediately | 203 // allocate space in the actual frame for the virtual element immediately |
| 137 // above the stack pointer. | 204 // above the stack pointer. |
| 138 void VirtualFrame::SpillElementAt(int index) { | 205 void VirtualFrame::SpillElementAt(int index) { |
| 139 SyncElementAt(index); | 206 SyncElementAt(index); |
| 140 // The element is now in memory. | 207 // The element is now in memory. |
| 208 if (elements_[index].is_register()) { |
| 209 Unuse(elements_[index].reg()); |
| 210 } |
| 141 elements_[index] = FrameElement(); | 211 elements_[index] = FrameElement(); |
| 142 } | 212 } |
| 143 | 213 |
| 144 | 214 |
| 215 // Clear the dirty bits for all elements. |
| 216 void VirtualFrame::SyncAll() { |
| 217 for (int i = 0; i < elements_.length(); i++) { |
| 218 SyncElementAt(i); |
| 219 } |
| 220 } |
| 221 |
| 222 |
| 145 // Make the type of all elements be MEMORY. | 223 // Make the type of all elements be MEMORY. |
| 146 void VirtualFrame::SpillAll() { | 224 void VirtualFrame::SpillAll() { |
| 147 for (int i = 0; i < elements_.length(); i++) { | 225 for (int i = 0; i < elements_.length(); i++) { |
| 148 SpillElementAt(i); | 226 SpillElementAt(i); |
| 149 } | 227 } |
| 150 } | 228 } |
| 151 | 229 |
| 152 | 230 |
| 153 void VirtualFrame::PrepareForCall(int frame_arg_count) { | 231 void VirtualFrame::PrepareForCall(int frame_arg_count) { |
| 154 ASSERT(height() >= frame_arg_count); | 232 ASSERT(height() >= frame_arg_count); |
| (...skipping 24 matching lines...) Expand all Loading... |
| 179 // We cannot merge to a frame that has constants as elements, because an | 257 // We cannot merge to a frame that has constants as elements, because an |
| 180 // arbitrary frame might not have constants in those locations. | 258 // arbitrary frame might not have constants in those locations. |
| 181 // | 259 // |
| 182 // We cannot merge to a frame that has registers as elements because we | 260 // We cannot merge to a frame that has registers as elements because we |
| 183 // haven't implemented merging for such frames yet. | 261 // haven't implemented merging for such frames yet. |
| 184 SpillAll(); | 262 SpillAll(); |
| 185 } | 263 } |
| 186 | 264 |
| 187 | 265 |
| 188 void VirtualFrame::MergeTo(VirtualFrame* expected) { | 266 void VirtualFrame::MergeTo(VirtualFrame* expected) { |
| 267 ASSERT(cgen_ == expected->cgen_); |
| 189 ASSERT(masm_ == expected->masm_); | 268 ASSERT(masm_ == expected->masm_); |
| 190 ASSERT(elements_.length() == expected->elements_.length()); | 269 ASSERT(elements_.length() == expected->elements_.length()); |
| 191 ASSERT(parameter_count_ == expected->parameter_count_); | 270 ASSERT(parameter_count_ == expected->parameter_count_); |
| 192 ASSERT(local_count_ == expected->local_count_); | 271 ASSERT(local_count_ == expected->local_count_); |
| 193 ASSERT(frame_pointer_ == expected->frame_pointer_); | 272 ASSERT(frame_pointer_ == expected->frame_pointer_); |
| 194 | 273 |
| 195 // Mergable frames do not have constants and they do not (currently) have | 274 // Mergable frames do not have constants and they do not (currently) have |
| 196 // registers. They are always fully spilled, so the only thing needed to | 275 // registers. They are always fully spilled, so the only thing needed to |
| 197 // make this frame match the expected one is to spill everything. | 276 // make this frame match the expected one is to spill everything. |
| 198 // | 277 // |
| 199 // TODO(): Implement a non-stupid way of merging frames. | 278 // TODO(): Implement a non-stupid way of merging frames. |
| 200 SpillAll(); | 279 SpillAll(); |
| 201 | 280 |
| 202 ASSERT(stack_pointer_ == expected->stack_pointer_); | 281 ASSERT(stack_pointer_ == expected->stack_pointer_); |
| 203 } | 282 } |
| 204 | 283 |
| 205 | 284 |
| 206 void VirtualFrame::Enter() { | 285 void VirtualFrame::Enter() { |
| 286 // Registers live on entry: esp, ebp, esi, edi. |
| 207 Comment cmnt(masm_, "[ Enter JS frame"); | 287 Comment cmnt(masm_, "[ Enter JS frame"); |
| 208 EmitPush(ebp); | 288 EmitPush(ebp); |
| 209 | 289 |
| 210 frame_pointer_ = stack_pointer_; | 290 frame_pointer_ = stack_pointer_; |
| 211 __ mov(ebp, Operand(esp)); | 291 __ mov(ebp, Operand(esp)); |
| 212 | 292 |
| 213 // Store the context and the function in the frame. | 293 // Store the context and the function in the frame. |
| 214 FrameElement context(esi); | 294 Push(esi); |
| 215 context.clear_dirty(); | 295 // The frame owns the register reference now. |
| 216 elements_.Add(context); | 296 cgen_->allocator()->Unuse(esi); |
| 217 stack_pointer_++; | |
| 218 __ push(esi); | |
| 219 | 297 |
| 220 FrameElement function(edi); | 298 Push(edi); |
| 221 function.clear_dirty(); | 299 cgen_->allocator()->Unuse(edi); |
| 222 elements_.Add(function); | |
| 223 stack_pointer_++; | |
| 224 __ push(edi); | |
| 225 | |
| 226 // Clear the function slot when generating debug code. | |
| 227 if (FLAG_debug_code) { | |
| 228 SpillElementAt(stack_pointer_); | |
| 229 __ Set(edi, Immediate(reinterpret_cast<int>(kZapValue))); | |
| 230 } | |
| 231 } | 300 } |
| 232 | 301 |
| 233 | 302 |
| 234 void VirtualFrame::Exit() { | 303 void VirtualFrame::Exit() { |
| 235 Comment cmnt(masm_, "[ Exit JS frame"); | 304 Comment cmnt(masm_, "[ Exit JS frame"); |
| 236 // Record the location of the JS exit code for patching when setting | 305 // Record the location of the JS exit code for patching when setting |
| 237 // break point. | 306 // break point. |
| 238 __ RecordJSReturn(); | 307 __ RecordJSReturn(); |
| 239 | 308 |
| 240 // Avoid using the leave instruction here, because it is too | 309 // Avoid using the leave instruction here, because it is too |
| 241 // short. We need the return sequence to be a least the size of a | 310 // short. We need the return sequence to be a least the size of a |
| 242 // call instruction to support patching the exit code in the | 311 // call instruction to support patching the exit code in the |
| 243 // debugger. See VisitReturnStatement for the full return sequence. | 312 // debugger. See VisitReturnStatement for the full return sequence. |
| 244 __ mov(esp, Operand(ebp)); | 313 __ mov(esp, Operand(ebp)); |
| 245 stack_pointer_ = frame_pointer_; | 314 stack_pointer_ = frame_pointer_; |
| 246 for (int i = elements_.length() - 1; i > stack_pointer_; i--) { | 315 for (int i = elements_.length() - 1; i > stack_pointer_; i--) { |
| 247 elements_.RemoveLast(); | 316 FrameElement last = elements_.RemoveLast(); |
| 317 if (last.is_register()) { |
| 318 Unuse(last.reg()); |
| 319 } |
| 248 } | 320 } |
| 249 | 321 |
| 250 frame_pointer_ = kIllegalIndex; | 322 frame_pointer_ = kIllegalIndex; |
| 251 EmitPop(ebp); | 323 EmitPop(ebp); |
| 252 } | 324 } |
| 253 | 325 |
| 254 | 326 |
| 255 void VirtualFrame::AllocateStackSlots(int count) { | 327 void VirtualFrame::AllocateStackSlots(int count) { |
| 256 ASSERT(height() == 0); | 328 ASSERT(height() == 0); |
| 257 local_count_ = count; | 329 local_count_ = count; |
| 258 | 330 |
| 259 if (count > 0) { | 331 if (count > 0) { |
| 260 Comment cmnt(masm_, "[ Allocate space for locals"); | 332 Comment cmnt(masm_, "[ Allocate space for locals"); |
| 261 // The locals are constants (the undefined value), but we sync them with | 333 // The locals are constants (the undefined value), but we sync them with |
| 262 // the actual frame to allocate space for spilling them. | 334 // the actual frame to allocate space for spilling them. |
| 263 FrameElement initial_value(Factory::undefined_value()); | 335 SyncAll(); |
| 264 initial_value.clear_dirty(); | 336 Handle<Object> undefined = Factory::undefined_value(); |
| 265 __ Set(eax, Immediate(Factory::undefined_value())); | 337 FrameElement initial_value(undefined, FrameElement::SYNCED); |
| 338 Register tmp = cgen_->allocator()->Allocate(); |
| 339 __ Set(tmp, Immediate(undefined)); |
| 266 for (int i = 0; i < count; i++) { | 340 for (int i = 0; i < count; i++) { |
| 267 elements_.Add(initial_value); | 341 elements_.Add(initial_value); |
| 268 stack_pointer_++; | 342 stack_pointer_++; |
| 269 __ push(eax); | 343 __ push(tmp); |
| 270 } | 344 } |
| 345 cgen_->allocator()->Unuse(tmp); |
| 271 } | 346 } |
| 272 } | 347 } |
| 273 | 348 |
| 274 | 349 |
| 275 void VirtualFrame::PushTryHandler(HandlerType type) { | 350 void VirtualFrame::PushTryHandler(HandlerType type) { |
| 276 // Grow the expression stack by handler size less two (the return address | 351 // Grow the expression stack by handler size less two (the return address |
| 277 // is already pushed by a call instruction, and PushTryHandler from the | 352 // is already pushed by a call instruction, and PushTryHandler from the |
| 278 // macro assembler will leave the top of stack in the eax register to be | 353 // macro assembler will leave the top of stack in the eax register to be |
| 279 // pushed separately). | 354 // pushed separately). |
| 280 Adjust(kHandlerSize - 2); | 355 Adjust(kHandlerSize - 2); |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 316 PrepareForCall(frame_arg_count); | 391 PrepareForCall(frame_arg_count); |
| 317 __ call(code, rmode); | 392 __ call(code, rmode); |
| 318 } | 393 } |
| 319 | 394 |
| 320 | 395 |
| 321 void VirtualFrame::Drop(int count) { | 396 void VirtualFrame::Drop(int count) { |
| 322 ASSERT(height() >= count); | 397 ASSERT(height() >= count); |
| 323 | 398 |
| 324 // Discard elements above the stack pointer. | 399 // Discard elements above the stack pointer. |
| 325 while (count > 0 && stack_pointer_ < elements_.length() - 1) { | 400 while (count > 0 && stack_pointer_ < elements_.length() - 1) { |
| 326 elements_.RemoveLast(); | 401 FrameElement last = elements_.RemoveLast(); |
| 402 if (last.is_register()) { |
| 403 Unuse(last.reg()); |
| 404 } |
| 327 } | 405 } |
| 328 | 406 |
| 329 // Discard the rest of the elements and lower the stack pointer. | 407 // Discard the rest of the elements and lower the stack pointer. |
| 330 Forget(count); | 408 Forget(count); |
| 331 if (count > 0) { | 409 if (count > 0) { |
| 332 __ add(Operand(esp), Immediate(count * kPointerSize)); | 410 __ add(Operand(esp), Immediate(count * kPointerSize)); |
| 333 } | 411 } |
| 334 } | 412 } |
| 335 | 413 |
| 336 | 414 |
| (...skipping 27 matching lines...) Expand all Loading... |
| 364 void VirtualFrame::EmitPush(Operand operand) { | 442 void VirtualFrame::EmitPush(Operand operand) { |
| 365 ASSERT(stack_pointer_ == elements_.length() - 1); | 443 ASSERT(stack_pointer_ == elements_.length() - 1); |
| 366 elements_.Add(FrameElement()); | 444 elements_.Add(FrameElement()); |
| 367 stack_pointer_++; | 445 stack_pointer_++; |
| 368 __ push(operand); | 446 __ push(operand); |
| 369 } | 447 } |
| 370 | 448 |
| 371 | 449 |
| 372 void VirtualFrame::EmitPush(Immediate immediate) { | 450 void VirtualFrame::EmitPush(Immediate immediate) { |
| 373 ASSERT(stack_pointer_ == elements_.length() - 1); | 451 ASSERT(stack_pointer_ == elements_.length() - 1); |
| 374 elements_.Add(FrameElement()); | 452 FrameElement memory_element; |
| 453 elements_.Add(memory_element); |
| 375 stack_pointer_++; | 454 stack_pointer_++; |
| 376 __ push(immediate); | 455 __ push(immediate); |
| 377 } | 456 } |
| 378 | 457 |
| 379 | 458 |
| 459 void VirtualFrame::Push(Register reg) { |
| 460 FrameElement register_element(reg, FrameElement::NOT_SYNCED); |
| 461 Use(reg); |
| 462 elements_.Add(register_element); |
| 463 } |
| 464 |
| 465 |
| 466 void VirtualFrame::Push(Handle<Object> value) { |
| 467 FrameElement constant_element(value, FrameElement::NOT_SYNCED); |
| 468 elements_.Add(constant_element); |
| 469 } |
| 470 |
| 471 |
| 380 #undef __ | 472 #undef __ |
| 381 | 473 |
| 382 } } // namespace v8::internal | 474 } } // namespace v8::internal |
| OLD | NEW |