Merge V8 5.3.332.45. DO NOT MERGE
Test: Manual
FPIIM-449
Change-Id: Id3254828b068abdea3cb10442e0172a8c9a98e03
(cherry picked from commit 13e2dadd00298019ed862f2b2fc5068bba730bcf)
diff --git a/src/compiler/escape-analysis.cc b/src/compiler/escape-analysis.cc
index d11c3ab..9409a27 100644
--- a/src/compiler/escape-analysis.cc
+++ b/src/compiler/escape-analysis.cc
@@ -794,6 +794,12 @@
break;
case IrOpcode::kSelect:
case IrOpcode::kTypeGuard:
+ // TODO(mstarzinger): The following list of operators will eventually be
+ // handled by the EscapeAnalysisReducer (similar to ObjectIsSmi).
+ case IrOpcode::kObjectIsCallable:
+ case IrOpcode::kObjectIsNumber:
+ case IrOpcode::kObjectIsString:
+ case IrOpcode::kObjectIsUndetectable:
if (SetEscaped(rep)) {
TRACE("Setting #%d (%s) to escaped because of use by #%d (%s)\n",
rep->id(), rep->op()->mnemonic(), use->id(),
@@ -843,6 +849,7 @@
EscapeAnalysis::EscapeAnalysis(Graph* graph, CommonOperatorBuilder* common,
Zone* zone)
: zone_(zone),
+ slot_not_analyzed_(graph->NewNode(common->NumberConstant(0x1c0debad))),
common_(common),
status_analysis_(new (zone) EscapeStatusAnalysis(this, graph, zone)),
virtual_states_(zone),
@@ -1321,11 +1328,24 @@
return false;
}
-int EscapeAnalysis::OffsetFromAccess(Node* node) {
- DCHECK(OpParameter<FieldAccess>(node).offset % kPointerSize == 0);
- return OpParameter<FieldAccess>(node).offset / kPointerSize;
+namespace {
+
+int OffsetForFieldAccess(Node* node) {
+ FieldAccess access = FieldAccessOf(node->op());
+ DCHECK_EQ(access.offset % kPointerSize, 0);
+ return access.offset / kPointerSize;
}
+int OffsetForElementAccess(Node* node, int index) {
+ ElementAccess access = ElementAccessOf(node->op());
+ DCHECK_GE(ElementSizeLog2Of(access.machine_type.representation()),
+ kPointerSizeLog2);
+ DCHECK_EQ(access.header_size % kPointerSize, 0);
+ return access.header_size / kPointerSize + index;
+}
+
+} // namespace
+
void EscapeAnalysis::ProcessLoadFromPhi(int offset, Node* from, Node* load,
VirtualState* state) {
TRACE("Load #%d from phi #%d", load->id(), from->id());
@@ -1368,11 +1388,9 @@
Node* from = ResolveReplacement(NodeProperties::GetValueInput(node, 0));
VirtualState* state = virtual_states_[node->id()];
if (VirtualObject* object = GetVirtualObject(state, from)) {
- int offset = OffsetFromAccess(node);
- if (!object->IsTracked() ||
- static_cast<size_t>(offset) >= object->field_count()) {
- return;
- }
+ if (!object->IsTracked()) return;
+ int offset = OffsetForFieldAccess(node);
+ if (static_cast<size_t>(offset) >= object->field_count()) return;
Node* value = object->GetField(offset);
if (value) {
value = ResolveReplacement(value);
@@ -1380,8 +1398,8 @@
// Record that the load has this alias.
UpdateReplacement(state, node, value);
} else if (from->opcode() == IrOpcode::kPhi &&
- OpParameter<FieldAccess>(node).offset % kPointerSize == 0) {
- int offset = OffsetFromAccess(node);
+ FieldAccessOf(node->op()).offset % kPointerSize == 0) {
+ int offset = OffsetForFieldAccess(node);
// Only binary phis are supported for now.
ProcessLoadFromPhi(offset, from, node, state);
} else {
@@ -1400,19 +1418,11 @@
index_node->opcode() != IrOpcode::kInt64Constant &&
index_node->opcode() != IrOpcode::kFloat32Constant &&
index_node->opcode() != IrOpcode::kFloat64Constant);
- ElementAccess access = OpParameter<ElementAccess>(node);
if (index.HasValue()) {
- int offset = index.Value() + access.header_size / kPointerSize;
if (VirtualObject* object = GetVirtualObject(state, from)) {
- CHECK_GE(ElementSizeLog2Of(access.machine_type.representation()),
- kPointerSizeLog2);
- CHECK_EQ(access.header_size % kPointerSize, 0);
-
- if (!object->IsTracked() ||
- static_cast<size_t>(offset) >= object->field_count()) {
- return;
- }
-
+ if (!object->IsTracked()) return;
+ int offset = OffsetForElementAccess(node, index.Value());
+ if (static_cast<size_t>(offset) >= object->field_count()) return;
Node* value = object->GetField(offset);
if (value) {
value = ResolveReplacement(value);
@@ -1420,8 +1430,7 @@
// Record that the load has this alias.
UpdateReplacement(state, node, value);
} else if (from->opcode() == IrOpcode::kPhi) {
- ElementAccess access = OpParameter<ElementAccess>(node);
- int offset = index.Value() + access.header_size / kPointerSize;
+ int offset = OffsetForElementAccess(node, index.Value());
ProcessLoadFromPhi(offset, from, node, state);
} else {
UpdateReplacement(state, node, nullptr);
@@ -1443,14 +1452,23 @@
ForwardVirtualState(node);
Node* to = ResolveReplacement(NodeProperties::GetValueInput(node, 0));
VirtualState* state = virtual_states_[node->id()];
- VirtualObject* obj = GetVirtualObject(state, to);
- int offset = OffsetFromAccess(node);
- if (obj && obj->IsTracked() &&
- static_cast<size_t>(offset) < obj->field_count()) {
+ if (VirtualObject* object = GetVirtualObject(state, to)) {
+ if (!object->IsTracked()) return;
+ int offset = OffsetForFieldAccess(node);
+ if (static_cast<size_t>(offset) >= object->field_count()) return;
Node* val = ResolveReplacement(NodeProperties::GetValueInput(node, 1));
- if (obj->GetField(offset) != val) {
- obj = CopyForModificationAt(obj, state, node);
- obj->SetField(offset, val);
+ // TODO(mstarzinger): The following is a workaround to not track the code
+ // entry field in virtual JSFunction objects. We only ever store the inner
+ // pointer into the compile lazy stub in this field and the deoptimizer has
+ // this assumption hard-coded in {TranslatedState::MaterializeAt} as well.
+ if (val->opcode() == IrOpcode::kInt32Constant ||
+ val->opcode() == IrOpcode::kInt64Constant) {
+ DCHECK_EQ(JSFunction::kCodeEntryOffset, FieldAccessOf(node->op()).offset);
+ val = slot_not_analyzed_;
+ }
+ if (object->GetField(offset) != val) {
+ object = CopyForModificationAt(object, state, node);
+ object->SetField(offset, val);
}
}
}
@@ -1465,20 +1483,16 @@
index_node->opcode() != IrOpcode::kInt64Constant &&
index_node->opcode() != IrOpcode::kFloat32Constant &&
index_node->opcode() != IrOpcode::kFloat64Constant);
- ElementAccess access = OpParameter<ElementAccess>(node);
VirtualState* state = virtual_states_[node->id()];
- VirtualObject* obj = GetVirtualObject(state, to);
if (index.HasValue()) {
- int offset = index.Value() + access.header_size / kPointerSize;
- if (obj && obj->IsTracked() &&
- static_cast<size_t>(offset) < obj->field_count()) {
- CHECK_GE(ElementSizeLog2Of(access.machine_type.representation()),
- kPointerSizeLog2);
- CHECK_EQ(access.header_size % kPointerSize, 0);
+ if (VirtualObject* object = GetVirtualObject(state, to)) {
+ if (!object->IsTracked()) return;
+ int offset = OffsetForElementAccess(node, index.Value());
+ if (static_cast<size_t>(offset) >= object->field_count()) return;
Node* val = ResolveReplacement(NodeProperties::GetValueInput(node, 2));
- if (obj->GetField(offset) != val) {
- obj = CopyForModificationAt(obj, state, node);
- obj->SetField(offset, val);
+ if (object->GetField(offset) != val) {
+ object = CopyForModificationAt(object, state, node);
+ object->SetField(offset, val);
}
}
} else {
@@ -1490,12 +1504,13 @@
to->id(), to->op()->mnemonic(), node->id(), index_node->id(),
index_node->op()->mnemonic());
}
- if (obj && obj->IsTracked()) {
- if (!obj->AllFieldsClear()) {
- obj = CopyForModificationAt(obj, state, node);
- obj->ClearAllFields();
+ if (VirtualObject* object = GetVirtualObject(state, to)) {
+ if (!object->IsTracked()) return;
+ if (!object->AllFieldsClear()) {
+ object = CopyForModificationAt(object, state, node);
+ object->ClearAllFields();
TRACE("Cleared all fields of @%d:#%d\n",
- status_analysis_->GetAlias(obj->id()), obj->id());
+ status_analysis_->GetAlias(object->id()), object->id());
}
}
}