Commit 9091eb19 authored by jarin's avatar jarin Committed by Commit bot

[deoptimizer] Materialize array iterators in the deoptimizer.

This also introduces exhaustive switch-cases for instance types.

BUG=chromium:681383

Review-Url: https://codereview.chromium.org/2646433002
Cr-Commit-Position: refs/heads/master@{#42447}
parent e1fbcce8
......@@ -3614,109 +3614,58 @@ void TranslatedState::Prepare(bool has_adapted_arguments,
UpdateFromPreviouslyMaterializedObjects();
}
Handle<Object> TranslatedState::MaterializeAt(int frame_index,
int* value_index) {
CHECK_LT(static_cast<size_t>(frame_index), frames().size());
TranslatedFrame* frame = &(frames_[frame_index]);
CHECK_LT(static_cast<size_t>(*value_index), frame->values_.size());
TranslatedValue* slot = &(frame->values_[*value_index]);
(*value_index)++;
switch (slot->kind()) {
case TranslatedValue::kTagged:
case TranslatedValue::kInt32:
case TranslatedValue::kUInt32:
case TranslatedValue::kBoolBit:
case TranslatedValue::kFloat:
case TranslatedValue::kDouble: {
slot->MaterializeSimple();
Handle<Object> value = slot->GetValue();
if (value->IsMutableHeapNumber()) {
HeapNumber::cast(*value)->set_map(isolate()->heap()->heap_number_map());
}
return value;
}
case TranslatedValue::kArgumentsObject: {
int length = slot->GetChildrenCount();
Handle<JSObject> arguments;
if (GetAdaptedArguments(&arguments, frame_index)) {
// Store the materialized object and consume the nested values.
for (int i = 0; i < length; ++i) {
MaterializeAt(frame_index, value_index);
}
} else {
Handle<JSFunction> function =
Handle<JSFunction>::cast(frame->front().GetValue());
arguments = isolate_->factory()->NewArgumentsObject(function, length);
Handle<FixedArray> array = isolate_->factory()->NewFixedArray(length);
DCHECK_EQ(array->length(), length);
arguments->set_elements(*array);
for (int i = 0; i < length; ++i) {
Handle<Object> value = MaterializeAt(frame_index, value_index);
array->set(i, *value);
}
}
slot->value_ = arguments;
return arguments;
}
case TranslatedValue::kCapturedObject: {
int length = slot->GetChildrenCount();
class FieldMaterializer {
class TranslatedState::CapturedObjectMaterializer {
public:
FieldMaterializer(TranslatedState* state, int frame_index,
CapturedObjectMaterializer(TranslatedState* state, int frame_index,
int field_count)
: state_(state),
frame_index_(frame_index),
field_count_(field_count) {}
: state_(state), frame_index_(frame_index), field_count_(field_count) {}
Handle<Object> At(int* value_index) {
Handle<Object> FieldAt(int* value_index) {
CHECK(field_count_ > 0);
--field_count_;
return state_->MaterializeAt(frame_index_, value_index);
}
~FieldMaterializer() { CHECK_EQ(0, field_count_); }
~CapturedObjectMaterializer() { CHECK_EQ(0, field_count_); }
private:
TranslatedState* state_;
int frame_index_;
int field_count_;
};
FieldMaterializer materializer(this, frame_index, length);
};
// The map must be a tagged object.
CHECK(frame->values_[*value_index].kind() == TranslatedValue::kTagged);
Handle<Object> TranslatedState::MaterializeCapturedObjectAt(
TranslatedValue* slot, int frame_index, int* value_index) {
int length = slot->GetChildrenCount();
CapturedObjectMaterializer materializer(this, frame_index, length);
Handle<Object> result;
if (slot->value_.ToHandle(&result)) {
// This has been previously materialized, return the previous value.
// We still need to skip all the nested objects.
for (int i = 0; i < length; i++) {
materializer.At(value_index);
materializer.FieldAt(value_index);
}
return result;
}
Handle<Object> map_object = materializer.At(value_index);
Handle<Object> map_object = materializer.FieldAt(value_index);
Handle<Map> map = Map::GeneralizeAllFields(Handle<Map>::cast(map_object));
switch (map->instance_type()) {
case MUTABLE_HEAP_NUMBER_TYPE:
case HEAP_NUMBER_TYPE: {
// Reuse the HeapNumber value directly as it is already properly
// tagged and skip materializing the HeapNumber explicitly.
Handle<Object> object = materializer.At(value_index);
Handle<Object> object = materializer.FieldAt(value_index);
slot->value_ = object;
// On 32-bit architectures, there is an extra slot there because
// the escape analysis calculates the number of slots as
// object-size/pointer-size. To account for this, we read out
// any extra slots.
for (int i = 0; i < length - 2; i++) {
materializer.At(value_index);
materializer.FieldAt(value_index);
}
return object;
}
......@@ -3726,24 +3675,74 @@ Handle<Object> TranslatedState::MaterializeAt(int frame_index,
Handle<JSObject> object =
isolate_->factory()->NewJSObjectFromMap(map, NOT_TENURED);
slot->value_ = object;
Handle<Object> properties = materializer.At(value_index);
Handle<Object> elements = materializer.At(value_index);
Handle<Object> properties = materializer.FieldAt(value_index);
Handle<Object> elements = materializer.FieldAt(value_index);
object->set_properties(FixedArray::cast(*properties));
object->set_elements(FixedArrayBase::cast(*elements));
for (int i = 0; i < length - 3; ++i) {
Handle<Object> value = materializer.At(value_index);
Handle<Object> value = materializer.FieldAt(value_index);
FieldIndex index = FieldIndex::ForPropertyIndex(object->map(), i);
object->FastPropertyAtPut(index, *value);
}
return object;
}
case JS_TYPED_ARRAY_KEY_ITERATOR_TYPE:
case JS_FAST_ARRAY_KEY_ITERATOR_TYPE:
case JS_GENERIC_ARRAY_KEY_ITERATOR_TYPE:
case JS_UINT8_ARRAY_KEY_VALUE_ITERATOR_TYPE:
case JS_INT8_ARRAY_KEY_VALUE_ITERATOR_TYPE:
case JS_UINT16_ARRAY_KEY_VALUE_ITERATOR_TYPE:
case JS_INT16_ARRAY_KEY_VALUE_ITERATOR_TYPE:
case JS_UINT32_ARRAY_KEY_VALUE_ITERATOR_TYPE:
case JS_INT32_ARRAY_KEY_VALUE_ITERATOR_TYPE:
case JS_FLOAT32_ARRAY_KEY_VALUE_ITERATOR_TYPE:
case JS_FLOAT64_ARRAY_KEY_VALUE_ITERATOR_TYPE:
case JS_UINT8_CLAMPED_ARRAY_KEY_VALUE_ITERATOR_TYPE:
case JS_FAST_SMI_ARRAY_KEY_VALUE_ITERATOR_TYPE:
case JS_FAST_HOLEY_SMI_ARRAY_KEY_VALUE_ITERATOR_TYPE:
case JS_FAST_ARRAY_KEY_VALUE_ITERATOR_TYPE:
case JS_FAST_HOLEY_ARRAY_KEY_VALUE_ITERATOR_TYPE:
case JS_FAST_DOUBLE_ARRAY_KEY_VALUE_ITERATOR_TYPE:
case JS_FAST_HOLEY_DOUBLE_ARRAY_KEY_VALUE_ITERATOR_TYPE:
case JS_GENERIC_ARRAY_KEY_VALUE_ITERATOR_TYPE:
case JS_UINT8_ARRAY_VALUE_ITERATOR_TYPE:
case JS_INT8_ARRAY_VALUE_ITERATOR_TYPE:
case JS_UINT16_ARRAY_VALUE_ITERATOR_TYPE:
case JS_INT16_ARRAY_VALUE_ITERATOR_TYPE:
case JS_UINT32_ARRAY_VALUE_ITERATOR_TYPE:
case JS_INT32_ARRAY_VALUE_ITERATOR_TYPE:
case JS_FLOAT32_ARRAY_VALUE_ITERATOR_TYPE:
case JS_FLOAT64_ARRAY_VALUE_ITERATOR_TYPE:
case JS_UINT8_CLAMPED_ARRAY_VALUE_ITERATOR_TYPE:
case JS_FAST_SMI_ARRAY_VALUE_ITERATOR_TYPE:
case JS_FAST_HOLEY_SMI_ARRAY_VALUE_ITERATOR_TYPE:
case JS_FAST_ARRAY_VALUE_ITERATOR_TYPE:
case JS_FAST_HOLEY_ARRAY_VALUE_ITERATOR_TYPE:
case JS_FAST_DOUBLE_ARRAY_VALUE_ITERATOR_TYPE:
case JS_FAST_HOLEY_DOUBLE_ARRAY_VALUE_ITERATOR_TYPE:
case JS_GENERIC_ARRAY_VALUE_ITERATOR_TYPE: {
Handle<JSArrayIterator> object = Handle<JSArrayIterator>::cast(
isolate_->factory()->NewJSObjectFromMap(map, NOT_TENURED));
slot->value_ = object;
Handle<Object> properties = materializer.FieldAt(value_index);
Handle<Object> elements = materializer.FieldAt(value_index);
Handle<Object> iterated_object = materializer.FieldAt(value_index);
Handle<Object> next_index = materializer.FieldAt(value_index);
Handle<Object> iterated_object_map = materializer.FieldAt(value_index);
object->set_properties(FixedArray::cast(*properties));
object->set_elements(FixedArrayBase::cast(*elements));
object->set_object(*iterated_object);
object->set_index(*next_index);
object->set_object_map(*iterated_object_map);
return object;
}
case JS_ARRAY_TYPE: {
Handle<JSArray> object = Handle<JSArray>::cast(
isolate_->factory()->NewJSObjectFromMap(map, NOT_TENURED));
slot->value_ = object;
Handle<Object> properties = materializer.At(value_index);
Handle<Object> elements = materializer.At(value_index);
Handle<Object> length = materializer.At(value_index);
Handle<Object> properties = materializer.FieldAt(value_index);
Handle<Object> elements = materializer.FieldAt(value_index);
Handle<Object> length = materializer.FieldAt(value_index);
object->set_properties(FixedArray::cast(*properties));
object->set_elements(FixedArrayBase::cast(*elements));
object->set_length(*length);
......@@ -3752,21 +3751,20 @@ Handle<Object> TranslatedState::MaterializeAt(int frame_index,
case JS_FUNCTION_TYPE: {
Handle<SharedFunctionInfo> temporary_shared =
isolate_->factory()->NewSharedFunctionInfo(
isolate_->factory()->empty_string(), MaybeHandle<Code>(),
false);
isolate_->factory()->empty_string(), MaybeHandle<Code>(), false);
Handle<JSFunction> object =
isolate_->factory()->NewFunctionFromSharedFunctionInfo(
map, temporary_shared, isolate_->factory()->undefined_value(),
NOT_TENURED);
slot->value_ = object;
Handle<Object> properties = materializer.At(value_index);
Handle<Object> elements = materializer.At(value_index);
Handle<Object> prototype = materializer.At(value_index);
Handle<Object> shared = materializer.At(value_index);
Handle<Object> context = materializer.At(value_index);
Handle<Object> literals = materializer.At(value_index);
Handle<Object> entry = materializer.At(value_index);
Handle<Object> next_link = materializer.At(value_index);
Handle<Object> properties = materializer.FieldAt(value_index);
Handle<Object> elements = materializer.FieldAt(value_index);
Handle<Object> prototype = materializer.FieldAt(value_index);
Handle<Object> shared = materializer.FieldAt(value_index);
Handle<Object> context = materializer.FieldAt(value_index);
Handle<Object> literals = materializer.FieldAt(value_index);
Handle<Object> entry = materializer.FieldAt(value_index);
Handle<Object> next_link = materializer.FieldAt(value_index);
object->ReplaceCode(*isolate_->builtins()->CompileLazy());
object->set_map(*map);
object->set_properties(FixedArray::cast(*properties));
......@@ -3786,10 +3784,10 @@ Handle<Object> TranslatedState::MaterializeAt(int frame_index,
isolate_->factory()->undefined_string())
.ToHandleChecked());
slot->value_ = object;
Handle<Object> hash = materializer.At(value_index);
Handle<Object> length = materializer.At(value_index);
Handle<Object> first = materializer.At(value_index);
Handle<Object> second = materializer.At(value_index);
Handle<Object> hash = materializer.FieldAt(value_index);
Handle<Object> length = materializer.FieldAt(value_index);
Handle<Object> first = materializer.FieldAt(value_index);
Handle<Object> second = materializer.FieldAt(value_index);
object->set_map(*map);
object->set_length(Smi::cast(*length)->value());
object->set_first(String::cast(*first));
......@@ -3803,32 +3801,31 @@ Handle<Object> TranslatedState::MaterializeAt(int frame_index,
isolate_->factory()->NewScopeInfo(1),
isolate_->factory()->undefined_value());
slot->value_ = object;
Handle<Object> scope_info = materializer.At(value_index);
Handle<Object> extension = materializer.At(value_index);
Handle<Object> scope_info = materializer.FieldAt(value_index);
Handle<Object> extension = materializer.FieldAt(value_index);
object->set_scope_info(ScopeInfo::cast(*scope_info));
object->set_extension(*extension);
return object;
}
case FIXED_ARRAY_TYPE: {
Handle<Object> lengthObject = materializer.At(value_index);
Handle<Object> lengthObject = materializer.FieldAt(value_index);
int32_t length = 0;
CHECK(lengthObject->ToInt32(&length));
Handle<FixedArray> object =
isolate_->factory()->NewFixedArray(length);
Handle<FixedArray> object = isolate_->factory()->NewFixedArray(length);
// We need to set the map, because the fixed array we are
// materializing could be a context or an arguments object,
// in which case we must retain that information.
object->set_map(*map);
slot->value_ = object;
for (int i = 0; i < length; ++i) {
Handle<Object> value = materializer.At(value_index);
Handle<Object> value = materializer.FieldAt(value_index);
object->set(i, *value);
}
return object;
}
case FIXED_DOUBLE_ARRAY_TYPE: {
DCHECK_EQ(*map, isolate_->heap()->fixed_double_array_map());
Handle<Object> lengthObject = materializer.At(value_index);
Handle<Object> lengthObject = materializer.FieldAt(value_index);
int32_t length = 0;
CHECK(lengthObject->ToInt32(&length));
Handle<FixedArrayBase> object =
......@@ -3838,23 +3835,162 @@ Handle<Object> TranslatedState::MaterializeAt(int frame_index,
Handle<FixedDoubleArray> double_array =
Handle<FixedDoubleArray>::cast(object);
for (int i = 0; i < length; ++i) {
Handle<Object> value = materializer.At(value_index);
Handle<Object> value = materializer.FieldAt(value_index);
CHECK(value->IsNumber());
double_array->set(i, value->Number());
}
}
return object;
}
default:
PrintF(stderr, "[couldn't handle instance type %d]\n",
map->instance_type());
FATAL("unreachable");
return Handle<Object>::null();
}
case STRING_TYPE:
case ONE_BYTE_STRING_TYPE:
case CONS_ONE_BYTE_STRING_TYPE:
case SLICED_STRING_TYPE:
case SLICED_ONE_BYTE_STRING_TYPE:
case EXTERNAL_STRING_TYPE:
case EXTERNAL_ONE_BYTE_STRING_TYPE:
case EXTERNAL_STRING_WITH_ONE_BYTE_DATA_TYPE:
case SHORT_EXTERNAL_STRING_TYPE:
case SHORT_EXTERNAL_ONE_BYTE_STRING_TYPE:
case SHORT_EXTERNAL_STRING_WITH_ONE_BYTE_DATA_TYPE:
case INTERNALIZED_STRING_TYPE:
case ONE_BYTE_INTERNALIZED_STRING_TYPE:
case EXTERNAL_INTERNALIZED_STRING_TYPE:
case EXTERNAL_ONE_BYTE_INTERNALIZED_STRING_TYPE:
case EXTERNAL_INTERNALIZED_STRING_WITH_ONE_BYTE_DATA_TYPE:
case SHORT_EXTERNAL_INTERNALIZED_STRING_TYPE:
case SHORT_EXTERNAL_ONE_BYTE_INTERNALIZED_STRING_TYPE:
case SHORT_EXTERNAL_INTERNALIZED_STRING_WITH_ONE_BYTE_DATA_TYPE:
case SYMBOL_TYPE:
case ODDBALL_TYPE:
case SIMD128_VALUE_TYPE:
case JS_GLOBAL_OBJECT_TYPE:
case JS_GLOBAL_PROXY_TYPE:
case JS_API_OBJECT_TYPE:
case JS_SPECIAL_API_OBJECT_TYPE:
case JS_VALUE_TYPE:
case JS_MESSAGE_OBJECT_TYPE:
case JS_DATE_TYPE:
case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
case JS_GENERATOR_OBJECT_TYPE:
case JS_MODULE_NAMESPACE_TYPE:
case JS_ARRAY_BUFFER_TYPE:
case JS_REGEXP_TYPE:
case JS_TYPED_ARRAY_TYPE:
case JS_DATA_VIEW_TYPE:
case JS_SET_TYPE:
case JS_MAP_TYPE:
case JS_SET_ITERATOR_TYPE:
case JS_MAP_ITERATOR_TYPE:
case JS_STRING_ITERATOR_TYPE:
case JS_WEAK_MAP_TYPE:
case JS_WEAK_SET_TYPE:
case JS_PROMISE_CAPABILITY_TYPE:
case JS_PROMISE_TYPE:
case JS_BOUND_FUNCTION_TYPE:
case JS_PROXY_TYPE:
case MAP_TYPE:
case ALLOCATION_SITE_TYPE:
case ACCESSOR_INFO_TYPE:
case SHARED_FUNCTION_INFO_TYPE:
case FUNCTION_TEMPLATE_INFO_TYPE:
case ACCESSOR_PAIR_TYPE:
case BYTE_ARRAY_TYPE:
case BYTECODE_ARRAY_TYPE:
case TRANSITION_ARRAY_TYPE:
case FOREIGN_TYPE:
case SCRIPT_TYPE:
case CODE_TYPE:
case PROPERTY_CELL_TYPE:
case MODULE_TYPE:
case MODULE_INFO_ENTRY_TYPE:
case FREE_SPACE_TYPE:
#define FIXED_TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
case FIXED_##TYPE##_ARRAY_TYPE:
TYPED_ARRAYS(FIXED_TYPED_ARRAY_CASE)
#undef FIXED_TYPED_ARRAY_CASE
case FILLER_TYPE:
case ACCESS_CHECK_INFO_TYPE:
case INTERCEPTOR_INFO_TYPE:
case CALL_HANDLER_INFO_TYPE:
case OBJECT_TEMPLATE_INFO_TYPE:
case ALLOCATION_MEMENTO_TYPE:
case TYPE_FEEDBACK_INFO_TYPE:
case ALIASED_ARGUMENTS_ENTRY_TYPE:
case BOX_TYPE:
case PROMISE_RESOLVE_THENABLE_JOB_INFO_TYPE:
case PROMISE_REACTION_JOB_INFO_TYPE:
case DEBUG_INFO_TYPE:
case BREAK_POINT_INFO_TYPE:
case CELL_TYPE:
case WEAK_CELL_TYPE:
case PROTOTYPE_INFO_TYPE:
case TUPLE2_TYPE:
case TUPLE3_TYPE:
case CONSTANT_ELEMENTS_PAIR_TYPE:
OFStream os(stderr);
os << "[couldn't handle instance type " << map->instance_type() << "]"
<< std::endl;
UNREACHABLE();
break;
}
UNREACHABLE();
return Handle<Object>::null();
}
Handle<Object> TranslatedState::MaterializeAt(int frame_index,
int* value_index) {
CHECK_LT(static_cast<size_t>(frame_index), frames().size());
TranslatedFrame* frame = &(frames_[frame_index]);
CHECK_LT(static_cast<size_t>(*value_index), frame->values_.size());
TranslatedValue* slot = &(frame->values_[*value_index]);
(*value_index)++;
switch (slot->kind()) {
case TranslatedValue::kTagged:
case TranslatedValue::kInt32:
case TranslatedValue::kUInt32:
case TranslatedValue::kBoolBit:
case TranslatedValue::kFloat:
case TranslatedValue::kDouble: {
slot->MaterializeSimple();
Handle<Object> value = slot->GetValue();
if (value->IsMutableHeapNumber()) {
HeapNumber::cast(*value)->set_map(isolate()->heap()->heap_number_map());
}
return value;
}
case TranslatedValue::kArgumentsObject: {
int length = slot->GetChildrenCount();
Handle<JSObject> arguments;
if (GetAdaptedArguments(&arguments, frame_index)) {
// Store the materialized object and consume the nested values.
for (int i = 0; i < length; ++i) {
MaterializeAt(frame_index, value_index);
}
} else {
Handle<JSFunction> function =
Handle<JSFunction>::cast(frame->front().GetValue());
arguments = isolate_->factory()->NewArgumentsObject(function, length);
Handle<FixedArray> array = isolate_->factory()->NewFixedArray(length);
DCHECK_EQ(array->length(), length);
arguments->set_elements(*array);
for (int i = 0; i < length; ++i) {
Handle<Object> value = MaterializeAt(frame_index, value_index);
array->set(i, *value);
}
}
slot->value_ = arguments;
return arguments;
}
case TranslatedValue::kCapturedObject: {
// The map must be a tagged object.
CHECK(frame->values_[*value_index].kind() == TranslatedValue::kTagged);
CHECK(frame->values_[*value_index].GetValue()->IsMap());
return MaterializeCapturedObjectAt(slot, frame_index, value_index);
}
case TranslatedValue::kDuplicatedObject: {
int object_index = slot->object_index();
TranslatedState::ObjectPosition pos = object_positions_[object_index];
......@@ -3884,14 +4020,12 @@ Handle<Object> TranslatedState::MaterializeAt(int frame_index,
return Handle<Object>::null();
}
Handle<Object> TranslatedState::MaterializeObjectAt(int object_index) {
CHECK_LT(static_cast<size_t>(object_index), object_positions_.size());
TranslatedState::ObjectPosition pos = object_positions_[object_index];
return MaterializeAt(pos.frame_index_, &(pos.value_index_));
}
bool TranslatedState::GetAdaptedArguments(Handle<JSObject>* result,
int frame_index) {
if (frame_index == 0) {
......@@ -3931,7 +4065,6 @@ bool TranslatedState::GetAdaptedArguments(Handle<JSObject>* result,
}
}
TranslatedFrame* TranslatedState::GetArgumentsInfoFromJSFrameIndex(
int jsframe_index, int* args_count) {
for (size_t i = 0; i < frames_.size(); i++) {
......@@ -3940,7 +4073,8 @@ TranslatedFrame* TranslatedState::GetArgumentsInfoFromJSFrameIndex(
if (jsframe_index > 0) {
jsframe_index--;
} else {
// We have the JS function frame, now check if it has arguments adaptor.
// We have the JS function frame, now check if it has arguments
// adaptor.
if (i > 0 &&
frames_[i - 1].kind() == TranslatedFrame::kArgumentsAdaptor) {
*args_count = frames_[i - 1].height();
......@@ -4006,7 +4140,6 @@ void TranslatedState::StoreMaterializedValuesAndDeopt(JavaScriptFrame* frame) {
}
}
void TranslatedState::UpdateFromPreviouslyMaterializedObjects() {
MaterializedObjectStore* materialized_store =
isolate_->materialized_object_store();
......
......@@ -292,6 +292,9 @@ class TranslatedState {
void UpdateFromPreviouslyMaterializedObjects();
Handle<Object> MaterializeAt(int frame_index, int* value_index);
Handle<Object> MaterializeObjectAt(int object_index);
class CapturedObjectMaterializer;
Handle<Object> MaterializeCapturedObjectAt(TranslatedValue* slot,
int frame_index, int* value_index);
bool GetAdaptedArguments(Handle<JSObject>* result, int frame_index);
static uint32_t GetUInt32Slot(Address fp, int slot_index);
......
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax
function f(deopt) {
let array = [42];
let it = array[Symbol.iterator]();
if (deopt) {
%_DeoptimizeNow();
return it.next().value;
}
}
f(false);
f(false);
%OptimizeFunctionOnNextCall(f);
assertEquals(f(true), 42);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment