Index: runtime/vm/object.cc |
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc |
index 894452d9d8129ad33a01af9b4d1ec9e7675022a8..9afe3fc37ceb3d49ad4d77fb5437a277ac0761c4 100644 |
--- a/runtime/vm/object.cc |
+++ b/runtime/vm/object.cc |
@@ -2779,6 +2779,81 @@ void Class::SetTraceAllocation(bool trace_allocation) const { |
} |
+bool Class::ValidatePostFinalizePatch(const Class& orig_class, |
+ Error* error) const { |
+ ASSERT(error != NULL); |
+ // Not allowed to add new fields in a post finalization patch. |
+ if (fields() != Object::empty_array().raw()) { |
+ *error = LanguageError::NewFormatted( |
+ *error, // No previous error. |
+ Script::Handle(script()), |
+ token_pos(), |
+ Report::AtLocation, |
+ Report::kError, |
+ Heap::kNew, |
+ "new fields are not allowed for this patch"); |
+ return false; |
+ } |
+ // There seem to be no functions, the patch is pointless. |
+ if (functions() == Object::empty_array().raw()) { |
+ *error = LanguageError::NewFormatted( |
+ *error, // No previous error. |
+ Script::Handle(script()), |
+ token_pos(), |
+ Report::AtLocation, |
+ Report::kError, |
+ Heap::kNew, |
+ "no functions to patch"); |
+ return false; |
+ } |
+ // Iterate over all functions that will be patched and make sure |
+ // the original function was declared 'external' and has not executed |
+ // so far i.e no code has been generated for it. |
+ Thread* thread = Thread::Current(); |
+ ASSERT(thread->IsMutatorThread()); |
+ Zone* zone = thread->zone(); |
+ const Array& funcs = Array::Handle(zone, functions()); |
+ Function& func = Function::Handle(zone); |
+ Function& orig_func = Function::Handle(zone); |
+ String& name = String::Handle(zone); |
+ for (intptr_t i = 0; i < funcs.Length(); i++) { |
+ func ^= funcs.At(i); |
+ name ^= func.name(); |
+ orig_func ^= orig_class.LookupFunctionAllowPrivate(name); |
+ if (!orig_func.IsNull()) { |
+ if (!orig_func.is_external() || orig_func.HasCode()) { |
+ // We can only patch external functions in a post finalized class. |
+ *error = LanguageError::NewFormatted( |
+ *error, // No previous error. |
+ Script::Handle(script()), |
+ token_pos(), |
+ Report::AtLocation, |
+ Report::kError, |
+ Heap::kNew, |
+ !orig_func.is_external() ? |
+ "'%s' is not external and therefore cannot be patched" : |
+ "'%s' has already executed and therefore cannot be patched", |
+ name.ToCString()); |
+ return false; |
+ } |
+ } else if (!Library::IsPrivate(name)) { |
+ // We can only have new private functions that are added. |
+ *error = LanguageError::NewFormatted( |
+ *error, // No previous error. |
+ Script::Handle(script()), |
+ token_pos(), |
+ Report::AtLocation, |
+ Report::kError, |
+ Heap::kNew, |
+ "'%s' is not private and therefore cannot be patched", |
+ name.ToCString()); |
+ return false; |
+ } |
+ } |
+ return true; |
+} |
+ |
+ |
void Class::set_cha_codes(const Array& cache) const { |
StorePointer(&raw_ptr()->cha_codes_, cache.raw()); |
} |
@@ -3422,6 +3497,14 @@ void Class::set_is_finalized() const { |
} |
+void Class::SetRefinalizeAfterPatch() const { |
+ ASSERT(!IsTopLevel()); |
+ set_state_bits(ClassFinalizedBits::update(RawClass::kRefinalizeAfterPatch, |
+ raw_ptr()->state_bits_)); |
+ set_state_bits(TypeFinalizedBit::update(false, raw_ptr()->state_bits_)); |
+} |
+ |
+ |
void Class::ResetFinalization() const { |
ASSERT(IsTopLevel()); |
set_state_bits(ClassFinalizedBits::update(RawClass::kAllocated, |
@@ -5832,6 +5915,7 @@ void Function::SetIsNativeAutoSetupScope(bool value) const { |
bool Function::CanBeInlined() const { |
Thread* thread = Thread::Current(); |
return is_inlinable() && |
+ !is_external() && |
!is_generated_body() && |
(!FLAG_support_debugger || |
!thread->isolate()->debugger()->HasBreakpoint(*this, thread->zone())); |