| Index: runtime/vm/object.cc
|
| ===================================================================
|
| --- runtime/vm/object.cc (revision 24510)
|
| +++ runtime/vm/object.cc (working copy)
|
| @@ -1492,6 +1492,7 @@
|
| StorePointer(&raw_ptr()->canonical_types_, Object::empty_array().raw());
|
| StorePointer(&raw_ptr()->functions_, Object::empty_array().raw());
|
| StorePointer(&raw_ptr()->fields_, Object::empty_array().raw());
|
| + StorePointer(&raw_ptr()->no_such_method_cache_, Object::empty_array().raw());
|
| }
|
|
|
|
|
| @@ -1748,6 +1749,97 @@
|
| }
|
|
|
|
|
| +RawFunction* Class::GetNoSuchMethodDispatcher(const String& target_name,
|
| + const Array& args_desc) const {
|
| + enum {
|
| + kNameIndex = 0,
|
| + kArgsDescIndex,
|
| + kFunctionIndex,
|
| + kEntrySize
|
| + };
|
| +
|
| + Function& dispatcher = Function::Handle();
|
| + Array& cache = Array::Handle(no_such_method_cache());
|
| + ASSERT(!cache.IsNull());
|
| + String& name = String::Handle();
|
| + Array& desc = Array::Handle();
|
| + intptr_t i = 0;
|
| + for (; i < cache.Length(); i += kEntrySize) {
|
| + name ^= cache.At(i + kNameIndex);
|
| + if (name.IsNull()) break; // Reached last entry.
|
| + if (!name.Equals(target_name)) continue;
|
| + desc ^= cache.At(i + kArgsDescIndex);
|
| + if (desc.raw() == args_desc.raw()) {
|
| + // Found match.
|
| + dispatcher ^= cache.At(i + kFunctionIndex);
|
| + ASSERT(dispatcher.IsFunction());
|
| + break;
|
| + }
|
| + }
|
| +
|
| + if (dispatcher.IsNull()) {
|
| + if (i == cache.Length()) {
|
| + // Allocate new larger cache.
|
| + intptr_t new_len = cache.Length() == 0 ? kEntrySize : cache.Length() * 2;
|
| + cache ^= Array::Grow(cache, new_len);
|
| + set_no_such_method_cache(cache);
|
| + }
|
| + dispatcher ^= CreateNoSuchMethodDispatcher(target_name, args_desc);
|
| + cache.SetAt(i + kNameIndex, target_name);
|
| + cache.SetAt(i + kArgsDescIndex, args_desc);
|
| + cache.SetAt(i + kFunctionIndex, dispatcher);
|
| + }
|
| + return dispatcher.raw();
|
| +}
|
| +
|
| +
|
| +RawFunction* Class::CreateNoSuchMethodDispatcher(const String& target_name,
|
| + const Array& args_desc) const {
|
| + Function& invocation = Function::Handle(
|
| + Function::New(String::Handle(Symbols::New(target_name)),
|
| + RawFunction::kNoSuchMethodDispatcher,
|
| + false, // Not static.
|
| + false, // Not const.
|
| + false, // Not abstract.
|
| + false, // Not external.
|
| + *this,
|
| + 0)); // No token position.
|
| + ArgumentsDescriptor desc(args_desc);
|
| + const intptr_t num_parameters = desc.Count();
|
| + invocation.set_num_fixed_parameters(num_parameters);
|
| + invocation.SetNumOptionalParameters(0, true);
|
| + invocation.set_parameter_types(Array::Handle(Array::New(num_parameters,
|
| + Heap::kOld)));
|
| + invocation.set_parameter_names(Array::Handle(Array::New(num_parameters,
|
| + Heap::kOld)));
|
| + // Receiver.
|
| + invocation.SetParameterTypeAt(0, Type::Handle(Type::DynamicType()));
|
| + invocation.SetParameterNameAt(0, Symbols::This());
|
| + // Remaining parameters.
|
| + for (intptr_t i = 1; i < num_parameters; i++) {
|
| + invocation.SetParameterTypeAt(i, Type::Handle(Type::DynamicType()));
|
| + char name[64];
|
| + OS::SNPrint(name, 64, ":p%"Pd, i);
|
| + invocation.SetParameterNameAt(i, String::Handle(Symbols::New(name)));
|
| + }
|
| + invocation.set_result_type(Type::Handle(Type::DynamicType()));
|
| + invocation.set_is_visible(false); // Not visible in stack trace.
|
| + invocation.set_saved_args_desc(args_desc);
|
| +
|
| + return invocation.raw();
|
| +}
|
| +
|
| +
|
| +RawArray* Class::no_such_method_cache() const {
|
| + return raw_ptr()->no_such_method_cache_;
|
| +}
|
| +
|
| +
|
| +void Class::set_no_such_method_cache(const Array& cache) const {
|
| + StorePointer(&raw_ptr()->no_such_method_cache_, cache.raw());
|
| +}
|
| +
|
| +
|
| void Class::Finalize() const {
|
| ASSERT(!is_finalized());
|
| // Prefinalized classes have a VM internal representation and no Dart fields.
|
| @@ -3555,6 +3647,21 @@
|
| }
|
|
|
|
|
| +RawArray* Function::saved_args_desc() const {
|
| + ASSERT(kind() == RawFunction::kNoSuchMethodDispatcher);
|
| + const Object& obj = Object::Handle(raw_ptr()->data_);
|
| + ASSERT(obj.IsArray());
|
| + return Array::Cast(obj).raw();
|
| +}
|
| +
|
| +
|
| +void Function::set_saved_args_desc(const Array& value) const {
|
| + ASSERT(kind() == RawFunction::kNoSuchMethodDispatcher);
|
| + ASSERT(raw_ptr()->data_ == Object::null());
|
| + set_data(value);
|
| +}
|
| +
|
| +
|
| RawFunction* Function::parent_function() const {
|
| if (IsClosureFunction()) {
|
| const Object& obj = Object::Handle(raw_ptr()->data_);
|
|
|