summaryrefslogtreecommitdiff
path: root/chromium/v8/src/hydrogen-instructions.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/v8/src/hydrogen-instructions.cc')
-rw-r--r--chromium/v8/src/hydrogen-instructions.cc975
1 files changed, 356 insertions, 619 deletions
diff --git a/chromium/v8/src/hydrogen-instructions.cc b/chromium/v8/src/hydrogen-instructions.cc
index d2f16f46acc..833f00b1b91 100644
--- a/chromium/v8/src/hydrogen-instructions.cc
+++ b/chromium/v8/src/hydrogen-instructions.cc
@@ -149,116 +149,6 @@ void HValue::AddDependantsToWorklist(HInferRepresentationPhase* h_infer) {
}
-// This method is recursive but it is guaranteed to terminate because
-// RedefinedOperand() always dominates "this".
-bool HValue::IsRelationTrue(NumericRelation relation,
- HValue* other,
- int offset,
- int scale) {
- if (this == other) {
- return scale == 0 && relation.IsExtendable(offset);
- }
-
- // Test the direct relation.
- if (IsRelationTrueInternal(relation, other, offset, scale)) return true;
-
- // If scale is 0 try the reversed relation.
- if (scale == 0 &&
- // TODO(mmassi): do we need the full, recursive IsRelationTrue?
- other->IsRelationTrueInternal(relation.Reversed(), this, -offset)) {
- return true;
- }
-
- // Try decomposition (but do not accept scaled compounds).
- DecompositionResult decomposition;
- if (TryDecompose(&decomposition) &&
- decomposition.scale() == 0 &&
- decomposition.base()->IsRelationTrue(relation, other,
- offset + decomposition.offset(),
- scale)) {
- return true;
- }
-
- // Pass the request to the redefined value.
- HValue* redefined = RedefinedOperand();
- return redefined != NULL && redefined->IsRelationTrue(relation, other,
- offset, scale);
-}
-
-
-bool HValue::TryGuaranteeRange(HValue* upper_bound) {
- RangeEvaluationContext context = RangeEvaluationContext(this, upper_bound);
- TryGuaranteeRangeRecursive(&context);
- bool result = context.is_range_satisfied();
- if (result) {
- context.lower_bound_guarantee()->SetResponsibilityForRange(DIRECTION_LOWER);
- context.upper_bound_guarantee()->SetResponsibilityForRange(DIRECTION_UPPER);
- }
- return result;
-}
-
-
-void HValue::TryGuaranteeRangeRecursive(RangeEvaluationContext* context) {
- // Check if we already know that this value satisfies the lower bound.
- if (context->lower_bound_guarantee() == NULL) {
- if (IsRelationTrueInternal(NumericRelation::Ge(), context->lower_bound(),
- context->offset(), context->scale())) {
- context->set_lower_bound_guarantee(this);
- }
- }
-
- // Check if we already know that this value satisfies the upper bound.
- if (context->upper_bound_guarantee() == NULL) {
- if (IsRelationTrueInternal(NumericRelation::Lt(), context->upper_bound(),
- context->offset(), context->scale()) ||
- (context->scale() == 0 &&
- context->upper_bound()->IsRelationTrue(NumericRelation::Gt(),
- this, -context->offset()))) {
- context->set_upper_bound_guarantee(this);
- }
- }
-
- if (context->is_range_satisfied()) return;
-
- // See if our RedefinedOperand() satisfies the constraints.
- if (RedefinedOperand() != NULL) {
- RedefinedOperand()->TryGuaranteeRangeRecursive(context);
- }
- if (context->is_range_satisfied()) return;
-
- // See if the constraints can be satisfied by decomposition.
- DecompositionResult decomposition;
- if (TryDecompose(&decomposition)) {
- context->swap_candidate(&decomposition);
- context->candidate()->TryGuaranteeRangeRecursive(context);
- context->swap_candidate(&decomposition);
- }
- if (context->is_range_satisfied()) return;
-
- // Try to modify this to satisfy the constraint.
-
- TryGuaranteeRangeChanging(context);
-}
-
-
-RangeEvaluationContext::RangeEvaluationContext(HValue* value, HValue* upper)
- : lower_bound_(upper->block()->graph()->GetConstant0()),
- lower_bound_guarantee_(NULL),
- candidate_(value),
- upper_bound_(upper),
- upper_bound_guarantee_(NULL),
- offset_(0),
- scale_(0) {
-}
-
-
-HValue* RangeEvaluationContext::ConvertGuarantee(HValue* guarantee) {
- return guarantee->IsBoundsCheckBaseIndexInformation()
- ? HBoundsCheckBaseIndexInformation::cast(guarantee)->bounds_check()
- : guarantee;
-}
-
-
static int32_t ConvertAndSetOverflow(Representation r,
int64_t result,
bool* overflow) {
@@ -484,55 +374,6 @@ HType HType::TypeFromValue(Handle<Object> value) {
}
-bool HValue::Dominates(HValue* dominator, HValue* dominated) {
- if (dominator->block() != dominated->block()) {
- // If they are in different blocks we can use the dominance relation
- // between the blocks.
- return dominator->block()->Dominates(dominated->block());
- } else {
- // Otherwise we must see which instruction comes first, considering
- // that phis always precede regular instructions.
- if (dominator->IsInstruction()) {
- if (dominated->IsInstruction()) {
- for (HInstruction* next = HInstruction::cast(dominator)->next();
- next != NULL;
- next = next->next()) {
- if (next == dominated) return true;
- }
- return false;
- } else if (dominated->IsPhi()) {
- return false;
- } else {
- UNREACHABLE();
- }
- } else if (dominator->IsPhi()) {
- if (dominated->IsInstruction()) {
- return true;
- } else {
- // We cannot compare which phi comes first.
- UNREACHABLE();
- }
- } else {
- UNREACHABLE();
- }
- return false;
- }
-}
-
-
-bool HValue::TestDominanceUsingProcessedFlag(HValue* dominator,
- HValue* dominated) {
- if (dominator->block() != dominated->block()) {
- return dominator->block()->Dominates(dominated->block());
- } else {
- // If both arguments are in the same block we check if dominator is a phi
- // or if dominated has not already been processed: in either case we know
- // that dominator precedes dominated.
- return dominator->IsPhi() || !dominated->CheckFlag(kIDefsProcessingDone);
- }
-}
-
-
bool HValue::IsDefinedAfter(HBasicBlock* other) const {
return block()->block_id() > other->block_id();
}
@@ -547,7 +388,7 @@ HUseListNode* HUseListNode::tail() {
}
-bool HValue::CheckUsesForFlag(Flag f) {
+bool HValue::CheckUsesForFlag(Flag f) const {
for (HUseIterator it(uses()); !it.Done(); it.Advance()) {
if (it.value()->IsSimulate()) continue;
if (!it.value()->CheckFlag(f)) return false;
@@ -556,7 +397,19 @@ bool HValue::CheckUsesForFlag(Flag f) {
}
-bool HValue::HasAtLeastOneUseWithFlagAndNoneWithout(Flag f) {
+bool HValue::CheckUsesForFlag(Flag f, HValue** value) const {
+ for (HUseIterator it(uses()); !it.Done(); it.Advance()) {
+ if (it.value()->IsSimulate()) continue;
+ if (!it.value()->CheckFlag(f)) {
+ *value = it.value();
+ return false;
+ }
+ }
+ return true;
+}
+
+
+bool HValue::HasAtLeastOneUseWithFlagAndNoneWithout(Flag f) const {
bool return_value = false;
for (HUseIterator it(uses()); !it.Done(); it.Advance()) {
if (it.value()->IsSimulate()) continue;
@@ -960,58 +813,6 @@ void HInstruction::Verify() {
#endif
-HNumericConstraint* HNumericConstraint::AddToGraph(
- HValue* constrained_value,
- NumericRelation relation,
- HValue* related_value,
- HInstruction* insertion_point) {
- if (insertion_point == NULL) {
- if (constrained_value->IsInstruction()) {
- insertion_point = HInstruction::cast(constrained_value);
- } else if (constrained_value->IsPhi()) {
- insertion_point = constrained_value->block()->first();
- } else {
- UNREACHABLE();
- }
- }
- HNumericConstraint* result =
- new(insertion_point->block()->zone()) HNumericConstraint(
- constrained_value, relation, related_value);
- result->InsertAfter(insertion_point);
- return result;
-}
-
-
-void HNumericConstraint::PrintDataTo(StringStream* stream) {
- stream->Add("(");
- constrained_value()->PrintNameTo(stream);
- stream->Add(" %s ", relation().Mnemonic());
- related_value()->PrintNameTo(stream);
- stream->Add(")");
-}
-
-
-HInductionVariableAnnotation* HInductionVariableAnnotation::AddToGraph(
- HPhi* phi,
- NumericRelation relation,
- int operand_index) {
- HInductionVariableAnnotation* result =
- new(phi->block()->zone()) HInductionVariableAnnotation(phi, relation,
- operand_index);
- result->InsertAfter(phi->block()->first());
- return result;
-}
-
-
-void HInductionVariableAnnotation::PrintDataTo(StringStream* stream) {
- stream->Add("(");
- RedefinedOperand()->PrintNameTo(stream);
- stream->Add(" %s ", relation().Mnemonic());
- induction_base()->PrintNameTo(stream);
- stream->Add(")");
-}
-
-
void HDummyUse::PrintDataTo(StringStream* stream) {
value()->PrintNameTo(stream);
}
@@ -1038,40 +839,6 @@ void HBinaryCall::PrintDataTo(StringStream* stream) {
}
-void HBoundsCheck::TryGuaranteeRangeChanging(RangeEvaluationContext* context) {
- if (context->candidate()->ActualValue() != base()->ActualValue() ||
- context->scale() < scale()) {
- return;
- }
-
- // TODO(mmassi)
- // Instead of checking for "same basic block" we should check for
- // "dominates and postdominates".
- if (context->upper_bound() == length() &&
- context->lower_bound_guarantee() != NULL &&
- context->lower_bound_guarantee() != this &&
- context->lower_bound_guarantee()->block() != block() &&
- offset() < context->offset() &&
- index_can_increase() &&
- context->upper_bound_guarantee() == NULL) {
- offset_ = context->offset();
- SetResponsibilityForRange(DIRECTION_UPPER);
- context->set_upper_bound_guarantee(this);
- isolate()->counters()->bounds_checks_eliminated()->Increment();
- } else if (context->upper_bound_guarantee() != NULL &&
- context->upper_bound_guarantee() != this &&
- context->upper_bound_guarantee()->block() != block() &&
- offset() > context->offset() &&
- index_can_decrease() &&
- context->lower_bound_guarantee() == NULL) {
- offset_ = context->offset();
- SetResponsibilityForRange(DIRECTION_LOWER);
- context->set_lower_bound_guarantee(this);
- isolate()->counters()->bounds_checks_eliminated()->Increment();
- }
-}
-
-
void HBoundsCheck::ApplyIndexChange() {
if (skip_check()) return;
@@ -1119,40 +886,6 @@ void HBoundsCheck::ApplyIndexChange() {
base_ = NULL;
offset_ = 0;
scale_ = 0;
- responsibility_direction_ = DIRECTION_NONE;
-}
-
-
-void HBoundsCheck::AddInformativeDefinitions() {
- // TODO(mmassi): Executing this code during AddInformativeDefinitions
- // is a hack. Move it to some other HPhase.
- if (FLAG_array_bounds_checks_elimination) {
- if (index()->TryGuaranteeRange(length())) {
- set_skip_check();
- }
- if (DetectCompoundIndex()) {
- HBoundsCheckBaseIndexInformation* base_index_info =
- new(block()->graph()->zone())
- HBoundsCheckBaseIndexInformation(this);
- base_index_info->InsertAfter(this);
- }
- }
-}
-
-
-bool HBoundsCheck::IsRelationTrueInternal(NumericRelation relation,
- HValue* related_value,
- int offset,
- int scale) {
- if (related_value == length()) {
- // A HBoundsCheck is smaller than the length it compared against.
- return NumericRelation::Lt().CompoundImplies(relation, 0, 0, offset, scale);
- } else if (related_value == block()->graph()->GetConstant0()) {
- // A HBoundsCheck is greater than or equal to zero.
- return NumericRelation::Ge().CompoundImplies(relation, 0, 0, offset, scale);
- } else {
- return false;
- }
}
@@ -1195,25 +928,6 @@ void HBoundsCheck::InferRepresentation(HInferRepresentationPhase* h_infer) {
}
-bool HBoundsCheckBaseIndexInformation::IsRelationTrueInternal(
- NumericRelation relation,
- HValue* related_value,
- int offset,
- int scale) {
- if (related_value == bounds_check()->length()) {
- return NumericRelation::Lt().CompoundImplies(
- relation,
- bounds_check()->offset(), bounds_check()->scale(), offset, scale);
- } else if (related_value == block()->graph()->GetConstant0()) {
- return NumericRelation::Ge().CompoundImplies(
- relation,
- bounds_check()->offset(), bounds_check()->scale(), offset, scale);
- } else {
- return false;
- }
-}
-
-
void HBoundsCheckBaseIndexInformation::PrintDataTo(StringStream* stream) {
stream->Add("base: ");
base_index()->PrintNameTo(stream);
@@ -1453,6 +1167,29 @@ void HLoadFieldByIndex::PrintDataTo(StringStream* stream) {
}
+static bool MatchLeftIsOnes(HValue* l, HValue* r, HValue** negated) {
+ if (!l->EqualsInteger32Constant(~0)) return false;
+ *negated = r;
+ return true;
+}
+
+
+static bool MatchNegationViaXor(HValue* instr, HValue** negated) {
+ if (!instr->IsBitwise()) return false;
+ HBitwise* b = HBitwise::cast(instr);
+ return (b->op() == Token::BIT_XOR) &&
+ (MatchLeftIsOnes(b->left(), b->right(), negated) ||
+ MatchLeftIsOnes(b->right(), b->left(), negated));
+}
+
+
+static bool MatchDoubleNegation(HValue* instr, HValue** arg) {
+ HValue* negated;
+ return MatchNegationViaXor(instr, &negated) &&
+ MatchNegationViaXor(negated, arg);
+}
+
+
HValue* HBitwise::Canonicalize() {
if (!representation().IsSmiOrInteger32()) return this;
// If x is an int32, then x & -1 == x, x | 0 == x and x ^ 0 == x.
@@ -1465,18 +1202,10 @@ HValue* HBitwise::Canonicalize() {
!left()->CheckFlag(kUint32)) {
return left();
}
- return this;
-}
-
-
-HValue* HBitNot::Canonicalize() {
- // Optimize ~~x, a common pattern used for ToInt32(x).
- if (value()->IsBitNot()) {
- HValue* result = HBitNot::cast(value())->value();
- ASSERT(result->representation().IsInteger32());
- if (!result->CheckFlag(kUint32)) {
- return result;
- }
+ // Optimize double negation, a common pattern used for ToInt32(x).
+ HValue* arg;
+ if (MatchDoubleNegation(this, &arg) && !arg->CheckFlag(kUint32)) {
+ return arg;
}
return this;
}
@@ -1489,8 +1218,15 @@ static bool IsIdentityOperation(HValue* arg1, HValue* arg2, int32_t identity) {
HValue* HAdd::Canonicalize() {
- if (IsIdentityOperation(left(), right(), 0)) return left();
- if (IsIdentityOperation(right(), left(), 0)) return right();
+ // Adding 0 is an identity operation except in case of -0: -0 + 0 = +0
+ if (IsIdentityOperation(left(), right(), 0) &&
+ !left()->representation().IsDouble()) { // Left could be -0.
+ return left();
+ }
+ if (IsIdentityOperation(right(), left(), 0) &&
+ !left()->representation().IsDouble()) { // Right could be -0.
+ return right();
+ }
return this;
}
@@ -1514,6 +1250,7 @@ HValue* HMod::Canonicalize() {
HValue* HDiv::Canonicalize() {
+ if (IsIdentityOperation(left(), right(), 1)) return left();
return this;
}
@@ -1568,16 +1305,16 @@ static HValue* SimplifiedDividendForMathFloorOfDiv(HValue* dividend) {
HValue* HUnaryMathOperation::Canonicalize() {
- if (op() == kMathRound) {
+ if (op() == kMathRound || op() == kMathFloor) {
HValue* val = value();
if (val->IsChange()) val = HChange::cast(val)->value();
- // If the input is integer32 then we replace the round instruction
- // with its input.
+ // If the input is smi or integer32 then we replace the instruction with its
+ // input.
if (val->representation().IsSmiOrInteger32()) {
if (!val->representation().Equals(representation())) {
HChange* result = new(block()->zone()) HChange(
- val, representation(), false, false, false);
+ val, representation(), false, false);
result->InsertBefore(this);
return result;
}
@@ -1588,19 +1325,6 @@ HValue* HUnaryMathOperation::Canonicalize() {
if (op() == kMathFloor) {
HValue* val = value();
if (val->IsChange()) val = HChange::cast(val)->value();
-
- // If the input is integer32 then we replace the floor instruction
- // with its input.
- if (val->representation().IsSmiOrInteger32()) {
- if (!val->representation().Equals(representation())) {
- HChange* result = new(block()->zone()) HChange(
- val, representation(), false, false, false);
- result->InsertBefore(this);
- return result;
- }
- return val;
- }
-
if (val->IsDiv() && (val->UseCount() == 1)) {
HDiv* hdiv = HDiv::cast(val);
HValue* left = hdiv->left();
@@ -1610,7 +1334,7 @@ HValue* HUnaryMathOperation::Canonicalize() {
if (new_left == NULL &&
hdiv->observed_input_representation(1).IsSmiOrInteger32()) {
new_left = new(block()->zone()) HChange(
- left, Representation::Integer32(), false, false, false);
+ left, Representation::Integer32(), false, false);
HChange::cast(new_left)->InsertBefore(this);
}
HValue* new_right =
@@ -1621,7 +1345,7 @@ HValue* HUnaryMathOperation::Canonicalize() {
#endif
hdiv->observed_input_representation(2).IsSmiOrInteger32()) {
new_right = new(block()->zone()) HChange(
- right, Representation::Integer32(), false, false, false);
+ right, Representation::Integer32(), false, false);
HChange::cast(new_right)->InsertBefore(this);
}
@@ -1712,10 +1436,10 @@ void HCheckMaps::HandleSideEffectDominator(GVNFlag side_effect,
// for which the map is known.
if (HasNoUses() && dominator->IsStoreNamedField()) {
HStoreNamedField* store = HStoreNamedField::cast(dominator);
- UniqueValueId map_unique_id = store->transition_unique_id();
- if (!map_unique_id.IsInitialized() || store->object() != value()) return;
+ if (!store->has_transition() || store->object() != value()) return;
+ HConstant* transition = HConstant::cast(store->transition());
for (int i = 0; i < map_set()->length(); i++) {
- if (map_unique_id == map_unique_ids_.at(i)) {
+ if (transition->UniqueValueIdsMatch(map_unique_ids_.at(i))) {
DeleteAndReplaceWith(NULL);
return;
}
@@ -1734,15 +1458,16 @@ void HCheckMaps::PrintDataTo(StringStream* stream) {
}
-void HCheckFunction::PrintDataTo(StringStream* stream) {
+void HCheckValue::PrintDataTo(StringStream* stream) {
value()->PrintNameTo(stream);
- stream->Add(" %p", *target());
+ stream->Add(" ");
+ object()->ShortPrint(stream);
}
-HValue* HCheckFunction::Canonicalize() {
+HValue* HCheckValue::Canonicalize() {
return (value()->IsConstant() &&
- HConstant::cast(value())->UniqueValueIdsMatch(target_unique_id_))
+ HConstant::cast(value())->UniqueValueIdsMatch(object_unique_id_))
? NULL
: this;
}
@@ -1766,13 +1491,6 @@ void HCheckInstanceType::PrintDataTo(StringStream* stream) {
}
-void HCheckPrototypeMaps::PrintDataTo(StringStream* stream) {
- stream->Add("[receiver_prototype=%p,holder=%p]%s",
- *prototypes_.first(), *prototypes_.last(),
- CanOmitPrototypeChecks() ? " (omitted)" : "");
-}
-
-
void HCallStub::PrintDataTo(StringStream* stream) {
stream->Add("%s ",
CodeStub::MajorName(major_key_, false));
@@ -1780,6 +1498,15 @@ void HCallStub::PrintDataTo(StringStream* stream) {
}
+void HUnknownOSRValue::PrintDataTo(StringStream *stream) {
+ const char* type = "expression";
+ if (environment_->is_local_index(index_)) type = "local";
+ if (environment_->is_special_index(index_)) type = "special";
+ if (environment_->is_parameter_index(index_)) type = "parameter";
+ stream->Add("%s @ %d", type, index_);
+}
+
+
void HInstanceOf::PrintDataTo(StringStream* stream) {
left()->PrintNameTo(stream);
stream->Add(" ");
@@ -1975,60 +1702,6 @@ Range* HMod::InferRange(Zone* zone) {
}
-void HPhi::AddInformativeDefinitions() {
- if (OperandCount() == 2) {
- // If one of the operands is an OSR block give up (this cannot be an
- // induction variable).
- if (OperandAt(0)->block()->is_osr_entry() ||
- OperandAt(1)->block()->is_osr_entry()) return;
-
- for (int operand_index = 0; operand_index < 2; operand_index++) {
- int other_operand_index = (operand_index + 1) % 2;
-
- static NumericRelation relations[] = {
- NumericRelation::Ge(),
- NumericRelation::Le()
- };
-
- // Check if this phi is an induction variable. If, e.g., we know that
- // its first input is greater than the phi itself, then that must be
- // the back edge, and the phi is always greater than its second input.
- for (int relation_index = 0; relation_index < 2; relation_index++) {
- if (OperandAt(operand_index)->IsRelationTrue(relations[relation_index],
- this)) {
- HInductionVariableAnnotation::AddToGraph(this,
- relations[relation_index],
- other_operand_index);
- }
- }
- }
- }
-}
-
-
-bool HPhi::IsRelationTrueInternal(NumericRelation relation,
- HValue* other,
- int offset,
- int scale) {
- if (CheckFlag(kNumericConstraintEvaluationInProgress)) return false;
-
- SetFlag(kNumericConstraintEvaluationInProgress);
- bool result = true;
- for (int i = 0; i < OperandCount(); i++) {
- // Skip OSR entry blocks
- if (OperandAt(i)->block()->is_osr_entry()) continue;
-
- if (!OperandAt(i)->IsRelationTrue(relation, other, offset, scale)) {
- result = false;
- break;
- }
- }
- ClearFlag(kNumericConstraintEvaluationInProgress);
-
- return result;
-}
-
-
InductionVariableData* InductionVariableData::ExaminePhi(HPhi* phi) {
if (phi->block()->loop_information() == NULL) return NULL;
if (phi->OperandCount() != 2) return NULL;
@@ -2646,6 +2319,38 @@ void HSimulate::PrintDataTo(StringStream* stream) {
}
+void HSimulate::ReplayEnvironment(HEnvironment* env) {
+ ASSERT(env != NULL);
+ env->set_ast_id(ast_id());
+ env->Drop(pop_count());
+ for (int i = values()->length() - 1; i >= 0; --i) {
+ HValue* value = values()->at(i);
+ if (HasAssignedIndexAt(i)) {
+ env->Bind(GetAssignedIndexAt(i), value);
+ } else {
+ env->Push(value);
+ }
+ }
+}
+
+
+// Replay captured objects by replacing all captured objects with the
+// same capture id in the current and all outer environments.
+void HCapturedObject::ReplayEnvironment(HEnvironment* env) {
+ ASSERT(env != NULL);
+ while (env != NULL) {
+ for (int i = 0; i < env->length(); ++i) {
+ HValue* value = env->values()->at(i);
+ if (value->IsCapturedObject() &&
+ HCapturedObject::cast(value)->capture_id() == this->capture_id()) {
+ env->SetValueAt(i, this);
+ }
+ }
+ env = env->outer();
+ }
+}
+
+
void HEnterInlined::RegisterReturnTarget(HBasicBlock* return_target,
Zone* zone) {
ASSERT(return_target->IsInlineReturnTarget());
@@ -2723,6 +2428,24 @@ HConstant::HConstant(Handle<Object> handle,
}
+HConstant::HConstant(Handle<Map> handle,
+ UniqueValueId unique_id)
+ : HTemplateInstruction<0>(HType::Tagged()),
+ handle_(handle),
+ unique_id_(unique_id),
+ has_smi_value_(false),
+ has_int32_value_(false),
+ has_double_value_(false),
+ has_external_reference_value_(false),
+ is_internalized_string_(false),
+ is_not_in_new_space_(true),
+ is_cell_(false),
+ boolean_value_(false) {
+ ASSERT(!handle.is_null());
+ Initialize(Representation::Tagged());
+}
+
+
HConstant::HConstant(int32_t integer_value,
Representation r,
bool is_not_in_new_space,
@@ -2780,9 +2503,17 @@ HConstant::HConstant(ExternalReference reference)
}
+static void PrepareConstant(Handle<Object> object) {
+ if (!object->IsJSObject()) return;
+ Handle<JSObject> js_object = Handle<JSObject>::cast(object);
+ if (!js_object->map()->is_deprecated()) return;
+ JSObject::TryMigrateInstance(js_object);
+}
+
+
void HConstant::Initialize(Representation r) {
if (r.IsNone()) {
- if (has_smi_value_ && kSmiValueSize == 31) {
+ if (has_smi_value_ && SmiValuesAre31Bits()) {
r = Representation::Smi();
} else if (has_int32_value_) {
r = Representation::Integer32();
@@ -2791,6 +2522,7 @@ void HConstant::Initialize(Representation r) {
} else if (has_external_reference_value_) {
r = Representation::External();
} else {
+ PrepareConstant(handle_);
r = Representation::Tagged();
}
}
@@ -2859,12 +2591,13 @@ Maybe<HConstant*> HConstant::CopyToTruncatedInt32(Zone* zone) {
Maybe<HConstant*> HConstant::CopyToTruncatedNumber(Zone* zone) {
HConstant* res = NULL;
- if (handle()->IsBoolean()) {
- res = handle()->BooleanValue() ?
+ Handle<Object> handle = this->handle(zone->isolate());
+ if (handle->IsBoolean()) {
+ res = handle->BooleanValue() ?
new(zone) HConstant(1) : new(zone) HConstant(0);
- } else if (handle()->IsUndefined()) {
+ } else if (handle->IsUndefined()) {
res = new(zone) HConstant(OS::nan_value());
- } else if (handle()->IsNull()) {
+ } else if (handle->IsNull()) {
res = new(zone) HConstant(0);
}
return Maybe<HConstant*>(res != NULL, res);
@@ -2880,7 +2613,7 @@ void HConstant::PrintDataTo(StringStream* stream) {
stream->Add("%p ", reinterpret_cast<void*>(
external_reference_value_.address()));
} else {
- handle()->ShortPrint(stream);
+ handle(Isolate::Current())->ShortPrint(stream);
}
}
@@ -3115,16 +2848,6 @@ void HStringCompareAndBranch::PrintDataTo(StringStream* stream) {
}
-void HCompareNumericAndBranch::AddInformativeDefinitions() {
- NumericRelation r = NumericRelation::FromToken(token());
- if (r.IsNone()) return;
-
- HNumericConstraint::AddToGraph(left(), r, right(), SuccessorAt(0)->first());
- HNumericConstraint::AddToGraph(
- left(), r.Negated(), right(), SuccessorAt(1)->first());
-}
-
-
void HCompareNumericAndBranch::PrintDataTo(StringStream* stream) {
stream->Add(Token::Name(token()));
stream->Add(" ");
@@ -3143,6 +2866,18 @@ void HCompareObjectEqAndBranch::PrintDataTo(StringStream* stream) {
}
+void HCompareHoleAndBranch::PrintDataTo(StringStream* stream) {
+ object()->PrintNameTo(stream);
+ HControlInstruction::PrintDataTo(stream);
+}
+
+
+void HCompareHoleAndBranch::InferRepresentation(
+ HInferRepresentationPhase* h_infer) {
+ ChangeRepresentation(object()->representation());
+}
+
+
void HGoto::PrintDataTo(StringStream* stream) {
stream->Add("B%d", SuccessorAt(0)->block_id());
}
@@ -3195,123 +2930,6 @@ void HParameter::PrintDataTo(StringStream* stream) {
void HLoadNamedField::PrintDataTo(StringStream* stream) {
object()->PrintNameTo(stream);
access_.PrintTo(stream);
- if (HasTypeCheck()) {
- stream->Add(" ");
- typecheck()->PrintNameTo(stream);
- }
-}
-
-
-// Returns true if an instance of this map can never find a property with this
-// name in its prototype chain. This means all prototypes up to the top are
-// fast and don't have the name in them. It would be good if we could optimize
-// polymorphic loads where the property is sometimes found in the prototype
-// chain.
-static bool PrototypeChainCanNeverResolve(
- Handle<Map> map, Handle<String> name) {
- Isolate* isolate = map->GetIsolate();
- Object* current = map->prototype();
- while (current != isolate->heap()->null_value()) {
- if (current->IsJSGlobalProxy() ||
- current->IsGlobalObject() ||
- !current->IsJSObject() ||
- JSObject::cast(current)->map()->has_named_interceptor() ||
- JSObject::cast(current)->IsAccessCheckNeeded() ||
- !JSObject::cast(current)->HasFastProperties()) {
- return false;
- }
-
- LookupResult lookup(isolate);
- Map* map = JSObject::cast(current)->map();
- map->LookupDescriptor(NULL, *name, &lookup);
- if (lookup.IsFound()) return false;
- if (!lookup.IsCacheable()) return false;
- current = JSObject::cast(current)->GetPrototype();
- }
- return true;
-}
-
-
-HLoadNamedFieldPolymorphic::HLoadNamedFieldPolymorphic(HValue* context,
- HValue* object,
- SmallMapList* types,
- Handle<String> name,
- Zone* zone)
- : types_(Min(types->length(), kMaxLoadPolymorphism), zone),
- name_(name),
- types_unique_ids_(0, zone),
- name_unique_id_(),
- need_generic_(false) {
- SetOperandAt(0, context);
- SetOperandAt(1, object);
- set_representation(Representation::Tagged());
- SetGVNFlag(kDependsOnMaps);
- SmallMapList negative_lookups;
- for (int i = 0;
- i < types->length() && types_.length() < kMaxLoadPolymorphism;
- ++i) {
- Handle<Map> map = types->at(i);
- // Deprecated maps are updated to the current map in the type oracle.
- ASSERT(!map->is_deprecated());
- LookupResult lookup(map->GetIsolate());
- map->LookupDescriptor(NULL, *name, &lookup);
- if (lookup.IsFound()) {
- switch (lookup.type()) {
- case FIELD: {
- int index = lookup.GetLocalFieldIndexFromMap(*map);
- if (index < 0) {
- SetGVNFlag(kDependsOnInobjectFields);
- } else {
- SetGVNFlag(kDependsOnBackingStoreFields);
- }
- if (FLAG_track_double_fields &&
- lookup.representation().IsDouble()) {
- // Since the value needs to be boxed, use a generic handler for
- // loading doubles.
- continue;
- }
- types_.Add(types->at(i), zone);
- break;
- }
- case CONSTANT:
- types_.Add(types->at(i), zone);
- break;
- case CALLBACKS:
- break;
- case TRANSITION:
- case INTERCEPTOR:
- case NONEXISTENT:
- case NORMAL:
- case HANDLER:
- UNREACHABLE();
- break;
- }
- } else if (lookup.IsCacheable() &&
- // For dicts the lookup on the map will fail, but the object may
- // contain the property so we cannot generate a negative lookup
- // (which would just be a map check and return undefined).
- !map->is_dictionary_map() &&
- !map->has_named_interceptor() &&
- PrototypeChainCanNeverResolve(map, name)) {
- negative_lookups.Add(types->at(i), zone);
- }
- }
-
- bool need_generic =
- (types->length() != negative_lookups.length() + types_.length());
- if (!need_generic && FLAG_deoptimize_uncommon_cases) {
- SetFlag(kUseGVN);
- for (int i = 0; i < negative_lookups.length(); i++) {
- types_.Add(negative_lookups.at(i), zone);
- }
- } else {
- // We don't have an easy way to handle both a call (to the generic stub) and
- // a deopt in the same hydrogen instruction, so in this case we don't add
- // the negative lookups which can deopt - just let the generic stub handle
- // them.
- SetAllSideEffects();
- need_generic_ = true;
- }
}
@@ -3322,10 +2940,10 @@ HCheckMaps* HCheckMaps::New(Zone* zone,
CompilationInfo* info,
HValue* typecheck) {
HCheckMaps* check_map = new(zone) HCheckMaps(value, zone, typecheck);
- check_map->map_set_.Add(map, zone);
+ check_map->Add(map, zone);
if (map->CanOmitMapChecks() &&
value->IsConstant() &&
- HConstant::cast(value)->InstanceOf(map)) {
+ HConstant::cast(value)->HasMap(map)) {
check_map->omit(info);
}
return check_map;
@@ -3342,46 +2960,6 @@ void HCheckMaps::FinalizeUniqueValueId() {
}
-void HLoadNamedFieldPolymorphic::FinalizeUniqueValueId() {
- if (!types_unique_ids_.is_empty()) return;
- Zone* zone = block()->zone();
- types_unique_ids_.Initialize(types_.length(), zone);
- for (int i = 0; i < types_.length(); i++) {
- types_unique_ids_.Add(UniqueValueId(types_.at(i)), zone);
- }
- name_unique_id_ = UniqueValueId(name_);
-}
-
-
-bool HLoadNamedFieldPolymorphic::DataEquals(HValue* value) {
- ASSERT_EQ(types_.length(), types_unique_ids_.length());
- HLoadNamedFieldPolymorphic* other = HLoadNamedFieldPolymorphic::cast(value);
- if (name_unique_id_ != other->name_unique_id_) return false;
- if (types_unique_ids_.length() != other->types_unique_ids_.length()) {
- return false;
- }
- if (need_generic_ != other->need_generic_) return false;
- for (int i = 0; i < types_unique_ids_.length(); i++) {
- bool found = false;
- for (int j = 0; j < types_unique_ids_.length(); j++) {
- if (types_unique_ids_.at(j) == other->types_unique_ids_.at(i)) {
- found = true;
- break;
- }
- }
- if (!found) return false;
- }
- return true;
-}
-
-
-void HLoadNamedFieldPolymorphic::PrintDataTo(StringStream* stream) {
- object()->PrintNameTo(stream);
- stream->Add(".");
- stream->Add(*String::cast(*name())->ToCString());
-}
-
-
void HLoadNamedGeneric::PrintDataTo(StringStream* stream) {
object()->PrintNameTo(stream);
stream->Add(".");
@@ -3454,18 +3032,8 @@ bool HLoadKeyed::UsesMustHandleHole() const {
bool HLoadKeyed::AllUsesCanTreatHoleAsNaN() const {
- if (!IsFastDoubleElementsKind(elements_kind())) {
- return false;
- }
-
- for (HUseIterator it(uses()); !it.Done(); it.Advance()) {
- HValue* use = it.value();
- if (!use->CheckFlag(HValue::kAllowUndefinedAsNaN)) {
- return false;
- }
- }
-
- return true;
+ return IsFastDoubleElementsKind(elements_kind()) &&
+ CheckUsesForFlag(HValue::kAllowUndefinedAsNaN);
}
@@ -3547,8 +3115,8 @@ void HStoreNamedField::PrintDataTo(StringStream* stream) {
if (NeedsWriteBarrier()) {
stream->Add(" (write-barrier)");
}
- if (!transition().is_null()) {
- stream->Add(" (transition map %p)", *transition());
+ if (has_transition()) {
+ stream->Add(" (transition map %p)", *transition_map());
}
}
@@ -3594,6 +3162,7 @@ void HTransitionElementsKind::PrintDataTo(StringStream* stream) {
ElementsAccessor::ForKind(from_kind)->name(),
*transitioned_map(),
ElementsAccessor::ForKind(to_kind)->name());
+ if (IsSimpleMapChangeTransition(from_kind, to_kind)) stream->Add(" (simple)");
}
@@ -3684,8 +3253,6 @@ Representation HUnaryMathOperation::RepresentationFromInputs() {
Representation input_rep = value()->representation();
if (!input_rep.IsTagged()) {
rep = rep.generalize(input_rep);
- } else if (flexible_int()) {
- rep = Representation::Integer32();
}
return rep;
}
@@ -3694,6 +3261,7 @@ Representation HUnaryMathOperation::RepresentationFromInputs() {
void HAllocate::HandleSideEffectDominator(GVNFlag side_effect,
HValue* dominator) {
ASSERT(side_effect == kChangesNewSpacePromotion);
+ Zone* zone = block()->zone();
if (!FLAG_use_allocation_folding) return;
// Try to fold allocations together with their dominating allocations.
@@ -3705,31 +3273,44 @@ void HAllocate::HandleSideEffectDominator(GVNFlag side_effect,
return;
}
- HAllocate* dominator_allocate_instr = HAllocate::cast(dominator);
- HValue* dominator_size = dominator_allocate_instr->size();
+ HAllocate* dominator_allocate = HAllocate::cast(dominator);
+ HValue* dominator_size = dominator_allocate->size();
HValue* current_size = size();
- // We can just fold allocations that are guaranteed in new space.
+
// TODO(hpayer): Add support for non-constant allocation in dominator.
- if (!IsNewSpaceAllocation() || !current_size->IsInteger32Constant() ||
- !dominator_allocate_instr->IsNewSpaceAllocation() ||
+ if (!current_size->IsInteger32Constant() ||
!dominator_size->IsInteger32Constant()) {
if (FLAG_trace_allocation_folding) {
- PrintF("#%d (%s) cannot fold into #%d (%s)\n",
+ PrintF("#%d (%s) cannot fold into #%d (%s), dynamic allocation size\n",
id(), Mnemonic(), dominator->id(), dominator->Mnemonic());
}
return;
}
+ dominator_allocate = GetFoldableDominator(dominator_allocate);
+ if (dominator_allocate == NULL) {
+ return;
+ }
+
+ ASSERT((IsNewSpaceAllocation() &&
+ dominator_allocate->IsNewSpaceAllocation()) ||
+ (IsOldDataSpaceAllocation() &&
+ dominator_allocate->IsOldDataSpaceAllocation()) ||
+ (IsOldPointerSpaceAllocation() &&
+ dominator_allocate->IsOldPointerSpaceAllocation()));
+
// First update the size of the dominator allocate instruction.
- int32_t dominator_size_constant =
+ dominator_size = dominator_allocate->size();
+ int32_t original_object_size =
HConstant::cast(dominator_size)->GetInteger32Constant();
+ int32_t dominator_size_constant = original_object_size;
int32_t current_size_constant =
HConstant::cast(current_size)->GetInteger32Constant();
int32_t new_dominator_size = dominator_size_constant + current_size_constant;
if (MustAllocateDoubleAligned()) {
- if (!dominator_allocate_instr->MustAllocateDoubleAligned()) {
- dominator_allocate_instr->MakeDoubleAligned();
+ if (!dominator_allocate->MustAllocateDoubleAligned()) {
+ dominator_allocate->MakeDoubleAligned();
}
if ((dominator_size_constant & kDoubleAlignmentMask) != 0) {
dominator_size_constant += kDoubleSize / 2;
@@ -3740,36 +3321,180 @@ void HAllocate::HandleSideEffectDominator(GVNFlag side_effect,
if (new_dominator_size > Page::kMaxNonCodeHeapObjectSize) {
if (FLAG_trace_allocation_folding) {
PrintF("#%d (%s) cannot fold into #%d (%s) due to size: %d\n",
- id(), Mnemonic(), dominator->id(), dominator->Mnemonic(),
- new_dominator_size);
+ id(), Mnemonic(), dominator_allocate->id(),
+ dominator_allocate->Mnemonic(), new_dominator_size);
}
return;
}
- HBasicBlock* block = dominator->block();
- Zone* zone = block->zone();
- HInstruction* new_dominator_size_constant =
- HConstant::New(zone, context(), new_dominator_size);
- new_dominator_size_constant->InsertBefore(dominator_allocate_instr);
- dominator_allocate_instr->UpdateSize(new_dominator_size_constant);
+
+ HInstruction* new_dominator_size_constant = HConstant::CreateAndInsertBefore(
+ zone,
+ context(),
+ new_dominator_size,
+ Representation::None(),
+ dominator_allocate);
+ dominator_allocate->UpdateSize(new_dominator_size_constant);
#ifdef VERIFY_HEAP
- if (FLAG_verify_heap) {
- dominator_allocate_instr->MakePrefillWithFiller();
+ if (FLAG_verify_heap && dominator_allocate->IsNewSpaceAllocation()) {
+ dominator_allocate->MakePrefillWithFiller();
+ } else {
+ // TODO(hpayer): This is a short-term hack to make allocation mementos
+ // work again in new space.
+ dominator_allocate->ClearNextMapWord(original_object_size);
}
+#else
+ // TODO(hpayer): This is a short-term hack to make allocation mementos
+ // work again in new space.
+ dominator_allocate->ClearNextMapWord(original_object_size);
#endif
+ dominator_allocate->clear_next_map_word_ = clear_next_map_word_;
+
// After that replace the dominated allocate instruction.
HInstruction* dominated_allocate_instr =
HInnerAllocatedObject::New(zone,
context(),
- dominator_allocate_instr,
+ dominator_allocate,
dominator_size_constant,
type());
dominated_allocate_instr->InsertBefore(this);
DeleteAndReplaceWith(dominated_allocate_instr);
if (FLAG_trace_allocation_folding) {
PrintF("#%d (%s) folded into #%d (%s)\n",
- id(), Mnemonic(), dominator->id(), dominator->Mnemonic());
+ id(), Mnemonic(), dominator_allocate->id(),
+ dominator_allocate->Mnemonic());
+ }
+}
+
+
+HAllocate* HAllocate::GetFoldableDominator(HAllocate* dominator) {
+ if (!IsFoldable(dominator)) {
+ // We cannot hoist old space allocations over new space allocations.
+ if (IsNewSpaceAllocation() || dominator->IsNewSpaceAllocation()) {
+ if (FLAG_trace_allocation_folding) {
+ PrintF("#%d (%s) cannot fold into #%d (%s), new space hoisting\n",
+ id(), Mnemonic(), dominator->id(), dominator->Mnemonic());
+ }
+ return NULL;
+ }
+
+ HAllocate* dominator_dominator = dominator->dominating_allocate_;
+
+ // We can hoist old data space allocations over an old pointer space
+ // allocation and vice versa. For that we have to check the dominator
+ // of the dominator allocate instruction.
+ if (dominator_dominator == NULL) {
+ dominating_allocate_ = dominator;
+ if (FLAG_trace_allocation_folding) {
+ PrintF("#%d (%s) cannot fold into #%d (%s), different spaces\n",
+ id(), Mnemonic(), dominator->id(), dominator->Mnemonic());
+ }
+ return NULL;
+ }
+
+ // We can just fold old space allocations that are in the same basic block,
+ // since it is not guaranteed that we fill up the whole allocated old
+ // space memory.
+ // TODO(hpayer): Remove this limitation and add filler maps for each each
+ // allocation as soon as we have store elimination.
+ if (block()->block_id() != dominator_dominator->block()->block_id()) {
+ if (FLAG_trace_allocation_folding) {
+ PrintF("#%d (%s) cannot fold into #%d (%s), different basic blocks\n",
+ id(), Mnemonic(), dominator_dominator->id(),
+ dominator_dominator->Mnemonic());
+ }
+ return NULL;
+ }
+
+ ASSERT((IsOldDataSpaceAllocation() &&
+ dominator_dominator->IsOldDataSpaceAllocation()) ||
+ (IsOldPointerSpaceAllocation() &&
+ dominator_dominator->IsOldPointerSpaceAllocation()));
+
+ int32_t current_size = HConstant::cast(size())->GetInteger32Constant();
+ HStoreNamedField* dominator_free_space_size =
+ dominator->filler_free_space_size_;
+ if (dominator_free_space_size != NULL) {
+ // We already hoisted one old space allocation, i.e., we already installed
+ // a filler map. Hence, we just have to update the free space size.
+ dominator->UpdateFreeSpaceFiller(current_size);
+ } else {
+ // This is the first old space allocation that gets hoisted. We have to
+ // install a filler map since the follwing allocation may cause a GC.
+ dominator->CreateFreeSpaceFiller(current_size);
+ }
+
+ // We can hoist the old space allocation over the actual dominator.
+ return dominator_dominator;
+ }
+ return dominator;
+}
+
+
+void HAllocate::UpdateFreeSpaceFiller(int32_t free_space_size) {
+ ASSERT(filler_free_space_size_ != NULL);
+ Zone* zone = block()->zone();
+ // We must explicitly force Smi representation here because on x64 we
+ // would otherwise automatically choose int32, but the actual store
+ // requires a Smi-tagged value.
+ HConstant* new_free_space_size = HConstant::CreateAndInsertBefore(
+ zone,
+ context(),
+ filler_free_space_size_->value()->GetInteger32Constant() +
+ free_space_size,
+ Representation::Smi(),
+ filler_free_space_size_);
+ filler_free_space_size_->UpdateValue(new_free_space_size);
+}
+
+
+void HAllocate::CreateFreeSpaceFiller(int32_t free_space_size) {
+ ASSERT(filler_free_space_size_ == NULL);
+ Zone* zone = block()->zone();
+ int32_t dominator_size =
+ HConstant::cast(dominating_allocate_->size())->GetInteger32Constant();
+ HInstruction* free_space_instr =
+ HInnerAllocatedObject::New(zone, context(), dominating_allocate_,
+ dominator_size, type());
+ free_space_instr->InsertBefore(this);
+ HConstant* filler_map = HConstant::New(
+ zone,
+ context(),
+ isolate()->factory()->free_space_map(),
+ UniqueValueId::free_space_map(isolate()->heap()));
+ filler_map->InsertAfter(free_space_instr);
+ HInstruction* store_map = HStoreNamedField::New(zone, context(),
+ free_space_instr, HObjectAccess::ForMap(), filler_map);
+ store_map->SetFlag(HValue::kHasNoObservableSideEffects);
+ store_map->InsertAfter(filler_map);
+
+ // We must explicitly force Smi representation here because on x64 we
+ // would otherwise automatically choose int32, but the actual store
+ // requires a Smi-tagged value.
+ HConstant* filler_size = HConstant::CreateAndInsertAfter(
+ zone, context(), free_space_size, Representation::Smi(), store_map);
+ // Must force Smi representation for x64 (see comment above).
+ HObjectAccess access =
+ HObjectAccess::ForJSObjectOffset(FreeSpace::kSizeOffset,
+ Representation::Smi());
+ HStoreNamedField* store_size = HStoreNamedField::New(zone, context(),
+ free_space_instr, access, filler_size);
+ store_size->SetFlag(HValue::kHasNoObservableSideEffects);
+ store_size->InsertAfter(filler_size);
+ filler_free_space_size_ = store_size;
+}
+
+
+void HAllocate::ClearNextMapWord(int offset) {
+ if (clear_next_map_word_) {
+ Zone* zone = block()->zone();
+ HObjectAccess access = HObjectAccess::ForJSObjectOffset(offset);
+ HStoreNamedField* clear_next_map =
+ HStoreNamedField::New(zone, context(), this, access,
+ block()->graph()->GetConstantNull());
+ clear_next_map->ClearAllSideEffects();
+ clear_next_map->InsertAfter(this);
}
}
@@ -3960,7 +3685,7 @@ HInstruction* HStringCharFromCode::New(
Zone* zone, HValue* context, HValue* char_code) {
if (FLAG_fold_constants && char_code->IsConstant()) {
HConstant* c_code = HConstant::cast(char_code);
- Isolate* isolate = Isolate::Current();
+ Isolate* isolate = zone->isolate();
if (c_code->HasNumberValue()) {
if (std::isfinite(c_code->DoubleValue())) {
uint32_t code = c_code->NumberValueAsInteger32() & 0xffff;
@@ -4242,10 +3967,10 @@ void HPhi::SimplifyConstantInputs() {
DoubleToInt32(operand->DoubleValue()));
integer_input->InsertAfter(operand);
SetOperandAt(i, integer_input);
- } else if (operand == graph->GetConstantTrue()) {
- SetOperandAt(i, graph->GetConstant1());
- } else {
- // This catches |false|, |undefined|, strings and objects.
+ } else if (operand->HasBooleanValue()) {
+ SetOperandAt(i, operand->BooleanValue() ? graph->GetConstant1()
+ : graph->GetConstant0());
+ } else if (operand->ImmortalImmovable()) {
SetOperandAt(i, graph->GetConstant0());
}
}
@@ -4285,6 +4010,9 @@ Representation HPhi::RepresentationFromInputs() {
Representation HValue::RepresentationFromUseRequirements() {
Representation rep = Representation::None();
for (HUseIterator it(uses()); !it.Done(); it.Advance()) {
+ // Ignore the use requirement from never run code
+ if (it.value()->block()->IsDeoptimizing()) continue;
+
// We check for observed_input_representation elsewhere.
Representation use_rep =
it.value()->RequiredInputRepresentation(it.index());
@@ -4345,7 +4073,7 @@ void HCheckHeapObject::Verify() {
}
-void HCheckFunction::Verify() {
+void HCheckValue::Verify() {
HInstruction::Verify();
ASSERT(HasNoUses());
}
@@ -4375,6 +4103,15 @@ HObjectAccess HObjectAccess::ForJSObjectOffset(int offset,
}
+HObjectAccess HObjectAccess::ForContextSlot(int index) {
+ ASSERT(index >= 0);
+ Portion portion = kInobject;
+ int offset = Context::kHeaderSize + index * kPointerSize;
+ ASSERT_EQ(offset, Context::SlotOffset(index) + kHeapObjectTag);
+ return HObjectAccess(portion, offset, Representation::Tagged());
+}
+
+
HObjectAccess HObjectAccess::ForJSArrayOffset(int offset) {
ASSERT(offset >= 0);
Portion portion = kInobject;