Revision: 3920
Author: [email protected]
Date: Fri Feb 19 06:52:39 2010
Log: Begin using a list of bailouts instead of a singleton in the fast code
generator.
A list of bailout descriptions is kept in the CompilationInfo
structure that is shared between the primary and secondary code
generators. The primary adds a description to the list for each
bailout position.
Responsibility for binding labels is moved from the primary to the
secondary code generator. All the labels still target the start of the
secondary code and the compilation state of the primary is still
ignored.
Move the compilation mode flag to the CompilationInfo.
Review URL: http://codereview.chromium.org/651031
http://code.google.com/p/v8/source/detail?r=3920
Modified:
/branches/bleeding_edge/src/arm/codegen-arm.cc
/branches/bleeding_edge/src/arm/codegen-arm.h
/branches/bleeding_edge/src/arm/fast-codegen-arm.cc
/branches/bleeding_edge/src/codegen.cc
/branches/bleeding_edge/src/compiler.h
/branches/bleeding_edge/src/fast-codegen.cc
/branches/bleeding_edge/src/fast-codegen.h
/branches/bleeding_edge/src/ia32/codegen-ia32.cc
/branches/bleeding_edge/src/ia32/codegen-ia32.h
/branches/bleeding_edge/src/ia32/fast-codegen-ia32.cc
/branches/bleeding_edge/src/ia32/fast-codegen-ia32.h
/branches/bleeding_edge/src/x64/codegen-x64.cc
/branches/bleeding_edge/src/x64/codegen-x64.h
/branches/bleeding_edge/src/x64/fast-codegen-x64.cc
=======================================
--- /branches/bleeding_edge/src/arm/codegen-arm.cc Fri Feb 19 05:07:37 2010
+++ /branches/bleeding_edge/src/arm/codegen-arm.cc Fri Feb 19 06:52:39 2010
@@ -142,7 +142,7 @@
// r1: called JS function
// cp: callee's context
-void CodeGenerator::Generate(CompilationInfo* info, Mode mode) {
+void CodeGenerator::Generate(CompilationInfo* info) {
// Record the position for debugging purposes.
CodeForFunctionPosition(info->function());
@@ -174,7 +174,7 @@
}
#endif
- if (mode == PRIMARY) {
+ if (info->mode() == CompilationInfo::PRIMARY) {
frame_->Enter();
// tos: code slot
@@ -277,6 +277,12 @@
frame_->Adjust(4);
allocator_->Unuse(r1);
allocator_->Unuse(lr);
+
+ // Bind all the bailout labels to the beginning of the function.
+ List<CompilationInfo::Bailout*>* bailouts = info->bailouts();
+ for (int i = 0; i < bailouts->length(); i++) {
+ __ bind(bailouts->at(i)->label());
+ }
}
// Initialize the function return target after the locals are set
=======================================
--- /branches/bleeding_edge/src/arm/codegen-arm.h Fri Feb 19 05:07:37 2010
+++ /branches/bleeding_edge/src/arm/codegen-arm.h Fri Feb 19 06:52:39 2010
@@ -150,15 +150,6 @@
class CodeGenerator: public AstVisitor {
public:
- // Compilation mode. Either the compiler is used as the primary
- // compiler and needs to setup everything or the compiler is used as
- // the secondary compiler for split compilation and has to handle
- // bailouts.
- enum Mode {
- PRIMARY,
- SECONDARY
- };
-
// Takes a function literal, generates code for it. This function should
only
// be called by compiler.cc.
static Handle<Code> MakeCode(CompilationInfo* info);
@@ -244,7 +235,7 @@
inline void VisitStatementsAndSpill(ZoneList<Statement*>* statements);
// Main code generation function
- void Generate(CompilationInfo* info, Mode mode);
+ void Generate(CompilationInfo* info);
// The following are used by class Reference.
void LoadReference(Reference* ref);
=======================================
--- /branches/bleeding_edge/src/arm/fast-codegen-arm.cc Wed Feb 17 06:18:47
2010
+++ /branches/bleeding_edge/src/arm/fast-codegen-arm.cc Fri Feb 19 06:52:39
2010
@@ -148,17 +148,25 @@
if (!destination().is(no_reg)) {
__ orr(destination(), accumulator1(), Operand(accumulator0()));
}
- } else if (destination().is(no_reg)) {
- // Result is not needed but do not clobber the operands in case of
- // bailout.
- __ orr(scratch0(), accumulator1(), Operand(accumulator0()));
- __ BranchOnNotSmi(scratch0(), bailout());
} else {
- // Preserve the destination operand in a scratch register in case of
- // bailout.
- __ mov(scratch0(), destination());
- __ orr(destination(), accumulator1(), Operand(accumulator0()));
- __ BranchOnNotSmi(destination(), bailout());
+ // Left is in accumulator1, right in accumulator0.
+ if (destination().is(accumulator0())) {
+ __ mov(scratch0(), accumulator0());
+ __ orr(destination(), accumulator1(), Operand(accumulator1()));
+ Label* bailout =
+ info()->AddBailout(accumulator1(), scratch0()); // Left, right.
+ __ BranchOnNotSmi(destination(), bailout);
+ } else if (destination().is(accumulator1())) {
+ __ mov(scratch0(), accumulator1());
+ __ orr(destination(), accumulator1(), Operand(accumulator0()));
+ Label* bailout = info()->AddBailout(scratch0(), accumulator0());
+ __ BranchOnNotSmi(destination(), bailout);
+ } else {
+ ASSERT(destination().is(no_reg));
+ __ orr(scratch0(), accumulator1(), Operand(accumulator0()));
+ Label* bailout = info()->AddBailout(accumulator1(), accumulator0());
+ __ BranchOnNotSmi(scratch0(), bailout);
+ }
}
// If we didn't bailout, the result (in fact, both inputs too) is known
to
@@ -179,6 +187,7 @@
// Note that we keep a live register reference to cp (context) at
// this point.
+ Label* bailout_to_beginning = info()->AddBailout();
// Receiver (this) is allocated to a fixed register.
if (info()->has_this_properties()) {
Comment cmnt(masm(), ";; MapCheck(this)");
@@ -189,7 +198,7 @@
Handle<HeapObject> object =
Handle<HeapObject>::cast(info()->receiver());
Handle<Map> map(object->map());
EmitLoadReceiver();
- __ CheckMap(receiver_reg(), scratch0(), map, bailout(), false);
+ __ CheckMap(receiver_reg(), scratch0(), map, bailout_to_beginning,
false);
}
// If there is a global variable access check if the global object is the
@@ -202,7 +211,7 @@
ASSERT(info()->has_global_object());
Handle<Map> map(info()->global_object()->map());
__ ldr(scratch0(), CodeGenerator::GlobalObject());
- __ CheckMap(scratch0(), scratch1(), map, bailout(), true);
+ __ CheckMap(scratch0(), scratch1(), map, bailout_to_beginning, true);
}
VisitStatements(function()->body());
@@ -217,8 +226,6 @@
int32_t sp_delta = (scope()->num_parameters() + 1) * kPointerSize;
__ add(sp, sp, Operand(sp_delta));
__ Jump(lr);
-
- __ bind(&bailout_);
}
=======================================
--- /branches/bleeding_edge/src/codegen.cc Fri Feb 19 05:07:37 2010
+++ /branches/bleeding_edge/src/codegen.cc Fri Feb 19 06:52:39 2010
@@ -248,7 +248,7 @@
CodeGenerator cgen(&masm);
CodeGeneratorScope scope(&cgen);
live_edit_tracker.RecordFunctionScope(info->function()->scope());
- cgen.Generate(info, PRIMARY);
+ cgen.Generate(info);
if (cgen.HasStackOverflow()) {
ASSERT(!Top::has_pending_exception());
return Handle<Code>::null();
=======================================
--- /branches/bleeding_edge/src/compiler.h Tue Feb 16 07:15:31 2010
+++ /branches/bleeding_edge/src/compiler.h Fri Feb 19 06:52:39 2010
@@ -41,6 +41,37 @@
// is constructed based on the resources available at compile-time.
class CompilationInfo BASE_EMBEDDED {
public:
+ // Compilation mode. Either the compiler is used as the primary
+ // compiler and needs to setup everything or the compiler is used as
+ // the secondary compiler for split compilation and has to handle
+ // bailouts.
+ enum Mode {
+ PRIMARY,
+ SECONDARY
+ };
+
+ // A description of the compilation state at a bailout to the secondary
+ // code generator.
+ //
+ // The state is currently simple: there are no parameters or local
+ // variables to worry about ('this' can be found in the stack frame).
+ // There are at most two live values.
+ //
+ // There is a label that should be bound to the beginning of the bailout
+ // stub code.
+ class Bailout : public ZoneObject {
+ public:
+ Bailout(Register left, Register right) : left_(left), right_(right) {}
+
+ Label* label() { return &label_; }
+
+ private:
+ Register left_;
+ Register right_;
+ Label label_;
+ };
+
+
// Lazy compilation of a JSFunction.
CompilationInfo(Handle<JSFunction> closure,
int loop_nesting,
@@ -117,9 +148,13 @@
int loop_nesting() { return loop_nesting_; }
bool has_receiver() { return !receiver_.is_null(); }
Handle<Object> receiver() { return receiver_; }
-
- // Accessors for mutable fields, possibly set by analysis passes with
+ List<Bailout*>* bailouts() { return &bailouts_; }
+
+ // Accessors for mutable fields (possibly set by analysis passes) with
// default values given by Initialize.
+ Mode mode() { return mode_; }
+ void set_mode(Mode mode) { mode_ = mode; }
+
bool has_this_properties() { return has_this_properties_; }
void set_has_this_properties(bool flag) { has_this_properties_ = flag; }
@@ -136,9 +171,20 @@
// Derived accessors.
Scope* scope() { return function()->scope(); }
+
+ // Add a bailout with two live values.
+ Label* AddBailout(Register left, Register right) {
+ Bailout* bailout = new Bailout(left, right);
+ bailouts_.Add(bailout);
+ return bailout->label();
+ }
+
+ // Add a bailout with no live values.
+ Label* AddBailout() { return AddBailout(no_reg, no_reg); }
private:
void Initialize() {
+ mode_ = PRIMARY;
has_this_properties_ = false;
has_globals_ = false;
}
@@ -148,6 +194,7 @@
Handle<Script> script_;
FunctionLiteral* function_;
+ Mode mode_;
bool is_eval_;
int loop_nesting_;
@@ -157,6 +204,10 @@
bool has_this_properties_;
bool has_globals_;
+ // An ordered list of bailout points encountered during fast-path
+ // compilation.
+ List<Bailout*> bailouts_;
+
DISALLOW_COPY_AND_ASSIGN(CompilationInfo);
};
=======================================
--- /branches/bleeding_edge/src/fast-codegen.cc Thu Feb 18 07:10:35 2010
+++ /branches/bleeding_edge/src/fast-codegen.cc Fri Feb 19 06:52:39 2010
@@ -456,7 +456,8 @@
// macro assembler.
CodeGenerator cgen(&masm);
CodeGeneratorScope scope(&cgen);
- cgen.Generate(info, CodeGenerator::SECONDARY);
+ info->set_mode(CompilationInfo::SECONDARY);
+ cgen.Generate(info);
if (cgen.HasStackOverflow()) {
ASSERT(!Top::has_pending_exception());
return Handle<Code>::null();
=======================================
--- /branches/bleeding_edge/src/fast-codegen.h Fri Feb 19 01:17:37 2010
+++ /branches/bleeding_edge/src/fast-codegen.h Fri Feb 19 06:52:39 2010
@@ -36,6 +36,7 @@
#include "ast.h"
#include "compiler.h"
+#include "list.h"
namespace v8 {
namespace internal {
@@ -80,7 +81,6 @@
private:
MacroAssembler* masm() { return masm_; }
CompilationInfo* info() { return info_; }
- Label* bailout() { return &bailout_; }
Register destination() { return destination_; }
void set_destination(Register reg) { destination_ = reg; }
@@ -146,7 +146,6 @@
MacroAssembler* masm_;
CompilationInfo* info_;
- Label bailout_;
Register destination_;
uint32_t smi_bits_;
=======================================
--- /branches/bleeding_edge/src/ia32/codegen-ia32.cc Fri Feb 19 05:07:37
2010
+++ /branches/bleeding_edge/src/ia32/codegen-ia32.cc Fri Feb 19 06:52:39
2010
@@ -125,7 +125,7 @@
// edi: called JS function
// esi: callee's context
-void CodeGenerator::Generate(CompilationInfo* info, Mode mode) {
+void CodeGenerator::Generate(CompilationInfo* info) {
// Record the position for debugging purposes.
CodeForFunctionPosition(info->function());
@@ -164,7 +164,7 @@
// esi: callee's context
allocator_->Initialize();
- if (mode == PRIMARY) {
+ if (info->mode() == CompilationInfo::PRIMARY) {
frame_->Enter();
// Allocate space for locals and initialize them.
@@ -255,6 +255,12 @@
// frame to match this state.
frame_->Adjust(3);
allocator_->Unuse(edi);
+
+ // Bind all the bailout labels to the beginning of the function.
+ List<CompilationInfo::Bailout*>* bailouts = info->bailouts();
+ for (int i = 0; i < bailouts->length(); i++) {
+ __ bind(bailouts->at(i)->label());
+ }
}
// Initialize the function return target after the locals are set
=======================================
--- /branches/bleeding_edge/src/ia32/codegen-ia32.h Fri Feb 19 05:07:37 2010
+++ /branches/bleeding_edge/src/ia32/codegen-ia32.h Fri Feb 19 06:52:39 2010
@@ -294,15 +294,6 @@
class CodeGenerator: public AstVisitor {
public:
- // Compilation mode. Either the compiler is used as the primary
- // compiler and needs to setup everything or the compiler is used as
- // the secondary compiler for split compilation and has to handle
- // bailouts.
- enum Mode {
- PRIMARY,
- SECONDARY
- };
-
// Takes a function literal, generates code for it. This function should
only
// be called by compiler.cc.
static Handle<Code> MakeCode(CompilationInfo* info);
@@ -384,7 +375,7 @@
void VisitStatementsAndSpill(ZoneList<Statement*>* statements);
// Main code generation function
- void Generate(CompilationInfo* info, Mode mode);
+ void Generate(CompilationInfo* info);
// Generate the return sequence code. Should be called no more than
// once per compiled function, immediately after binding the return
=======================================
--- /branches/bleeding_edge/src/ia32/fast-codegen-ia32.cc Fri Feb 19
03:39:12 2010
+++ /branches/bleeding_edge/src/ia32/fast-codegen-ia32.cc Fri Feb 19
06:52:39 2010
@@ -456,7 +456,8 @@
// macro assembler.
CodeGenerator cgen(&masm);
CodeGeneratorScope scope(&cgen);
- cgen.Generate(info, CodeGenerator::SECONDARY);
+ info->set_mode(CompilationInfo::SECONDARY);
+ cgen.Generate(info);
if (cgen.HasStackOverflow()) {
ASSERT(!Top::has_pending_exception());
return Handle<Code>::null();
@@ -587,20 +588,27 @@
// commutative.
__ or_(destination(), Operand(other_accumulator(destination())));
}
- } else if (destination().is(no_reg)) {
- // Result is not needed but do not clobber the operands in case of
- // bailout.
- __ mov(scratch0(), accumulator1());
- __ or_(scratch0(), Operand(accumulator0()));
- __ test(scratch0(), Immediate(kSmiTagMask));
- __ j(not_zero, bailout(), not_taken);
} else {
- // Preserve the destination operand in a scratch register in case of
- // bailout.
- __ mov(scratch0(), destination());
- __ or_(destination(), Operand(other_accumulator(destination())));
- __ test(destination(), Immediate(kSmiTagMask));
- __ j(not_zero, bailout(), not_taken);
+ // Left is in accumulator1, right in accumulator0.
+ Label* bailout = NULL;
+ if (destination().is(accumulator0())) {
+ __ mov(scratch0(), accumulator0());
+ __ or_(destination(), Operand(accumulator1())); // Or is
commutative.
+ __ test(destination(), Immediate(kSmiTagMask));
+ bailout = info()->AddBailout(accumulator1(), scratch0()); // Left,
right.
+ } else if (destination().is(accumulator1())) {
+ __ mov(scratch0(), accumulator1());
+ __ or_(destination(), Operand(accumulator0()));
+ __ test(destination(), Immediate(kSmiTagMask));
+ bailout = info()->AddBailout(scratch0(), accumulator0());
+ } else {
+ ASSERT(destination().is(no_reg));
+ __ mov(scratch0(), accumulator1());
+ __ or_(scratch0(), Operand(accumulator0()));
+ __ test(scratch0(), Immediate(kSmiTagMask));
+ bailout = info()->AddBailout(accumulator1(), accumulator0());
+ }
+ __ j(not_zero, bailout, not_taken);
}
// If we didn't bailout, the result (in fact, both inputs too) is known
to
@@ -623,6 +631,7 @@
// Note that we keep a live register reference to esi (context) at this
// point.
+ Label* bailout_to_beginning = info()->AddBailout();
// Receiver (this) is allocated to a fixed register.
if (info()->has_this_properties()) {
Comment cmnt(masm(), ";; MapCheck(this)");
@@ -633,7 +642,7 @@
Handle<HeapObject> object =
Handle<HeapObject>::cast(info()->receiver());
Handle<Map> map(object->map());
EmitLoadReceiver();
- __ CheckMap(receiver_reg(), map, bailout(), false);
+ __ CheckMap(receiver_reg(), map, bailout_to_beginning, false);
}
// If there is a global variable access check if the global object is the
@@ -646,7 +655,7 @@
ASSERT(info()->has_global_object());
Handle<Map> map(info()->global_object()->map());
__ mov(scratch0(), CodeGenerator::GlobalObject());
- __ CheckMap(scratch0(), map, bailout(), true);
+ __ CheckMap(scratch0(), map, bailout_to_beginning, true);
}
VisitStatements(function()->body());
@@ -659,8 +668,6 @@
__ mov(esp, ebp);
__ pop(ebp);
__ ret((scope()->num_parameters() + 1) * kPointerSize);
-
- __ bind(&bailout_);
}
=======================================
--- /branches/bleeding_edge/src/ia32/fast-codegen-ia32.h Fri Feb 19
01:59:47 2010
+++ /branches/bleeding_edge/src/ia32/fast-codegen-ia32.h Fri Feb 19
06:52:39 2010
@@ -32,6 +32,7 @@
#include "ast.h"
#include "compiler.h"
+#include "list.h"
namespace v8 {
namespace internal {
@@ -76,7 +77,6 @@
private:
MacroAssembler* masm() { return masm_; }
CompilationInfo* info() { return info_; }
- Label* bailout() { return &bailout_; }
Register destination() { return destination_; }
void set_destination(Register reg) { destination_ = reg; }
@@ -142,7 +142,7 @@
MacroAssembler* masm_;
CompilationInfo* info_;
- Label bailout_;
+
Register destination_;
uint32_t smi_bits_;
=======================================
--- /branches/bleeding_edge/src/x64/codegen-x64.cc Fri Feb 19 05:07:37 2010
+++ /branches/bleeding_edge/src/x64/codegen-x64.cc Fri Feb 19 06:52:39 2010
@@ -277,7 +277,7 @@
}
-void CodeGenerator::Generate(CompilationInfo* info, Mode mode) {
+void CodeGenerator::Generate(CompilationInfo* info) {
// Record the position for debugging purposes.
CodeForFunctionPosition(info->function());
@@ -316,7 +316,7 @@
// rsi: callee's context
allocator_->Initialize();
- if (mode == PRIMARY) {
+ if (info->mode() == CompilationInfo::PRIMARY) {
frame_->Enter();
// Allocate space for locals and initialize them.
@@ -407,6 +407,12 @@
// frame to match this state.
frame_->Adjust(3);
allocator_->Unuse(rdi);
+
+ // Bind all the bailout labels to the beginning of the function.
+ List<CompilationInfo::Bailout*>* bailouts = info->bailouts();
+ for (int i = 0; i < bailouts->length(); i++) {
+ __ bind(bailouts->at(i)->label());
+ }
}
// Initialize the function return target after the locals are set
=======================================
--- /branches/bleeding_edge/src/x64/codegen-x64.h Fri Feb 19 05:07:37 2010
+++ /branches/bleeding_edge/src/x64/codegen-x64.h Fri Feb 19 06:52:39 2010
@@ -294,15 +294,6 @@
class CodeGenerator: public AstVisitor {
public:
- // Compilation mode. Either the compiler is used as the primary
- // compiler and needs to setup everything or the compiler is used as
- // the secondary compiler for split compilation and has to handle
- // bailouts.
- enum Mode {
- PRIMARY,
- SECONDARY
- };
-
// Takes a function literal, generates code for it. This function should
only
// be called by compiler.cc.
static Handle<Code> MakeCode(CompilationInfo* info);
@@ -385,7 +376,7 @@
void VisitStatementsAndSpill(ZoneList<Statement*>* statements);
// Main code generation function
- void Generate(CompilationInfo* info, Mode mode);
+ void Generate(CompilationInfo* info);
// Generate the return sequence code. Should be called no more than
// once per compiled function, immediately after binding the return
=======================================
--- /branches/bleeding_edge/src/x64/fast-codegen-x64.cc Wed Feb 17 06:18:47
2010
+++ /branches/bleeding_edge/src/x64/fast-codegen-x64.cc Fri Feb 19 06:52:39
2010
@@ -156,20 +156,27 @@
// commutative.
__ or_(destination(), other_accumulator(destination()));
}
- } else if (destination().is(no_reg)) {
- // Result is not needed but do not clobber the operands in case of
- // bailout.
- __ movq(scratch0(), accumulator1());
- __ or_(scratch0(), accumulator0());
- __ JumpIfNotSmi(scratch0(), bailout());
} else {
- // Preserve the destination operand in a scratch register in case of
- // bailout.
- __ movq(scratch0(), destination());
- __ or_(destination(), other_accumulator(destination()));
- __ JumpIfNotSmi(destination(), bailout());
- }
-
+ // Left is in accumulator1, right in accumulator0.
+ if (destination().is(accumulator0())) {
+ __ movq(scratch0(), accumulator0());
+ __ or_(destination(), accumulator1()); // Or is commutative.
+ Label* bailout =
+ info()->AddBailout(accumulator1(), scratch0()); // Left, right.
+ __ JumpIfNotSmi(destination(), bailout);
+ } else if (destination().is(accumulator1())) {
+ __ movq(scratch0(), accumulator1());
+ __ or_(destination(), accumulator0());
+ Label* bailout = info()->AddBailout(scratch0(), accumulator0());
+ __ JumpIfNotSmi(destination(), bailout);
+ } else {
+ ASSERT(destination().is(no_reg));
+ __ movq(scratch0(), accumulator1());
+ __ or_(scratch0(), accumulator0());
+ Label* bailout = info()->AddBailout(accumulator1(), accumulator0());
+ __ JumpIfNotSmi(scratch0(), bailout);
+ }
+ }
// If we didn't bailout, the result (in fact, both inputs too) is known
to
// be a smi.
@@ -191,6 +198,7 @@
// Note that we keep a live register reference to esi (context) at this
// point.
+ Label* bailout_to_beginning = info()->AddBailout();
// Receiver (this) is allocated to a fixed register.
if (info()->has_this_properties()) {
Comment cmnt(masm(), ";; MapCheck(this)");
@@ -201,7 +209,7 @@
Handle<HeapObject> object =
Handle<HeapObject>::cast(info()->receiver());
Handle<Map> map(object->map());
EmitLoadReceiver();
- __ CheckMap(receiver_reg(), map, bailout(), false);
+ __ CheckMap(receiver_reg(), map, bailout_to_beginning, false);
}
// If there is a global variable access check if the global object is the
@@ -214,7 +222,7 @@
ASSERT(info()->has_global_object());
Handle<Map> map(info()->global_object()->map());
__ movq(scratch0(), CodeGenerator::GlobalObject());
- __ CheckMap(scratch0(), map, bailout(), true);
+ __ CheckMap(scratch0(), map, bailout_to_beginning, true);
}
VisitStatements(info()->function()->body());
@@ -227,8 +235,6 @@
__ movq(rsp, rbp);
__ pop(rbp);
__ ret((scope()->num_parameters() + 1) * kPointerSize);
-
- __ bind(&bailout_);
}
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev