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);
}
}
+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));
}
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);
}
// 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) \
V(CheckMap) \
V(CheckPrototypeMaps) \
V(CheckSmi) \
+ V(ClassOfTest) \
+ V(ClassOfTestAndBranch) \
V(CmpID) \
V(CmpIDAndBranch) \
V(CmpJSObjectEq) \
V(ConstantD) \
V(ConstantI) \
V(ConstantT) \
+ V(Context) \
V(DeleteProperty) \
V(Deoptimize) \
V(DivI) \
V(GlobalObject) \
V(GlobalReceiver) \
V(Goto) \
+ V(HasCachedArrayIndex) \
+ V(HasCachedArrayIndexAndBranch) \
+ V(HasInstanceType) \
+ V(HasInstanceTypeAndBranch) \
V(InstanceOf) \
V(InstanceOfAndBranch) \
V(InstanceOfKnownGlobal) \
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) \
V(NumberUntagD) \
V(ObjectLiteral) \
V(OsrEntry) \
+ V(OuterContext) \
V(Parameter) \
V(PushArgument) \
V(RegExpLiteral) \
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) \
};
-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);
};
};
-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); }
};
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());
}
+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));
}
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);
}
V(CompareJSObjectEq) \
V(CompareMap) \
V(Constant) \
+ V(Context) \
V(DeleteProperty) \
V(Deoptimize) \
V(Div) \
V(Mul) \
V(ObjectLiteral) \
V(OsrEntry) \
+ V(OuterContext) \
V(Parameter) \
V(Power) \
V(PushArgument) \
V(Shr) \
V(Simulate) \
V(StackCheck) \
+ V(StoreContextSlot) \
V(StoreGlobal) \
V(StoreKeyedFastElement) \
V(StoreKeyedGeneric) \
V(GlobalVars) \
V(Maps) \
V(ArrayLengths) \
+ V(ContextSlots) \
V(OsrEntries)
#define DECLARE_INSTRUCTION(type) \
};
-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")
};
-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")
};
-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_;
};
};
-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)
HValue* value() const { return OperandAt(1); }
void set_value(HValue* value) { SetOperandAt(1, value); }
- bool NeedsWriteBarrier() const {
- return StoringValueNeedsWriteBarrier(value());
- }
-
DECLARE_INSTRUCTION(StoreNamed)
private:
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;
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_;
}
+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) {
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;
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");
}
}
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;
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);
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;
}
} 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;
HValue* switch_value,
CaseClause* clause);
+ HValue* BuildContextChainWalk(Variable* var);
+
void AddCheckConstantFunction(Call* expr,
HValue* receiver,
Handle<Map> receiver_map,
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());
}
+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));
}
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);
}
}
+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));
}
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);
}
// 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);
}
// 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) \
V(CheckMap) \
V(CheckPrototypeMaps) \
V(CheckSmi) \
+ V(ClassOfTest) \
+ V(ClassOfTestAndBranch) \
V(CmpID) \
V(CmpIDAndBranch) \
V(CmpJSObjectEq) \
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) \
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) \
V(NumberUntagD) \
V(ObjectLiteral) \
V(OsrEntry) \
+ V(OuterContext) \
V(Parameter) \
V(Power) \
V(PushArgument) \
V(SmiTag) \
V(SmiUntag) \
V(StackCheck) \
+ V(StoreContextSlot) \
V(StoreGlobal) \
V(StoreKeyedFastElement) \
V(StoreKeyedGeneric) \
};
-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) {
};
-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); }
};
void LLoadContextSlot::PrintDataTo(StringStream* stream) {
- stream->Add("(%d, %d)", context_chain_length(), slot_index());
+ InputAt(0)->PrintTo(stream);
+ stream->Add("[%d]", slot_index());
}
}
+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);
}
LInstruction* LChunkBuilder::DoStoreGlobal(HStoreGlobal* instr) {
- return new LStoreGlobal(UseRegisterAtStart(instr->value()));}
+ return new LStoreGlobal(UseRegisterAtStart(instr->value()));
+}
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());
};
-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);