-// Copyright 2010 the V8 project authors. All rights reserved.
+// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
}
+void HLoadKeyedGeneric::InternalSetOperandAt(int index, HValue* value) {
+ if (index < 2) {
+ operands_[index] = value;
+ } else {
+ context_ = value;
+ }
+}
+
+
+void HCallKeyed::InternalSetOperandAt(int index, HValue* value) {
+ // The key and all the arguments are stored in the base class's arguments_
+ // vector. The context is in the object itself. Ugly.
+ if (index <= argument_count()) {
+ arguments_[index] = value;
+ } else {
+ context_ = value;
+ }
+}
+
+
+void HCallNamed::InternalSetOperandAt(int index, HValue* value) {
+ // The arguments are in the base class's arguments_ vector. The context
+ // is in the object itself.
+ if (index < argument_count()) {
+ arguments_[index] = value;
+ } else {
+ context_ = value;
+ }
+}
+
+
+void HCallFunction::InternalSetOperandAt(int index, HValue* value) {
+ // The arguments are in the base class's arguments_ vector. The context
+ // is in the object itself.
+ if (index < argument_count()) {
+ arguments_[index] = value;
+ } else {
+ context_ = value;
+ }
+}
+
+
+void HCallGlobal::InternalSetOperandAt(int index, HValue* value) {
+ // The arguments are in the base class's arguments_ vector. The context
+ // is in the object itself.
+ if (index < argument_count()) {
+ arguments_[index] = value;
+ } else {
+ context_ = value;
+ }
+}
+
+
+void HCallNew::InternalSetOperandAt(int index, HValue* value) {
+ // The arguments are in the base class's arguments_ vector. The context
+ // is in the object itself.
+ if (index < argument_count()) {
+ arguments_[index] = value;
+ } else {
+ context_ = value;
+ }
+}
+
+
+void HStoreKeyedGeneric::InternalSetOperandAt(int index, HValue* value) {
+ if (index < 3) {
+ operands_[index] = value;
+ } else {
+ context_ = value;
+ }
+}
+
+
+void HStoreNamedGeneric::InternalSetOperandAt(int index, HValue* value) {
+ if (index < 2) {
+ operands_[index] = value;
+ } else {
+ context_ = value;
+ }
+}
+
+
void HValue::ReplaceAndDelete(HValue* other) {
ReplaceValue(other);
Delete();
HCall::PrintDataTo(stream);
}
+
void HCallStub::PrintDataTo(StringStream* stream) const {
- stream->Add("%s(%d)",
+ HUnaryOperation::PrintDataTo(stream);
+ stream->Add(" %s(%d)",
CodeStub::MajorName(major_key_, false),
argument_count_);
}
+void HInstanceOf::PrintDataTo(StringStream* stream) const {
+ left()->PrintNameTo(stream);
+ stream->Add(" ");
+ right()->PrintNameTo(stream);
+ stream->Add(" ");
+ context()->PrintNameTo(stream);
+}
+
+
Range* HValue::InferRange() {
if (representation().IsTagged()) {
// Tagged values are always in int32 range when converted to integer,
};
+// TODO(3190496): This class uses hacks to get additional operands that ar
+// not arguments to work with the current setup. This _needs_ a cleanup.
+// (see HCall).
class HCallKeyed: public HCall {
public:
- HCallKeyed(HValue* key, int argument_count)
- : HCall(argument_count + 1) {
+ HCallKeyed(HValue* context, HValue* key, int argument_count)
+ : HCall(argument_count + 1), context_(NULL) {
SetOperandAt(0, key);
+ SetOperandAt(argument_count + 1, context);
}
virtual Representation RequiredInputRepresentation(int index) const {
return Representation::Tagged();
}
- // TODO(3190496): This is a hack to get an additional operand that
- // is not an argument to work with the current setup. This _needs_ a cleanup.
- // (see HCall)
virtual void PrintDataTo(StringStream* stream) const;
+
HValue* key() const { return OperandAt(0); }
+ HValue* context() const { return context_; }
+
virtual int argument_count() const { return arguments_.length() - 1; }
- virtual int OperandCount() const { return arguments_.length(); }
- virtual HValue* OperandAt(int index) const { return arguments_[index]; }
+ virtual int OperandCount() const { return arguments_.length() + 1; }
+
+ virtual HValue* OperandAt(int index) const {
+ // The key and all the arguments are stored in the base class's
+ // arguments_ vector. The context is in the object itself. Ugly.
+ return (index <= argument_count()) ? arguments_[index] : context_;
+ }
+
virtual HPushArgument* PushArgumentAt(int index) const {
return HPushArgument::cast(OperandAt(index + 1));
}
}
DECLARE_CONCRETE_INSTRUCTION(CallKeyed, "call_keyed")
+
+ protected:
+ virtual void InternalSetOperandAt(int index, HValue* value);
+
+ private:
+ HValue* context_;
};
class HCallNamed: public HCall {
public:
- HCallNamed(Handle<String> name, int argument_count)
- : HCall(argument_count), name_(name) { }
+ HCallNamed(HValue* context, Handle<String> name, int argument_count)
+ : HCall(argument_count), context_(NULL), name_(name) {
+ SetOperandAt(argument_count, context);
+ }
+
virtual void PrintDataTo(StringStream* stream) const;
+ HValue* context() const { return context_; }
Handle<String> name() const { return name_; }
+ virtual int OperandCount() const { return arguments_.length() + 1; }
+
+ virtual HValue* OperandAt(int index) const {
+ // The arguments are in the base class's arguments_ vector. The context
+ // is in the object itself.
+ return (index < argument_count()) ? arguments_[index] : context_;
+ }
+
DECLARE_CONCRETE_INSTRUCTION(CallNamed, "call_named")
+ protected:
+ virtual void InternalSetOperandAt(int index, HValue* value);
+
private:
+ HValue* context_;
Handle<String> name_;
};
class HCallFunction: public HCall {
public:
- explicit HCallFunction(int argument_count) : HCall(argument_count) { }
+ HCallFunction(HValue* context, int argument_count)
+ : HCall(argument_count), context_(NULL) {
+ SetOperandAt(argument_count, context);
+ }
+
+ HValue* context() const { return context_; }
+
+ virtual int OperandCount() const { return arguments_.length() + 1; }
+
+ virtual HValue* OperandAt(int index) const {
+ // The arguments are in the base class's arguments_ vector. The context
+ // is in the object itself.
+ return (index < argument_count()) ? arguments_[index] : context_;
+ }
DECLARE_CONCRETE_INSTRUCTION(CallFunction, "call_function")
+
+ protected:
+ virtual void InternalSetOperandAt(int index, HValue* value);
+
+ private:
+ HValue* context_;
};
class HCallGlobal: public HCall {
public:
- HCallGlobal(Handle<String> name, int argument_count)
- : HCall(argument_count), name_(name) { }
+ HCallGlobal(HValue* context, Handle<String> name, int argument_count)
+ : HCall(argument_count), context_(NULL), name_(name) {
+ SetOperandAt(argument_count, context);
+ }
virtual void PrintDataTo(StringStream* stream) const;
+ HValue* context() const { return context_; }
Handle<String> name() const { return name_; }
+ virtual int OperandCount() const { return arguments_.length() + 1; }
+
+ virtual HValue* OperandAt(int index) const {
+ // The arguments are in the base class's arguments_ vector. The context
+ // is in the object itself.
+ return (index < argument_count()) ? arguments_[index] : context_;
+ }
+
DECLARE_CONCRETE_INSTRUCTION(CallGlobal, "call_global")
+ protected:
+ virtual void InternalSetOperandAt(int index, HValue* value);
+
private:
+ HValue* context_;
Handle<String> name_;
};
class HCallNew: public HCall {
public:
- explicit HCallNew(int argument_count) : HCall(argument_count) { }
+ HCallNew(HValue* context, int argument_count)
+ : HCall(argument_count), context_(NULL) {
+ SetOperandAt(argument_count, context);
+ }
virtual Representation RequiredInputRepresentation(int index) const {
return Representation::Tagged();
}
+ HValue* context() const { return context_; }
HValue* constructor() const { return ArgumentAt(0); }
+ virtual int OperandCount() const { return arguments_.length() + 1; }
+
+ virtual HValue* OperandAt(int index) const {
+ // The arguments are in the base class's arguments_ vector. The context
+ // is in the object itself.
+ return (index < argument_count()) ? arguments_[index] : context_;
+ }
+
DECLARE_CONCRETE_INSTRUCTION(CallNew, "call_new")
+
+ protected:
+ virtual void InternalSetOperandAt(int index, HValue* value);
+
+ private:
+ HValue* context_;
};
operands_[index] = value;
}
- private:
HOperandVector<2> operands_;
};
};
-class HInstanceOf: public HBinaryOperation {
+class HInstanceOf: public HInstruction {
public:
- HInstanceOf(HValue* left, HValue* right) : HBinaryOperation(left, right) {
+ HInstanceOf(HValue* context, HValue* left, HValue* right) {
+ SetOperandAt(0, context);
+ SetOperandAt(1, left);
+ SetOperandAt(2, right);
set_representation(Representation::Tagged());
SetAllSideEffects();
}
+ HValue* context() const { return operands_[0]; }
+ HValue* left() const { return operands_[1]; }
+ HValue* right() const { return operands_[2]; }
+
virtual bool EmitAtUses() const { return uses()->length() <= 1; }
virtual Representation RequiredInputRepresentation(int index) const {
return Representation::Tagged();
}
+ virtual void PrintDataTo(StringStream* stream) const;
+
+ virtual int OperandCount() const { return 3; }
+ virtual HValue* OperandAt(int index) const { return operands_[index]; }
+
DECLARE_CONCRETE_INSTRUCTION(InstanceOf, "instance_of")
+
+ protected:
+ virtual void InternalSetOperandAt(int index, HValue* value) {
+ operands_[index] = value;
+ }
+
+ private:
+ HOperandVector<3> operands_;
};
};
-class HCallStub: public HInstruction {
+class HCallStub: public HUnaryOperation {
public:
- HCallStub(CodeStub::Major major_key, int argument_count)
- : major_key_(major_key),
+ HCallStub(HValue* context, CodeStub::Major major_key, int argument_count)
+ : HUnaryOperation(context),
+ major_key_(major_key),
argument_count_(argument_count),
transcendental_type_(TranscendentalCache::kNumberOfCaches) {
set_representation(Representation::Tagged());
CodeStub::Major major_key() { return major_key_; }
int argument_count() { return argument_count_; }
+ HValue* context() { return OperandAt(0); }
void set_transcendental_type(TranscendentalCache::Type transcendental_type) {
transcendental_type_ = transcendental_type;
};
-class HLoadNamedGeneric: public HUnaryOperation {
+class HLoadNamedGeneric: public HBinaryOperation {
public:
- HLoadNamedGeneric(HValue* object, Handle<Object> name)
- : HUnaryOperation(object), name_(name) {
+ HLoadNamedGeneric(HValue* context, HValue* object, Handle<Object> name)
+ : HBinaryOperation(context, object), name_(name) {
set_representation(Representation::Tagged());
SetAllSideEffects();
}
- HValue* object() const { return OperandAt(0); }
+ HValue* context() const { return OperandAt(0); }
+ HValue* object() const { return OperandAt(1); }
Handle<Object> name() const { return name_; }
virtual Representation RequiredInputRepresentation(int index) const {
class HLoadKeyedGeneric: public HLoadKeyed {
public:
- HLoadKeyedGeneric(HValue* obj, HValue* key) : HLoadKeyed(obj, key) {
+ HLoadKeyedGeneric(HContext* context, HValue* obj, HValue* key)
+ : HLoadKeyed(obj, key), context_(NULL) {
+ SetOperandAt(2, context);
SetAllSideEffects();
}
+ HValue* context() const { return context_; }
+ HValue* object() const { return operands_[0]; }
+ HValue* key() const { return operands_[1]; }
+
+ virtual int OperandCount() const { return 3; }
+ virtual HValue* OperandAt(int index) const {
+ return (index < 2) ? operands_[index] : context_;
+ }
+
DECLARE_CONCRETE_INSTRUCTION(LoadKeyedGeneric, "load_keyed_generic")
+
+ protected:
+ virtual void InternalSetOperandAt(int index, HValue* value);
+
+ private:
+ HValue* context_;
};
class HStoreNamed: public HBinaryOperation {
public:
- HStoreNamed(HValue* obj, Handle<Object> name, HValue* val)
+ HStoreNamed(HValue* obj, Handle<String> name, HValue* val)
: HBinaryOperation(obj, val), name_(name) {
}
virtual void PrintDataTo(StringStream* stream) const;
HValue* object() const { return OperandAt(0); }
- Handle<Object> name() const { return name_; }
+ Handle<String> name() const { return name_; }
HValue* value() const { return OperandAt(1); }
void set_value(HValue* value) { SetOperandAt(1, value); }
DECLARE_INSTRUCTION(StoreNamed)
private:
- Handle<Object> name_;
+ Handle<String> name_;
};
class HStoreNamedField: public HStoreNamed {
public:
HStoreNamedField(HValue* obj,
- Handle<Object> name,
+ Handle<String> name,
HValue* val,
bool in_object,
int offset)
class HStoreNamedGeneric: public HStoreNamed {
public:
- HStoreNamedGeneric(HValue* obj, Handle<Object> name, HValue* val)
- : HStoreNamed(obj, name, val) {
+ HStoreNamedGeneric(HValue* context,
+ HValue* object,
+ Handle<String> name,
+ HValue* value)
+ : HStoreNamed(object, name, value), context_(NULL) {
+ SetOperandAt(2, context);
SetAllSideEffects();
}
+ HValue* context() const { return context_; }
+ HValue* object() const { return operands_[0]; }
+ HValue* value() const { return operands_[1]; }
+
+ virtual int OperandCount() const { return 3; }
+
+ virtual HValue* OperandAt(int index) const {
+ return (index < 2) ? operands_[index] : context_;
+ }
+
DECLARE_CONCRETE_INSTRUCTION(StoreNamedGeneric, "store_named_generic")
+
+ protected:
+ virtual void InternalSetOperandAt(int index, HValue* value);
+
+ private:
+ HValue* context_;
};
operands_[index] = value;
}
- private:
HOperandVector<3> operands_;
};
class HStoreKeyedGeneric: public HStoreKeyed {
public:
- HStoreKeyedGeneric(HValue* obj, HValue* key, HValue* val)
- : HStoreKeyed(obj, key, val) {
+ HStoreKeyedGeneric(HValue* context,
+ HValue* object,
+ HValue* key,
+ HValue* value)
+ : HStoreKeyed(object, key, value), context_(NULL) {
+ SetOperandAt(3, context);
SetAllSideEffects();
}
+ HValue* context() const { return context_; }
+ HValue* object() const { return operands_[0]; }
+ HValue* key() const { return operands_[1]; }
+ HValue* value() const { return operands_[2]; }
+
+ virtual int OperandCount() const { return 4; }
+
+ virtual HValue* OperandAt(int index) const {
+ return (index < 3) ? operands_[index] : context_;
+ }
+
DECLARE_CONCRETE_INSTRUCTION(StoreKeyedGeneric, "store_keyed_generic")
+
+ protected:
+ virtual void InternalSetOperandAt(int index, HValue* value);
+
+ private:
+ HValue* context_;
};
class HObjectLiteral: public HMaterializedLiteral {
public:
- HObjectLiteral(Handle<FixedArray> constant_properties,
+ HObjectLiteral(HValue* context,
+ Handle<FixedArray> constant_properties,
bool fast_elements,
int literal_index,
int depth)
: HMaterializedLiteral(literal_index, depth),
+ context_(NULL),
constant_properties_(constant_properties),
- fast_elements_(fast_elements) {}
+ fast_elements_(fast_elements) {
+ SetOperandAt(0, context);
+ }
+ HValue* context() const { return context_; }
Handle<FixedArray> constant_properties() const {
return constant_properties_;
}
bool fast_elements() const { return fast_elements_; }
+ virtual int OperandCount() const { return 1; }
+ virtual HValue* OperandAt(int index) const { return context_; }
+
DECLARE_CONCRETE_INSTRUCTION(ObjectLiteral, "object_literal")
+ protected:
+ virtual void InternalSetOperandAt(int index, HValue* value) {
+ context_ = value;
+ }
+
private:
+ HValue* context_;
Handle<FixedArray> constant_properties_;
bool fast_elements_;
};
void HGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
- HObjectLiteral* literal = (new HObjectLiteral(expr->constant_properties(),
+ HContext* context = new HContext;
+ AddInstruction(context);
+ HObjectLiteral* literal = (new HObjectLiteral(context,
+ expr->constant_properties(),
expr->fast_elements(),
expr->literal_index(),
expr->depth()));
VISIT_FOR_VALUE(value);
HValue* value = Pop();
Handle<String> name = Handle<String>::cast(key->handle());
- AddInstruction(new HStoreNamedGeneric(literal, name, value));
+ HStoreNamedGeneric* store =
+ new HStoreNamedGeneric(context, literal, name, value);
+ AddInstruction(store);
AddSimulate(key->id());
} else {
VISIT_FOR_EFFECT(value);
HInstruction* HGraphBuilder::BuildStoreNamedGeneric(HValue* object,
Handle<String> name,
HValue* value) {
- return new HStoreNamedGeneric(object, name, value);
+ HContext* context = new HContext;
+ AddInstruction(context);
+ return new HStoreNamedGeneric(context, object, name, value);
}
// If none of the properties were named fields we generate a
// generic store.
if (maps.length() == 0) {
- HInstruction* instr = new HStoreNamedGeneric(object, name, value);
+ HInstruction* instr = BuildStoreNamedGeneric(object, name, value);
Push(value);
instr->set_position(expr->position());
AddInstruction(instr);
if (!needs_generic && FLAG_deoptimize_uncommon_cases) {
subgraph->FinishExit(new HDeoptimize());
} else {
- HInstruction* instr = new HStoreNamedGeneric(object, name, value);
+ HInstruction* instr = BuildStoreNamedGeneric(object, name, value);
Push(value);
instr->set_position(expr->position());
AddInstruction(instr);
return;
} else {
- instr = new HStoreNamedGeneric(object, name, value);
+ instr = BuildStoreNamedGeneric(object, name, value);
}
} else {
bool is_fast_elements = prop->IsMonomorphic() &&
prop->GetMonomorphicReceiverType()->has_fast_elements();
-
HInstruction* load = is_fast_elements
? BuildLoadKeyedFastElement(obj, key, prop)
: BuildLoadKeyedGeneric(obj, key);
Property* expr) {
ASSERT(expr->key()->IsPropertyName());
Handle<Object> name = expr->key()->AsLiteral()->handle();
- return new HLoadNamedGeneric(obj, name);
+ HContext* context = new HContext;
+ AddInstruction(context);
+ return new HLoadNamedGeneric(context, obj, name);
}
HInstruction* HGraphBuilder::BuildLoadKeyedGeneric(HValue* object,
HValue* key) {
- return new HLoadKeyedGeneric(object, key);
+ HContext* context = new HContext;
+ AddInstruction(context);
+ return new HLoadKeyedGeneric(context, object, key);
}
HInstruction* HGraphBuilder::BuildStoreKeyedGeneric(HValue* object,
HValue* key,
HValue* value) {
- return new HStoreKeyedGeneric(object, key, value);
+ HContext* context = new HContext;
+ AddInstruction(context);
+ return new HStoreKeyedGeneric(context, object, key, value);
}
// If we couldn't compute the target for any of the maps just perform an
// IC call.
if (maps.length() == 0) {
- HCall* call = new HCallNamed(name, argument_count);
+ HContext* context = new HContext;
+ AddInstruction(context);
+ HCall* call = new HCallNamed(context, name, argument_count);
call->set_position(expr->position());
ProcessCall(call);
ast_context()->ReturnInstruction(call, expr->id());
if (!needs_generic && FLAG_deoptimize_uncommon_cases) {
subgraph->FinishExit(new HDeoptimize());
} else {
- HCall* call = new HCallNamed(name, argument_count);
+ HContext* context = new HContext;
+ AddInstruction(context);
+ HCall* call = new HCallNamed(context, name, argument_count);
call->set_position(expr->position());
ProcessCall(call);
PushAndAdd(call);
VisitArgumentList(expr->arguments());
CHECK_BAILOUT;
- call = new HCallKeyed(key, argument_count);
+ HContext* context = new HContext;
+ AddInstruction(context);
+ call = new HCallKeyed(context, key, argument_count);
call->set_position(expr->position());
ProcessCall(call);
Drop(1); // Key.
// When the target has a custom call IC generator, use the IC,
// because it is likely to generate better code. Also use the
// IC when a primitive receiver check is required.
- call = new HCallNamed(name, argument_count);
+ HContext* context = new HContext;
+ AddInstruction(context);
+ call = new HCallNamed(context, name, argument_count);
} else {
AddCheckConstantFunction(expr, receiver, receiver_map, true);
return;
} else {
- call = new HCallNamed(name, argument_count);
+ HContext* context = new HContext;
+ AddInstruction(context);
+ call = new HCallNamed(context, name, argument_count);
}
} else {
VisitArgumentList(expr->arguments());
CHECK_BAILOUT;
- call = new HCallGlobal(var->name(), argument_count);
+ call = new HCallGlobal(context, var->name(), argument_count);
}
} else {
VisitArgumentList(expr->arguments());
CHECK_BAILOUT;
- call = new HCallFunction(argument_count);
+ call = new HCallFunction(context, argument_count);
}
}
CHECK_BAILOUT;
int argument_count = expr->arguments()->length() + 1; // Plus constructor.
- HCall* call = new HCallNew(argument_count);
+ HContext* context = new HContext;
+ AddInstruction(context);
+ HCall* call = new HCallNew(context, argument_count);
call->set_position(expr->position());
ProcessCall(call);
ast_context()->ReturnInstruction(call, expr->id());
HInstruction* store = is_fast_elements
? BuildStoreKeyedFastElement(obj, key, after, prop)
- : new HStoreKeyedGeneric(obj, key, after);
+ : BuildStoreKeyedGeneric(obj, key, after);
AddInstruction(store);
// Drop the key from the bailout environment. Overwrite the receiver
// If the target is not null we have found a known global function that is
// assumed to stay the same for this instanceof.
if (target.is_null()) {
- instr = new HInstanceOf(left, right);
+ HContext* context = new HContext;
+ AddInstruction(context);
+ instr = new HInstanceOf(context, left, right);
} else {
AddInstruction(new HCheckFunction(right, target));
instr = new HInstanceOfKnownGlobal(left, target);
void HGraphBuilder::GenerateStringCharAt(int argument_count, int ast_id) {
ASSERT_EQ(2, argument_count);
PushArgumentsForStubCall(argument_count);
- HCallStub* result = new HCallStub(CodeStub::StringCharAt, argument_count);
+ HContext* context = new HContext;
+ AddInstruction(context);
+ HCallStub* result =
+ new HCallStub(context, CodeStub::StringCharAt, argument_count);
ast_context()->ReturnInstruction(result, ast_id);
}
void HGraphBuilder::GenerateStringAdd(int argument_count, int ast_id) {
ASSERT_EQ(2, argument_count);
PushArgumentsForStubCall(argument_count);
- HCallStub* result = new HCallStub(CodeStub::StringAdd, argument_count);
+ HContext* context = new HContext;
+ AddInstruction(context);
+ HCallStub* result =
+ new HCallStub(context, CodeStub::StringAdd, argument_count);
ast_context()->ReturnInstruction(result, ast_id);
}
void HGraphBuilder::GenerateSubString(int argument_count, int ast_id) {
ASSERT_EQ(3, argument_count);
PushArgumentsForStubCall(argument_count);
- HCallStub* result = new HCallStub(CodeStub::SubString, argument_count);
+ HContext* context = new HContext;
+ AddInstruction(context);
+ HCallStub* result =
+ new HCallStub(context, CodeStub::SubString, argument_count);
ast_context()->ReturnInstruction(result, ast_id);
}
void HGraphBuilder::GenerateStringCompare(int argument_count, int ast_id) {
ASSERT_EQ(2, argument_count);
PushArgumentsForStubCall(argument_count);
- HCallStub* result = new HCallStub(CodeStub::StringCompare, argument_count);
+ HContext* context = new HContext;
+ AddInstruction(context);
+ HCallStub* result =
+ new HCallStub(context, CodeStub::StringCompare, argument_count);
ast_context()->ReturnInstruction(result, ast_id);
}
void HGraphBuilder::GenerateRegExpExec(int argument_count, int ast_id) {
ASSERT_EQ(4, argument_count);
PushArgumentsForStubCall(argument_count);
- HCallStub* result = new HCallStub(CodeStub::RegExpExec, argument_count);
+ HContext* context = new HContext;
+ AddInstruction(context);
+ HCallStub* result =
+ new HCallStub(context, CodeStub::RegExpExec, argument_count);
ast_context()->ReturnInstruction(result, ast_id);
}
int ast_id) {
ASSERT_EQ(3, argument_count);
PushArgumentsForStubCall(argument_count);
+ HContext* context = new HContext;
+ AddInstruction(context);
HCallStub* result =
- new HCallStub(CodeStub::RegExpConstructResult, argument_count);
+ new HCallStub(context,CodeStub::RegExpConstructResult, argument_count);
ast_context()->ReturnInstruction(result, ast_id);
}
void HGraphBuilder::GenerateNumberToString(int argument_count, int ast_id) {
ASSERT_EQ(1, argument_count);
PushArgumentsForStubCall(argument_count);
- HCallStub* result = new HCallStub(CodeStub::NumberToString, argument_count);
+ HContext* context = new HContext;
+ AddInstruction(context);
+ HCallStub* result =
+ new HCallStub(context, CodeStub::NumberToString, argument_count);
ast_context()->ReturnInstruction(result, ast_id);
}
void HGraphBuilder::GenerateMathSin(int argument_count, int ast_id) {
ASSERT_EQ(1, argument_count);
PushArgumentsForStubCall(argument_count);
+ HContext* context = new HContext;
+ AddInstruction(context);
HCallStub* result =
- new HCallStub(CodeStub::TranscendentalCache, argument_count);
+ new HCallStub(context, CodeStub::TranscendentalCache, argument_count);
result->set_transcendental_type(TranscendentalCache::SIN);
ast_context()->ReturnInstruction(result, ast_id);
}
void HGraphBuilder::GenerateMathCos(int argument_count, int ast_id) {
ASSERT_EQ(1, argument_count);
PushArgumentsForStubCall(argument_count);
+ HContext* context = new HContext;
+ AddInstruction(context);
HCallStub* result =
- new HCallStub(CodeStub::TranscendentalCache, argument_count);
+ new HCallStub(context, CodeStub::TranscendentalCache, argument_count);
result->set_transcendental_type(TranscendentalCache::COS);
ast_context()->ReturnInstruction(result, ast_id);
}
void HGraphBuilder::GenerateMathLog(int argument_count, int ast_id) {
ASSERT_EQ(1, argument_count);
PushArgumentsForStubCall(argument_count);
+ HContext* context = new HContext;
+ AddInstruction(context);
HCallStub* result =
- new HCallStub(CodeStub::TranscendentalCache, argument_count);
+ new HCallStub(context, CodeStub::TranscendentalCache, argument_count);
result->set_transcendental_type(TranscendentalCache::LOG);
ast_context()->ReturnInstruction(result, ast_id);
}
// The original source code covered by the above license above has been
// modified significantly by Google Inc.
-// Copyright 2010 the V8 project authors. All rights reserved.
+// Copyright 2011 the V8 project authors. All rights reserved.
// A light-weight IA32 Assembler.
// and best performance in optimized code.
//
struct Register {
- static const int kNumAllocatableRegisters = 5;
+ static const int kNumAllocatableRegisters = 6;
static const int kNumRegisters = 8;
- static int ToAllocationIndex(Register reg) {
- ASSERT(reg.code() < 4 || reg.code() == 7);
- return (reg.code() == 7) ? 4 : reg.code();
- }
+ static inline const char* AllocationIndexToString(int index);
- static Register FromAllocationIndex(int index) {
- ASSERT(index >= 0 && index < kNumAllocatableRegisters);
- return (index == 4) ? from_code(7) : from_code(index);
- }
+ static inline int ToAllocationIndex(Register reg);
- static const char* AllocationIndexToString(int index) {
- ASSERT(index >= 0 && index < kNumAllocatableRegisters);
- const char* const names[] = {
- "eax",
- "ecx",
- "edx",
- "ebx",
- "edi"
- };
- return names[index];
- }
+ static inline Register FromAllocationIndex(int index);
static Register from_code(int code) {
Register r = { code };
int code_;
};
+
const Register eax = { 0 };
const Register ecx = { 1 };
const Register edx = { 2 };
const Register no_reg = { -1 };
+inline const char* Register::AllocationIndexToString(int index) {
+ ASSERT(index >= 0 && index < kNumAllocatableRegisters);
+ // This is the mapping of allocation indices to registers.
+ const char* const kNames[] = { "eax", "ecx", "edx", "ebx", "esi", "edi" };
+ return kNames[index];
+}
+
+
+inline int Register::ToAllocationIndex(Register reg) {
+ ASSERT(reg.is_valid() && !reg.is(esp) && !reg.is(ebp));
+ return (reg.code() >= 6) ? reg.code() - 2 : reg.code();
+}
+
+
+inline Register Register::FromAllocationIndex(int index) {
+ ASSERT(index >= 0 && index < kNumAllocatableRegisters);
+ return (index >= 4) ? from_code(index + 2) : from_code(index);
+}
+
+
struct XMMRegister {
static const int kNumAllocatableRegisters = 7;
static const int kNumRegisters = 8;
// Emit the write barrier code if the location is in the heap.
if (dst->type() == Slot::CONTEXT) {
int offset = Context::SlotOffset(dst->index());
+ ASSERT(!scratch1.is(esi) && !src.is(esi) && !scratch2.is(esi));
__ RecordWrite(scratch1, offset, src, scratch2);
}
}
// Trace the call.
if (FLAG_trace) {
+ // We have not executed any compiled code yet, so esi still holds the
+ // incoming context.
__ CallRuntime(Runtime::kTraceEnter, 0);
}
return !is_aborted();
void LCodeGen::CallCode(Handle<Code> code,
RelocInfo::Mode mode,
- LInstruction* instr) {
+ LInstruction* instr,
+ bool adjusted) {
ASSERT(instr != NULL);
LPointerMap* pointers = instr->pointer_map();
RecordPosition(pointers->position());
+ if (!adjusted) {
+ __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
+ }
__ call(code, mode);
RegisterLazyDeoptimization(instr);
}
-void LCodeGen::CallRuntime(Runtime::Function* function,
- int num_arguments,
- LInstruction* instr) {
+void LCodeGen::CallRuntime(Runtime::Function* fun,
+ int argc,
+ LInstruction* instr,
+ bool adjusted) {
ASSERT(instr != NULL);
ASSERT(instr->HasPointerMap());
LPointerMap* pointers = instr->pointer_map();
RecordPosition(pointers->position());
- __ CallRuntime(function, num_arguments);
+ if (!adjusted) {
+ __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
+ }
+ __ CallRuntime(fun, argc);
RegisterLazyDeoptimization(instr);
}
safepoint.DefinePointerRegister(ToRegister(pointer));
}
}
- if (kind & Safepoint::kWithRegisters) {
- // Register esi always contains a pointer to the context.
- safepoint.DefinePointerRegister(esi);
- }
}
void LCodeGen::DoCallStub(LCallStub* instr) {
+ ASSERT(ToRegister(instr->context()).is(esi));
ASSERT(ToRegister(instr->result()).is(eax));
switch (instr->hydrogen()->major_key()) {
case CodeStub::RegExpConstructResult: {
void LCodeGen::DoThrow(LThrow* instr) {
__ push(ToOperand(instr->InputAt(0)));
- CallRuntime(Runtime::kThrow, 1, instr);
+ CallRuntime(Runtime::kThrow, 1, instr, false);
if (FLAG_debug_code) {
Comment("Unreachable code.");
ASSERT(ToRegister(instr->result()).is(eax));
TypeRecordingBinaryOpStub stub(instr->op(), NO_OVERWRITE);
- CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
+ CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, false);
}
void LCodeGen::DoDeferredStackCheck(LGoto* instr) {
__ pushad();
+ __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
__ CallRuntimeSaveDoubles(Runtime::kStackGuard);
RecordSafepointWithRegisters(
instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex);
void LCodeGen::DoInstanceOf(LInstanceOf* instr) {
// Object and function are in fixed registers defined by the stub.
+ ASSERT(ToRegister(instr->context()).is(esi));
InstanceofStub stub(InstanceofStub::kArgsInRegisters);
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
void LCodeGen::DoInstanceOfAndBranch(LInstanceOfAndBranch* instr) {
+ ASSERT(ToRegister(instr->context()).is(esi));
int true_block = chunk_->LookupDestination(instr->true_block_id());
int false_block = chunk_->LookupDestination(instr->false_block_id());
Register temp = ToRegister(instr->TempAt(0));
ASSERT(temp.is(edi));
__ mov(InstanceofStub::right(), Immediate(instr->function()));
- static const int kAdditionalDelta = 13;
+ static const int kAdditionalDelta = 16;
int delta = masm_->SizeOfCodeGeneratedSince(map_check) + kAdditionalDelta;
Label before_push_delta;
__ bind(&before_push_delta);
__ mov(temp, Immediate(delta));
__ mov(Operand(esp, EspIndexForPushAll(temp) * kPointerSize), temp);
+ __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
__ call(stub.GetCode(), RelocInfo::CODE_TARGET);
ASSERT_EQ(kAdditionalDelta,
masm_->SizeOfCodeGeneratedSince(&before_push_delta));
Token::Value op = instr->op();
Handle<Code> ic = CompareIC::GetUninitialized(op);
- CallCode(ic, RelocInfo::CODE_TARGET, instr);
+ CallCode(ic, RelocInfo::CODE_TARGET, instr, false);
Condition condition = ComputeCompareCondition(op);
if (op == Token::GT || op == Token::LTE) {
int false_block = chunk_->LookupDestination(instr->false_block_id());
Handle<Code> ic = CompareIC::GetUninitialized(op);
- CallCode(ic, RelocInfo::CODE_TARGET, instr);
+ CallCode(ic, RelocInfo::CODE_TARGET, instr, false);
// The compare stub expects compare condition and the input operands
// reversed for GT and LTE.
void LCodeGen::DoReturn(LReturn* instr) {
if (FLAG_trace) {
- // Preserve the return value on the stack and rely on the runtime
- // call to return the value in the same register.
+ // Preserve the return value on the stack and rely on the runtime call
+ // to return the value in the same register. We're leaving the code
+ // managed by the register allocator and tearing down the frame, it's
+ // safe to write to the context register.
__ push(eax);
+ __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
__ CallRuntime(Runtime::kTraceExit, 1);
}
__ mov(esp, ebp);
void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) {
+ ASSERT(ToRegister(instr->context()).is(esi));
ASSERT(ToRegister(instr->object()).is(eax));
ASSERT(ToRegister(instr->result()).is(eax));
void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) {
+ ASSERT(ToRegister(instr->context()).is(esi));
ASSERT(ToRegister(instr->object()).is(edx));
ASSERT(ToRegister(instr->key()).is(eax));
__ jmp(&receiver_ok);
__ bind(&global_receiver);
- __ mov(receiver, GlobalObjectOperand());
+ // TODO(kmillikin): We have a hydrogen value for the global object. See
+ // if it's better to use it than to explicitly fetch it from the context
+ // here.
+ __ mov(receiver, Operand(ebp, StandardFrameConstants::kContextOffset));
+ __ mov(receiver, ContextOperand(receiver, Context::GLOBAL_INDEX));
__ bind(&receiver_ok);
Label invoke;
ASSERT(receiver.is(eax));
v8::internal::ParameterCount actual(eax);
__ InvokeFunction(edi, actual, CALL_FUNCTION, &safepoint_generator);
-
- // Restore context.
- __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
}
void LCodeGen::DoContext(LContext* instr) {
Register result = ToRegister(instr->result());
- __ mov(result, esi);
+ __ mov(result, Operand(ebp, StandardFrameConstants::kContextOffset));
}
(scope()->num_heap_slots() > 0);
if (change_context) {
__ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
+ } else {
+ __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
}
// Set eax to arguments count if adaption is not needed. Assumes that eax
// Setup deoptimization.
RegisterLazyDeoptimization(instr);
-
- // Restore context.
- __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
}
// Slow case: Call the runtime system to do the number allocation.
__ bind(&slow);
+ __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
__ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
RecordSafepointWithRegisters(
instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex);
ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
TranscendentalCacheStub stub(TranscendentalCache::LOG,
TranscendentalCacheStub::UNTAGGED);
- CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
+ CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, false);
}
ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
TranscendentalCacheStub stub(TranscendentalCache::COS,
TranscendentalCacheStub::UNTAGGED);
- CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
+ CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, false);
}
ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
TranscendentalCacheStub stub(TranscendentalCache::SIN,
TranscendentalCacheStub::UNTAGGED);
- CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
+ CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, false);
}
void LCodeGen::DoCallKeyed(LCallKeyed* instr) {
+ ASSERT(ToRegister(instr->context()).is(esi));
+ ASSERT(ToRegister(instr->key()).is(ecx));
ASSERT(ToRegister(instr->result()).is(eax));
- ASSERT(ToRegister(instr->InputAt(0)).is(ecx));
int arity = instr->arity();
Handle<Code> ic = StubCache::ComputeKeyedCallInitialize(arity, NOT_IN_LOOP);
CallCode(ic, RelocInfo::CODE_TARGET, instr);
- __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
}
void LCodeGen::DoCallNamed(LCallNamed* instr) {
+ ASSERT(ToRegister(instr->context()).is(esi));
ASSERT(ToRegister(instr->result()).is(eax));
int arity = instr->arity();
Handle<Code> ic = StubCache::ComputeCallInitialize(arity, NOT_IN_LOOP);
__ mov(ecx, instr->name());
CallCode(ic, RelocInfo::CODE_TARGET, instr);
- __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
}
void LCodeGen::DoCallFunction(LCallFunction* instr) {
+ ASSERT(ToRegister(instr->context()).is(esi));
ASSERT(ToRegister(instr->result()).is(eax));
int arity = instr->arity();
CallFunctionStub stub(arity, NOT_IN_LOOP, RECEIVER_MIGHT_BE_VALUE);
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
__ Drop(1);
- __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
}
void LCodeGen::DoCallGlobal(LCallGlobal* instr) {
+ ASSERT(ToRegister(instr->context()).is(esi));
ASSERT(ToRegister(instr->result()).is(eax));
int arity = instr->arity();
Handle<Code> ic = StubCache::ComputeCallInitialize(arity, NOT_IN_LOOP);
__ mov(ecx, instr->name());
CallCode(ic, RelocInfo::CODE_TARGET_CONTEXT, instr);
- __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
}
void LCodeGen::DoCallNew(LCallNew* instr) {
- ASSERT(ToRegister(instr->InputAt(0)).is(edi));
+ ASSERT(ToRegister(instr->context()).is(esi));
+ ASSERT(ToRegister(instr->constructor()).is(edi));
ASSERT(ToRegister(instr->result()).is(eax));
Handle<Code> builtin(Builtins::builtin(Builtins::JSConstructCall));
void LCodeGen::DoCallRuntime(LCallRuntime* instr) {
- CallRuntime(instr->function(), instr->arity(), instr);
+ CallRuntime(instr->function(), instr->arity(), instr, false);
}
void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
+ ASSERT(ToRegister(instr->context()).is(esi));
ASSERT(ToRegister(instr->object()).is(edx));
ASSERT(ToRegister(instr->value()).is(eax));
void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
+ ASSERT(ToRegister(instr->context()).is(esi));
ASSERT(ToRegister(instr->object()).is(edx));
ASSERT(ToRegister(instr->key()).is(ecx));
ASSERT(ToRegister(instr->value()).is(eax));
__ SmiTag(index);
__ push(index);
}
+ __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
__ CallRuntimeSaveDoubles(Runtime::kStringCharCodeAt);
RecordSafepointWithRegisters(
instr->pointer_map(), 2, Safepoint::kNoDeoptimizationIndex);
// integer value.
__ mov(Operand(esp, EspIndexForPushAll(reg) * kPointerSize), Immediate(0));
+ __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
__ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
RecordSafepointWithRegisters(
instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex);
__ Set(reg, Immediate(0));
__ PushSafepointRegisters();
+ __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
__ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
RecordSafepointWithRegisters(
instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex);
FastCloneShallowArrayStub::Mode mode =
FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS;
FastCloneShallowArrayStub stub(mode, length);
- CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
+ CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, false);
} else if (instr->hydrogen()->depth() > 1) {
- CallRuntime(Runtime::kCreateArrayLiteral, 3, instr);
+ CallRuntime(Runtime::kCreateArrayLiteral, 3, instr, false);
} else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
- CallRuntime(Runtime::kCreateArrayLiteralShallow, 3, instr);
+ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3, instr, false);
} else {
FastCloneShallowArrayStub::Mode mode =
FastCloneShallowArrayStub::CLONE_ELEMENTS;
FastCloneShallowArrayStub stub(mode, length);
- CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
+ CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, false);
}
}
void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) {
+ ASSERT(ToRegister(instr->context()).is(esi));
// Setup the parameters to the stub/runtime call.
__ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
__ push(FieldOperand(eax, JSFunction::kLiteralsOffset));
__ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
__ push(Immediate(instr->hydrogen()->pattern()));
__ push(Immediate(instr->hydrogen()->flags()));
- CallRuntime(Runtime::kMaterializeRegExpLiteral, 4, instr);
+ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4, instr, false);
__ mov(ebx, eax);
__ bind(&materialized);
__ bind(&runtime_allocate);
__ push(ebx);
__ push(Immediate(Smi::FromInt(size)));
- CallRuntime(Runtime::kAllocateInNewSpace, 1, instr);
+ CallRuntime(Runtime::kAllocateInNewSpace, 1, instr, false);
__ pop(ebx);
__ bind(&allocated);
if (shared_info->num_literals() == 0 && !pretenure) {
FastNewClosureStub stub;
__ push(Immediate(shared_info));
- CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
+ CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, false);
} else {
- __ push(esi);
+ __ push(Operand(ebp, StandardFrameConstants::kContextOffset));
__ push(Immediate(shared_info));
__ push(Immediate(pretenure
? Factory::true_value()
: Factory::false_value()));
- CallRuntime(Runtime::kNewClosure, 3, instr);
+ CallRuntime(Runtime::kNewClosure, 3, instr, false);
}
}
} else {
__ push(ToOperand(input));
}
- CallRuntime(Runtime::kTypeof, 1, instr);
+ CallRuntime(Runtime::kTypeof, 1, instr, false);
}
SafepointGenerator safepoint_generator(this,
pointers,
env->deoptimization_index());
+ __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
__ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, &safepoint_generator);
}
__ j(above_equal, &done);
StackCheckStub stub;
- CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
+ CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, false);
__ bind(&done);
}
bool GenerateDeferredCode();
bool GenerateSafepointTable();
- void CallCode(Handle<Code> code,
- RelocInfo::Mode mode,
- LInstruction* instr);
- void CallRuntime(Runtime::Function* function,
- int num_arguments,
- LInstruction* instr);
- void CallRuntime(Runtime::FunctionId id,
- int num_arguments,
- LInstruction* instr) {
+ void CallCode(Handle<Code> code, RelocInfo::Mode mode, LInstruction* instr,
+ bool adjusted = true);
+ void CallRuntime(Runtime::Function* fun, int argc, LInstruction* instr,
+ bool adjusted = true);
+ void CallRuntime(Runtime::FunctionId id, int argc, LInstruction* instr,
+ bool adjusted = true) {
Runtime::Function* function = Runtime::FunctionForId(id);
- CallRuntime(function, num_arguments, instr);
+ CallRuntime(function, argc, instr, adjusted);
}
// Generate a direct call to a known function. Expects the function
UseRegisterAtStart(compare->right()));
} else if (v->IsInstanceOf()) {
HInstanceOf* instance_of = HInstanceOf::cast(v);
+ LOperand* left = UseFixed(instance_of->left(), InstanceofStub::left());
+ LOperand* right = UseFixed(instance_of->right(), InstanceofStub::right());
+ LOperand* context = UseFixed(instance_of->context(), esi);
LInstanceOfAndBranch* result =
- new LInstanceOfAndBranch(
- UseFixed(instance_of->left(), InstanceofStub::left()),
- UseFixed(instance_of->right(), InstanceofStub::right()));
+ new LInstanceOfAndBranch(context, left, right);
return MarkAsCall(result, instr);
} else if (v->IsTypeofIs()) {
HTypeofIs* typeof_is = HTypeofIs::cast(v);
LInstruction* LChunkBuilder::DoInstanceOf(HInstanceOf* instr) {
- LInstanceOf* result =
- new LInstanceOf(UseFixed(instr->left(), InstanceofStub::left()),
- UseFixed(instr->right(), InstanceofStub::right()));
+ LOperand* left = UseFixed(instr->left(), InstanceofStub::left());
+ LOperand* right = UseFixed(instr->right(), InstanceofStub::right());
+ LOperand* context = UseFixed(instr->context(), esi);
+ LInstanceOf* result = new LInstanceOf(context, left, right);
return MarkAsCall(DefineFixed(result, eax), instr);
}
LInstruction* LChunkBuilder::DoCallKeyed(HCallKeyed* instr) {
ASSERT(instr->key()->representation().IsTagged());
- argument_count_ -= instr->argument_count();
+ LOperand* context = UseFixed(instr->context(), esi);
LOperand* key = UseFixed(instr->key(), ecx);
- return MarkAsCall(DefineFixed(new LCallKeyed(key), eax), instr);
+ argument_count_ -= instr->argument_count();
+ LCallKeyed* result = new LCallKeyed(context, key);
+ return MarkAsCall(DefineFixed(result, eax), instr);
}
LInstruction* LChunkBuilder::DoCallNamed(HCallNamed* instr) {
+ LOperand* context = UseFixed(instr->context(), esi);
argument_count_ -= instr->argument_count();
- return MarkAsCall(DefineFixed(new LCallNamed, eax), instr);
+ LCallNamed* result = new LCallNamed(context);
+ return MarkAsCall(DefineFixed(result, eax), instr);
}
LInstruction* LChunkBuilder::DoCallGlobal(HCallGlobal* instr) {
+ LOperand* context = UseFixed(instr->context(), esi);
argument_count_ -= instr->argument_count();
- return MarkAsCall(DefineFixed(new LCallGlobal, eax), instr);
+ LCallGlobal* result = new LCallGlobal(context);
+ return MarkAsCall(DefineFixed(result, eax), instr);
}
LInstruction* LChunkBuilder::DoCallNew(HCallNew* instr) {
+ LOperand* context = UseFixed(instr->context(), esi);
LOperand* constructor = UseFixed(instr->constructor(), edi);
argument_count_ -= instr->argument_count();
- LCallNew* result = new LCallNew(constructor);
+ LCallNew* result = new LCallNew(context, constructor);
return MarkAsCall(DefineFixed(result, eax), instr);
}
LInstruction* LChunkBuilder::DoCallFunction(HCallFunction* instr) {
+ LOperand* context = UseFixed(instr->context(), esi);
argument_count_ -= instr->argument_count();
- return MarkAsCall(DefineFixed(new LCallFunction, eax), instr);
+ LCallFunction* result = new LCallFunction(context);
+ return MarkAsCall(DefineFixed(result, eax), instr);
}
LInstruction* LChunkBuilder::DoLoadNamedGeneric(HLoadNamedGeneric* instr) {
+ LOperand* context = UseFixed(instr->context(), esi);
LOperand* object = UseFixed(instr->object(), eax);
- LLoadNamedGeneric* result = new LLoadNamedGeneric(object);
+ LLoadNamedGeneric* result = new LLoadNamedGeneric(context, object);
return MarkAsCall(DefineFixed(result, eax), instr);
}
LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) {
+ LOperand* context = UseFixed(instr->context(), esi);
LOperand* object = UseFixed(instr->object(), edx);
LOperand* key = UseFixed(instr->key(), eax);
- LLoadKeyedGeneric* result = new LLoadKeyedGeneric(object, key);
+ LLoadKeyedGeneric* result = new LLoadKeyedGeneric(context, object, key);
return MarkAsCall(DefineFixed(result, eax), instr);
}
LInstruction* LChunkBuilder::DoStoreKeyedGeneric(HStoreKeyedGeneric* instr) {
- LOperand* obj = UseFixed(instr->object(), edx);
+ LOperand* context = UseFixed(instr->context(), esi);
+ LOperand* object = UseFixed(instr->object(), edx);
LOperand* key = UseFixed(instr->key(), ecx);
- LOperand* val = UseFixed(instr->value(), eax);
+ LOperand* value = UseFixed(instr->value(), eax);
ASSERT(instr->object()->representation().IsTagged());
ASSERT(instr->key()->representation().IsTagged());
ASSERT(instr->value()->representation().IsTagged());
- return MarkAsCall(new LStoreKeyedGeneric(obj, key, val), instr);
+ LStoreKeyedGeneric* result =
+ new LStoreKeyedGeneric(context, object, key, value);
+ return MarkAsCall(result, instr);
}
LInstruction* LChunkBuilder::DoStoreNamedGeneric(HStoreNamedGeneric* instr) {
- LOperand* obj = UseFixed(instr->object(), edx);
- LOperand* val = UseFixed(instr->value(), eax);
+ LOperand* context = UseFixed(instr->context(), esi);
+ LOperand* object = UseFixed(instr->object(), edx);
+ LOperand* value = UseFixed(instr->value(), eax);
- LStoreNamedGeneric* result = new LStoreNamedGeneric(obj, val);
+ LStoreNamedGeneric* result = new LStoreNamedGeneric(context, object, value);
return MarkAsCall(result, instr);
}
LInstruction* LChunkBuilder::DoObjectLiteral(HObjectLiteral* instr) {
- return MarkAsCall(DefineFixed(new LObjectLiteral, eax), instr);
+ LOperand* context = UseFixed(instr->context(), esi);
+ return MarkAsCall(DefineFixed(new LObjectLiteral(context), eax), instr);
}
LInstruction* LChunkBuilder::DoCallStub(HCallStub* instr) {
+ LOperand* context = UseFixed(instr->context(), esi);
argument_count_ -= instr->argument_count();
- return MarkAsCall(DefineFixed(new LCallStub, eax), instr);
+ LCallStub* result = new LCallStub(context);
+ return MarkAsCall(DefineFixed(result, eax), instr);
}
};
-class LCallStub: public LTemplateInstruction<1, 0, 0> {
+class LCallStub: public LTemplateInstruction<1, 1, 0> {
public:
+ explicit LCallStub(LOperand* context) {
+ inputs_[0] = context;
+ }
+
DECLARE_CONCRETE_INSTRUCTION(CallStub, "call-stub")
DECLARE_HYDROGEN_ACCESSOR(CallStub)
+ LOperand* context() { return inputs_[0]; }
+
TranscendentalCache::Type transcendental_type() {
return hydrogen()->transcendental_type();
}
};
-class LInstanceOf: public LTemplateInstruction<1, 2, 0> {
+class LInstanceOf: public LTemplateInstruction<1, 3, 0> {
public:
- LInstanceOf(LOperand* left, LOperand* right) {
- inputs_[0] = left;
- inputs_[1] = right;
+ LInstanceOf(LOperand* context, LOperand* left, LOperand* right) {
+ inputs_[0] = context;
+ inputs_[1] = left;
+ inputs_[2] = right;
}
DECLARE_CONCRETE_INSTRUCTION(InstanceOf, "instance-of")
+
+ LOperand* context() { return inputs_[0]; }
};
-class LInstanceOfAndBranch: public LControlInstruction<2, 0> {
+class LInstanceOfAndBranch: public LControlInstruction<3, 0> {
public:
- LInstanceOfAndBranch(LOperand* left, LOperand* right) {
- inputs_[0] = left;
- inputs_[1] = right;
+ LInstanceOfAndBranch(LOperand* context, LOperand* left, LOperand* right) {
+ inputs_[0] = context;
+ inputs_[1] = left;
+ inputs_[2] = right;
}
DECLARE_CONCRETE_INSTRUCTION(InstanceOfAndBranch, "instance-of-and-branch")
+
+ LOperand* context() { return inputs_[0]; }
};
};
-class LLoadNamedGeneric: public LTemplateInstruction<1, 1, 0> {
+class LLoadNamedGeneric: public LTemplateInstruction<1, 2, 0> {
public:
- explicit LLoadNamedGeneric(LOperand* object) {
- inputs_[0] = object;
+ LLoadNamedGeneric(LOperand* context, LOperand* object) {
+ inputs_[0] = context;
+ inputs_[1] = object;
}
DECLARE_CONCRETE_INSTRUCTION(LoadNamedGeneric, "load-named-generic")
DECLARE_HYDROGEN_ACCESSOR(LoadNamedGeneric)
- LOperand* object() { return inputs_[0]; }
+ LOperand* context() { return inputs_[0]; }
+ LOperand* object() { return inputs_[1]; }
Handle<Object> name() const { return hydrogen()->name(); }
};
};
-class LLoadKeyedGeneric: public LTemplateInstruction<1, 2, 0> {
+class LLoadKeyedGeneric: public LTemplateInstruction<1, 3, 0> {
public:
- LLoadKeyedGeneric(LOperand* obj, LOperand* key) {
- inputs_[0] = obj;
- inputs_[1] = key;
+ LLoadKeyedGeneric(LOperand* context, LOperand* obj, LOperand* key) {
+ inputs_[0] = context;
+ inputs_[1] = obj;
+ inputs_[2] = key;
}
DECLARE_CONCRETE_INSTRUCTION(LoadKeyedGeneric, "load-keyed-generic")
- LOperand* object() { return inputs_[0]; }
- LOperand* key() { return inputs_[1]; }
+ LOperand* context() { return inputs_[0]; }
+ LOperand* object() { return inputs_[1]; }
+ LOperand* key() { return inputs_[2]; }
};
};
-class LCallKeyed: public LTemplateInstruction<1, 1, 0> {
+class LCallKeyed: public LTemplateInstruction<1, 2, 0> {
public:
- explicit LCallKeyed(LOperand* key) {
- inputs_[0] = key;
+ LCallKeyed(LOperand* context, LOperand* key) {
+ inputs_[0] = context;
+ inputs_[1] = key;
}
DECLARE_CONCRETE_INSTRUCTION(CallKeyed, "call-keyed")
DECLARE_HYDROGEN_ACCESSOR(CallKeyed)
+ LOperand* context() { return inputs_[0]; }
+ LOperand* key() { return inputs_[1]; }
+
virtual void PrintDataTo(StringStream* stream);
int arity() const { return hydrogen()->argument_count() - 1; }
};
-class LCallNamed: public LTemplateInstruction<1, 0, 0> {
+class LCallNamed: public LTemplateInstruction<1, 1, 0> {
public:
+ explicit LCallNamed(LOperand* context) {
+ inputs_[0] = context;
+ }
+
DECLARE_CONCRETE_INSTRUCTION(CallNamed, "call-named")
DECLARE_HYDROGEN_ACCESSOR(CallNamed)
virtual void PrintDataTo(StringStream* stream);
+ LOperand* context() { return inputs_[0]; }
Handle<String> name() const { return hydrogen()->name(); }
int arity() const { return hydrogen()->argument_count() - 1; }
};
-class LCallFunction: public LTemplateInstruction<1, 0, 0> {
+class LCallFunction: public LTemplateInstruction<1, 1, 0> {
public:
+ explicit LCallFunction(LOperand* context) {
+ inputs_[0] = context;
+ }
+
DECLARE_CONCRETE_INSTRUCTION(CallFunction, "call-function")
DECLARE_HYDROGEN_ACCESSOR(CallFunction)
+ LOperand* context() { return inputs_[0]; }
int arity() const { return hydrogen()->argument_count() - 2; }
};
-class LCallGlobal: public LTemplateInstruction<1, 0, 0> {
+class LCallGlobal: public LTemplateInstruction<1, 1, 0> {
public:
+ explicit LCallGlobal(LOperand* context) {
+ inputs_[0] = context;
+ }
+
DECLARE_CONCRETE_INSTRUCTION(CallGlobal, "call-global")
DECLARE_HYDROGEN_ACCESSOR(CallGlobal)
virtual void PrintDataTo(StringStream* stream);
+ LOperand* context() { return inputs_[0]; }
Handle<String> name() const {return hydrogen()->name(); }
int arity() const { return hydrogen()->argument_count() - 1; }
};
};
-class LCallNew: public LTemplateInstruction<1, 1, 0> {
+class LCallNew: public LTemplateInstruction<1, 2, 0> {
public:
- explicit LCallNew(LOperand* constructor) {
- inputs_[0] = constructor;
+ LCallNew(LOperand* context, LOperand* constructor) {
+ inputs_[0] = context;
+ inputs_[1] = constructor;
}
DECLARE_CONCRETE_INSTRUCTION(CallNew, "call-new")
virtual void PrintDataTo(StringStream* stream);
+ LOperand* context() { return inputs_[0]; }
+ LOperand* constructor() { return inputs_[1]; }
int arity() const { return hydrogen()->argument_count() - 1; }
};
};
-class LStoreNamedGeneric: public LStoreNamed {
+class LStoreNamedGeneric: public LTemplateInstruction<0, 3, 0> {
public:
- LStoreNamedGeneric(LOperand* obj, LOperand* val)
- : LStoreNamed(obj, val) { }
+ LStoreNamedGeneric(LOperand* context, LOperand* object, LOperand* value) {
+ inputs_[0] = context;
+ inputs_[1] = object;
+ inputs_[2] = value;
+ }
DECLARE_CONCRETE_INSTRUCTION(StoreNamedGeneric, "store-named-generic")
DECLARE_HYDROGEN_ACCESSOR(StoreNamedGeneric)
+
+ LOperand* context() { return inputs_[0]; }
+ LOperand* object() { return inputs_[1]; }
+ LOperand* value() { return inputs_[2]; }
+ Handle<Object> name() const { return hydrogen()->name(); }
};
};
-class LStoreKeyedGeneric: public LStoreKeyed {
+class LStoreKeyedGeneric: public LTemplateInstruction<0, 4, 0> {
public:
- LStoreKeyedGeneric(LOperand* obj, LOperand* key, LOperand* val)
- : LStoreKeyed(obj, key, val) { }
+ LStoreKeyedGeneric(LOperand* context,
+ LOperand* object,
+ LOperand* key,
+ LOperand* value) {
+ inputs_[0] = context;
+ inputs_[1] = object;
+ inputs_[2] = key;
+ inputs_[3] = value;
+ }
DECLARE_CONCRETE_INSTRUCTION(StoreKeyedGeneric, "store-keyed-generic")
+
+ LOperand* context() { return inputs_[0]; }
+ LOperand* object() { return inputs_[1]; }
+ LOperand* key() { return inputs_[2]; }
+ LOperand* value() { return inputs_[3]; }
};
};
-class LObjectLiteral: public LTemplateInstruction<1, 0, 0> {
+class LObjectLiteral: public LTemplateInstruction<1, 1, 0> {
public:
+ explicit LObjectLiteral(LOperand* context) {
+ inputs_[0] = context;
+ }
+
DECLARE_CONCRETE_INSTRUCTION(ObjectLiteral, "object-literal")
DECLARE_HYDROGEN_ACCESSOR(ObjectLiteral)
+
+ LOperand* context() { return inputs_[0]; }
};
int offset,
Register value,
Register scratch) {
- // The compiled code assumes that record write doesn't change the
- // context register, so we check that none of the clobbered
- // registers are esi.
- ASSERT(!object.is(esi) && !value.is(esi) && !scratch.is(esi));
-
// First, check if a write barrier is even needed. The tests below
// catch stores of Smis and stores into young gen.
NearLabel done;
void MacroAssembler::RecordWrite(Register object,
Register address,
Register value) {
- // The compiled code assumes that record write doesn't change the
- // context register, so we check that none of the clobbered
- // registers are esi.
- ASSERT(!object.is(esi) && !value.is(esi) && !address.is(esi));
-
// First, check if a write barrier is even needed. The tests below
// catch stores of Smis and stores into young gen.
Label done;