Introduce a hydrogen value for contexts, support context slot assignment.

Each context in the context chain has a corresponding hydrogen value.
The context values are used for global object lookup and context slot
lookup.  Add simple (non-compound) assignment to context slots.

Review URL: http://codereview.chromium.org/6390003

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@6615 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent a2fb4a12
......@@ -258,7 +258,15 @@ void LUnaryMathOperation::PrintDataTo(StringStream* stream) {
void LLoadContextSlot::PrintDataTo(StringStream* stream) {
stream->Add("(%d, %d)", context_chain_length(), slot_index());
InputAt(0)->PrintTo(stream);
stream->Add("[%d]", slot_index());
}
void LStoreContextSlot::PrintDataTo(StringStream* stream) {
InputAt(0)->PrintTo(stream);
stream->Add("[%d] <- ", slot_index());
InputAt(1)->PrintTo(stream);
}
......@@ -1105,13 +1113,26 @@ LInstruction* LChunkBuilder::DoPushArgument(HPushArgument* instr) {
}
LInstruction* LChunkBuilder::DoContext(HContext* instr) {
return DefineAsRegister(new LContext);
}
LInstruction* LChunkBuilder::DoOuterContext(HOuterContext* instr) {
LOperand* context = UseRegisterAtStart(instr->value());
return DefineAsRegister(new LOuterContext(context));
}
LInstruction* LChunkBuilder::DoGlobalObject(HGlobalObject* instr) {
return DefineAsRegister(new LGlobalObject);
LOperand* context = UseRegisterAtStart(instr->value());
return DefineAsRegister(new LGlobalObject(context));
}
LInstruction* LChunkBuilder::DoGlobalReceiver(HGlobalReceiver* instr) {
return DefineAsRegister(new LGlobalReceiver);
LOperand* global_object = UseRegisterAtStart(instr->value());
return DefineAsRegister(new LGlobalReceiver(global_object));
}
......@@ -1621,7 +1642,20 @@ LInstruction* LChunkBuilder::DoStoreGlobal(HStoreGlobal* instr) {
LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) {
return DefineAsRegister(new LLoadContextSlot);
LOperand* context = UseRegisterAtStart(instr->value());
return DefineAsRegister(new LLoadContextSlot(context));
}
LInstruction* LChunkBuilder::DoStoreContextSlot(HStoreContextSlot* instr) {
LOperand* context = UseTempRegister(instr->context());
LOperand* value;
if (instr->NeedsWriteBarrier()) {
value = UseTempRegister(instr->value());
} else {
value = UseRegister(instr->value());
}
return new LStoreContextSlot(context, value);
}
......
......@@ -39,118 +39,6 @@ namespace internal {
// Forward declarations.
class LCodeGen;
// Type hierarchy:
//
// LInstruction
// LTemplateInstruction
// LControlInstruction
// LBranch
// LClassOfTestAndBranch
// LCmpJSObjectEqAndBranch
// LCmpIDAndBranch
// LHasCachedArrayIndexAndBranch
// LHasInstanceTypeAndBranch
// LInstanceOfAndBranch
// LIsNullAndBranch
// LIsObjectAndBranch
// LIsSmiAndBranch
// LTypeofIsAndBranch
// LAccessArgumentsAt
// LArgumentsElements
// LArgumentsLength
// LAddI
// LApplyArguments
// LArithmeticD
// LArithmeticT
// LBitI
// LBoundsCheck
// LCmpID
// LCmpJSObjectEq
// LCmpT
// LDivI
// LInstanceOf
// LInstanceOfKnownGlobal
// LLoadKeyedFastElement
// LLoadKeyedGeneric
// LModI
// LMulI
// LPower
// LShiftI
// LSubI
// LCallConstantFunction
// LCallFunction
// LCallGlobal
// LCallKeyed
// LCallKnownGlobal
// LCallNamed
// LCallRuntime
// LCallStub
// LConstant
// LConstantD
// LConstantI
// LConstantT
// LDeoptimize
// LFunctionLiteral
// LGap
// LLabel
// LGlobalObject
// LGlobalReceiver
// LGoto
// LLazyBailout
// LLoadGlobal
// LCheckPrototypeMaps
// LLoadContextSlot
// LArrayLiteral
// LObjectLiteral
// LRegExpLiteral
// LOsrEntry
// LParameter
// LRegExpConstructResult
// LStackCheck
// LStoreKeyed
// LStoreKeyedFastElement
// LStoreKeyedGeneric
// LStoreNamed
// LStoreNamedField
// LStoreNamedGeneric
// LStringCharCodeAt
// LBitNotI
// LCallNew
// LCheckFunction
// LCheckPrototypeMaps
// LCheckInstanceType
// LCheckMap
// LCheckSmi
// LClassOfTest
// LDeleteProperty
// LDoubleToI
// LFixedArrayLength
// LHasCachedArrayIndex
// LHasInstanceType
// LInteger32ToDouble
// LIsNull
// LIsObject
// LIsSmi
// LJSArrayLength
// LLoadNamedField
// LLoadNamedGeneric
// LLoadFunctionPrototype
// LNumberTagD
// LNumberTagI
// LPushArgument
// LReturn
// LSmiTag
// LStoreGlobal
// LStringLength
// LTaggedToI
// LThrow
// LTypeof
// LTypeofIs
// LUnaryMathOperation
// LValueOf
// LUnknownOSRValue
#define LITHIUM_ALL_INSTRUCTION_LIST(V) \
V(ControlInstruction) \
V(Constant) \
......@@ -187,6 +75,8 @@ class LCodeGen;
V(CheckMap) \
V(CheckPrototypeMaps) \
V(CheckSmi) \
V(ClassOfTest) \
V(ClassOfTestAndBranch) \
V(CmpID) \
V(CmpIDAndBranch) \
V(CmpJSObjectEq) \
......@@ -197,6 +87,7 @@ class LCodeGen;
V(ConstantD) \
V(ConstantI) \
V(ConstantT) \
V(Context) \
V(DeleteProperty) \
V(Deoptimize) \
V(DivI) \
......@@ -207,6 +98,10 @@ class LCodeGen;
V(GlobalObject) \
V(GlobalReceiver) \
V(Goto) \
V(HasCachedArrayIndex) \
V(HasCachedArrayIndexAndBranch) \
V(HasInstanceType) \
V(HasInstanceTypeAndBranch) \
V(InstanceOf) \
V(InstanceOfAndBranch) \
V(InstanceOfKnownGlobal) \
......@@ -218,22 +113,16 @@ class LCodeGen;
V(IsSmi) \
V(IsSmiAndBranch) \
V(JSArrayLength) \
V(HasInstanceType) \
V(HasInstanceTypeAndBranch) \
V(HasCachedArrayIndex) \
V(HasCachedArrayIndexAndBranch) \
V(ClassOfTest) \
V(ClassOfTestAndBranch) \
V(Label) \
V(LazyBailout) \
V(LoadContextSlot) \
V(LoadElements) \
V(LoadFunctionPrototype) \
V(LoadGlobal) \
V(LoadKeyedFastElement) \
V(LoadKeyedGeneric) \
V(LoadNamedField) \
V(LoadNamedGeneric) \
V(LoadFunctionPrototype) \
V(ModI) \
V(MulI) \
V(NumberTagD) \
......@@ -241,6 +130,7 @@ class LCodeGen;
V(NumberUntagD) \
V(ObjectLiteral) \
V(OsrEntry) \
V(OuterContext) \
V(Parameter) \
V(PushArgument) \
V(RegExpLiteral) \
......@@ -249,14 +139,15 @@ class LCodeGen;
V(SmiTag) \
V(SmiUntag) \
V(StackCheck) \
V(StoreContextSlot) \
V(StoreGlobal) \
V(StoreKeyedFastElement) \
V(StoreKeyedGeneric) \
V(StoreNamedField) \
V(StoreNamedGeneric) \
V(SubI) \
V(StringCharCodeAt) \
V(StringLength) \
V(SubI) \
V(TaggedToI) \
V(Throw) \
V(Typeof) \
......@@ -1266,13 +1157,36 @@ class LStoreGlobal: public LTemplateInstruction<0, 1, 1> {
};
class LLoadContextSlot: public LTemplateInstruction<1, 0, 0> {
class LLoadContextSlot: public LTemplateInstruction<1, 1, 0> {
public:
explicit LLoadContextSlot(LOperand* context) {
inputs_[0] = context;
}
DECLARE_CONCRETE_INSTRUCTION(LoadContextSlot, "load-context-slot")
DECLARE_HYDROGEN_ACCESSOR(LoadContextSlot)
int context_chain_length() { return hydrogen()->context_chain_length(); }
LOperand* context() { return InputAt(0); }
int slot_index() { return hydrogen()->slot_index(); }
virtual void PrintDataTo(StringStream* stream);
};
class LStoreContextSlot: public LTemplateInstruction<0, 2, 0> {
public:
LStoreContextSlot(LOperand* context, LOperand* value) {
inputs_[0] = context;
inputs_[1] = value;
}
DECLARE_CONCRETE_INSTRUCTION(StoreContextSlot, "store-context-slot")
DECLARE_HYDROGEN_ACCESSOR(StoreContextSlot)
LOperand* context() { return InputAt(0); }
LOperand* value() { return InputAt(1); }
int slot_index() { return hydrogen()->slot_index(); }
int needs_write_barrier() { return hydrogen()->NeedsWriteBarrier(); }
virtual void PrintDataTo(StringStream* stream);
};
......@@ -1288,15 +1202,45 @@ class LPushArgument: public LTemplateInstruction<0, 1, 0> {
};
class LGlobalObject: public LTemplateInstruction<1, 0, 0> {
class LContext: public LTemplateInstruction<1, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(Context, "context")
};
class LOuterContext: public LTemplateInstruction<1, 1, 0> {
public:
explicit LOuterContext(LOperand* context) {
inputs_[0] = context;
}
DECLARE_CONCRETE_INSTRUCTION(OuterContext, "outer-context")
LOperand* context() { return InputAt(0); }
};
class LGlobalObject: public LTemplateInstruction<1, 1, 0> {
public:
explicit LGlobalObject(LOperand* context) {
inputs_[0] = context;
}
DECLARE_CONCRETE_INSTRUCTION(GlobalObject, "global-object")
LOperand* context() { return InputAt(0); }
};
class LGlobalReceiver: public LTemplateInstruction<1, 0, 0> {
class LGlobalReceiver: public LTemplateInstruction<1, 1, 0> {
public:
explicit LGlobalReceiver(LOperand* global_object) {
inputs_[0] = global_object;
}
DECLARE_CONCRETE_INSTRUCTION(GlobalReceiver, "global-receiver")
LOperand* global() { return InputAt(0); }
};
......
......@@ -2212,13 +2212,27 @@ void LCodeGen::DoStoreGlobal(LStoreGlobal* instr) {
void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
// TODO(antonm): load a context with a separate instruction.
Register context = ToRegister(instr->context());
Register result = ToRegister(instr->result());
__ LoadContext(result, instr->context_chain_length());
__ ldr(result,
MemOperand(context, Context::SlotOffset(Context::FCONTEXT_INDEX)));
__ ldr(result, ContextOperand(result, instr->slot_index()));
}
void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
Register context = ToRegister(instr->context());
Register value = ToRegister(instr->value());
__ ldr(context,
MemOperand(context, Context::SlotOffset(Context::FCONTEXT_INDEX)));
__ str(value, ContextOperand(context, instr->slot_index()));
if (instr->needs_write_barrier()) {
int offset = Context::SlotOffset(instr->slot_index());
__ RecordWrite(context, Operand(offset), value, scratch0());
}
}
void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
Register object = ToRegister(instr->InputAt(0));
Register result = ToRegister(instr->result());
......@@ -2469,16 +2483,32 @@ void LCodeGen::DoPushArgument(LPushArgument* instr) {
}
void LCodeGen::DoContext(LContext* instr) {
Register result = ToRegister(instr->result());
__ mov(result, cp);
}
void LCodeGen::DoOuterContext(LOuterContext* instr) {
Register context = ToRegister(instr->context());
Register result = ToRegister(instr->result());
__ ldr(result,
MemOperand(context, Context::SlotOffset(Context::CLOSURE_INDEX)));
__ ldr(result, FieldMemOperand(result, JSFunction::kContextOffset));
}
void LCodeGen::DoGlobalObject(LGlobalObject* instr) {
Register context = ToRegister(instr->context());
Register result = ToRegister(instr->result());
__ ldr(result, ContextOperand(cp, Context::GLOBAL_INDEX));
}
void LCodeGen::DoGlobalReceiver(LGlobalReceiver* instr) {
Register global = ToRegister(instr->global());
Register result = ToRegister(instr->result());
__ ldr(result, ContextOperand(cp, Context::GLOBAL_INDEX));
__ ldr(result, FieldMemOperand(result, GlobalObject::kGlobalReceiverOffset));
__ ldr(result, FieldMemOperand(global, GlobalObject::kGlobalReceiverOffset));
}
......
......@@ -1193,7 +1193,15 @@ void HStoreGlobal::PrintDataTo(StringStream* stream) const {
void HLoadContextSlot::PrintDataTo(StringStream* stream) const {
stream->Add("(%d, %d)", context_chain_length(), slot_index());
value()->PrintNameTo(stream);
stream->Add("[%d]", slot_index());
}
void HStoreContextSlot::PrintDataTo(StringStream* stream) const {
context()->PrintNameTo(stream);
stream->Add("[%d] = ", slot_index());
value()->PrintNameTo(stream);
}
......
......@@ -98,6 +98,7 @@ class LChunkBuilder;
V(CompareJSObjectEq) \
V(CompareMap) \
V(Constant) \
V(Context) \
V(DeleteProperty) \
V(Deoptimize) \
V(Div) \
......@@ -129,6 +130,7 @@ class LChunkBuilder;
V(Mul) \
V(ObjectLiteral) \
V(OsrEntry) \
V(OuterContext) \
V(Parameter) \
V(Power) \
V(PushArgument) \
......@@ -139,6 +141,7 @@ class LChunkBuilder;
V(Shr) \
V(Simulate) \
V(StackCheck) \
V(StoreContextSlot) \
V(StoreGlobal) \
V(StoreKeyedFastElement) \
V(StoreKeyedGeneric) \
......@@ -163,6 +166,7 @@ class LChunkBuilder;
V(GlobalVars) \
V(Maps) \
V(ArrayLengths) \
V(ContextSlots) \
V(OsrEntries)
#define DECLARE_INSTRUCTION(type) \
......@@ -1060,12 +1064,39 @@ class HPushArgument: public HUnaryOperation {
};
class HGlobalObject: public HInstruction {
class HContext: public HInstruction {
public:
HGlobalObject() {
HContext() {
set_representation(Representation::Tagged());
SetFlag(kUseGVN);
}
DECLARE_CONCRETE_INSTRUCTION(Context, "context");
protected:
virtual bool DataEquals(HValue* other) const { return true; }
};
class HOuterContext: public HUnaryOperation {
public:
explicit HOuterContext(HValue* inner) : HUnaryOperation(inner) {
set_representation(Representation::Tagged());
SetFlag(kUseGVN);
}
DECLARE_CONCRETE_INSTRUCTION(OuterContext, "outer_context");
protected:
virtual bool DataEquals(HValue* other) const { return true; }
};
class HGlobalObject: public HUnaryOperation {
public:
explicit HGlobalObject(HValue* context) : HUnaryOperation(context) {
set_representation(Representation::Tagged());
SetFlag(kUseGVN);
SetFlag(kDependsOnCalls);
}
DECLARE_CONCRETE_INSTRUCTION(GlobalObject, "global_object")
......@@ -1075,12 +1106,12 @@ class HGlobalObject: public HInstruction {
};
class HGlobalReceiver: public HInstruction {
class HGlobalReceiver: public HUnaryOperation {
public:
HGlobalReceiver() {
explicit HGlobalReceiver(HValue* global_object)
: HUnaryOperation(global_object) {
set_representation(Representation::Tagged());
SetFlag(kUseGVN);
SetFlag(kDependsOnCalls);
}
DECLARE_CONCRETE_INSTRUCTION(GlobalReceiver, "global_receiver")
......@@ -2613,35 +2644,66 @@ class HStoreGlobal: public HUnaryOperation {
};
class HLoadContextSlot: public HInstruction {
class HLoadContextSlot: public HUnaryOperation {
public:
HLoadContextSlot(int context_chain_length , int slot_index)
: context_chain_length_(context_chain_length), slot_index_(slot_index) {
HLoadContextSlot(HValue* context , int slot_index)
: HUnaryOperation(context), slot_index_(slot_index) {
set_representation(Representation::Tagged());
SetFlag(kUseGVN);
SetFlag(kDependsOnCalls);
SetFlag(kDependsOnContextSlots);
}
int context_chain_length() const { return context_chain_length_; }
int slot_index() const { return slot_index_; }
virtual void PrintDataTo(StringStream* stream) const;
virtual intptr_t Hashcode() const {
return context_chain_length() * 29 + slot_index();
virtual Representation RequiredInputRepresentation(int index) const {
return Representation::Tagged();
}
virtual void PrintDataTo(StringStream* stream) const;
DECLARE_CONCRETE_INSTRUCTION(LoadContextSlot, "load_context_slot")
protected:
virtual bool DataEquals(HValue* other) const {
HLoadContextSlot* b = HLoadContextSlot::cast(other);
return (context_chain_length() == b->context_chain_length())
&& (slot_index() == b->slot_index());
return (slot_index() == b->slot_index());
}
private:
int context_chain_length_;
int slot_index_;
};
static inline bool StoringValueNeedsWriteBarrier(HValue* value) {
return !value->type().IsSmi() &&
!(value->IsConstant() && HConstant::cast(value)->InOldSpace());
}
class HStoreContextSlot: public HBinaryOperation {
public:
HStoreContextSlot(HValue* context, int slot_index, HValue* value)
: HBinaryOperation(context, value), slot_index_(slot_index) {
SetFlag(kChangesContextSlots);
}
HValue* context() const { return OperandAt(0); }
HValue* value() const { return OperandAt(1); }
int slot_index() const { return slot_index_; }
bool NeedsWriteBarrier() const {
return StoringValueNeedsWriteBarrier(value());
}
virtual Representation RequiredInputRepresentation(int index) const {
return Representation::Tagged();
}
virtual void PrintDataTo(StringStream* stream) const;
DECLARE_CONCRETE_INSTRUCTION(StoreContextSlot, "store_context_slot")
private:
int slot_index_;
};
......@@ -2777,12 +2839,6 @@ class HLoadKeyedGeneric: public HLoadKeyed {
};
static inline bool StoringValueNeedsWriteBarrier(HValue* value) {
return !value->type().IsSmi() &&
!(value->IsConstant() && HConstant::cast(value)->InOldSpace());
}
class HStoreNamed: public HBinaryOperation {
public:
HStoreNamed(HValue* obj, Handle<Object> name, HValue* val)
......@@ -2800,10 +2856,6 @@ class HStoreNamed: public HBinaryOperation {
HValue* value() const { return OperandAt(1); }
void set_value(HValue* value) { SetOperandAt(1, value); }
bool NeedsWriteBarrier() const {
return StoringValueNeedsWriteBarrier(value());
}
DECLARE_INSTRUCTION(StoreNamed)
private:
......@@ -2831,7 +2883,7 @@ class HStoreNamedField: public HStoreNamed {
DECLARE_CONCRETE_INSTRUCTION(StoreNamedField, "store_named_field")
virtual Representation RequiredInputRepresentation(int index) const {
return Representation::Tagged();
return Representation::Tagged();
}
virtual void PrintDataTo(StringStream* stream) const;
......@@ -2840,6 +2892,10 @@ class HStoreNamedField: public HStoreNamed {
Handle<Map> transition() const { return transition_; }
void set_transition(Handle<Map> map) { transition_ = map; }
bool NeedsWriteBarrier() const {
return StoringValueNeedsWriteBarrier(value());
}
private:
bool is_in_object_;
int offset_;
......
......@@ -2955,6 +2955,19 @@ void HGraphBuilder::LookupGlobalPropertyCell(Variable* var,
}
HValue* HGraphBuilder::BuildContextChainWalk(Variable* var) {
ASSERT(var->IsContextSlot());
HInstruction* context = new HContext;
AddInstruction(context);
int length = graph()->info()->scope()->ContextChainLength(var->scope());
while (length-- > 0) {
context = new HOuterContext(context);
AddInstruction(context);
}
return context;
}
void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
Variable* variable = expr->AsVariable();
if (variable == NULL) {
......@@ -2968,16 +2981,9 @@ void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
if (variable->mode() == Variable::CONST) {
BAILOUT("reference to const context slot");
}
Slot* slot = variable->AsSlot();
CompilationInfo* info = graph()->info();
int context_chain_length = info->function()->scope()->
ContextChainLength(slot->var()->scope());
ASSERT(context_chain_length >= 0);
// TODO(antonm): if slot's value is not modified by closures, instead
// of reading it out of context, we could just embed the value as
// a constant.
HLoadContextSlot* instr =
new HLoadContextSlot(context_chain_length, slot->index());
HValue* context = BuildContextChainWalk(variable);
int index = variable->AsSlot()->index();
HLoadContextSlot* instr = new HLoadContextSlot(context, index);
ast_context()->ReturnInstruction(instr, expr->id());
} else if (variable->is_global()) {
LookupResult lookup;
......@@ -3515,35 +3521,48 @@ void HGraphBuilder::VisitAssignment(Assignment* expr) {
if (proxy->IsArguments()) BAILOUT("assignment to arguments");
// Handle the assignment.
if (var->is_global()) {
if (var->IsStackAllocated()) {
HValue* value = NULL;
// Handle stack-allocated variables on the right-hand side directly.
// We do not allow the arguments object to occur in a context where it
// may escape, but assignments to stack-allocated locals are
// permitted. Handling such assignments here bypasses the check for
// the arguments object in VisitVariableProxy.
Variable* rhs_var = expr->value()->AsVariableProxy()->AsVariable();
if (rhs_var != NULL && rhs_var->IsStackAllocated()) {
value = environment()->Lookup(rhs_var);
} else {
VISIT_FOR_VALUE(expr->value());
value = Pop();
}
Bind(var, value);
ast_context()->ReturnValue(value);
} else if (var->IsContextSlot() && var->mode() != Variable::CONST) {
VISIT_FOR_VALUE(expr->value());
HValue* context = BuildContextChainWalk(var);
int index = var->AsSlot()->index();
HStoreContextSlot* instr = new HStoreContextSlot(context, index, Top());
AddInstruction(instr);
if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId());
ast_context()->ReturnValue(Pop());
} else if (var->is_global()) {
VISIT_FOR_VALUE(expr->value());
HandleGlobalVariableAssignment(var,
Top(),
expr->position(),
expr->AssignmentId());
} else if (var->IsStackAllocated()) {
// We allow reference to the arguments object only in assignemtns
// to local variables to make sure that the arguments object does
// not escape and is not modified.
VariableProxy* rhs = expr->value()->AsVariableProxy();
if (rhs != NULL &&
rhs->var()->IsStackAllocated() &&
environment()->Lookup(rhs->var())->CheckFlag(HValue::kIsArguments)) {
Push(environment()->Lookup(rhs->var()));
} else {
VISIT_FOR_VALUE(expr->value());
}
Bind(proxy->var(), Top());
ast_context()->ReturnValue(Pop());
} else {
BAILOUT("Assigning to no non-stack-allocated/non-global variable");
BAILOUT("assignment to LOOKUP or const CONTEXT variable");
}
// Return the value.
ast_context()->ReturnValue(Pop());
} else if (prop != NULL) {
HandlePropertyAssignment(expr);
} else {
BAILOUT("unsupported invalid lhs");
BAILOUT("invalid left-hand side in assignment");
}
}
......@@ -4422,7 +4441,10 @@ void HGraphBuilder::VisitCall(Call* expr) {
if (known_global_function) {
// Push the global object instead of the global receiver because
// code generated by the full code generator expects it.
PushAndAdd(new HGlobalObject);
HContext* context = new HContext;
HGlobalObject* global_object = new HGlobalObject(context);
AddInstruction(context);
PushAndAdd(global_object);
VisitArgumentList(expr->arguments());
CHECK_BAILOUT;
......@@ -4431,7 +4453,7 @@ void HGraphBuilder::VisitCall(Call* expr) {
AddInstruction(new HCheckFunction(function, expr->target()));
// Replace the global object with the global receiver.
HGlobalReceiver* global_receiver = new HGlobalReceiver;
HGlobalReceiver* global_receiver = new HGlobalReceiver(global_object);
// Index of the receiver from the top of the expression stack.
const int receiver_index = argument_count - 1;
AddInstruction(global_receiver);
......@@ -4458,7 +4480,9 @@ void HGraphBuilder::VisitCall(Call* expr) {
call = new HCallKnownGlobal(expr->target(), argument_count);
} else {
PushAndAdd(new HGlobalObject);
HContext* context = new HContext;
AddInstruction(context);
PushAndAdd(new HGlobalObject(context));
VisitArgumentList(expr->arguments());
CHECK_BAILOUT;
......@@ -4466,7 +4490,11 @@ void HGraphBuilder::VisitCall(Call* expr) {
}
} else {
PushAndAdd(new HGlobalReceiver);
HContext* context = new HContext;
HGlobalObject* global_object = new HGlobalObject(context);
AddInstruction(context);
AddInstruction(global_object);
PushAndAdd(new HGlobalReceiver(global_object));
VisitArgumentList(expr->arguments());
CHECK_BAILOUT;
......
......@@ -823,6 +823,8 @@ class HGraphBuilder: public AstVisitor {
HValue* switch_value,
CaseClause* clause);
HValue* BuildContextChainWalk(Variable* var);
void AddCheckConstantFunction(Call* expr,
HValue* receiver,
Handle<Map> receiver_map,
......
......@@ -1914,13 +1914,28 @@ void LCodeGen::DoStoreGlobal(LStoreGlobal* instr) {
void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
// TODO(antonm): load a context with a separate instruction.
Register context = ToRegister(instr->InputAt(0));
Register result = ToRegister(instr->result());
__ LoadContext(result, instr->context_chain_length());
__ mov(result,
Operand(context, Context::SlotOffset(Context::FCONTEXT_INDEX)));
__ mov(result, ContextOperand(result, instr->slot_index()));
}
void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
Register context = ToRegister(instr->context());
Register value = ToRegister(instr->value());
__ mov(context,
Operand(context, Context::SlotOffset(Context::FCONTEXT_INDEX)));
__ mov(ContextOperand(context, instr->slot_index()), value);
if (instr->needs_write_barrier()) {
Register temp = ToRegister(instr->TempAt(0));
int offset = Context::SlotOffset(instr->slot_index());
__ RecordWrite(context, offset, value, temp);
}
}
void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
Register object = ToRegister(instr->InputAt(0));
Register result = ToRegister(instr->result());
......@@ -2155,16 +2170,31 @@ void LCodeGen::DoPushArgument(LPushArgument* instr) {
}
void LCodeGen::DoContext(LContext* instr) {
Register result = ToRegister(instr->result());
__ mov(result, esi);
}
void LCodeGen::DoOuterContext(LOuterContext* instr) {
Register context = ToRegister(instr->context());
Register result = ToRegister(instr->result());
__ mov(result, Operand(context, Context::SlotOffset(Context::CLOSURE_INDEX)));
__ mov(result, FieldOperand(result, JSFunction::kContextOffset));
}
void LCodeGen::DoGlobalObject(LGlobalObject* instr) {
Register context = ToRegister(instr->context());
Register result = ToRegister(instr->result());
__ mov(result, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
__ mov(result, Operand(context, Context::SlotOffset(Context::GLOBAL_INDEX)));
}
void LCodeGen::DoGlobalReceiver(LGlobalReceiver* instr) {
Register global = ToRegister(instr->global());
Register result = ToRegister(instr->result());
__ mov(result, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
__ mov(result, FieldOperand(result, GlobalObject::kGlobalReceiverOffset));
__ mov(result, FieldOperand(global, GlobalObject::kGlobalReceiverOffset));
}
......
......@@ -268,7 +268,15 @@ void LUnaryMathOperation::PrintDataTo(StringStream* stream) {
void LLoadContextSlot::PrintDataTo(StringStream* stream) {
stream->Add("(%d, %d)", context_chain_length(), slot_index());
InputAt(0)->PrintTo(stream);
stream->Add("[%d]", slot_index());
}
void LStoreContextSlot::PrintDataTo(StringStream* stream) {
InputAt(0)->PrintTo(stream);
stream->Add("[%d] <- ", slot_index());
InputAt(1)->PrintTo(stream);
}
......@@ -1140,13 +1148,26 @@ LInstruction* LChunkBuilder::DoPushArgument(HPushArgument* instr) {
}
LInstruction* LChunkBuilder::DoContext(HContext* instr) {
return DefineAsRegister(new LContext);
}
LInstruction* LChunkBuilder::DoOuterContext(HOuterContext* instr) {
LOperand* context = UseRegisterAtStart(instr->value());
return DefineAsRegister(new LOuterContext(context));
}
LInstruction* LChunkBuilder::DoGlobalObject(HGlobalObject* instr) {
return DefineAsRegister(new LGlobalObject);
LOperand* context = UseRegisterAtStart(instr->value());
return DefineAsRegister(new LGlobalObject(context));
}
LInstruction* LChunkBuilder::DoGlobalReceiver(HGlobalReceiver* instr) {
return DefineAsRegister(new LGlobalReceiver);
LOperand* global_object = UseRegisterAtStart(instr->value());
return DefineAsRegister(new LGlobalReceiver(global_object));
}
......@@ -1658,7 +1679,23 @@ LInstruction* LChunkBuilder::DoStoreGlobal(HStoreGlobal* instr) {
LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) {
return DefineAsRegister(new LLoadContextSlot);
LOperand* context = UseRegisterAtStart(instr->value());
return DefineAsRegister(new LLoadContextSlot(context));
}
LInstruction* LChunkBuilder::DoStoreContextSlot(HStoreContextSlot* instr) {
LOperand* context = UseTempRegister(instr->context());
LOperand* value;
LOperand* temp;
if (instr->NeedsWriteBarrier()) {
value = UseTempRegister(instr->value());
temp = TempRegister();
} else {
value = UseRegister(instr->value());
temp = NULL;
}
return new LStoreContextSlot(context, value, temp);
}
......@@ -1756,7 +1793,8 @@ LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
// We only need a scratch register if we have a write barrier or we
// have a store into the properties array (not in-object-property).
LOperand* temp = (!instr->is_in_object() || needs_write_barrier)
? TempRegister() : NULL;
? TempRegister()
: NULL;
return new LStoreNamedField(obj, val, temp);
}
......
......@@ -39,118 +39,6 @@ namespace internal {
// Forward declarations.
class LCodeGen;
// Type hierarchy:
//
// LInstruction
// LTemplateInstruction
// LControlInstruction
// LBranch
// LClassOfTestAndBranch
// LCmpJSObjectEqAndBranch
// LCmpIDAndBranch
// LHasCachedArrayIndexAndBranch
// LHasInstanceTypeAndBranch
// LInstanceOfAndBranch
// LIsNullAndBranch
// LIsObjectAndBranch
// LIsSmiAndBranch
// LTypeofIsAndBranch
// LAccessArgumentsAt
// LArgumentsElements
// LArgumentsLength
// LAddI
// LApplyArguments
// LArithmeticD
// LArithmeticT
// LBitI
// LBoundsCheck
// LCmpID
// LCmpJSObjectEq
// LCmpT
// LDivI
// LInstanceOf
// LInstanceOfKnownGlobal
// LLoadKeyedFastElement
// LLoadKeyedGeneric
// LModI
// LMulI
// LPower
// LShiftI
// LSubI
// LCallConstantFunction
// LCallFunction
// LCallGlobal
// LCallKeyed
// LCallKnownGlobal
// LCallNamed
// LCallRuntime
// LCallStub
// LConstant
// LConstantD
// LConstantI
// LConstantT
// LDeoptimize
// LFunctionLiteral
// LGap
// LLabel
// LGlobalObject
// LGlobalReceiver
// LGoto
// LLazyBailout
// LLoadGlobal
// LCheckPrototypeMaps
// LLoadContextSlot
// LArrayLiteral
// LObjectLiteral
// LRegExpLiteral
// LOsrEntry
// LParameter
// LRegExpConstructResult
// LStackCheck
// LStoreKeyed
// LStoreKeyedFastElement
// LStoreKeyedGeneric
// LStoreNamed
// LStoreNamedField
// LStoreNamedGeneric
// LStringCharCodeAt
// LBitNotI
// LCallNew
// LCheckFunction
// LCheckPrototypeMaps
// LCheckInstanceType
// LCheckMap
// LCheckSmi
// LClassOfTest
// LDeleteProperty
// LDoubleToI
// LFixedArrayLength
// LHasCachedArrayIndex
// LHasInstanceType
// LInteger32ToDouble
// LIsNull
// LIsObject
// LIsSmi
// LJSArrayLength
// LLoadNamedField
// LLoadNamedGeneric
// LLoadFunctionPrototype
// LNumberTagD
// LNumberTagI
// LPushArgument
// LReturn
// LSmiTag
// LStoreGlobal
// LStringLength
// LTaggedToI
// LThrow
// LTypeof
// LTypeofIs
// LUnaryMathOperation
// LValueOf
// LUnknownOSRValue
#define LITHIUM_ALL_INSTRUCTION_LIST(V) \
V(ControlInstruction) \
V(Constant) \
......@@ -187,6 +75,8 @@ class LCodeGen;
V(CheckMap) \
V(CheckPrototypeMaps) \
V(CheckSmi) \
V(ClassOfTest) \
V(ClassOfTestAndBranch) \
V(CmpID) \
V(CmpIDAndBranch) \
V(CmpJSObjectEq) \
......@@ -197,16 +87,21 @@ class LCodeGen;
V(ConstantD) \
V(ConstantI) \
V(ConstantT) \
V(Context) \
V(DeleteProperty) \
V(Deoptimize) \
V(DivI) \
V(DoubleToI) \
V(FixedArrayLength) \
V(FunctionLiteral) \
V(Gap) \
V(GlobalObject) \
V(GlobalReceiver) \
V(Goto) \
V(FixedArrayLength) \
V(HasCachedArrayIndex) \
V(HasCachedArrayIndexAndBranch) \
V(HasInstanceType) \
V(HasInstanceTypeAndBranch) \
V(InstanceOf) \
V(InstanceOfAndBranch) \
V(InstanceOfKnownGlobal) \
......@@ -218,22 +113,16 @@ class LCodeGen;
V(IsSmi) \
V(IsSmiAndBranch) \
V(JSArrayLength) \
V(HasInstanceType) \
V(HasInstanceTypeAndBranch) \
V(HasCachedArrayIndex) \
V(HasCachedArrayIndexAndBranch) \
V(ClassOfTest) \
V(ClassOfTestAndBranch) \
V(Label) \
V(LazyBailout) \
V(LoadContextSlot) \
V(LoadElements) \
V(LoadFunctionPrototype) \
V(LoadGlobal) \
V(LoadKeyedFastElement) \
V(LoadKeyedGeneric) \
V(LoadNamedField) \
V(LoadNamedGeneric) \
V(LoadFunctionPrototype) \
V(ModI) \
V(MulI) \
V(NumberTagD) \
......@@ -241,6 +130,7 @@ class LCodeGen;
V(NumberUntagD) \
V(ObjectLiteral) \
V(OsrEntry) \
V(OuterContext) \
V(Parameter) \
V(Power) \
V(PushArgument) \
......@@ -250,6 +140,7 @@ class LCodeGen;
V(SmiTag) \
V(SmiUntag) \
V(StackCheck) \
V(StoreContextSlot) \
V(StoreGlobal) \
V(StoreKeyedFastElement) \
V(StoreKeyedGeneric) \
......@@ -1286,18 +1177,42 @@ class LStoreGlobal: public LTemplateInstruction<0, 1, 0> {
};
class LLoadContextSlot: public LTemplateInstruction<1, 0, 0> {
class LLoadContextSlot: public LTemplateInstruction<1, 1, 0> {
public:
explicit LLoadContextSlot(LOperand* context) {
inputs_[0] = context;
}
DECLARE_CONCRETE_INSTRUCTION(LoadContextSlot, "load-context-slot")
DECLARE_HYDROGEN_ACCESSOR(LoadContextSlot)
int context_chain_length() { return hydrogen()->context_chain_length(); }
LOperand* context() { return InputAt(0); }
int slot_index() { return hydrogen()->slot_index(); }
virtual void PrintDataTo(StringStream* stream);
};
class LStoreContextSlot: public LTemplateInstruction<0, 2, 1> {
public:
LStoreContextSlot(LOperand* context, LOperand* value, LOperand* temp) {
inputs_[0] = context;
inputs_[1] = value;
temps_[0] = temp;
}
DECLARE_CONCRETE_INSTRUCTION(StoreContextSlot, "store-context-slot")
DECLARE_HYDROGEN_ACCESSOR(StoreContextSlot)
LOperand* context() { return InputAt(0); }
LOperand* value() { return InputAt(1); }
int slot_index() { return hydrogen()->slot_index(); }
int needs_write_barrier() { return hydrogen()->NeedsWriteBarrier(); }
virtual void PrintDataTo(StringStream* stream);
};
class LPushArgument: public LTemplateInstruction<0, 1, 0> {
public:
explicit LPushArgument(LOperand* value) {
......@@ -1308,15 +1223,45 @@ class LPushArgument: public LTemplateInstruction<0, 1, 0> {
};
class LGlobalObject: public LTemplateInstruction<1, 0, 0> {
class LContext: public LTemplateInstruction<1, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(Context, "context")
};
class LOuterContext: public LTemplateInstruction<1, 1, 0> {
public:
explicit LOuterContext(LOperand* context) {
inputs_[0] = context;
}
DECLARE_CONCRETE_INSTRUCTION(OuterContext, "outer-context")
LOperand* context() { return InputAt(0); }
};
class LGlobalObject: public LTemplateInstruction<1, 1, 0> {
public:
explicit LGlobalObject(LOperand* context) {
inputs_[0] = context;
}
DECLARE_CONCRETE_INSTRUCTION(GlobalObject, "global-object")
LOperand* context() { return InputAt(0); }
};
class LGlobalReceiver: public LTemplateInstruction<1, 0, 0> {
class LGlobalReceiver: public LTemplateInstruction<1, 1, 0> {
public:
explicit LGlobalReceiver(LOperand* global_object) {
inputs_[0] = global_object;
}
DECLARE_CONCRETE_INSTRUCTION(GlobalReceiver, "global-receiver")
LOperand* global() { return InputAt(0); }
};
......
......@@ -262,7 +262,8 @@ void LUnaryMathOperation::PrintDataTo(StringStream* stream) {
void LLoadContextSlot::PrintDataTo(StringStream* stream) {
stream->Add("(%d, %d)", context_chain_length(), slot_index());
InputAt(0)->PrintTo(stream);
stream->Add("[%d]", slot_index());
}
......@@ -1049,6 +1050,18 @@ LInstruction* LChunkBuilder::DoPushArgument(HPushArgument* instr) {
}
LInstruction* LChunkBuilder::DoContext(HContext* instr) {
Abort("Unimplemented: DoContext");
return NULL;
}
LInstruction* LChunkBuilder::DoOuterContext(HOuterContext* instr) {
Abort("Unimplemented: DoOuterContext");
return NULL;
}
LInstruction* LChunkBuilder::DoGlobalObject(HGlobalObject* instr) {
return DefineAsRegister(new LGlobalObject);
}
......@@ -1472,7 +1485,8 @@ LInstruction* LChunkBuilder::DoLoadGlobal(HLoadGlobal* instr) {
LInstruction* LChunkBuilder::DoStoreGlobal(HStoreGlobal* instr) {
return new LStoreGlobal(UseRegisterAtStart(instr->value()));}
return new LStoreGlobal(UseRegisterAtStart(instr->value()));
}
LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) {
......@@ -1481,6 +1495,12 @@ LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) {
}
LInstruction* LChunkBuilder::DoStoreContextSlot(HStoreContextSlot* instr) {
Abort("Unimplemented: DoStoreContextSlot");
return NULL;
}
LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) {
ASSERT(instr->representation().IsTagged());
LOperand* obj = UseRegisterAtStart(instr->object());
......
......@@ -1280,12 +1280,16 @@ class LStoreGlobal: public LTemplateInstruction<0, 1, 0> {
};
class LLoadContextSlot: public LTemplateInstruction<1, 0, 0> {
class LLoadContextSlot: public LTemplateInstruction<1, 1, 0> {
public:
explicit LLoadContextSlot(LOperand* context) {
inputs_[0] = context;
}
DECLARE_CONCRETE_INSTRUCTION(LoadContextSlot, "load-context-slot")
DECLARE_HYDROGEN_ACCESSOR(LoadContextSlot)
int context_chain_length() { return hydrogen()->context_chain_length(); }
LOperand* context() { return InputAt(0); }
int slot_index() { return hydrogen()->slot_index(); }
virtual void PrintDataTo(StringStream* stream);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment