Moved the function GetValue from the code generator to the Reference

helper class.

As a consequence, also removed the optional Reference from the code
generator state and got rid of some state-dependent behavior in the
code generator.
Review URL: http://codereview.chromium.org/6538

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@466 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
kmillikin@chromium.org 2008-10-08 07:24:06 +00:00
parent d0b27552dc
commit 5d7f354384
2 changed files with 328 additions and 363 deletions

View File

@ -51,6 +51,7 @@ class ArmCodeGenerator;
// on the execution stack to represent the reference.
enum InitState { CONST_INIT, NOT_CONST_INIT };
enum TypeofState { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF };
class Reference BASE_EMBEDDED {
public:
@ -72,6 +73,18 @@ class Reference BASE_EMBEDDED {
bool is_slot() const { return type_ == SLOT; }
bool is_property() const { return type_ == NAMED || type_ == KEYED; }
// Return the name. Only valid for named property references.
Handle<String> GetName();
// Generate code to push the value of the reference on top of the
// expression stack. The reference is expected to be already on top of
// the expression stack, and it is left in place with its value above it.
void GetValue(TypeofState typeof_state);
// Generate code to store the value on top of the expression stack in the
// reference. The reference is expected to be immediately below the value
// on the expression stack. The stored value is left in place (with the
// reference intact below it) to support chained assignments.
void SetValue(InitState init_state);
private:
@ -91,42 +104,29 @@ class Reference BASE_EMBEDDED {
class CodeGenState BASE_EMBEDDED {
public:
enum AccessType {
UNDEFINED,
LOAD,
LOAD_TYPEOF_EXPR
};
// Create an initial code generator state. Destroying the initial state
// leaves the code generator with a NULL state.
explicit CodeGenState(ArmCodeGenerator* owner);
// Create a code generator state based on a code generator's current
// state. The new state has its own access type and pair of branch
// labels, and no reference.
// state. The new state has its own typeof state and pair of branch
// labels.
CodeGenState(ArmCodeGenerator* owner,
AccessType access,
TypeofState typeof_state,
Label* true_target,
Label* false_target);
// Create a code generator state based on a code generator's current
// state. The new state has an access type of LOAD, its own reference,
// and inherits the pair of branch labels of the current state.
CodeGenState(ArmCodeGenerator* owner, Reference* ref);
// Destroy a code generator state and restore the owning code generator's
// previous state.
~CodeGenState();
AccessType access() const { return access_; }
Reference* ref() const { return ref_; }
TypeofState typeof_state() const { return typeof_state_; }
Label* true_target() const { return true_target_; }
Label* false_target() const { return false_target_; }
private:
ArmCodeGenerator* owner_;
AccessType access_;
Reference* ref_;
TypeofState typeof_state_;
Label* true_target_;
Label* false_target_;
CodeGenState* previous_;
@ -178,9 +178,7 @@ class ArmCodeGenerator: public CodeGenerator {
// State
bool has_cc() const { return cc_reg_ != al; }
CodeGenState::AccessType access() const { return state_->access(); }
Reference* ref() const { return state_->ref(); }
bool is_referenced() const { return state_->ref() != NULL; }
TypeofState typeof_state() const { return state_->typeof_state(); }
Label* true_target() const { return state_->true_target(); }
Label* false_target() const { return state_->false_target(); }
@ -209,12 +207,17 @@ class ArmCodeGenerator: public CodeGenerator {
MemOperand SlotOperand(Slot* slot, Register tmp);
void LoadCondition(Expression* x, CodeGenState::AccessType access,
Label* true_target, Label* false_target, bool force_cc);
void Load(Expression* x,
CodeGenState::AccessType access = CodeGenState::LOAD);
void LoadCondition(Expression* x,
TypeofState typeof_state,
Label* true_target,
Label* false_target,
bool force_cc);
void Load(Expression* x, TypeofState typeof_state = NOT_INSIDE_TYPEOF);
void LoadGlobal();
// Read a value from a slot and leave it on top of the expression stack.
void LoadFromSlot(Slot* slot, TypeofState typeof_state);
// Special code for typeof expressions: Unfortunately, we must
// be careful when loading the expression in 'typeof'
// expressions. We are not allowed to throw reference errors for
@ -223,24 +226,6 @@ class ArmCodeGenerator: public CodeGenerator {
// through the context chain.
void LoadTypeofExpression(Expression* x);
// References
// Generate code to fetch the value of a reference. The reference is
// expected to be on top of the expression stack. It is left in place and
// its value is pushed on top of it.
void GetValue(Reference* ref) {
ASSERT(!has_cc());
ASSERT(!ref->is_illegal());
CodeGenState new_state(this, ref);
Visit(ref->expression());
}
// Generate code to fetch a value from a property of a reference. The
// reference is expected on top of the expression stack. It is left in
// place and its value is pushed on top of it.
void GetReferenceProperty(Expression* key);
void ToBoolean(Label* true_target, Label* false_target);
void GenericBinaryOperation(Token::Value op);
@ -309,8 +294,7 @@ class ArmCodeGenerator: public CodeGenerator {
CodeGenState::CodeGenState(ArmCodeGenerator* owner)
: owner_(owner),
access_(UNDEFINED),
ref_(NULL),
typeof_state_(NOT_INSIDE_TYPEOF),
true_target_(NULL),
false_target_(NULL),
previous_(NULL) {
@ -319,12 +303,11 @@ CodeGenState::CodeGenState(ArmCodeGenerator* owner)
CodeGenState::CodeGenState(ArmCodeGenerator* owner,
AccessType access,
TypeofState typeof_state,
Label* true_target,
Label* false_target)
: owner_(owner),
access_(access),
ref_(NULL),
typeof_state_(typeof_state),
true_target_(true_target),
false_target_(false_target),
previous_(owner->state()) {
@ -332,17 +315,6 @@ CodeGenState::CodeGenState(ArmCodeGenerator* owner,
}
CodeGenState::CodeGenState(ArmCodeGenerator* owner, Reference* ref)
: owner_(owner),
access_(LOAD),
ref_(ref),
true_target_(owner->state()->true_target_),
false_target_(owner->state()->false_target_),
previous_(owner->state()) {
owner_->set_state(this);
}
CodeGenState::~CodeGenState() {
ASSERT(owner_->state() == this);
owner_->set_state(previous_);
@ -708,15 +680,13 @@ MemOperand ArmCodeGenerator::SlotOperand(Slot* slot, Register tmp) {
// code register and no value is pushed. If the condition code register was set,
// has_cc() is true and cc_reg_ contains the condition to test for 'true'.
void ArmCodeGenerator::LoadCondition(Expression* x,
CodeGenState::AccessType access,
TypeofState typeof_state,
Label* true_target,
Label* false_target,
bool force_cc) {
ASSERT(access == CodeGenState::LOAD ||
access == CodeGenState::LOAD_TYPEOF_EXPR);
ASSERT(!has_cc() && !is_referenced());
ASSERT(!has_cc());
{ CodeGenState new_state(this, access, true_target, false_target);
{ CodeGenState new_state(this, typeof_state, true_target, false_target);
Visit(x);
}
if (force_cc && !has_cc()) {
@ -727,13 +697,10 @@ void ArmCodeGenerator::LoadCondition(Expression* x,
}
void ArmCodeGenerator::Load(Expression* x, CodeGenState::AccessType access) {
ASSERT(access == CodeGenState::LOAD ||
access == CodeGenState::LOAD_TYPEOF_EXPR);
void ArmCodeGenerator::Load(Expression* x, TypeofState typeof_state) {
Label true_target;
Label false_target;
LoadCondition(x, access, &true_target, &false_target, false);
LoadCondition(x, typeof_state, &true_target, &false_target, false);
if (has_cc()) {
// convert cc_reg_ into a bool
@ -786,8 +753,8 @@ void ArmCodeGenerator::LoadGlobal() {
// TODO(1241834): Get rid of this function in favor of just using Load, now
// that we have the LOAD_TYPEOF_EXPR access type. => Need to handle
// global variables w/o reference errors elsewhere.
// that we have the INSIDE_TYPEOF typeof state. => Need to handle global
// variables w/o reference errors elsewhere.
void ArmCodeGenerator::LoadTypeofExpression(Expression* x) {
Variable* variable = x->AsVariableProxy()->AsVariable();
if (variable != NULL && !variable->is_this() && variable->is_global()) {
@ -801,7 +768,7 @@ void ArmCodeGenerator::LoadTypeofExpression(Expression* x) {
Property property(&global, &key, RelocInfo::kNoPosition);
Load(&property);
} else {
Load(x, CodeGenState::LOAD_TYPEOF_EXPR);
Load(x, INSIDE_TYPEOF);
}
}
@ -818,6 +785,7 @@ Reference::~Reference() {
void ArmCodeGenerator::LoadReference(Reference* ref) {
Comment cmnt(masm_, "[ LoadReference");
Expression* e = ref->expression();
Property* property = e->AsProperty();
Variable* var = e->AsVariableProxy()->AsVariable();
@ -859,6 +827,7 @@ void ArmCodeGenerator::LoadReference(Reference* ref) {
void ArmCodeGenerator::UnloadReference(Reference* ref) {
Comment cmnt(masm_, "[ UnloadReference");
int size = ref->size();
if (size <= 0) {
// Do nothing. No popping is necessary.
@ -994,43 +963,6 @@ class InvokeBuiltinStub : public CodeStub {
};
void ArmCodeGenerator::GetReferenceProperty(Expression* key) {
ASSERT(!ref()->is_illegal());
// TODO(1241834): Make sure that this it is safe to ignore the distinction
// between access types LOAD and LOAD_TYPEOF_EXPR. If there is a chance
// that reference errors can be thrown below, we must distinguish between
// the two kinds of loads (typeof expression loads must not throw a
// reference error).
if (ref()->type() == Reference::NAMED) {
// Compute the name of the property.
Literal* literal = key->AsLiteral();
Handle<String> name(String::cast(*literal->handle()));
// Call the appropriate IC code.
// Setup the name register.
__ mov(r2, Operand(name));
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
Variable* var = ref()->expression()->AsVariableProxy()->AsVariable();
if (var != NULL) {
ASSERT(var->is_global());
__ Call(ic, RelocInfo::CODE_TARGET_CONTEXT);
} else {
__ Call(ic, RelocInfo::CODE_TARGET);
}
} else {
// Access keyed property.
ASSERT(ref()->type() == Reference::KEYED);
// TODO(1224671): Implement inline caching for keyed loads as on ia32.
GetPropertyStub stub;
__ CallStub(&stub);
}
__ push(r0);
}
void ArmCodeGenerator::GenericBinaryOperation(Token::Value op) {
// sp[0] : y
// sp[1] : x
@ -1527,7 +1459,7 @@ void ArmCodeGenerator::VisitIfStatement(IfStatement* node) {
Label then;
Label else_;
// if (cond)
LoadCondition(node->condition(), CodeGenState::LOAD, &then, &else_, true);
LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true);
Branch(false, &else_);
// then
__ bind(&then);
@ -1542,7 +1474,7 @@ void ArmCodeGenerator::VisitIfStatement(IfStatement* node) {
ASSERT(!has_else_stm);
Label then;
// if (cond)
LoadCondition(node->condition(), CodeGenState::LOAD, &then, &exit, true);
LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &exit, true);
Branch(false, &exit);
// then
__ bind(&then);
@ -1553,7 +1485,7 @@ void ArmCodeGenerator::VisitIfStatement(IfStatement* node) {
ASSERT(!has_then_stm);
Label else_;
// if (!cond)
LoadCondition(node->condition(), CodeGenState::LOAD, &exit, &else_, true);
LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &exit, &else_, true);
Branch(true, &exit);
// else
__ bind(&else_);
@ -1563,7 +1495,7 @@ void ArmCodeGenerator::VisitIfStatement(IfStatement* node) {
Comment cmnt(masm_, "[ If");
ASSERT(!has_then_stm && !has_else_stm);
// if (cond)
LoadCondition(node->condition(), CodeGenState::LOAD, &exit, &exit, false);
LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &exit, &exit, false);
if (has_cc()) {
cc_reg_ = al;
} else {
@ -1806,7 +1738,7 @@ void ArmCodeGenerator::VisitLoopStatement(LoopStatement* node) {
case DONT_KNOW:
CheckStack(); // TODO(1222600): ignore if body contains calls.
LoadCondition(node->cond(),
CodeGenState::LOAD,
NOT_INSIDE_TYPEOF,
&loop,
node->break_target(),
true);
@ -1972,7 +1904,6 @@ void ArmCodeGenerator::VisitForInStatement(ForInStatement* node) {
{ Reference each(this, node->each());
if (!each.is_illegal()) {
if (each.size() > 0) {
// Reference's size is positive.
__ ldr(r0, MemOperand(sp, kPointerSize * each.size()));
__ push(r0);
}
@ -2273,46 +2204,42 @@ void ArmCodeGenerator::VisitFunctionBoilerplateLiteral(
void ArmCodeGenerator::VisitConditional(Conditional* node) {
Comment cmnt(masm_, "[ Conditional");
Label then, else_, exit;
LoadCondition(node->condition(), CodeGenState::LOAD, &then, &else_, true);
LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true);
Branch(false, &else_);
__ bind(&then);
Load(node->then_expression(), access());
Load(node->then_expression(), typeof_state());
__ b(&exit);
__ bind(&else_);
Load(node->else_expression(), access());
Load(node->else_expression(), typeof_state());
__ bind(&exit);
}
void ArmCodeGenerator::VisitSlot(Slot* node) {
ASSERT(access() != CodeGenState::UNDEFINED);
Comment cmnt(masm_, "[ Slot");
if (node->type() == Slot::LOOKUP) {
ASSERT(node->var()->mode() == Variable::DYNAMIC);
void ArmCodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) {
if (slot->type() == Slot::LOOKUP) {
ASSERT(slot->var()->mode() == Variable::DYNAMIC);
// For now, just do a runtime call.
__ push(cp);
__ mov(r0, Operand(node->var()->name()));
__ mov(r0, Operand(slot->var()->name()));
__ push(r0);
if (access() == CodeGenState::LOAD) {
__ CallRuntime(Runtime::kLoadContextSlot, 2);
} else {
ASSERT(access() == CodeGenState::LOAD_TYPEOF_EXPR);
if (typeof_state == INSIDE_TYPEOF) {
__ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
} else {
__ CallRuntime(Runtime::kLoadContextSlot, 2);
}
__ push(r0);
} else {
// Note: We would like to keep the assert below, but it fires because of
// some nasty code in LoadTypeofExpression() which should be removed...
// ASSERT(node->var()->mode() != Variable::DYNAMIC);
// ASSERT(slot->var()->mode() != Variable::DYNAMIC);
// Special handling for locals allocated in registers.
__ ldr(r0, SlotOperand(node, r2));
__ ldr(r0, SlotOperand(slot, r2));
__ push(r0);
if (node->var()->mode() == Variable::CONST) {
if (slot->var()->mode() == Variable::CONST) {
// Const slots may contain 'the hole' value (the constant hasn't been
// initialized yet) which needs to be converted into the 'undefined'
// value.
@ -2326,24 +2253,22 @@ void ArmCodeGenerator::VisitSlot(Slot* node) {
}
void ArmCodeGenerator::VisitSlot(Slot* node) {
Comment cmnt(masm_, "[ Slot");
LoadFromSlot(node, typeof_state());
}
void ArmCodeGenerator::VisitVariableProxy(VariableProxy* node) {
Comment cmnt(masm_, "[ VariableProxy");
Variable* var_node = node->var();
Expression* expr = var_node->rewrite();
Variable* var = node->var();
Expression* expr = var->rewrite();
if (expr != NULL) {
Visit(expr);
} else {
ASSERT(var_node->is_global());
if (is_referenced()) {
if (var_node->AsProperty() != NULL) {
__ RecordPosition(var_node->AsProperty()->position());
}
GetReferenceProperty(new Literal(var_node->name()));
} else {
Reference property(this, node);
GetValue(&property);
}
ASSERT(var->is_global());
Reference ref(this, node);
ref.GetValue(typeof_state());
}
}
@ -2556,7 +2481,7 @@ void ArmCodeGenerator::VisitAssignment(Assignment* node) {
Load(node->value());
} else {
GetValue(&target);
target.GetValue(NOT_INSIDE_TYPEOF);
Literal* literal = node->value()->AsLiteral();
if (literal != NULL && literal->handle()->IsSmi()) {
SmiOperation(node->binary_op(), literal->handle(), false);
@ -2601,15 +2526,8 @@ void ArmCodeGenerator::VisitThrow(Throw* node) {
void ArmCodeGenerator::VisitProperty(Property* node) {
Comment cmnt(masm_, "[ Property");
if (is_referenced()) {
__ RecordPosition(node->position());
GetReferenceProperty(node->key());
} else {
Reference property(this, node);
__ RecordPosition(node->position());
GetValue(&property);
}
Reference property(this, node);
property.GetValue(typeof_state());
}
@ -2713,7 +2631,7 @@ void ArmCodeGenerator::VisitCall(Call* node) {
// Load the function to call from the property through a reference.
Reference ref(this, property);
GetValue(&ref); // receiver
ref.GetValue(NOT_INSIDE_TYPEOF); // receiver
// Pass receiver to called function.
__ ldr(r0, MemOperand(sp, ref.size() * kPointerSize));
@ -2957,7 +2875,7 @@ void ArmCodeGenerator::VisitUnaryOperation(UnaryOperation* node) {
if (op == Token::NOT) {
LoadCondition(node->expression(),
CodeGenState::LOAD,
NOT_INSIDE_TYPEOF,
false_target(),
true_target(),
true);
@ -3092,7 +3010,7 @@ void ArmCodeGenerator::VisitCountOperation(CountOperation* node) {
{ Reference target(this, node->expression());
if (target.is_illegal()) return;
GetValue(&target);
target.GetValue(NOT_INSIDE_TYPEOF);
__ pop(r0);
Label slow, exit;
@ -3174,7 +3092,7 @@ void ArmCodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
if (op == Token::AND) {
Label is_true;
LoadCondition(node->left(),
CodeGenState::LOAD,
NOT_INSIDE_TYPEOF,
&is_true,
false_target(),
false);
@ -3184,7 +3102,7 @@ void ArmCodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
// Evaluate right side expression.
__ bind(&is_true);
LoadCondition(node->right(),
CodeGenState::LOAD,
NOT_INSIDE_TYPEOF,
true_target(),
false_target(),
false);
@ -3215,7 +3133,7 @@ void ArmCodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
} else if (op == Token::OR) {
Label is_false;
LoadCondition(node->left(),
CodeGenState::LOAD,
NOT_INSIDE_TYPEOF,
true_target(),
&is_false,
false);
@ -3225,7 +3143,7 @@ void ArmCodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
// Evaluate right side expression.
__ bind(&is_false);
LoadCondition(node->right(),
CodeGenState::LOAD,
NOT_INSIDE_TYPEOF,
true_target(),
false_target(),
false);
@ -3517,10 +3435,91 @@ void ArmCodeGenerator::ExitJSFrame() {
#undef __
#define __ masm->
Handle<String> Reference::GetName() {
ASSERT(type_ == NAMED);
Property* property = expression_->AsProperty();
if (property == NULL) {
// Global variable reference treated as a named property reference.
VariableProxy* proxy = expression_->AsVariableProxy();
ASSERT(proxy->AsVariable() != NULL);
ASSERT(proxy->AsVariable()->is_global());
return proxy->name();
} else {
Literal* raw_name = property->key()->AsLiteral();
ASSERT(raw_name != NULL);
return Handle<String>(String::cast(*raw_name->handle()));
}
}
void Reference::GetValue(TypeofState typeof_state) {
ASSERT(!is_illegal());
ASSERT(!cgen_->has_cc());
MacroAssembler* masm = cgen_->masm();
Property* property = expression_->AsProperty();
if (property != NULL) {
__ RecordPosition(property->position());
}
switch (type_) {
case SLOT: {
Comment cmnt(masm, "[ Load from Slot");
Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot();
ASSERT(slot != NULL);
cgen_->LoadFromSlot(slot, typeof_state);
break;
}
case NAMED: {
// TODO(1241834): Make sure that this it is safe to ignore the
// distinction between expressions in a typeof and not in a typeof. If
// there is a chance that reference errors can be thrown below, we
// must distinguish between the two kinds of loads (typeof expression
// loads must not throw a reference error).
Comment cmnt(masm, "[ Load from named Property");
// Setup the name register.
Handle<String> name(GetName());
__ mov(r2, Operand(name));
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
Variable* var = expression_->AsVariableProxy()->AsVariable();
if (var != NULL) {
ASSERT(var->is_global());
__ Call(ic, RelocInfo::CODE_TARGET_CONTEXT);
} else {
__ Call(ic, RelocInfo::CODE_TARGET);
}
__ push(r0);
break;
}
case KEYED: {
// TODO(1241834): Make sure that this it is safe to ignore the
// distinction between expressions in a typeof and not in a typeof.
Comment cmnt(masm, "[ Load from keyed Property");
ASSERT(property != NULL);
// TODO(1224671): Implement inline caching for keyed loads as on ia32.
GetPropertyStub stub;
__ CallStub(&stub);
__ push(r0);
break;
}
default:
UNREACHABLE();
}
}
void Reference::SetValue(InitState init_state) {
ASSERT(!is_illegal());
ASSERT(!cgen_->has_cc());
MacroAssembler* masm = cgen_->masm();
Property* property = expression_->AsProperty();
if (property != NULL) {
__ RecordPosition(property->position());
}
switch (type_) {
case SLOT: {
Comment cmnt(masm, "[ Store to Slot");
@ -3606,24 +3605,10 @@ void Reference::SetValue(InitState init_state) {
case NAMED: {
Comment cmnt(masm, "[ Store to named Property");
Property* property = expression_->AsProperty();
Handle<String> name;
if (property == NULL) {
// Global variable reference treated as named property access.
VariableProxy* proxy = expression_->AsVariableProxy();
ASSERT(proxy->AsVariable() != NULL);
ASSERT(proxy->AsVariable()->is_global());
name = proxy->name();
} else {
Literal* raw_name = property->key()->AsLiteral();
ASSERT(raw_name != NULL);
name = Handle<String>(String::cast(*raw_name->handle()));
__ RecordPosition(property->position());
}
// Call the appropriate IC code.
__ pop(r0); // value
// Setup the name register.
Handle<String> name(GetName());
__ mov(r2, Operand(name));
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET);

View File

@ -57,6 +57,7 @@ enum OverwriteMode { NO_OVERWRITE, OVERWRITE_LEFT, OVERWRITE_RIGHT };
// on the execution stack to represent the reference.
enum InitState { CONST_INIT, NOT_CONST_INIT };
enum TypeofState { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF };
class Reference BASE_EMBEDDED {
public:
@ -79,6 +80,18 @@ class Reference BASE_EMBEDDED {
bool is_slot() const { return type_ == SLOT; }
bool is_property() const { return type_ == NAMED || type_ == KEYED; }
// Return the name. Only valid for named property references.
Handle<String> GetName();
// Generate code to push the value of the reference on top of the
// expression stack. The reference is expected to be already on top of
// the expression stack, and it is left in place with its value above it.
void GetValue(TypeofState typeof_state);
// Generate code to store the value on top of the expression stack in the
// reference. The reference is expected to be immediately below the value
// on the expression stack. The stored value is left in place (with the
// reference intact below it) to support chained assignments.
void SetValue(InitState init_state);
private:
@ -98,42 +111,29 @@ class Reference BASE_EMBEDDED {
class CodeGenState BASE_EMBEDDED {
public:
enum AccessType {
UNDEFINED,
LOAD,
LOAD_TYPEOF_EXPR
};
// Create an initial code generator state. Destroying the initial state
// leaves the code generator with a NULL state.
explicit CodeGenState(Ia32CodeGenerator* owner);
// Create a code generator state based on a code generator's current
// state. The new state has its own access type and pair of branch
// labels, and no reference.
// state. The new state has its own typeof state and pair of branch
// labels.
CodeGenState(Ia32CodeGenerator* owner,
AccessType access,
TypeofState typeof_state,
Label* true_target,
Label* false_target);
// Create a code generator state based on a code generator's current
// state. The new state has an access type of LOAD, its own reference,
// and inherits the pair of branch labels of the current state.
CodeGenState(Ia32CodeGenerator* owner, Reference* ref);
// Destroy a code generator state and restore the owning code generator's
// previous state.
~CodeGenState();
AccessType access() const { return access_; }
Reference* ref() const { return ref_; }
TypeofState typeof_state() const { return typeof_state_; }
Label* true_target() const { return true_target_; }
Label* false_target() const { return false_target_; }
private:
Ia32CodeGenerator* owner_;
AccessType access_;
Reference* ref_;
TypeofState typeof_state_;
Label* true_target_;
Label* false_target_;
CodeGenState* previous_;
@ -185,9 +185,7 @@ class Ia32CodeGenerator: public CodeGenerator {
// State
bool has_cc() const { return cc_reg_ >= 0; }
CodeGenState::AccessType access() const { return state_->access(); }
Reference* ref() const { return state_->ref(); }
bool is_referenced() const { return state_->ref() != NULL; }
TypeofState typeof_state() const { return state_->typeof_state(); }
Label* true_target() const { return state_->true_target(); }
Label* false_target() const { return state_->false_target(); }
@ -216,14 +214,16 @@ class Ia32CodeGenerator: public CodeGenerator {
Operand SlotOperand(Slot* slot, Register tmp);
void LoadCondition(Expression* x,
CodeGenState::AccessType access,
TypeofState typeof_state,
Label* true_target,
Label* false_target,
bool force_cc);
void Load(Expression* x,
CodeGenState::AccessType access = CodeGenState::LOAD);
void Load(Expression* x, TypeofState typeof_state = NOT_INSIDE_TYPEOF);
void LoadGlobal();
// Read a value from a slot and leave it on top of the expression stack.
void LoadFromSlot(Slot* slot, TypeofState typeof_state);
// Special code for typeof expressions: Unfortunately, we must
// be careful when loading the expression in 'typeof'
// expressions. We are not allowed to throw reference errors for
@ -232,23 +232,6 @@ class Ia32CodeGenerator: public CodeGenerator {
// through the context chain.
void LoadTypeofExpression(Expression* x);
// References
// Generate code to fetch the value of a reference. The reference is
// expected to be on top of the expression stack. It is left in place and
// its value is pushed on top of it.
void GetValue(Reference* ref) {
ASSERT(!has_cc());
ASSERT(!ref->is_illegal());
CodeGenState new_state(this, ref);
Visit(ref->expression());
}
// Generate code to fetch a value from a property of a reference. The
// reference is expected on top of the expression stack. It is left in
// place and its value is pushed on top of it.
void GetReferenceProperty(Expression* key);
void ToBoolean(Label* true_target, Label* false_target);
void GenericBinaryOperation(
@ -340,8 +323,7 @@ class Ia32CodeGenerator: public CodeGenerator {
CodeGenState::CodeGenState(Ia32CodeGenerator* owner)
: owner_(owner),
access_(UNDEFINED),
ref_(NULL),
typeof_state_(NOT_INSIDE_TYPEOF),
true_target_(NULL),
false_target_(NULL),
previous_(NULL) {
@ -350,12 +332,11 @@ CodeGenState::CodeGenState(Ia32CodeGenerator* owner)
CodeGenState::CodeGenState(Ia32CodeGenerator* owner,
AccessType access,
TypeofState typeof_state,
Label* true_target,
Label* false_target)
: owner_(owner),
access_(access),
ref_(NULL),
typeof_state_(typeof_state),
true_target_(true_target),
false_target_(false_target),
previous_(owner->state()) {
@ -363,17 +344,6 @@ CodeGenState::CodeGenState(Ia32CodeGenerator* owner,
}
CodeGenState::CodeGenState(Ia32CodeGenerator* owner, Reference* ref)
: owner_(owner),
access_(LOAD),
ref_(ref),
true_target_(owner->state()->true_target_),
false_target_(owner->state()->false_target_),
previous_(owner->state()) {
owner_->set_state(this);
}
CodeGenState::~CodeGenState() {
ASSERT(owner_->state() == this);
owner_->set_state(previous_);
@ -759,15 +729,13 @@ Operand Ia32CodeGenerator::SlotOperand(Slot* slot, Register tmp) {
// register and no value is pushed. If the condition code register was set,
// has_cc() is true and cc_reg_ contains the condition to test for 'true'.
void Ia32CodeGenerator::LoadCondition(Expression* x,
CodeGenState::AccessType access,
TypeofState typeof_state,
Label* true_target,
Label* false_target,
bool force_cc) {
ASSERT(access == CodeGenState::LOAD ||
access == CodeGenState::LOAD_TYPEOF_EXPR);
ASSERT(!has_cc() && !is_referenced());
ASSERT(!has_cc());
{ CodeGenState new_state(this, access, true_target, false_target);
{ CodeGenState new_state(this, typeof_state, true_target, false_target);
Visit(x);
}
if (force_cc && !has_cc()) {
@ -777,13 +745,10 @@ void Ia32CodeGenerator::LoadCondition(Expression* x,
}
void Ia32CodeGenerator::Load(Expression* x, CodeGenState::AccessType access) {
ASSERT(access == CodeGenState::LOAD ||
access == CodeGenState::LOAD_TYPEOF_EXPR);
void Ia32CodeGenerator::Load(Expression* x, TypeofState typeof_state) {
Label true_target;
Label false_target;
LoadCondition(x, access, &true_target, &false_target, false);
LoadCondition(x, typeof_state, &true_target, &false_target, false);
if (has_cc()) {
// convert cc_reg_ into a bool
@ -832,8 +797,8 @@ void Ia32CodeGenerator::LoadGlobal() {
// TODO(1241834): Get rid of this function in favor of just using Load, now
// that we have the LOAD_TYPEOF_EXPR access type. => Need to handle
// global variables w/o reference errors elsewhere.
// that we have the INSIDE_TYPEOF typeof state. => Need to handle global
// variables w/o reference errors elsewhere.
void Ia32CodeGenerator::LoadTypeofExpression(Expression* x) {
Variable* variable = x->AsVariableProxy()->AsVariable();
if (variable != NULL && !variable->is_this() && variable->is_global()) {
@ -847,7 +812,7 @@ void Ia32CodeGenerator::LoadTypeofExpression(Expression* x) {
Property property(&global, &key, RelocInfo::kNoPosition);
Load(&property);
} else {
Load(x, CodeGenState::LOAD_TYPEOF_EXPR);
Load(x, INSIDE_TYPEOF);
}
}
@ -864,6 +829,7 @@ Reference::~Reference() {
void Ia32CodeGenerator::LoadReference(Reference* ref) {
Comment cmnt(masm_, "[ LoadReference");
Expression* e = ref->expression();
Property* property = e->AsProperty();
Variable* var = e->AsVariableProxy()->AsVariable();
@ -905,7 +871,7 @@ void Ia32CodeGenerator::LoadReference(Reference* ref) {
void Ia32CodeGenerator::UnloadReference(Reference* ref) {
// Pop n references on the stack while preserving TOS
// Pop a reference from the stack while preserving TOS.
Comment cmnt(masm_, "[ UnloadReference");
int size = ref->size();
if (size <= 0) {
@ -985,47 +951,6 @@ void Ia32CodeGenerator::ToBoolean(Label* true_target, Label* false_target) {
}
void Ia32CodeGenerator::GetReferenceProperty(Expression* key) {
ASSERT(!ref()->is_illegal());
// TODO(1241834): Make sure that this it is safe to ignore the distinction
// between access types LOAD and LOAD_TYPEOF_EXPR. If there is a chance
// that reference errors can be thrown below, we must distinguish between
// the two kinds of loads (typeof expression loads must not throw a
// reference error).
if (ref()->type() == Reference::NAMED) {
// Compute the name of the property.
Literal* literal = key->AsLiteral();
Handle<String> name(String::cast(*literal->handle()));
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
Variable* var = ref()->expression()->AsVariableProxy()->AsVariable();
// Setup the name register.
__ Set(ecx, Immediate(name));
if (var != NULL) {
ASSERT(var->is_global());
__ call(ic, RelocInfo::CODE_TARGET_CONTEXT);
} else {
__ call(ic, RelocInfo::CODE_TARGET);
}
} else {
// Access keyed property.
ASSERT(ref()->type() == Reference::KEYED);
// Call IC code.
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
Variable* var = ref()->expression()->AsVariableProxy()->AsVariable();
if (var != NULL) {
ASSERT(var->is_global());
__ call(ic, RelocInfo::CODE_TARGET_CONTEXT);
} else {
__ call(ic, RelocInfo::CODE_TARGET);
}
}
__ push(eax); // IC call leaves result in eax, push it out
}
class FloatingPointHelper : public AllStatic {
public:
// Code pattern for loading floating point values. Input values must
@ -1676,7 +1601,9 @@ class CallFunctionStub: public CodeStub {
void Ia32CodeGenerator::CallWithArguments(ZoneList<Expression*>* args,
int position) {
// Push the arguments ("left-to-right") on the stack.
for (int i = 0; i < args->length(); i++) Load(args->at(i));
for (int i = 0; i < args->length(); i++) {
Load(args->at(i));
}
// Record the position for debugging purposes.
__ RecordPosition(position);
@ -1821,7 +1748,7 @@ void Ia32CodeGenerator::VisitIfStatement(IfStatement* node) {
Label then;
Label else_;
// if (cond)
LoadCondition(node->condition(), CodeGenState::LOAD, &then, &else_, true);
LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true);
Branch(false, &else_);
// then
__ bind(&then);
@ -1835,7 +1762,7 @@ void Ia32CodeGenerator::VisitIfStatement(IfStatement* node) {
ASSERT(!has_else_stm);
Label then;
// if (cond)
LoadCondition(node->condition(), CodeGenState::LOAD, &then, &exit, true);
LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &exit, true);
Branch(false, &exit);
// then
__ bind(&then);
@ -1845,7 +1772,7 @@ void Ia32CodeGenerator::VisitIfStatement(IfStatement* node) {
ASSERT(!has_then_stm);
Label else_;
// if (!cond)
LoadCondition(node->condition(), CodeGenState::LOAD, &exit, &else_, true);
LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &exit, &else_, true);
Branch(true, &exit);
// else
__ bind(&else_);
@ -1854,7 +1781,7 @@ void Ia32CodeGenerator::VisitIfStatement(IfStatement* node) {
} else {
ASSERT(!has_then_stm && !has_else_stm);
// if (cond)
LoadCondition(node->condition(), CodeGenState::LOAD, &exit, &exit, false);
LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &exit, &exit, false);
if (has_cc()) {
cc_reg_ = no_condition;
} else {
@ -2139,7 +2066,7 @@ void Ia32CodeGenerator::VisitLoopStatement(LoopStatement* node) {
case ALWAYS_FALSE:
break;
case DONT_KNOW:
LoadCondition(node->cond(), CodeGenState::LOAD, &loop,
LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &loop,
node->break_target(), true);
Branch(true, &loop);
break;
@ -2608,78 +2535,71 @@ void Ia32CodeGenerator::VisitFunctionBoilerplateLiteral(
void Ia32CodeGenerator::VisitConditional(Conditional* node) {
Comment cmnt(masm_, "[ Conditional");
Label then, else_, exit;
LoadCondition(node->condition(), CodeGenState::LOAD, &then, &else_, true);
LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true);
Branch(false, &else_);
__ bind(&then);
Load(node->then_expression(), access());
Load(node->then_expression(), typeof_state());
__ jmp(&exit);
__ bind(&else_);
Load(node->else_expression(), access());
Load(node->else_expression(), typeof_state());
__ bind(&exit);
}
void Ia32CodeGenerator::VisitSlot(Slot* node) {
ASSERT(access() != CodeGenState::UNDEFINED);
Comment cmnt(masm_, "[ Slot");
if (node->type() == Slot::LOOKUP) {
ASSERT(node->var()->mode() == Variable::DYNAMIC);
void Ia32CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) {
if (slot->type() == Slot::LOOKUP) {
ASSERT(slot->var()->mode() == Variable::DYNAMIC);
// For now, just do a runtime call.
__ push(Operand(esi));
__ push(Immediate(node->var()->name()));
__ push(esi);
__ push(Immediate(slot->var()->name()));
if (access() == CodeGenState::LOAD) {
__ CallRuntime(Runtime::kLoadContextSlot, 2);
} else {
ASSERT(access() == CodeGenState::LOAD_TYPEOF_EXPR);
if (typeof_state == INSIDE_TYPEOF) {
__ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
} else {
__ CallRuntime(Runtime::kLoadContextSlot, 2);
}
__ push(eax);
} else {
// Note: We would like to keep the assert below, but it fires because of
// some nasty code in LoadTypeofExpression() which should be removed...
// ASSERT(node->var()->mode() != Variable::DYNAMIC);
if (node->var()->mode() == Variable::CONST) {
// ASSERT(slot->var()->mode() != Variable::DYNAMIC);
if (slot->var()->mode() == Variable::CONST) {
// Const slots may contain 'the hole' value (the constant hasn't been
// initialized yet) which needs to be converted into the 'undefined'
// value.
Comment cmnt(masm_, "[ Load const");
Label L;
__ mov(eax, SlotOperand(node, ecx));
Label exit;
__ mov(eax, SlotOperand(slot, ecx));
__ cmp(eax, Factory::the_hole_value());
__ j(not_equal, &L);
__ j(not_equal, &exit);
__ mov(eax, Factory::undefined_value());
__ bind(&L);
__ bind(&exit);
__ push(eax);
} else {
__ push(SlotOperand(node, ecx));
__ push(SlotOperand(slot, ecx));
}
}
}
void Ia32CodeGenerator::VisitSlot(Slot* node) {
Comment cmnt(masm_, "[ Slot");
LoadFromSlot(node, typeof_state());
}
void Ia32CodeGenerator::VisitVariableProxy(VariableProxy* node) {
Comment cmnt(masm_, "[ VariableProxy");
Variable* var_node = node->var();
Expression* expr = var_node->rewrite();
Variable* var = node->var();
Expression* expr = var->rewrite();
if (expr != NULL) {
Visit(expr);
} else {
ASSERT(var_node->is_global());
if (is_referenced()) {
if (var_node->AsProperty() != NULL) {
__ RecordPosition(var_node->AsProperty()->position());
}
GetReferenceProperty(new Literal(var_node->name()));
} else {
Reference property(this, node);
GetValue(&property);
}
ASSERT(var->is_global());
Reference ref(this, node);
ref.GetValue(typeof_state());
}
}
@ -2942,7 +2862,7 @@ void Ia32CodeGenerator::VisitAssignment(Assignment* node) {
Load(node->value());
} else {
GetValue(&target);
target.GetValue(NOT_INSIDE_TYPEOF);
Literal* literal = node->value()->AsLiteral();
if (IsInlineSmi(literal)) {
SmiOperation(node->binary_op(), literal->handle(), false, NO_OVERWRITE);
@ -2983,15 +2903,8 @@ void Ia32CodeGenerator::VisitThrow(Throw* node) {
void Ia32CodeGenerator::VisitProperty(Property* node) {
Comment cmnt(masm_, "[ Property");
if (is_referenced()) {
__ RecordPosition(node->position());
GetReferenceProperty(node->key());
} else {
Reference property(this, node);
__ RecordPosition(node->position());
GetValue(&property);
}
Reference property(this, node);
property.GetValue(typeof_state());
}
@ -3090,7 +3003,7 @@ void Ia32CodeGenerator::VisitCall(Call* node) {
// Load the function to call from the property through a reference.
Reference ref(this, property);
GetValue(&ref);
ref.GetValue(NOT_INSIDE_TYPEOF);
// Pass receiver to called function.
// The reference's size is non-negative.
@ -3456,7 +3369,7 @@ void Ia32CodeGenerator::VisitUnaryOperation(UnaryOperation* node) {
Token::Value op = node->op();
if (op == Token::NOT) {
LoadCondition(node->expression(), CodeGenState::LOAD,
LoadCondition(node->expression(), NOT_INSIDE_TYPEOF,
false_target(), true_target(), true);
cc_reg_ = NegateCondition(cc_reg_);
@ -3677,7 +3590,7 @@ void Ia32CodeGenerator::VisitCountOperation(CountOperation* node) {
{ Reference target(this, node->expression());
if (target.is_illegal()) return;
GetValue(&target);
target.GetValue(NOT_INSIDE_TYPEOF);
int result_offset = target.size() * kPointerSize;
CountOperationDeferred* deferred =
@ -3732,14 +3645,14 @@ void Ia32CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
if (op == Token::AND) {
Label is_true;
LoadCondition(node->left(), CodeGenState::LOAD, &is_true,
LoadCondition(node->left(), NOT_INSIDE_TYPEOF, &is_true,
false_target(), false);
if (has_cc()) {
Branch(false, false_target());
// Evaluate right side expression.
__ bind(&is_true);
LoadCondition(node->right(), CodeGenState::LOAD, true_target(),
LoadCondition(node->right(), NOT_INSIDE_TYPEOF, true_target(),
false_target(), false);
} else {
@ -3768,14 +3681,14 @@ void Ia32CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
} else if (op == Token::OR) {
Label is_false;
LoadCondition(node->left(), CodeGenState::LOAD, true_target(),
LoadCondition(node->left(), NOT_INSIDE_TYPEOF, true_target(),
&is_false, false);
if (has_cc()) {
Branch(true, true_target());
// Evaluate right side expression.
__ bind(&is_false);
LoadCondition(node->right(), CodeGenState::LOAD, true_target(),
LoadCondition(node->right(), NOT_INSIDE_TYPEOF, true_target(),
false_target(), false);
} else {
@ -4090,6 +4003,87 @@ void Ia32CodeGenerator::ExitJSFrame() {
#undef __
#define __ masm->
Handle<String> Reference::GetName() {
ASSERT(type_ == NAMED);
Property* property = expression_->AsProperty();
if (property == NULL) {
// Global variable reference treated as a named property reference.
VariableProxy* proxy = expression_->AsVariableProxy();
ASSERT(proxy->AsVariable() != NULL);
ASSERT(proxy->AsVariable()->is_global());
return proxy->name();
} else {
MacroAssembler* masm = cgen_->masm();
__ RecordPosition(property->position());
Literal* raw_name = property->key()->AsLiteral();
ASSERT(raw_name != NULL);
return Handle<String>(String::cast(*raw_name->handle()));
}
}
void Reference::GetValue(TypeofState typeof_state) {
ASSERT(!is_illegal());
ASSERT(!cgen_->has_cc());
MacroAssembler* masm = cgen_->masm();
switch (type_) {
case SLOT: {
Comment cmnt(masm, "[ Load from Slot");
Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot();
ASSERT(slot != NULL);
cgen_->LoadFromSlot(slot, typeof_state);
break;
}
case NAMED: {
// TODO(1241834): Make sure that this it is safe to ignore the
// distinction between expressions in a typeof and not in a typeof. If
// there is a chance that reference errors can be thrown below, we
// must distinguish between the two kinds of loads (typeof expression
// loads must not throw a reference error).
Comment cmnt(masm, "[ Load from named Property");
Handle<String> name(GetName());
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
// Setup the name register.
__ mov(ecx, name);
Variable* var = expression_->AsVariableProxy()->AsVariable();
if (var != NULL) {
ASSERT(var->is_global());
__ call(ic, RelocInfo::CODE_TARGET_CONTEXT);
} else {
__ call(ic, RelocInfo::CODE_TARGET);
}
__ push(eax); // IC call leaves result in eax, push it out
break;
}
case KEYED: {
// TODO(1241834): Make sure that this it is safe to ignore the
// distinction between expressions in a typeof and not in a typeof.
Comment cmnt(masm, "[ Load from keyed Property");
Property* property = expression_->AsProperty();
ASSERT(property != NULL);
__ RecordPosition(property->position());
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
Variable* var = expression_->AsVariableProxy()->AsVariable();
if (var != NULL) {
ASSERT(var->is_global());
__ call(ic, RelocInfo::CODE_TARGET_CONTEXT);
} else {
__ call(ic, RelocInfo::CODE_TARGET);
}
__ push(eax); // IC call leaves result in eax, push it out
break;
}
default:
UNREACHABLE();
}
}
void Reference::SetValue(InitState init_state) {
ASSERT(!is_illegal());
ASSERT(!cgen_->has_cc());
@ -4172,22 +4166,8 @@ void Reference::SetValue(InitState init_state) {
case NAMED: {
Comment cmnt(masm, "[ Store to named Property");
Property* property = expression_->AsProperty();
Handle<String> name;
if (property == NULL) {
// Global variable reference treated as named property access.
VariableProxy* proxy = expression_->AsVariableProxy();
ASSERT(proxy->AsVariable() != NULL);
ASSERT(proxy->AsVariable()->is_global());
name = proxy->name();
} else {
Literal* raw_name = property->key()->AsLiteral();
ASSERT(raw_name != NULL);
name = Handle<String>(String::cast(*raw_name->handle()));
__ RecordPosition(property->position());
}
// Call the appropriate IC code.
Handle<String> name(GetName());
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
// TODO(1222589): Make the IC grab the values from the stack.
__ pop(eax);