 Chromium Code Reviews
 Chromium Code Reviews Issue 10827288:
  - Support for patching of class methods and fields.  (Closed) 
  Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
    
  
    Issue 10827288:
  - Support for patching of class methods and fields.  (Closed) 
  Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/| Index: runtime/vm/object.cc | 
| =================================================================== | 
| --- runtime/vm/object.cc (revision 10615) | 
| +++ runtime/vm/object.cc (working copy) | 
| @@ -74,6 +74,7 @@ | 
| RawClass* Object::type_arguments_class_ = reinterpret_cast<RawClass*>(RAW_NULL); | 
| RawClass* Object::instantiated_type_arguments_class_ = | 
| reinterpret_cast<RawClass*>(RAW_NULL); | 
| +RawClass* Object::patch_class_class_ = reinterpret_cast<RawClass*>(RAW_NULL); | 
| RawClass* Object::function_class_ = reinterpret_cast<RawClass*>(RAW_NULL); | 
| RawClass* Object::field_class_ = reinterpret_cast<RawClass*>(RAW_NULL); | 
| RawClass* Object::literal_token_class_ = reinterpret_cast<RawClass*>(RAW_NULL); | 
| @@ -288,6 +289,9 @@ | 
| cls = Class::New<InstantiatedTypeArguments>(); | 
| instantiated_type_arguments_class_ = cls.raw(); | 
| + cls = Class::New<PatchClass>(); | 
| + patch_class_class_ = cls.raw(); | 
| + | 
| cls = Class::New<Function>(); | 
| function_class_ = cls.raw(); | 
| @@ -1230,7 +1234,7 @@ | 
| intptr_t len = value.Length(); | 
| for (intptr_t i = 0; i < len; i++) { | 
| func ^= value.At(i); | 
| - ASSERT(func.owner() == raw()); | 
| + ASSERT(func.Owner() == raw()); | 
| } | 
| #endif | 
| StorePointer(&raw_ptr()->functions_, value.raw()); | 
| @@ -1320,7 +1324,7 @@ | 
| const Function& signature_fun = Function::Handle(signature_function()); | 
| if (!signature_fun.is_static() && | 
| !signature_fun.HasInstantiatedSignature()) { | 
| - cls = signature_fun.owner(); | 
| + cls = signature_fun.Owner(); | 
| } | 
| } | 
| intptr_t num_type_args = NumTypeParameters(); | 
| @@ -1480,6 +1484,57 @@ | 
| } | 
| +void Class::ApplyPatch(const Class& with) const { | 
| + ASSERT(!is_finalized()); | 
| + const Script& patch_script = Script::Handle(with.script()); | 
| + const String& str = String::Handle(patch_script.Source()); | 
| + OS::PrintErr("patch_script: %s\n", str.ToCString()); | 
| 
Ivan Posva
2012/08/14 01:21:49
Debug print removed...
 | 
| + const PatchClass& patch = PatchClass::Handle( | 
| + PatchClass::New(*this, patch_script)); | 
| + | 
| + const Array& orig_functions = Array::Handle(functions()); | 
| + intptr_t orig_len = orig_functions.Length(); | 
| + | 
| + const Array& patch_functions = Array::Handle(with.functions()); | 
| + intptr_t patch_len = patch_functions.Length(); | 
| + | 
| + // TODO(iposva): Verify that only patching existing methods and adding only | 
| + // new private methods. | 
| + Function& func = Function::Handle(); | 
| + const Array& new_functions = Array::Handle(Array::New(patch_len + orig_len)); | 
| 
siva
2012/08/15 00:16:04
I think you should add a comment here that current
 
Ivan Posva
2012/08/15 06:50:39
I attempted to address the second part of your sug
 | 
| + for (intptr_t i = 0; i < patch_len; i++) { | 
| + func ^= patch_functions.At(i); | 
| + func.set_owner(patch); | 
| + new_functions.SetAt(i, func); | 
| + } | 
| + for (intptr_t i = 0; i < orig_len; i++) { | 
| + func ^= orig_functions.At(i); | 
| + new_functions.SetAt(patch_len + i, func); | 
| + } | 
| + SetFunctions(new_functions); | 
| + | 
| + const Array& orig_fields = Array::Handle(fields()); | 
| + orig_len = orig_fields.Length(); | 
| + | 
| + const Array& patch_fields = Array::Handle(with.fields()); | 
| + patch_len = patch_fields.Length(); | 
| 
siva
2012/08/15 00:16:04
why not call the array handle variables orig_list,
 
Ivan Posva
2012/08/15 06:50:39
ditto
 | 
| + | 
| + // TODO(iposva): Verify that no duplicate fields are entered. | 
| + Field& field = Field::Handle(); | 
| + const Array& new_fields = Array::Handle(Array::New(patch_len + orig_len)); | 
| + for (intptr_t i = 0; i < patch_len; i++) { | 
| + field ^= patch_fields.At(i); | 
| + field.set_owner(*this); | 
| + new_fields.SetAt(i, field); | 
| + } | 
| + for (intptr_t i = 0; i < orig_len; i++) { | 
| + field ^= orig_fields.At(i); | 
| + new_fields.SetAt(patch_len + i, field); | 
| + } | 
| + SetFields(new_fields); | 
| +} | 
| + | 
| + | 
| void Class::SetFields(const Array& value) const { | 
| ASSERT(!value.IsNull()); | 
| #if defined(DEBUG) | 
| @@ -1557,7 +1612,7 @@ | 
| const Function& signature_function, | 
| const Script& script) { | 
| ASSERT(!signature_function.IsNull()); | 
| - const Class& owner_class = Class::Handle(signature_function.owner()); | 
| + const Class& owner_class = Class::Handle(signature_function.Owner()); | 
| ASSERT(!owner_class.IsNull()); | 
| TypeArguments& type_parameters = TypeArguments::Handle(); | 
| // A signature class extends class Instance and is parameterized in the same | 
| @@ -3502,6 +3557,45 @@ | 
| } | 
| +const char* PatchClass::ToCString() const { | 
| + const char* kFormat = "PatchClass for %s"; | 
| + const Class& cls = Class::Handle(patched_class()); | 
| + const char* cls_name = cls.ToCString(); | 
| + intptr_t len = OS::SNPrint(NULL, 0, kFormat, cls_name) + 1; | 
| + char* chars = Isolate::Current()->current_zone()->Alloc<char>(len); | 
| + OS::SNPrint(chars, len, kFormat, cls_name); | 
| + return chars; | 
| +} | 
| + | 
| + | 
| +RawPatchClass* PatchClass::New(const Class& patched_class, | 
| + const Script& script) { | 
| + const PatchClass& result = PatchClass::Handle(PatchClass::New()); | 
| + result.set_patched_class(patched_class); | 
| + result.set_script(script); | 
| + return result.raw(); | 
| +} | 
| + | 
| + | 
| +RawPatchClass* PatchClass::New() { | 
| + ASSERT(Object::patch_class_class() != Class::null()); | 
| + RawObject* raw = Object::Allocate(PatchClass::kClassId, | 
| + PatchClass::InstanceSize(), | 
| + Heap::kOld); | 
| + return reinterpret_cast<RawPatchClass*>(raw); | 
| +} | 
| + | 
| + | 
| +void PatchClass::set_patched_class(const Class& value) const { | 
| + StorePointer(&raw_ptr()->patched_class_, value.raw()); | 
| +} | 
| + | 
| + | 
| +void PatchClass::set_script(const Script& value) const { | 
| + StorePointer(&raw_ptr()->script_, value.raw()); | 
| +} | 
| + | 
| + | 
| void Function::SetCode(const Code& value) const { | 
| StorePointer(&raw_ptr()->code_, value.raw()); | 
| ASSERT(Function::Handle(value.function()).IsNull() || | 
| @@ -3569,7 +3663,7 @@ | 
| } | 
| -void Function::set_owner(const Class& value) const { | 
| +void Function::set_owner(const Object& value) const { | 
| ASSERT(!value.IsNull()); | 
| StorePointer(&raw_ptr()->owner_, value.raw()); | 
| } | 
| @@ -3813,7 +3907,7 @@ | 
| const Function& parent = Function::Handle(function.parent_function()); | 
| intptr_t written = 0; | 
| if (parent.IsNull()) { | 
| - const Class& function_class = Class::Handle(function.owner()); | 
| + const Class& function_class = Class::Handle(function.Owner()); | 
| ASSERT(!function_class.IsNull()); | 
| const char* class_name = String::Handle(function_class.Name()).ToCString(); | 
| ASSERT(class_name != NULL); | 
| @@ -4053,7 +4147,7 @@ | 
| intptr_t token_pos) { | 
| ASSERT(name.IsOneByteString()); | 
| ASSERT(!parent.IsNull()); | 
| - const Class& parent_class = Class::Handle(parent.owner()); | 
| + const Class& parent_class = Class::Handle(parent.Owner()); | 
| ASSERT(!parent_class.IsNull()); | 
| const Function& result = Function::Handle( | 
| Function::New(name, | 
| @@ -4115,15 +4209,15 @@ | 
| // Lookup or create a new signature class for the closure function in the | 
| // library of the owner class. | 
| - const Class& owner_class = Class::Handle(owner()); | 
| - ASSERT(!owner_class.IsNull() && (owner() == closure_function.owner())); | 
| + const Class& owner_class = Class::Handle(Owner()); | 
| + ASSERT(!owner_class.IsNull() && (Owner() == closure_function.Owner())); | 
| const Library& library = Library::Handle(owner_class.library()); | 
| ASSERT(!library.IsNull()); | 
| const String& signature = String::Handle(closure_function.Signature()); | 
| Class& signature_class = Class::ZoneHandle( | 
| library.LookupLocalClass(signature)); | 
| if (signature_class.IsNull()) { | 
| - const Script& script = Script::Handle(owner_class.script()); | 
| + const Script& script = Script::Handle(this->script()); | 
| signature_class = Class::NewSignatureClass(signature, | 
| closure_function, | 
| script); | 
| @@ -4163,7 +4257,7 @@ | 
| String::Handle(Symbols::New(" extends ")); | 
| const String& kLAngleBracket = String::Handle(Symbols::New("<")); | 
| const String& kRAngleBracket = String::Handle(Symbols::New(">")); | 
| - const Class& function_class = Class::Handle(owner()); | 
| + const Class& function_class = Class::Handle(Owner()); | 
| ASSERT(!function_class.IsNull()); | 
| const TypeArguments& type_parameters = TypeArguments::Handle( | 
| function_class.type_parameters()); | 
| @@ -4254,6 +4348,26 @@ | 
| } | 
| +RawClass* Function::Owner() const { | 
| + const Object& obj = Object::Handle(raw_ptr()->owner_); | 
| 
hausner
2012/08/14 18:25:06
It would be nice if you could avoid this extra han
 
Ivan Posva
2012/08/15 06:50:39
I have seen 0% impact by this change on performanc
 | 
| + if (obj.IsClass()) { | 
| + return Class::Cast(obj).raw(); | 
| + } | 
| + ASSERT(obj.IsPatchClass()); | 
| + return PatchClass::Cast(obj).patched_class(); | 
| +} | 
| + | 
| + | 
| +RawScript* Function::script() const { | 
| + const Object& obj = Object::Handle(raw_ptr()->owner_); | 
| + if (obj.IsClass()) { | 
| + return Class::Cast(obj).script(); | 
| + } | 
| + ASSERT(obj.IsPatchClass()); | 
| + return PatchClass::Cast(obj).script(); | 
| +} | 
| + | 
| + | 
| bool Function::HasOptimizedCode() const { | 
| return HasCode() && Code::Handle(raw_ptr()->code_).is_optimized(); | 
| } | 
| @@ -4268,7 +4382,7 @@ | 
| RawString* Function::QualifiedUserVisibleName() const { | 
| String& tmp = String::Handle(); | 
| String& suffix = String::Handle(); | 
| - const Class& cls = Class::Handle(owner()); | 
| + const Class& cls = Class::Handle(Owner()); | 
| if (IsClosureFunction()) { | 
| if (IsLocalFunction()) { | 
| @@ -5499,8 +5613,6 @@ | 
| const GrowableObjectArray& scripts = | 
| GrowableObjectArray::Handle(GrowableObjectArray::New(8)); | 
| Object& entry = Object::Handle(); | 
| - Function& func = Function::Handle(); | 
| - Field& field = Field::Handle(); | 
| Class& cls = Class::Handle(); | 
| Script& owner_script = Script::Handle(); | 
| DictionaryIterator it(*this); | 
| @@ -5508,17 +5620,15 @@ | 
| while (it.HasNext()) { | 
| entry = it.GetNext(); | 
| if (entry.IsClass()) { | 
| - cls ^= entry.raw(); | 
| + owner_script = Class::Cast(entry).script(); | 
| } else if (entry.IsFunction()) { | 
| - func ^= entry.raw(); | 
| - cls = func.owner(); | 
| + owner_script = Function::Cast(entry).script(); | 
| } else if (entry.IsField()) { | 
| - field ^= entry.raw(); | 
| - cls = field.owner(); | 
| + cls = Field::Cast(entry).owner(); | 
| + owner_script = cls.script(); | 
| } else { | 
| continue; | 
| } | 
| - owner_script = cls.script(); | 
| if (owner_script.IsNull()) { | 
| continue; | 
| } | 
| @@ -5778,7 +5888,7 @@ | 
| lib ^= cls.library(); | 
| } else if (obj.IsFunction()) { | 
| func ^= obj.raw(); | 
| - cls ^= func.owner(); | 
| + cls ^= func.Owner(); | 
| lib ^= cls.library(); | 
| } else if (obj.IsField()) { | 
| field ^= obj.raw(); | 
| @@ -7642,7 +7752,7 @@ | 
| if (NumberOfChecks() == 0) return false; | 
| Class& cls = Class::Handle(); | 
| for (intptr_t i = 0; i < NumberOfChecks(); i++) { | 
| - cls = Function::Handle(GetTargetAt(i)).owner(); | 
| + cls = Function::Handle(GetTargetAt(i)).Owner(); | 
| if (cls.id() != owner_cid) { | 
| return false; | 
| } | 
| @@ -7655,7 +7765,7 @@ | 
| if (NumberOfChecks() == 0) return false; | 
| Class& cls = Class::Handle(); | 
| for (intptr_t i = 0; i < NumberOfChecks(); i++) { | 
| - cls = Function::Handle(GetTargetAt(i)).owner(); | 
| + cls = Function::Handle(GetTargetAt(i)).Owner(); | 
| const intptr_t cid = cls.id(); | 
| if ((cid != kSmiCid) && | 
| (cid != kMintCid) && | 
| @@ -10938,7 +11048,6 @@ | 
| const char* Stacktrace::ToCString() const { | 
| Function& function = Function::Handle(); | 
| Code& code = Code::Handle(); | 
| - Class& owner = Class::Handle(); | 
| Script& script = Script::Handle(); | 
| String& function_name = String::Handle(); | 
| String& url = String::Handle(); | 
| @@ -10953,8 +11062,7 @@ | 
| code = CodeAtFrame(i); | 
| uword pc = code.EntryPoint() + Smi::Value(PcOffsetAtFrame(i)); | 
| intptr_t token_pos = code.GetTokenIndexOfPC(pc); | 
| - owner = function.owner(); | 
| - script = owner.script(); | 
| + script = function.script(); | 
| function_name = function.QualifiedUserVisibleName(); | 
| url = script.url(); | 
| intptr_t line = -1; |