Files
sdk/runtime/vm/deferred_objects.cc
T
Regis Crelier 7f57ebcfa1 Remove signature classes from the VM.
They were used as the class of closure instances and as the type class of
function types.
All closure instances now have class _Closure and function types are represented
by a new class FunctionType extending AbstractType.
Fix issue 24567 and add regression test.

R=asiva@google.com, rmacnak@google.com

Review URL: https://codereview.chromium.org/1584223006 .
2016-01-19 16:32:59 -08:00

382 lines
13 KiB
C++

// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "vm/deferred_objects.h"
#include "vm/code_patcher.h"
#include "vm/compiler.h"
#include "vm/deopt_instructions.h"
#include "vm/flags.h"
#include "vm/object.h"
namespace dart {
DECLARE_FLAG(bool, trace_deoptimization);
DECLARE_FLAG(bool, trace_deoptimization_verbose);
void DeferredDouble::Materialize(DeoptContext* deopt_context) {
RawDouble** double_slot = reinterpret_cast<RawDouble**>(slot());
*double_slot = Double::New(value());
if (FLAG_trace_deoptimization_verbose) {
OS::PrintErr("materializing double at %" Px ": %g\n",
reinterpret_cast<uword>(slot()), value());
}
}
void DeferredMint::Materialize(DeoptContext* deopt_context) {
RawMint** mint_slot = reinterpret_cast<RawMint**>(slot());
ASSERT(!Smi::IsValid(value()));
Mint& mint = Mint::Handle();
mint ^= Integer::New(value());
*mint_slot = mint.raw();
if (FLAG_trace_deoptimization_verbose) {
OS::PrintErr("materializing mint at %" Px ": %" Pd64 "\n",
reinterpret_cast<uword>(slot()), value());
}
}
void DeferredFloat32x4::Materialize(DeoptContext* deopt_context) {
RawFloat32x4** float32x4_slot = reinterpret_cast<RawFloat32x4**>(slot());
RawFloat32x4* raw_float32x4 = Float32x4::New(value());
*float32x4_slot = raw_float32x4;
if (FLAG_trace_deoptimization_verbose) {
float x = raw_float32x4->x();
float y = raw_float32x4->y();
float z = raw_float32x4->z();
float w = raw_float32x4->w();
OS::PrintErr("materializing Float32x4 at %" Px ": %g,%g,%g,%g\n",
reinterpret_cast<uword>(slot()), x, y, z, w);
}
}
void DeferredFloat64x2::Materialize(DeoptContext* deopt_context) {
RawFloat64x2** float64x2_slot = reinterpret_cast<RawFloat64x2**>(slot());
RawFloat64x2* raw_float64x2 = Float64x2::New(value());
*float64x2_slot = raw_float64x2;
if (FLAG_trace_deoptimization_verbose) {
double x = raw_float64x2->x();
double y = raw_float64x2->y();
OS::PrintErr("materializing Float64x2 at %" Px ": %g,%g\n",
reinterpret_cast<uword>(slot()), x, y);
}
}
void DeferredInt32x4::Materialize(DeoptContext* deopt_context) {
RawInt32x4** int32x4_slot = reinterpret_cast<RawInt32x4**>(slot());
RawInt32x4* raw_int32x4 = Int32x4::New(value());
*int32x4_slot = raw_int32x4;
if (FLAG_trace_deoptimization_verbose) {
uint32_t x = raw_int32x4->x();
uint32_t y = raw_int32x4->y();
uint32_t z = raw_int32x4->z();
uint32_t w = raw_int32x4->w();
OS::PrintErr("materializing Int32x4 at %" Px ": %x,%x,%x,%x\n",
reinterpret_cast<uword>(slot()), x, y, z, w);
}
}
void DeferredObjectRef::Materialize(DeoptContext* deopt_context) {
DeferredObject* obj = deopt_context->GetDeferredObject(index());
*slot() = obj->object();
if (FLAG_trace_deoptimization_verbose) {
const Class& cls = Class::Handle(Isolate::Current()->class_table()->At(
Object::Handle(obj->object()).GetClassId()));
OS::PrintErr("writing instance of class %s ref at %" Px ".\n",
cls.ToCString(),
reinterpret_cast<uword>(slot()));
}
}
void DeferredRetAddr::Materialize(DeoptContext* deopt_context) {
Thread* thread = deopt_context->thread();
Zone* zone = deopt_context->zone();
Function& function = Function::Handle(zone);
function ^= deopt_context->ObjectAt(index_);
const Error& error = Error::Handle(zone,
Compiler::EnsureUnoptimizedCode(thread, function));
if (!error.IsNull()) {
Exceptions::PropagateError(error);
}
const Code& code = Code::Handle(zone, function.unoptimized_code());
// Check that deopt_id exists.
// TODO(vegorov): verify after deoptimization targets as well.
#ifdef DEBUG
ASSERT(Thread::IsDeoptAfter(deopt_id_) ||
(code.GetPcForDeoptId(deopt_id_, RawPcDescriptors::kDeopt) != 0));
#endif
uword continue_at_pc = code.GetPcForDeoptId(deopt_id_,
RawPcDescriptors::kDeopt);
ASSERT(continue_at_pc != 0);
uword* dest_addr = reinterpret_cast<uword*>(slot());
*dest_addr = continue_at_pc;
if (FLAG_trace_deoptimization_verbose) {
OS::PrintErr("materializing return addr at 0x%" Px ": 0x%" Px "\n",
reinterpret_cast<uword>(slot()), continue_at_pc);
}
uword pc = code.GetPcForDeoptId(deopt_id_, RawPcDescriptors::kIcCall);
if (pc != 0) {
// If the deoptimization happened at an IC call, update the IC data
// to avoid repeated deoptimization at the same site next time around.
ICData& ic_data = ICData::Handle(zone);
CodePatcher::GetInstanceCallAt(pc, code, &ic_data);
if (!ic_data.IsNull()) {
ic_data.AddDeoptReason(deopt_context->deopt_reason());
// Propagate the reason to all ICData-s with same deopt_id since
// only unoptimized-code ICData (IC calls) are propagated.
function.SetDeoptReasonForAll(ic_data.deopt_id(),
deopt_context->deopt_reason());
}
} else {
if (deopt_context->HasDeoptFlag(ICData::kHoisted)) {
// Prevent excessive deoptimization.
function.set_allows_hoisting_check_class(false);
}
if (deopt_context->HasDeoptFlag(ICData::kGeneralized)) {
function.set_allows_bounds_check_generalization(false);
}
}
}
void DeferredPcMarker::Materialize(DeoptContext* deopt_context) {
Thread* thread = deopt_context->thread();
Zone* zone = deopt_context->zone();
uword* dest_addr = reinterpret_cast<uword*>(slot());
Function& function = Function::Handle(zone);
function ^= deopt_context->ObjectAt(index_);
ASSERT(!function.IsNull());
const Error& error = Error::Handle(zone,
Compiler::EnsureUnoptimizedCode(thread, function));
if (!error.IsNull()) {
Exceptions::PropagateError(error);
}
const Code& code = Code::Handle(zone, function.unoptimized_code());
ASSERT(!code.IsNull());
ASSERT(function.HasCode());
*reinterpret_cast<RawObject**>(dest_addr) = code.raw();
if (FLAG_trace_deoptimization_verbose) {
THR_Print("materializing pc marker at 0x%" Px ": %s, %s\n",
reinterpret_cast<uword>(slot()), code.ToCString(),
function.ToCString());
}
// Increment the deoptimization counter. This effectively increments each
// function occurring in the optimized frame.
if (deopt_context->deoptimizing_code()) {
function.set_deoptimization_counter(function.deoptimization_counter() + 1);
}
if (FLAG_trace_deoptimization || FLAG_trace_deoptimization_verbose) {
THR_Print("Deoptimizing '%s' (count %d)\n",
function.ToFullyQualifiedCString(),
function.deoptimization_counter());
}
// Clear invocation counter so that hopefully the function gets reoptimized
// only after more feedback has been collected.
function.set_usage_counter(0);
if (function.HasOptimizedCode()) {
function.SwitchToUnoptimizedCode();
}
}
void DeferredPp::Materialize(DeoptContext* deopt_context) {
Thread* thread = deopt_context->thread();
Zone* zone = deopt_context->zone();
Function& function = Function::Handle(zone);
function ^= deopt_context->ObjectAt(index_);
ASSERT(!function.IsNull());
const Error& error = Error::Handle(zone,
Compiler::EnsureUnoptimizedCode(thread, function));
if (!error.IsNull()) {
Exceptions::PropagateError(error);
}
const Code& code = Code::Handle(zone, function.unoptimized_code());
ASSERT(!code.IsNull());
ASSERT(code.GetObjectPool() != Object::null());
*slot() = code.GetObjectPool();
if (FLAG_trace_deoptimization_verbose) {
OS::PrintErr("materializing pp at 0x%" Px ": 0x%" Px "\n",
reinterpret_cast<uword>(slot()),
reinterpret_cast<uword>(code.GetObjectPool()));
}
}
RawObject* DeferredObject::object() {
if (object_ == NULL) {
Create();
}
return object_->raw();
}
void DeferredObject::Create() {
if (object_ != NULL) {
return;
}
Class& cls = Class::Handle();
cls ^= GetClass();
if (cls.raw() == Object::context_class()) {
intptr_t num_variables = Smi::Cast(Object::Handle(GetLength())).Value();
if (FLAG_trace_deoptimization_verbose) {
OS::PrintErr(
"materializing context of length %" Pd " (%" Px ", %" Pd " vars)\n",
num_variables,
reinterpret_cast<uword>(args_),
field_count_);
}
object_ = &Context::ZoneHandle(Context::New(num_variables));
} else {
if (FLAG_trace_deoptimization_verbose) {
OS::PrintErr("materializing instance of %s (%" Px ", %" Pd " fields)\n",
cls.ToCString(),
reinterpret_cast<uword>(args_),
field_count_);
}
object_ = &Instance::ZoneHandle(Instance::New(cls));
}
}
static intptr_t ToContextIndex(intptr_t offset_in_bytes) {
intptr_t result = (offset_in_bytes - Context::variable_offset(0)) / kWordSize;
ASSERT(result >= 0);
return result;
}
void DeferredObject::Fill() {
Create(); // Ensure instance is created.
Class& cls = Class::Handle();
cls ^= GetClass();
if (cls.raw() == Object::context_class()) {
const Context& context = Context::Cast(*object_);
Smi& offset = Smi::Handle();
Object& value = Object::Handle();
for (intptr_t i = 0; i < field_count_; i++) {
offset ^= GetFieldOffset(i);
if (offset.Value() == Context::parent_offset()) {
// Copy parent.
Context& parent = Context::Handle();
parent ^= GetValue(i);
context.set_parent(parent);
if (FLAG_trace_deoptimization_verbose) {
OS::PrintErr(" ctx@parent (offset %" Pd ") <- %s\n",
offset.Value(),
value.ToCString());
}
} else {
intptr_t context_index = ToContextIndex(offset.Value());
value = GetValue(i);
context.SetAt(context_index, value);
if (FLAG_trace_deoptimization_verbose) {
OS::PrintErr(" ctx@%" Pd " (offset %" Pd ") <- %s\n",
context_index,
offset.Value(),
value.ToCString());
}
}
}
} else if (cls.id() == kClosureCid) {
// TODO(regis): It would be better to programmatically add these fields to
// the VM Closure class. Declaring them in the Dart class _Closure does not
// work, because the class is prefinalized and CalculateFieldOffsets is
// therefore not called. Resetting the finalization state may be an option.
const Closure& closure = Closure::Cast(*object_);
Smi& offset = Smi::Handle();
Object& value = Object::Handle();
for (intptr_t i = 0; i < field_count_; i++) {
offset ^= GetFieldOffset(i);
if (offset.Value() == Closure::type_arguments_offset()) {
TypeArguments& arguments = TypeArguments::Handle();
arguments ^= GetValue(i);
closure.SetTypeArguments(arguments);
if (FLAG_trace_deoptimization_verbose) {
OS::PrintErr(" closure@type_arguments (offset %" Pd ") <- %s\n",
offset.Value(),
value.ToCString());
}
} else if (offset.Value() == Closure::function_offset()) {
Function& function = Function::Handle();
function ^= GetValue(i);
closure.set_function(function);
if (FLAG_trace_deoptimization_verbose) {
OS::PrintErr(" closure@function (offset %" Pd ") <- %s\n",
offset.Value(),
value.ToCString());
}
} else {
ASSERT(offset.Value() == Closure::context_offset());
Context& context = Context::Handle();
context ^= GetValue(i);
closure.set_context(context);
if (FLAG_trace_deoptimization_verbose) {
OS::PrintErr(" closure@context (offset %" Pd ") <- %s\n",
offset.Value(),
value.ToCString());
}
}
}
} else {
const Instance& obj = Instance::Cast(*object_);
Smi& offset = Smi::Handle();
Field& field = Field::Handle();
Object& value = Object::Handle();
const Array& offset_map = Array::Handle(cls.OffsetToFieldMap());
for (intptr_t i = 0; i < field_count_; i++) {
offset ^= GetFieldOffset(i);
field ^= offset_map.At(offset.Value() / kWordSize);
value = GetValue(i);
if (!field.IsNull()) {
obj.SetField(field, value);
if (FLAG_trace_deoptimization_verbose) {
OS::PrintErr(" %s <- %s\n",
String::Handle(field.name()).ToCString(),
value.ToCString());
}
} else {
ASSERT(offset.Value() == cls.type_arguments_field_offset());
obj.SetFieldAtOffset(offset.Value(), value);
if (FLAG_trace_deoptimization_verbose) {
OS::PrintErr(" null Field @ offset(%" Pd ") <- %s\n",
offset.Value(),
value.ToCString());
}
}
}
}
}
} // namespace dart