Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(709)

Unified Diff: runtime/vm/object.cc

Issue 1965823002: Initial isolate reload support (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: runtime/vm/object.cc
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 7780ecd88ecbdad2e891540f5fa6c6db7bec48ea..ad7b37ae34434626c45ade692961e4d8114c090a 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -27,10 +27,12 @@
#include "vm/hash_table.h"
#include "vm/heap.h"
#include "vm/intrinsifier.h"
+#include "vm/isolate_reload.h"
#include "vm/object_store.h"
#include "vm/parser.h"
#include "vm/precompiler.h"
#include "vm/profiler.h"
+#include "vm/resolver.h"
#include "vm/reusable_handles.h"
#include "vm/runtime_entry.h"
#include "vm/scopes.h"
@@ -61,9 +63,13 @@ DEFINE_FLAG(bool, use_exp_cache, true, "Use library exported name cache");
DEFINE_FLAG(bool, ignore_patch_signature_mismatch, false,
"Ignore patch file member signature mismatch.");
+DEFINE_FLAG(bool, remove_script_timestamps_for_test, false,
+ "Remove script timestamps to allow for deterministic testing.");
+
DECLARE_FLAG(bool, show_invisible_frames);
DECLARE_FLAG(bool, trace_deoptimization);
DECLARE_FLAG(bool, trace_deoptimization_verbose);
+DECLARE_FLAG(bool, trace_reload);
DECLARE_FLAG(bool, write_protect_code);
DECLARE_FLAG(bool, support_externalizable_strings);
@@ -2773,13 +2779,18 @@ void Class::RegisterCHACode(const Code& code) {
void Class::DisableCHAOptimizedCode(const Class& subclass) {
ASSERT(Thread::Current()->IsMutatorThread());
CHACodeArray a(*this);
- if (FLAG_trace_deoptimization && a.HasCodes()) {
+ if (FLAG_trace_deoptimization && a.HasCodes() && !subclass.IsNull()) {
THR_Print("Adding subclass %s\n", subclass.ToCString());
}
a.DisableCode();
}
+void Class::DisableAllCHAOptimizedCode() {
+ DisableCHAOptimizedCode(Class::Handle());
+}
+
+
bool Class::TraceAllocation(Isolate* isolate) const {
ClassTable* class_table = isolate->class_table();
return class_table->TraceAllocationFor(id());
@@ -3124,7 +3135,7 @@ void Class::AddFields(const GrowableArray<const Field*>& new_fields) const {
template <class FakeInstance>
-RawClass* Class::New(intptr_t index) {
+RawClass* Class::NewCommon(intptr_t index) {
ASSERT(Object::class_class() != Class::null());
Class& result = Class::Handle();
{
@@ -3147,18 +3158,28 @@ RawClass* Class::New(intptr_t index) {
result.set_num_native_fields(0);
result.set_token_pos(TokenPosition::kNoSource);
result.InitEmptyFields();
+ return result.raw();
+}
+
+
+template <class FakeInstance>
+RawClass* Class::New(intptr_t index) {
+ Class& result = Class::Handle(NewCommon<FakeInstance>(index));
Isolate::Current()->RegisterClass(result);
return result.raw();
}
-RawClass* Class::New(const String& name,
+RawClass* Class::New(const Library& lib,
+ const String& name,
const Script& script,
TokenPosition token_pos) {
- Class& result = Class::Handle(New<Instance>(kIllegalCid));
+ Class& result = Class::Handle(NewCommon<Instance>(kIllegalCid));
+ result.set_library(lib);
result.set_name(name);
result.set_script(script);
result.set_token_pos(token_pos);
+ Isolate::Current()->RegisterClass(result);
return result.raw();
}
@@ -3168,7 +3189,7 @@ RawClass* Class::NewNativeWrapper(const Library& library,
int field_count) {
Class& cls = Class::Handle(library.LookupClass(name));
if (cls.IsNull()) {
- cls = New(name, Script::Handle(), TokenPosition::kNoSource);
+ cls = New(library, name, Script::Handle(), TokenPosition::kNoSource);
cls.SetFields(Object::empty_array());
cls.SetFunctions(Object::empty_array());
// Set super class to Object.
@@ -5471,6 +5492,19 @@ void Function::ClearCode() const {
}
+void Function::EnsureHasCompiledUnoptimizedCode() const {
+ Thread* thread = Thread::Current();
+ Zone* zone = thread->zone();
+ ASSERT(thread->IsMutatorThread());
+
+ const Error& error = Error::Handle(zone,
+ Compiler::EnsureUnoptimizedCode(thread, *this));
+ if (!error.IsNull()) {
+ Exceptions::PropagateError(error);
+ }
+}
+
+
void Function::SwitchToUnoptimizedCode() const {
ASSERT(HasOptimizedCode());
Thread* thread = Thread::Current();
@@ -5497,6 +5531,34 @@ void Function::SwitchToUnoptimizedCode() const {
}
+void Function::SwitchToLazyCompiledUnoptimizedCode() const {
+ if (!HasOptimizedCode()) {
+ return;
+ }
+
+ Thread* thread = Thread::Current();
+ Zone* zone = thread->zone();
+ ASSERT(thread->IsMutatorThread());
+
+ const Code& current_code = Code::Handle(zone, CurrentCode());
+ TIR_Print("Disabling optimized code for %s\n", ToCString());
+ current_code.DisableDartCode();
+
+ const Code& unopt_code = Code::Handle(zone, unoptimized_code());
+ if (unopt_code.IsNull()) {
+ // Set the lazy compile code.
+ TIR_Print("Switched to lazy compile stub for %s\n", ToCString());
+ SetInstructions(Code::Handle(StubCode::LazyCompile_entry()->code()));
+ return;
+ }
+
+ TIR_Print("Switched to unoptimized code for %s\n", ToCString());
+
+ AttachCode(unopt_code);
+ unopt_code.Enable();
+}
+
+
void Function::set_unoptimized_code(const Code& value) const {
ASSERT(Thread::Current()->IsMutatorThread());
ASSERT(value.IsNull() || !value.is_optimized());
@@ -7061,6 +7123,8 @@ RawClass* Function::origin() const {
RawScript* Function::script() const {
+ // NOTE(turnidge): If you update this function, you probably want to
+ // update Class::PatchFieldsAndFunctions() at the same time.
if (token_pos() == TokenPosition::kMinSource) {
// Testing for position 0 is an optimization that relies on temporary
// eval functions having token position 0.
@@ -7538,6 +7602,8 @@ RawClass* Field::Origin() const {
RawScript* Field::Script() const {
+ // NOTE(turnidge): If you update this function, you probably want to
+ // update Class::PatchFieldsAndFunctions() at the same time.
const Field& field = Field::Handle(Original());
ASSERT(field.IsOriginal());
const Object& obj = Object::Handle(field.raw_ptr()->owner_);
@@ -7569,16 +7635,14 @@ RawField* Field::New() {
}
-RawField* Field::New(const String& name,
- bool is_static,
- bool is_final,
- bool is_const,
- bool is_reflectable,
- const Class& owner,
- const AbstractType& type,
- TokenPosition token_pos) {
- ASSERT(!owner.IsNull());
- const Field& result = Field::Handle(Field::New());
+void Field::InitializeNew(const Field& result,
+ const String& name,
+ bool is_static,
+ bool is_final,
+ bool is_const,
+ bool is_reflectable,
+ const Object& owner,
+ TokenPosition token_pos) {
result.set_name(name);
result.set_is_static(is_static);
if (!is_static) {
@@ -7589,19 +7653,47 @@ RawField* Field::New(const String& name,
result.set_is_reflectable(is_reflectable);
result.set_is_double_initialized(false);
result.set_owner(owner);
- result.SetFieldType(type);
result.set_token_pos(token_pos);
result.set_has_initializer(false);
result.set_is_unboxing_candidate(true);
- result.set_guarded_cid(FLAG_use_field_guards ? kIllegalCid : kDynamicCid);
- result.set_is_nullable(FLAG_use_field_guards ? false : true);
+ Isolate* isolate = Isolate::Current();
+
+ // Use field guards if they are enabled and the isolate has never reloaded.
+ // TODO(johnmccutchan): The reload case assumes the worst case (everything is
+ // dynamic and possibly null). Attempt to relax this later.
+ const bool use_field_guards =
+ FLAG_use_field_guards && !isolate->HasAttemptedReload();
+ result.set_guarded_cid(use_field_guards ? kIllegalCid : kDynamicCid);
+ result.set_is_nullable(use_field_guards ? false : true);
result.set_guarded_list_length_in_object_offset(Field::kUnknownLengthOffset);
// Presently, we only attempt to remember the list length for final fields.
- if (is_final && FLAG_use_field_guards) {
+ if (is_final && use_field_guards) {
result.set_guarded_list_length(Field::kUnknownFixedLength);
} else {
result.set_guarded_list_length(Field::kNoFixedLength);
}
+}
+
+
+RawField* Field::New(const String& name,
+ bool is_static,
+ bool is_final,
+ bool is_const,
+ bool is_reflectable,
+ const Class& owner,
+ const AbstractType& type,
+ TokenPosition token_pos) {
+ ASSERT(!owner.IsNull());
+ const Field& result = Field::Handle(Field::New());
+ InitializeNew(result,
+ name,
+ is_static,
+ is_final,
+ is_const,
+ is_reflectable,
+ owner,
+ token_pos);
+ result.SetFieldType(type);
return result.raw();
}
@@ -7613,25 +7705,14 @@ RawField* Field::NewTopLevel(const String& name,
TokenPosition token_pos) {
ASSERT(!owner.IsNull());
const Field& result = Field::Handle(Field::New());
- result.set_name(name);
- result.set_is_static(true);
- result.set_is_final(is_final);
- result.set_is_const(is_const);
- result.set_is_reflectable(true);
- result.set_is_double_initialized(false);
- result.set_owner(owner);
- result.set_token_pos(token_pos);
- result.set_has_initializer(false);
- result.set_is_unboxing_candidate(true);
- result.set_guarded_cid(FLAG_use_field_guards ? kIllegalCid : kDynamicCid);
- result.set_is_nullable(FLAG_use_field_guards ? false : true);
- result.set_guarded_list_length_in_object_offset(Field::kUnknownLengthOffset);
- // Presently, we only attempt to remember the list length for final fields.
- if (is_final && FLAG_use_field_guards) {
- result.set_guarded_list_length(Field::kUnknownFixedLength);
- } else {
- result.set_guarded_list_length(Field::kNoFixedLength);
- }
+ InitializeNew(result,
+ name,
+ true, /* is_static */
+ is_final,
+ is_const,
+ true, /* is_reflectable */
+ owner,
+ token_pos);
return result.raw();
}
@@ -8100,6 +8181,18 @@ void Field::RecordStore(const Object& value) const {
}
+void Field::ForceDynamicGuardedCidAndLength() const {
+ // Assume nothing about this field.
+ set_is_unboxing_candidate(false);
+ set_guarded_cid(kDynamicCid);
+ set_is_nullable(true);
+ set_guarded_list_length(Field::kNoFixedLength);
+ set_guarded_list_length_in_object_offset(Field::kUnknownLengthOffset);
+ // Drop any code that relied on the above assumptions.
+ DeoptimizeDependentCode();
+}
+
+
void LiteralToken::set_literal(const String& literal) const {
StorePointer(&raw_ptr()->literal_, literal.raw());
}
@@ -8927,6 +9020,11 @@ void Script::set_kind(RawScript::Kind value) const {
}
+void Script::set_load_timestamp(int64_t value) const {
+ StoreNonPointer(&raw_ptr()->load_timestamp_, value);
+}
+
+
void Script::set_tokens(const TokenStream& value) const {
StorePointer(&raw_ptr()->tokens_, value.raw());
}
@@ -9180,13 +9278,16 @@ RawScript* Script::New(const String& url,
result.set_url(String::Handle(zone, Symbols::New(thread, url)));
result.set_source(source);
result.set_kind(kind);
+ result.set_load_timestamp(FLAG_remove_script_timestamps_for_test
+ ? 0 : OS::GetCurrentTimeMillis());
result.SetLocationOffset(0, 0);
return result.raw();
}
const char* Script::ToCString() const {
- return "Script";
+ const String& name = String::Handle(url());
+ return OS::SCreate(Thread::Current()->zone(), "Script(%s)", name.ToCString());
}
@@ -12676,9 +12777,20 @@ intptr_t ICData::TestEntryLength() const {
}
+intptr_t ICData::Length() const {
+ return (Smi::Value(ic_data()->ptr()->length_) / TestEntryLength());
+}
+
+
intptr_t ICData::NumberOfChecks() const {
- // Do not count the sentinel;
- return (Smi::Value(ic_data()->ptr()->length_) / TestEntryLength()) - 1;
+ const intptr_t length = Length();
+ for (intptr_t i = 0; i < length; i++) {
+ if (IsSentinelAt(i)) {
+ return i;
+ }
+ }
Florian Schneider 2016/05/18 09:36:56 This approach does not work with background compil
+ UNREACHABLE();
+ return -1;
}
@@ -12715,6 +12827,7 @@ bool ICData::HasCheck(const GrowableArray<intptr_t>& cids) const {
GetClassIdsAt(i, &class_ids);
bool matches = true;
for (intptr_t k = 0; k < class_ids.length(); k++) {
+ ASSERT(class_ids[k] != kIllegalCid);
if (class_ids[k] != cids[k]) {
matches = false;
break;
@@ -12729,6 +12842,142 @@ bool ICData::HasCheck(const GrowableArray<intptr_t>& cids) const {
#endif // DEBUG
+void ICData::WriteSentinelAt(intptr_t index) const {
+ const intptr_t len = Length();
+ ASSERT(index >= 0);
+ ASSERT(index < len);
+ Array& data = Array::Handle(ic_data());
+ const intptr_t start = index * TestEntryLength();
+ const intptr_t end = start + TestEntryLength();
+ for (intptr_t i = start; i < end; i++) {
+ data.SetAt(i, smi_illegal_cid());
+ }
+}
+
+
+void ICData::ClearCountAt(intptr_t index) const {
+ const intptr_t len = NumberOfChecks();
+ ASSERT(index >= 0);
+ ASSERT(index < len);
+ SetCountAt(index, 0);
+}
+
+
+void ICData::ClearWithSentinel() const {
+ if (IsImmutable()) {
+ return;
+ }
+ // Write the sentinel value into all entries except the first one.
+ const intptr_t len = Length();
+ if (len == 0) {
+ return;
+ }
+ // The final entry is always the sentinel.
+ ASSERT(IsSentinelAt(len - 1));
+ for (intptr_t i = len - 1; i > 0; i--) {
+ WriteSentinelAt(i);
+ }
+ if (NumArgsTested() != 2) {
+ // Not the smi fast path case, write sentinel to first one and exit.
+ WriteSentinelAt(0);
+ return;
+ }
+ if (IsSentinelAt(0)) {
+ return;
+ }
+ Zone* zone = Thread::Current()->zone();
+ const String& name = String::Handle(target_name());
+ const Class& smi_class = Class::Handle(Smi::Class());
+ const Function& smi_op_target =
+ Function::Handle(Resolver::ResolveDynamicAnyArgs(zone, smi_class, name));
+ GrowableArray<intptr_t> class_ids(2);
+ Function& target = Function::Handle();
+ GetCheckAt(0, &class_ids, &target);
+ if ((target.raw() == smi_op_target.raw()) &&
+ (class_ids[0] == kSmiCid) && (class_ids[1] == kSmiCid)) {
+ // The smi fast path case, preserve the initial entry but reset the count.
+ ClearCountAt(0);
+ return;
+ }
+ WriteSentinelAt(0);
+}
+
+
+void ICData::ClearAndSetStaticTarget(const Function& func) const {
+ if (IsImmutable()) {
+ return;
+ }
+ const intptr_t len = Length();
+ if (len == 0) {
+ return;
+ }
+ // The final entry is always the sentinel.
+ ASSERT(IsSentinelAt(len - 1));
+ if (NumArgsTested() == 0) {
+ // No type feedback is being collected.
+ const Array& data = Array::Handle(ic_data());
+ // Static calls with no argument checks hold only one target and the
+ // sentinel value.
+ ASSERT(len == 2);
+ // Static calls with no argument checks only need two words.
+ ASSERT(TestEntryLength() == 2);
+ // Set the target.
+ data.SetAt(0, func);
+ // Set count to 0 as this is called during compilation, before the
+ // call has been executed.
+ const Smi& value = Smi::Handle(Smi::New(0));
+ data.SetAt(1, value);
+ } else {
+ // Type feedback on arguments is being collected.
+ const Array& data = Array::Handle(ic_data());
+
+ // Fill all but the first entry with the sentinel.
+ for (intptr_t i = len - 1; i > 0; i--) {
+ WriteSentinelAt(i);
+ }
+ // Rewrite the dummy entry.
+ const Smi& object_cid = Smi::Handle(Smi::New(kObjectCid));
+ for (intptr_t i = 0; i < NumArgsTested(); i++) {
+ data.SetAt(i, object_cid);
+ }
+ data.SetAt(NumArgsTested(), func);
+ const Smi& value = Smi::Handle(Smi::New(0));
+ data.SetAt(NumArgsTested() + 1, value);
+ }
+}
+
+
+// Add an initial Smi/Smi check with count 0.
+bool ICData::AddSmiSmiCheckForFastSmiStubs() const {
+ bool is_smi_two_args_op = false;
+
+ ASSERT(NumArgsTested() == 2);
+ const String& name = String::Handle(target_name());
+ const Class& smi_class = Class::Handle(Smi::Class());
+ Zone* zone = Thread::Current()->zone();
+ const Function& smi_op_target =
+ Function::Handle(Resolver::ResolveDynamicAnyArgs(zone, smi_class, name));
+ if (NumberOfChecks() == 0) {
+ GrowableArray<intptr_t> class_ids(2);
+ class_ids.Add(kSmiCid);
+ class_ids.Add(kSmiCid);
+ AddCheck(class_ids, smi_op_target);
+ // 'AddCheck' sets the initial count to 1.
+ SetCountAt(0, 0);
+ is_smi_two_args_op = true;
+ } else if (NumberOfChecks() == 1) {
+ GrowableArray<intptr_t> class_ids(2);
+ Function& target = Function::Handle();
+ GetCheckAt(0, &class_ids, &target);
+ if ((target.raw() == smi_op_target.raw()) &&
+ (class_ids[0] == kSmiCid) && (class_ids[1] == kSmiCid)) {
+ is_smi_two_args_op = true;
+ }
+ }
+ return is_smi_two_args_op;
+}
+
+
// Used for unoptimized static calls when no class-ids are checked.
void ICData::AddTarget(const Function& target) const {
ASSERT(!target.IsNull());
@@ -12798,10 +13047,10 @@ void ICData::AddCheck(const GrowableArray<intptr_t>& class_ids,
return;
}
}
- const intptr_t new_len = data.Length() + TestEntryLength();
- data = Array::Grow(data, new_len, Heap::kOld);
- WriteSentinel(data, TestEntryLength());
- intptr_t data_pos = old_num * TestEntryLength();
+ intptr_t index = -1;
+ data = FindFreeIndex(&index);
+ ASSERT(!data.IsNull());
+ intptr_t data_pos = index * TestEntryLength();
Smi& value = Smi::Handle();
for (intptr_t i = 0; i < class_ids.length(); i++) {
// kIllegalCid is used as terminating value, do not add it.
@@ -12819,6 +13068,57 @@ void ICData::AddCheck(const GrowableArray<intptr_t>& class_ids,
}
+RawArray* ICData::FindFreeIndex(intptr_t* index) const {
+ // The final entry is always the sentinel value, don't consider it
+ // when searching.
+ const intptr_t len = Length() - 1;
+ Array& data = Array::Handle(ic_data());
+ *index = len;
+ for (intptr_t i = 0; i < len; i++) {
+ if (IsSentinelAt(i)) {
+ *index = i;
+ break;
+ }
+ }
+ if (*index < len) {
+ // We've found a free slot.
+ return data.raw();
+ }
+ // Append case.
+ ASSERT(*index == len);
+ ASSERT(*index >= 0);
+ // Grow array.
+ const intptr_t new_len = data.Length() + TestEntryLength();
+ data = Array::Grow(data, new_len, Heap::kOld);
+ WriteSentinel(data, TestEntryLength());
+ return data.raw();
+}
+
+
+void ICData::DebugDump() const {
+ const Function& owner = Function::Handle(Owner());
+ THR_Print("ICData::DebugDump\n");
+ THR_Print("Owner = %s [deopt=%" Pd "]\n", owner.ToCString(), deopt_id());
+ THR_Print("NumArgsTested = %" Pd "\n", NumArgsTested());
+ THR_Print("Length = %" Pd "\n", Length());
+ THR_Print("NumberOfChecks = %" Pd "\n", NumberOfChecks());
+
+ GrowableArray<intptr_t> class_ids;
+ for (intptr_t i = 0; i < NumberOfChecks(); i++) {
+ THR_Print("Check[%" Pd "]:", i);
+ GetClassIdsAt(i, &class_ids);
+ for (intptr_t c = 0; c < class_ids.length(); c++) {
+ THR_Print(" %" Pd "", class_ids[c]);
+ }
+ THR_Print("--- %" Pd " hits\n", GetCountAt(i));
+ }
+}
+
+
+void ICData::ValidateSentinelLocations() const {
+}
+
+
void ICData::AddReceiverCheck(intptr_t receiver_class_id,
const Function& target,
intptr_t count) const {
@@ -12831,12 +13131,9 @@ void ICData::AddReceiverCheck(intptr_t receiver_class_id,
ASSERT(NumArgsTested() == 1); // Otherwise use 'AddCheck'.
ASSERT(receiver_class_id != kIllegalCid);
- const intptr_t old_num = NumberOfChecks();
- Array& data = Array::Handle(ic_data());
- const intptr_t new_len = data.Length() + TestEntryLength();
- data = Array::Grow(data, new_len, Heap::kOld);
- WriteSentinel(data, TestEntryLength());
- intptr_t data_pos = old_num * TestEntryLength();
+ intptr_t index = -1;
+ Array& data = Array::Handle(FindFreeIndex(&index));
+ intptr_t data_pos = index * TestEntryLength();
if ((receiver_class_id == kSmiCid) && (data_pos > 0)) {
ASSERT(GetReceiverClassIdAt(0) != kSmiCid);
// Move class occupying position 0 to the data_pos.
@@ -12881,10 +13178,26 @@ void ICData::GetCheckAt(intptr_t index,
}
+bool ICData::IsSentinelAt(intptr_t index) const {
+ ASSERT(index < Length());
+ const Array& data = Array::Handle(ic_data());
+ const intptr_t entry_length = TestEntryLength();
+ intptr_t data_pos = index * TestEntryLength();
+ for (intptr_t i = 0; i < entry_length; i++) {
+ if (data.At(data_pos++) != smi_illegal_cid().raw()) {
+ return false;
+ }
+ }
+ // The entry at |index| was filled with the value kIllegalCid.
+ return true;
+}
+
+
void ICData::GetClassIdsAt(intptr_t index,
GrowableArray<intptr_t>* class_ids) const {
- ASSERT(index < NumberOfChecks());
+ ASSERT(index < Length());
ASSERT(class_ids != NULL);
+ ASSERT(!IsSentinelAt(index));
class_ids->Clear();
const Array& data = Array::Handle(ic_data());
intptr_t data_pos = index * TestEntryLength();
@@ -12923,7 +13236,8 @@ intptr_t ICData::GetClassIdAt(intptr_t index, intptr_t arg_nr) const {
intptr_t ICData::GetReceiverClassIdAt(intptr_t index) const {
- ASSERT(index < NumberOfChecks());
+ ASSERT(index < Length());
+ ASSERT(!IsSentinelAt(index));
const intptr_t data_pos = index * TestEntryLength();
NoSafepointScope no_safepoint;
RawArray* raw_data = ic_data();
@@ -13127,10 +13441,9 @@ RawICData* ICData::AsUnaryClassChecksSortedByCount() const {
// Room for all entries and the sentinel.
const intptr_t data_len =
result.TestEntryLength() * (aggregate.length() + 1);
+ // Allocate the array but do not assign it to result until we have populated
+ // it with the aggregate data and the terminating sentinel.
const Array& data = Array::Handle(Array::New(data_len, Heap::kOld));
- result.set_ic_data_array(data);
- ASSERT(result.NumberOfChecks() == aggregate.length());
-
intptr_t pos = 0;
for (intptr_t i = 0; i < aggregate.length(); i++) {
data.SetAt(pos + 0, Smi::Handle(Smi::New(aggregate[i].cid)));
@@ -13142,6 +13455,7 @@ RawICData* ICData::AsUnaryClassChecksSortedByCount() const {
}
WriteSentinel(data, result.TestEntryLength());
result.set_ic_data_array(data);
+ ASSERT(result.NumberOfChecks() == aggregate.length());
return result.raw();
}
@@ -13288,6 +13602,22 @@ RawICData* ICData::NewDescriptor(Zone* zone,
}
+bool ICData::IsImmutable() const {
+ const Array& data = Array::Handle(ic_data());
+ return data.IsImmutable();
+}
+
+
+void ICData::ResetData() const {
+ // Number of array elements in one test entry.
+ intptr_t len = TestEntryLength();
+ // IC data array must be null terminated (sentinel entry).
+ const Array& ic_data = Array::Handle(Array::New(len, Heap::kOld));
+ set_ic_data_array(ic_data);
+ WriteSentinel(ic_data, len);
+}
+
+
RawICData* ICData::New() {
ICData& result = ICData::Handle();
{
@@ -15611,6 +15941,13 @@ bool AbstractType::HasResolvedTypeClass() const {
}
+classid_t AbstractType::type_class_id() const {
+ // AbstractType is an abstract class.
+ UNREACHABLE();
+ return kIllegalCid;
+}
+
+
RawClass* AbstractType::type_class() const {
// AbstractType is an abstract class.
UNREACHABLE();
@@ -16476,19 +16813,18 @@ void Type::SetIsResolved() const {
bool Type::HasResolvedTypeClass() const {
- return (raw_ptr()->type_class_->GetClassId() == kClassCid);
+ return !raw_ptr()->type_class_id_->IsHeapObject();
}
-RawClass* Type::type_class() const {
-#ifdef DEBUG
+classid_t Type::type_class_id() const {
ASSERT(HasResolvedTypeClass());
- Class& type_class = Class::Handle();
- type_class ^= raw_ptr()->type_class_;
- return type_class.raw();
-#else
- return reinterpret_cast<RawClass*>(raw_ptr()->type_class_);
-#endif
+ return Smi::Value(reinterpret_cast<RawSmi*>(raw_ptr()->type_class_id_));
+}
+
+
+RawClass* Type::type_class() const {
+ return Isolate::Current()->class_table()->At(type_class_id());
}
@@ -16496,13 +16832,13 @@ RawUnresolvedClass* Type::unresolved_class() const {
#ifdef DEBUG
ASSERT(!HasResolvedTypeClass());
UnresolvedClass& unresolved_class = UnresolvedClass::Handle();
- unresolved_class ^= raw_ptr()->type_class_;
+ unresolved_class ^= raw_ptr()->type_class_id_;
ASSERT(!unresolved_class.IsNull());
return unresolved_class.raw();
#else
- ASSERT(!Object::Handle(raw_ptr()->type_class_).IsNull());
- ASSERT(Object::Handle(raw_ptr()->type_class_).IsUnresolvedClass());
- return reinterpret_cast<RawUnresolvedClass*>(raw_ptr()->type_class_);
+ ASSERT(!Object::Handle(raw_ptr()->type_class_id_).IsNull());
+ ASSERT(Object::Handle(raw_ptr()->type_class_id_).IsUnresolvedClass());
+ return reinterpret_cast<RawUnresolvedClass*>(raw_ptr()->type_class_id_);
#endif
}
@@ -17068,9 +17404,16 @@ intptr_t Type::Hash() const {
}
-void Type::set_type_class(const Object& value) const {
- ASSERT(!value.IsNull() && (value.IsClass() || value.IsUnresolvedClass()));
- StorePointer(&raw_ptr()->type_class_, value.raw());
+void Type::set_type_class(const Class& value) const {
+ ASSERT(!value.IsNull());
+ StorePointer(&raw_ptr()->type_class_id_,
+ reinterpret_cast<RawObject*>(Smi::New(value.id())));
+}
+
+
+void Type::set_unresolved_class(const Object& value) const {
+ ASSERT(!value.IsNull() && value.IsUnresolvedClass());
+ StorePointer(&raw_ptr()->type_class_id_, value.raw());
}
@@ -17093,7 +17436,11 @@ RawType* Type::New(const Object& clazz,
TokenPosition token_pos,
Heap::Space space) {
const Type& result = Type::Handle(Type::New(space));
- result.set_type_class(clazz);
+ if (clazz.IsClass()) {
+ result.set_type_class(Class::Cast(clazz));
+ } else {
+ result.set_unresolved_class(clazz);
+ }
result.set_arguments(arguments);
result.set_token_pos(token_pos);
result.StoreNonPointer(&result.raw_ptr()->type_state_, RawType::kAllocated);
@@ -17341,7 +17688,25 @@ bool TypeParameter::IsEquivalent(const Instance& other, TrailPtr trail) const {
void TypeParameter::set_parameterized_class(const Class& value) const {
// Set value may be null.
- StorePointer(&raw_ptr()->parameterized_class_, value.raw());
+ classid_t cid = kIllegalCid;
+ if (!value.IsNull()) {
+ cid = value.id();
+ }
+ StoreNonPointer(&raw_ptr()->parameterized_class_id_, cid);
+}
+
+
+classid_t TypeParameter::parameterized_class_id() const {
+ return raw_ptr()->parameterized_class_id_;
+}
+
+
+RawClass* TypeParameter::parameterized_class() const {
+ classid_t cid = parameterized_class_id();
+ if (cid == kIllegalCid) {
+ return Class::null();
+ }
+ return Isolate::Current()->class_table()->At(cid);
}
« runtime/vm/object.h ('K') | « runtime/vm/object.h ('k') | runtime/vm/object_reload.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698