#include "debug.h"
#include "ic-inl.h"
#include "jsregexp.h"
+#include "jump-target-light-inl.h"
#include "parser.h"
#include "regexp-macro-assembler.h"
#include "regexp-stack.h"
#include "runtime.h"
#include "scopes.h"
#include "virtual-frame-inl.h"
+#include "virtual-frame-arm-inl.h"
namespace v8 {
namespace internal {
+
#define __ ACCESS_MASM(masm_)
static void EmitIdenticalObjectComparison(MacroAssembler* masm,
// Initialize the function return target after the locals are set
// up, because it needs the expected frame height from the frame.
- function_return_.set_direction(JumpTarget::BIDIRECTIONAL);
+ function_return_.SetExpectedHeight();
function_return_is_shadowed_ = false;
// Generate code to 'execute' declarations and initialize functions
VirtualFrame::SpilledScope spilled_scope(frame_);
Comment cmnt(masm_, "[ Block");
CodeForStatementPosition(node);
- node->break_target()->set_direction(JumpTarget::FORWARD_ONLY);
+ node->break_target()->SetExpectedHeight();
VisitStatementsAndSpill(node->statements());
if (node->break_target()->is_linked()) {
node->break_target()->Bind();
VirtualFrame::SpilledScope spilled_scope(frame_);
Comment cmnt(masm_, "[ SwitchStatement");
CodeForStatementPosition(node);
- node->break_target()->set_direction(JumpTarget::FORWARD_ONLY);
+ node->break_target()->SetExpectedHeight();
LoadAndSpill(node->tag());
VirtualFrame::SpilledScope spilled_scope(frame_);
Comment cmnt(masm_, "[ DoWhileStatement");
CodeForStatementPosition(node);
- node->break_target()->set_direction(JumpTarget::FORWARD_ONLY);
+ node->break_target()->SetExpectedHeight();
JumpTarget body(JumpTarget::BIDIRECTIONAL);
IncrementLoopNesting();
ConditionAnalysis info = AnalyzeCondition(node->cond());
switch (info) {
case ALWAYS_TRUE:
- node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL);
+ node->continue_target()->SetExpectedHeight();
node->continue_target()->Bind();
break;
case ALWAYS_FALSE:
- node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY);
+ node->continue_target()->SetExpectedHeight();
break;
case DONT_KNOW:
- node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY);
+ node->continue_target()->SetExpectedHeight();
body.Bind();
break;
}
ConditionAnalysis info = AnalyzeCondition(node->cond());
if (info == ALWAYS_FALSE) return;
- node->break_target()->set_direction(JumpTarget::FORWARD_ONLY);
+ node->break_target()->SetExpectedHeight();
IncrementLoopNesting();
// Label the top of the loop with the continue target for the backward
// CFG edge.
- node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL);
+ node->continue_target()->SetExpectedHeight();
node->continue_target()->Bind();
if (info == DONT_KNOW) {
ConditionAnalysis info = AnalyzeCondition(node->cond());
if (info == ALWAYS_FALSE) return;
- node->break_target()->set_direction(JumpTarget::FORWARD_ONLY);
+ node->break_target()->SetExpectedHeight();
IncrementLoopNesting();
// If there is no update statement, label the top of the loop with the
// continue target, otherwise with the loop target.
JumpTarget loop(JumpTarget::BIDIRECTIONAL);
if (node->next() == NULL) {
- node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL);
+ node->continue_target()->SetExpectedHeight();
node->continue_target()->Bind();
} else {
- node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY);
+ node->continue_target()->SetExpectedHeight();
loop.Bind();
}
// sp[4] : enumerable
// Grab the current frame's height for the break and continue
// targets only after all the state is pushed on the frame.
- node->break_target()->set_direction(JumpTarget::FORWARD_ONLY);
- node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY);
+ node->break_target()->SetExpectedHeight();
+ node->continue_target()->SetExpectedHeight();
// Load the current count to r0, load the length to r1.
__ ldrd(r0, frame_->ElementAt(0));
#define V8_ARM_CODEGEN_ARM_H_
#include "ic-inl.h"
+#include "ast.h"
namespace v8 {
namespace internal {
// Forward declarations
class CompilationInfo;
class DeferredCode;
+class JumpTarget;
class RegisterAllocator;
class RegisterFile;
// which are still live in the C++ code.
ASSERT(cgen()->HasValidEntryRegisters());
- if (is_bound()) {
- // Backward jump. There already a frame expectation at the target.
- ASSERT(direction_ == BIDIRECTIONAL);
- cgen()->frame()->MergeTo(entry_frame_);
+ if (entry_frame_set_) {
+ // There already a frame expectation at the target.
+ cgen()->frame()->MergeTo(&entry_frame_);
cgen()->DeleteFrame();
} else {
- // Use the current frame as the expected one at the target if necessary.
- if (entry_frame_ == NULL) {
- entry_frame_ = cgen()->frame();
- RegisterFile empty;
- cgen()->SetFrame(NULL, &empty);
- } else {
- cgen()->frame()->MergeTo(entry_frame_);
- cgen()->DeleteFrame();
- }
-
- // The predicate is_linked() should be made true. Its implementation
- // detects the presence of a frame pointer in the reaching_frames_ list.
- if (!is_linked()) {
- reaching_frames_.Add(NULL);
- ASSERT(is_linked());
- }
+ // Clone the current frame to use as the expected one at the target.
+ set_entry_frame(cgen()->frame());
+ RegisterFile empty;
+ cgen()->SetFrame(NULL, &empty);
}
__ jmp(&entry_label_);
}
void JumpTarget::DoBranch(Condition cc, Hint ignored) {
ASSERT(cgen()->has_valid_frame());
- if (is_bound()) {
- ASSERT(direction_ == BIDIRECTIONAL);
+ if (entry_frame_set_) {
// Backward branch. We have an expected frame to merge to on the
// backward edge.
- cgen()->frame()->MergeTo(entry_frame_);
- } else {
- // Clone the current frame to use as the expected one at the target if
- // necessary.
- if (entry_frame_ == NULL) {
- entry_frame_ = new VirtualFrame(cgen()->frame());
- }
- // The predicate is_linked() should be made true. Its implementation
- // detects the presence of a frame pointer in the reaching_frames_ list.
- if (!is_linked()) {
- reaching_frames_.Add(NULL);
- ASSERT(is_linked());
+ if (cc == al) {
+ cgen()->frame()->MergeTo(&entry_frame_);
+ } else {
+ // We can't do conditional merges yet so you have to ensure that all
+ // conditional branches to the JumpTarget have the same virtual frame.
+ ASSERT(cgen()->frame()->Equals(&entry_frame_));
}
+ } else {
+ // Clone the current frame to use as the expected one at the target.
+ set_entry_frame(cgen()->frame());
}
__ b(cc, &entry_label_);
}
// Calls are always 'forward' so we use a copy of the current frame (plus
// one for a return address) as the expected frame.
- ASSERT(entry_frame_ == NULL);
- VirtualFrame* target_frame = new VirtualFrame(cgen()->frame());
- target_frame->Adjust(1);
- entry_frame_ = target_frame;
-
- // The predicate is_linked() should now be made true. Its implementation
- // detects the presence of a frame pointer in the reaching_frames_ list.
- reaching_frames_.Add(NULL);
- ASSERT(is_linked());
+ ASSERT(!entry_frame_set_);
+ VirtualFrame target_frame = *cgen()->frame();
+ target_frame.Adjust(1);
+ set_entry_frame(&target_frame);
__ bl(&entry_label_);
}
if (cgen()->has_valid_frame()) {
// If there is a current frame we can use it on the fall through.
- if (entry_frame_ == NULL) {
- entry_frame_ = new VirtualFrame(cgen()->frame());
+ if (!entry_frame_set_) {
+ entry_frame_ = *cgen()->frame();
+ entry_frame_set_ = true;
} else {
- ASSERT(cgen()->frame()->Equals(entry_frame_));
+ cgen()->frame()->MergeTo(&entry_frame_);
}
} else {
// If there is no current frame we must have an entry frame which we can
// copy.
- ASSERT(entry_frame_ != NULL);
+ ASSERT(entry_frame_set_);
RegisterFile empty;
- cgen()->SetFrame(new VirtualFrame(entry_frame_), &empty);
- }
-
- // The predicate is_linked() should be made false. Its implementation
- // detects the presence (or absence) of frame pointers in the
- // reaching_frames_ list. If we inserted a bogus frame to make
- // is_linked() true, remove it now.
- if (is_linked()) {
- reaching_frames_.Clear();
+ cgen()->SetFrame(new VirtualFrame(&entry_frame_), &empty);
}
__ bind(&entry_label_);
}
-void BreakTarget::Jump() {
- // On ARM we do not currently emit merge code for jumps, so we need to do
- // it explicitly here. The only merging necessary is to drop extra
- // statement state from the stack.
- ASSERT(cgen()->has_valid_frame());
- int count = cgen()->frame()->height() - expected_height_;
- cgen()->frame()->Drop(count);
- DoJump();
-}
-
-
-void BreakTarget::Jump(Result* arg) {
- UNIMPLEMENTED();
-}
-
-
-void BreakTarget::Bind() {
-#ifdef DEBUG
- // All the forward-reaching frames should have been adjusted at the
- // jumps to this target.
- for (int i = 0; i < reaching_frames_.length(); i++) {
- ASSERT(reaching_frames_[i] == NULL ||
- reaching_frames_[i]->height() == expected_height_);
- }
-#endif
- // Drop leftover statement state from the frame before merging, even
- // on the fall through. This is so we can bind the return target
- // with state on the frame.
- if (cgen()->has_valid_frame()) {
- int count = cgen()->frame()->height() - expected_height_;
- // On ARM we do not currently emit merge code at binding sites, so we need
- // to do it explicitly here. The only merging necessary is to drop extra
- // statement state from the stack.
- cgen()->frame()->Drop(count);
- }
-
- DoBind();
-}
-
-
-void BreakTarget::Bind(Result* arg) {
- UNIMPLEMENTED();
-}
-
-
#undef __
--- /dev/null
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_VIRTUAL_FRAME_ARM_INL_H_
+#define V8_VIRTUAL_FRAME_ARM_INL_H_
+
+#include "assembler-arm.h"
+#include "virtual-frame-arm.h"
+
+namespace v8 {
+namespace internal {
+
+// These VirtualFrame methods should actually be in a virtual-frame-arm-inl.h
+// file if such a thing existed.
+MemOperand VirtualFrame::ParameterAt(int index) {
+ // Index -1 corresponds to the receiver.
+ ASSERT(-1 <= index); // -1 is the receiver.
+ ASSERT(index <= parameter_count());
+ return MemOperand(fp, (1 + parameter_count() - index) * kPointerSize);
+}
+
+ // The receiver frame slot.
+MemOperand VirtualFrame::Receiver() {
+ return ParameterAt(-1);
+}
+
+} } // namespace v8::internal
+
+#endif // V8_VIRTUAL_FRAME_ARM_INL_H_
void VirtualFrame::EmitPop(Register reg) {
- ASSERT(!is_used(reg));
+ ASSERT(!is_used(RegisterAllocator::ToNumber(reg)));
if (top_of_stack_state_ == NO_TOS_REGISTERS) {
__ pop(reg);
} else {
#define V8_ARM_VIRTUAL_FRAME_ARM_H_
#include "register-allocator.h"
-#include "scopes.h"
namespace v8 {
namespace internal {
+// This dummy class is only used to create invalid virtual frames.
+extern class InvalidVirtualFrameInitializer {}* kInvalidVirtualFrameInitializer;
+
+
// -------------------------------------------------------------------------
// Virtual frames
//
// is not spilled, ie. where register allocation occurs. Eventually
// when RegisterAllocationScope is ubiquitous it can be removed
// along with the (by then unused) SpilledScope class.
- explicit RegisterAllocationScope(CodeGenerator* cgen)
- : cgen_(cgen),
- old_is_spilled_(SpilledScope::is_spilled_) {
- SpilledScope::is_spilled_ = false;
- if (old_is_spilled_) {
- VirtualFrame* frame = cgen->frame();
- if (frame != NULL) {
- frame->AssertIsSpilled();
- }
- }
- }
- ~RegisterAllocationScope() {
- SpilledScope::is_spilled_ = old_is_spilled_;
- if (old_is_spilled_) {
- VirtualFrame* frame = cgen_->frame();
- if (frame != NULL) {
- frame->SpillAll();
- }
- }
- }
+ inline explicit RegisterAllocationScope(CodeGenerator* cgen);
+ inline ~RegisterAllocationScope();
private:
CodeGenerator* cgen_;
// Construct an initial virtual frame on entry to a JS function.
inline VirtualFrame();
+ // Construct an invalid virtual frame, used by JumpTargets.
+ inline VirtualFrame(InvalidVirtualFrameInitializer* dummy);
+
// Construct a virtual frame as a clone of an existing one.
explicit inline VirtualFrame(VirtualFrame* original);
- CodeGenerator* cgen() { return CodeGeneratorScope::Current(); }
- MacroAssembler* masm() { return cgen()->masm(); }
+ inline CodeGenerator* cgen();
+ inline MacroAssembler* masm();
// The number of elements on the virtual frame.
int element_count() { return element_count_; }
// The height of the virtual expression stack.
- int height() {
- return element_count() - expression_base_index();
- }
+ inline int height();
bool is_used(int num) {
switch (num) {
}
}
- bool is_used(Register reg) {
- return is_used(RegisterAllocator::ToNumber(reg));
- }
-
// Add extra in-memory elements to the top of the frame to match an actual
// frame (eg, the frame after an exception handler is pushed). No code is
// emitted.
}
// A frame-allocated local as an assembly operand.
- MemOperand LocalAt(int index) {
- ASSERT(0 <= index);
- ASSERT(index < local_count());
- return MemOperand(fp, kLocal0Offset - index * kPointerSize);
- }
+ inline MemOperand LocalAt(int index);
// Push the address of the receiver slot on the frame.
void PushReceiverSlotAddress();
MemOperand Context() { return MemOperand(fp, kContextOffset); }
// A parameter as an assembly operand.
- MemOperand ParameterAt(int index) {
- // Index -1 corresponds to the receiver.
- ASSERT(-1 <= index); // -1 is the receiver.
- ASSERT(index <= parameter_count());
- return MemOperand(fp, (1 + parameter_count() - index) * kPointerSize);
- }
+ inline MemOperand ParameterAt(int index);
// The receiver frame slot.
- MemOperand Receiver() { return ParameterAt(-1); }
+ inline MemOperand Receiver();
// Push a try-catch or try-finally handler on top of the virtual frame.
void PushTryHandler(HandlerType type);
// Call stub given the number of arguments it expects on (and
// removes from) the stack.
- void CallStub(CodeStub* stub, int arg_count) {
- if (arg_count != 0) Forget(arg_count);
- ASSERT(cgen()->HasValidEntryRegisters());
- masm()->CallStub(stub);
- }
+ inline void CallStub(CodeStub* stub, int arg_count);
// Call JS function from top of the stack with arguments
// taken from the stack.
int stack_pointer() { return element_count_ - 1; }
// The number of frame-allocated locals and parameters respectively.
- int parameter_count() { return cgen()->scope()->num_parameters(); }
- int local_count() { return cgen()->scope()->num_stack_slots(); }
+ inline int parameter_count();
+ inline int local_count();
// The index of the element that is at the processor's frame pointer
// (the fp register). The parameters, receiver, function, and context
// are below the frame pointer.
- int frame_pointer() { return parameter_count() + 3; }
+ inline int frame_pointer();
// The index of the first parameter. The receiver lies below the first
// parameter.
// The index of the context slot in the frame. It is immediately
// below the frame pointer.
- int context_index() { return frame_pointer() - 1; }
+ inline int context_index();
// The index of the function slot in the frame. It is below the frame
// pointer and context slot.
- int function_index() { return frame_pointer() - 2; }
+ inline int function_index();
// The index of the first local. Between the frame pointer and the
// locals lies the return address.
- int local0_index() { return frame_pointer() + 2; }
+ inline int local0_index();
// The index of the base of the expression stack.
- int expression_base_index() { return local0_index() + local_count(); }
+ inline int expression_base_index();
// Convert a frame index into a frame pointer relative offset into the
// actual stack.
- int fp_relative(int index) {
- ASSERT(index < element_count());
- ASSERT(frame_pointer() < element_count()); // FP is on the frame.
- return (frame_pointer() - index) * kPointerSize;
- }
+ inline int fp_relative(int index);
// Spill all elements in registers. Spill the top spilled_args elements
// on the frame. Sync all other frame elements.
inline bool Equals(VirtualFrame* other);
friend class JumpTarget;
- friend class DeferredCode;
};
--- /dev/null
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "ast.h"
+
+namespace v8 {
+namespace internal {
+
+BreakableStatement::BreakableStatement(ZoneStringList* labels, Type type)
+ : labels_(labels), type_(type) {
+ ASSERT(labels == NULL || labels->length() > 0);
+}
+
+
+SwitchStatement::SwitchStatement(ZoneStringList* labels)
+ : BreakableStatement(labels, TARGET_FOR_ANONYMOUS),
+ tag_(NULL), cases_(NULL) {
+}
+
+
+IterationStatement::IterationStatement(ZoneStringList* labels)
+ : BreakableStatement(labels, TARGET_FOR_ANONYMOUS), body_(NULL) {
+}
+
+
+Block::Block(ZoneStringList* labels, int capacity, bool is_initializer_block)
+ : BreakableStatement(labels, TARGET_FOR_NAMED_ONLY),
+ statements_(capacity),
+ is_initializer_block_(is_initializer_block) {
+}
+
+
+ForStatement::ForStatement(ZoneStringList* labels)
+ : IterationStatement(labels),
+ init_(NULL),
+ cond_(NULL),
+ next_(NULL),
+ may_have_function_literal_(true),
+ loop_variable_(NULL),
+ peel_this_loop_(false) {
+}
+
+
+ForInStatement::ForInStatement(ZoneStringList* labels)
+ : IterationStatement(labels), each_(NULL), enumerable_(NULL) {
+}
+
+
+DoWhileStatement::DoWhileStatement(ZoneStringList* labels)
+ : IterationStatement(labels), cond_(NULL), condition_position_(-1) {
+}
+
+} } // namespace v8::internal
#include "parser.h"
#include "scopes.h"
#include "string-stream.h"
+#include "ast-inl.h"
+#include "jump-target-inl.h"
namespace v8 {
namespace internal {
}
+WhileStatement::WhileStatement(ZoneStringList* labels)
+ : IterationStatement(labels),
+ cond_(NULL),
+ may_have_function_literal_(true) {
+}
+
+
ExpressionStatement::ExpressionStatement(ExpressionStatement* other,
Expression* expression)
: Statement(other), expression_(expression) {}
: BreakableStatement(other), body_(body) {}
+CaseClause::CaseClause(Expression* label, ZoneList<Statement*>* statements)
+ : label_(label), statements_(statements) {
+}
+
+
ForStatement::ForStatement(ForStatement* other,
Statement* init,
Expression* cond,
bool is_target_for_anonymous() const { return type_ == TARGET_FOR_ANONYMOUS; }
protected:
- BreakableStatement(ZoneStringList* labels, Type type)
- : labels_(labels), type_(type) {
- ASSERT(labels == NULL || labels->length() > 0);
- }
+ inline BreakableStatement(ZoneStringList* labels, Type type);
explicit BreakableStatement(BreakableStatement* other);
class Block: public BreakableStatement {
public:
- Block(ZoneStringList* labels, int capacity, bool is_initializer_block)
- : BreakableStatement(labels, TARGET_FOR_NAMED_ONLY),
- statements_(capacity),
- is_initializer_block_(is_initializer_block) { }
+ inline Block(ZoneStringList* labels, int capacity, bool is_initializer_block);
// Construct a clone initialized from the original block and
// a deep copy of all statements of the original block.
BreakTarget* continue_target() { return &continue_target_; }
protected:
- explicit IterationStatement(ZoneStringList* labels)
- : BreakableStatement(labels, TARGET_FOR_ANONYMOUS), body_(NULL) { }
+ explicit inline IterationStatement(ZoneStringList* labels);
// Construct a clone initialized from original and
// a deep copy of the original body.
class DoWhileStatement: public IterationStatement {
public:
- explicit DoWhileStatement(ZoneStringList* labels)
- : IterationStatement(labels), cond_(NULL), condition_position_(-1) {
- }
+ explicit inline DoWhileStatement(ZoneStringList* labels);
void Initialize(Expression* cond, Statement* body) {
IterationStatement::Initialize(body);
class WhileStatement: public IterationStatement {
public:
- explicit WhileStatement(ZoneStringList* labels)
- : IterationStatement(labels),
- cond_(NULL),
- may_have_function_literal_(true) {
- }
+ explicit WhileStatement(ZoneStringList* labels);
void Initialize(Expression* cond, Statement* body) {
IterationStatement::Initialize(body);
class ForStatement: public IterationStatement {
public:
- explicit ForStatement(ZoneStringList* labels)
- : IterationStatement(labels),
- init_(NULL),
- cond_(NULL),
- next_(NULL),
- may_have_function_literal_(true),
- loop_variable_(NULL),
- peel_this_loop_(false) {}
+ explicit inline ForStatement(ZoneStringList* labels);
// Construct a for-statement initialized from another for-statement
// and deep copies of all parts of the original statement.
class ForInStatement: public IterationStatement {
public:
- explicit ForInStatement(ZoneStringList* labels)
- : IterationStatement(labels), each_(NULL), enumerable_(NULL) { }
+ explicit inline ForInStatement(ZoneStringList* labels);
void Initialize(Expression* each, Expression* enumerable, Statement* body) {
IterationStatement::Initialize(body);
class CaseClause: public ZoneObject {
public:
- CaseClause(Expression* label, ZoneList<Statement*>* statements)
- : label_(label), statements_(statements) { }
+ CaseClause(Expression* label, ZoneList<Statement*>* statements);
bool is_default() const { return label_ == NULL; }
Expression* label() const {
class SwitchStatement: public BreakableStatement {
public:
- explicit SwitchStatement(ZoneStringList* labels)
- : BreakableStatement(labels, TARGET_FOR_ANONYMOUS),
- tag_(NULL), cases_(NULL) { }
+ explicit inline SwitchStatement(ZoneStringList* labels);
void Initialize(Expression* tag, ZoneList<CaseClause*>* cases) {
tag_ = tag;
#ifndef V8_CODEGEN_H_
#define V8_CODEGEN_H_
-#include "ast.h"
#include "code-stubs.h"
#include "runtime.h"
#include "type-info.h"
#ifndef V8_IA32_CODEGEN_IA32_H_
#define V8_IA32_CODEGEN_IA32_H_
+#include "ast.h"
#include "ic-inl.h"
+#include "jump-target-heavy.h"
namespace v8 {
namespace internal {
#ifndef V8_IA32_VIRTUAL_FRAME_IA32_H_
#define V8_IA32_VIRTUAL_FRAME_IA32_H_
-#include "type-info.h"
+#include "codegen.h"
#include "register-allocator.h"
#include "scopes.h"
+#include "type-info.h"
namespace v8 {
namespace internal {
return register_locations_[num];
}
- int register_location(Register reg) {
- return register_locations_[RegisterAllocator::ToNumber(reg)];
- }
+ inline int register_location(Register reg);
- void set_register_location(Register reg, int index) {
- register_locations_[RegisterAllocator::ToNumber(reg)] = index;
- }
+ inline void set_register_location(Register reg, int index);
bool is_used(int num) {
ASSERT(num >= 0 && num < RegisterAllocator::kNumRegisters);
return register_locations_[num] != kIllegalIndex;
}
- bool is_used(Register reg) {
- return register_locations_[RegisterAllocator::ToNumber(reg)]
- != kIllegalIndex;
- }
+ inline bool is_used(Register reg);
// Add extra in-memory elements to the top of the frame to match an actual
// frame (eg, the frame after an exception handler is pushed). No code is
void SetElementAt(int index, Result* value);
// Set a frame element to a constant. The index is frame-top relative.
- void SetElementAt(int index, Handle<Object> value) {
- Result temp(value);
- SetElementAt(index, &temp);
- }
+ inline void SetElementAt(int index, Handle<Object> value);
void PushElementAt(int index) {
PushFrameSlotAt(element_count() - index - 1);
// Call stub given the number of arguments it expects on (and
// removes from) the stack.
- Result CallStub(CodeStub* stub, int arg_count) {
- PrepareForCall(arg_count, arg_count);
- return RawCallStub(stub);
- }
+ inline Result CallStub(CodeStub* stub, int arg_count);
// Call stub that takes a single argument passed in eax. The
// argument is given as a result which does not have to be eax or
int register_locations_[RegisterAllocator::kNumRegisters];
// The number of frame-allocated locals and parameters respectively.
- int parameter_count() {
- return cgen()->scope()->num_parameters();
- }
- int local_count() {
- return cgen()->scope()->num_stack_slots();
- }
+ inline int parameter_count();
+
+ inline int local_count();
// The index of the element that is at the processor's frame pointer
// (the ebp register). The parameters, receiver, and return address
namespace internal {
+bool JumpTarget::compiling_deferred_code_ = false;
+
+
void JumpTarget::Jump(Result* arg) {
ASSERT(cgen()->has_valid_frame());
}
}
+
+void JumpTarget::Unuse() {
+ reaching_frames_.Clear();
+ merge_labels_.Clear();
+ entry_frame_ = NULL;
+ entry_label_.Unuse();
+}
+
+
+void JumpTarget::AddReachingFrame(VirtualFrame* frame) {
+ ASSERT(reaching_frames_.length() == merge_labels_.length());
+ ASSERT(entry_frame_ == NULL);
+ Label fresh;
+ merge_labels_.Add(fresh);
+ reaching_frames_.Add(frame);
+}
+
+
+// -------------------------------------------------------------------------
+// BreakTarget implementation.
+
+void BreakTarget::set_direction(Directionality direction) {
+ JumpTarget::set_direction(direction);
+ ASSERT(cgen()->has_valid_frame());
+ expected_height_ = cgen()->frame()->height();
+}
+
+
+void BreakTarget::CopyTo(BreakTarget* destination) {
+ ASSERT(destination != NULL);
+ destination->direction_ = direction_;
+ destination->reaching_frames_.Rewind(0);
+ destination->reaching_frames_.AddAll(reaching_frames_);
+ destination->merge_labels_.Rewind(0);
+ destination->merge_labels_.AddAll(merge_labels_);
+ destination->entry_frame_ = entry_frame_;
+ destination->entry_label_ = entry_label_;
+ destination->expected_height_ = expected_height_;
+}
+
+
+void BreakTarget::Branch(Condition cc, Hint hint) {
+ ASSERT(cgen()->has_valid_frame());
+
+ int count = cgen()->frame()->height() - expected_height_;
+ if (count > 0) {
+ // We negate and branch here rather than using DoBranch's negate
+ // and branch. This gives us a hook to remove statement state
+ // from the frame.
+ JumpTarget fall_through;
+ // Branch to fall through will not negate, because it is a
+ // forward-only target.
+ fall_through.Branch(NegateCondition(cc), NegateHint(hint));
+ Jump(); // May emit merge code here.
+ fall_through.Bind();
+ } else {
+ DoBranch(cc, hint);
+ }
+}
+
} } // namespace v8::internal
--- /dev/null
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_JUMP_TARGET_HEAVY_H_
+#define V8_JUMP_TARGET_HEAVY_H_
+
+#include "macro-assembler.h"
+#include "zone-inl.h"
+
+namespace v8 {
+namespace internal {
+
+// Forward declarations.
+class FrameElement;
+class Result;
+class VirtualFrame;
+
+// -------------------------------------------------------------------------
+// Jump targets
+//
+// A jump target is an abstraction of a basic-block entry in generated
+// code. It collects all the virtual frames reaching the block by
+// forward jumps and pairs them with labels for the merge code along
+// all forward-reaching paths. When bound, an expected frame for the
+// block is determined and code is generated to merge to the expected
+// frame. For backward jumps, the merge code is generated at the edge
+// leaving the predecessor block.
+//
+// A jump target must have been reached via control flow (either by
+// jumping, branching, or falling through) at the time it is bound.
+// In particular, this means that at least one of the control-flow
+// graph edges reaching the target must be a forward edge.
+
+class JumpTarget : public ZoneObject { // Shadows are dynamically allocated.
+ public:
+ // Forward-only jump targets can only be reached by forward CFG edges.
+ enum Directionality { FORWARD_ONLY, BIDIRECTIONAL };
+
+ // Construct a jump target used to generate code and to provide
+ // access to a current frame.
+ explicit JumpTarget(Directionality direction)
+ : direction_(direction),
+ reaching_frames_(0),
+ merge_labels_(0),
+ entry_frame_(NULL) {
+ }
+
+ // Construct a jump target.
+ JumpTarget()
+ : direction_(FORWARD_ONLY),
+ reaching_frames_(0),
+ merge_labels_(0),
+ entry_frame_(NULL) {
+ }
+
+ virtual ~JumpTarget() {}
+
+ // Set the direction of the jump target.
+ virtual void set_direction(Directionality direction) {
+ direction_ = direction;
+ }
+
+ // Treat the jump target as a fresh one. The state is reset.
+ void Unuse();
+
+ inline CodeGenerator* cgen();
+
+ Label* entry_label() { return &entry_label_; }
+
+ VirtualFrame* entry_frame() const { return entry_frame_; }
+ void set_entry_frame(VirtualFrame* frame) {
+ entry_frame_ = frame;
+ }
+
+ // Predicates testing the state of the encapsulated label.
+ bool is_bound() const { return entry_label_.is_bound(); }
+ bool is_linked() const {
+ return !is_bound() && !reaching_frames_.is_empty();
+ }
+ bool is_unused() const {
+ // This is !is_bound() && !is_linked().
+ return !is_bound() && reaching_frames_.is_empty();
+ }
+
+ // Emit a jump to the target. There must be a current frame at the
+ // jump and there will be no current frame after the jump.
+ virtual void Jump();
+ virtual void Jump(Result* arg);
+
+ // Emit a conditional branch to the target. There must be a current
+ // frame at the branch. The current frame will fall through to the
+ // code after the branch. The arg is a result that is live both at
+ // the target and the fall-through.
+ virtual void Branch(Condition cc, Hint hint = no_hint);
+ virtual void Branch(Condition cc, Result* arg, Hint hint = no_hint);
+ virtual void Branch(Condition cc,
+ Result* arg0,
+ Result* arg1,
+ Hint hint = no_hint);
+
+ // Bind a jump target. If there is no current frame at the binding
+ // site, there must be at least one frame reaching via a forward
+ // jump.
+ virtual void Bind();
+ virtual void Bind(Result* arg);
+ virtual void Bind(Result* arg0, Result* arg1);
+
+ // Emit a call to a jump target. There must be a current frame at
+ // the call. The frame at the target is the same as the current
+ // frame except for an extra return address on top of it. The frame
+ // after the call is the same as the frame before the call.
+ void Call();
+
+ static void set_compiling_deferred_code(bool flag) {
+ compiling_deferred_code_ = flag;
+ }
+
+ protected:
+ // Directionality flag set at initialization time.
+ Directionality direction_;
+
+ // A list of frames reaching this block via forward jumps.
+ ZoneList<VirtualFrame*> reaching_frames_;
+
+ // A parallel list of labels for merge code.
+ ZoneList<Label> merge_labels_;
+
+ // The frame used on entry to the block and expected at backward
+ // jumps to the block. Set when the jump target is bound, but may
+ // or may not be set for forward-only blocks.
+ VirtualFrame* entry_frame_;
+
+ // The actual entry label of the block.
+ Label entry_label_;
+
+ // Implementations of Jump, Branch, and Bind with all arguments and
+ // return values using the virtual frame.
+ void DoJump();
+ void DoBranch(Condition cc, Hint hint);
+ void DoBind();
+
+ private:
+ static bool compiling_deferred_code_;
+
+ // Add a virtual frame reaching this labeled block via a forward jump,
+ // and a corresponding merge code label.
+ void AddReachingFrame(VirtualFrame* frame);
+
+ // Perform initialization required during entry frame computation
+ // after setting the virtual frame element at index in frame to be
+ // target.
+ inline void InitializeEntryElement(int index, FrameElement* target);
+
+ // Compute a frame to use for entry to this block.
+ void ComputeEntryFrame();
+
+ DISALLOW_COPY_AND_ASSIGN(JumpTarget);
+};
+
+
+// -------------------------------------------------------------------------
+// Break targets
+//
+// A break target is a jump target that can be used to break out of a
+// statement that keeps extra state on the stack (eg, for/in or
+// try/finally). They know the expected stack height at the target
+// and will drop state from nested statements as part of merging.
+//
+// Break targets are used for return, break, and continue targets.
+
+class BreakTarget : public JumpTarget {
+ public:
+ // Construct a break target.
+ BreakTarget() {}
+
+ virtual ~BreakTarget() {}
+
+ // Set the direction of the break target.
+ virtual void set_direction(Directionality direction);
+
+ // Copy the state of this break target to the destination. The
+ // lists of forward-reaching frames and merge-point labels are
+ // copied. All virtual frame pointers are copied, not the
+ // pointed-to frames. The previous state of the destination is
+ // overwritten, without deallocating pointed-to virtual frames.
+ void CopyTo(BreakTarget* destination);
+
+ // Emit a jump to the target. There must be a current frame at the
+ // jump and there will be no current frame after the jump.
+ virtual void Jump();
+ virtual void Jump(Result* arg);
+
+ // Emit a conditional branch to the target. There must be a current
+ // frame at the branch. The current frame will fall through to the
+ // code after the branch.
+ virtual void Branch(Condition cc, Hint hint = no_hint);
+ virtual void Branch(Condition cc, Result* arg, Hint hint = no_hint);
+
+ // Bind a break target. If there is no current frame at the binding
+ // site, there must be at least one frame reaching via a forward
+ // jump.
+ virtual void Bind();
+ virtual void Bind(Result* arg);
+
+ // Setter for expected height.
+ void set_expected_height(int expected) { expected_height_ = expected; }
+
+ private:
+ // The expected height of the expression stack where the target will
+ // be bound, statically known at initialization time.
+ int expected_height_;
+
+ DISALLOW_COPY_AND_ASSIGN(BreakTarget);
+};
+
+} } // namespace v8::internal
+
+#endif // V8_JUMP_TARGET_HEAVY_H_
namespace v8 {
namespace internal {
-void JumpTarget::InitializeEntryElement(int index, FrameElement* target) {
- UNIMPLEMENTED();
+// Construct a jump target.
+JumpTarget::JumpTarget(Directionality direction)
+ : entry_frame_set_(false),
+ entry_frame_(kInvalidVirtualFrameInitializer) {
}
+JumpTarget::JumpTarget()
+ : entry_frame_set_(false),
+ entry_frame_(kInvalidVirtualFrameInitializer) {
+}
+
+
+BreakTarget::BreakTarget() { }
+
} } // namespace v8::internal
#endif // V8_JUMP_TARGET_LIGHT_INL_H_
namespace internal {
-void JumpTarget::Jump(Result* arg) {
- UNIMPLEMENTED();
-}
+DeferredCode::DeferredCode()
+ : masm_(CodeGeneratorScope::Current()->masm()),
+ statement_position_(masm_->current_statement_position()),
+ position_(masm_->current_position()) {
+ ASSERT(statement_position_ != RelocInfo::kNoPosition);
+ ASSERT(position_ != RelocInfo::kNoPosition);
+ CodeGeneratorScope::Current()->AddDeferred(this);
-void JumpTarget::Branch(Condition cc, Result* arg, Hint hint) {
- UNIMPLEMENTED();
+#ifdef DEBUG
+ CodeGeneratorScope::Current()->frame()->AssertIsSpilled();
+#endif
}
-void JumpTarget::Branch(Condition cc, Result* arg0, Result* arg1, Hint hint) {
- UNIMPLEMENTED();
-}
+// -------------------------------------------------------------------------
+// BreakTarget implementation.
-void BreakTarget::Branch(Condition cc, Result* arg, Hint hint) {
- UNIMPLEMENTED();
+void BreakTarget::SetExpectedHeight() {
+ expected_height_ = cgen()->frame()->height();
}
-void JumpTarget::Bind(Result* arg) {
- UNIMPLEMENTED();
-}
-
+void BreakTarget::Jump() {
+ ASSERT(cgen()->has_valid_frame());
-void JumpTarget::Bind(Result* arg0, Result* arg1) {
- UNIMPLEMENTED();
+ int count = cgen()->frame()->height() - expected_height_;
+ if (count > 0) {
+ cgen()->frame()->Drop(count);
+ }
+ DoJump();
}
-void JumpTarget::ComputeEntryFrame() {
- UNIMPLEMENTED();
+void BreakTarget::Branch(Condition cc, Hint hint) {
+ if (cc == al) {
+ Jump();
+ return;
+ }
+
+ ASSERT(cgen()->has_valid_frame());
+
+ int count = cgen()->frame()->height() - expected_height_;
+ if (count > 0) {
+ // We negate and branch here rather than using DoBranch's negate
+ // and branch. This gives us a hook to remove statement state
+ // from the frame.
+ JumpTarget fall_through;
+ // Branch to fall through will not negate, because it is a
+ // forward-only target.
+ fall_through.Branch(NegateCondition(cc), NegateHint(hint));
+ // Emit merge code.
+ cgen()->frame()->Drop(count);
+ DoJump();
+ fall_through.Bind();
+ } else {
+ DoBranch(cc, hint);
+ }
}
-DeferredCode::DeferredCode()
- : masm_(CodeGeneratorScope::Current()->masm()),
- statement_position_(masm_->current_statement_position()),
- position_(masm_->current_position()) {
- ASSERT(statement_position_ != RelocInfo::kNoPosition);
- ASSERT(position_ != RelocInfo::kNoPosition);
-
- CodeGeneratorScope::Current()->AddDeferred(this);
-
-#ifdef DEBUG
- CodeGeneratorScope::Current()->frame()->AssertIsSpilled();
-#endif
+void BreakTarget::Bind() {
+ if (cgen()->has_valid_frame()) {
+ int count = cgen()->frame()->height() - expected_height_;
+ if (count > 0) {
+ cgen()->frame()->Drop(count);
+ }
+ }
+ DoBind();
}
} } // namespace v8::internal
--- /dev/null
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_JUMP_TARGET_LIGHT_H_
+#define V8_JUMP_TARGET_LIGHT_H_
+
+#include "macro-assembler.h"
+#include "zone-inl.h"
+#include "virtual-frame.h"
+
+namespace v8 {
+namespace internal {
+
+// Forward declarations.
+class FrameElement;
+class Result;
+
+// -------------------------------------------------------------------------
+// Jump targets
+//
+// A jump target is an abstraction of a basic-block entry in generated
+// code. It collects all the virtual frames reaching the block by
+// forward jumps and pairs them with labels for the merge code along
+// all forward-reaching paths. When bound, an expected frame for the
+// block is determined and code is generated to merge to the expected
+// frame. For backward jumps, the merge code is generated at the edge
+// leaving the predecessor block.
+//
+// A jump target must have been reached via control flow (either by
+// jumping, branching, or falling through) at the time it is bound.
+// In particular, this means that at least one of the control-flow
+// graph edges reaching the target must be a forward edge.
+
+class JumpTarget : public ZoneObject { // Shadows are dynamically allocated.
+ public:
+ // Forward-only jump targets can only be reached by forward CFG edges.
+ enum Directionality { FORWARD_ONLY, BIDIRECTIONAL };
+
+ // Construct a jump target.
+ explicit inline JumpTarget(Directionality direction);
+
+ inline JumpTarget();
+
+ virtual ~JumpTarget() {}
+
+ void Unuse() {
+ entry_frame_set_ = false;
+ entry_label_.Unuse();
+ }
+
+ inline CodeGenerator* cgen();
+
+ const VirtualFrame* entry_frame() const {
+ return entry_frame_set_ ? &entry_frame_ : NULL;
+ }
+
+ void set_entry_frame(VirtualFrame* frame) {
+ entry_frame_ = *frame;
+ entry_frame_set_ = true;
+ }
+
+ // Predicates testing the state of the encapsulated label.
+ bool is_bound() const { return entry_label_.is_bound(); }
+ bool is_linked() const { return entry_label_.is_linked(); }
+ bool is_unused() const { return entry_label_.is_unused(); }
+
+ // Copy the state of this jump target to the destination.
+ inline void CopyTo(JumpTarget* destination) {
+ *destination = *this;
+ }
+
+ // Emit a jump to the target. There must be a current frame at the
+ // jump and there will be no current frame after the jump.
+ virtual void Jump();
+
+ // Emit a conditional branch to the target. There must be a current
+ // frame at the branch. The current frame will fall through to the
+ // code after the branch. The arg is a result that is live both at
+ // the target and the fall-through.
+ virtual void Branch(Condition cc, Hint hint = no_hint);
+
+ // Bind a jump target. If there is no current frame at the binding
+ // site, there must be at least one frame reaching via a forward
+ // jump.
+ virtual void Bind();
+
+ // Emit a call to a jump target. There must be a current frame at
+ // the call. The frame at the target is the same as the current
+ // frame except for an extra return address on top of it. The frame
+ // after the call is the same as the frame before the call.
+ void Call();
+
+ protected:
+ // Has an entry frame been found?
+ bool entry_frame_set_;
+
+ // The frame used on entry to the block and expected at backward
+ // jumps to the block. Set the first time something branches to this
+ // jump target.
+ VirtualFrame entry_frame_;
+
+ // The actual entry label of the block.
+ Label entry_label_;
+
+ // Implementations of Jump, Branch, and Bind with all arguments and
+ // return values using the virtual frame.
+ void DoJump();
+ void DoBranch(Condition cc, Hint hint);
+ void DoBind();
+};
+
+
+// -------------------------------------------------------------------------
+// Break targets
+//
+// A break target is a jump target that can be used to break out of a
+// statement that keeps extra state on the stack (eg, for/in or
+// try/finally). They know the expected stack height at the target
+// and will drop state from nested statements as part of merging.
+//
+// Break targets are used for return, break, and continue targets.
+
+class BreakTarget : public JumpTarget {
+ public:
+ // Construct a break target.
+ inline BreakTarget();
+
+ virtual ~BreakTarget() {}
+
+ // Copy the state of this jump target to the destination.
+ inline void CopyTo(BreakTarget* destination) {
+ *destination = *this;
+ }
+
+ // Emit a jump to the target. There must be a current frame at the
+ // jump and there will be no current frame after the jump.
+ virtual void Jump();
+
+ // Emit a conditional branch to the target. There must be a current
+ // frame at the branch. The current frame will fall through to the
+ // code after the branch.
+ virtual void Branch(Condition cc, Hint hint = no_hint);
+
+ // Bind a break target. If there is no current frame at the binding
+ // site, there must be at least one frame reaching via a forward
+ // jump.
+ virtual void Bind();
+
+ // Setter for expected height.
+ void set_expected_height(int expected) { expected_height_ = expected; }
+
+ // Uses the current frame to set the expected height.
+ void SetExpectedHeight();
+
+ private:
+ // The expected height of the expression stack where the target will
+ // be bound, statically known at initialization time.
+ int expected_height_;
+};
+
+} } // namespace v8::internal
+
+#endif // V8_JUMP_TARGET_LIGHT_H_
// -------------------------------------------------------------------------
// JumpTarget implementation.
-bool JumpTarget::compiling_deferred_code_ = false;
-
-
-void JumpTarget::Unuse() {
- reaching_frames_.Clear();
- merge_labels_.Clear();
- entry_frame_ = NULL;
- entry_label_.Unuse();
-}
-
-
void JumpTarget::Jump() {
DoJump();
}
}
-void JumpTarget::AddReachingFrame(VirtualFrame* frame) {
- ASSERT(reaching_frames_.length() == merge_labels_.length());
- ASSERT(entry_frame_ == NULL);
- Label fresh;
- merge_labels_.Add(fresh);
- reaching_frames_.Add(frame);
-}
-
-
-// -------------------------------------------------------------------------
-// BreakTarget implementation.
-
-void BreakTarget::set_direction(Directionality direction) {
- JumpTarget::set_direction(direction);
- ASSERT(cgen()->has_valid_frame());
- expected_height_ = cgen()->frame()->height();
-}
-
-
-void BreakTarget::CopyTo(BreakTarget* destination) {
- ASSERT(destination != NULL);
- destination->direction_ = direction_;
- destination->reaching_frames_.Rewind(0);
- destination->reaching_frames_.AddAll(reaching_frames_);
- destination->merge_labels_.Rewind(0);
- destination->merge_labels_.AddAll(merge_labels_);
- destination->entry_frame_ = entry_frame_;
- destination->entry_label_ = entry_label_;
- destination->expected_height_ = expected_height_;
-}
-
-
-void BreakTarget::Branch(Condition cc, Hint hint) {
- ASSERT(cgen()->has_valid_frame());
-
- int count = cgen()->frame()->height() - expected_height_;
- if (count > 0) {
- // We negate and branch here rather than using DoBranch's negate
- // and branch. This gives us a hook to remove statement state
- // from the frame.
- JumpTarget fall_through;
- // Branch to fall through will not negate, because it is a
- // forward-only target.
- fall_through.Branch(NegateCondition(cc), NegateHint(hint));
- Jump(); // May emit merge code here.
- fall_through.Bind();
- } else {
- DoBranch(cc, hint);
- }
-}
-
-
// -------------------------------------------------------------------------
// ShadowTarget implementation.
#endif
}
-
} } // namespace v8::internal
#ifndef V8_JUMP_TARGET_H_
#define V8_JUMP_TARGET_H_
-#include "macro-assembler.h"
-#include "zone-inl.h"
+#if V8_TARGET_ARCH_IA32
+#include "jump-target-heavy.h"
+#elif V8_TARGET_ARCH_X64
+#include "jump-target-heavy.h"
+#elif V8_TARGET_ARCH_ARM
+#include "jump-target-light.h"
+#elif V8_TARGET_ARCH_MIPS
+#include "jump-target-light.h"
+#else
+#error Unsupported target architecture.
+#endif
namespace v8 {
namespace internal {
-// Forward declarations.
-class FrameElement;
-class Result;
-class VirtualFrame;
-
-// -------------------------------------------------------------------------
-// Jump targets
-//
-// A jump target is an abstraction of a basic-block entry in generated
-// code. It collects all the virtual frames reaching the block by
-// forward jumps and pairs them with labels for the merge code along
-// all forward-reaching paths. When bound, an expected frame for the
-// block is determined and code is generated to merge to the expected
-// frame. For backward jumps, the merge code is generated at the edge
-// leaving the predecessor block.
-//
-// A jump target must have been reached via control flow (either by
-// jumping, branching, or falling through) at the time it is bound.
-// In particular, this means that at least one of the control-flow
-// graph edges reaching the target must be a forward edge.
-
-class JumpTarget : public ZoneObject { // Shadows are dynamically allocated.
- public:
- // Forward-only jump targets can only be reached by forward CFG edges.
- enum Directionality { FORWARD_ONLY, BIDIRECTIONAL };
-
- // Construct a jump target used to generate code and to provide
- // access to a current frame.
- explicit JumpTarget(Directionality direction)
- : direction_(direction),
- reaching_frames_(0),
- merge_labels_(0),
- entry_frame_(NULL) {
- }
-
- // Construct a jump target.
- JumpTarget()
- : direction_(FORWARD_ONLY),
- reaching_frames_(0),
- merge_labels_(0),
- entry_frame_(NULL) {
- }
-
- virtual ~JumpTarget() {}
-
- // Set the direction of the jump target.
- virtual void set_direction(Directionality direction) {
- direction_ = direction;
- }
-
- // Treat the jump target as a fresh one. The state is reset.
- void Unuse();
-
- inline CodeGenerator* cgen();
-
- Label* entry_label() { return &entry_label_; }
-
- VirtualFrame* entry_frame() const { return entry_frame_; }
- void set_entry_frame(VirtualFrame* frame) {
- entry_frame_ = frame;
- }
-
- // Predicates testing the state of the encapsulated label.
- bool is_bound() const { return entry_label_.is_bound(); }
- bool is_linked() const {
- return !is_bound() && !reaching_frames_.is_empty();
- }
- bool is_unused() const {
- // This is !is_bound() && !is_linked().
- return !is_bound() && reaching_frames_.is_empty();
- }
-
- // Emit a jump to the target. There must be a current frame at the
- // jump and there will be no current frame after the jump.
- virtual void Jump();
- virtual void Jump(Result* arg);
-
- // Emit a conditional branch to the target. There must be a current
- // frame at the branch. The current frame will fall through to the
- // code after the branch. The arg is a result that is live both at
- // the target and the fall-through.
- virtual void Branch(Condition cc, Hint hint = no_hint);
- virtual void Branch(Condition cc, Result* arg, Hint hint = no_hint);
- virtual void Branch(Condition cc,
- Result* arg0,
- Result* arg1,
- Hint hint = no_hint);
-
- // Bind a jump target. If there is no current frame at the binding
- // site, there must be at least one frame reaching via a forward
- // jump.
- virtual void Bind();
- virtual void Bind(Result* arg);
- virtual void Bind(Result* arg0, Result* arg1);
-
- // Emit a call to a jump target. There must be a current frame at
- // the call. The frame at the target is the same as the current
- // frame except for an extra return address on top of it. The frame
- // after the call is the same as the frame before the call.
- void Call();
-
- static void set_compiling_deferred_code(bool flag) {
- compiling_deferred_code_ = flag;
- }
-
- protected:
- // Directionality flag set at initialization time.
- Directionality direction_;
-
- // A list of frames reaching this block via forward jumps.
- ZoneList<VirtualFrame*> reaching_frames_;
-
- // A parallel list of labels for merge code.
- ZoneList<Label> merge_labels_;
-
- // The frame used on entry to the block and expected at backward
- // jumps to the block. Set when the jump target is bound, but may
- // or may not be set for forward-only blocks.
- VirtualFrame* entry_frame_;
-
- // The actual entry label of the block.
- Label entry_label_;
-
- // Implementations of Jump, Branch, and Bind with all arguments and
- // return values using the virtual frame.
- void DoJump();
- void DoBranch(Condition cc, Hint hint);
- void DoBind();
-
- private:
- static bool compiling_deferred_code_;
-
- // Add a virtual frame reaching this labeled block via a forward jump,
- // and a corresponding merge code label.
- void AddReachingFrame(VirtualFrame* frame);
-
- // Perform initialization required during entry frame computation
- // after setting the virtual frame element at index in frame to be
- // target.
- inline void InitializeEntryElement(int index, FrameElement* target);
-
- // Compute a frame to use for entry to this block.
- void ComputeEntryFrame();
-
- DISALLOW_COPY_AND_ASSIGN(JumpTarget);
-};
-
-
-// -------------------------------------------------------------------------
-// Break targets
-//
-// A break target is a jump target that can be used to break out of a
-// statement that keeps extra state on the stack (eg, for/in or
-// try/finally). They know the expected stack height at the target
-// and will drop state from nested statements as part of merging.
-//
-// Break targets are used for return, break, and continue targets.
-
-class BreakTarget : public JumpTarget {
- public:
- // Construct a break target.
- BreakTarget() {}
-
- virtual ~BreakTarget() {}
-
- // Set the direction of the break target.
- virtual void set_direction(Directionality direction);
-
- // Copy the state of this break target to the destination. The
- // lists of forward-reaching frames and merge-point labels are
- // copied. All virtual frame pointers are copied, not the
- // pointed-to frames. The previous state of the destination is
- // overwritten, without deallocating pointed-to virtual frames.
- void CopyTo(BreakTarget* destination);
-
- // Emit a jump to the target. There must be a current frame at the
- // jump and there will be no current frame after the jump.
- virtual void Jump();
- virtual void Jump(Result* arg);
-
- // Emit a conditional branch to the target. There must be a current
- // frame at the branch. The current frame will fall through to the
- // code after the branch.
- virtual void Branch(Condition cc, Hint hint = no_hint);
- virtual void Branch(Condition cc, Result* arg, Hint hint = no_hint);
-
- // Bind a break target. If there is no current frame at the binding
- // site, there must be at least one frame reaching via a forward
- // jump.
- virtual void Bind();
- virtual void Bind(Result* arg);
-
- // Setter for expected height.
- void set_expected_height(int expected) { expected_height_ = expected; }
-
- private:
- // The expected height of the expression stack where the target will
- // be bound, statically known at initialization time.
- int expected_height_;
-
- DISALLOW_COPY_AND_ASSIGN(BreakTarget);
-};
-
-
// -------------------------------------------------------------------------
// Shadow break targets
//
DISALLOW_COPY_AND_ASSIGN(ShadowTarget);
};
-
} } // namespace v8::internal
#endif // V8_JUMP_TARGET_H_
#include "codegen.h"
#include "compiler.h"
#include "messages.h"
+#include "parser.h"
#include "platform.h"
#include "runtime.h"
-#include "parser.h"
#include "scopes.h"
#include "string-stream.h"
+#include "ast-inl.h"
+#include "jump-target-inl.h"
+
namespace v8 {
namespace internal {
Result RegisterAllocator::Allocate(Register target) {
// If the target is not referenced, it can simply be allocated.
- if (!is_used(target)) {
+ if (!is_used(RegisterAllocator::ToNumber(target))) {
return Result(target);
}
// If the target is only referenced in the frame, it can be spilled and
// then allocated.
ASSERT(cgen_->has_valid_frame());
- if (cgen_->frame()->is_used(target) && count(target) == 1) {
+ if (cgen_->frame()->is_used(RegisterAllocator::ToNumber(target)) &&
+ count(target) == 1) {
cgen_->frame()->Spill(target);
- ASSERT(!is_used(target));
+ ASSERT(!is_used(RegisterAllocator::ToNumber(target)));
return Result(target);
}
// Otherwise (if it's referenced outside the frame) we cannot allocate it.
#include "type-info.h"
#include "register-allocator.h"
#include "scopes.h"
+#include "register-allocator-inl.h"
+#include "codegen-inl.h"
namespace v8 {
namespace internal {
Push(Handle<Object> (value));
}
+
+int VirtualFrame::register_location(Register reg) {
+ return register_locations_[RegisterAllocator::ToNumber(reg)];
+}
+
+
+void VirtualFrame::set_register_location(Register reg, int index) {
+ register_locations_[RegisterAllocator::ToNumber(reg)] = index;
+}
+
+
+bool VirtualFrame::is_used(Register reg) {
+ return register_locations_[RegisterAllocator::ToNumber(reg)]
+ != kIllegalIndex;
+}
+
+
+void VirtualFrame::SetElementAt(int index, Handle<Object> value) {
+ Result temp(value);
+ SetElementAt(index, &temp);
+}
+
+
+Result VirtualFrame::CallStub(CodeStub* stub, int arg_count) {
+ PrepareForCall(arg_count, arg_count);
+ return RawCallStub(stub);
+}
+
+
+int VirtualFrame::parameter_count() {
+ return cgen()->scope()->num_parameters();
+}
+
+
+int VirtualFrame::local_count() {
+ return cgen()->scope()->num_stack_slots();
+}
+
} } // namespace v8::internal
#endif // V8_VIRTUAL_FRAME_HEAVY_INL_H_
#ifndef V8_VIRTUAL_FRAME_LIGHT_INL_H_
#define V8_VIRTUAL_FRAME_LIGHT_INL_H_
-#include "type-info.h"
+#include "codegen.h"
#include "register-allocator.h"
#include "scopes.h"
+#include "type-info.h"
+
+#include "codegen-inl.h"
+#include "jump-target-light-inl.h"
namespace v8 {
namespace internal {
+VirtualFrame::VirtualFrame(InvalidVirtualFrameInitializer* dummy)
+ : element_count_(0),
+ top_of_stack_state_(NO_TOS_REGISTERS),
+ register_allocation_map_(0) { }
+
+
// On entry to a function, the virtual frame already contains the receiver,
// the parameters, and a return address. All frame elements are in memory.
VirtualFrame::VirtualFrame()
}
+VirtualFrame::RegisterAllocationScope::RegisterAllocationScope(
+ CodeGenerator* cgen)
+ : cgen_(cgen),
+ old_is_spilled_(SpilledScope::is_spilled_) {
+ SpilledScope::is_spilled_ = false;
+ if (old_is_spilled_) {
+ VirtualFrame* frame = cgen->frame();
+ if (frame != NULL) {
+ frame->AssertIsSpilled();
+ }
+ }
+}
+
+
+VirtualFrame::RegisterAllocationScope::~RegisterAllocationScope() {
+ SpilledScope::is_spilled_ = old_is_spilled_;
+ if (old_is_spilled_) {
+ VirtualFrame* frame = cgen_->frame();
+ if (frame != NULL) {
+ frame->SpillAll();
+ }
+ }
+}
+
+
+CodeGenerator* VirtualFrame::cgen() { return CodeGeneratorScope::Current(); }
+
+
+MacroAssembler* VirtualFrame::masm() { return cgen()->masm(); }
+
+
+void VirtualFrame::CallStub(CodeStub* stub, int arg_count) {
+ if (arg_count != 0) Forget(arg_count);
+ ASSERT(cgen()->HasValidEntryRegisters());
+ masm()->CallStub(stub);
+}
+
+
+int VirtualFrame::parameter_count() {
+ return cgen()->scope()->num_parameters();
+}
+
+
+int VirtualFrame::local_count() { return cgen()->scope()->num_stack_slots(); }
+
+
+int VirtualFrame::frame_pointer() { return parameter_count() + 3; }
+
+
+int VirtualFrame::context_index() { return frame_pointer() - 1; }
+
+
+int VirtualFrame::function_index() { return frame_pointer() - 2; }
+
+
+int VirtualFrame::local0_index() { return frame_pointer() + 2; }
+
+
+int VirtualFrame::fp_relative(int index) {
+ ASSERT(index < element_count());
+ ASSERT(frame_pointer() < element_count()); // FP is on the frame.
+ return (frame_pointer() - index) * kPointerSize;
+}
+
+
+int VirtualFrame::expression_base_index() {
+ return local0_index() + local_count();
+}
+
+
+int VirtualFrame::height() {
+ return element_count() - expression_base_index();
+}
+
+
+MemOperand VirtualFrame::LocalAt(int index) {
+ ASSERT(0 <= index);
+ ASSERT(index < local_count());
+ return MemOperand(fp, kLocal0Offset - index * kPointerSize);
+}
+
} } // namespace v8::internal
#endif // V8_VIRTUAL_FRAME_LIGHT_INL_H_
return no_reg;
}
+
+InvalidVirtualFrameInitializer* kInvalidVirtualFrameInitializer = NULL;
+
} } // namespace v8::internal
#ifndef V8_X64_CODEGEN_X64_H_
#define V8_X64_CODEGEN_X64_H_
+#include "ast.h"
#include "ic-inl.h"
+#include "jump-target-heavy.h"
namespace v8 {
namespace internal {
#include "type-info.h"
#include "register-allocator.h"
#include "scopes.h"
+#include "codegen.h"
namespace v8 {
namespace internal {
return register_locations_[num];
}
- int register_location(Register reg) {
- return register_locations_[RegisterAllocator::ToNumber(reg)];
- }
+ inline int register_location(Register reg);
- void set_register_location(Register reg, int index) {
- register_locations_[RegisterAllocator::ToNumber(reg)] = index;
- }
+ inline void set_register_location(Register reg, int index);
bool is_used(int num) {
ASSERT(num >= 0 && num < RegisterAllocator::kNumRegisters);
return register_locations_[num] != kIllegalIndex;
}
- bool is_used(Register reg) {
- return register_locations_[RegisterAllocator::ToNumber(reg)]
- != kIllegalIndex;
- }
+ inline bool is_used(Register reg);
// Add extra in-memory elements to the top of the frame to match an actual
// frame (eg, the frame after an exception handler is pushed). No code is
void SetElementAt(int index, Result* value);
// Set a frame element to a constant. The index is frame-top relative.
- void SetElementAt(int index, Handle<Object> value) {
- Result temp(value);
- SetElementAt(index, &temp);
- }
+ inline void SetElementAt(int index, Handle<Object> value);
void PushElementAt(int index) {
PushFrameSlotAt(element_count() - index - 1);
// Call stub given the number of arguments it expects on (and
// removes from) the stack.
- Result CallStub(CodeStub* stub, int arg_count) {
- PrepareForCall(arg_count, arg_count);
- return RawCallStub(stub);
- }
+ inline Result CallStub(CodeStub* stub, int arg_count);
// Call stub that takes a single argument passed in eax. The
// argument is given as a result which does not have to be eax or
int register_locations_[RegisterAllocator::kNumRegisters];
// The number of frame-allocated locals and parameters respectively.
- int parameter_count() { return cgen()->scope()->num_parameters(); }
- int local_count() { return cgen()->scope()->num_stack_slots(); }
+ inline int parameter_count();
+ inline int local_count();
// The index of the element that is at the processor's frame pointer
// (the ebp register). The parameters, receiver, and return address
'../../src/assembler.cc',
'../../src/assembler.h',
'../../src/ast.cc',
+ '../../src/ast-inl.h',
'../../src/ast.h',
'../../src/bootstrapper.cc',
'../../src/bootstrapper.h',
],
'sources': [
'../../src/fast-codegen.cc',
+ '../../src/jump-target-light.h',
'../../src/jump-target-light-inl.h',
'../../src/jump-target-light.cc',
'../../src/virtual-frame-light-inl.h',
'../../src/arm/register-allocator-arm.cc',
'../../src/arm/simulator-arm.cc',
'../../src/arm/stub-cache-arm.cc',
+ '../../src/arm/virtual-frame-arm-inl.h',
'../../src/arm/virtual-frame-arm.cc',
'../../src/arm/virtual-frame-arm.h',
],
'../../src/ia32',
],
'sources': [
+ '../../src/jump-target-heavy.h',
'../../src/jump-target-heavy-inl.h',
'../../src/jump-target-heavy.cc',
'../../src/virtual-frame-heavy-inl.h',
],
'sources': [
'../../src/fast-codegen.cc',
+ '../../src/jump-target-heavy.h',
'../../src/jump-target-heavy-inl.h',
'../../src/jump-target-heavy.cc',
'../../src/virtual-frame-heavy-inl.h',
RelativePath="..\..\src\assembler.h"
>
</File>
+ <File
+ RelativePath="..\..\src\ast-inl.h"
+ >
+ </File>
<File
RelativePath="..\..\src\ast.cc"
>
RelativePath="..\..\src\jump-target-heavy-inl.h"
>
</File>
+ <File
+ RelativePath="..\..\src\jump-target-heavy.h"
+ >
+ </File>
<File
RelativePath="..\..\src\jump-target.cc"
>
RelativePath="..\..\src\assembler.h"
>
</File>
+ <File
+ RelativePath="..\..\src\ast-inl.h"
+ >
+ </File>
<File
RelativePath="..\..\src\ast.cc"
>
RelativePath="..\..\src\jump-target-light-inl.h"
>
</File>
+ <File
+ RelativePath="..\..\src\jump-target-light.h"
+ >
+ </File>
<File
RelativePath="..\..\src\jump-target.cc"
>
RelativePath="..\..\src\virtual-frame.h"
>
</File>
+ <File
+ RelativePath="..\..\src\arm\virtual-frame-arm-inl.h"
+ >
+ </File>
<File
RelativePath="..\..\src\arm\virtual-frame-arm.h"
>
RelativePath="..\..\src\assembler.h"
>
</File>
+ <File
+ RelativePath="..\..\src\ast-inl.h"
+ >
+ </File>
<File
RelativePath="..\..\src\ast.cc"
>
RelativePath="..\..\src\jump-target-heavy-inl.h"
>
</File>
+ <File
+ RelativePath="..\..\src\jump-target-heavy.h"
+ >
+ </File>
<File
RelativePath="..\..\src\jump-target.cc"
>