| // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| #include "vm/object.h" |
| |
| #include "include/dart_api.h" |
| #include "platform/assert.h" |
| #include "vm/assembler.h" |
| #include "vm/cpu.h" |
| #include "vm/bigint_operations.h" |
| #include "vm/bootstrap.h" |
| #include "vm/class_finalizer.h" |
| #include "vm/code_generator.h" |
| #include "vm/code_observers.h" |
| #include "vm/code_patcher.h" |
| #include "vm/compiler.h" |
| #include "vm/compiler_stats.h" |
| #include "vm/dart.h" |
| #include "vm/dart_api_state.h" |
| #include "vm/dart_entry.h" |
| #include "vm/datastream.h" |
| #include "vm/debugger.h" |
| #include "vm/deopt_instructions.h" |
| #include "vm/double_conversion.h" |
| #include "vm/exceptions.h" |
| #include "vm/growable_array.h" |
| #include "vm/heap.h" |
| #include "vm/intermediate_language.h" |
| #include "vm/intrinsifier.h" |
| #include "vm/object_store.h" |
| #include "vm/parser.h" |
| #include "vm/runtime_entry.h" |
| #include "vm/scopes.h" |
| #include "vm/stack_frame.h" |
| #include "vm/symbols.h" |
| #include "vm/timer.h" |
| #include "vm/unicode.h" |
| |
| namespace dart { |
| |
| DEFINE_FLAG(bool, show_internal_names, false, |
| "Show names of internal classes (e.g. \"OneByteString\") in error messages " |
| "instead of showing the corresponding interface names (e.g. \"String\")"); |
| DEFINE_FLAG(bool, trace_disabling_optimized_code, false, |
| "Trace disabling optimized code."); |
| DEFINE_FLAG(int, huge_method_cutoff_in_tokens, 20000, |
| "Huge method cutoff in tokens: Disables optimizations for huge methods."); |
| DEFINE_FLAG(int, huge_method_cutoff_in_code_size, 200000, |
| "Huge method cutoff in unoptimized code size (in bytes)."); |
| DECLARE_FLAG(bool, trace_compiler); |
| DECLARE_FLAG(bool, eliminate_type_checks); |
| DECLARE_FLAG(bool, enable_type_checks); |
| |
| static const char* kGetterPrefix = "get:"; |
| static const intptr_t kGetterPrefixLength = strlen(kGetterPrefix); |
| static const char* kSetterPrefix = "set:"; |
| static const intptr_t kSetterPrefixLength = strlen(kSetterPrefix); |
| |
| cpp_vtable Object::handle_vtable_ = 0; |
| cpp_vtable Object::builtin_vtables_[kNumPredefinedCids] = { 0 }; |
| cpp_vtable Smi::handle_vtable_ = 0; |
| |
| // These are initialized to a value that will force a illegal memory access if |
| // they are being used. |
| #if defined(RAW_NULL) |
| #error RAW_NULL should not be defined. |
| #endif |
| #define RAW_NULL kHeapObjectTag |
| Array* Object::empty_array_ = NULL; |
| Instance* Object::sentinel_ = NULL; |
| Instance* Object::transition_sentinel_ = NULL; |
| Bool* Object::bool_true_ = NULL; |
| Bool* Object::bool_false_ = NULL; |
| LanguageError* Object::snapshot_writer_error_ = NULL; |
| |
| RawObject* Object::null_ = reinterpret_cast<RawObject*>(RAW_NULL); |
| RawClass* Object::class_class_ = reinterpret_cast<RawClass*>(RAW_NULL); |
| RawClass* Object::null_class_ = reinterpret_cast<RawClass*>(RAW_NULL); |
| RawClass* Object::dynamic_class_ = reinterpret_cast<RawClass*>(RAW_NULL); |
| RawClass* Object::void_class_ = reinterpret_cast<RawClass*>(RAW_NULL); |
| RawClass* Object::unresolved_class_class_ = |
| reinterpret_cast<RawClass*>(RAW_NULL); |
| 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::closure_data_class_ = reinterpret_cast<RawClass*>(RAW_NULL); |
| RawClass* Object::redirection_data_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); |
| RawClass* Object::token_stream_class_ = reinterpret_cast<RawClass*>(RAW_NULL); |
| RawClass* Object::script_class_ = reinterpret_cast<RawClass*>(RAW_NULL); |
| RawClass* Object::library_class_ = reinterpret_cast<RawClass*>(RAW_NULL); |
| RawClass* Object::library_prefix_class_ = reinterpret_cast<RawClass*>(RAW_NULL); |
| RawClass* Object::namespace_class_ = reinterpret_cast<RawClass*>(RAW_NULL); |
| RawClass* Object::code_class_ = reinterpret_cast<RawClass*>(RAW_NULL); |
| RawClass* Object::instructions_class_ = reinterpret_cast<RawClass*>(RAW_NULL); |
| RawClass* Object::pc_descriptors_class_ = reinterpret_cast<RawClass*>(RAW_NULL); |
| RawClass* Object::stackmap_class_ = reinterpret_cast<RawClass*>(RAW_NULL); |
| RawClass* Object::var_descriptors_class_ = |
| reinterpret_cast<RawClass*>(RAW_NULL); |
| RawClass* Object::exception_handlers_class_ = |
| reinterpret_cast<RawClass*>(RAW_NULL); |
| RawClass* Object::deopt_info_class_ = reinterpret_cast<RawClass*>(RAW_NULL); |
| RawClass* Object::context_class_ = reinterpret_cast<RawClass*>(RAW_NULL); |
| RawClass* Object::context_scope_class_ = reinterpret_cast<RawClass*>(RAW_NULL); |
| RawClass* Object::icdata_class_ = reinterpret_cast<RawClass*>(RAW_NULL); |
| RawClass* Object::megamorphic_cache_class_ = |
| reinterpret_cast<RawClass*>(RAW_NULL); |
| RawClass* Object::subtypetestcache_class_ = |
| reinterpret_cast<RawClass*>(RAW_NULL); |
| RawClass* Object::api_error_class_ = reinterpret_cast<RawClass*>(RAW_NULL); |
| RawClass* Object::language_error_class_ = reinterpret_cast<RawClass*>(RAW_NULL); |
| RawClass* Object::unhandled_exception_class_ = |
| reinterpret_cast<RawClass*>(RAW_NULL); |
| RawClass* Object::unwind_error_class_ = reinterpret_cast<RawClass*>(RAW_NULL); |
| #undef RAW_NULL |
| |
| |
| const double MegamorphicCache::kLoadFactor = 0.75; |
| |
| |
| // The following functions are marked as invisible, meaning they will be hidden |
| // in the stack trace. |
| // (Library, class name, method name) |
| #define INVISIBLE_LIST(V) \ |
| V(CoreLibrary, Object, _noSuchMethod) \ |
| V(CoreLibrary, Object, _as) \ |
| V(CoreLibrary, Object, _instanceOf) \ |
| V(CoreLibrary, _ObjectArray, _ObjectArray.) \ |
| V(CoreLibrary, AssertionErrorImplementation, _throwNew) \ |
| V(CoreLibrary, TypeErrorImplementation, _throwNew) \ |
| V(CoreLibrary, FallThroughErrorImplementation, _throwNew) \ |
| V(CoreLibrary, AbstractClassInstantiationErrorImplementation, _throwNew) \ |
| V(CoreLibrary, NoSuchMethodError, _throwNew) \ |
| V(CoreLibrary, int, _throwFormatException) \ |
| V(CoreLibrary, int, _parse) \ |
| V(CoreLibrary, StackTrace, _setupFullStackTrace) \ |
| |
| |
| static void MarkFunctionAsInvisible(const Library& lib, |
| const char* class_name, |
| const char* function_name) { |
| ASSERT(!lib.IsNull()); |
| const Class& cls = Class::Handle( |
| lib.LookupClassAllowPrivate(String::Handle(String::New(class_name)))); |
| ASSERT(!cls.IsNull()); |
| const Function& function = |
| Function::Handle( |
| cls.LookupFunctionAllowPrivate( |
| String::Handle(String::New(function_name)))); |
| ASSERT(!function.IsNull()); |
| function.set_is_visible(false); |
| } |
| |
| |
| static void MarkInvisibleFunctions() { |
| #define MARK_FUNCTION(lib, class_name, function_name) \ |
| MarkFunctionAsInvisible(Library::Handle(Library::lib()), \ |
| #class_name, #function_name); \ |
| |
| INVISIBLE_LIST(MARK_FUNCTION) |
| #undef MARK_FUNCTION |
| } |
| |
| // Takes a vm internal name and makes it suitable for external user. |
| // |
| // Examples: |
| // |
| // Internal getter and setter prefixes are changed: |
| // |
| // get:foo -> foo |
| // set:foo -> foo= |
| // |
| // Private name mangling is removed, possibly twice: |
| // |
| // _ReceivePortImpl@6be832b -> _ReceivePortImpl |
| // _ReceivePortImpl@6be832b._internal@6be832b -> +ReceivePortImpl._internal |
| // |
| // The trailing . on the default constructor name is dropped: |
| // |
| // List. -> List |
| // |
| // And so forth: |
| // |
| // get:foo@6be832b -> foo |
| // _MyClass@6b3832b. -> _MyClass |
| // _MyClass@6b3832b.named -> _MyClass.named |
| // |
| static RawString* IdentifierPrettyName(const String& name) { |
| intptr_t len = name.Length(); |
| intptr_t start = 0; |
| intptr_t at_pos = len; // Position of '@' in the name. |
| intptr_t dot_pos = len; // Position of '.' in the name. |
| bool is_setter = false; |
| |
| if (name.Equals(Symbols::TopLevel())) { |
| // Name of invisible top-level class. |
| return Symbols::Empty().raw(); |
| } |
| for (int i = start; i < name.Length(); i++) { |
| if (name.CharAt(i) == ':') { |
| ASSERT(start == 0); |
| if (name.CharAt(0) == 's') { |
| is_setter = true; |
| } |
| start = i + 1; |
| } else if (name.CharAt(i) == '@') { |
| ASSERT(at_pos == len); |
| at_pos = i; |
| } else if (name.CharAt(i) == '.') { |
| dot_pos = i; |
| break; |
| } |
| } |
| intptr_t limit = (at_pos < dot_pos ? at_pos : dot_pos); |
| if (start == 0 && limit == len) { |
| // This name is fine as it is. |
| return name.raw(); |
| } |
| |
| const String& result = |
| String::Handle(String::SubString(name, start, (limit - start))); |
| |
| // Look for a second '@' now to correctly handle names like |
| // "_ReceivePortImpl@6be832b._internal@6be832b". |
| at_pos = len; |
| for (int i = dot_pos; i < name.Length(); i++) { |
| if (name.CharAt(i) == '@') { |
| ASSERT(at_pos == len); |
| at_pos = i; |
| } |
| } |
| |
| intptr_t suffix_len = at_pos - dot_pos; |
| if (suffix_len > 1) { |
| // This is a named constructor. Add the name back to the string. |
| const String& suffix = |
| String::Handle(String::SubString(name, dot_pos, suffix_len)); |
| return String::Concat(result, suffix); |
| } |
| |
| if (is_setter) { |
| // Setters need to end with '='. |
| return String::Concat(result, Symbols::Equals()); |
| } |
| |
| return result.raw(); |
| } |
| |
| |
| template<typename type> |
| static bool IsSpecialCharacter(type value) { |
| return ((value == '"') || |
| (value == '\n') || |
| (value == '\f') || |
| (value == '\b') || |
| (value == '\t') || |
| (value == '\v') || |
| (value == '\r') || |
| (value == '\\') || |
| (value == '$')); |
| } |
| |
| |
| template<typename type> |
| static type SpecialCharacter(type value) { |
| if (value == '"') { |
| return '"'; |
| } else if (value == '\n') { |
| return 'n'; |
| } else if (value == '\f') { |
| return 'f'; |
| } else if (value == '\b') { |
| return 'b'; |
| } else if (value == '\t') { |
| return 't'; |
| } else if (value == '\v') { |
| return 'v'; |
| } else if (value == '\r') { |
| return 'r'; |
| } else if (value == '\\') { |
| return '\\'; |
| } else if (value == '$') { |
| return '$'; |
| } |
| UNREACHABLE(); |
| return '\0'; |
| } |
| |
| |
| static void DeleteWeakPersistentHandle(Dart_Handle handle) { |
| ApiState* state = Isolate::Current()->api_state(); |
| ASSERT(state != NULL); |
| FinalizablePersistentHandle* weak_ref = |
| reinterpret_cast<FinalizablePersistentHandle*>(handle); |
| ASSERT(state->IsValidWeakPersistentHandle(handle)); |
| state->weak_persistent_handles().FreeHandle(weak_ref); |
| } |
| |
| |
| void Object::InitOnce() { |
| // TODO(iposva): NoGCScope needs to be added here. |
| ASSERT(class_class() == null_); |
| // Initialize the static vtable values. |
| { |
| Object fake_object; |
| Smi fake_smi; |
| Object::handle_vtable_ = fake_object.vtable(); |
| Smi::handle_vtable_ = fake_smi.vtable(); |
| } |
| |
| Isolate* isolate = Isolate::Current(); |
| Heap* heap = isolate->heap(); |
| |
| // Allocate the read only object handles here. |
| empty_array_ = Array::ReadOnlyHandle(isolate); |
| sentinel_ = Instance::ReadOnlyHandle(isolate); |
| transition_sentinel_ = Instance::ReadOnlyHandle(isolate); |
| bool_true_ = Bool::ReadOnlyHandle(isolate); |
| bool_false_ = Bool::ReadOnlyHandle(isolate); |
| snapshot_writer_error_ = LanguageError::ReadOnlyHandle(isolate); |
| |
| // Allocate and initialize the null instance. |
| // 'null_' must be the first object allocated as it is used in allocation to |
| // clear the object. |
| { |
| uword address = heap->Allocate(Instance::InstanceSize(), Heap::kOld); |
| null_ = reinterpret_cast<RawInstance*>(address + kHeapObjectTag); |
| // The call below is using 'null_' to initialize itself. |
| InitializeObject(address, kNullCid, Instance::InstanceSize()); |
| } |
| |
| // Initialize the empty array handle to null_ in order to be able to check |
| // if the empty array was allocated (RAW_NULL is not available). |
| *empty_array_ = Array::null(); |
| |
| Class& cls = Class::Handle(); |
| |
| // Allocate and initialize the class class. |
| { |
| intptr_t size = Class::InstanceSize(); |
| uword address = heap->Allocate(size, Heap::kOld); |
| class_class_ = reinterpret_cast<RawClass*>(address + kHeapObjectTag); |
| InitializeObject(address, Class::kClassId, size); |
| |
| Class fake; |
| // Initialization from Class::New<Class>. |
| // Directly set raw_ to break a circular dependency: SetRaw will attempt |
| // to lookup class class in the class table where it is not registered yet. |
| cls.raw_ = class_class_; |
| cls.set_handle_vtable(fake.vtable()); |
| cls.set_instance_size(Class::InstanceSize()); |
| cls.set_next_field_offset(Class::InstanceSize()); |
| cls.set_id(Class::kClassId); |
| cls.raw_ptr()->state_bits_ = 0; |
| cls.set_is_finalized(); |
| cls.raw_ptr()->type_arguments_field_offset_in_words_ = |
| Class::kNoTypeArguments; |
| cls.raw_ptr()->num_native_fields_ = 0; |
| cls.InitEmptyFields(); |
| isolate->class_table()->Register(cls); |
| } |
| |
| // Allocate and initialize the null class. |
| cls = Class::New<Instance>(kNullCid); |
| cls.set_is_finalized(); |
| null_class_ = cls.raw(); |
| |
| // Allocate and initialize the free list element class. |
| cls = Class::New<FreeListElement::FakeInstance>(kFreeListElement); |
| cls.set_is_finalized(); |
| |
| // Allocate and initialize the sentinel values of Null class. |
| { |
| *sentinel_ ^= |
| Object::Allocate(kNullCid, Instance::InstanceSize(), Heap::kOld); |
| |
| *transition_sentinel_ ^= |
| Object::Allocate(kNullCid, Instance::InstanceSize(), Heap::kOld); |
| } |
| |
| cls = Class::New<Instance>(kDynamicCid); |
| cls.set_is_finalized(); |
| cls.set_is_abstract(); |
| dynamic_class_ = cls.raw(); |
| |
| // Allocate the remaining VM internal classes. |
| cls = Class::New<UnresolvedClass>(); |
| unresolved_class_class_ = cls.raw(); |
| |
| cls = Class::New<Instance>(kVoidCid); |
| cls.set_is_finalized(); |
| void_class_ = cls.raw(); |
| |
| cls = Class::New<TypeArguments>(); |
| type_arguments_class_ = cls.raw(); |
| |
| 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(); |
| |
| cls = Class::New<ClosureData>(); |
| closure_data_class_ = cls.raw(); |
| |
| cls = Class::New<RedirectionData>(); |
| redirection_data_class_ = cls.raw(); |
| |
| cls = Class::New<Field>(); |
| field_class_ = cls.raw(); |
| |
| cls = Class::New<LiteralToken>(); |
| literal_token_class_ = cls.raw(); |
| |
| cls = Class::New<TokenStream>(); |
| token_stream_class_ = cls.raw(); |
| |
| cls = Class::New<Script>(); |
| script_class_ = cls.raw(); |
| |
| cls = Class::New<Library>(); |
| library_class_ = cls.raw(); |
| |
| cls = Class::New<LibraryPrefix>(); |
| library_prefix_class_ = cls.raw(); |
| |
| cls = Class::New<Namespace>(); |
| namespace_class_ = cls.raw(); |
| |
| cls = Class::New<Code>(); |
| code_class_ = cls.raw(); |
| |
| cls = Class::New<Instructions>(); |
| instructions_class_ = cls.raw(); |
| |
| cls = Class::New<PcDescriptors>(); |
| pc_descriptors_class_ = cls.raw(); |
| |
| cls = Class::New<Stackmap>(); |
| stackmap_class_ = cls.raw(); |
| |
| cls = Class::New<LocalVarDescriptors>(); |
| var_descriptors_class_ = cls.raw(); |
| |
| cls = Class::New<ExceptionHandlers>(); |
| exception_handlers_class_ = cls.raw(); |
| |
| cls = Class::New<DeoptInfo>(); |
| deopt_info_class_ = cls.raw(); |
| |
| cls = Class::New<Context>(); |
| context_class_ = cls.raw(); |
| |
| cls = Class::New<ContextScope>(); |
| context_scope_class_ = cls.raw(); |
| |
| cls = Class::New<ICData>(); |
| icdata_class_ = cls.raw(); |
| |
| cls = Class::New<MegamorphicCache>(); |
| megamorphic_cache_class_ = cls.raw(); |
| |
| cls = Class::New<SubtypeTestCache>(); |
| subtypetestcache_class_ = cls.raw(); |
| |
| cls = Class::New<ApiError>(); |
| api_error_class_ = cls.raw(); |
| |
| cls = Class::New<LanguageError>(); |
| language_error_class_ = cls.raw(); |
| |
| cls = Class::New<UnhandledException>(); |
| unhandled_exception_class_ = cls.raw(); |
| |
| cls = Class::New<UnwindError>(); |
| unwind_error_class_ = cls.raw(); |
| |
| ASSERT(class_class() != null_); |
| |
| // Pre-allocate classes in the vm isolate so that we can for example create a |
| // symbol table and populate it with some frequently used strings as symbols. |
| cls = Class::New<Array>(); |
| isolate->object_store()->set_array_class(cls); |
| cls.set_type_arguments_field_offset(Array::type_arguments_offset()); |
| cls = Class::New<ImmutableArray>(); |
| isolate->object_store()->set_immutable_array_class(cls); |
| cls.set_type_arguments_field_offset(Array::type_arguments_offset()); |
| cls = Class::NewStringClass(kOneByteStringCid); |
| isolate->object_store()->set_one_byte_string_class(cls); |
| cls = Class::NewStringClass(kTwoByteStringCid); |
| isolate->object_store()->set_two_byte_string_class(cls); |
| |
| // Allocate and initialize the empty_array instance. |
| { |
| uword address = heap->Allocate(Array::InstanceSize(0), Heap::kOld); |
| InitializeObject(address, kArrayCid, Array::InstanceSize(0)); |
| Array::initializeHandle( |
| empty_array_, |
| reinterpret_cast<RawArray*>(address + kHeapObjectTag)); |
| empty_array_->raw()->ptr()->length_ = Smi::New(0); |
| } |
| |
| // Allocate and initialize singleton true and false boolean objects. |
| cls = Class::New<Bool>(); |
| isolate->object_store()->set_bool_class(cls); |
| *bool_true_ = Bool::New(true); |
| *bool_false_ = Bool::New(false); |
| |
| *snapshot_writer_error_ = |
| LanguageError::New(String::Handle(String::New("SnapshotWriter Error"))); |
| |
| ASSERT(!empty_array_->IsSmi()); |
| ASSERT(empty_array_->IsArray()); |
| ASSERT(!sentinel_->IsSmi()); |
| ASSERT(sentinel_->IsInstance()); |
| ASSERT(!transition_sentinel_->IsSmi()); |
| ASSERT(transition_sentinel_->IsInstance()); |
| ASSERT(!bool_true_->IsSmi()); |
| ASSERT(bool_true_->IsBool()); |
| ASSERT(!bool_false_->IsSmi()); |
| ASSERT(bool_false_->IsBool()); |
| ASSERT(!snapshot_writer_error_->IsSmi()); |
| ASSERT(snapshot_writer_error_->IsLanguageError()); |
| } |
| |
| |
| #define SET_CLASS_NAME(class_name, name) \ |
| cls = class_name##_class(); \ |
| cls.set_name(Symbols::name()); \ |
| |
| void Object::RegisterSingletonClassNames() { |
| Class& cls = Class::Handle(); |
| |
| // Set up names for all VM singleton classes. |
| SET_CLASS_NAME(class, Class); |
| SET_CLASS_NAME(null, Null); |
| SET_CLASS_NAME(dynamic, Dynamic); |
| SET_CLASS_NAME(void, Void); |
| SET_CLASS_NAME(unresolved_class, UnresolvedClass); |
| SET_CLASS_NAME(type_arguments, TypeArguments); |
| SET_CLASS_NAME(instantiated_type_arguments, InstantiatedTypeArguments); |
| SET_CLASS_NAME(patch_class, PatchClass); |
| SET_CLASS_NAME(function, Function); |
| SET_CLASS_NAME(closure_data, ClosureData); |
| SET_CLASS_NAME(redirection_data, RedirectionData); |
| SET_CLASS_NAME(field, Field); |
| SET_CLASS_NAME(literal_token, LiteralToken); |
| SET_CLASS_NAME(token_stream, TokenStream); |
| SET_CLASS_NAME(script, Script); |
| SET_CLASS_NAME(library, LibraryClass); |
| SET_CLASS_NAME(library_prefix, LibraryPrefix); |
| SET_CLASS_NAME(namespace, Namespace); |
| SET_CLASS_NAME(code, Code); |
| SET_CLASS_NAME(instructions, Instructions); |
| SET_CLASS_NAME(pc_descriptors, PcDescriptors); |
| SET_CLASS_NAME(stackmap, Stackmap); |
| SET_CLASS_NAME(var_descriptors, LocalVarDescriptors); |
| SET_CLASS_NAME(exception_handlers, ExceptionHandlers); |
| SET_CLASS_NAME(deopt_info, DeoptInfo); |
| SET_CLASS_NAME(context, Context); |
| SET_CLASS_NAME(context_scope, ContextScope); |
| SET_CLASS_NAME(icdata, ICData); |
| SET_CLASS_NAME(megamorphic_cache, MegamorphicCache); |
| SET_CLASS_NAME(subtypetestcache, SubtypeTestCache); |
| SET_CLASS_NAME(api_error, ApiError); |
| SET_CLASS_NAME(language_error, LanguageError); |
| SET_CLASS_NAME(unhandled_exception, UnhandledException); |
| SET_CLASS_NAME(unwind_error, UnwindError); |
| |
| // Set up names for object array and one byte string class which are |
| // pre-allocated in the vm isolate also. |
| cls = Dart::vm_isolate()->object_store()->array_class(); |
| cls.set_name(Symbols::ObjectArray()); |
| cls = Dart::vm_isolate()->object_store()->one_byte_string_class(); |
| cls.set_name(Symbols::OneByteString()); |
| } |
| |
| |
| void Object::CreateInternalMetaData() { |
| // Initialize meta data for VM internal classes. |
| Class& cls = Class::Handle(); |
| Array& fields = Array::Handle(); |
| Field& fld = Field::Handle(); |
| String& name = String::Handle(); |
| |
| // TODO(iposva): Add more of the VM classes here. |
| cls = context_class_; |
| fields = Array::New(1); |
| name = Symbols::New("@parent_"); |
| fld = Field::New(name, false, false, false, cls, 0); |
| fields.SetAt(0, fld); |
| cls.SetFields(fields); |
| } |
| |
| |
| // Make unused space in an object whose type has been transformed safe |
| // for traversing during GC. |
| // The unused part of the transformed object is marked as an TypedDataInt8Array |
| // object. |
| void Object::MakeUnusedSpaceTraversable(const Object& obj, |
| intptr_t original_size, |
| intptr_t used_size) { |
| ASSERT(Isolate::Current()->no_gc_scope_depth() > 0); |
| ASSERT(!obj.IsNull()); |
| ASSERT(original_size >= used_size); |
| if (original_size > used_size) { |
| intptr_t leftover_size = original_size - used_size; |
| |
| uword addr = RawObject::ToAddr(obj.raw()) + used_size; |
| if (leftover_size >= TypedData::InstanceSize(0)) { |
| // Update the leftover space as an TypedDataInt8Array object. |
| RawTypedData* raw = |
| reinterpret_cast<RawTypedData*>(RawObject::FromAddr(addr)); |
| uword tags = 0; |
| tags = RawObject::SizeTag::update(leftover_size, tags); |
| tags = RawObject::ClassIdTag::update(kTypedDataInt8ArrayCid, tags); |
| raw->ptr()->tags_ = tags; |
| intptr_t leftover_len = (leftover_size - TypedData::InstanceSize(0)); |
| ASSERT(TypedData::InstanceSize(leftover_len) == leftover_size); |
| raw->ptr()->length_ = Smi::New(leftover_len); |
| } else { |
| // Update the leftover space as a basic object. |
| ASSERT(leftover_size == Object::InstanceSize()); |
| RawObject* raw = reinterpret_cast<RawObject*>(RawObject::FromAddr(addr)); |
| uword tags = 0; |
| tags = RawObject::SizeTag::update(leftover_size, tags); |
| tags = RawObject::ClassIdTag::update(kInstanceCid, tags); |
| raw->ptr()->tags_ = tags; |
| } |
| } |
| } |
| |
| |
| void Object::VerifyBuiltinVtables() { |
| #if defined(DEBUG) |
| Isolate* isolate = Isolate::Current(); |
| ASSERT(isolate != NULL); |
| Class& cls = Class::Handle(isolate, Class::null()); |
| for (intptr_t cid = (kIllegalCid + 1); cid < kNumPredefinedCids; cid++) { |
| if (isolate->class_table()->HasValidClassAt(cid)) { |
| cls ^= isolate->class_table()->At(cid); |
| ASSERT(builtin_vtables_[cid] == cls.raw_ptr()->handle_vtable_); |
| } |
| } |
| #endif |
| } |
| |
| |
| void Object::RegisterClass(const Class& cls, |
| const String& name, |
| const Library& lib) { |
| ASSERT(name.Length() > 0); |
| ASSERT(name.CharAt(0) != '_'); |
| cls.set_name(name); |
| lib.AddClass(cls); |
| } |
| |
| |
| void Object::RegisterPrivateClass(const Class& cls, |
| const String& public_class_name, |
| const Library& lib) { |
| ASSERT(public_class_name.Length() > 0); |
| ASSERT(public_class_name.CharAt(0) == '_'); |
| String& str = String::Handle(); |
| str = lib.PrivateName(public_class_name); |
| cls.set_name(str); |
| lib.AddClass(cls); |
| } |
| |
| |
| #define LOAD_LIBRARY(name, raw_name) \ |
| url = Symbols::Dart##name().raw(); \ |
| lib = Library::LookupLibrary(url); \ |
| if (lib.IsNull()) { \ |
| lib = Library::NewLibraryHelper(url, true); \ |
| lib.Register(); \ |
| } \ |
| isolate->object_store()->set_##raw_name##_library(lib); \ |
| |
| #define INIT_LIBRARY(name, raw_name, has_patch) \ |
| LOAD_LIBRARY(name, raw_name) \ |
| script = Bootstrap::Load##name##Script(false); \ |
| error = Bootstrap::Compile(lib, script); \ |
| if (!error.IsNull()) { \ |
| return error.raw(); \ |
| } \ |
| if (has_patch) { \ |
| script = Bootstrap::Load##name##Script(true); \ |
| error = lib.Patch(script); \ |
| if (!error.IsNull()) { \ |
| return error.raw(); \ |
| } \ |
| } \ |
| |
| |
| RawError* Object::Init(Isolate* isolate) { |
| TIMERSCOPE(time_bootstrap); |
| ObjectStore* object_store = isolate->object_store(); |
| |
| Class& cls = Class::Handle(); |
| Type& type = Type::Handle(); |
| Array& array = Array::Handle(); |
| String& url = String::Handle(); |
| Library& lib = Library::Handle(); |
| Script& script = Script::Handle(); |
| Error& error = Error::Handle(); |
| |
| // All RawArray fields will be initialized to an empty array, therefore |
| // initialize array class first. |
| cls = Class::New<Array>(); |
| object_store->set_array_class(cls); |
| |
| // Array and ImmutableArray are the only VM classes that are parameterized. |
| // Since they are pre-finalized, CalculateFieldOffsets() is not called, so we |
| // need to set the offset of their type_arguments_ field, which is explicitly |
| // declared in RawArray. |
| cls.set_type_arguments_field_offset(Array::type_arguments_offset()); |
| |
| // Set up the growable object array class (Has to be done after the array |
| // class is setup as one of its field is an array object). |
| cls = Class::New<GrowableObjectArray>(); |
| object_store->set_growable_object_array_class(cls); |
| cls.set_type_arguments_field_offset( |
| GrowableObjectArray::type_arguments_offset()); |
| |
| // canonical_type_arguments_ are Smi terminated. |
| // Last element contains the count of used slots. |
| const intptr_t kInitialCanonicalTypeArgumentsSize = 4; |
| array = Array::New(kInitialCanonicalTypeArgumentsSize + 1); |
| array.SetAt(kInitialCanonicalTypeArgumentsSize, Smi::Handle(Smi::New(0))); |
| object_store->set_canonical_type_arguments(array); |
| |
| // Setup type class early in the process. |
| cls = Class::New<Type>(); |
| object_store->set_type_class(cls); |
| |
| cls = Class::New<TypeParameter>(); |
| object_store->set_type_parameter_class(cls); |
| |
| cls = Class::New<BoundedType>(); |
| object_store->set_bounded_type_class(cls); |
| |
| cls = Class::New<MixinAppType>(); |
| object_store->set_mixin_app_type_class(cls); |
| |
| // Pre-allocate the OneByteString class needed by the symbol table. |
| cls = Class::NewStringClass(kOneByteStringCid); |
| object_store->set_one_byte_string_class(cls); |
| |
| // Pre-allocate the TwoByteString class needed by the symbol table. |
| cls = Class::NewStringClass(kTwoByteStringCid); |
| object_store->set_two_byte_string_class(cls); |
| |
| // Setup the symbol table for the symbols created in the isolate. |
| Symbols::SetupSymbolTable(isolate); |
| |
| // Set up the libraries array before initializing the core library. |
| const GrowableObjectArray& libraries = |
| GrowableObjectArray::Handle(GrowableObjectArray::New(Heap::kOld)); |
| object_store->set_libraries(libraries); |
| |
| // Pre-register the core library. |
| Library::InitCoreLibrary(isolate); |
| |
| // Basic infrastructure has been setup, initialize the class dictionary. |
| Library& core_lib = Library::Handle(Library::CoreLibrary()); |
| ASSERT(!core_lib.IsNull()); |
| |
| const GrowableObjectArray& pending_classes = |
| GrowableObjectArray::Handle(GrowableObjectArray::New(Heap::kOld)); |
| object_store->set_pending_classes(pending_classes); |
| |
| Context& context = Context::Handle(Context::New(0, Heap::kOld)); |
| object_store->set_empty_context(context); |
| |
| // Now that the symbol table is initialized and that the core dictionary as |
| // well as the core implementation dictionary have been setup, preallocate |
| // remaining classes and register them by name in the dictionaries. |
| String& name = String::Handle(); |
| cls = Class::New<Bool>(); |
| object_store->set_bool_class(cls); |
| RegisterClass(cls, Symbols::Bool(), core_lib); |
| pending_classes.Add(cls, Heap::kOld); |
| |
| cls = object_store->array_class(); // Was allocated above. |
| RegisterPrivateClass(cls, Symbols::ObjectArray(), core_lib); |
| pending_classes.Add(cls, Heap::kOld); |
| // We cannot use NewNonParameterizedType(cls), because Array is parameterized. |
| type ^= Type::New(Object::Handle(cls.raw()), |
| TypeArguments::Handle(), |
| Scanner::kDummyTokenIndex); |
| type.SetIsFinalized(); |
| type ^= type.Canonicalize(); |
| object_store->set_array_type(type); |
| |
| cls = object_store->growable_object_array_class(); // Was allocated above. |
| RegisterPrivateClass(cls, Symbols::GrowableObjectArray(), core_lib); |
| pending_classes.Add(cls, Heap::kOld); |
| |
| cls = Class::New<ImmutableArray>(); |
| object_store->set_immutable_array_class(cls); |
| cls.set_type_arguments_field_offset(Array::type_arguments_offset()); |
| ASSERT(object_store->immutable_array_class() != object_store->array_class()); |
| RegisterPrivateClass(cls, Symbols::ImmutableArray(), core_lib); |
| pending_classes.Add(cls, Heap::kOld); |
| |
| cls = object_store->one_byte_string_class(); // Was allocated above. |
| RegisterPrivateClass(cls, Symbols::OneByteString(), core_lib); |
| pending_classes.Add(cls, Heap::kOld); |
| |
| cls = object_store->two_byte_string_class(); // Was allocated above. |
| RegisterPrivateClass(cls, Symbols::TwoByteString(), core_lib); |
| pending_classes.Add(cls, Heap::kOld); |
| |
| cls = Class::NewStringClass(kExternalOneByteStringCid); |
| object_store->set_external_one_byte_string_class(cls); |
| RegisterPrivateClass(cls, Symbols::ExternalOneByteString(), core_lib); |
| pending_classes.Add(cls, Heap::kOld); |
| |
| cls = Class::NewStringClass(kExternalTwoByteStringCid); |
| object_store->set_external_two_byte_string_class(cls); |
| RegisterPrivateClass(cls, Symbols::ExternalTwoByteString(), core_lib); |
| pending_classes.Add(cls, Heap::kOld); |
| |
| cls = Class::New<Stacktrace>(); |
| object_store->set_stacktrace_class(cls); |
| RegisterClass(cls, Symbols::StackTrace(), core_lib); |
| pending_classes.Add(cls, Heap::kOld); |
| // Super type set below, after Object is allocated. |
| |
| cls = Class::New<JSRegExp>(); |
| object_store->set_jsregexp_class(cls); |
| RegisterPrivateClass(cls, Symbols::JSSyntaxRegExp(), core_lib); |
| pending_classes.Add(cls, Heap::kOld); |
| |
| // Initialize the base interfaces used by the core VM classes. |
| script = Bootstrap::LoadCoreScript(false); |
| |
| // Allocate and initialize the pre-allocated classes in the core library. |
| cls = Class::New<Instance>(kInstanceCid); |
| object_store->set_object_class(cls); |
| cls.set_name(Symbols::Object()); |
| cls.set_script(script); |
| cls.set_is_prefinalized(); |
| core_lib.AddClass(cls); |
| pending_classes.Add(cls, Heap::kOld); |
| type = Type::NewNonParameterizedType(cls); |
| object_store->set_object_type(type); |
| |
| cls = object_store->type_class(); |
| RegisterPrivateClass(cls, Symbols::Type(), core_lib); |
| pending_classes.Add(cls, Heap::kOld); |
| |
| cls = object_store->type_parameter_class(); |
| RegisterPrivateClass(cls, Symbols::TypeParameter(), core_lib); |
| pending_classes.Add(cls, Heap::kOld); |
| |
| cls = Class::New<Integer>(); |
| object_store->set_integer_implementation_class(cls); |
| RegisterPrivateClass(cls, Symbols::IntegerImplementation(), core_lib); |
| pending_classes.Add(cls, Heap::kOld); |
| |
| cls = Class::New<Smi>(); |
| object_store->set_smi_class(cls); |
| RegisterPrivateClass(cls, Symbols::_Smi(), core_lib); |
| pending_classes.Add(cls, Heap::kOld); |
| |
| cls = Class::New<Mint>(); |
| object_store->set_mint_class(cls); |
| RegisterPrivateClass(cls, Symbols::_Mint(), core_lib); |
| pending_classes.Add(cls, Heap::kOld); |
| |
| cls = Class::New<Bigint>(); |
| object_store->set_bigint_class(cls); |
| RegisterPrivateClass(cls, Symbols::_Bigint(), core_lib); |
| pending_classes.Add(cls, Heap::kOld); |
| |
| cls = Class::New<Double>(); |
| object_store->set_double_class(cls); |
| RegisterPrivateClass(cls, Symbols::_Double(), core_lib); |
| pending_classes.Add(cls, Heap::kOld); |
| |
| cls = Class::New<WeakProperty>(); |
| object_store->set_weak_property_class(cls); |
| RegisterPrivateClass(cls, Symbols::_WeakProperty(), core_lib); |
| |
| // Setup some default native field classes which can be extended for |
| // specifying native fields in dart classes. |
| Library::InitNativeWrappersLibrary(isolate); |
| ASSERT(isolate->object_store()->native_wrappers_library() != Library::null()); |
| |
| // Pre-register the typed_data library so the native class implementations |
| // can be hooked up before compiling it. |
| LOAD_LIBRARY(TypedData, typed_data); |
| ASSERT(!lib.IsNull()); |
| ASSERT(lib.raw() == Library::TypedDataLibrary()); |
| const intptr_t typed_data_class_array_length = |
| RawObject::NumberOfTypedDataClasses(); |
| Array& typed_data_classes = |
| Array::Handle(Array::New(typed_data_class_array_length)); |
| int index = 0; |
| #define REGISTER_TYPED_DATA_CLASS(clazz) \ |
| cls = Class::NewTypedDataClass(kTypedData##clazz##Cid); \ |
| index = kTypedData##clazz##Cid - kTypedDataInt8ArrayCid; \ |
| typed_data_classes.SetAt(index, cls); \ |
| RegisterPrivateClass(cls, Symbols::_##clazz(), lib); \ |
| |
| CLASS_LIST_TYPED_DATA(REGISTER_TYPED_DATA_CLASS); |
| #undef REGISTER_TYPED_DATA_CLASS |
| #define REGISTER_TYPED_DATA_VIEW_CLASS(clazz) \ |
| cls = Class::NewTypedDataViewClass(kTypedData##clazz##ViewCid); \ |
| index = kTypedData##clazz##ViewCid - kTypedDataInt8ArrayCid; \ |
| typed_data_classes.SetAt(index, cls); \ |
| RegisterPrivateClass(cls, Symbols::_##clazz##View(), lib); \ |
| pending_classes.Add(cls, Heap::kOld); \ |
| |
| CLASS_LIST_TYPED_DATA(REGISTER_TYPED_DATA_VIEW_CLASS); |
| cls = Class::NewTypedDataViewClass(kByteDataViewCid); |
| index = kByteDataViewCid - kTypedDataInt8ArrayCid; |
| typed_data_classes.SetAt(index, cls); |
| RegisterPrivateClass(cls, Symbols::_ByteDataView(), lib); |
| pending_classes.Add(cls, Heap::kOld); |
| #undef REGISTER_TYPED_DATA_VIEW_CLASS |
| #define REGISTER_EXT_TYPED_DATA_CLASS(clazz) \ |
| cls = Class::NewExternalTypedDataClass(kExternalTypedData##clazz##Cid); \ |
| index = kExternalTypedData##clazz##Cid - kTypedDataInt8ArrayCid; \ |
| typed_data_classes.SetAt(index, cls); \ |
| RegisterPrivateClass(cls, Symbols::_External##clazz(), lib); \ |
| |
| CLASS_LIST_TYPED_DATA(REGISTER_EXT_TYPED_DATA_CLASS); |
| #undef REGISTER_EXT_TYPED_DATA_CLASS |
| // Register Float32x4 and Uint32x4 in the object store. |
| cls = Class::New<Float32x4>(); |
| object_store->set_float32x4_class(cls); |
| RegisterPrivateClass(cls, Symbols::_Float32x4(), lib); |
| cls = Class::New<Uint32x4>(); |
| object_store->set_uint32x4_class(cls); |
| RegisterPrivateClass(cls, Symbols::_Uint32x4(), lib); |
| |
| cls = Class::New<Instance>(Symbols::Float32x4(), script, |
| Scanner::kDummyTokenIndex); |
| RegisterClass(cls, Symbols::Float32x4(), lib); |
| pending_classes.Add(cls, Heap::kOld); |
| type = Type::NewNonParameterizedType(cls); |
| object_store->set_float32x4_type(type); |
| |
| cls = Class::New<Instance>(Symbols::Uint32x4(), script, |
| Scanner::kDummyTokenIndex); |
| pending_classes.Add(cls, Heap::kOld); |
| type = Type::NewNonParameterizedType(cls); |
| object_store->set_uint32x4_type(type); |
| |
| object_store->set_typed_data_classes(typed_data_classes); |
| |
| // Set the super type of class Stacktrace to Object type so that the |
| // 'toString' method is implemented. |
| cls = object_store->stacktrace_class(); |
| cls.set_super_type(type); |
| |
| // Note: The abstract class Function is represented by VM class |
| // DartFunction, not VM class Function. |
| cls = Class::New<DartFunction>(); |
| RegisterClass(cls, Symbols::Function(), core_lib); |
| pending_classes.Add(cls, Heap::kOld); |
| type = Type::NewNonParameterizedType(cls); |
| object_store->set_function_type(type); |
| |
| cls = Class::New<Number>(); |
| RegisterClass(cls, Symbols::Number(), core_lib); |
| pending_classes.Add(cls, Heap::kOld); |
| type = Type::NewNonParameterizedType(cls); |
| object_store->set_number_type(type); |
| |
| cls = Class::New<Instance>(Symbols::Int(), script, Scanner::kDummyTokenIndex); |
| RegisterClass(cls, Symbols::Int(), core_lib); |
| pending_classes.Add(cls, Heap::kOld); |
| type = Type::NewNonParameterizedType(cls); |
| object_store->set_int_type(type); |
| |
| cls = Class::New<Instance>(Symbols::Double(), |
| script, |
| Scanner::kDummyTokenIndex); |
| RegisterClass(cls, Symbols::Double(), core_lib); |
| pending_classes.Add(cls, Heap::kOld); |
| type = Type::NewNonParameterizedType(cls); |
| object_store->set_double_type(type); |
| |
| name = Symbols::New("String"); |
| cls = Class::New<Instance>(name, script, Scanner::kDummyTokenIndex); |
| RegisterClass(cls, name, core_lib); |
| pending_classes.Add(cls, Heap::kOld); |
| type = Type::NewNonParameterizedType(cls); |
| object_store->set_string_type(type); |
| |
| cls = Class::New<Instance>(Symbols::List(), |
| script, |
| Scanner::kDummyTokenIndex); |
| RegisterClass(cls, Symbols::List(), core_lib); |
| pending_classes.Add(cls, Heap::kOld); |
| object_store->set_list_class(cls); |
| |
| cls = object_store->bool_class(); |
| type = Type::NewNonParameterizedType(cls); |
| object_store->set_bool_type(type); |
| |
| cls = object_store->smi_class(); |
| type = Type::NewNonParameterizedType(cls); |
| object_store->set_smi_type(type); |
| |
| cls = object_store->mint_class(); |
| type = Type::NewNonParameterizedType(cls); |
| object_store->set_mint_type(type); |
| |
| // The classes 'Null' and 'void' are not registered in the class dictionary, |
| // because their names are reserved keywords. Their names are not heap |
| // allocated, because the classes reside in the VM isolate. |
| // The corresponding types are stored in the object store. |
| cls = null_class(); |
| type = Type::NewNonParameterizedType(cls); |
| object_store->set_null_type(type); |
| |
| cls = void_class(); |
| type = Type::NewNonParameterizedType(cls); |
| object_store->set_void_type(type); |
| |
| // The class 'dynamic' is registered in the class dictionary because its name |
| // is a built-in identifier, rather than a reserved keyword. Its name is not |
| // heap allocated, because the class resides in the VM isolate. |
| // The corresponding type, the "unknown type", is stored in the object store. |
| cls = dynamic_class(); |
| type = Type::NewNonParameterizedType(cls); |
| object_store->set_dynamic_type(type); |
| |
| // Finish the initialization by compiling the bootstrap scripts containing the |
| // base interfaces and the implementation of the internal classes. |
| INIT_LIBRARY(Core, core, true); |
| |
| INIT_LIBRARY(Async, async, true); |
| INIT_LIBRARY(Collection, collection, true); |
| INIT_LIBRARY(CollectionDev, collection_dev, true); |
| INIT_LIBRARY(Crypto, crypto, false); |
| INIT_LIBRARY(Isolate, isolate, true); |
| INIT_LIBRARY(Json, json, true); |
| INIT_LIBRARY(Math, math, true); |
| INIT_LIBRARY(Mirrors, mirrors, true); |
| INIT_LIBRARY(TypedData, typed_data, true); |
| INIT_LIBRARY(Utf, utf, false); |
| INIT_LIBRARY(Uri, uri, false); |
| |
| Bootstrap::SetupNativeResolver(); |
| |
| // Remove the Object superclass cycle by setting the super type to null (not |
| // to the type of null). |
| cls = object_store->object_class(); |
| cls.set_super_type(Type::Handle()); |
| |
| ClassFinalizer::VerifyBootstrapClasses(); |
| MarkInvisibleFunctions(); |
| |
| // Set up the intrinsic state of all functions (core, math and scalar list). |
| Intrinsifier::InitializeState(); |
| |
| return Error::null(); |
| } |
| |
| |
| void Object::InitFromSnapshot(Isolate* isolate) { |
| TIMERSCOPE(time_bootstrap); |
| ObjectStore* object_store = isolate->object_store(); |
| |
| Class& cls = Class::Handle(); |
| |
| // Set up empty classes in the object store, these will get |
| // initialized correctly when we read from the snapshot. |
| // This is done to allow bootstrapping of reading classes from the snapshot. |
| cls = Class::New<Instance>(kInstanceCid); |
| object_store->set_object_class(cls); |
| |
| cls = Class::New<Type>(); |
| object_store->set_type_class(cls); |
| |
| cls = Class::New<TypeParameter>(); |
| object_store->set_type_parameter_class(cls); |
| |
| cls = Class::New<BoundedType>(); |
| object_store->set_bounded_type_class(cls); |
| |
| cls = Class::New<MixinAppType>(); |
| object_store->set_mixin_app_type_class(cls); |
| |
| cls = Class::New<Array>(); |
| object_store->set_array_class(cls); |
| |
| cls = Class::New<ImmutableArray>(); |
| object_store->set_immutable_array_class(cls); |
| |
| cls = Class::New<GrowableObjectArray>(); |
| object_store->set_growable_object_array_class(cls); |
| |
| cls = Class::New<Float32x4>(); |
| object_store->set_float32x4_class(cls); |
| |
| cls = Class::New<Uint32x4>(); |
| object_store->set_uint32x4_class(cls); |
| |
| #define REGISTER_TYPED_DATA_CLASS(clazz) \ |
| cls = Class::NewTypedDataClass(kTypedData##clazz##Cid); |
| CLASS_LIST_TYPED_DATA(REGISTER_TYPED_DATA_CLASS); |
| #undef REGISTER_TYPED_DATA_CLASS |
| #define REGISTER_TYPED_DATA_VIEW_CLASS(clazz) \ |
| cls = Class::NewTypedDataViewClass(kTypedData##clazz##ViewCid); |
| CLASS_LIST_TYPED_DATA(REGISTER_TYPED_DATA_VIEW_CLASS); |
| cls = Class::NewTypedDataViewClass(kByteDataViewCid); |
| #undef REGISTER_TYPED_DATA_VIEW_CLASS |
| #define REGISTER_EXT_TYPED_DATA_CLASS(clazz) \ |
| cls = Class::NewExternalTypedDataClass(kExternalTypedData##clazz##Cid); |
| CLASS_LIST_TYPED_DATA(REGISTER_EXT_TYPED_DATA_CLASS); |
| #undef REGISTER_EXT_TYPED_DATA_CLASS |
| |
| cls = Class::New<Integer>(); |
| object_store->set_integer_implementation_class(cls); |
| |
| cls = Class::New<Smi>(); |
| object_store->set_smi_class(cls); |
| |
| cls = Class::New<Mint>(); |
| object_store->set_mint_class(cls); |
| |
| cls = Class::New<Double>(); |
| object_store->set_double_class(cls); |
| |
| cls = Class::New<Bigint>(); |
| object_store->set_bigint_class(cls); |
| |
| cls = Class::NewStringClass(kOneByteStringCid); |
| object_store->set_one_byte_string_class(cls); |
| |
| cls = Class::NewStringClass(kTwoByteStringCid); |
| object_store->set_two_byte_string_class(cls); |
| |
| cls = Class::NewStringClass(kExternalOneByteStringCid); |
| object_store->set_external_one_byte_string_class(cls); |
| |
| cls = Class::NewStringClass(kExternalTwoByteStringCid); |
| object_store->set_external_two_byte_string_class(cls); |
| |
| cls = Class::New<Bool>(); |
| object_store->set_bool_class(cls); |
| |
| cls = Class::New<Stacktrace>(); |
| object_store->set_stacktrace_class(cls); |
| |
| cls = Class::New<JSRegExp>(); |
| object_store->set_jsregexp_class(cls); |
| |
| // Some classes are not stored in the object store. Yet we still need to |
| // create their Class object so that they get put into the class_table |
| // (as a side effect of Class::New()). |
| cls = Class::New<DartFunction>(); |
| cls = Class::New<Number>(); |
| |
| cls = Class::New<WeakProperty>(); |
| object_store->set_weak_property_class(cls); |
| } |
| |
| |
| void Object::Print() const { |
| OS::Print("%s\n", ToCString()); |
| } |
| |
| |
| RawString* Object::DictionaryName() const { |
| return String::null(); |
| } |
| |
| |
| void Object::InitializeObject(uword address, intptr_t class_id, intptr_t size) { |
| // TODO(iposva): Get a proper halt instruction from the assembler which |
| // would be needed here for code objects. |
| uword initial_value = reinterpret_cast<uword>(null_); |
| uword cur = address; |
| uword end = address + size; |
| while (cur < end) { |
| *reinterpret_cast<uword*>(cur) = initial_value; |
| cur += kWordSize; |
| } |
| uword tags = 0; |
| ASSERT(class_id != kIllegalCid); |
| tags = RawObject::ClassIdTag::update(class_id, tags); |
| tags = RawObject::SizeTag::update(size, tags); |
| reinterpret_cast<RawObject*>(address)->tags_ = tags; |
| } |
| |
| |
| void Object::CheckHandle() const { |
| #if defined(DEBUG) |
| if (raw_ != Object::null()) { |
| if ((reinterpret_cast<uword>(raw_) & kSmiTagMask) == kSmiTag) { |
| ASSERT(vtable() == Smi::handle_vtable_); |
| return; |
| } |
| intptr_t cid = raw_->GetClassId(); |
| if (cid >= kNumPredefinedCids) { |
| cid = kInstanceCid; |
| } |
| ASSERT(vtable() == builtin_vtables_[cid]); |
| if (FLAG_verify_handles) { |
| Isolate* isolate = Isolate::Current(); |
| Heap* isolate_heap = isolate->heap(); |
| Heap* vm_isolate_heap = Dart::vm_isolate()->heap(); |
| ASSERT(isolate_heap->Contains(RawObject::ToAddr(raw_)) || |
| vm_isolate_heap->Contains(RawObject::ToAddr(raw_))); |
| } |
| } |
| #endif |
| } |
| |
| |
| RawObject* Object::Allocate(intptr_t cls_id, |
| intptr_t size, |
| Heap::Space space) { |
| ASSERT(Utils::IsAligned(size, kObjectAlignment)); |
| Isolate* isolate = Isolate::Current(); |
| ASSERT(isolate->no_callback_scope_depth() == 0); |
| Heap* heap = isolate->heap(); |
| |
| uword address = heap->Allocate(size, space); |
| if (address == 0) { |
| // Use the preallocated out of memory exception to avoid calling |
| // into dart code or allocating any code. |
| const Instance& exception = |
| Instance::Handle(isolate->object_store()->out_of_memory()); |
| Exceptions::Throw(exception); |
| UNREACHABLE(); |
| } |
| NoGCScope no_gc; |
| InitializeObject(address, cls_id, size); |
| RawObject* raw_obj = reinterpret_cast<RawObject*>(address + kHeapObjectTag); |
| ASSERT(cls_id == RawObject::ClassIdTag::decode(raw_obj->ptr()->tags_)); |
| return raw_obj; |
| } |
| |
| |
| class StoreBufferUpdateVisitor : public ObjectPointerVisitor { |
| public: |
| explicit StoreBufferUpdateVisitor(Isolate* isolate, RawObject* obj) : |
| ObjectPointerVisitor(isolate), old_obj_(obj) { |
| ASSERT(old_obj_->IsOldObject()); |
| } |
| |
| void VisitPointers(RawObject** first, RawObject** last) { |
| for (RawObject** curr = first; curr <= last; ++curr) { |
| RawObject* raw_obj = *curr; |
| if (raw_obj->IsHeapObject() && raw_obj->IsNewObject()) { |
| uword ptr = reinterpret_cast<uword>(old_obj_); |
| isolate()->store_buffer()->AddPointer(ptr); |
| // Remembered this object. There is no need to continue searching. |
| return; |
| } |
| } |
| } |
| |
| private: |
| RawObject* old_obj_; |
| |
| DISALLOW_COPY_AND_ASSIGN(StoreBufferUpdateVisitor); |
| }; |
| |
| |
| bool Object::IsReadOnlyHandle() const { |
| return Dart::IsReadOnlyHandle(reinterpret_cast<uword>(this)); |
| } |
| |
| |
| bool Object::IsNotTemporaryScopedHandle() const { |
| return (IsZoneHandle() || IsReadOnlyHandle()); |
| } |
| |
| |
| |
| RawObject* Object::Clone(const Object& src, Heap::Space space) { |
| const Class& cls = Class::Handle(src.clazz()); |
| intptr_t size = src.raw()->Size(); |
| RawObject* raw_obj = Object::Allocate(cls.id(), size, space); |
| NoGCScope no_gc; |
| memmove(raw_obj->ptr(), src.raw()->ptr(), size); |
| if (space == Heap::kOld) { |
| StoreBufferUpdateVisitor visitor(Isolate::Current(), raw_obj); |
| raw_obj->VisitPointers(&visitor); |
| } |
| return raw_obj; |
| } |
| |
| |
| RawString* Class::Name() const { |
| ASSERT(raw_ptr()->name_ != String::null()); |
| return raw_ptr()->name_; |
| } |
| |
| |
| RawString* Class::UserVisibleName() const { |
| if (FLAG_show_internal_names) { |
| return Name(); |
| } |
| switch (id()) { |
| case kIntegerCid: |
| case kSmiCid: |
| case kMintCid: |
| case kBigintCid: |
| return Symbols::Int().raw(); |
| case kDoubleCid: |
| return Symbols::Double().raw(); |
| case kOneByteStringCid: |
| case kTwoByteStringCid: |
| case kExternalOneByteStringCid: |
| case kExternalTwoByteStringCid: |
| return Symbols::New("String"); |
| case kArrayCid: |
| case kImmutableArrayCid: |
| case kGrowableObjectArrayCid: |
| return Symbols::List().raw(); |
| case kFloat32x4Cid: |
| return Symbols::Float32x4().raw(); |
| case kUint32x4Cid: |
| return Symbols::Uint32x4().raw(); |
| case kTypedDataInt8ArrayCid: |
| case kExternalTypedDataInt8ArrayCid: |
| return Symbols::Int8List().raw(); |
| case kTypedDataUint8ArrayCid: |
| case kExternalTypedDataUint8ArrayCid: |
| return Symbols::Uint8List().raw(); |
| case kTypedDataUint8ClampedArrayCid: |
| case kExternalTypedDataUint8ClampedArrayCid: |
| return Symbols::Uint8ClampedList().raw(); |
| case kTypedDataInt16ArrayCid: |
| case kExternalTypedDataInt16ArrayCid: |
| return Symbols::Int16List().raw(); |
| case kTypedDataUint16ArrayCid: |
| case kExternalTypedDataUint16ArrayCid: |
| return Symbols::Uint16List().raw(); |
| case kTypedDataInt32ArrayCid: |
| case kExternalTypedDataInt32ArrayCid: |
| return Symbols::Int32List().raw(); |
| case kTypedDataUint32ArrayCid: |
| case kExternalTypedDataUint32ArrayCid: |
| return Symbols::Uint32List().raw(); |
| case kTypedDataInt64ArrayCid: |
| case kExternalTypedDataInt64ArrayCid: |
| return Symbols::Int64List().raw(); |
| case kTypedDataUint64ArrayCid: |
| case kExternalTypedDataUint64ArrayCid: |
| return Symbols::Uint64List().raw(); |
| case kTypedDataFloat32x4ArrayCid: |
| case kExternalTypedDataFloat32x4ArrayCid: |
| return Symbols::Float32x4List().raw(); |
| case kTypedDataFloat32ArrayCid: |
| case kExternalTypedDataFloat32ArrayCid: |
| return Symbols::Float32List().raw(); |
| case kTypedDataFloat64ArrayCid: |
| case kExternalTypedDataFloat64ArrayCid: |
| return Symbols::Float64List().raw(); |
| default: |
| if (!IsSignatureClass()) { |
| const String& name = String::Handle(Name()); |
| return IdentifierPrettyName(name); |
| } else { |
| return Name(); |
| } |
| } |
| UNREACHABLE(); |
| } |
| |
| |
| RawType* Class::SignatureType() const { |
| ASSERT(IsSignatureClass()); |
| const Function& function = Function::Handle(signature_function()); |
| ASSERT(!function.IsNull()); |
| if (function.signature_class() != raw()) { |
| // This class is a function type alias. Return the canonical signature type. |
| const Class& canonical_class = Class::Handle(function.signature_class()); |
| return canonical_class.SignatureType(); |
| } |
| // Return the first canonical signature type if already computed. |
| const Array& signature_types = Array::Handle(canonical_types()); |
| // The canonical_types array is initialized to the empty array. |
| ASSERT(!signature_types.IsNull()); |
| if (signature_types.Length() > 0) { |
| // At most one signature type per signature class. |
| ASSERT((signature_types.Length() == 1) || |
| ((signature_types.Length() == 2) && |
| (signature_types.At(1) == Type::null()))); |
| Type& signature_type = Type::Handle(); |
| signature_type ^= signature_types.At(0); |
| ASSERT(!signature_type.IsNull()); |
| return signature_type.raw(); |
| } |
| // A signature class extends class Instance and is parameterized in the same |
| // way as the owner class of its non-static signature function. |
| // It is not type parameterized if its signature function is static. |
| // See Class::NewSignatureClass() for the setup of its type parameters. |
| // During type finalization, the type arguments of the super class of the |
| // owner class of its signature function will be prepended to the type |
| // argument vector. Therefore, we only need to set the type arguments |
| // matching the type parameters here. |
| const TypeArguments& signature_type_arguments = |
| TypeArguments::Handle(type_parameters()); |
| const Type& signature_type = Type::Handle( |
| Type::New(*this, signature_type_arguments, token_pos())); |
| |
| // Return the still unfinalized signature type. |
| ASSERT(!signature_type.IsFinalized()); |
| return signature_type.raw(); |
| } |
| |
| |
| template <class FakeObject> |
| RawClass* Class::New() { |
| ASSERT(Object::class_class() != Class::null()); |
| Class& result = Class::Handle(); |
| { |
| RawObject* raw = Object::Allocate(Class::kClassId, |
| Class::InstanceSize(), |
| Heap::kOld); |
| NoGCScope no_gc; |
| result ^= raw; |
| } |
| FakeObject fake; |
| result.set_handle_vtable(fake.vtable()); |
| result.set_instance_size(FakeObject::InstanceSize()); |
| result.set_next_field_offset(FakeObject::InstanceSize()); |
| ASSERT((FakeObject::kClassId != kInstanceCid)); |
| result.set_id(FakeObject::kClassId); |
| result.raw_ptr()->state_bits_ = 0; |
| // VM backed classes are almost ready: run checks and resolve class |
| // references, but do not recompute size. |
| result.set_is_prefinalized(); |
| result.raw_ptr()->type_arguments_field_offset_in_words_ = kNoTypeArguments; |
| result.raw_ptr()->num_native_fields_ = 0; |
| result.raw_ptr()->token_pos_ = Scanner::kDummyTokenIndex; |
| result.InitEmptyFields(); |
| Isolate::Current()->class_table()->Register(result); |
| return result.raw(); |
| } |
| |
| |
| // Initialize class fields of type Array with empty array. |
| void Class::InitEmptyFields() { |
| if (Object::empty_array().raw() == Array::null()) { |
| // The empty array has not been initialized yet. |
| return; |
| } |
| StorePointer(&raw_ptr()->interfaces_, Object::empty_array().raw()); |
| StorePointer(&raw_ptr()->constants_, Object::empty_array().raw()); |
| 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()); |
| } |
| |
| |
| bool Class::HasInstanceFields() const { |
| const Array& field_array = Array::Handle(fields()); |
| Field& field = Field::Handle(); |
| for (intptr_t i = 0; i < field_array.Length(); ++i) { |
| field ^= field_array.At(i); |
| if (!field.is_static()) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| |
| void Class::SetFunctions(const Array& value) const { |
| ASSERT(!value.IsNull()); |
| #if defined(DEBUG) |
| // Verify that all the functions in the array have this class as owner. |
| Function& func = Function::Handle(); |
| intptr_t len = value.Length(); |
| for (intptr_t i = 0; i < len; i++) { |
| func ^= value.At(i); |
| ASSERT(func.Owner() == raw()); |
| } |
| #endif |
| StorePointer(&raw_ptr()->functions_, value.raw()); |
| } |
| |
| |
| void Class::AddFunction(const Function& function) const { |
| const Array& arr = Array::Handle(functions()); |
| const Array& new_arr = Array::Handle(Array::Grow(arr, arr.Length() + 1)); |
| new_arr.SetAt(arr.Length(), function); |
| SetFunctions(new_arr); |
| } |
| |
| |
| void Class::AddClosureFunction(const Function& function) const { |
| GrowableObjectArray& closures = |
| GrowableObjectArray::Handle(raw_ptr()->closure_functions_); |
| if (closures.IsNull()) { |
| closures = GrowableObjectArray::New(4); |
| StorePointer(&raw_ptr()->closure_functions_, closures.raw()); |
| } |
| ASSERT(function.IsNonImplicitClosureFunction()); |
| closures.Add(function); |
| } |
| |
| |
| // Lookup the innermost closure function that contains token at token_pos. |
| RawFunction* Class::LookupClosureFunction(intptr_t token_pos) const { |
| if (raw_ptr()->closure_functions_ == GrowableObjectArray::null()) { |
| return Function::null(); |
| } |
| const GrowableObjectArray& closures = |
| GrowableObjectArray::Handle(raw_ptr()->closure_functions_); |
| Function& closure = Function::Handle(); |
| intptr_t num_closures = closures.Length(); |
| intptr_t best_fit_token_pos = -1; |
| intptr_t best_fit_index = -1; |
| for (intptr_t i = 0; i < num_closures; i++) { |
| closure ^= closures.At(i); |
| ASSERT(!closure.IsNull()); |
| if ((closure.token_pos() <= token_pos) && |
| (token_pos < closure.end_token_pos()) && |
| (best_fit_token_pos < closure.token_pos())) { |
| best_fit_index = i; |
| best_fit_token_pos = closure.token_pos(); |
| } |
| } |
| closure = Function::null(); |
| if (best_fit_index >= 0) { |
| closure ^= closures.At(best_fit_index); |
| } |
| return closure.raw(); |
| } |
| |
| |
| void Class::set_signature_function(const Function& value) const { |
| ASSERT(value.IsClosureFunction() || value.IsSignatureFunction()); |
| StorePointer(&raw_ptr()->signature_function_, value.raw()); |
| } |
| |
| |
| void Class::set_class_state(RawClass::ClassState state) const { |
| ASSERT((state == RawClass::kAllocated) || |
| (state == RawClass::kPreFinalized) || |
| (state == RawClass::kFinalized)); |
| set_state_bits(StateBits::update(state, raw_ptr()->state_bits_)); |
| } |
| |
| |
| void Class::set_state_bits(intptr_t bits) const { |
| raw_ptr()->state_bits_ = static_cast<uint8_t>(bits); |
| } |
| |
| |
| void Class::set_library(const Library& value) const { |
| StorePointer(&raw_ptr()->library_, value.raw()); |
| } |
| |
| |
| void Class::set_type_parameters(const TypeArguments& value) const { |
| StorePointer(&raw_ptr()->type_parameters_, value.raw()); |
| } |
| |
| |
| intptr_t Class::NumTypeParameters() const { |
| const TypeArguments& type_params = TypeArguments::Handle(type_parameters()); |
| if (type_params.IsNull()) { |
| return 0; |
| } else { |
| return type_params.Length(); |
| } |
| } |
| |
| |
| intptr_t Class::NumTypeArguments() const { |
| // To work properly, this call requires the super class of this class to be |
| // resolved, which is checked by the SuperClass() call. |
| Class& cls = Class::Handle(raw()); |
| if (IsSignatureClass()) { |
| const Function& signature_fun = Function::Handle(signature_function()); |
| if (!signature_fun.is_static() && |
| !signature_fun.HasInstantiatedSignature()) { |
| cls = signature_fun.Owner(); |
| } |
| } |
| intptr_t num_type_args = NumTypeParameters(); |
| const Class& superclass = Class::Handle(cls.SuperClass()); |
| // Object is its own super class during bootstrap. |
| if (!superclass.IsNull() && (superclass.raw() != raw())) { |
| num_type_args += superclass.NumTypeArguments(); |
| } |
| return num_type_args; |
| } |
| |
| |
| bool Class::HasTypeArguments() const { |
| if (!IsSignatureClass() && (is_finalized() || is_prefinalized())) { |
| // More efficient than calling NumTypeArguments(). |
| return type_arguments_field_offset() != kNoTypeArguments; |
| } else { |
| // No need to check NumTypeArguments() if class has type parameters. |
| return (NumTypeParameters() > 0) || (NumTypeArguments() > 0); |
| } |
| } |
| |
| |
| RawClass* Class::SuperClass() const { |
| const AbstractType& sup_type = AbstractType::Handle(super_type()); |
| if (sup_type.IsNull()) { |
| return Class::null(); |
| } |
| return sup_type.type_class(); |
| } |
| |
| |
| void Class::set_super_type(const AbstractType& value) const { |
| ASSERT(value.IsNull() || |
| value.IsType() || |
| value.IsBoundedType() || |
| value.IsMixinAppType()); |
| StorePointer(&raw_ptr()->super_type_, value.raw()); |
| } |
| |
| |
| // Return a TypeParameter if the type_name is a type parameter of this class. |
| // Return null otherwise. |
| RawTypeParameter* Class::LookupTypeParameter(const String& type_name, |
| intptr_t token_pos) const { |
| ASSERT(!type_name.IsNull()); |
| const TypeArguments& type_params = TypeArguments::Handle(type_parameters()); |
| if (!type_params.IsNull()) { |
| intptr_t num_type_params = type_params.Length(); |
| TypeParameter& type_param = TypeParameter::Handle(); |
| String& type_param_name = String::Handle(); |
| for (intptr_t i = 0; i < num_type_params; i++) { |
| type_param ^= type_params.TypeAt(i); |
| type_param_name = type_param.name(); |
| if (type_param_name.Equals(type_name)) { |
| return type_param.raw(); |
| } |
| } |
| } |
| return TypeParameter::null(); |
| } |
| |
| |
| void Class::CalculateFieldOffsets() const { |
| Array& flds = Array::Handle(fields()); |
| const Class& super = Class::Handle(SuperClass()); |
| intptr_t offset = 0; |
| intptr_t type_args_field_offset = kNoTypeArguments; |
| if (super.IsNull()) { |
| offset = sizeof(RawObject); |
| } else { |
| type_args_field_offset = super.type_arguments_field_offset(); |
| offset = super.next_field_offset(); |
| ASSERT(offset > 0); |
| // We should never call CalculateFieldOffsets for native wrapper |
| // classes, assert this. |
| ASSERT(num_native_fields() == 0); |
| set_num_native_fields(super.num_native_fields()); |
| } |
| // If the super class is parameterized, use the same type_arguments field. |
| if (type_args_field_offset == kNoTypeArguments) { |
| const TypeArguments& type_params = TypeArguments::Handle(type_parameters()); |
| if (!type_params.IsNull()) { |
| ASSERT(type_params.Length() > 0); |
| // The instance needs a type_arguments field. |
| type_args_field_offset = offset; |
| offset += kWordSize; |
| } |
| } |
| set_type_arguments_field_offset(type_args_field_offset); |
| ASSERT(offset != 0); |
| Field& field = Field::Handle(); |
| intptr_t len = flds.Length(); |
| for (intptr_t i = 0; i < len; i++) { |
| field ^= flds.At(i); |
| // Offset is computed only for instance fields. |
| if (!field.is_static()) { |
| ASSERT(field.Offset() == 0); |
| field.SetOffset(offset); |
| offset += kWordSize; |
| } |
| } |
| set_instance_size(RoundedAllocationSize(offset)); |
| set_next_field_offset(offset); |
| } |
| |
| |
| void Class::Finalize() const { |
| ASSERT(!is_finalized()); |
| // Prefinalized classes have a VM internal representation and no Dart fields. |
| // Their instance size is precomputed and field offsets are known. |
| if (!is_prefinalized()) { |
| // Compute offsets of instance fields and instance size. |
| CalculateFieldOffsets(); |
| } |
| set_is_finalized(); |
| } |
| |
| |
| static const char* FormatPatchError(const char* format, const Object& obj) { |
| const char* msg = obj.ToCString(); |
| intptr_t len = OS::SNPrint(NULL, 0, format, msg) + 1; |
| char* result = Isolate::Current()->current_zone()->Alloc<char>(len); |
| OS::SNPrint(result, len, format, msg); |
| return result; |
| } |
| |
| |
| // Apply the members from the patch class to the original class. |
| const char* Class::ApplyPatch(const Class& patch) const { |
| ASSERT(!is_finalized()); |
| // Shared handles used during the iteration. |
| String& member_name = String::Handle(); |
| |
| const PatchClass& patch_class = |
| PatchClass::Handle(PatchClass::New(*this, patch)); |
| |
| Array& orig_list = Array::Handle(functions()); |
| intptr_t orig_len = orig_list.Length(); |
| Array& patch_list = Array::Handle(patch.functions()); |
| intptr_t patch_len = patch_list.Length(); |
| |
| // TODO(iposva): Verify that only patching existing methods and adding only |
| // new private methods. |
| Function& func = Function::Handle(); |
| Function& orig_func = Function::Handle(); |
| const GrowableObjectArray& new_functions = GrowableObjectArray::Handle( |
| GrowableObjectArray::New(orig_len)); |
| for (intptr_t i = 0; i < orig_len; i++) { |
| orig_func ^= orig_list.At(i); |
| member_name ^= orig_func.name(); |
| func = patch.LookupFunction(member_name); |
| if (func.IsNull()) { |
| // Non-patched function is preserved, all patched functions are added in |
| // the loop below. |
| new_functions.Add(orig_func); |
| } else if (!func.HasCompatibleParametersWith(orig_func) && |
| !(func.IsFactory() && orig_func.IsConstructor() && |
| (func.num_fixed_parameters() + 1 == |
| orig_func.num_fixed_parameters()))) { |
| return FormatPatchError("mismatched parameters: %s", member_name); |
| } |
| } |
| for (intptr_t i = 0; i < patch_len; i++) { |
| func ^= patch_list.At(i); |
| func.set_owner(patch_class); |
| new_functions.Add(func); |
| } |
| Array& new_list = Array::Handle(Array::MakeArray(new_functions)); |
| SetFunctions(new_list); |
| |
| // Merge the two list of fields. Raise an error when duplicates are found or |
| // when a public field is being added. |
| orig_list = fields(); |
| orig_len = orig_list.Length(); |
| patch_list = patch.fields(); |
| patch_len = patch_list.Length(); |
| |
| Field& field = Field::Handle(); |
| Field& orig_field = Field::Handle(); |
| new_list = Array::New(patch_len + orig_len); |
| for (intptr_t i = 0; i < patch_len; i++) { |
| field ^= patch_list.At(i); |
| field.set_owner(*this); |
| member_name = field.name(); |
| // TODO(iposva): Verify non-public fields only. |
| |
| // Verify no duplicate additions. |
| orig_field ^= LookupField(member_name); |
| if (!orig_field.IsNull()) { |
| return FormatPatchError("duplicate field: %s", member_name); |
| } |
| new_list.SetAt(i, field); |
| } |
| for (intptr_t i = 0; i < orig_len; i++) { |
| field ^= orig_list.At(i); |
| new_list.SetAt(patch_len + i, field); |
| } |
| SetFields(new_list); |
| |
| // The functions and fields in the patch class are no longer needed. |
| patch.SetFunctions(Object::empty_array()); |
| patch.SetFields(Object::empty_array()); |
| return NULL; |
| } |
| |
| |
| void Class::SetFields(const Array& value) const { |
| ASSERT(!value.IsNull()); |
| #if defined(DEBUG) |
| // Verify that all the fields in the array have this class as owner. |
| Field& field = Field::Handle(); |
| intptr_t len = value.Length(); |
| for (intptr_t i = 0; i < len; i++) { |
| field ^= value.At(i); |
| ASSERT(field.owner() == raw()); |
| } |
| #endif |
| // The value of static fields is already initialized to null. |
| StorePointer(&raw_ptr()->fields_, value.raw()); |
| } |
| |
| |
| template <class FakeInstance> |
| RawClass* Class::New(intptr_t index) { |
| ASSERT(Object::class_class() != Class::null()); |
| Class& result = Class::Handle(); |
| { |
| RawObject* raw = Object::Allocate(Class::kClassId, |
| Class::InstanceSize(), |
| Heap::kOld); |
| NoGCScope no_gc; |
| result ^= raw; |
| } |
| FakeInstance fake; |
| ASSERT(fake.IsInstance()); |
| result.set_handle_vtable(fake.vtable()); |
| result.set_instance_size(FakeInstance::InstanceSize()); |
| result.set_next_field_offset(FakeInstance::InstanceSize()); |
| result.set_id(index); |
| result.raw_ptr()->state_bits_ = 0; |
| result.raw_ptr()->type_arguments_field_offset_in_words_ = kNoTypeArguments; |
| result.raw_ptr()->num_native_fields_ = 0; |
| result.raw_ptr()->token_pos_ = Scanner::kDummyTokenIndex; |
| result.InitEmptyFields(); |
| Isolate::Current()->class_table()->Register(result); |
| return result.raw(); |
| } |
| |
| |
| template <class FakeInstance> |
| RawClass* Class::New(const String& name, |
| const Script& script, |
| intptr_t token_pos) { |
| Class& result = Class::Handle(New<FakeInstance>(kIllegalCid)); |
| result.set_name(name); |
| result.set_script(script); |
| result.set_token_pos(token_pos); |
| return result.raw(); |
| } |
| |
| |
| RawClass* Class::New(const String& name, |
| const Script& script, |
| intptr_t token_pos) { |
| Class& result = Class::Handle(New<Instance>(name, script, token_pos)); |
| return result.raw(); |
| } |
| |
| |
| RawClass* Class::NewSignatureClass(const String& name, |
| const Function& signature_function, |
| const Script& script, |
| intptr_t token_pos) { |
| const Class& result = Class::Handle(New<Instance>(name, script, token_pos)); |
| const Type& super_type = Type::Handle(Type::ObjectType()); |
| ASSERT(!super_type.IsNull()); |
| // Instances of a signature class can only be closures. |
| result.set_instance_size(Closure::InstanceSize()); |
| result.set_next_field_offset(Closure::InstanceSize()); |
| result.set_super_type(super_type); |
| result.set_type_arguments_field_offset(Closure::type_arguments_offset()); |
| // Implements interface "Function". |
| const Type& function_type = Type::Handle(Type::Function()); |
| const Array& interfaces = Array::Handle(Array::New(1, Heap::kOld)); |
| interfaces.SetAt(0, function_type); |
| result.set_interfaces(interfaces); |
| if (!signature_function.IsNull()) { |
| result.PatchSignatureFunction(signature_function); |
| } |
| return result.raw(); |
| } |
| |
| |
| void Class::PatchSignatureFunction(const Function& signature_function) const { |
| ASSERT(!signature_function.IsNull()); |
| 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 |
| // way as the owner class of its non-static signature function. |
| // It is not type parameterized if its signature function is static. |
| // In case of a function type alias, the function owner is the alias class |
| // instead of the enclosing class. |
| if (!signature_function.is_static() && |
| (owner_class.NumTypeParameters() > 0) && |
| !signature_function.HasInstantiatedSignature()) { |
| type_parameters = owner_class.type_parameters(); |
| } |
| set_signature_function(signature_function); |
| set_type_parameters(type_parameters); |
| if (owner_class.raw() == raw()) { |
| // This signature class is an alias, which cannot be the canonical |
| // signature class for this signature function. |
| ASSERT(!IsCanonicalSignatureClass()); |
| } else if (signature_function.signature_class() == Object::null()) { |
| // Make this signature class the canonical signature class. |
| signature_function.set_signature_class(*this); |
| ASSERT(IsCanonicalSignatureClass()); |
| } |
| set_is_prefinalized(); |
| } |
| |
| |
| RawClass* Class::NewNativeWrapper(const Library& library, |
| const String& name, |
| int field_count) { |
| Class& cls = Class::Handle(library.LookupClass(name)); |
| if (cls.IsNull()) { |
| cls = New<Instance>(name, Script::Handle(), Scanner::kDummyTokenIndex); |
| cls.SetFields(Object::empty_array()); |
| cls.SetFunctions(Object::empty_array()); |
| // Set super class to Object. |
| cls.set_super_type(Type::Handle(Type::ObjectType())); |
| // Compute instance size. First word contains a pointer to a properly |
| // sized typed array once the first native field has been set. |
| intptr_t instance_size = sizeof(RawObject) + kWordSize; |
| cls.set_instance_size(RoundedAllocationSize(instance_size)); |
| cls.set_next_field_offset(instance_size); |
| cls.set_num_native_fields(field_count); |
| cls.set_is_finalized(); |
| library.AddClass(cls); |
| return cls.raw(); |
| } else { |
| return Class::null(); |
| } |
| } |
| |
| |
| RawClass* Class::NewStringClass(intptr_t class_id) { |
| intptr_t instance_size; |
| if (class_id == kOneByteStringCid) { |
| instance_size = OneByteString::InstanceSize(); |
| } else if (class_id == kTwoByteStringCid) { |
| instance_size = TwoByteString::InstanceSize(); |
| } else if (class_id == kExternalOneByteStringCid) { |
| instance_size = ExternalOneByteString::InstanceSize(); |
| } else { |
| ASSERT(class_id == kExternalTwoByteStringCid); |
| instance_size = ExternalTwoByteString::InstanceSize(); |
| } |
| Class& result = Class::Handle(New<String>(class_id)); |
| result.set_instance_size(instance_size); |
| result.set_next_field_offset(instance_size); |
| result.set_is_prefinalized(); |
| return result.raw(); |
| } |
| |
| |
| RawClass* Class::NewTypedDataClass(intptr_t class_id) { |
| ASSERT(RawObject::IsTypedDataClassId(class_id)); |
| intptr_t instance_size = TypedData::InstanceSize(); |
| Class& result = Class::Handle(New<TypedData>(class_id)); |
| result.set_instance_size(instance_size); |
| result.set_next_field_offset(instance_size); |
| result.set_is_prefinalized(); |
| return result.raw(); |
| } |
| |
| |
| RawClass* Class::NewTypedDataViewClass(intptr_t class_id) { |
| ASSERT(RawObject::IsTypedDataViewClassId(class_id)); |
| Class& result = Class::Handle(New<Instance>(class_id)); |
| result.set_instance_size(0); |
| result.set_next_field_offset(0); |
| return result.raw(); |
| } |
| |
| |
| RawClass* Class::NewExternalTypedDataClass(intptr_t class_id) { |
| ASSERT(RawObject::IsExternalTypedDataClassId(class_id)); |
| intptr_t instance_size = ExternalTypedData::InstanceSize(); |
| Class& result = Class::Handle(New<ExternalTypedData>(class_id)); |
| result.set_instance_size(instance_size); |
| result.set_next_field_offset(instance_size); |
| result.set_is_prefinalized(); |
| return result.raw(); |
| } |
| |
| |
| void Class::set_name(const String& value) const { |
| ASSERT(value.IsSymbol()); |
| StorePointer(&raw_ptr()->name_, value.raw()); |
| } |
| |
| |
| void Class::set_script(const Script& value) const { |
| StorePointer(&raw_ptr()->script_, value.raw()); |
| } |
| |
| |
| void Class::set_token_pos(intptr_t token_pos) const { |
| ASSERT(token_pos >= 0); |
| raw_ptr()->token_pos_ = token_pos; |
| } |
| |
| |
| void Class::set_is_implemented() const { |
| set_state_bits(ImplementedBit::update(true, raw_ptr()->state_bits_)); |
| } |
| |
| |
| void Class::set_is_abstract() const { |
| set_state_bits(AbstractBit::update(true, raw_ptr()->state_bits_)); |
| } |
| |
| |
| void Class::set_is_const() const { |
| set_state_bits(ConstBit::update(true, raw_ptr()->state_bits_)); |
| } |
| |
| |
| void Class::set_is_finalized() const { |
| ASSERT(!is_finalized()); |
| set_state_bits(StateBits::update(RawClass::kFinalized, |
| raw_ptr()->state_bits_)); |
| } |
| |
| |
| void Class::set_is_prefinalized() const { |
| ASSERT(!is_finalized()); |
| set_state_bits(StateBits::update(RawClass::kPreFinalized, |
| raw_ptr()->state_bits_)); |
| } |
| |
| |
| void Class::set_interfaces(const Array& value) const { |
| // Verification and resolving of interfaces occurs in finalizer. |
| ASSERT(!value.IsNull()); |
| StorePointer(&raw_ptr()->interfaces_, value.raw()); |
| } |
| |
| |
| void Class::set_mixin(const Type& value) const { |
| // Resolution and application of mixin type occurs in finalizer. |
| ASSERT(!value.IsNull()); |
| StorePointer(&raw_ptr()->mixin_, value.raw()); |
| } |
| |
| |
| void Class::AddDirectSubclass(const Class& subclass) const { |
| ASSERT(!subclass.IsNull()); |
| ASSERT(subclass.SuperClass() == raw()); |
| // Do not keep track of the direct subclasses of class Object. |
| ASSERT(!IsObjectClass()); |
| GrowableObjectArray& direct_subclasses = |
| GrowableObjectArray::Handle(raw_ptr()->direct_subclasses_); |
| if (direct_subclasses.IsNull()) { |
| direct_subclasses = GrowableObjectArray::New(4, Heap::kOld); |
| StorePointer(&raw_ptr()->direct_subclasses_, direct_subclasses.raw()); |
| } |
| #if defined(DEBUG) |
| // Verify that the same class is not added twice. |
| for (intptr_t i = 0; i < direct_subclasses.Length(); i++) { |
| ASSERT(direct_subclasses.At(i) != subclass.raw()); |
| } |
| #endif |
| direct_subclasses.Add(subclass); |
| } |
| |
| |
| RawArray* Class::constants() const { |
| return raw_ptr()->constants_; |
| } |
| |
| void Class::set_constants(const Array& value) const { |
| ASSERT(!value.IsNull()); |
| StorePointer(&raw_ptr()->constants_, value.raw()); |
| } |
| |
| |
| RawArray* Class::canonical_types() const { |
| return raw_ptr()->canonical_types_; |
| } |
| |
| void Class::set_canonical_types(const Array& value) const { |
| ASSERT(!value.IsNull()); |
| StorePointer(&raw_ptr()->canonical_types_, value.raw()); |
| } |
| |
| |
| void Class::set_allocation_stub(const Code& value) const { |
| ASSERT(!value.IsNull()); |
| ASSERT(raw_ptr()->allocation_stub_ == Code::null()); |
| StorePointer(&raw_ptr()->allocation_stub_, value.raw()); |
| } |
| |
| |
| bool Class::IsFunctionClass() const { |
| return raw() == Type::Handle(Type::Function()).type_class(); |
| } |
| |
| |
| bool Class::IsListClass() const { |
| return raw() == Isolate::Current()->object_store()->list_class(); |
| } |
| |
| |
| bool Class::IsCanonicalSignatureClass() const { |
| const Function& function = Function::Handle(signature_function()); |
| return (!function.IsNull() && (function.signature_class() == raw())); |
| } |
| |
| |
| // If test_kind == kIsSubtypeOf, checks if type S is a subtype of type T. |
| // If test_kind == kIsMoreSpecificThan, checks if S is more specific than T. |
| // Type S is specified by this class parameterized with 'type_arguments', and |
| // type T by class 'other' parameterized with 'other_type_arguments'. |
| // This class and class 'other' do not need to be finalized, however, they must |
| // be resolved as well as their interfaces. |
| bool Class::TypeTest( |
| TypeTestKind test_kind, |
| const AbstractTypeArguments& type_arguments, |
| const Class& other, |
| const AbstractTypeArguments& other_type_arguments, |
| Error* malformed_error) const { |
| ASSERT(!IsVoidClass()); |
| // Check for DynamicType. |
| // Each occurrence of DynamicType in type T is interpreted as the dynamic |
| // type, a supertype of all types. |
| if (other.IsDynamicClass()) { |
| return true; |
| } |
| // In the case of a subtype test, each occurrence of DynamicType in type S is |
| // interpreted as the bottom type, a subtype of all types. |
| // However, DynamicType is not more specific than any type. |
| if (IsDynamicClass()) { |
| return test_kind == kIsSubtypeOf; |
| } |
| // Check for NullType, which is only a subtype of ObjectType, of DynamicType, |
| // or of itself, and which is more specific than any type. |
| if (IsNullClass()) { |
| // We already checked for other.IsDynamicClass() above. |
| return (test_kind == kIsMoreSpecificThan) || |
| other.IsObjectClass() || other.IsNullClass(); |
| } |
| // Check for ObjectType. Any type that is not NullType or DynamicType (already |
| // checked above), is more specific than ObjectType. |
| if (other.IsObjectClass()) { |
| return true; |
| } |
| // Check for reflexivity. |
| if (raw() == other.raw()) { |
| const intptr_t len = NumTypeArguments(); |
| if (len == 0) { |
| return true; |
| } |
| // Since we do not truncate the type argument vector of a subclass (see |
| // below), we only check a prefix of the proper length. |
| // Check for covariance. |
| if (other_type_arguments.IsNull() || other_type_arguments.IsRaw(len)) { |
| return true; |
| } |
| if (type_arguments.IsNull() || type_arguments.IsRaw(len)) { |
| // Other type can't be more specific than this one because for that |
| // it would have to have all dynamic type arguments which is checked |
| // above. |
| return test_kind == kIsSubtypeOf; |
| } |
| return type_arguments.TypeTest(test_kind, |
| other_type_arguments, |
| len, |
| malformed_error); |
| } |
| const bool other_is_function_class = other.IsFunctionClass(); |
| if (other.IsSignatureClass() || other_is_function_class) { |
| const Function& other_fun = Function::Handle(other.signature_function()); |
| if (IsSignatureClass()) { |
| if (other_is_function_class) { |
| return true; |
| } |
| // Check for two function types. |
| const Function& fun = Function::Handle(signature_function()); |
| return fun.TypeTest(test_kind, |
| type_arguments, |
| other_fun, |
| other_type_arguments, |
| malformed_error); |
| } |
| // Check if type S has a call() method of function type T. |
| Function& function = |
| Function::Handle(LookupDynamicFunction(Symbols::Call())); |
| if (function.IsNull()) { |
| // Walk up the super_class chain. |
| Class& cls = Class::Handle(SuperClass()); |
| while (!cls.IsNull() && function.IsNull()) { |
| function = cls.LookupDynamicFunction(Symbols::Call()); |
| cls = cls.SuperClass(); |
| } |
| } |
| if (!function.IsNull()) { |
| if (other_is_function_class || |
| function.TypeTest(test_kind, |
| type_arguments, |
| other_fun, |
| other_type_arguments, |
| malformed_error)) { |
| return true; |
| } |
| } |
| } |
| // Check for 'direct super type' specified in the implements clause |
| // and check for transitivity at the same time. |
| Array& interfaces = Array::Handle(this->interfaces()); |
| AbstractType& interface = AbstractType::Handle(); |
| Class& interface_class = Class::Handle(); |
| AbstractTypeArguments& interface_args = AbstractTypeArguments::Handle(); |
| Error& args_malformed_error = Error::Handle(); |
| for (intptr_t i = 0; i < interfaces.Length(); i++) { |
| interface ^= interfaces.At(i); |
| interface_class = interface.type_class(); |
| interface_args = interface.arguments(); |
| if (!interface_args.IsNull() && !interface_args.IsInstantiated()) { |
| // This type class implements an interface that is parameterized with |
| // generic type(s), e.g. it implements List<T>. |
| // The uninstantiated type T must be instantiated using the type |
| // parameters of this type before performing the type test. |
| // The type arguments of this type that are referred to by the type |
| // parameters of the interface are at the end of the type vector, |
| // after the type arguments of the super type of this type. |
| // The index of the type parameters is adjusted upon finalization. |
| ASSERT(interface.IsFinalized()); |
| args_malformed_error = Error::null(); |
| interface_args = interface_args.InstantiateFrom(type_arguments, |
| &args_malformed_error); |
| if (!args_malformed_error.IsNull()) { |
| // Return the first malformed error to the caller if it requests it. |
| if ((malformed_error != NULL) && malformed_error->IsNull()) { |
| *malformed_error = args_malformed_error.raw(); |
| } |
| continue; // Another interface may work better. |
| } |
| } |
| if (interface_class.TypeTest(test_kind, |
| interface_args, |
| other, |
| other_type_arguments, |
| malformed_error)) { |
| return true; |
| } |
| } |
| const Class& super_class = Class::Handle(SuperClass()); |
| if (super_class.IsNull()) { |
| return false; |
| } |
| // Instead of truncating the type argument vector to the length of the super |
| // type argument vector, we make sure that the code works with a vector that |
| // is longer than necessary. |
| return super_class.TypeTest(test_kind, |
| type_arguments, |
| other, |
| other_type_arguments, |
| malformed_error); |
| } |
| |
| |
| bool Class::IsTopLevel() const { |
| return String::Handle(Name()).Equals("::"); |
| } |
| |
| |
| RawFunction* Class::LookupDynamicFunction(const String& name) const { |
| Function& function = Function::Handle(LookupFunction(name)); |
| if (function.IsNull() || !function.IsDynamicFunction()) { |
| return Function::null(); |
| } |
| return function.raw(); |
| } |
| |
| |
| RawFunction* Class::LookupDynamicFunctionAllowPrivate( |
| const String& name) const { |
| Function& function = Function::Handle(LookupFunctionAllowPrivate(name)); |
| if (function.IsNull() || !function.IsDynamicFunction()) { |
| return Function::null(); |
| } |
| return function.raw(); |
| } |
| |
| |
| RawFunction* Class::LookupStaticFunction(const String& name) const { |
| Function& function = Function::Handle(LookupFunction(name)); |
| if (function.IsNull() || !function.IsStaticFunction()) { |
| return Function::null(); |
| } |
| return function.raw(); |
| } |
| |
| |
| RawFunction* Class::LookupStaticFunctionAllowPrivate(const String& name) const { |
| Function& function = Function::Handle(LookupFunctionAllowPrivate(name)); |
| if (function.IsNull() || !function.IsStaticFunction()) { |
| return Function::null(); |
| } |
| return function.raw(); |
| } |
| |
| |
| RawFunction* Class::LookupConstructor(const String& name) const { |
| Function& function = Function::Handle(LookupFunction(name)); |
| if (function.IsNull() || !function.IsConstructor()) { |
| return Function::null(); |
| } |
| ASSERT(!function.is_static()); |
| return function.raw(); |
| } |
| |
| |
| RawFunction* Class::LookupConstructorAllowPrivate(const String& name) const { |
| Function& function = Function::Handle(LookupFunctionAllowPrivate(name)); |
| if (function.IsNull() || !function.IsConstructor()) { |
| return Function::null(); |
| } |
| ASSERT(!function.is_static()); |
| return function.raw(); |
| } |
| |
| |
| RawFunction* Class::LookupFactory(const String& name) const { |
| Function& function = Function::Handle(LookupFunction(name)); |
| if (function.IsNull() || !function.IsFactory()) { |
| return Function::null(); |
| } |
| ASSERT(function.is_static()); |
| return function.raw(); |
| } |
| |
| |
| // Returns true if 'prefix' and 'accessor_name' match 'name'. |
| static bool MatchesAccessorName(const String& name, |
| const char* prefix, |
| intptr_t prefix_length, |
| const String& accessor_name) { |
| intptr_t name_len = name.Length(); |
| intptr_t accessor_name_len = accessor_name.Length(); |
| |
| if (name_len != (accessor_name_len + prefix_length)) { |
| return false; |
| } |
| for (intptr_t i = 0; i < prefix_length; i++) { |
| if (name.CharAt(i) != prefix[i]) { |
| return false; |
| } |
| } |
| for (intptr_t i = 0, j = prefix_length; i < accessor_name_len; i++, j++) { |
| if (name.CharAt(j) != accessor_name.CharAt(i)) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| |
| RawFunction* Class::LookupFunction(const String& name) const { |
| Isolate* isolate = Isolate::Current(); |
| Array& funcs = Array::Handle(isolate, functions()); |
| if (funcs.IsNull()) { |
| // This can occur, e.g., for Null classes. |
| return Function::null(); |
| } |
| Function& function = Function::Handle(isolate, Function::null()); |
| const intptr_t len = funcs.Length(); |
| if (name.IsSymbol()) { |
| // Quick Symbol compare. |
| NoGCScope no_gc; |
| for (intptr_t i = 0; i < len; i++) { |
| function ^= funcs.At(i); |
| if (function.name() == name.raw()) { |
| return function.raw(); |
| } |
| } |
| } else { |
| String& function_name = String::Handle(isolate, String::null()); |
| for (intptr_t i = 0; i < len; i++) { |
| function ^= funcs.At(i); |
| function_name ^= function.name(); |
| if (function_name.Equals(name)) { |
| return function.raw(); |
| } |
| } |
| } |
| // No function found. |
| return Function::null(); |
| } |
| |
| |
| RawFunction* Class::LookupFunctionAllowPrivate(const String& name) const { |
| Isolate* isolate = Isolate::Current(); |
| Array& funcs = Array::Handle(isolate, functions()); |
| if (funcs.IsNull()) { |
| // This can occur, e.g., for Null classes. |
| return Function::null(); |
| } |
| Function& function = Function::Handle(isolate, Function::null()); |
| String& function_name = String::Handle(isolate, String::null()); |
| intptr_t len = funcs.Length(); |
| for (intptr_t i = 0; i < len; i++) { |
| function ^= funcs.At(i); |
| function_name ^= function.name(); |
| if (String::EqualsIgnoringPrivateKey(function_name, name)) { |
| return function.raw(); |
| } |
| } |
| // No function found. |
| return Function::null(); |
| } |
| |
| |
| RawFunction* Class::LookupGetterFunction(const String& name) const { |
| return LookupAccessorFunction(kGetterPrefix, kGetterPrefixLength, name); |
| } |
| |
| |
| RawFunction* Class::LookupSetterFunction(const String& name) const { |
| return LookupAccessorFunction(kSetterPrefix, kSetterPrefixLength, name); |
| } |
| |
| |
| RawFunction* Class::LookupAccessorFunction(const char* prefix, |
| intptr_t prefix_length, |
| const String& name) const { |
| Isolate* isolate = Isolate::Current(); |
| Array& funcs = Array::Handle(isolate, functions()); |
| Function& function = Function::Handle(isolate, Function::null()); |
| String& function_name = String::Handle(isolate, String::null()); |
| intptr_t len = funcs.Length(); |
| for (intptr_t i = 0; i < len; i++) { |
| function ^= funcs.At(i); |
| function_name ^= function.name(); |
| if (MatchesAccessorName(function_name, prefix, prefix_length, name)) { |
| return function.raw(); |
| } |
| } |
| |
| // No function found. |
| return Function::null(); |
| } |
| |
| |
| RawFunction* Class::LookupFunctionAtToken(intptr_t token_pos) const { |
| // TODO(hausner): we can shortcut the negative case if we knew the |
| // beginning and end token position of the class. |
| Function& func = Function::Handle(); |
| func = LookupClosureFunction(token_pos); |
| if (!func.IsNull()) { |
| return func.raw(); |
| } |
| Array& funcs = Array::Handle(functions()); |
| intptr_t len = funcs.Length(); |
| for (intptr_t i = 0; i < len; i++) { |
| func ^= funcs.At(i); |
| if ((func.token_pos() <= token_pos) && |
| (token_pos <= func.end_token_pos())) { |
| return func.raw(); |
| } |
| } |
| // No function found. |
| return Function::null(); |
| } |
| |
| |
| RawField* Class::LookupInstanceField(const String& name) const { |
| ASSERT(is_finalized()); |
| const Field& field = Field::Handle(LookupField(name)); |
| if (!field.IsNull()) { |
| if (field.is_static()) { |
| // Name matches but it is not of the correct kind, return NULL. |
| return Field::null(); |
| } |
| return field.raw(); |
| } |
| // No field found. |
| return Field::null(); |
| } |
| |
| |
| RawField* Class::LookupStaticField(const String& name) const { |
| ASSERT(is_finalized()); |
| const Field& field = Field::Handle(LookupField(name)); |
| if (!field.IsNull()) { |
| if (!field.is_static()) { |
| // Name matches but it is not of the correct kind, return NULL. |
| return Field::null(); |
| } |
| return field.raw(); |
| } |
| // No field found. |
| return Field::null(); |
| } |
| |
| |
| RawField* Class::LookupField(const String& name) const { |
| Isolate* isolate = Isolate::Current(); |
| const Array& flds = Array::Handle(isolate, fields()); |
| Field& field = Field::Handle(isolate, Field::null()); |
| String& field_name = String::Handle(isolate, String::null()); |
| intptr_t len = flds.Length(); |
| for (intptr_t i = 0; i < len; i++) { |
| field ^= flds.At(i); |
| field_name ^= field.name(); |
| if (String::EqualsIgnoringPrivateKey(field_name, name)) { |
| return field.raw(); |
| } |
| } |
| // No field found. |
| return Field::null(); |
| } |
| |
| |
| RawLibraryPrefix* Class::LookupLibraryPrefix(const String& name) const { |
| Isolate* isolate = Isolate::Current(); |
| const Library& lib = Library::Handle(isolate, library()); |
| const Object& obj = Object::Handle(isolate, lib.LookupLocalObject(name)); |
| if (!obj.IsNull() && obj.IsLibraryPrefix()) { |
| const LibraryPrefix& lib_prefix = LibraryPrefix::Cast(obj); |
| return lib_prefix.raw(); |
| } |
| return LibraryPrefix::null(); |
| } |
| |
| |
| const char* Class::ToCString() const { |
| const char* format = "%s Class: %s"; |
| const Library& lib = Library::Handle(library()); |
| const char* library_name = lib.IsNull() ? "" : lib.ToCString(); |
| const char* class_name = String::Handle(Name()).ToCString(); |
| intptr_t len = OS::SNPrint(NULL, 0, format, library_name, class_name) + 1; |
| char* chars = Isolate::Current()->current_zone()->Alloc<char>(len); |
| OS::SNPrint(chars, len, format, library_name, class_name); |
| return chars; |
| } |
| |
| |
| void Class::InsertCanonicalConstant(intptr_t index, |
| const Instance& constant) const { |
| // The constant needs to be added to the list. Grow the list if it is full. |
| Array& canonical_list = Array::Handle(constants()); |
| const intptr_t list_len = canonical_list.Length(); |
| if (index >= list_len) { |
| const intptr_t new_length = (list_len == 0) ? 4 : list_len + 4; |
| const Array& new_canonical_list = |
| Array::Handle(Array::Grow(canonical_list, new_length, Heap::kOld)); |
| set_constants(new_canonical_list); |
| new_canonical_list.SetAt(index, constant); |
| } else { |
| canonical_list.SetAt(index, constant); |
| } |
| } |
| |
| |
| RawUnresolvedClass* UnresolvedClass::New(const LibraryPrefix& library_prefix, |
| const String& ident, |
| intptr_t token_pos) { |
| const UnresolvedClass& type = UnresolvedClass::Handle(UnresolvedClass::New()); |
| type.set_library_prefix(library_prefix); |
| type.set_ident(ident); |
| type.set_token_pos(token_pos); |
| return type.raw(); |
| } |
| |
| |
| RawUnresolvedClass* UnresolvedClass::New() { |
| ASSERT(Object::unresolved_class_class() != Class::null()); |
| RawObject* raw = Object::Allocate(UnresolvedClass::kClassId, |
| UnresolvedClass::InstanceSize(), |
| Heap::kOld); |
| return reinterpret_cast<RawUnresolvedClass*>(raw); |
| } |
| |
| |
| void UnresolvedClass::set_token_pos(intptr_t token_pos) const { |
| ASSERT(token_pos >= 0); |
| raw_ptr()->token_pos_ = token_pos; |
| } |
| |
| |
| void UnresolvedClass::set_ident(const String& ident) const { |
| StorePointer(&raw_ptr()->ident_, ident.raw()); |
| } |
| |
| |
| void UnresolvedClass::set_library_prefix( |
| const LibraryPrefix& library_prefix) const { |
| StorePointer(&raw_ptr()->library_prefix_, library_prefix.raw()); |
| } |
| |
| |
| RawString* UnresolvedClass::Name() const { |
| if (library_prefix() != LibraryPrefix::null()) { |
| const LibraryPrefix& lib_prefix = LibraryPrefix::Handle(library_prefix()); |
| String& name = String::Handle(); |
| name = lib_prefix.name(); // Qualifier. |
| name = String::Concat(name, Symbols::Dot()); |
| const String& str = String::Handle(ident()); |
| name = String::Concat(name, str); |
| return name.raw(); |
| } else { |
| return ident(); |
| } |
| } |
| |
| |
| const char* UnresolvedClass::ToCString() const { |
| const char* format = "unresolved class '%s'"; |
| const char* cname = String::Handle(Name()).ToCString(); |
| intptr_t len = OS::SNPrint(NULL, 0, format, cname) + 1; |
| char* chars = Isolate::Current()->current_zone()->Alloc<char>(len); |
| OS::SNPrint(chars, len, format, cname); |
| return chars; |
| } |
| |
| |
| intptr_t AbstractTypeArguments::Length() const { |
| // AbstractTypeArguments is an abstract class. |
| UNREACHABLE(); |
| return -1; |
| } |
| |
| |
| RawAbstractType* AbstractTypeArguments::TypeAt(intptr_t index) const { |
| // AbstractTypeArguments is an abstract class. |
| UNREACHABLE(); |
| return NULL; |
| } |
| |
| |
| void AbstractTypeArguments::SetTypeAt(intptr_t index, |
| const AbstractType& value) const { |
| // AbstractTypeArguments is an abstract class. |
| UNREACHABLE(); |
| } |
| |
| |
| bool AbstractTypeArguments::IsResolved() const { |
| // AbstractTypeArguments is an abstract class. |
| UNREACHABLE(); |
| return false; |
| } |
| |
| |
| bool AbstractTypeArguments::IsInstantiated() const { |
| // AbstractTypeArguments is an abstract class. |
| UNREACHABLE(); |
| return false; |
| } |
| |
| |
| bool AbstractTypeArguments::IsUninstantiatedIdentity() const { |
| // AbstractTypeArguments is an abstract class. |
| UNREACHABLE(); |
| return false; |
| } |
| |
| |
| bool AbstractTypeArguments::IsBounded() const { |
| // AbstractTypeArguments is an abstract class. |
| UNREACHABLE(); |
| return false; |
| } |
| |
| |
| static intptr_t FinalizeHash(uword hash) { |
| hash += hash << 3; |
| hash ^= hash >> 11; |
| hash += hash << 15; |
| return hash; |
| } |
| |
| |
| intptr_t AbstractTypeArguments::Hash() const { |
| if (IsNull()) return 0; |
| uword result = 0; |
| intptr_t num_types = Length(); |
| AbstractType& type = AbstractType::Handle(); |
| for (intptr_t i = 0; i < num_types; i++) { |
| type = TypeAt(i); |
| result += type.Hash(); |
| result += result << 10; |
| result ^= result >> 6; |
| } |
| return FinalizeHash(result); |
| } |
| |
| |
| RawString* AbstractTypeArguments::SubvectorName( |
| intptr_t from_index, |
| intptr_t len, |
| NameVisibility name_visibility) const { |
| ASSERT(from_index + len <= Length()); |
| String& name = String::Handle(); |
| const intptr_t num_strings = 2*len + 1; // "<""T"", ""T"">". |
| const Array& strings = Array::Handle(Array::New(num_strings)); |
| intptr_t s = 0; |
| strings.SetAt(s++, Symbols::LAngleBracket()); |
| AbstractType& type = AbstractType::Handle(); |
| for (intptr_t i = 0; i < len; i++) { |
| type = TypeAt(from_index + i); |
| name = type.BuildName(name_visibility); |
| strings.SetAt(s++, name); |
| if (i < len - 1) { |
| strings.SetAt(s++, Symbols::CommaSpace()); |
| } |
| } |
| strings.SetAt(s++, Symbols::RAngleBracket()); |
| ASSERT(s == num_strings); |
| name = String::ConcatAll(strings); |
| return Symbols::New(name); |
| } |
| |
| |
| bool AbstractTypeArguments::Equals(const AbstractTypeArguments& other) const { |
| ASSERT(!IsNull()); // Use AbstractTypeArguments::AreEqual(). |
| if (this->raw() == other.raw()) { |
| return true; |
| } |
| if (other.IsNull()) { |
| return false; |
| } |
| intptr_t num_types = Length(); |
| if (num_types != other.Length()) { |
| return false; |
| } |
| AbstractType& type = AbstractType::Handle(); |
| AbstractType& other_type = AbstractType::Handle(); |
| for (intptr_t i = 0; i < num_types; i++) { |
| type = TypeAt(i); |
| other_type = other.TypeAt(i); |
| if (!type.Equals(other_type)) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| |
| bool AbstractTypeArguments::AreEqual( |
| const AbstractTypeArguments& arguments, |
| const AbstractTypeArguments& other_arguments) { |
| if (arguments.raw() == other_arguments.raw()) { |
| return true; |
| } |
| if (arguments.IsNull()) { |
| return other_arguments.IsDynamicTypes(false, other_arguments.Length()); |
| } |
| if (other_arguments.IsNull()) { |
| return arguments.IsDynamicTypes(false, arguments.Length()); |
| } |
| return arguments.Equals(other_arguments); |
| } |
| |
| |
| RawAbstractTypeArguments* AbstractTypeArguments::InstantiateFrom( |
| const AbstractTypeArguments& instantiator_type_arguments, |
| Error* malformed_error) const { |
| // AbstractTypeArguments is an abstract class. |
| UNREACHABLE(); |
| return NULL; |
| } |
| |
| |
| bool AbstractTypeArguments::IsDynamicTypes(bool raw_instantiated, |
| intptr_t len) const { |
| ASSERT(Length() >= len); |
| AbstractType& type = AbstractType::Handle(); |
| |