| // 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/bit_vector.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/disassembler.h" |
| #include "vm/double_conversion.h" |
| #include "vm/exceptions.h" |
| #include "vm/flow_graph_builder.h" |
| #include "vm/flow_graph_compiler.h" |
| #include "vm/growable_array.h" |
| #include "vm/hash_table.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/profiler.h" |
| #include "vm/report.h" |
| #include "vm/reusable_handles.h" |
| #include "vm/runtime_entry.h" |
| #include "vm/scopes.h" |
| #include "vm/stack_frame.h" |
| #include "vm/symbols.h" |
| #include "vm/tags.h" |
| #include "vm/timer.h" |
| #include "vm/unicode.h" |
| #include "vm/verified_memory.h" |
| #include "vm/weak_code.h" |
| |
| namespace dart { |
| |
| DEFINE_FLAG(int, huge_method_cutoff_in_code_size, 200000, |
| "Huge method cutoff in unoptimized code size (in bytes)."); |
| DEFINE_FLAG(int, huge_method_cutoff_in_tokens, 20000, |
| "Huge method cutoff in tokens: Disables optimizations for huge methods."); |
| DEFINE_FLAG(bool, overlap_type_arguments, true, |
| "When possible, partially or fully overlap the type arguments of a type " |
| "with the type arguments of its super type."); |
| 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, throw_on_javascript_int_overflow, false, |
| "Throw an exception when the result of an integer calculation will not " |
| "fit into a javascript integer."); |
| DEFINE_FLAG(bool, trace_cha, false, "Trace CHA operations"); |
| DEFINE_FLAG(bool, use_field_guards, true, "Guard field cids."); |
| DEFINE_FLAG(bool, use_lib_cache, true, "Use library name cache"); |
| DEFINE_FLAG(bool, trace_field_guards, false, "Trace changes in field's cids."); |
| DEFINE_FLAG(bool, ignore_patch_signature_mismatch, false, |
| "Ignore patch file member signature mismatch."); |
| |
| DECLARE_FLAG(charp, coverage_dir); |
| DECLARE_FLAG(bool, load_deferred_eagerly); |
| DECLARE_FLAG(bool, show_invisible_frames); |
| DECLARE_FLAG(bool, trace_compiler); |
| DECLARE_FLAG(bool, trace_deoptimization); |
| DECLARE_FLAG(bool, trace_deoptimization_verbose); |
| DECLARE_FLAG(bool, write_protect_code); |
| |
| |
| 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 |
| Object* Object::null_object_ = NULL; |
| Array* Object::null_array_ = NULL; |
| String* Object::null_string_ = NULL; |
| Instance* Object::null_instance_ = NULL; |
| TypeArguments* Object::null_type_arguments_ = NULL; |
| Array* Object::empty_array_ = NULL; |
| Array* Object::zero_array_ = NULL; |
| ContextScope* Object::empty_context_scope_ = NULL; |
| ObjectPool* Object::empty_object_pool_ = NULL; |
| PcDescriptors* Object::empty_descriptors_ = NULL; |
| LocalVarDescriptors* Object::empty_var_descriptors_ = NULL; |
| ExceptionHandlers* Object::empty_exception_handlers_ = NULL; |
| Array* Object::extractor_parameter_types_ = NULL; |
| Array* Object::extractor_parameter_names_ = NULL; |
| Instance* Object::sentinel_ = NULL; |
| Instance* Object::transition_sentinel_ = NULL; |
| Instance* Object::unknown_constant_ = NULL; |
| Instance* Object::non_constant_ = NULL; |
| Bool* Object::bool_true_ = NULL; |
| Bool* Object::bool_false_ = NULL; |
| Smi* Object::smi_illegal_cid_ = NULL; |
| LanguageError* Object::snapshot_writer_error_ = NULL; |
| LanguageError* Object::branch_offset_error_ = NULL; |
| Array* Object::vm_isolate_snapshot_object_table_ = NULL; |
| |
| RawObject* Object::null_ = reinterpret_cast<RawObject*>(RAW_NULL); |
| RawClass* Object::class_class_ = reinterpret_cast<RawClass*>(RAW_NULL); |
| RawClass* Object::dynamic_class_ = reinterpret_cast<RawClass*>(RAW_NULL); |
| RawClass* Object::void_class_ = reinterpret_cast<RawClass*>(RAW_NULL); |
| RawType* Object::dynamic_type_ = reinterpret_cast<RawType*>(RAW_NULL); |
| RawType* Object::void_type_ = reinterpret_cast<RawType*>(RAW_NULL); |
| RawClass* Object::unresolved_class_class_ = |
| reinterpret_cast<RawClass*>(RAW_NULL); |
| RawClass* Object::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::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::object_pool_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::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); |
| |
| |
| const double MegamorphicCache::kLoadFactor = 0.75; |
| |
| |
| static void AppendSubString(Zone* zone, |
| GrowableArray<const char*>* segments, |
| const char* name, |
| intptr_t start_pos, intptr_t len) { |
| char* segment = zone->Alloc<char>(len + 1); // '\0'-terminated. |
| memmove(segment, name + start_pos, len); |
| segment[len] = '\0'; |
| segments->Add(segment); |
| } |
| |
| |
| static const char* MergeSubStrings(Zone* zone, |
| const GrowableArray<const char*>& segments, |
| intptr_t alloc_len) { |
| char* result = zone->Alloc<char>(alloc_len + 1); // '\0'-terminated |
| intptr_t pos = 0; |
| for (intptr_t k = 0; k < segments.length(); k++) { |
| const char* piece = segments[k]; |
| const intptr_t piece_len = strlen(segments[k]); |
| memmove(result + pos, piece, piece_len); |
| pos += piece_len; |
| ASSERT(pos <= alloc_len); |
| } |
| result[pos] = '\0'; |
| return result; |
| } |
| |
| |
| // 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 multiple times: |
| // |
| // _ReceivePortImpl@709387912 -> _ReceivePortImpl |
| // _ReceivePortImpl@709387912._internal@709387912 -> |
| // _ReceivePortImpl._internal |
| // _C@6328321&_E@6328321&_F@6328321 -> _C&_E&_F |
| // |
| // The trailing . on the default constructor name is dropped: |
| // |
| // List. -> List |
| // |
| // And so forth: |
| // |
| // get:foo@6328321 -> foo |
| // _MyClass@6328321. -> _MyClass |
| // _MyClass@6328321.named -> _MyClass.named |
| // |
| RawString* String::IdentifierPrettyName(const String& name) { |
| Zone* zone = Thread::Current()->zone(); |
| if (name.Equals(Symbols::TopLevel())) { |
| // Name of invisible top-level class. |
| return Symbols::Empty().raw(); |
| } |
| |
| const char* cname = name.ToCString(); |
| ASSERT(strlen(cname) == static_cast<size_t>(name.Length())); |
| const intptr_t name_len = name.Length(); |
| // First remove all private name mangling. |
| intptr_t start_pos = 0; |
| GrowableArray<const char*> unmangled_segments; |
| intptr_t sum_segment_len = 0; |
| for (intptr_t i = 0; i < name_len; i++) { |
| if ((cname[i] == '@') && ((i + 1) < name_len) && |
| (cname[i + 1] >= '0') && (cname[i + 1] <= '9')) { |
| // Append the current segment to the unmangled name. |
| const intptr_t segment_len = i - start_pos; |
| sum_segment_len += segment_len; |
| AppendSubString(zone, &unmangled_segments, cname, start_pos, segment_len); |
| // Advance until past the name mangling. The private keys are only |
| // numbers so we skip until the first non-number. |
| i++; // Skip the '@'. |
| while ((i < name.Length()) && |
| (name.CharAt(i) >= '0') && |
| (name.CharAt(i) <= '9')) { |
| i++; |
| } |
| start_pos = i; |
| i--; // Account for for-loop increment. |
| } |
| } |
| |
| const char* unmangled_name = NULL; |
| if (start_pos == 0) { |
| // No name unmangling needed, reuse the name that was passed in. |
| unmangled_name = cname; |
| sum_segment_len = name_len; |
| } else if (name.Length() != start_pos) { |
| // Append the last segment. |
| const intptr_t segment_len = name.Length() - start_pos; |
| sum_segment_len += segment_len; |
| AppendSubString(zone, &unmangled_segments, cname, start_pos, segment_len); |
| } |
| if (unmangled_name == NULL) { |
| // Merge unmangled_segments. |
| unmangled_name = MergeSubStrings(zone, unmangled_segments, sum_segment_len); |
| } |
| |
| intptr_t len = sum_segment_len; |
| intptr_t start = 0; |
| intptr_t dot_pos = -1; // Position of '.' in the name, if any. |
| bool is_setter = false; |
| for (intptr_t i = start; i < len; i++) { |
| if (unmangled_name[i] == ':') { |
| if (start != 0) { |
| // Reset and break. |
| start = 0; |
| dot_pos = -1; |
| break; |
| } |
| ASSERT(start == 0); // Only one : is possible in getters or setters. |
| if (unmangled_name[0] == 's') { |
| is_setter = true; |
| } |
| start = i + 1; |
| } else if (unmangled_name[i] == '.') { |
| if (dot_pos != -1) { |
| // Reset and break. |
| start = 0; |
| dot_pos = -1; |
| break; |
| } |
| ASSERT(dot_pos == -1); // Only one dot is supported. |
| dot_pos = i; |
| } |
| } |
| |
| if ((start == 0) && (dot_pos == -1)) { |
| // This unmangled_name is fine as it is. |
| return Symbols::New(unmangled_name, sum_segment_len); |
| } |
| |
| // Drop the trailing dot if needed. |
| intptr_t end = ((dot_pos + 1) == len) ? dot_pos : len; |
| |
| unmangled_segments.Clear(); |
| intptr_t final_len = end - start; |
| AppendSubString(zone, &unmangled_segments, unmangled_name, start, final_len); |
| if (is_setter) { |
| const char* equals = Symbols::Equals().ToCString(); |
| const intptr_t equals_len = strlen(equals); |
| AppendSubString(zone, &unmangled_segments, equals, 0, equals_len); |
| final_len += equals_len; |
| } |
| |
| unmangled_name = MergeSubStrings(zone, unmangled_segments, final_len); |
| |
| return Symbols::New(unmangled_name); |
| } |
| |
| |
| RawString* String::IdentifierPrettyNameRetainPrivate(const String& name) { |
| intptr_t len = name.Length(); |
| intptr_t start = 0; |
| intptr_t at_pos = -1; // Position of '@' in the name, if any. |
| bool is_setter = false; |
| |
| for (intptr_t i = start; i < len; i++) { |
| if (name.CharAt(i) == ':') { |
| ASSERT(start == 0); // Only one : is possible in getters or setters. |
| if (name.CharAt(0) == 's') { |
| is_setter = true; |
| } |
| start = i + 1; |
| } else if (name.CharAt(i) == '@') { |
| // Setters should have only one @ so we know where to put the =. |
| ASSERT(!is_setter || (at_pos == -1)); |
| at_pos = i; |
| } |
| } |
| |
| if (start == 0) { |
| // This unmangled_name is fine as it is. |
| return name.raw(); |
| } |
| |
| String& result = |
| String::Handle(String::SubString(name, start, (len - start))); |
| |
| if (is_setter) { |
| // Setters need to end with '='. |
| if (at_pos == -1) { |
| return String::Concat(result, Symbols::Equals()); |
| } else { |
| const String& pre_at = |
| String::Handle(String::SubString(result, 0, at_pos - 4)); |
| const String& post_at = |
| String::Handle(String::SubString(name, at_pos, len - at_pos)); |
| result = String::Concat(pre_at, Symbols::Equals()); |
| result = String::Concat(result, post_at); |
| } |
| } |
| |
| 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 == '$')); |
| } |
| |
| |
| static inline bool IsAsciiNonprintable(int32_t c) { |
| return ((0 <= c) && (c < 32)) || (c == 127); |
| } |
| |
| |
| static inline bool NeedsEscapeSequence(int32_t c) { |
| return (c == '"') || |
| (c == '\\') || |
| (c == '$') || |
| IsAsciiNonprintable(c); |
| } |
| |
| |
| static int32_t EscapeOverhead(int32_t c) { |
| if (IsSpecialCharacter(c)) { |
| return 1; // 1 additional byte for the backslash. |
| } else if (IsAsciiNonprintable(c)) { |
| return 3; // 3 additional bytes to encode c as \x00. |
| } |
| return 0; |
| } |
| |
| |
| 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'; |
| } |
| |
| |
| void Object::InitNull(Isolate* isolate) { |
| // Should only be run by the vm isolate. |
| ASSERT(isolate == Dart::vm_isolate()); |
| |
| // TODO(iposva): NoSafepointScope needs to be added here. |
| ASSERT(class_class() == null_); |
| |
| Heap* heap = isolate->heap(); |
| |
| // 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(), true); |
| } |
| } |
| |
| |
| void Object::InitOnce(Isolate* isolate) { |
| // Should only be run by the vm isolate. |
| ASSERT(isolate == Dart::vm_isolate()); |
| |
| // Initialize the static vtable values. |
| { |
| Object fake_object; |
| Smi fake_smi; |
| Object::handle_vtable_ = fake_object.vtable(); |
| Smi::handle_vtable_ = fake_smi.vtable(); |
| } |
| |
| Heap* heap = isolate->heap(); |
| |
| // Allocate the read only object handles here. |
| null_object_ = Object::ReadOnlyHandle(); |
| null_array_ = Array::ReadOnlyHandle(); |
| null_string_ = String::ReadOnlyHandle(); |
| null_instance_ = Instance::ReadOnlyHandle(); |
| null_type_arguments_ = TypeArguments::ReadOnlyHandle(); |
| empty_array_ = Array::ReadOnlyHandle(); |
| zero_array_ = Array::ReadOnlyHandle(); |
| empty_context_scope_ = ContextScope::ReadOnlyHandle(); |
| empty_object_pool_ = ObjectPool::ReadOnlyHandle(); |
| empty_descriptors_ = PcDescriptors::ReadOnlyHandle(); |
| empty_var_descriptors_ = LocalVarDescriptors::ReadOnlyHandle(); |
| empty_exception_handlers_ = ExceptionHandlers::ReadOnlyHandle(); |
| extractor_parameter_types_ = Array::ReadOnlyHandle(); |
| extractor_parameter_names_ = Array::ReadOnlyHandle(); |
| sentinel_ = Instance::ReadOnlyHandle(); |
| transition_sentinel_ = Instance::ReadOnlyHandle(); |
| unknown_constant_ = Instance::ReadOnlyHandle(); |
| non_constant_ = Instance::ReadOnlyHandle(); |
| bool_true_ = Bool::ReadOnlyHandle(); |
| bool_false_ = Bool::ReadOnlyHandle(); |
| smi_illegal_cid_ = Smi::ReadOnlyHandle(); |
| snapshot_writer_error_ = LanguageError::ReadOnlyHandle(); |
| branch_offset_error_ = LanguageError::ReadOnlyHandle(); |
| vm_isolate_snapshot_object_table_ = Array::ReadOnlyHandle(); |
| |
| *null_object_ = Object::null(); |
| *null_array_ = Array::null(); |
| *null_string_ = String::null(); |
| *null_instance_ = Instance::null(); |
| *null_type_arguments_ = TypeArguments::null(); |
| |
| // Initialize the empty and zero array handles to null_ in order to be able to |
| // check if the empty and zero arrays were allocated (RAW_NULL is not |
| // available). |
| *empty_array_ = Array::null(); |
| *zero_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, true); |
| |
| 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::NextFieldOffset()); |
| cls.set_id(Class::kClassId); |
| cls.set_state_bits(0); |
| cls.set_is_finalized(); |
| cls.set_is_type_finalized(); |
| cls.set_type_arguments_field_offset_in_words(Class::kNoTypeArguments); |
| cls.set_num_type_arguments(0); |
| cls.set_num_own_type_arguments(0); |
| cls.set_num_native_fields(0); |
| cls.InitEmptyFields(); |
| isolate->RegisterClass(cls); |
| } |
| |
| // Allocate and initialize the null class. |
| cls = Class::New<Instance>(kNullCid); |
| cls.set_num_type_arguments(0); |
| cls.set_num_own_type_arguments(0); |
| isolate->object_store()->set_null_class(cls); |
| |
| // Allocate and initialize the free list element class. |
| cls = Class::New<FreeListElement::FakeInstance>(kFreeListElement); |
| cls.set_num_type_arguments(0); |
| cls.set_num_own_type_arguments(0); |
| cls.set_is_finalized(); |
| cls.set_is_type_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); |
| } |
| |
| // Allocate and initialize optimizing compiler constants. |
| { |
| *unknown_constant_ ^= |
| Object::Allocate(kNullCid, Instance::InstanceSize(), Heap::kOld); |
| *non_constant_ ^= |
| Object::Allocate(kNullCid, Instance::InstanceSize(), Heap::kOld); |
| } |
| |
| // Allocate the remaining VM internal classes. |
| cls = Class::New<UnresolvedClass>(); |
| unresolved_class_class_ = cls.raw(); |
| |
| cls = Class::New<TypeArguments>(); |
| 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<Namespace>(); |
| namespace_class_ = cls.raw(); |
| |
| cls = Class::New<Code>(); |
| code_class_ = cls.raw(); |
| |
| cls = Class::New<Instructions>(); |
| instructions_class_ = cls.raw(); |
| |
| cls = Class::New<ObjectPool>(); |
| object_pool_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<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.set_num_type_arguments(1); |
| cls.set_num_own_type_arguments(1); |
| cls = Class::New<Array>(kImmutableArrayCid); |
| isolate->object_store()->set_immutable_array_class(cls); |
| cls.set_type_arguments_field_offset(Array::type_arguments_offset()); |
| cls.set_num_type_arguments(1); |
| cls.set_num_own_type_arguments(1); |
| 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); |
| cls = Class::New<Mint>(); |
| isolate->object_store()->set_mint_class(cls); |
| cls = Class::New<Bigint>(); |
| isolate->object_store()->set_bigint_class(cls); |
| cls = Class::New<Double>(); |
| isolate->object_store()->set_double_class(cls); |
| |
| // Ensure that class kExternalTypedDataUint8ArrayCid is registered as we |
| // need it when reading in the token stream of bootstrap classes in the VM |
| // isolate. |
| Class::NewExternalTypedDataClass(kExternalTypedDataUint8ArrayCid); |
| |
| // Needed for object pools of VM isolate stubs. |
| Class::NewTypedDataClass(kTypedDataInt8ArrayCid); |
| |
| // Allocate and initialize the empty_array instance. |
| { |
| uword address = heap->Allocate(Array::InstanceSize(0), Heap::kOld); |
| InitializeObject(address, kImmutableArrayCid, Array::InstanceSize(0), true); |
| Array::initializeHandle( |
| empty_array_, |
| reinterpret_cast<RawArray*>(address + kHeapObjectTag)); |
| empty_array_->StoreSmi(&empty_array_->raw_ptr()->length_, Smi::New(0)); |
| } |
| |
| Smi& smi = Smi::Handle(); |
| // Allocate and initialize the zero_array instance. |
| { |
| uword address = heap->Allocate(Array::InstanceSize(1), Heap::kOld); |
| InitializeObject(address, kImmutableArrayCid, Array::InstanceSize(1), true); |
| Array::initializeHandle( |
| zero_array_, |
| reinterpret_cast<RawArray*>(address + kHeapObjectTag)); |
| zero_array_->StoreSmi(&zero_array_->raw_ptr()->length_, Smi::New(1)); |
| smi = Smi::New(0); |
| zero_array_->SetAt(0, smi); |
| } |
| |
| // Allocate and initialize the canonical empty context scope object. |
| { |
| uword address = heap->Allocate(ContextScope::InstanceSize(0), Heap::kOld); |
| InitializeObject(address, |
| kContextScopeCid, |
| ContextScope::InstanceSize(0), |
| true); |
| ContextScope::initializeHandle( |
| empty_context_scope_, |
| reinterpret_cast<RawContextScope*>(address + kHeapObjectTag)); |
| empty_context_scope_->StoreNonPointer( |
| &empty_context_scope_->raw_ptr()->num_variables_, 0); |
| empty_context_scope_->StoreNonPointer( |
| &empty_context_scope_->raw_ptr()->is_implicit_, true); |
| } |
| |
| // Allocate and initialize the canonical empty object pool object. |
| { |
| uword address = |
| heap->Allocate(ObjectPool::InstanceSize(0), Heap::kOld); |
| InitializeObject(address, |
| kObjectPoolCid, |
| ObjectPool::InstanceSize(0), |
| true); |
| ObjectPool::initializeHandle( |
| empty_object_pool_, |
| reinterpret_cast<RawObjectPool*>(address + kHeapObjectTag)); |
| empty_object_pool_->StoreNonPointer( |
| &empty_object_pool_->raw_ptr()->length_, 0); |
| } |
| |
| // Allocate and initialize the empty_descriptors instance. |
| { |
| uword address = heap->Allocate(PcDescriptors::InstanceSize(0), Heap::kOld); |
| InitializeObject(address, kPcDescriptorsCid, |
| PcDescriptors::InstanceSize(0), |
| true); |
| PcDescriptors::initializeHandle( |
| empty_descriptors_, |
| reinterpret_cast<RawPcDescriptors*>(address + kHeapObjectTag)); |
| empty_descriptors_->StoreNonPointer(&empty_descriptors_->raw_ptr()->length_, |
| 0); |
| } |
| |
| // Allocate and initialize the canonical empty variable descriptor object. |
| { |
| uword address = |
| heap->Allocate(LocalVarDescriptors::InstanceSize(0), Heap::kOld); |
| InitializeObject(address, |
| kLocalVarDescriptorsCid, |
| LocalVarDescriptors::InstanceSize(0), |
| true); |
| LocalVarDescriptors::initializeHandle( |
| empty_var_descriptors_, |
| reinterpret_cast<RawLocalVarDescriptors*>(address + kHeapObjectTag)); |
| empty_var_descriptors_->StoreNonPointer( |
| &empty_var_descriptors_->raw_ptr()->num_entries_, 0); |
| } |
| |
| // Allocate and initialize the canonical empty exception handler info object. |
| // The vast majority of all functions do not contain an exception handler |
| // and can share this canonical descriptor. |
| { |
| uword address = |
| heap->Allocate(ExceptionHandlers::InstanceSize(0), Heap::kOld); |
| InitializeObject(address, |
| kExceptionHandlersCid, |
| ExceptionHandlers::InstanceSize(0), |
| true); |
| ExceptionHandlers::initializeHandle( |
| empty_exception_handlers_, |
| reinterpret_cast<RawExceptionHandlers*>(address + kHeapObjectTag)); |
| empty_exception_handlers_->StoreNonPointer( |
| &empty_exception_handlers_->raw_ptr()->num_entries_, 0); |
| } |
| |
| // The VM isolate snapshot object table is initialized to an empty array |
| // as we do not have any VM isolate snapshot at this time. |
| *vm_isolate_snapshot_object_table_ = Object::empty_array().raw(); |
| |
| cls = Class::New<Instance>(kDynamicCid); |
| cls.set_is_abstract(); |
| cls.set_num_type_arguments(0); |
| cls.set_num_own_type_arguments(0); |
| cls.set_is_type_finalized(); |
| cls.set_is_finalized(); |
| dynamic_class_ = cls.raw(); |
| |
| cls = Class::New<Instance>(kVoidCid); |
| cls.set_num_type_arguments(0); |
| cls.set_num_own_type_arguments(0); |
| cls.set_is_type_finalized(); |
| cls.set_is_finalized(); |
| void_class_ = cls.raw(); |
| |
| cls = Class::New<Type>(); |
| cls.set_is_type_finalized(); |
| cls.set_is_finalized(); |
| |
| cls = dynamic_class_; |
| dynamic_type_ = Type::NewNonParameterizedType(cls); |
| |
| cls = void_class_; |
| void_type_ = Type::NewNonParameterizedType(cls); |
| |
| // 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); |
| |
| *smi_illegal_cid_ = Smi::New(kIllegalCid); |
| |
| String& error_str = String::Handle(); |
| error_str = String::New("SnapshotWriter Error", Heap::kOld); |
| *snapshot_writer_error_ = LanguageError::New(error_str, |
| Report::kError, |
| Heap::kOld); |
| error_str = String::New("Branch offset overflow", Heap::kOld); |
| *branch_offset_error_ = LanguageError::New(error_str, |
| Report::kBailout, |
| Heap::kOld); |
| |
| ASSERT(!null_object_->IsSmi()); |
| ASSERT(!null_array_->IsSmi()); |
| ASSERT(null_array_->IsArray()); |
| ASSERT(!null_string_->IsSmi()); |
| ASSERT(null_string_->IsString()); |
| ASSERT(!null_instance_->IsSmi()); |
| ASSERT(null_instance_->IsInstance()); |
| ASSERT(!null_type_arguments_->IsSmi()); |
| ASSERT(null_type_arguments_->IsTypeArguments()); |
| ASSERT(!empty_array_->IsSmi()); |
| ASSERT(empty_array_->IsArray()); |
| ASSERT(!zero_array_->IsSmi()); |
| ASSERT(zero_array_->IsArray()); |
| ASSERT(!empty_context_scope_->IsSmi()); |
| ASSERT(empty_context_scope_->IsContextScope()); |
| ASSERT(!empty_descriptors_->IsSmi()); |
| ASSERT(empty_descriptors_->IsPcDescriptors()); |
| ASSERT(!empty_var_descriptors_->IsSmi()); |
| ASSERT(empty_var_descriptors_->IsLocalVarDescriptors()); |
| ASSERT(!empty_exception_handlers_->IsSmi()); |
| ASSERT(empty_exception_handlers_->IsExceptionHandlers()); |
| ASSERT(!sentinel_->IsSmi()); |
| ASSERT(sentinel_->IsInstance()); |
| ASSERT(!transition_sentinel_->IsSmi()); |
| ASSERT(transition_sentinel_->IsInstance()); |
| ASSERT(!unknown_constant_->IsSmi()); |
| ASSERT(unknown_constant_->IsInstance()); |
| ASSERT(!non_constant_->IsSmi()); |
| ASSERT(non_constant_->IsInstance()); |
| ASSERT(!bool_true_->IsSmi()); |
| ASSERT(bool_true_->IsBool()); |
| ASSERT(!bool_false_->IsSmi()); |
| ASSERT(bool_false_->IsBool()); |
| ASSERT(smi_illegal_cid_->IsSmi()); |
| ASSERT(!snapshot_writer_error_->IsSmi()); |
| ASSERT(snapshot_writer_error_->IsLanguageError()); |
| ASSERT(!branch_offset_error_->IsSmi()); |
| ASSERT(branch_offset_error_->IsLanguageError()); |
| ASSERT(!vm_isolate_snapshot_object_table_->IsSmi()); |
| ASSERT(vm_isolate_snapshot_object_table_->IsArray()); |
| } |
| |
| |
| // An object visitor which will mark all visited objects. This is used to |
| // premark all objects in the vm_isolate_ heap. |
| class PremarkingVisitor : public ObjectVisitor { |
| public: |
| explicit PremarkingVisitor(Isolate* isolate) : ObjectVisitor(isolate) {} |
| |
| void VisitObject(RawObject* obj) { |
| // Free list elements should never be marked. |
| if (!obj->IsFreeListElement()) { |
| ASSERT(obj->IsVMHeapObject()); |
| if (obj->IsMarked()) { |
| // Precompiled instructions are loaded pre-marked. |
| ASSERT(Dart::IsRunningPrecompiledCode()); |
| ASSERT(obj->IsInstructions()); |
| } else { |
| obj->SetMarkBitUnsynchronized(); |
| } |
| } |
| } |
| }; |
| |
| |
| #define SET_CLASS_NAME(class_name, name) \ |
| cls = class_name##_class(); \ |
| cls.set_name(Symbols::name()); \ |
| |
| void Object::FinalizeVMIsolate(Isolate* isolate) { |
| // Should only be run by the vm isolate. |
| ASSERT(isolate == Dart::vm_isolate()); |
| |
| // Allocate the parameter arrays for method extractor types and names. |
| *extractor_parameter_types_ = Array::New(1, Heap::kOld); |
| extractor_parameter_types_->SetAt(0, Type::Handle(Type::DynamicType())); |
| *extractor_parameter_names_ = Array::New(1, Heap::kOld); |
| extractor_parameter_names_->SetAt(0, Symbols::This()); |
| |
| ASSERT(!extractor_parameter_types_->IsSmi()); |
| ASSERT(extractor_parameter_types_->IsArray()); |
| ASSERT(!extractor_parameter_names_->IsSmi()); |
| ASSERT(extractor_parameter_names_->IsArray()); |
| |
| |
| // Set up names for all VM singleton classes. |
| Class& cls = Class::Handle(); |
| |
| SET_CLASS_NAME(class, Class); |
| 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(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(namespace, Namespace); |
| SET_CLASS_NAME(code, Code); |
| SET_CLASS_NAME(instructions, Instructions); |
| SET_CLASS_NAME(object_pool, ObjectPool); |
| 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(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 = isolate->object_store()->array_class(); |
| cls.set_name(Symbols::_List()); |
| cls = isolate->object_store()->one_byte_string_class(); |
| cls.set_name(Symbols::OneByteString()); |
| |
| { |
| ASSERT(isolate == Dart::vm_isolate()); |
| WritableVMIsolateScope scope(Thread::Current()); |
| PremarkingVisitor premarker(isolate); |
| ASSERT(isolate->heap()->UsedInWords(Heap::kNew) == 0); |
| isolate->heap()->IterateOldObjects(&premarker); |
| // Make the VM isolate read-only again after setting all objects as marked. |
| } |
| } |
| |
| |
| void Object::InitVmIsolateSnapshotObjectTable(intptr_t len) { |
| ASSERT(Isolate::Current() == Dart::vm_isolate()); |
| *vm_isolate_snapshot_object_table_ = Array::New(len, Heap::kOld); |
| } |
| |
| |
| // 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(Thread::Current()->no_safepoint_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 a TypedDataInt8Array object. |
| RawTypedData* raw = |
| reinterpret_cast<RawTypedData*>(RawObject::FromAddr(addr)); |
| uword new_tags = RawObject::ClassIdTag::update(kTypedDataInt8ArrayCid, 0); |
| new_tags = RawObject::SizeTag::update(leftover_size, new_tags); |
| uword tags = raw->ptr()->tags_; |
| uword old_tags; |
| // TODO(iposva): Investigate whether CompareAndSwapWord is necessary. |
| do { |
| old_tags = tags; |
| tags = AtomicOperations::CompareAndSwapWord( |
| &raw->ptr()->tags_, old_tags, new_tags); |
| } while (tags != old_tags); |
| |
| intptr_t leftover_len = (leftover_size - TypedData::InstanceSize(0)); |
| ASSERT(TypedData::InstanceSize(leftover_len) == leftover_size); |
| raw->InitializeSmi(&(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 new_tags = RawObject::ClassIdTag::update(kInstanceCid, 0); |
| new_tags = RawObject::SizeTag::update(leftover_size, new_tags); |
| uword tags = raw->ptr()->tags_; |
| uword old_tags; |
| // TODO(iposva): Investigate whether CompareAndSwapWord is necessary. |
| do { |
| old_tags = tags; |
| tags = AtomicOperations::CompareAndSwapWord( |
| &raw->ptr()->tags_, old_tags, new_tags); |
| } while (tags != old_tags); |
| } |
| } |
| } |
| |
| |
| void Object::VerifyBuiltinVtables() { |
| #if defined(DEBUG) |
| Thread* thread = Thread::Current(); |
| Isolate* isolate = thread->isolate(); |
| Class& cls = Class::Handle(thread->zone(), 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_); |
| } |
| } |
| ASSERT(builtin_vtables_[kFreeListElement] == 0); |
| #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); |
| } |
| |
| |
| RawError* Object::Init(Isolate* isolate) { |
| Thread* thread = Thread::Current(); |
| Zone* zone = thread->zone(); |
| ASSERT(isolate == thread->isolate()); |
| TimelineDurationScope tds(thread, |
| isolate->GetIsolateStream(), |
| "Object::Init"); |
| |
| #if defined(DART_NO_SNAPSHOT) |
| // Object::Init version when we are running in a version of dart that does |
| // not have a full snapshot linked in. |
| ObjectStore* object_store = isolate->object_store(); |
| |
| Class& cls = Class::Handle(zone); |
| Type& type = Type::Handle(zone); |
| Array& array = Array::Handle(zone); |
| Library& lib = Library::Handle(zone); |
| |
| // 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); |
| |
| // VM classes that are parameterized (Array, ImmutableArray, |
| // GrowableObjectArray, and LinkedHashMap) are also pre-finalized, |
| // so CalculateFieldOffsets() is not called, so we need to set the |
| // offset of their type_arguments_ field, which is explicitly |
| // declared in their respective Raw* classes. |
| cls.set_type_arguments_field_offset(Array::type_arguments_offset()); |
| cls.set_num_type_arguments(1); |
| |
| // 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()); |
| cls.set_num_type_arguments(1); |
| |
| // 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(zone, Smi::New(0))); |
| object_store->set_canonical_type_arguments(array); |
| |
| // Setup type class early in the process. |
| const Class& type_cls = Class::Handle(zone, Class::New<Type>()); |
| const Class& type_ref_cls = Class::Handle(zone, Class::New<TypeRef>()); |
| const Class& type_parameter_cls = Class::Handle(zone, |
| Class::New<TypeParameter>()); |
| const Class& bounded_type_cls = Class::Handle(zone, |
| Class::New<BoundedType>()); |
| const Class& mixin_app_type_cls = Class::Handle(zone, |
| Class::New<MixinAppType>()); |
| const Class& library_prefix_cls = Class::Handle(zone, |
| Class::New<LibraryPrefix>()); |
| |
| // 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( |
| zone, 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. |
| const Library& core_lib = Library::Handle(zone, Library::CoreLibrary()); |
| ASSERT(!core_lib.IsNull()); |
| |
| const GrowableObjectArray& pending_classes = |
| GrowableObjectArray::Handle(zone, GrowableObjectArray::New()); |
| object_store->set_pending_classes(pending_classes); |
| |
| Context& context = Context::Handle(zone, 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(zone); |
| cls = object_store->array_class(); // Was allocated above. |
| RegisterPrivateClass(cls, Symbols::_List(), core_lib); |
| pending_classes.Add(cls); |
| // We cannot use NewNonParameterizedType(cls), because Array is parameterized. |
| // Warning: class _List has not been patched yet. Its declared number of type |
| // parameters is still 0. It will become 1 after patching. The array type |
| // allocated below represents the raw type _List and not _List<E> as we |
| // could expect. Use with caution. |
| type ^= Type::New(Object::Handle(zone, cls.raw()), |
| TypeArguments::Handle(zone), |
| Scanner::kNoSourcePos); |
| type.SetIsFinalized(); |
| type ^= type.Canonicalize(); |
| object_store->set_array_type(type); |
| |
| cls = object_store->growable_object_array_class(); // Was allocated above. |
| RegisterPrivateClass(cls, Symbols::_GrowableList(), core_lib); |
| pending_classes.Add(cls); |
| |
| cls = Class::New<Array>(kImmutableArrayCid); |
| object_store->set_immutable_array_class(cls); |
| cls.set_type_arguments_field_offset(Array::type_arguments_offset()); |
| cls.set_num_type_arguments(1); |
| ASSERT(object_store->immutable_array_class() != object_store->array_class()); |
| cls.set_is_prefinalized(); |
| RegisterPrivateClass(cls, Symbols::_ImmutableList(), core_lib); |
| pending_classes.Add(cls); |
| |
| cls = object_store->one_byte_string_class(); // Was allocated above. |
| RegisterPrivateClass(cls, Symbols::OneByteString(), core_lib); |
| pending_classes.Add(cls); |
| |
| cls = object_store->two_byte_string_class(); // Was allocated above. |
| RegisterPrivateClass(cls, Symbols::TwoByteString(), core_lib); |
| pending_classes.Add(cls); |
| |
| cls = Class::NewStringClass(kExternalOneByteStringCid); |
| object_store->set_external_one_byte_string_class(cls); |
| RegisterPrivateClass(cls, Symbols::ExternalOneByteString(), core_lib); |
| pending_classes.Add(cls); |
| |
| cls = Class::NewStringClass(kExternalTwoByteStringCid); |
| object_store->set_external_two_byte_string_class(cls); |
| RegisterPrivateClass(cls, Symbols::ExternalTwoByteString(), core_lib); |
| pending_classes.Add(cls); |
| |
| // Pre-register the isolate library so the native class implementations |
| // can be hooked up before compiling it. |
| Library& isolate_lib = |
| Library::Handle(zone, Library::LookupLibrary(Symbols::DartIsolate())); |
| if (isolate_lib.IsNull()) { |
| isolate_lib = Library::NewLibraryHelper(Symbols::DartIsolate(), true); |
| isolate_lib.SetLoadRequested(); |
| isolate_lib.Register(); |
| object_store->set_bootstrap_library(ObjectStore::kIsolate, isolate_lib); |
| } |
| ASSERT(!isolate_lib.IsNull()); |
| ASSERT(isolate_lib.raw() == Library::IsolateLibrary()); |
| |
| cls = Class::New<Capability>(); |
| RegisterPrivateClass(cls, Symbols::_CapabilityImpl(), isolate_lib); |
| pending_classes.Add(cls); |
| |
| cls = Class::New<ReceivePort>(); |
| RegisterPrivateClass(cls, Symbols::_RawReceivePortImpl(), isolate_lib); |
| pending_classes.Add(cls); |
| |
| cls = Class::New<SendPort>(); |
| RegisterPrivateClass(cls, Symbols::_SendPortImpl(), isolate_lib); |
| pending_classes.Add(cls); |
| |
| const Class& stacktrace_cls = Class::Handle(zone, |
| Class::New<Stacktrace>()); |
| RegisterPrivateClass(stacktrace_cls, Symbols::_StackTrace(), core_lib); |
| pending_classes.Add(stacktrace_cls); |
| // Super type set below, after Object is allocated. |
| |
| cls = Class::New<JSRegExp>(); |
| RegisterPrivateClass(cls, Symbols::JSSyntaxRegExp(), core_lib); |
| pending_classes.Add(cls); |
| |
| // Initialize the base interfaces used by the core VM classes. |
| |
| // Allocate and initialize the pre-allocated classes in the core library. |
| // The script and token index of these pre-allocated classes is set up in |
| // the parser when the corelib script is compiled (see |
| // Parser::ParseClassDefinition). |
| cls = Class::New<Instance>(kInstanceCid); |
| object_store->set_object_class(cls); |
| cls.set_name(Symbols::Object()); |
| cls.set_num_type_arguments(0); |
| cls.set_num_own_type_arguments(0); |
| cls.set_is_prefinalized(); |
| core_lib.AddClass(cls); |
| pending_classes.Add(cls); |
| type = Type::NewNonParameterizedType(cls); |
| object_store->set_object_type(type); |
| |
| cls = Class::New<Bool>(); |
| object_store->set_bool_class(cls); |
| RegisterClass(cls, Symbols::Bool(), core_lib); |
| pending_classes.Add(cls); |
| |
| cls = Class::New<Instance>(kNullCid); |
| object_store->set_null_class(cls); |
| cls.set_num_type_arguments(0); |
| cls.set_num_own_type_arguments(0); |
| cls.set_is_prefinalized(); |
| RegisterClass(cls, Symbols::Null(), core_lib); |
| pending_classes.Add(cls); |
| |
| ASSERT(!library_prefix_cls.IsNull()); |
| RegisterPrivateClass(library_prefix_cls, Symbols::_LibraryPrefix(), core_lib); |
| pending_classes.Add(library_prefix_cls); |
| |
| RegisterPrivateClass(type_cls, Symbols::Type(), core_lib); |
| pending_classes.Add(type_cls); |
| |
| RegisterPrivateClass(type_ref_cls, Symbols::TypeRef(), core_lib); |
| pending_classes.Add(type_ref_cls); |
| |
| RegisterPrivateClass(type_parameter_cls, Symbols::TypeParameter(), core_lib); |
| pending_classes.Add(type_parameter_cls); |
| |
| RegisterPrivateClass(bounded_type_cls, Symbols::BoundedType(), core_lib); |
| pending_classes.Add(bounded_type_cls); |
| |
| RegisterPrivateClass(mixin_app_type_cls, Symbols::MixinAppType(), core_lib); |
| pending_classes.Add(mixin_app_type_cls); |
| |
| cls = Class::New<Integer>(); |
| object_store->set_integer_implementation_class(cls); |
| RegisterPrivateClass(cls, Symbols::IntegerImplementation(), core_lib); |
| pending_classes.Add(cls); |
| |
| cls = Class::New<Smi>(); |
| object_store->set_smi_class(cls); |
| RegisterPrivateClass(cls, Symbols::_Smi(), core_lib); |
| pending_classes.Add(cls); |
| |
| cls = Class::New<Mint>(); |
| object_store->set_mint_class(cls); |
| RegisterPrivateClass(cls, Symbols::_Mint(), core_lib); |
| pending_classes.Add(cls); |
| |
| cls = Class::New<Bigint>(); |
| object_store->set_bigint_class(cls); |
| RegisterPrivateClass(cls, Symbols::_Bigint(), core_lib); |
| pending_classes.Add(cls); |
| |
| cls = Class::New<Double>(); |
| object_store->set_double_class(cls); |
| RegisterPrivateClass(cls, Symbols::_Double(), core_lib); |
| pending_classes.Add(cls); |
| |
| // Abstract super class for all signature classes. |
| cls = Class::New<Instance>(kIllegalCid); |
| cls.set_num_type_arguments(0); |
| cls.set_num_own_type_arguments(0); |
| cls.set_is_prefinalized(); |
| RegisterPrivateClass(cls, Symbols::FunctionImpl(), core_lib); |
| pending_classes.Add(cls); |
| type = Type::NewNonParameterizedType(cls); |
| object_store->set_function_impl_type(type); |
| |
| cls = Class::New<WeakProperty>(); |
| object_store->set_weak_property_class(cls); |
| RegisterPrivateClass(cls, Symbols::_WeakProperty(), core_lib); |
| |
| // Pre-register the mirrors library so we can place the vm class |
| // MirrorReference there rather than the core library. |
| lib = Library::LookupLibrary(Symbols::DartMirrors()); |
| if (lib.IsNull()) { |
| lib = Library::NewLibraryHelper(Symbols::DartMirrors(), true); |
| lib.SetLoadRequested(); |
| lib.Register(); |
| object_store->set_bootstrap_library(ObjectStore::kMirrors, lib); |
| } |
| ASSERT(!lib.IsNull()); |
| ASSERT(lib.raw() == Library::MirrorsLibrary()); |
| |
| cls = Class::New<MirrorReference>(); |
| RegisterPrivateClass(cls, Symbols::_MirrorReference(), lib); |
| |
| // Pre-register the collection library so we can place the vm class |
| // LinkedHashMap there rather than the core library. |
| lib = Library::LookupLibrary(Symbols::DartCollection()); |
| if (lib.IsNull()) { |
| lib = Library::NewLibraryHelper(Symbols::DartCollection(), true); |
| lib.SetLoadRequested(); |
| lib.Register(); |
| object_store->set_bootstrap_library(ObjectStore::kCollection, lib); |
| } |
| ASSERT(!lib.IsNull()); |
| ASSERT(lib.raw() == Library::CollectionLibrary()); |
| cls = Class::New<LinkedHashMap>(); |
| object_store->set_linked_hash_map_class(cls); |
| cls.set_type_arguments_field_offset(LinkedHashMap::type_arguments_offset()); |
| cls.set_num_type_arguments(2); |
| cls.set_num_own_type_arguments(2); |
| RegisterPrivateClass(cls, Symbols::_LinkedHashMap(), lib); |
| pending_classes.Add(cls); |
| |
| // Pre-register the developer library so we can place the vm class |
| // UserTag there rather than the core library. |
| lib = Library::LookupLibrary(Symbols::DartDeveloper()); |
| if (lib.IsNull()) { |
| lib = Library::NewLibraryHelper(Symbols::DartDeveloper(), true); |
| lib.SetLoadRequested(); |
| lib.Register(); |
| object_store->set_bootstrap_library(ObjectStore::kDeveloper, lib); |
| } |
| ASSERT(!lib.IsNull()); |
| ASSERT(lib.raw() == Library::DeveloperLibrary()); |
| |
| lib = Library::LookupLibrary(Symbols::DartDeveloper()); |
| ASSERT(!lib.IsNull()); |
| cls = Class::New<UserTag>(); |
| RegisterPrivateClass(cls, Symbols::_UserTag(), lib); |
| pending_classes.Add(cls); |
| |
| // Setup some default native field classes which can be extended for |
| // specifying native fields in dart classes. |
| Library::InitNativeWrappersLibrary(isolate); |
| ASSERT(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. |
| lib = Library::LookupLibrary(Symbols::DartTypedData()); |
| if (lib.IsNull()) { |
| lib = Library::NewLibraryHelper(Symbols::DartTypedData(), true); |
| lib.SetLoadRequested(); |
| lib.Register(); |
| object_store->set_bootstrap_library(ObjectStore::kTypedData, lib); |
| } |
| ASSERT(!lib.IsNull()); |
| ASSERT(lib.raw() == Library::TypedDataLibrary()); |
| #define REGISTER_TYPED_DATA_CLASS(clazz) \ |
| cls = Class::NewTypedDataClass(kTypedData##clazz##Cid); \ |
| 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); \ |
| RegisterPrivateClass(cls, Symbols::_##clazz##View(), lib); \ |
| pending_classes.Add(cls); \ |
| |
| CLASS_LIST_TYPED_DATA(REGISTER_TYPED_DATA_VIEW_CLASS); |
| cls = Class::NewTypedDataViewClass(kByteDataViewCid); |
| RegisterPrivateClass(cls, Symbols::_ByteDataView(), lib); |
| pending_classes.Add(cls); |
| #undef REGISTER_TYPED_DATA_VIEW_CLASS |
| #define REGISTER_EXT_TYPED_DATA_CLASS(clazz) \ |
| cls = Class::NewExternalTypedDataClass(kExternalTypedData##clazz##Cid); \ |
| RegisterPrivateClass(cls, Symbols::_External##clazz(), lib); \ |
| |
| cls = Class::New<Instance>(kByteBufferCid); |
| cls.set_instance_size(0); |
| cls.set_next_field_offset(-kWordSize); |
| RegisterPrivateClass(cls, Symbols::_ByteBuffer(), lib); |
| pending_classes.Add(cls); |
| |
| CLASS_LIST_TYPED_DATA(REGISTER_EXT_TYPED_DATA_CLASS); |
| #undef REGISTER_EXT_TYPED_DATA_CLASS |
| // Register Float32x4 and Int32x4 in the object store. |
| cls = Class::New<Float32x4>(); |
| object_store->set_float32x4_class(cls); |
| RegisterPrivateClass(cls, Symbols::_Float32x4(), lib); |
| cls = Class::New<Int32x4>(); |
| object_store->set_int32x4_class(cls); |
| RegisterPrivateClass(cls, Symbols::_Int32x4(), lib); |
| cls = Class::New<Float64x2>(); |
| object_store->set_float64x2_class(cls); |
| RegisterPrivateClass(cls, Symbols::_Float64x2(), lib); |
| |
| cls = Class::New<Instance>(kIllegalCid); |
| RegisterClass(cls, Symbols::Float32x4(), lib); |
| cls.set_num_type_arguments(0); |
| cls.set_num_own_type_arguments(0); |
| cls.set_is_prefinalized(); |
| pending_classes.Add(cls); |
| type = Type::NewNonParameterizedType(cls); |
| object_store->set_float32x4_type(type); |
| |
| cls = Class::New<Instance>(kIllegalCid); |
| RegisterClass(cls, Symbols::Int32x4(), lib); |
| cls.set_num_type_arguments(0); |
| cls.set_num_own_type_arguments(0); |
| cls.set_is_prefinalized(); |
| pending_classes.Add(cls); |
| type = Type::NewNonParameterizedType(cls); |
| object_store->set_int32x4_type(type); |
| |
| cls = Class::New<Instance>(kIllegalCid); |
| RegisterClass(cls, Symbols::Float64x2(), lib); |
| cls.set_num_type_arguments(0); |
| cls.set_num_own_type_arguments(0); |
| cls.set_is_prefinalized(); |
| pending_classes.Add(cls); |
| type = Type::NewNonParameterizedType(cls); |
| object_store->set_float64x2_type(type); |
| |
| // Set the super type of class Stacktrace to Object type so that the |
| // 'toString' method is implemented. |
| type = object_store->object_type(); |
| stacktrace_cls.set_super_type(type); |
| |
| // Abstract class that represents the Dart class Function. |
| cls = Class::New<Instance>(kIllegalCid); |
| cls.set_num_type_arguments(0); |
| cls.set_num_own_type_arguments(0); |
| cls.set_is_prefinalized(); |
| RegisterClass(cls, Symbols::Function(), core_lib); |
| pending_classes.Add(cls); |
| type = Type::NewNonParameterizedType(cls); |
| object_store->set_function_type(type); |
| |
| cls = Class::New<Number>(); |
| RegisterClass(cls, Symbols::Number(), core_lib); |
| pending_classes.Add(cls); |
| type = Type::NewNonParameterizedType(cls); |
| object_store->set_number_type(type); |
| |
| cls = Class::New<Instance>(kIllegalCid); |
| RegisterClass(cls, Symbols::Int(), core_lib); |
| cls.set_num_type_arguments(0); |
| cls.set_num_own_type_arguments(0); |
| cls.set_is_prefinalized(); |
| pending_classes.Add(cls); |
| type = Type::NewNonParameterizedType(cls); |
| object_store->set_int_type(type); |
| |
| cls = Class::New<Instance>(kIllegalCid); |
| RegisterClass(cls, Symbols::Double(), core_lib); |
| cls.set_num_type_arguments(0); |
| cls.set_num_own_type_arguments(0); |
| cls.set_is_prefinalized(); |
| pending_classes.Add(cls); |
| type = Type::NewNonParameterizedType(cls); |
| object_store->set_double_type(type); |
| |
| name = Symbols::New("String"); |
| cls = Class::New<Instance>(kIllegalCid); |
| RegisterClass(cls, name, core_lib); |
| cls.set_num_type_arguments(0); |
| cls.set_num_own_type_arguments(0); |
| cls.set_is_prefinalized(); |
| pending_classes.Add(cls); |
| type = Type::NewNonParameterizedType(cls); |
| object_store->set_string_type(type); |
| |
| 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 'void' and 'dynamic' are phoney classes to make type checking |
| // more regular; they live in the VM isolate. The class 'void' is not |
| // registered in the class dictionary because its name is a reserved word. |
| // The class 'dynamic' is registered in the class dictionary because its name |
| // is a built-in identifier (this is wrong). |
| // The corresponding types are stored in the object store. |
| cls = object_store->null_class(); |
| type = Type::NewNonParameterizedType(cls); |
| object_store->set_null_type(type); |
| |
| // Consider removing when/if Null becomes an ordinary class. |
| type = object_store->object_type(); |
| cls.set_super_type(type); |
| |
| // Finish the initialization by compiling the bootstrap scripts containing the |
| // base interfaces and the implementation of the internal classes. |
| const Error& error = Error::Handle(Bootstrap::LoadandCompileScripts()); |
| if (!error.IsNull()) { |
| return error.raw(); |
| } |
| |
| ClassFinalizer::VerifyBootstrapClasses(); |
| |
| // Set up the intrinsic state of all functions (core, math and typed data). |
| Intrinsifier::InitializeState(); |
| |
| // Set up recognized state of all functions (core, math and typed data). |
| MethodRecognizer::InitializeState(); |
| |
| // Adds static const fields (class ids) to the class 'ClassID'); |
| lib = Library::LookupLibrary(Symbols::DartInternal()); |
| ASSERT(!lib.IsNull()); |
| cls = lib.LookupClassAllowPrivate(Symbols::ClassID()); |
| ASSERT(!cls.IsNull()); |
| Field& field = Field::Handle(zone); |
| Smi& value = Smi::Handle(zone); |
| String& field_name = String::Handle(zone); |
| |
| #define CLASS_LIST_WITH_NULL(V) \ |
| V(Null) \ |
| CLASS_LIST_NO_OBJECT(V) |
| |
| #define ADD_SET_FIELD(clazz) \ |
| field_name = Symbols::New("cid"#clazz); \ |
| field = Field::New(field_name, true, false, true, false, cls, 0); \ |
| value = Smi::New(k##clazz##Cid); \ |
| field.SetStaticValue(value, true); \ |
| field.set_type(Type::Handle(Type::IntType())); \ |
| cls.AddField(field); \ |
| |
| CLASS_LIST_WITH_NULL(ADD_SET_FIELD) |
| #undef ADD_SET_FIELD |
| |
| isolate->object_store()->InitKnownObjects(); |
| |
| return Error::null(); |
| #else // defined(DART_NO_SNAPSHOT). |
| // Object::Init version when we are running in a version of dart that has |
| // a full snapshot linked in and an isolate is initialized using the full |
| // snapshot. |
| 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. |
| // 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<Instance>(kInstanceCid); |
| object_store->set_object_class(cls); |
| |
| cls = Class::New<LibraryPrefix>(); |
| cls = Class::New<Type>(); |
| cls = Class::New<TypeRef>(); |
| cls = Class::New<TypeParameter>(); |
| cls = Class::New<BoundedType>(); |
| cls = Class::New<MixinAppType>(); |
| |
| cls = Class::New<Array>(); |
| object_store->set_array_class(cls); |
| |
| cls = Class::New<Array>(kImmutableArrayCid); |
| object_store->set_immutable_array_class(cls); |
| |
| cls = Class::New<GrowableObjectArray>(); |
| object_store->set_growable_object_array_class(cls); |
| |
| cls = Class::New<LinkedHashMap>(); |
| object_store->set_linked_hash_map_class(cls); |
| |
| cls = Class::New<Float32x4>(); |
| object_store->set_float32x4_class(cls); |
| |
| cls = Class::New<Int32x4>(); |
| object_store->set_int32x4_class(cls); |
| |
| cls = Class::New<Float64x2>(); |
| object_store->set_float64x2_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<Instance>(kByteBufferCid); |
| |
| 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<Instance>(kNullCid); |
| object_store->set_null_class(cls); |
| |
| cls = Class::New<Capability>(); |
| cls = Class::New<ReceivePort>(); |
| cls = Class::New<SendPort>(); |
| cls = Class::New<Stacktrace>(); |
| cls = Class::New<JSRegExp>(); |
| cls = Class::New<Number>(); |
| |
| cls = Class::New<WeakProperty>(); |
| object_store->set_weak_property_class(cls); |
| |
| cls = Class::New<MirrorReference>(); |
| cls = Class::New<UserTag>(); |
| |
| const Context& context = Context::Handle(zone, |
| Context::New(0, Heap::kOld)); |
| object_store->set_empty_context(context); |
| |
| #endif // defined(DART_NO_SNAPSHOT). |
| |
| return Error::null(); |
| } |
| |
| |
| void Object::Print() const { |
| THR_Print("%s\n", ToCString()); |
| } |
| |
| |
| static void AddNameProperties(JSONObject* jsobj, |
| const String& name, |
| const String& vm_name) { |
| jsobj->AddProperty("name", name.ToCString()); |
| if (!name.Equals(vm_name)) { |
| jsobj->AddProperty("_vmName", vm_name.ToCString()); |
| } |
| } |
| |
| |
| void Object::AddCommonObjectProperties(JSONObject* jsobj, |
| const char* protocol_type, |
| bool ref) const { |
| const char* vm_type = JSONType(); |
| bool same_type = (strcmp(protocol_type, vm_type) == 0); |
| if (ref) { |
| jsobj->AddPropertyF("type", "@%s", protocol_type); |
| } else { |
| jsobj->AddProperty("type", protocol_type); |
| } |
| if (!same_type) { |
| jsobj->AddProperty("_vmType", vm_type); |
| } |
| if (!ref || IsInstance() || IsNull()) { |
| // TODO(turnidge): Provide the type arguments here too? |
| const Class& cls = Class::Handle(this->clazz()); |
| jsobj->AddProperty("class", cls); |
| } |
| if (!ref) { |
| if (raw()->IsHeapObject()) { |
| jsobj->AddProperty("size", raw()->Size()); |
| } else { |
| jsobj->AddProperty("size", (intptr_t)0); |
| } |
| } |
| } |
| |
| |
| void Object::PrintJSON(JSONStream* stream, bool ref) const { |
| if (IsNull()) { |
| JSONObject jsobj(stream); |
| AddCommonObjectProperties(&jsobj, "Instance", ref); |
| jsobj.AddProperty("kind", "Null"); |
| jsobj.AddFixedServiceId("objects/null"); |
| jsobj.AddProperty("valueAsString", "null"); |
| } else { |
| PrintJSONImpl(stream, ref); |
| } |
| } |
| |
| |
| void Object::PrintJSONImpl(JSONStream* stream, bool ref) const { |
| JSONObject jsobj(stream); |
| AddCommonObjectProperties(&jsobj, "Object", ref); |
| jsobj.AddServiceId(*this); |
| if (ref) { |
| return; |
| } |
| } |
| |
| |
| RawString* Object::DictionaryName() const { |
| return String::null(); |
| } |
| |
| |
| void Object::InitializeObject(uword address, |
| intptr_t class_id, |
| intptr_t size, |
| bool is_vm_object) { |
| const uword break_instruction_value = Assembler::GetBreakInstructionFiller(); |
| const uword null_value = reinterpret_cast<uword>(null_); |
| const bool is_instructions = class_id == kInstructionsCid; |
| uword initial_value = |
| is_instructions ? break_instruction_value : null_value; |
| uword cur = address; |
| uword end = address + size; |
| if (is_instructions) { |
| // Fill the header with null. The remainder of the Instructions object will |
| // be filled with the break_instruction_value. |
| uword header_end = address + Instructions::HeaderSize(); |
| while (cur < header_end) { |
| *reinterpret_cast<uword*>(cur) = null_value; |
| cur += kWordSize; |
| } |
| } |
| 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); |
| tags = RawObject::VMHeapObjectTag::update(is_vm_object, tags); |
| reinterpret_cast<RawObject*>(address)->tags_ = tags; |
| ASSERT(is_vm_object == RawObject::IsVMHeapObject(tags)); |
| VerifiedMemory::Accept(address, size); |
| } |
| |
| |
| 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)); |
| Thread* thread = Thread::Current(); |
| Isolate* isolate = thread->isolate(); |
| // New space allocation allowed only in mutator thread (Dart thread); |
| ASSERT(isolate->MutatorThreadIsCurrentThread() || (space != Heap::kNew)); |
| ASSERT(thread->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(thread, exception); |
| UNREACHABLE(); |
| } |
| ClassTable* class_table = isolate->class_table(); |
| if (space == Heap::kNew) { |
| class_table->UpdateAllocatedNew(cls_id, size); |
| } else { |
| class_table->UpdateAllocatedOld(cls_id, size); |
| } |
| const Class& cls = Class::Handle(class_table->At(cls_id)); |
| if (cls.TraceAllocation(isolate)) { |
| Profiler::RecordAllocation(thread, cls_id); |
| } |
| NoSafepointScope no_safepoint; |
| InitializeObject(address, cls_id, size, (isolate == Dart::vm_isolate())); |
| 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(Thread* thread, RawObject* obj) : |
| ObjectPointerVisitor(thread->isolate()), thread_(thread), 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()) { |
| old_obj_->SetRememberedBit(); |
| thread_->StoreBufferAddObject(old_obj_); |
| // Remembered this object. There is no need to continue searching. |
| return; |
| } |
| } |
| } |
| |
| private: |
| Thread* thread_; |
| 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& orig, Heap::Space space) { |
| const Class& cls = Class::Handle(orig.clazz()); |
| intptr_t size = orig.raw()->Size(); |
| RawObject* raw_clone = Object::Allocate(cls.id(), size, space); |
| NoSafepointScope no_safepoint; |
| // TODO(koda): This will trip when we start allocating black. |
| // Revisit code below at that point, to account for the new write barrier. |
| ASSERT(!raw_clone->IsMarked()); |
| // Copy the body of the original into the clone. |
| uword orig_addr = RawObject::ToAddr(orig.raw()); |
| uword clone_addr = RawObject::ToAddr(raw_clone); |
| static const intptr_t kHeaderSizeInBytes = sizeof(RawObject); |
| memmove(reinterpret_cast<uint8_t*>(clone_addr + kHeaderSizeInBytes), |
| reinterpret_cast<uint8_t*>(orig_addr + kHeaderSizeInBytes), |
| size - kHeaderSizeInBytes); |
| VerifiedMemory::Accept(clone_addr, size); |
| // Add clone to store buffer, if needed. |
| if (!raw_clone->IsOldObject()) { |
| // No need to remember an object in new space. |
| return raw_clone; |
| } else if (orig.raw()->IsOldObject() && !orig.raw()->IsRemembered()) { |
| // Old original doesn't need to be remembered, so neither does the clone. |
| return raw_clone; |
| } |
| StoreBufferUpdateVisitor visitor(Thread::Current(), raw_clone); |
| raw_clone->VisitPointers(&visitor); |
| return raw_clone; |
| } |
| |
| |
| RawString* Class::Name() const { |
| // TODO(turnidge): This assert fails for the fake kFreeListElement class. |
| // Fix this. |
| ASSERT(raw_ptr()->name_ != String::null()); |
| return raw_ptr()->name_; |
| } |
| |
| |
| RawString* Class::PrettyName() const { |
| return GeneratePrettyName(); |
| } |
| |
| |
| RawString* Class::UserVisibleName() const { |
| ASSERT(raw_ptr()->user_name_ != String::null()); |
| return raw_ptr()->user_name_; |
| } |
| |
| |
| bool Class::IsInFullSnapshot() const { |
| NoSafepointScope no_safepoint; |
| return raw_ptr()->library_->ptr()->is_in_fullsnapshot_; |
| } |
| |
| |
| RawType* Class::SignatureType() const { |
| ASSERT(IsSignatureClass()); |
| Zone* zone = Thread::Current()->zone(); |
| const Function& function = Function::Handle(zone, 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_signature_class = |
| Class::Handle(zone, function.signature_class()); |
| return canonical_signature_class.SignatureType(); |
| } |
| const Type& signature_type = Type::Handle(zone, CanonicalType()); |
| if (!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(zone, type_parameters()); |
| // Return the still unfinalized signature type. |
| return Type::New(*this, signature_type_arguments, token_pos()); |
| } |
| |
| |
| RawAbstractType* Class::RareType() const { |
| const Type& type = Type::Handle(Type::New( |
| *this, |
| Object::null_type_arguments(), |
| Scanner::kNoSourcePos)); |
| return ClassFinalizer::FinalizeType(*this, |
| type, |
| ClassFinalizer::kCanonicalize); |
| } |
| |
| |
| RawAbstractType* Class::DeclarationType() const { |
| const TypeArguments& args = TypeArguments::Handle(type_parameters()); |
| const Type& type = Type::Handle(Type::New( |
| *this, |
| args, |
| Scanner::kNoSourcePos)); |
| return ClassFinalizer::FinalizeType(*this, |
| type, |
| ClassFinalizer::kCanonicalize); |
| } |
| |
| |
| 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); |
| NoSafepointScope no_safepoint; |
| result ^= raw; |
| } |
| FakeObject fake; |
| result.set_handle_vtable(fake.vtable()); |
| result.set_instance_size(FakeObject::InstanceSize()); |
| result.set_next_field_offset(FakeObject::NextFieldOffset()); |
| COMPILE_ASSERT((FakeObject::kClassId != kInstanceCid)); |
| result.set_id(FakeObject::kClassId); |
| result.set_state_bits(0); |
| if (FakeObject::kClassId < kInstanceCid) { |
| // VM internal classes are done. There is no finalization needed or |
| // possible in this case. |
| result.set_is_finalized(); |
| } else { |
| // VM backed classes are almost ready: run checks and resolve class |
| // references, but do not recompute size. |
| result.set_is_prefinalized(); |
| } |
| result.set_type_arguments_field_offset_in_words(kNoTypeArguments); |
| result.set_num_type_arguments(0); |
| result.set_num_own_type_arguments(0); |
| result.set_num_native_fields(0); |
| result.set_token_pos(Scanner::kNoSourcePos); |
| result.InitEmptyFields(); |
| Isolate::Current()->RegisterClass(result); |
| return result.raw(); |
| } |
| |
| |
| |
| static void ReportTooManyTypeArguments(const Class& cls) { |
| Report::MessageF(Report::kError, |
| Script::Handle(cls.script()), |
| cls.token_pos(), |
| "too many type parameters declared in class '%s' or in its " |
| "super classes", |
| String::Handle(cls.Name()).ToCString()); |
| UNREACHABLE(); |
| } |
| |
| |
| void Class::set_num_type_arguments(intptr_t value) const { |
| if (!Utils::IsInt(16, value)) { |
| ReportTooManyTypeArguments(*this); |
| } |
| StoreNonPointer(&raw_ptr()->num_type_arguments_, value); |
| } |
| |
| |
| void Class::set_num_own_type_arguments(intptr_t value) const { |
| if (!Utils::IsInt(16, value)) { |
| ReportTooManyTypeArguments(*this); |
| } |
| StoreNonPointer(&raw_ptr()->num_own_type_arguments_, value); |
| } |
| |
| |
| // 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()->functions_, Object::empty_array().raw()); |
| StorePointer(&raw_ptr()->fields_, Object::empty_array().raw()); |
| StorePointer(&raw_ptr()->invocation_dispatcher_cache_, |
| Object::empty_array().raw()); |
| } |
| |
| |
| RawArray* Class::OffsetToFieldMap() const { |
| Array& array = Array::Handle(raw_ptr()->offset_in_words_to_field_); |
| if (array.IsNull()) { |
| ASSERT(is_finalized()); |
| const intptr_t length = raw_ptr()->instance_size_in_words_; |
| array = Array::New(length, Heap::kOld); |
| Class& cls = Class::Handle(this->raw()); |
| Array& fields = Array::Handle(); |
| Field& f = Field::Handle(); |
| while (!cls.IsNull()) { |
| fields = cls.fields(); |
| for (intptr_t i = 0; i < fields.Length(); ++i) { |
| f ^= fields.At(i); |
| if (!f.is_static()) { |
| array.SetAt(f.Offset() >> kWordSizeLog2, f); |
| } |
| } |
| cls = cls.SuperClass(); |
| } |
| StorePointer(&raw_ptr()->offset_in_words_to_field_, array.raw()); |
| } |
| return 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; |
| } |
| |
| |
| class FunctionName { |
| public: |
| FunctionName(const String& name, String* tmp_string) |
| : name_(name), tmp_string_(tmp_string) {} |
| bool Matches(const Function& function) const { |
| if (name_.IsSymbol()) { |
| return name_.raw() == function.name(); |
| } else { |
| *tmp_string_ = function.name(); |
| return name_.Equals(*tmp_string_); |
| } |
| } |
| intptr_t Hash() const { return name_.Hash(); } |
| private: |
| const String& name_; |
| String* tmp_string_; |
| }; |
| |
| |
| // Traits for looking up Functions by name. |
| class ClassFunctionsTraits { |
| public: |
| // Called when growing the table. |
| static bool IsMatch(const Object& a, const Object& b) { |
| ASSERT(a.IsFunction() && b.IsFunction()); |
| // Function objects are always canonical. |
| return a.raw() == b.raw(); |
| } |
| static bool IsMatch(const FunctionName& name, const Object& obj) { |
| return name.Matches(Function::Cast(obj)); |
| } |
| static uword Hash(const Object& key) { |
| return String::HashRawSymbol(Function::Cast(key).name()); |
| } |
| static uword Hash(const FunctionName& name) { |
| return name.Hash(); |
| } |
| }; |
| typedef UnorderedHashSet<ClassFunctionsTraits> ClassFunctionsSet; |
| |
| |
| void Class::SetFunctions(const Array& value) const { |
| ASSERT(!value.IsNull()); |
| StorePointer(&raw_ptr()->functions_, value.raw()); |
| const intptr_t len = value.Length(); |
| ClassFunctionsSet set(HashTables::New<ClassFunctionsSet>(len, Heap::kOld)); |
| if (len >= kFunctionLookupHashTreshold) { |
| Function& func = Function::Handle(); |
| for (intptr_t i = 0; i < len; ++i) { |
| func ^= value.At(i); |
| // Verify that all the functions in the array have this class as owner. |
| ASSERT(func.Owner() == raw()); |
| set.Insert(func); |
| } |
| } |
| StorePointer(&raw_ptr()->functions_hash_table_, set.Release().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, Heap::kOld)); |
| new_arr.SetAt(arr.Length(), function); |
| StorePointer(&raw_ptr()->functions_, new_arr.raw()); |
| // Add to hash table, if any. |
| const intptr_t new_len = new_arr.Length(); |
| if (new_len == kFunctionLookupHashTreshold) { |
| // Transition to using hash table. |
| SetFunctions(new_arr); |
| } else if (new_len > kFunctionLookupHashTreshold) { |
| ClassFunctionsSet set(raw_ptr()->functions_hash_table_); |
| set.Insert(function); |
| StorePointer(&raw_ptr()->functions_hash_table_, set.Release().raw()); |
| } |
| } |
| |
| |
| void Class::RemoveFunction(const Function& function) const { |
| const Array& arr = Array::Handle(functions()); |
| StorePointer(&raw_ptr()->functions_, Object::empty_array().raw()); |
| Function& entry = Function::Handle(); |
| for (intptr_t i = 0; i < arr.Length(); i++) { |
| entry ^= arr.At(i); |
| if (function.raw() != entry.raw()) { |
| AddFunction(entry); |
| } |
| } |
| } |
| |
| |
| intptr_t Class::FindFunctionIndex(const Function& needle) const { |
| Thread* thread = Thread::Current(); |
| if (EnsureIsFinalized(thread) != Error::null()) { |
| return -1; |
| } |
| REUSABLE_ARRAY_HANDLESCOPE(thread); |
| REUSABLE_FUNCTION_HANDLESCOPE(thread); |
| Array& funcs = thread->ArrayHandle(); |
| Function& function = thread->FunctionHandle(); |
| funcs ^= functions(); |
| ASSERT(!funcs.IsNull()); |
| const intptr_t len = funcs.Length(); |
| for (intptr_t i = 0; i < len; i++) { |
| function ^= funcs.At(i); |
| if (function.raw() == needle.raw()) { |
| return i; |
| } |
| } |
| // No function found. |
| return -1; |
| } |
| |
| |
| RawFunction* Class::FunctionFromIndex(intptr_t idx) const { |
| const Array& funcs = Array::Handle(functions()); |
| if ((idx < 0) || (idx >= funcs.Length())) { |
| return Function::null(); |
| } |
| Function& func = Function::Handle(); |
| func ^= funcs.At(idx); |
| ASSERT(!func.IsNull()); |
| return func.raw(); |
| } |
| |
| |
| RawFunction* Class::ImplicitClosureFunctionFromIndex(intptr_t idx) const { |
| const Array& funcs = Array::Handle(functions()); |
| if ((idx < 0) || (idx >= funcs.Length())) { |
| return Function::null(); |
| } |
| Function& func = Function::Handle(); |
| func ^= funcs.At(idx); |
| ASSERT(!func.IsNull()); |
| if (!func.HasImplicitClosureFunction()) { |
| return Function::null(); |
| } |
| const Function& closure_func = |
| Function::Handle(func.ImplicitClosureFunction()); |
| ASSERT(!closure_func.IsNull()); |
| return closure_func.raw(); |
| } |
| |
| |
| intptr_t Class::FindImplicitClosureFunctionIndex(const Function& needle) const { |
| Thread* thread = Thread::Current(); |
| if (EnsureIsFinalized(thread) != Error::null()) { |
| return -1; |
| } |
| REUSABLE_ARRAY_HANDLESCOPE(thread); |
| REUSABLE_FUNCTION_HANDLESCOPE(thread); |
| Array& funcs = thread->ArrayHandle(); |
| Function& function = thread->FunctionHandle(); |
| funcs ^= functions(); |
| ASSERT(!funcs.IsNull()); |
| Function& implicit_closure = Function::Handle(thread->zone()); |
| const intptr_t len = funcs.Length(); |
| for (intptr_t i = 0; i < len; i++) { |
| function ^= funcs.At(i); |
| implicit_closure ^= function.implicit_closure_function(); |
| if (implicit_closure.IsNull()) { |
| // Skip non-implicit closure functions. |
| continue; |
| } |
| if (needle.raw() == implicit_closure.raw()) { |
| return i; |
| } |
| } |
| // No function found. |
| return -1; |
| } |
| |
| |
| |
| intptr_t Class::FindInvocationDispatcherFunctionIndex( |
| const Function& needle) const { |
| Thread* thread = Thread::Current(); |
| if (EnsureIsFinalized(thread) != Error::null()) { |
| return -1; |
| } |
| REUSABLE_ARRAY_HANDLESCOPE(thread); |
| REUSABLE_OBJECT_HANDLESCOPE(thread); |
| Array& funcs = thread->ArrayHandle(); |
| Object& object = thread->ObjectHandle(); |
| funcs ^= invocation_dispatcher_cache(); |
| ASSERT(!funcs.IsNull()); |
| const intptr_t len = funcs.Length(); |
| for (intptr_t i = 0; i < len; i++) { |
| object = funcs.At(i); |
| // The invocation_dispatcher_cache is a table with some entries that |
| // are functions. |
| if (object.IsFunction()) { |
| if (Function::Cast(object).raw() == needle.raw()) { |
| return i; |
| } |
| } |
| } |
| // No function found. |
| return -1; |
| } |
| |
| |
| |
| RawFunction* Class::InvocationDispatcherFunctionFromIndex(intptr_t idx) const { |
| Thread* thread = Thread::Current(); |
| REUSABLE_ARRAY_HANDLESCOPE(thread); |
| REUSABLE_OBJECT_HANDLESCOPE(thread); |
| Array& dispatcher_cache = thread->ArrayHandle(); |
| Object& object = thread->ObjectHandle(); |
| dispatcher_cache ^= invocation_dispatcher_cache(); |
| object = dispatcher_cache.At(idx); |
| if (!object.IsFunction()) { |
| return Function::null(); |
| } |
| return Function::Cast(object).raw(); |
| } |
| |
| |
| void Class::set_closures(const GrowableObjectArray& value) const { |
| StorePointer(&raw_ptr()->closure_functions_, value.raw()); |
| } |
| |
| |
| void Class::AddClosureFunction(const Function& function) const { |
| GrowableObjectArray& closures = |
| GrowableObjectArray::Handle(raw_ptr()->closure_functions_); |
| if (closures.IsNull()) { |
| closures = GrowableObjectArray::New(4, Heap::kOld); |
| StorePointer(&raw_ptr()->closure_functions_, closures.raw()); |
| } |
| ASSERT(function.IsNonImplicitClosureFunction()); |
| ASSERT(function.Owner() == this->raw()); |
| closures.Add(function, Heap::kOld); |
| } |
| |
| |
| // 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(); |
| } |
| |
| intptr_t Class::FindClosureIndex(const Function& needle) const { |
| if (closures() == GrowableObjectArray::null()) { |
| return -1; |
| } |
| Thread* thread = Thread::Current(); |
| const GrowableObjectArray& closures_array = |
| GrowableObjectArray::Handle(thread->zone(), closures()); |
| REUSABLE_FUNCTION_HANDLESCOPE(thread); |
| Function& closure = thread->FunctionHandle(); |
| intptr_t num_closures = closures_array.Length(); |
| for (intptr_t i = 0; i < num_closures; i++) { |
| closure ^= closures_array.At(i); |
| ASSERT(!closure.IsNull()); |
| if (closure.raw() == needle.raw()) { |
| return i; |
| } |
| } |
| return -1; |
| } |
| |
| |
| RawFunction* Class::ClosureFunctionFromIndex(intptr_t idx) const { |
| const GrowableObjectArray& closures_array = |
| GrowableObjectArray::Handle(closures()); |
| if ((idx < 0) || (idx >= closures_array.Length())) { |
| return Function::null(); |
| } |
| Function& func = Function::Handle(); |
| func ^= closures_array.At(idx); |
| ASSERT(!func.IsNull()); |
| return func.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_state_bits(intptr_t bits) const { |
| StoreNonPointer(&raw_ptr()->state_bits_, static_cast<uint16_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(Thread* thread) const { |
| if (IsMixinApplication() && !is_mixin_type_applied()) { |
| ClassFinalizer::ApplyMixinType(*this); |
| } |
| if (type_parameters() == TypeArguments::null()) { |
| return 0; |
| } |
| REUSABLE_TYPE_ARGUMENTS_HANDLESCOPE(thread); |
| TypeArguments& type_params = thread->TypeArgumentsHandle(); |
| type_params = type_parameters(); |
| return type_params.Length(); |
| } |
| |
| |
| intptr_t Class::NumOwnTypeArguments() const { |
| // Return cached value if already calculated. |
| if (num_own_type_arguments() != kUnknownNumTypeArguments) { |
| return num_own_type_arguments(); |
| } |
| Thread* thread = Thread::Current(); |
| Isolate* isolate = thread->isolate(); |
| Zone* zone = thread->zone(); |
| const intptr_t num_type_params = NumTypeParameters(); |
| if (!FLAG_overlap_type_arguments || |
| (num_type_params == 0) || |
| (super_type() == AbstractType::null()) || |
| (super_type() == isolate->object_store()->object_type())) { |
| set_num_own_type_arguments(num_type_params); |
| return num_type_params; |
| } |
| ASSERT(!IsMixinApplication() || is_mixin_type_applied()); |
| const AbstractType& sup_type = AbstractType::Handle(zone, super_type()); |
| const TypeArguments& sup_type_args = |
| TypeArguments::Handle(zone, sup_type.arguments()); |
| if (sup_type_args.IsNull()) { |
| // The super type is raw or the super class is non generic. |
| // In either case, overlapping is not possible. |
| set_num_own_type_arguments(num_type_params); |
| return num_type_params; |
| } |
| const intptr_t num_sup_type_args = sup_type_args.Length(); |
| // At this point, the super type may or may not be finalized. In either case, |
| // the result of this function must remain the same. |
| // The value of num_sup_type_args may increase when the super type is |
| // finalized, but the last num_sup_type_args type arguments will not be |
| // modified by finalization, only shifted to higher indices in the vector. |
| // They may however get wrapped in a BoundedType, which we skip. |
| // The super type may not even be resolved yet. This is not necessary, since |
| // we only check for matching type parameters, which are resolved by default. |
| const TypeArguments& type_params = |
| TypeArguments::Handle(zone, type_parameters()); |
| // Determine the maximum overlap of a prefix of the vector consisting of the |
| // type parameters of this class with a suffix of the vector consisting of the |
| // type arguments of the super type of this class. |
| // The number of own type arguments of this class is the number of its type |
| // parameters minus the number of type arguments in the overlap. |
| // Attempt to overlap the whole vector of type parameters; reduce the size |
| // of the vector (keeping the first type parameter) until it fits or until |
| // its size is zero. |
| TypeParameter& type_param = TypeParameter::Handle(zone); |
| AbstractType& sup_type_arg = AbstractType::Handle(zone); |
| for (intptr_t num_overlapping_type_args = |
| (num_type_params < num_sup_type_args) ? |
| num_type_params : num_sup_type_args; |
| num_overlapping_type_args > 0; num_overlapping_type_args--) { |
| intptr_t i = 0; |
| for (; i < num_overlapping_type_args; i++) { |
| type_param ^= type_params.TypeAt(i); |
| sup_type_arg = sup_type_args.TypeAt( |
| num_sup_type_args - num_overlapping_type_args + i); |
| // BoundedType can nest in case the finalized super type has bounded type |
| // arguments that overlap multiple times in its own super class chain. |
| while (sup_type_arg.IsBoundedType()) { |
| sup_type_arg = BoundedType::Cast(sup_type_arg).type(); |
| } |
| if (!type_param.Equals(sup_type_arg)) break; |
| } |
| if (i == num_overlapping_type_args) { |
| // Overlap found. |
| set_num_own_type_arguments(num_type_params - num_overlapping_type_args); |
| return num_type_params - num_overlapping_type_args; |
| } |
| } |
| // No overlap found. |
| set_num_own_type_arguments(num_type_params); |
| return num_type_params; |
| } |
| |
| |
| bool Class::IsGeneric() const { |
| return NumTypeParameters() != 0; |
| } |
| |
| |
| intptr_t Class::NumTypeArguments() const { |
| // Return cached value if already calculated. |
| if (num_type_arguments() != kUnknownNumTypeArguments) { |
| return num_type_arguments(); |
| } |
| // To work properly, this call requires the super class of this class to be |
| // resolved, which is checked by the type_class() call on the super type. |
| // Note that calling type_class() on a MixinAppType fails. |
| Thread* thread = Thread::Current(); |
| Zone* zone = thread->zone(); |
| Isolate* isolate = thread->isolate(); |
| Class& cls = Class::Handle(zone); |
| AbstractType& sup_type = AbstractType::Handle(zone); |
| cls = raw(); |
| intptr_t num_type_args = 0; |
| do { |
| if (cls.IsSignatureClass()) { |
| Function& signature_fun = Function::Handle(zone); |
| signature_fun ^= cls.signature_function(); |
| if (!signature_fun.is_static() && |
| !signature_fun.HasInstantiatedSignature()) { |
| cls = signature_fun.Owner(); |
| } |
| } |
| // Calling NumOwnTypeArguments() on a mixin application class will setup the |
| // type parameters if not already done. |
| num_type_args += cls.NumOwnTypeArguments(); |
| // Super type of Object class is null. |
| if ((cls.super_type() == AbstractType::null()) || |
| (cls.super_type() == isolate->object_store()->object_type())) { |
| break; |
| } |
| sup_type = cls.super_type(); |
| ClassFinalizer::ResolveTypeClass(cls, sup_type); |
| cls = sup_type.type_class(); |
| } while (true); |
| set_num_type_arguments(num_type_args); |
| return num_type_args; |
| } |
| |
| |
| RawClass* Class::SuperClass() const { |
| if (super_type() == AbstractType::null()) { |
| return Class::null(); |
| } |
| const AbstractType& sup_type = AbstractType::Handle(super_type()); |
| return sup_type.type_class(); |
| } |
| |
| |
| void Class::set_super_type(const AbstractType& value) const { |
| ASSERT(value.IsNull() || |
| (value.IsType() && !value.IsDynamicType()) || |
| 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) const { |
| ASSERT(!type_name.IsNull()); |
| Thread* thread = Thread::Current(); |
| REUSABLE_TYPE_ARGUMENTS_HANDLESCOPE(thread); |
| REUSABLE_TYPE_PARAMETER_HANDLESCOPE(thread); |
| REUSABLE_STRING_HANDLESCOPE(thread); |
| TypeArguments& type_params = thread->TypeArgumentsHandle(); |
| TypeParameter& type_param = thread->TypeParameterHandle(); |
| String& type_param_name = thread->StringHandle(); |
| |
| type_params ^= type_parameters(); |
| if (!type_params.IsNull()) { |
| const intptr_t num_type_params = type_params.Length(); |
| 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 = Instance::NextFieldOffset(); |
| ASSERT(offset > 0); |
| } else { |
| ASSERT(super.is_finalized() || super.is_prefinalized()); |
| 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, |
| // otherwise, if this class is the first in the super chain to be |
| // parameterized, introduce a new 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); |
| } |
| |
| |
| RawFunction* Class::GetInvocationDispatcher(const String& target_name, |
| const Array& args_desc, |
| RawFunction::Kind kind, |
| bool create_if_absent) const { |
| enum { |
| kNameIndex = 0, |
| kArgsDescIndex, |
| kFunctionIndex, |
| kEntrySize |
| }; |
| |
| ASSERT(kind == RawFunction::kNoSuchMethodDispatcher || |
| kind == RawFunction::kInvokeFieldDispatcher); |
| Function& dispatcher = Function::Handle(); |
| Array& cache = Array::Handle(invocation_dispatcher_cache()); |
| ASSERT(!cache.IsNull()); |
| String& name = String::Handle(); |
| Array& desc = Array::Handle(); |
| intptr_t i = 0; |
| for (; i < cache.Length(); i += kEntrySize) { |
| name ^= cache.At(i + kNameIndex); |
| if (name.IsNull()) break; // Reached last entry. |
| if (!name.Equals(target_name)) continue; |
| desc ^= cache.At(i + kArgsDescIndex); |
| if (desc.raw() != args_desc.raw()) continue; |
| dispatcher ^= cache.At(i + kFunctionIndex); |
| if (dispatcher.kind() == kind) { |
| // Found match. |
| ASSERT(dispatcher.IsFunction()); |
| break; |
| } |
| } |
| |
| if (dispatcher.IsNull() && create_if_absent) { |
| if (i == cache.Length()) { |
| // Allocate new larger cache. |
| intptr_t new_len = (cache.Length() == 0) |
| ? static_cast<intptr_t>(kEntrySize) |
| : cache.Length() * 2; |
| cache ^= Array::Grow(cache, new_len); |
| set_invocation_dispatcher_cache(cache); |
| } |
| dispatcher ^= CreateInvocationDispatcher(target_name, args_desc, kind); |
| cache.SetAt(i + kNameIndex, target_name); |
| cache.SetAt(i + kArgsDescIndex, args_desc); |
| cache.SetAt(i + kFunctionIndex, dispatcher); |
| } |
| return dispatcher.raw(); |
| } |
| |
| |
| RawFunction* Class::CreateInvocationDispatcher(const String& target_name, |
| const Array& args_desc, |
| RawFunction::Kind kind) const { |
| Function& invocation = Function::Handle( |
| Function::New(String::Handle(Symbols::New(target_name)), |
| kind, |
| false, // Not static. |
| false, // Not const. |
| false, // Not abstract. |
| false, // Not external. |
| false, // Not native. |
| *this, |
| 0)); // No token position. |
| ArgumentsDescriptor desc(args_desc); |
| invocation.set_num_fixed_parameters(desc.PositionalCount()); |
| invocation.SetNumOptionalParameters(desc.NamedCount(), |
| false); // Not positional. |
| invocation.set_parameter_types(Array::Handle(Array::New(desc.Count(), |
| Heap::kOld))); |
| invocation.set_parameter_names(Array::Handle(Array::New(desc.Count(), |
| Heap::kOld))); |
| // Receiver. |
| invocation.SetParameterTypeAt(0, Type::Handle(Type::DynamicType())); |
| invocation.SetParameterNameAt(0, Symbols::This()); |
| // Remaining positional parameters. |
| intptr_t i = 1; |
| for (; i < desc.PositionalCount(); i++) { |
| invocation.SetParameterTypeAt(i, Type::Handle(Type::DynamicType())); |
| char name[64]; |
| OS::SNPrint(name, 64, ":p%" Pd, i); |
| invocation.SetParameterNameAt(i, String::Handle(Symbols::New(name))); |
| } |
|