Index: vm/object.cc |
=================================================================== |
--- vm/object.cc (revision 591) |
+++ vm/object.cc (working copy) |
@@ -3414,22 +3414,46 @@ |
} |
-ClassDictionaryIterator::ClassDictionaryIterator(const Library& library) |
+DictionaryIterator::DictionaryIterator(const Library& library) |
: array_(Array::Handle(library.dictionary())), |
// Last element in array is a Smi. |
size_(Array::Handle(library.dictionary()).Length() - 1), |
next_ix_(0) { |
+ MoveToNextObject(); |
+} |
+ |
+ |
+RawObject* DictionaryIterator::GetNext() { |
+ ASSERT(HasNext()); |
+ int ix = next_ix_++; |
+ MoveToNextObject(); |
+ ASSERT(array_.At(ix) != Object::null()); |
+ return array_.At(ix); |
+} |
+ |
+ |
+void DictionaryIterator::MoveToNextObject() { |
+ Object& obj = Object::Handle(array_.At(next_ix_)); |
+ while (obj.IsNull() && HasNext()) { |
+ next_ix_++; |
+ obj = array_.At(next_ix_); |
+ } |
+} |
+ |
+ |
+ClassDictionaryIterator::ClassDictionaryIterator(const Library& library) |
+ : DictionaryIterator(library) { |
MoveToNextClass(); |
} |
-RawClass* ClassDictionaryIterator::GetNext() { |
+RawClass* ClassDictionaryIterator::GetNextClass() { |
ASSERT(HasNext()); |
int ix = next_ix_++; |
+ Object& obj = Object::Handle(array_.At(ix)); |
MoveToNextClass(); |
- ASSERT(array_.At(ix) != Object::null()); |
Class& cls = Class::Handle(); |
- cls ^= array_.At(ix); |
+ cls ^= obj.raw(); |
return cls.raw(); |
} |
@@ -3585,16 +3609,23 @@ |
} |
-RawObject* Library::LookupObject(const String& name) const { |
+RawObject* Library::LookupObjectFiltered(const String& name, |
+ const Library& filter_lib) const { |
+ // First check if name is found in the local scope of the library. |
Object& obj = Object::Handle(LookupLocalObject(name)); |
if (!obj.IsNull()) { |
return obj.raw(); |
} |
- Library& import = Library::Handle(); |
- Array& imports = Array::Handle(this->imports()); |
- for (intptr_t i = 0; i < num_imports(); i++) { |
- import ^= imports.At(i); |
- obj = import.LookupLocalObject(name); |
+ // Now check if name is found in the top level scope of any imported libs. |
+ const Array& imports = Array::Handle(this->imports()); |
+ Library& import_lib = Library::Handle(); |
+ for (intptr_t j = 0; j < this->num_imports(); j++) { |
+ import_lib ^= imports.At(j); |
+ // Skip over the library that we need to filter out. |
+ if (!filter_lib.IsNull() && import_lib.raw() == filter_lib.raw()) { |
+ continue; |
+ } |
+ obj = import_lib.LookupLocalObject(name); |
if (!obj.IsNull()) { |
return obj.raw(); |
} |
@@ -3603,6 +3634,100 @@ |
} |
+RawObject* Library::LookupObject(const String& name) const { |
+ return LookupObjectFiltered(name, Library::Handle()); |
+} |
+ |
+ |
+RawLibrary* Library::LookupObjectInImporter(const String& name) const { |
+ const Array& imported_into_libs = Array::Handle(this->imported_into()); |
+ Library& lib = Library::Handle(); |
+ Object& obj = Object::Handle(); |
+ for (intptr_t i = 0; i < this->num_imported_into(); i++) { |
+ lib ^= imported_into_libs.At(i); |
+ obj = lib.LookupObjectFiltered(name, *this); |
+ if (!obj.IsNull()) { |
+ // If the object found is a class, field or function extract the |
+ // library in which it is defined as it might be defined in one of |
+ // the imported libraries. |
+ Class& cls = Class::Handle(); |
+ Function& func = Function::Handle(); |
+ Field& field = Field::Handle(); |
+ if (obj.IsClass()) { |
+ cls ^= obj.raw(); |
+ lib ^= cls.library(); |
+ } else if (obj.IsFunction()) { |
+ func ^= obj.raw(); |
+ cls ^= func.owner(); |
+ lib ^= cls.library(); |
+ } else if (obj.IsField()) { |
+ field ^= obj.raw(); |
+ cls ^= field.owner(); |
+ lib ^= cls.library(); |
+ } |
+ return lib.raw(); |
+ } |
+ } |
+ return Library::null(); |
+} |
+ |
+ |
+RawString* Library::DuplicateDefineErrorString(const String& entry_name, |
+ const Library& conflict) const { |
+ String& errstr = String::Handle(); |
+ Array& array = Array::Handle(Array::New(7)); |
+ errstr = String::New("'"); |
+ array.SetAt(0, errstr); |
+ array.SetAt(1, entry_name); |
+ errstr = String::New("' is defined in '"); |
+ array.SetAt(2, errstr); |
+ errstr = url(); |
+ array.SetAt(3, errstr); |
+ errstr = String::New("' and '"); |
+ array.SetAt(4, errstr); |
+ errstr = conflict.url(); |
+ array.SetAt(5, errstr); |
+ errstr = String::New("'"); |
+ array.SetAt(6, errstr); |
+ errstr = String::ConcatAll(array); |
+ return errstr.raw(); |
+} |
+ |
+ |
+RawString* Library::FindDuplicateDefinition(Library* conflicting_lib) const { |
+ DictionaryIterator it(*this); |
+ Object& obj = Object::Handle(); |
+ Class& cls = Class::Handle(); |
+ Function& func = Function::Handle(); |
+ Field& field = Field::Handle(); |
+ String& entry_name = String::Handle(); |
+ while (it.HasNext()) { |
+ obj = it.GetNext(); |
+ ASSERT(!obj.IsNull()); |
+ if (obj.IsClass()) { |
+ cls ^= obj.raw(); |
+ entry_name = cls.Name(); |
+ } else if (obj.IsFunction()) { |
+ func ^= obj.raw(); |
+ entry_name = func.name(); |
+ } else if (obj.IsField()) { |
+ field ^= obj.raw(); |
+ entry_name = field.name(); |
+ } else { |
+ // We don't check for library prefixes defined in this library because |
+ // they are not visible in the importing scope and hence cannot |
+ // cause any duplicate definitions. |
+ continue; |
+ } |
+ *conflicting_lib = LookupObjectInImporter(entry_name); |
+ if (!conflicting_lib->IsNull()) { |
+ return entry_name.raw(); |
+ } |
+ } |
+ return String::null(); |
+} |
+ |
+ |
RawClass* Library::LookupClass(const String& name) const { |
Object& obj = Object::Handle(LookupObject(name)); |
if (!obj.IsNull() && obj.IsClass()) { |
@@ -3662,9 +3787,24 @@ |
intptr_t index = num_imports(); |
imports.SetAt(index, library); |
set_num_imports(index + 1); |
+ library.AddImportedInto(*this); |
} |
+void Library::AddImportedInto(const Library& library) const { |
+ Array& imported_into = Array::Handle(this->imported_into()); |
+ intptr_t capacity = imported_into.Length(); |
+ if (num_imported_into() == capacity) { |
+ capacity = capacity + kImportedIntoCapacityIncrement; |
+ imported_into = Array::Grow(imported_into, capacity); |
+ StorePointer(&raw_ptr()->imported_into_, imported_into.raw()); |
+ } |
+ intptr_t index = num_imported_into(); |
+ imported_into.SetAt(index, library); |
+ set_num_imported_into(index + 1); |
+} |
+ |
+ |
void Library::InitClassDictionary() const { |
// The last element of the dictionary specifies the number of in use slots. |
// TODO(iposva): Find reasonable initial size. |
@@ -3685,6 +3825,14 @@ |
} |
+void Library::InitImportedIntoList() const { |
+ const Array& imported_into = |
+ Array::Handle(Array::New(kInitialImportedIntoCapacity, Heap::kOld)); |
+ StorePointer(&raw_ptr()->imported_into_, imported_into.raw()); |
+ raw_ptr()->num_imported_into_ = 0; |
+} |
+ |
+ |
RawLibrary* Library::New() { |
const Class& library_class = Class::Handle(Object::library_class()); |
RawObject* raw = Object::Allocate(library_class, |
@@ -3710,6 +3858,7 @@ |
result.raw_ptr()->loaded_ = false; |
result.InitClassDictionary(); |
result.InitImportList(); |
+ result.InitImportedIntoList(); |
if (import_core_lib) { |
Library& core_lib = Library::Handle(Library::CoreLibrary()); |
ASSERT(!core_lib.IsNull()); |
@@ -3761,6 +3910,26 @@ |
} |
+RawString* Library::CheckForDuplicateDefinition() { |
+ Library& lib = Library::Handle(); |
+ Isolate* isolate = Isolate::Current(); |
+ ASSERT(isolate != NULL); |
+ ObjectStore* object_store = isolate->object_store(); |
+ ASSERT(object_store != NULL); |
+ lib ^= object_store->registered_libraries(); |
+ String& entry_name = String::Handle(); |
+ Library& conflicting_lib = Library::Handle(); |
+ while (!lib.IsNull()) { |
+ entry_name = lib.FindDuplicateDefinition(&conflicting_lib); |
+ if (!entry_name.IsNull()) { |
+ return lib.DuplicateDefineErrorString(entry_name, conflicting_lib); |
+ } |
+ lib ^= lib.next_registered(); |
+ } |
+ return String::null(); |
+} |
+ |
+ |
bool Library::IsKeyUsed(intptr_t key) { |
intptr_t lib_key; |
Library& lib = Library::Handle(); |
@@ -3854,7 +4023,7 @@ |
while (!lib.IsNull()) { |
ClassDictionaryIterator it(lib); |
while (it.HasNext()) { |
- cls ^= it.GetNext(); |
+ cls ^= it.GetNextClass(); |
if (!cls.is_interface()) { |
Compiler::CompileAllFunctions(cls); |
} |