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:
parent
d0b27552dc
commit
5d7f354384
@ -51,6 +51,7 @@ class ArmCodeGenerator;
|
|||||||
// on the execution stack to represent the reference.
|
// on the execution stack to represent the reference.
|
||||||
|
|
||||||
enum InitState { CONST_INIT, NOT_CONST_INIT };
|
enum InitState { CONST_INIT, NOT_CONST_INIT };
|
||||||
|
enum TypeofState { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF };
|
||||||
|
|
||||||
class Reference BASE_EMBEDDED {
|
class Reference BASE_EMBEDDED {
|
||||||
public:
|
public:
|
||||||
@ -72,6 +73,18 @@ class Reference BASE_EMBEDDED {
|
|||||||
bool is_slot() const { return type_ == SLOT; }
|
bool is_slot() const { return type_ == SLOT; }
|
||||||
bool is_property() const { return type_ == NAMED || type_ == KEYED; }
|
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);
|
void SetValue(InitState init_state);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -91,42 +104,29 @@ class Reference BASE_EMBEDDED {
|
|||||||
|
|
||||||
class CodeGenState BASE_EMBEDDED {
|
class CodeGenState BASE_EMBEDDED {
|
||||||
public:
|
public:
|
||||||
enum AccessType {
|
|
||||||
UNDEFINED,
|
|
||||||
LOAD,
|
|
||||||
LOAD_TYPEOF_EXPR
|
|
||||||
};
|
|
||||||
|
|
||||||
// Create an initial code generator state. Destroying the initial state
|
// Create an initial code generator state. Destroying the initial state
|
||||||
// leaves the code generator with a NULL state.
|
// leaves the code generator with a NULL state.
|
||||||
explicit CodeGenState(ArmCodeGenerator* owner);
|
explicit CodeGenState(ArmCodeGenerator* owner);
|
||||||
|
|
||||||
// Create a code generator state based on a code generator's current
|
// 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
|
// state. The new state has its own typeof state and pair of branch
|
||||||
// labels, and no reference.
|
// labels.
|
||||||
CodeGenState(ArmCodeGenerator* owner,
|
CodeGenState(ArmCodeGenerator* owner,
|
||||||
AccessType access,
|
TypeofState typeof_state,
|
||||||
Label* true_target,
|
Label* true_target,
|
||||||
Label* false_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
|
// Destroy a code generator state and restore the owning code generator's
|
||||||
// previous state.
|
// previous state.
|
||||||
~CodeGenState();
|
~CodeGenState();
|
||||||
|
|
||||||
AccessType access() const { return access_; }
|
TypeofState typeof_state() const { return typeof_state_; }
|
||||||
Reference* ref() const { return ref_; }
|
|
||||||
Label* true_target() const { return true_target_; }
|
Label* true_target() const { return true_target_; }
|
||||||
Label* false_target() const { return false_target_; }
|
Label* false_target() const { return false_target_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ArmCodeGenerator* owner_;
|
ArmCodeGenerator* owner_;
|
||||||
AccessType access_;
|
TypeofState typeof_state_;
|
||||||
Reference* ref_;
|
|
||||||
Label* true_target_;
|
Label* true_target_;
|
||||||
Label* false_target_;
|
Label* false_target_;
|
||||||
CodeGenState* previous_;
|
CodeGenState* previous_;
|
||||||
@ -178,9 +178,7 @@ class ArmCodeGenerator: public CodeGenerator {
|
|||||||
|
|
||||||
// State
|
// State
|
||||||
bool has_cc() const { return cc_reg_ != al; }
|
bool has_cc() const { return cc_reg_ != al; }
|
||||||
CodeGenState::AccessType access() const { return state_->access(); }
|
TypeofState typeof_state() const { return state_->typeof_state(); }
|
||||||
Reference* ref() const { return state_->ref(); }
|
|
||||||
bool is_referenced() const { return state_->ref() != NULL; }
|
|
||||||
Label* true_target() const { return state_->true_target(); }
|
Label* true_target() const { return state_->true_target(); }
|
||||||
Label* false_target() const { return state_->false_target(); }
|
Label* false_target() const { return state_->false_target(); }
|
||||||
|
|
||||||
@ -209,12 +207,17 @@ class ArmCodeGenerator: public CodeGenerator {
|
|||||||
|
|
||||||
MemOperand SlotOperand(Slot* slot, Register tmp);
|
MemOperand SlotOperand(Slot* slot, Register tmp);
|
||||||
|
|
||||||
void LoadCondition(Expression* x, CodeGenState::AccessType access,
|
void LoadCondition(Expression* x,
|
||||||
Label* true_target, Label* false_target, bool force_cc);
|
TypeofState typeof_state,
|
||||||
void Load(Expression* x,
|
Label* true_target,
|
||||||
CodeGenState::AccessType access = CodeGenState::LOAD);
|
Label* false_target,
|
||||||
|
bool force_cc);
|
||||||
|
void Load(Expression* x, TypeofState typeof_state = NOT_INSIDE_TYPEOF);
|
||||||
void LoadGlobal();
|
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
|
// Special code for typeof expressions: Unfortunately, we must
|
||||||
// be careful when loading the expression in 'typeof'
|
// be careful when loading the expression in 'typeof'
|
||||||
// expressions. We are not allowed to throw reference errors for
|
// expressions. We are not allowed to throw reference errors for
|
||||||
@ -223,24 +226,6 @@ class ArmCodeGenerator: public CodeGenerator {
|
|||||||
// through the context chain.
|
// through the context chain.
|
||||||
void LoadTypeofExpression(Expression* x);
|
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 ToBoolean(Label* true_target, Label* false_target);
|
||||||
|
|
||||||
void GenericBinaryOperation(Token::Value op);
|
void GenericBinaryOperation(Token::Value op);
|
||||||
@ -309,8 +294,7 @@ class ArmCodeGenerator: public CodeGenerator {
|
|||||||
|
|
||||||
CodeGenState::CodeGenState(ArmCodeGenerator* owner)
|
CodeGenState::CodeGenState(ArmCodeGenerator* owner)
|
||||||
: owner_(owner),
|
: owner_(owner),
|
||||||
access_(UNDEFINED),
|
typeof_state_(NOT_INSIDE_TYPEOF),
|
||||||
ref_(NULL),
|
|
||||||
true_target_(NULL),
|
true_target_(NULL),
|
||||||
false_target_(NULL),
|
false_target_(NULL),
|
||||||
previous_(NULL) {
|
previous_(NULL) {
|
||||||
@ -319,12 +303,11 @@ CodeGenState::CodeGenState(ArmCodeGenerator* owner)
|
|||||||
|
|
||||||
|
|
||||||
CodeGenState::CodeGenState(ArmCodeGenerator* owner,
|
CodeGenState::CodeGenState(ArmCodeGenerator* owner,
|
||||||
AccessType access,
|
TypeofState typeof_state,
|
||||||
Label* true_target,
|
Label* true_target,
|
||||||
Label* false_target)
|
Label* false_target)
|
||||||
: owner_(owner),
|
: owner_(owner),
|
||||||
access_(access),
|
typeof_state_(typeof_state),
|
||||||
ref_(NULL),
|
|
||||||
true_target_(true_target),
|
true_target_(true_target),
|
||||||
false_target_(false_target),
|
false_target_(false_target),
|
||||||
previous_(owner->state()) {
|
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() {
|
CodeGenState::~CodeGenState() {
|
||||||
ASSERT(owner_->state() == this);
|
ASSERT(owner_->state() == this);
|
||||||
owner_->set_state(previous_);
|
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,
|
// 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'.
|
// has_cc() is true and cc_reg_ contains the condition to test for 'true'.
|
||||||
void ArmCodeGenerator::LoadCondition(Expression* x,
|
void ArmCodeGenerator::LoadCondition(Expression* x,
|
||||||
CodeGenState::AccessType access,
|
TypeofState typeof_state,
|
||||||
Label* true_target,
|
Label* true_target,
|
||||||
Label* false_target,
|
Label* false_target,
|
||||||
bool force_cc) {
|
bool force_cc) {
|
||||||
ASSERT(access == CodeGenState::LOAD ||
|
ASSERT(!has_cc());
|
||||||
access == CodeGenState::LOAD_TYPEOF_EXPR);
|
|
||||||
ASSERT(!has_cc() && !is_referenced());
|
|
||||||
|
|
||||||
{ CodeGenState new_state(this, access, true_target, false_target);
|
{ CodeGenState new_state(this, typeof_state, true_target, false_target);
|
||||||
Visit(x);
|
Visit(x);
|
||||||
}
|
}
|
||||||
if (force_cc && !has_cc()) {
|
if (force_cc && !has_cc()) {
|
||||||
@ -727,13 +697,10 @@ void ArmCodeGenerator::LoadCondition(Expression* x,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ArmCodeGenerator::Load(Expression* x, CodeGenState::AccessType access) {
|
void ArmCodeGenerator::Load(Expression* x, TypeofState typeof_state) {
|
||||||
ASSERT(access == CodeGenState::LOAD ||
|
|
||||||
access == CodeGenState::LOAD_TYPEOF_EXPR);
|
|
||||||
|
|
||||||
Label true_target;
|
Label true_target;
|
||||||
Label false_target;
|
Label false_target;
|
||||||
LoadCondition(x, access, &true_target, &false_target, false);
|
LoadCondition(x, typeof_state, &true_target, &false_target, false);
|
||||||
|
|
||||||
if (has_cc()) {
|
if (has_cc()) {
|
||||||
// convert cc_reg_ into a bool
|
// 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
|
// 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
|
// that we have the INSIDE_TYPEOF typeof state. => Need to handle global
|
||||||
// global variables w/o reference errors elsewhere.
|
// variables w/o reference errors elsewhere.
|
||||||
void ArmCodeGenerator::LoadTypeofExpression(Expression* x) {
|
void ArmCodeGenerator::LoadTypeofExpression(Expression* x) {
|
||||||
Variable* variable = x->AsVariableProxy()->AsVariable();
|
Variable* variable = x->AsVariableProxy()->AsVariable();
|
||||||
if (variable != NULL && !variable->is_this() && variable->is_global()) {
|
if (variable != NULL && !variable->is_this() && variable->is_global()) {
|
||||||
@ -801,7 +768,7 @@ void ArmCodeGenerator::LoadTypeofExpression(Expression* x) {
|
|||||||
Property property(&global, &key, RelocInfo::kNoPosition);
|
Property property(&global, &key, RelocInfo::kNoPosition);
|
||||||
Load(&property);
|
Load(&property);
|
||||||
} else {
|
} else {
|
||||||
Load(x, CodeGenState::LOAD_TYPEOF_EXPR);
|
Load(x, INSIDE_TYPEOF);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -818,6 +785,7 @@ Reference::~Reference() {
|
|||||||
|
|
||||||
|
|
||||||
void ArmCodeGenerator::LoadReference(Reference* ref) {
|
void ArmCodeGenerator::LoadReference(Reference* ref) {
|
||||||
|
Comment cmnt(masm_, "[ LoadReference");
|
||||||
Expression* e = ref->expression();
|
Expression* e = ref->expression();
|
||||||
Property* property = e->AsProperty();
|
Property* property = e->AsProperty();
|
||||||
Variable* var = e->AsVariableProxy()->AsVariable();
|
Variable* var = e->AsVariableProxy()->AsVariable();
|
||||||
@ -859,6 +827,7 @@ void ArmCodeGenerator::LoadReference(Reference* ref) {
|
|||||||
|
|
||||||
|
|
||||||
void ArmCodeGenerator::UnloadReference(Reference* ref) {
|
void ArmCodeGenerator::UnloadReference(Reference* ref) {
|
||||||
|
Comment cmnt(masm_, "[ UnloadReference");
|
||||||
int size = ref->size();
|
int size = ref->size();
|
||||||
if (size <= 0) {
|
if (size <= 0) {
|
||||||
// Do nothing. No popping is necessary.
|
// 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) {
|
void ArmCodeGenerator::GenericBinaryOperation(Token::Value op) {
|
||||||
// sp[0] : y
|
// sp[0] : y
|
||||||
// sp[1] : x
|
// sp[1] : x
|
||||||
@ -1527,7 +1459,7 @@ void ArmCodeGenerator::VisitIfStatement(IfStatement* node) {
|
|||||||
Label then;
|
Label then;
|
||||||
Label else_;
|
Label else_;
|
||||||
// if (cond)
|
// if (cond)
|
||||||
LoadCondition(node->condition(), CodeGenState::LOAD, &then, &else_, true);
|
LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true);
|
||||||
Branch(false, &else_);
|
Branch(false, &else_);
|
||||||
// then
|
// then
|
||||||
__ bind(&then);
|
__ bind(&then);
|
||||||
@ -1542,7 +1474,7 @@ void ArmCodeGenerator::VisitIfStatement(IfStatement* node) {
|
|||||||
ASSERT(!has_else_stm);
|
ASSERT(!has_else_stm);
|
||||||
Label then;
|
Label then;
|
||||||
// if (cond)
|
// if (cond)
|
||||||
LoadCondition(node->condition(), CodeGenState::LOAD, &then, &exit, true);
|
LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &exit, true);
|
||||||
Branch(false, &exit);
|
Branch(false, &exit);
|
||||||
// then
|
// then
|
||||||
__ bind(&then);
|
__ bind(&then);
|
||||||
@ -1553,7 +1485,7 @@ void ArmCodeGenerator::VisitIfStatement(IfStatement* node) {
|
|||||||
ASSERT(!has_then_stm);
|
ASSERT(!has_then_stm);
|
||||||
Label else_;
|
Label else_;
|
||||||
// if (!cond)
|
// if (!cond)
|
||||||
LoadCondition(node->condition(), CodeGenState::LOAD, &exit, &else_, true);
|
LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &exit, &else_, true);
|
||||||
Branch(true, &exit);
|
Branch(true, &exit);
|
||||||
// else
|
// else
|
||||||
__ bind(&else_);
|
__ bind(&else_);
|
||||||
@ -1563,7 +1495,7 @@ void ArmCodeGenerator::VisitIfStatement(IfStatement* node) {
|
|||||||
Comment cmnt(masm_, "[ If");
|
Comment cmnt(masm_, "[ If");
|
||||||
ASSERT(!has_then_stm && !has_else_stm);
|
ASSERT(!has_then_stm && !has_else_stm);
|
||||||
// if (cond)
|
// if (cond)
|
||||||
LoadCondition(node->condition(), CodeGenState::LOAD, &exit, &exit, false);
|
LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &exit, &exit, false);
|
||||||
if (has_cc()) {
|
if (has_cc()) {
|
||||||
cc_reg_ = al;
|
cc_reg_ = al;
|
||||||
} else {
|
} else {
|
||||||
@ -1806,7 +1738,7 @@ void ArmCodeGenerator::VisitLoopStatement(LoopStatement* node) {
|
|||||||
case DONT_KNOW:
|
case DONT_KNOW:
|
||||||
CheckStack(); // TODO(1222600): ignore if body contains calls.
|
CheckStack(); // TODO(1222600): ignore if body contains calls.
|
||||||
LoadCondition(node->cond(),
|
LoadCondition(node->cond(),
|
||||||
CodeGenState::LOAD,
|
NOT_INSIDE_TYPEOF,
|
||||||
&loop,
|
&loop,
|
||||||
node->break_target(),
|
node->break_target(),
|
||||||
true);
|
true);
|
||||||
@ -1972,7 +1904,6 @@ void ArmCodeGenerator::VisitForInStatement(ForInStatement* node) {
|
|||||||
{ Reference each(this, node->each());
|
{ Reference each(this, node->each());
|
||||||
if (!each.is_illegal()) {
|
if (!each.is_illegal()) {
|
||||||
if (each.size() > 0) {
|
if (each.size() > 0) {
|
||||||
// Reference's size is positive.
|
|
||||||
__ ldr(r0, MemOperand(sp, kPointerSize * each.size()));
|
__ ldr(r0, MemOperand(sp, kPointerSize * each.size()));
|
||||||
__ push(r0);
|
__ push(r0);
|
||||||
}
|
}
|
||||||
@ -2273,46 +2204,42 @@ void ArmCodeGenerator::VisitFunctionBoilerplateLiteral(
|
|||||||
void ArmCodeGenerator::VisitConditional(Conditional* node) {
|
void ArmCodeGenerator::VisitConditional(Conditional* node) {
|
||||||
Comment cmnt(masm_, "[ Conditional");
|
Comment cmnt(masm_, "[ Conditional");
|
||||||
Label then, else_, exit;
|
Label then, else_, exit;
|
||||||
LoadCondition(node->condition(), CodeGenState::LOAD, &then, &else_, true);
|
LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true);
|
||||||
Branch(false, &else_);
|
Branch(false, &else_);
|
||||||
__ bind(&then);
|
__ bind(&then);
|
||||||
Load(node->then_expression(), access());
|
Load(node->then_expression(), typeof_state());
|
||||||
__ b(&exit);
|
__ b(&exit);
|
||||||
__ bind(&else_);
|
__ bind(&else_);
|
||||||
Load(node->else_expression(), access());
|
Load(node->else_expression(), typeof_state());
|
||||||
__ bind(&exit);
|
__ bind(&exit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ArmCodeGenerator::VisitSlot(Slot* node) {
|
void ArmCodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) {
|
||||||
ASSERT(access() != CodeGenState::UNDEFINED);
|
if (slot->type() == Slot::LOOKUP) {
|
||||||
Comment cmnt(masm_, "[ Slot");
|
ASSERT(slot->var()->mode() == Variable::DYNAMIC);
|
||||||
|
|
||||||
if (node->type() == Slot::LOOKUP) {
|
|
||||||
ASSERT(node->var()->mode() == Variable::DYNAMIC);
|
|
||||||
|
|
||||||
// For now, just do a runtime call.
|
// For now, just do a runtime call.
|
||||||
__ push(cp);
|
__ push(cp);
|
||||||
__ mov(r0, Operand(node->var()->name()));
|
__ mov(r0, Operand(slot->var()->name()));
|
||||||
__ push(r0);
|
__ push(r0);
|
||||||
|
|
||||||
if (access() == CodeGenState::LOAD) {
|
if (typeof_state == INSIDE_TYPEOF) {
|
||||||
__ CallRuntime(Runtime::kLoadContextSlot, 2);
|
|
||||||
} else {
|
|
||||||
ASSERT(access() == CodeGenState::LOAD_TYPEOF_EXPR);
|
|
||||||
__ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
|
__ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
|
||||||
|
} else {
|
||||||
|
__ CallRuntime(Runtime::kLoadContextSlot, 2);
|
||||||
}
|
}
|
||||||
__ push(r0);
|
__ push(r0);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Note: We would like to keep the assert below, but it fires because of
|
// Note: We would like to keep the assert below, but it fires because of
|
||||||
// some nasty code in LoadTypeofExpression() which should be removed...
|
// 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.
|
// Special handling for locals allocated in registers.
|
||||||
__ ldr(r0, SlotOperand(node, r2));
|
__ ldr(r0, SlotOperand(slot, r2));
|
||||||
__ push(r0);
|
__ 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
|
// Const slots may contain 'the hole' value (the constant hasn't been
|
||||||
// initialized yet) which needs to be converted into the 'undefined'
|
// initialized yet) which needs to be converted into the 'undefined'
|
||||||
// value.
|
// 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) {
|
void ArmCodeGenerator::VisitVariableProxy(VariableProxy* node) {
|
||||||
Comment cmnt(masm_, "[ VariableProxy");
|
Comment cmnt(masm_, "[ VariableProxy");
|
||||||
Variable* var_node = node->var();
|
Variable* var = node->var();
|
||||||
|
Expression* expr = var->rewrite();
|
||||||
Expression* expr = var_node->rewrite();
|
|
||||||
if (expr != NULL) {
|
if (expr != NULL) {
|
||||||
Visit(expr);
|
Visit(expr);
|
||||||
} else {
|
} else {
|
||||||
ASSERT(var_node->is_global());
|
ASSERT(var->is_global());
|
||||||
if (is_referenced()) {
|
Reference ref(this, node);
|
||||||
if (var_node->AsProperty() != NULL) {
|
ref.GetValue(typeof_state());
|
||||||
__ RecordPosition(var_node->AsProperty()->position());
|
|
||||||
}
|
|
||||||
GetReferenceProperty(new Literal(var_node->name()));
|
|
||||||
} else {
|
|
||||||
Reference property(this, node);
|
|
||||||
GetValue(&property);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2556,7 +2481,7 @@ void ArmCodeGenerator::VisitAssignment(Assignment* node) {
|
|||||||
Load(node->value());
|
Load(node->value());
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
GetValue(&target);
|
target.GetValue(NOT_INSIDE_TYPEOF);
|
||||||
Literal* literal = node->value()->AsLiteral();
|
Literal* literal = node->value()->AsLiteral();
|
||||||
if (literal != NULL && literal->handle()->IsSmi()) {
|
if (literal != NULL && literal->handle()->IsSmi()) {
|
||||||
SmiOperation(node->binary_op(), literal->handle(), false);
|
SmiOperation(node->binary_op(), literal->handle(), false);
|
||||||
@ -2601,15 +2526,8 @@ void ArmCodeGenerator::VisitThrow(Throw* node) {
|
|||||||
|
|
||||||
void ArmCodeGenerator::VisitProperty(Property* node) {
|
void ArmCodeGenerator::VisitProperty(Property* node) {
|
||||||
Comment cmnt(masm_, "[ Property");
|
Comment cmnt(masm_, "[ Property");
|
||||||
|
Reference property(this, node);
|
||||||
if (is_referenced()) {
|
property.GetValue(typeof_state());
|
||||||
__ RecordPosition(node->position());
|
|
||||||
GetReferenceProperty(node->key());
|
|
||||||
} else {
|
|
||||||
Reference property(this, node);
|
|
||||||
__ RecordPosition(node->position());
|
|
||||||
GetValue(&property);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2713,7 +2631,7 @@ void ArmCodeGenerator::VisitCall(Call* node) {
|
|||||||
|
|
||||||
// Load the function to call from the property through a reference.
|
// Load the function to call from the property through a reference.
|
||||||
Reference ref(this, property);
|
Reference ref(this, property);
|
||||||
GetValue(&ref); // receiver
|
ref.GetValue(NOT_INSIDE_TYPEOF); // receiver
|
||||||
|
|
||||||
// Pass receiver to called function.
|
// Pass receiver to called function.
|
||||||
__ ldr(r0, MemOperand(sp, ref.size() * kPointerSize));
|
__ ldr(r0, MemOperand(sp, ref.size() * kPointerSize));
|
||||||
@ -2957,7 +2875,7 @@ void ArmCodeGenerator::VisitUnaryOperation(UnaryOperation* node) {
|
|||||||
|
|
||||||
if (op == Token::NOT) {
|
if (op == Token::NOT) {
|
||||||
LoadCondition(node->expression(),
|
LoadCondition(node->expression(),
|
||||||
CodeGenState::LOAD,
|
NOT_INSIDE_TYPEOF,
|
||||||
false_target(),
|
false_target(),
|
||||||
true_target(),
|
true_target(),
|
||||||
true);
|
true);
|
||||||
@ -3092,7 +3010,7 @@ void ArmCodeGenerator::VisitCountOperation(CountOperation* node) {
|
|||||||
|
|
||||||
{ Reference target(this, node->expression());
|
{ Reference target(this, node->expression());
|
||||||
if (target.is_illegal()) return;
|
if (target.is_illegal()) return;
|
||||||
GetValue(&target);
|
target.GetValue(NOT_INSIDE_TYPEOF);
|
||||||
__ pop(r0);
|
__ pop(r0);
|
||||||
|
|
||||||
Label slow, exit;
|
Label slow, exit;
|
||||||
@ -3174,7 +3092,7 @@ void ArmCodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
|
|||||||
if (op == Token::AND) {
|
if (op == Token::AND) {
|
||||||
Label is_true;
|
Label is_true;
|
||||||
LoadCondition(node->left(),
|
LoadCondition(node->left(),
|
||||||
CodeGenState::LOAD,
|
NOT_INSIDE_TYPEOF,
|
||||||
&is_true,
|
&is_true,
|
||||||
false_target(),
|
false_target(),
|
||||||
false);
|
false);
|
||||||
@ -3184,7 +3102,7 @@ void ArmCodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
|
|||||||
// Evaluate right side expression.
|
// Evaluate right side expression.
|
||||||
__ bind(&is_true);
|
__ bind(&is_true);
|
||||||
LoadCondition(node->right(),
|
LoadCondition(node->right(),
|
||||||
CodeGenState::LOAD,
|
NOT_INSIDE_TYPEOF,
|
||||||
true_target(),
|
true_target(),
|
||||||
false_target(),
|
false_target(),
|
||||||
false);
|
false);
|
||||||
@ -3215,7 +3133,7 @@ void ArmCodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
|
|||||||
} else if (op == Token::OR) {
|
} else if (op == Token::OR) {
|
||||||
Label is_false;
|
Label is_false;
|
||||||
LoadCondition(node->left(),
|
LoadCondition(node->left(),
|
||||||
CodeGenState::LOAD,
|
NOT_INSIDE_TYPEOF,
|
||||||
true_target(),
|
true_target(),
|
||||||
&is_false,
|
&is_false,
|
||||||
false);
|
false);
|
||||||
@ -3225,7 +3143,7 @@ void ArmCodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
|
|||||||
// Evaluate right side expression.
|
// Evaluate right side expression.
|
||||||
__ bind(&is_false);
|
__ bind(&is_false);
|
||||||
LoadCondition(node->right(),
|
LoadCondition(node->right(),
|
||||||
CodeGenState::LOAD,
|
NOT_INSIDE_TYPEOF,
|
||||||
true_target(),
|
true_target(),
|
||||||
false_target(),
|
false_target(),
|
||||||
false);
|
false);
|
||||||
@ -3517,10 +3435,91 @@ void ArmCodeGenerator::ExitJSFrame() {
|
|||||||
#undef __
|
#undef __
|
||||||
#define __ masm->
|
#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) {
|
void Reference::SetValue(InitState init_state) {
|
||||||
ASSERT(!is_illegal());
|
ASSERT(!is_illegal());
|
||||||
ASSERT(!cgen_->has_cc());
|
ASSERT(!cgen_->has_cc());
|
||||||
MacroAssembler* masm = cgen_->masm();
|
MacroAssembler* masm = cgen_->masm();
|
||||||
|
Property* property = expression_->AsProperty();
|
||||||
|
if (property != NULL) {
|
||||||
|
__ RecordPosition(property->position());
|
||||||
|
}
|
||||||
|
|
||||||
switch (type_) {
|
switch (type_) {
|
||||||
case SLOT: {
|
case SLOT: {
|
||||||
Comment cmnt(masm, "[ Store to Slot");
|
Comment cmnt(masm, "[ Store to Slot");
|
||||||
@ -3606,24 +3605,10 @@ void Reference::SetValue(InitState init_state) {
|
|||||||
|
|
||||||
case NAMED: {
|
case NAMED: {
|
||||||
Comment cmnt(masm, "[ Store to named Property");
|
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.
|
// Call the appropriate IC code.
|
||||||
__ pop(r0); // value
|
__ pop(r0); // value
|
||||||
// Setup the name register.
|
// Setup the name register.
|
||||||
|
Handle<String> name(GetName());
|
||||||
__ mov(r2, Operand(name));
|
__ mov(r2, Operand(name));
|
||||||
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
|
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
|
||||||
__ Call(ic, RelocInfo::CODE_TARGET);
|
__ Call(ic, RelocInfo::CODE_TARGET);
|
||||||
|
@ -57,6 +57,7 @@ enum OverwriteMode { NO_OVERWRITE, OVERWRITE_LEFT, OVERWRITE_RIGHT };
|
|||||||
// on the execution stack to represent the reference.
|
// on the execution stack to represent the reference.
|
||||||
|
|
||||||
enum InitState { CONST_INIT, NOT_CONST_INIT };
|
enum InitState { CONST_INIT, NOT_CONST_INIT };
|
||||||
|
enum TypeofState { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF };
|
||||||
|
|
||||||
class Reference BASE_EMBEDDED {
|
class Reference BASE_EMBEDDED {
|
||||||
public:
|
public:
|
||||||
@ -79,6 +80,18 @@ class Reference BASE_EMBEDDED {
|
|||||||
bool is_slot() const { return type_ == SLOT; }
|
bool is_slot() const { return type_ == SLOT; }
|
||||||
bool is_property() const { return type_ == NAMED || type_ == KEYED; }
|
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);
|
void SetValue(InitState init_state);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -98,42 +111,29 @@ class Reference BASE_EMBEDDED {
|
|||||||
|
|
||||||
class CodeGenState BASE_EMBEDDED {
|
class CodeGenState BASE_EMBEDDED {
|
||||||
public:
|
public:
|
||||||
enum AccessType {
|
|
||||||
UNDEFINED,
|
|
||||||
LOAD,
|
|
||||||
LOAD_TYPEOF_EXPR
|
|
||||||
};
|
|
||||||
|
|
||||||
// Create an initial code generator state. Destroying the initial state
|
// Create an initial code generator state. Destroying the initial state
|
||||||
// leaves the code generator with a NULL state.
|
// leaves the code generator with a NULL state.
|
||||||
explicit CodeGenState(Ia32CodeGenerator* owner);
|
explicit CodeGenState(Ia32CodeGenerator* owner);
|
||||||
|
|
||||||
// Create a code generator state based on a code generator's current
|
// 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
|
// state. The new state has its own typeof state and pair of branch
|
||||||
// labels, and no reference.
|
// labels.
|
||||||
CodeGenState(Ia32CodeGenerator* owner,
|
CodeGenState(Ia32CodeGenerator* owner,
|
||||||
AccessType access,
|
TypeofState typeof_state,
|
||||||
Label* true_target,
|
Label* true_target,
|
||||||
Label* false_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
|
// Destroy a code generator state and restore the owning code generator's
|
||||||
// previous state.
|
// previous state.
|
||||||
~CodeGenState();
|
~CodeGenState();
|
||||||
|
|
||||||
AccessType access() const { return access_; }
|
TypeofState typeof_state() const { return typeof_state_; }
|
||||||
Reference* ref() const { return ref_; }
|
|
||||||
Label* true_target() const { return true_target_; }
|
Label* true_target() const { return true_target_; }
|
||||||
Label* false_target() const { return false_target_; }
|
Label* false_target() const { return false_target_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ia32CodeGenerator* owner_;
|
Ia32CodeGenerator* owner_;
|
||||||
AccessType access_;
|
TypeofState typeof_state_;
|
||||||
Reference* ref_;
|
|
||||||
Label* true_target_;
|
Label* true_target_;
|
||||||
Label* false_target_;
|
Label* false_target_;
|
||||||
CodeGenState* previous_;
|
CodeGenState* previous_;
|
||||||
@ -185,9 +185,7 @@ class Ia32CodeGenerator: public CodeGenerator {
|
|||||||
|
|
||||||
// State
|
// State
|
||||||
bool has_cc() const { return cc_reg_ >= 0; }
|
bool has_cc() const { return cc_reg_ >= 0; }
|
||||||
CodeGenState::AccessType access() const { return state_->access(); }
|
TypeofState typeof_state() const { return state_->typeof_state(); }
|
||||||
Reference* ref() const { return state_->ref(); }
|
|
||||||
bool is_referenced() const { return state_->ref() != NULL; }
|
|
||||||
Label* true_target() const { return state_->true_target(); }
|
Label* true_target() const { return state_->true_target(); }
|
||||||
Label* false_target() const { return state_->false_target(); }
|
Label* false_target() const { return state_->false_target(); }
|
||||||
|
|
||||||
@ -216,14 +214,16 @@ class Ia32CodeGenerator: public CodeGenerator {
|
|||||||
Operand SlotOperand(Slot* slot, Register tmp);
|
Operand SlotOperand(Slot* slot, Register tmp);
|
||||||
|
|
||||||
void LoadCondition(Expression* x,
|
void LoadCondition(Expression* x,
|
||||||
CodeGenState::AccessType access,
|
TypeofState typeof_state,
|
||||||
Label* true_target,
|
Label* true_target,
|
||||||
Label* false_target,
|
Label* false_target,
|
||||||
bool force_cc);
|
bool force_cc);
|
||||||
void Load(Expression* x,
|
void Load(Expression* x, TypeofState typeof_state = NOT_INSIDE_TYPEOF);
|
||||||
CodeGenState::AccessType access = CodeGenState::LOAD);
|
|
||||||
void LoadGlobal();
|
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
|
// Special code for typeof expressions: Unfortunately, we must
|
||||||
// be careful when loading the expression in 'typeof'
|
// be careful when loading the expression in 'typeof'
|
||||||
// expressions. We are not allowed to throw reference errors for
|
// expressions. We are not allowed to throw reference errors for
|
||||||
@ -232,23 +232,6 @@ class Ia32CodeGenerator: public CodeGenerator {
|
|||||||
// through the context chain.
|
// through the context chain.
|
||||||
void LoadTypeofExpression(Expression* x);
|
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 ToBoolean(Label* true_target, Label* false_target);
|
||||||
|
|
||||||
void GenericBinaryOperation(
|
void GenericBinaryOperation(
|
||||||
@ -340,8 +323,7 @@ class Ia32CodeGenerator: public CodeGenerator {
|
|||||||
|
|
||||||
CodeGenState::CodeGenState(Ia32CodeGenerator* owner)
|
CodeGenState::CodeGenState(Ia32CodeGenerator* owner)
|
||||||
: owner_(owner),
|
: owner_(owner),
|
||||||
access_(UNDEFINED),
|
typeof_state_(NOT_INSIDE_TYPEOF),
|
||||||
ref_(NULL),
|
|
||||||
true_target_(NULL),
|
true_target_(NULL),
|
||||||
false_target_(NULL),
|
false_target_(NULL),
|
||||||
previous_(NULL) {
|
previous_(NULL) {
|
||||||
@ -350,12 +332,11 @@ CodeGenState::CodeGenState(Ia32CodeGenerator* owner)
|
|||||||
|
|
||||||
|
|
||||||
CodeGenState::CodeGenState(Ia32CodeGenerator* owner,
|
CodeGenState::CodeGenState(Ia32CodeGenerator* owner,
|
||||||
AccessType access,
|
TypeofState typeof_state,
|
||||||
Label* true_target,
|
Label* true_target,
|
||||||
Label* false_target)
|
Label* false_target)
|
||||||
: owner_(owner),
|
: owner_(owner),
|
||||||
access_(access),
|
typeof_state_(typeof_state),
|
||||||
ref_(NULL),
|
|
||||||
true_target_(true_target),
|
true_target_(true_target),
|
||||||
false_target_(false_target),
|
false_target_(false_target),
|
||||||
previous_(owner->state()) {
|
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() {
|
CodeGenState::~CodeGenState() {
|
||||||
ASSERT(owner_->state() == this);
|
ASSERT(owner_->state() == this);
|
||||||
owner_->set_state(previous_);
|
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,
|
// 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'.
|
// has_cc() is true and cc_reg_ contains the condition to test for 'true'.
|
||||||
void Ia32CodeGenerator::LoadCondition(Expression* x,
|
void Ia32CodeGenerator::LoadCondition(Expression* x,
|
||||||
CodeGenState::AccessType access,
|
TypeofState typeof_state,
|
||||||
Label* true_target,
|
Label* true_target,
|
||||||
Label* false_target,
|
Label* false_target,
|
||||||
bool force_cc) {
|
bool force_cc) {
|
||||||
ASSERT(access == CodeGenState::LOAD ||
|
ASSERT(!has_cc());
|
||||||
access == CodeGenState::LOAD_TYPEOF_EXPR);
|
|
||||||
ASSERT(!has_cc() && !is_referenced());
|
|
||||||
|
|
||||||
{ CodeGenState new_state(this, access, true_target, false_target);
|
{ CodeGenState new_state(this, typeof_state, true_target, false_target);
|
||||||
Visit(x);
|
Visit(x);
|
||||||
}
|
}
|
||||||
if (force_cc && !has_cc()) {
|
if (force_cc && !has_cc()) {
|
||||||
@ -777,13 +745,10 @@ void Ia32CodeGenerator::LoadCondition(Expression* x,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Ia32CodeGenerator::Load(Expression* x, CodeGenState::AccessType access) {
|
void Ia32CodeGenerator::Load(Expression* x, TypeofState typeof_state) {
|
||||||
ASSERT(access == CodeGenState::LOAD ||
|
|
||||||
access == CodeGenState::LOAD_TYPEOF_EXPR);
|
|
||||||
|
|
||||||
Label true_target;
|
Label true_target;
|
||||||
Label false_target;
|
Label false_target;
|
||||||
LoadCondition(x, access, &true_target, &false_target, false);
|
LoadCondition(x, typeof_state, &true_target, &false_target, false);
|
||||||
|
|
||||||
if (has_cc()) {
|
if (has_cc()) {
|
||||||
// convert cc_reg_ into a bool
|
// 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
|
// 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
|
// that we have the INSIDE_TYPEOF typeof state. => Need to handle global
|
||||||
// global variables w/o reference errors elsewhere.
|
// variables w/o reference errors elsewhere.
|
||||||
void Ia32CodeGenerator::LoadTypeofExpression(Expression* x) {
|
void Ia32CodeGenerator::LoadTypeofExpression(Expression* x) {
|
||||||
Variable* variable = x->AsVariableProxy()->AsVariable();
|
Variable* variable = x->AsVariableProxy()->AsVariable();
|
||||||
if (variable != NULL && !variable->is_this() && variable->is_global()) {
|
if (variable != NULL && !variable->is_this() && variable->is_global()) {
|
||||||
@ -847,7 +812,7 @@ void Ia32CodeGenerator::LoadTypeofExpression(Expression* x) {
|
|||||||
Property property(&global, &key, RelocInfo::kNoPosition);
|
Property property(&global, &key, RelocInfo::kNoPosition);
|
||||||
Load(&property);
|
Load(&property);
|
||||||
} else {
|
} else {
|
||||||
Load(x, CodeGenState::LOAD_TYPEOF_EXPR);
|
Load(x, INSIDE_TYPEOF);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -864,6 +829,7 @@ Reference::~Reference() {
|
|||||||
|
|
||||||
|
|
||||||
void Ia32CodeGenerator::LoadReference(Reference* ref) {
|
void Ia32CodeGenerator::LoadReference(Reference* ref) {
|
||||||
|
Comment cmnt(masm_, "[ LoadReference");
|
||||||
Expression* e = ref->expression();
|
Expression* e = ref->expression();
|
||||||
Property* property = e->AsProperty();
|
Property* property = e->AsProperty();
|
||||||
Variable* var = e->AsVariableProxy()->AsVariable();
|
Variable* var = e->AsVariableProxy()->AsVariable();
|
||||||
@ -905,7 +871,7 @@ void Ia32CodeGenerator::LoadReference(Reference* ref) {
|
|||||||
|
|
||||||
|
|
||||||
void Ia32CodeGenerator::UnloadReference(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");
|
Comment cmnt(masm_, "[ UnloadReference");
|
||||||
int size = ref->size();
|
int size = ref->size();
|
||||||
if (size <= 0) {
|
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 {
|
class FloatingPointHelper : public AllStatic {
|
||||||
public:
|
public:
|
||||||
// Code pattern for loading floating point values. Input values must
|
// Code pattern for loading floating point values. Input values must
|
||||||
@ -1676,7 +1601,9 @@ class CallFunctionStub: public CodeStub {
|
|||||||
void Ia32CodeGenerator::CallWithArguments(ZoneList<Expression*>* args,
|
void Ia32CodeGenerator::CallWithArguments(ZoneList<Expression*>* args,
|
||||||
int position) {
|
int position) {
|
||||||
// Push the arguments ("left-to-right") on the stack.
|
// 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.
|
// Record the position for debugging purposes.
|
||||||
__ RecordPosition(position);
|
__ RecordPosition(position);
|
||||||
@ -1821,7 +1748,7 @@ void Ia32CodeGenerator::VisitIfStatement(IfStatement* node) {
|
|||||||
Label then;
|
Label then;
|
||||||
Label else_;
|
Label else_;
|
||||||
// if (cond)
|
// if (cond)
|
||||||
LoadCondition(node->condition(), CodeGenState::LOAD, &then, &else_, true);
|
LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true);
|
||||||
Branch(false, &else_);
|
Branch(false, &else_);
|
||||||
// then
|
// then
|
||||||
__ bind(&then);
|
__ bind(&then);
|
||||||
@ -1835,7 +1762,7 @@ void Ia32CodeGenerator::VisitIfStatement(IfStatement* node) {
|
|||||||
ASSERT(!has_else_stm);
|
ASSERT(!has_else_stm);
|
||||||
Label then;
|
Label then;
|
||||||
// if (cond)
|
// if (cond)
|
||||||
LoadCondition(node->condition(), CodeGenState::LOAD, &then, &exit, true);
|
LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &exit, true);
|
||||||
Branch(false, &exit);
|
Branch(false, &exit);
|
||||||
// then
|
// then
|
||||||
__ bind(&then);
|
__ bind(&then);
|
||||||
@ -1845,7 +1772,7 @@ void Ia32CodeGenerator::VisitIfStatement(IfStatement* node) {
|
|||||||
ASSERT(!has_then_stm);
|
ASSERT(!has_then_stm);
|
||||||
Label else_;
|
Label else_;
|
||||||
// if (!cond)
|
// if (!cond)
|
||||||
LoadCondition(node->condition(), CodeGenState::LOAD, &exit, &else_, true);
|
LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &exit, &else_, true);
|
||||||
Branch(true, &exit);
|
Branch(true, &exit);
|
||||||
// else
|
// else
|
||||||
__ bind(&else_);
|
__ bind(&else_);
|
||||||
@ -1854,7 +1781,7 @@ void Ia32CodeGenerator::VisitIfStatement(IfStatement* node) {
|
|||||||
} else {
|
} else {
|
||||||
ASSERT(!has_then_stm && !has_else_stm);
|
ASSERT(!has_then_stm && !has_else_stm);
|
||||||
// if (cond)
|
// if (cond)
|
||||||
LoadCondition(node->condition(), CodeGenState::LOAD, &exit, &exit, false);
|
LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &exit, &exit, false);
|
||||||
if (has_cc()) {
|
if (has_cc()) {
|
||||||
cc_reg_ = no_condition;
|
cc_reg_ = no_condition;
|
||||||
} else {
|
} else {
|
||||||
@ -2139,7 +2066,7 @@ void Ia32CodeGenerator::VisitLoopStatement(LoopStatement* node) {
|
|||||||
case ALWAYS_FALSE:
|
case ALWAYS_FALSE:
|
||||||
break;
|
break;
|
||||||
case DONT_KNOW:
|
case DONT_KNOW:
|
||||||
LoadCondition(node->cond(), CodeGenState::LOAD, &loop,
|
LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &loop,
|
||||||
node->break_target(), true);
|
node->break_target(), true);
|
||||||
Branch(true, &loop);
|
Branch(true, &loop);
|
||||||
break;
|
break;
|
||||||
@ -2608,78 +2535,71 @@ void Ia32CodeGenerator::VisitFunctionBoilerplateLiteral(
|
|||||||
void Ia32CodeGenerator::VisitConditional(Conditional* node) {
|
void Ia32CodeGenerator::VisitConditional(Conditional* node) {
|
||||||
Comment cmnt(masm_, "[ Conditional");
|
Comment cmnt(masm_, "[ Conditional");
|
||||||
Label then, else_, exit;
|
Label then, else_, exit;
|
||||||
LoadCondition(node->condition(), CodeGenState::LOAD, &then, &else_, true);
|
LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true);
|
||||||
Branch(false, &else_);
|
Branch(false, &else_);
|
||||||
__ bind(&then);
|
__ bind(&then);
|
||||||
Load(node->then_expression(), access());
|
Load(node->then_expression(), typeof_state());
|
||||||
__ jmp(&exit);
|
__ jmp(&exit);
|
||||||
__ bind(&else_);
|
__ bind(&else_);
|
||||||
Load(node->else_expression(), access());
|
Load(node->else_expression(), typeof_state());
|
||||||
__ bind(&exit);
|
__ bind(&exit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Ia32CodeGenerator::VisitSlot(Slot* node) {
|
void Ia32CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) {
|
||||||
ASSERT(access() != CodeGenState::UNDEFINED);
|
if (slot->type() == Slot::LOOKUP) {
|
||||||
Comment cmnt(masm_, "[ Slot");
|
ASSERT(slot->var()->mode() == Variable::DYNAMIC);
|
||||||
|
|
||||||
if (node->type() == Slot::LOOKUP) {
|
|
||||||
ASSERT(node->var()->mode() == Variable::DYNAMIC);
|
|
||||||
|
|
||||||
// For now, just do a runtime call.
|
// For now, just do a runtime call.
|
||||||
__ push(Operand(esi));
|
__ push(esi);
|
||||||
__ push(Immediate(node->var()->name()));
|
__ push(Immediate(slot->var()->name()));
|
||||||
|
|
||||||
if (access() == CodeGenState::LOAD) {
|
if (typeof_state == INSIDE_TYPEOF) {
|
||||||
__ CallRuntime(Runtime::kLoadContextSlot, 2);
|
|
||||||
} else {
|
|
||||||
ASSERT(access() == CodeGenState::LOAD_TYPEOF_EXPR);
|
|
||||||
__ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
|
__ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
|
||||||
|
} else {
|
||||||
|
__ CallRuntime(Runtime::kLoadContextSlot, 2);
|
||||||
}
|
}
|
||||||
__ push(eax);
|
__ push(eax);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Note: We would like to keep the assert below, but it fires because of
|
// Note: We would like to keep the assert below, but it fires because of
|
||||||
// some nasty code in LoadTypeofExpression() which should be removed...
|
// some nasty code in LoadTypeofExpression() which should be removed...
|
||||||
// ASSERT(node->var()->mode() != Variable::DYNAMIC);
|
// ASSERT(slot->var()->mode() != Variable::DYNAMIC);
|
||||||
|
if (slot->var()->mode() == Variable::CONST) {
|
||||||
if (node->var()->mode() == Variable::CONST) {
|
|
||||||
// Const slots may contain 'the hole' value (the constant hasn't been
|
// Const slots may contain 'the hole' value (the constant hasn't been
|
||||||
// initialized yet) which needs to be converted into the 'undefined'
|
// initialized yet) which needs to be converted into the 'undefined'
|
||||||
// value.
|
// value.
|
||||||
Comment cmnt(masm_, "[ Load const");
|
Comment cmnt(masm_, "[ Load const");
|
||||||
Label L;
|
Label exit;
|
||||||
__ mov(eax, SlotOperand(node, ecx));
|
__ mov(eax, SlotOperand(slot, ecx));
|
||||||
__ cmp(eax, Factory::the_hole_value());
|
__ cmp(eax, Factory::the_hole_value());
|
||||||
__ j(not_equal, &L);
|
__ j(not_equal, &exit);
|
||||||
__ mov(eax, Factory::undefined_value());
|
__ mov(eax, Factory::undefined_value());
|
||||||
__ bind(&L);
|
__ bind(&exit);
|
||||||
__ push(eax);
|
__ push(eax);
|
||||||
} else {
|
} 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) {
|
void Ia32CodeGenerator::VisitVariableProxy(VariableProxy* node) {
|
||||||
Comment cmnt(masm_, "[ VariableProxy");
|
Comment cmnt(masm_, "[ VariableProxy");
|
||||||
Variable* var_node = node->var();
|
Variable* var = node->var();
|
||||||
|
Expression* expr = var->rewrite();
|
||||||
Expression* expr = var_node->rewrite();
|
|
||||||
if (expr != NULL) {
|
if (expr != NULL) {
|
||||||
Visit(expr);
|
Visit(expr);
|
||||||
} else {
|
} else {
|
||||||
ASSERT(var_node->is_global());
|
ASSERT(var->is_global());
|
||||||
if (is_referenced()) {
|
Reference ref(this, node);
|
||||||
if (var_node->AsProperty() != NULL) {
|
ref.GetValue(typeof_state());
|
||||||
__ RecordPosition(var_node->AsProperty()->position());
|
|
||||||
}
|
|
||||||
GetReferenceProperty(new Literal(var_node->name()));
|
|
||||||
} else {
|
|
||||||
Reference property(this, node);
|
|
||||||
GetValue(&property);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2942,7 +2862,7 @@ void Ia32CodeGenerator::VisitAssignment(Assignment* node) {
|
|||||||
Load(node->value());
|
Load(node->value());
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
GetValue(&target);
|
target.GetValue(NOT_INSIDE_TYPEOF);
|
||||||
Literal* literal = node->value()->AsLiteral();
|
Literal* literal = node->value()->AsLiteral();
|
||||||
if (IsInlineSmi(literal)) {
|
if (IsInlineSmi(literal)) {
|
||||||
SmiOperation(node->binary_op(), literal->handle(), false, NO_OVERWRITE);
|
SmiOperation(node->binary_op(), literal->handle(), false, NO_OVERWRITE);
|
||||||
@ -2983,15 +2903,8 @@ void Ia32CodeGenerator::VisitThrow(Throw* node) {
|
|||||||
|
|
||||||
void Ia32CodeGenerator::VisitProperty(Property* node) {
|
void Ia32CodeGenerator::VisitProperty(Property* node) {
|
||||||
Comment cmnt(masm_, "[ Property");
|
Comment cmnt(masm_, "[ Property");
|
||||||
|
Reference property(this, node);
|
||||||
if (is_referenced()) {
|
property.GetValue(typeof_state());
|
||||||
__ RecordPosition(node->position());
|
|
||||||
GetReferenceProperty(node->key());
|
|
||||||
} else {
|
|
||||||
Reference property(this, node);
|
|
||||||
__ RecordPosition(node->position());
|
|
||||||
GetValue(&property);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -3090,7 +3003,7 @@ void Ia32CodeGenerator::VisitCall(Call* node) {
|
|||||||
|
|
||||||
// Load the function to call from the property through a reference.
|
// Load the function to call from the property through a reference.
|
||||||
Reference ref(this, property);
|
Reference ref(this, property);
|
||||||
GetValue(&ref);
|
ref.GetValue(NOT_INSIDE_TYPEOF);
|
||||||
|
|
||||||
// Pass receiver to called function.
|
// Pass receiver to called function.
|
||||||
// The reference's size is non-negative.
|
// The reference's size is non-negative.
|
||||||
@ -3456,7 +3369,7 @@ void Ia32CodeGenerator::VisitUnaryOperation(UnaryOperation* node) {
|
|||||||
Token::Value op = node->op();
|
Token::Value op = node->op();
|
||||||
|
|
||||||
if (op == Token::NOT) {
|
if (op == Token::NOT) {
|
||||||
LoadCondition(node->expression(), CodeGenState::LOAD,
|
LoadCondition(node->expression(), NOT_INSIDE_TYPEOF,
|
||||||
false_target(), true_target(), true);
|
false_target(), true_target(), true);
|
||||||
cc_reg_ = NegateCondition(cc_reg_);
|
cc_reg_ = NegateCondition(cc_reg_);
|
||||||
|
|
||||||
@ -3677,7 +3590,7 @@ void Ia32CodeGenerator::VisitCountOperation(CountOperation* node) {
|
|||||||
|
|
||||||
{ Reference target(this, node->expression());
|
{ Reference target(this, node->expression());
|
||||||
if (target.is_illegal()) return;
|
if (target.is_illegal()) return;
|
||||||
GetValue(&target);
|
target.GetValue(NOT_INSIDE_TYPEOF);
|
||||||
|
|
||||||
int result_offset = target.size() * kPointerSize;
|
int result_offset = target.size() * kPointerSize;
|
||||||
CountOperationDeferred* deferred =
|
CountOperationDeferred* deferred =
|
||||||
@ -3732,14 +3645,14 @@ void Ia32CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
|
|||||||
|
|
||||||
if (op == Token::AND) {
|
if (op == Token::AND) {
|
||||||
Label is_true;
|
Label is_true;
|
||||||
LoadCondition(node->left(), CodeGenState::LOAD, &is_true,
|
LoadCondition(node->left(), NOT_INSIDE_TYPEOF, &is_true,
|
||||||
false_target(), false);
|
false_target(), false);
|
||||||
if (has_cc()) {
|
if (has_cc()) {
|
||||||
Branch(false, false_target());
|
Branch(false, false_target());
|
||||||
|
|
||||||
// Evaluate right side expression.
|
// Evaluate right side expression.
|
||||||
__ bind(&is_true);
|
__ bind(&is_true);
|
||||||
LoadCondition(node->right(), CodeGenState::LOAD, true_target(),
|
LoadCondition(node->right(), NOT_INSIDE_TYPEOF, true_target(),
|
||||||
false_target(), false);
|
false_target(), false);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@ -3768,14 +3681,14 @@ void Ia32CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
|
|||||||
|
|
||||||
} else if (op == Token::OR) {
|
} else if (op == Token::OR) {
|
||||||
Label is_false;
|
Label is_false;
|
||||||
LoadCondition(node->left(), CodeGenState::LOAD, true_target(),
|
LoadCondition(node->left(), NOT_INSIDE_TYPEOF, true_target(),
|
||||||
&is_false, false);
|
&is_false, false);
|
||||||
if (has_cc()) {
|
if (has_cc()) {
|
||||||
Branch(true, true_target());
|
Branch(true, true_target());
|
||||||
|
|
||||||
// Evaluate right side expression.
|
// Evaluate right side expression.
|
||||||
__ bind(&is_false);
|
__ bind(&is_false);
|
||||||
LoadCondition(node->right(), CodeGenState::LOAD, true_target(),
|
LoadCondition(node->right(), NOT_INSIDE_TYPEOF, true_target(),
|
||||||
false_target(), false);
|
false_target(), false);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@ -4090,6 +4003,87 @@ void Ia32CodeGenerator::ExitJSFrame() {
|
|||||||
#undef __
|
#undef __
|
||||||
#define __ masm->
|
#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) {
|
void Reference::SetValue(InitState init_state) {
|
||||||
ASSERT(!is_illegal());
|
ASSERT(!is_illegal());
|
||||||
ASSERT(!cgen_->has_cc());
|
ASSERT(!cgen_->has_cc());
|
||||||
@ -4172,22 +4166,8 @@ void Reference::SetValue(InitState init_state) {
|
|||||||
|
|
||||||
case NAMED: {
|
case NAMED: {
|
||||||
Comment cmnt(masm, "[ Store to named Property");
|
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.
|
// Call the appropriate IC code.
|
||||||
|
Handle<String> name(GetName());
|
||||||
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
|
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
|
||||||
// TODO(1222589): Make the IC grab the values from the stack.
|
// TODO(1222589): Make the IC grab the values from the stack.
|
||||||
__ pop(eax);
|
__ pop(eax);
|
||||||
|
Loading…
Reference in New Issue
Block a user