// 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/bigint_operations.h" #include "vm/bootstrap.h" #include "vm/class_finalizer.h" #include "vm/code_generator.h" #include "vm/code_observers.h" #include "vm/code_patcher.h" #include "vm/compiler.h" #include "vm/compiler_stats.h" #include "vm/dart.h" #include "vm/dart_api_state.h" #include "vm/dart_entry.h" #include "vm/datastream.h" #include "vm/debugger.h" #include "vm/deopt_instructions.h" #include "vm/double_conversion.h" #include "vm/exceptions.h" #include "vm/growable_array.h" #include "vm/heap.h" #include "vm/intrinsifier.h" #include "vm/object_store.h" #include "vm/parser.h" #include "vm/runtime_entry.h" #include "vm/scopes.h" #include "vm/stack_frame.h" #include "vm/symbols.h" #include "vm/timer.h" #include "vm/unicode.h" namespace dart { DEFINE_FLAG(bool, show_internal_names, false, "Show names of internal classes (e.g. \"OneByteString\") in error messages " "instead of showing the corresponding interface names (e.g. \"String\")"); DEFINE_FLAG(bool, trace_disabling_optimized_code, false, "Trace disabling optimized code."); DEFINE_FLAG(int, huge_method_cutoff_in_tokens, 20000, "Huge method cutoff in tokens: Disables optimizations for huge methods."); DEFINE_FLAG(int, huge_method_cutoff_in_code_size, 200000, "Huge method cutoff in unoptimized code size (in bytes)."); DECLARE_FLAG(bool, trace_compiler); DECLARE_FLAG(bool, eliminate_type_checks); DECLARE_FLAG(bool, enable_type_checks); static const char* kGetterPrefix = "get:"; static const intptr_t kGetterPrefixLength = strlen(kGetterPrefix); static const char* kSetterPrefix = "set:"; static const intptr_t kSetterPrefixLength = strlen(kSetterPrefix); cpp_vtable Object::handle_vtable_ = 0; cpp_vtable Object::builtin_vtables_[kNumPredefinedCids] = { 0 }; cpp_vtable Smi::handle_vtable_ = 0; // These are initialized to a value that will force a illegal memory access if // they are being used. #if defined(RAW_NULL) #error RAW_NULL should not be defined. #endif #define RAW_NULL kHeapObjectTag Array* Object::empty_array_ = NULL; Instance* Object::sentinel_ = NULL; Instance* Object::transition_sentinel_ = NULL; Bool* Object::bool_true_ = NULL; Bool* Object::bool_false_ = NULL; RawObject* Object::null_ = reinterpret_cast(RAW_NULL); RawClass* Object::class_class_ = reinterpret_cast(RAW_NULL); RawClass* Object::null_class_ = reinterpret_cast(RAW_NULL); RawClass* Object::dynamic_class_ = reinterpret_cast(RAW_NULL); RawClass* Object::void_class_ = reinterpret_cast(RAW_NULL); RawClass* Object::unresolved_class_class_ = reinterpret_cast(RAW_NULL); RawClass* Object::type_arguments_class_ = reinterpret_cast(RAW_NULL); RawClass* Object::instantiated_type_arguments_class_ = reinterpret_cast(RAW_NULL); RawClass* Object::patch_class_class_ = reinterpret_cast(RAW_NULL); RawClass* Object::function_class_ = reinterpret_cast(RAW_NULL); RawClass* Object::closure_data_class_ = reinterpret_cast(RAW_NULL); RawClass* Object::redirection_data_class_ = reinterpret_cast(RAW_NULL); RawClass* Object::field_class_ = reinterpret_cast(RAW_NULL); RawClass* Object::literal_token_class_ = reinterpret_cast(RAW_NULL); RawClass* Object::token_stream_class_ = reinterpret_cast(RAW_NULL); RawClass* Object::script_class_ = reinterpret_cast(RAW_NULL); RawClass* Object::library_class_ = reinterpret_cast(RAW_NULL); RawClass* Object::library_prefix_class_ = reinterpret_cast(RAW_NULL); RawClass* Object::namespace_class_ = reinterpret_cast(RAW_NULL); RawClass* Object::code_class_ = reinterpret_cast(RAW_NULL); RawClass* Object::instructions_class_ = reinterpret_cast(RAW_NULL); RawClass* Object::pc_descriptors_class_ = reinterpret_cast(RAW_NULL); RawClass* Object::stackmap_class_ = reinterpret_cast(RAW_NULL); RawClass* Object::var_descriptors_class_ = reinterpret_cast(RAW_NULL); RawClass* Object::exception_handlers_class_ = reinterpret_cast(RAW_NULL); RawClass* Object::deopt_info_class_ = reinterpret_cast(RAW_NULL); RawClass* Object::context_class_ = reinterpret_cast(RAW_NULL); RawClass* Object::context_scope_class_ = reinterpret_cast(RAW_NULL); RawClass* Object::icdata_class_ = reinterpret_cast(RAW_NULL); RawClass* Object::megamorphic_cache_class_ = reinterpret_cast(RAW_NULL); RawClass* Object::subtypetestcache_class_ = reinterpret_cast(RAW_NULL); RawClass* Object::api_error_class_ = reinterpret_cast(RAW_NULL); RawClass* Object::language_error_class_ = reinterpret_cast(RAW_NULL); RawClass* Object::unhandled_exception_class_ = reinterpret_cast(RAW_NULL); RawClass* Object::unwind_error_class_ = reinterpret_cast(RAW_NULL); #undef RAW_NULL const double MegamorphicCache::kLoadFactor = 0.75; // The following functions are marked as invisible, meaning they will be hidden // in the stack trace. // (Library, class name, method name) #define INVISIBLE_LIST(V) \ V(CoreLibrary, Object, _noSuchMethod) \ V(CoreLibrary, List, _throwArgumentError) \ V(CoreLibrary, AssertionErrorImplementation, _throwNew) \ V(CoreLibrary, TypeErrorImplementation, _throwNew) \ V(CoreLibrary, FallThroughErrorImplementation, _throwNew) \ V(CoreLibrary, AbstractClassInstantiationErrorImplementation, _throwNew) \ V(CoreLibrary, NoSuchMethodError, _throwNew) \ V(CoreLibrary, int, _throwFormatException) \ V(CoreLibrary, int, _parse) \ static void MarkFunctionAsInvisible(const Library& lib, const char* class_name, const char* function_name) { ASSERT(!lib.IsNull()); const Class& cls = Class::Handle( lib.LookupClass(String::Handle(String::New(class_name)))); ASSERT(!cls.IsNull()); const Function& function = Function::Handle( cls.LookupFunctionAllowPrivate( String::Handle(String::New(function_name)))); ASSERT(!function.IsNull()); function.set_is_visible(false); } static void MarkInvisibleFunctions() { #define MARK_FUNCTION(lib, class_name, function_name) \ MarkFunctionAsInvisible(Library::Handle(Library::lib()), \ #class_name, #function_name); \ INVISIBLE_LIST(MARK_FUNCTION) #undef MARK_FUNCTION } // Takes a vm internal name and makes it suitable for external user. // // Examples: // // Internal getter and setter prefixes are changed: // // get:foo -> foo // set:foo -> foo= // // Private name mangling is removed, possibly twice: // // _ReceivePortImpl@6be832b -> _ReceivePortImpl // _ReceivePortImpl@6be832b._internal@6be832b -> +ReceivePortImpl._internal // // The trailing . on the default constructor name is dropped: // // List. -> List // // And so forth: // // get:foo@6be832b -> foo // _MyClass@6b3832b. -> _MyClass // _MyClass@6b3832b.named -> _MyClass.named // static RawString* IdentifierPrettyName(const String& name) { intptr_t len = name.Length(); intptr_t start = 0; intptr_t at_pos = len; // Position of '@' in the name. intptr_t dot_pos = len; // Position of '.' in the name. bool is_setter = false; for (int i = 0; i < name.Length(); i++) { if (name.CharAt(i) == ':') { ASSERT(start == 0); if (name.CharAt(0) == 's') { is_setter = true; } start = i + 1; } else if (name.CharAt(i) == '@') { ASSERT(at_pos == len); at_pos = i; } else if (name.CharAt(i) == '.') { dot_pos = i; break; } } intptr_t limit = (at_pos < dot_pos ? at_pos : dot_pos); if (start == 0 && limit == len) { // This name is fine as it is. return name.raw(); } const String& result = String::Handle(String::SubString(name, start, (limit - start))); // Look for a second '@' now to correctly handle names like // "_ReceivePortImpl@6be832b._internal@6be832b". at_pos = len; for (int i = dot_pos; i < name.Length(); i++) { if (name.CharAt(i) == '@') { ASSERT(at_pos == len); at_pos = i; } } intptr_t suffix_len = at_pos - dot_pos; if (suffix_len > 1) { // This is a named constructor. Add the name back to the string. const String& suffix = String::Handle(String::SubString(name, dot_pos, suffix_len)); return String::Concat(result, suffix); } if (is_setter) { // Setters need to end with '='. return String::Concat(result, Symbols::Equals()); } return result.raw(); } template static bool IsSpecialCharacter(type value) { return ((value == '"') || (value == '\n') || (value == '\f') || (value == '\b') || (value == '\t') || (value == '\v') || (value == '\r')); } template 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'; } UNREACHABLE(); return '\0'; } static void DeleteWeakPersistentHandle(Dart_Handle handle) { ApiState* state = Isolate::Current()->api_state(); ASSERT(state != NULL); FinalizablePersistentHandle* weak_ref = reinterpret_cast(handle); ASSERT(state->IsValidWeakPersistentHandle(handle)); state->weak_persistent_handles().FreeHandle(weak_ref); } void Object::InitOnce() { // TODO(iposva): NoGCScope needs to be added here. ASSERT(class_class() == null_); // Initialize the static vtable values. { Object fake_object; Smi fake_smi; Object::handle_vtable_ = fake_object.vtable(); Smi::handle_vtable_ = fake_smi.vtable(); } Isolate* isolate = Isolate::Current(); Heap* heap = isolate->heap(); // Allocate the read only object handles here. empty_array_ = Array::ReadOnlyHandle(isolate); sentinel_ = Instance::ReadOnlyHandle(isolate); transition_sentinel_ = Instance::ReadOnlyHandle(isolate); bool_true_ = Bool::ReadOnlyHandle(isolate); bool_false_ = Bool::ReadOnlyHandle(isolate); // 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(address + kHeapObjectTag); // The call below is using 'null_' to initialize itself. InitializeObject(address, kNullCid, Instance::InstanceSize()); } // Initialize the empty array handle to null_ in order to be able to check // if the empty array was allocated (RAW_NULL is not available). *empty_array_ = Array::null(); Class& cls = Class::Handle(); // Allocate and initialize the class class. { intptr_t size = Class::InstanceSize(); uword address = heap->Allocate(size, Heap::kOld); class_class_ = reinterpret_cast(address + kHeapObjectTag); InitializeObject(address, Class::kClassId, size); Class fake; // Initialization from Class::New. // Directly set raw_ to break a circular dependency: SetRaw will attempt // to lookup class class in the class table where it is not registered yet. cls.raw_ = class_class_; cls.set_handle_vtable(fake.vtable()); cls.set_instance_size(Class::InstanceSize()); cls.set_next_field_offset(Class::InstanceSize()); cls.set_id(Class::kClassId); cls.raw_ptr()->state_bits_ = 0; cls.set_is_finalized(); cls.raw_ptr()->type_arguments_field_offset_in_words_ = Class::kNoTypeArguments; cls.raw_ptr()->num_native_fields_ = 0; cls.InitEmptyFields(); isolate->class_table()->Register(cls); } // Allocate and initialize the null class. cls = Class::New(kNullCid); cls.set_is_finalized(); null_class_ = cls.raw(); // Allocate and initialize the free list element class. cls = Class::New(kFreeListElement); cls.set_is_finalized(); // Allocate and initialize the sentinel values of Null class. { *sentinel_ ^= Object::Allocate(kNullCid, Instance::InstanceSize(), Heap::kOld); *transition_sentinel_ ^= Object::Allocate(kNullCid, Instance::InstanceSize(), Heap::kOld); } cls = Class::New(kDynamicCid); cls.set_is_finalized(); cls.set_is_abstract(); dynamic_class_ = cls.raw(); // Allocate the remaining VM internal classes. cls = Class::New(); unresolved_class_class_ = cls.raw(); cls = Class::New(kVoidCid); cls.set_is_finalized(); void_class_ = cls.raw(); cls = Class::New(); type_arguments_class_ = cls.raw(); cls = Class::New(); instantiated_type_arguments_class_ = cls.raw(); cls = Class::New(); patch_class_class_ = cls.raw(); cls = Class::New(); function_class_ = cls.raw(); cls = Class::New(); closure_data_class_ = cls.raw(); cls = Class::New(); redirection_data_class_ = cls.raw(); cls = Class::New(); field_class_ = cls.raw(); cls = Class::New(); literal_token_class_ = cls.raw(); cls = Class::New(); token_stream_class_ = cls.raw(); cls = Class::New